【算法】隨機快速排序和隨機選擇算法

文章目錄

    • 1、隨機快速排序
      • 1.1 什么是隨機快排
      • 1.2 隨機快排的好處
    • 2、隨機選擇算法

前言: 快速排序就是每次劃分前,通過一種方法將一個基準值的位置確定好,再進入不同的部分重復相同的工作以此確定好每個值的位置以達到有序。如果你之前并不了解快速排序請看快速排序。

1、隨機快速排序

1.1 什么是隨機快排

隨機快速排序顧名思義也是一種快速排序,它和普通的快排不同在有以下的優化。

  1. 通過隨機選取一個基準值,保證應對快排在有序情況下的最壞效率問題。
  2. 通過三路劃分的方式,假設基準值為x,每一趟劃分都會確保區間為<x ==x >x。

隨機快排的思路:

  1. 通過數組下標控制范圍,在這個范圍內通過隨機函數選擇一個隨機數。
  2. 選好隨機數后以此數為基準值,通過三路劃分的方式劃分區間為<x ==x >x。
  3. 通過下標控制邊界,通過函數遞歸重復1和2。

?
第一步:選隨機數。 由于采用的是C++語言,用的是rand函數,下面先看用法再看快排相關的。

#include <ctime>
#include <cstdlib>
srand(time(0)); //確保每次運行rand的隨機序列不同
int num = rand(); // 會返回0到32767之間的整數
//如果生成[a,b)區間的話,而[a,b]就在后面加1
int num = a + rand() % (b-a) // a + rand() % (b-a+1)////那么快排中選取一個隨機數就是(當然這里也可以用下標)
int x = nums[l + rand() % (r - l + 1)];

?
第二步:確定好基準值后進行以基準值分割區域

int first = 0, last = 0;
void partition(vector<int>& nums, int l, int r, int x){first = l, last = r;int i = l;while (i <= last){if (nums[i] < x) swap(nums[i++], nums[first++]);else if (nums[i] > x) swap(nums[i], nums[last--]);else i++;}}

選定全局first(下圖F)和last(下圖L)作為等于x區域的左邊界和右邊界,用i來遍歷數組,x代表所選隨機數。其中F左邊的區域代表小于x的,L右邊的區域代表大于x的。F和i開始一起。

  1. 當nums[i] < x時,交換i和F的數,并且i和F向右走,使得F左邊都是小于x的數。
  2. 當nums[i] > x時,交換i和L的數,這時只有L向左走(因為交換后i位置可能還是大于x的數),保證L右邊都是大于x的數。
  3. 當nums[i] == x時,i直接向右走,此時F左邊依舊是小于x的數,L右邊依舊是大于x的數。

?

第三步:通過下標控制邊界,通過函數遞歸重復1和2

void RandomQuickSort(vector<int>& nums, int l, int r)
{if (l >= r) return;int x = nums[l + rand() % (r - l + 1)];partition(nums, l, r, x);RandomQuickSort(nums, l, first - 1);RandomQuickSort(nums, last + 1, r);
}

下面通過一道題進行隨機快排的測試。

排序數組

完整代碼

class Solution {
public:int first = 0, last = 0;void partition(vector<int>& nums, int l, int r, int x){first = l, last = r;int i = l;while (i <= last){if (nums[i] < x) swap(nums[i++], nums[first++]);else if (nums[i] > x) swap(nums[i], nums[last--]);else i++;}}void RandomQuickSort(vector<int>& nums, int l, int r){if (l >= r) return;int x = nums[l + rand() % (r - l + 1)];partition(nums, l, r, x);RandomQuickSort(nums, l, first - 1);RandomQuickSort(nums, last + 1, r);}vector<int> sortArray(vector<int>& nums) {RandomQuickSort(nums, 0, nums.size() - 1);return nums;}
};

隨機快排的時間復雜度為O(N*LogN),空間復雜度為O(LogN)。
?

1.2 隨機快排的好處

接下來我們看看為什么隨機快排需要挑選隨機數以及三路劃分

我們先來看看什么是快排效率最差的情況

  • 最差情況:當對一個有序數組進行快排,比如[1 2 3 4 5 6 7],如果依據上面partition的做法,普通的按照最后一個數為基準值,那么每次都得拿最后一個數和前面每一個數進行比較(比如第一趟7和前面每一個數都比了一遍),那么時間復雜度就是O(N^2)。如果通過隨機選取一個基準值,那么就可以極大概率降低每次都抽到最后一個數的情況。

為什么要用三路劃分?

  • 如果給定一組數3 3 3 4 3 3 3,如果按照之前快排的挖坑法,第一次排序后還是3 3 3 4 3 3 3,因為其采用的是劃分為>=x 和 <=x的區域,而通過三路劃分則可以劃分為3 3 3 3 3 3 4。(這兩個方法都可以實現有序,只是在一些場景下我們要求嚴格的<x =x >x進行劃分,通過三路劃分就更好。比如下面隨機選擇算法的這道題)

?

2、隨機選擇算法

隨機選擇算法主要用于在無序數組中快速定位第k大的元素。其通過分區策略和隨機化選擇,最終時間復雜度能達到O(N)。
它的原理如下:

  1. 通過確定隨機數后進行三路劃分,得到<x ==x >x三個范圍,并且這個x所在位置和有序的情況是一樣的(因為快排所做的就是讓每個基準值放在對應有序的位置)。
  2. 因為第k大的元素,反過來就是len-k小的元素,在有序情況下這個元素就是對應所在下標位置。
  3. 因此,假設對應k位置的值為val,那么val大于x,就說明還需要道x的右邊區域查找(也就是再細分區域),如果val小于x,就說明要道x的左邊區域繼續查找。如果等于x就說明第k大的元素就是x。

數組中的第K個最大元素

完整代碼

class Solution {
public:int first = 0, last = 0;int findKthLargest(vector<int>& nums, int k) {//找第k大的,就是找nums.size-k小的return findKthSmall(nums, nums.size() - k);}int findKthSmall(vector<int>& nums, int i){int ans = 0;int l = 0, r = nums.size() - 1;while (l <= r){int x = nums[l + rand() % (r - l + 1)];//將x對應的有序位置進行確定partition(nums, l, r, x);//看nums[i]和x的大小關系,確定nums[i]的位置if (nums[i] > x) l = last + 1;else if (nums[i] < x) r = first - 1;else{ans = nums[i];break;}}return ans;}//三路劃分, 一定要注意劃分范圍是 >x ==x >x 不然不行void partition(vector<int>& nums, int l, int r, int x){first = l, last = r;int i = l;while (i <= last){if (nums[i] < x) swap(nums[i++], nums[first++]);else if (nums[i] > x) swap(nums[i], nums[last--]);else ++i;}}
};

為什么只能用三路劃分?partition用挖坑法行嗎?
如果是3 3 3 4 3 3 3這樣一組數找第一大的,如果采用挖坑法只能劃分<=x >=x兩個范圍,對于隨機到3而言,第一趟劃分就是不變,就無法通過比較對應i位置的大小確定第一大的數的位置。因此一定得保證劃分范圍是 >x ==x >x 。

算法中有很多精妙又美麗的思想傳統,請務必堅持下去!!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/78887.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/78887.shtml
英文地址,請注明出處:http://en.pswp.cn/web/78887.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

網絡技術基礎,NAT,橋接,交換機,路由器

什么是NAT Network Address Translation&#xff08;網絡地址轉換&#xff09;&#xff0c;它負責將目標IP或源IP進行了改變&#xff0c;相當于一個中間代理&#xff0c;我們家庭常用的路由器就是一個NAT設備&#xff0c;NAT是為了解決IPv4的IP地址快要耗盡的問題&#xff0c;…

DVWA靶場保姆級通關教程--03CSRF跨站請求偽造

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 目錄 文章目錄 前言 一、low級別的源碼分析 二、medium級別源碼分析 安全性分析 增加了一層 Referer 驗證&#xff1a; 關鍵點是&#xff1a;在真實的網絡環境中&a…

【Ansible自動化運維實戰:從Playbook到負載均衡指南】

本文是「VagrantVirtualBox虛擬化環境搭建」的續篇&#xff0c;深入探索Ansible在自動化運維中的核心應用&#xff1a; ? Ansible核心技能&#xff1a;Playbook編寫、角色&#xff08;Roles&#xff09;模塊化、標簽&#xff08;Tags&#xff09;精準控制 ? 實戰場景覆蓋&a…

基于STM32、HAL庫的STC31-C-R3氣體傳感器驅動程序設計

一、簡介: STC31-C-R3是Sensirion公司推出的一款基于CMOSens技術的CO2傳感器,具有以下特點: 測量范圍:0-100%體積濃度 I2C數字接口 低功耗設計 高精度和長期穩定性 小尺寸封裝(5mm x 5mm) 二、硬件接口: STC31-C-R3 STM32L4xx ---------------------------- VDD (P…

Nginx篇之限制公網IP訪問特定接口url實操

一、nginx配置限制IP訪問 要在 Nginx 配置中添加 IP 限制&#xff0c;阻止來自指定公網 IP 地址段的訪問&#xff0c;并且只對特定路徑進行限制&#xff0c;可以在 location 配置中使用 deny 和 allow 指令來控制訪問。 二、案例 1. 需求 對來自特定公網的地址段&#xff0…

算法研習:無重復字符的最長子串問題剖析

算法研習:無重復字符的最長子串問題剖析 一、引言 在算法的廣袤天地中,字符串相關問題一直是備受關注的焦點。“無重復字符的最長子串”這一問題,不僅在面試中頻繁出現,更是對算法思維和編程技巧的一次深度考驗。它要求我們從給定字符串中找出不含有重復字符的最長子串的長…

Spring Cloud Gateway路由+斷言+過濾

目錄 介紹核心功能三大核心Route以服務名動態獲取URLPredicate常用斷言Path Route PredicateAfter Route PredicateBefore Route PredicateBetween Route PredicateCookie Route PredicateHeader Route PredicateHost Route PredicateQuery Route PredicateRemoteAddr Route Pr…

springboot集成langchain4j記憶對話

流式輸出 LLM 一次生成一個標記&#xff08;token&#xff09;&#xff0c;因此許多 LLM 提供商提供了一種方式&#xff0c;可以逐個標記地流式傳輸響應&#xff0c;而不是等待整個文本生成完畢。 這顯著改善了用戶體驗&#xff0c;因為用戶不需要等待未知的時間&#xff0c;幾…

【SpringCloud GateWay】Connection prematurely closed BEFORE response 報錯分析與解決方案

一、背景 今天業務方調用我們的網關服務報錯: Connection prematurely closed BEFORE response二、原因分析 三、解決方案 第一步: 增加 SCG 服務的JVM啟動參數,調整連接獲取策略。 將連接池獲取策略由默認的 FIFO&#xff08;先進先出&#xff09;變更為 LIFO&#xff08…

使用ZYNQ芯片和LVGL框架實現用戶高刷新UI設計系列教程(第十一講)

這一期講解lvgl中下拉框的基礎使用&#xff0c;下拉列表允許用戶從選項列表中選擇一個值&#xff0c;下拉列表的選項表默認是關閉的&#xff0c;其中的選項可以是單個值或預定義文本。 當單擊下拉列表后&#xff0c;其將創建一個列表&#xff0c;用戶可以從中選擇一個選項。 當…

【神經網絡與深度學習】VAE 在解碼前進行重參數化

在 VAE 中&#xff0c;解碼之前進行重參數化主要有以下幾個重要原因&#xff1a; 可微分性 在深度學習里&#xff0c;模型是通過反向傳播算法來學習的&#xff0c;而這需要計算梯度。若直接從潛在變量的分布 (q_{\theta}(z|x))&#xff08;由編碼器輸出的均值 (\mu) 和方差 (…

BBDM學習筆記

1. configs 1.1 LBBDM: Latent BBDM [readme]

mysql主從復制搭建,并基于?Keepalived + VIP實現高可用

以下是基于 ?Keepalived VIP? 實現 MySQL 主從復制高可用的詳細步驟&#xff0c;涵蓋主從復制搭建與故障自動切換&#xff1a; 一、MySQL 主從復制搭建&#xff08;基礎步驟回顧&#xff09; 1. ?主庫&#xff08;Master&#xff09;配置? 修改配置文件? /etc/my.cnf&…

CD36.【C++ Dev】STL庫的string的使用 (下)

目錄 1.reserve函數(不是reverse) 代碼示例 2.resize 代碼示例 3.reserve和resize的區別 4.shrink_to_fit 代碼示例 5.與C語言的配合的接口函數: c_str 代碼示例 6.rfind 知識回顧:find函數 rfind 代碼示例 練習題: 字符串最后一個單詞的長度 代碼 提交結果 ?…

STM32的網絡天氣時鐘項目

一、項目概述與硬件架構 1.1 核心功能 本智能天氣時鐘系統集成了實時天氣獲取、網絡時間同步、環境監測和低功耗管理四大核心功能&#xff1a; 網絡數據獲取&#xff1a; 通過ESP8266 WiFi模塊連接心知天氣API&#xff08;每小時更新&#xff09;獲取北京標準時間服務器的時…

FPGA DDR4多通道管理控制器設計

DDR4控制器一般采用自帶的MIG控制器&#xff0c;用戶控制主要是基于MIG IP核進行設計 實際工程項目中可能只掛載了一組DDR&#xff0c;但是用戶數據可能有很多種&#xff0c;用戶通過給每種數據劃分特定地址進行存儲&#xff0c;如何實現靈活管理成為設計的關鍵 為了方便后端數…

低代碼 x AI,解鎖數智化應用的創新引擎

AI 智能體開發指南 隨著全球信息化浪潮的持續推進&#xff0c;數字化、智能化轉型已成為企業發展的必經之路。在這個變革的時代&#xff0c;企業面臨著前所未有的挑戰與機遇。一方面&#xff0c;市場環境瞬息萬變&#xff0c;企業需要快速響應并調整業務模式&#xff1b;另一方…

【Spring Boot 注解】@Configuration與@AutoConfiguration

文章目錄 Configuration與AutoConfiguration一、Configuration二、AutoConfiguration Configuration與AutoConfiguration 一、Configuration 這是最常用的 Spring 注解之一&#xff0c;表示當前類是一個 配置類&#xff0c;可以定義 Bean 方法&#xff0c;等效于傳統的 XML 配…

arXiv論文 MALOnt: An Ontology for Malware Threat Intelligence

文章講惡意軟件威脅情報本體。 作者信息 作者是老美的&#xff0c;單位是倫斯勒理工學院&#xff0c;文章是2020年的預印本&#xff0c;不知道后來發表在哪里&#xff08;沒搜到&#xff0c;或許作者懶得投稿&#xff0c;也可能是改了標題&#xff09;。 中心思想 介紹開源…

【存儲管理—動態不等長存儲資源分配算法】

文章目錄 一、實驗目的二、實驗內容與設計思想實驗內容設計思路 三、實驗代碼實現四、總結 一、實驗目的 理解動態異長存儲分區資源管理&#xff0c;掌握所需數據結構和管理程序&#xff0c;了解各種存儲分配算法的優點和缺點。 二、實驗內容與設計思想 實驗內容 1.分析uni…