快速排序--全集

快速排序:一聽名字就知道這種排序很快的,是吧?沒錯,它是一種效率比較高的排序算法。

快速排序采用的是分治的思想。

比如,將一串數中的一個元素作為基準,然后將比它小的數排在它的左邊,比它大的數排在它的右邊。將作為基準的那個元素排在正確的位置。然后通過遞歸,依次將所有的元素都排好。(實質就是遞歸子問題)

在這里,快速排序也有幾種不同的方式,下面我給大家一一敘述吧。

快速排序的幾種方法:

1.左右指針法(交換):
?????? 有一個數組a[size],左指針left指向下標為0的位置,右指針right指向下標為size-1的位置,同時標志key=a[right];left找a[left]>key的元素的下標,right找a[right] < key的元素的下標。left先開始走,當遇到比key大的數時,停下來,再由right開始走,當遇到比key小的數時,停下來。將left和right分別指的數交換,前提是left<right時,如果left>=right就說明一次快排結束。再將left指向的值與key值交換即可。此時的數組呈現出左邊的值都比key值小,右邊的值都比key值大。一次快排將數組分為兩個區間,我們再對每個區間進行上述的排序方式。直到每個小區間已不能再劃分。(即一個區間只有兩個元素)



代碼實現:

int PartSort(int* a,int left,int right)
{int& key = a[right];//int key = right;while(left < right) {while(left < right && a[left] <= key) //a[left] <= a[key]++left;while(left < right && a[right] >= key) //a[right] >= a[key]--right;swap(a[left],a[right]);}swap(a[left],key);//swap(a[left],a[key]);return left;
}
void QuickSort(int* a,int left,int right)
{if(left < right){int div = PartSort(a,left,right);QuickSort(a,left,div-1);QuickSort(a,div+1,right);}
}
void Display(int *a,size_t size)
{for(size_t i = 0; i < size; ++i){cout<<a[i]<<" ";}cout<<endl;
}


2.挖坑法
?????? 有一個數組a[size],左指針left指向下標為0的位置,右指針right指向下標為size-1的位置,同時標志key=a[right];首先將key的位置設為一個坑,從left開始,找比key值大的,找到后將a[left]放到坑里,即a[right]=a[left],同時將left的位置再設為坑;再從right開始找比key小的,找到后將a[right]放到上次設的坑里,即a[left]= a[right];直到left>=right,將key值放到現在的坑中即可。此時的數組呈現出左邊的值都比key值小,右邊的值都比key值大。一次快排將數組分為兩個區間,我們再對每個區間進行上述的排序方式。直到每個小區間已不能再劃分。(即一個區間只有兩個元素)



代碼實現:

int PartSort1(int* a,int left,int right)
{int key = a[right];while(left < right) {while(left < right && a[left] <= key) ++left;a[right] = a[left];while(left < right && a[right] >= key) --right;a[left] = a[right];}a[left] = key;return left;
}
void QuickSort(int* a,int left,int right)
{if(left < right){int div = PartSort1(a,left,right);QuickSort(a,left,div-1);QuickSort(a,div+1,right);}
}


3.前后指針法
????? 有一個數組a[size],指針cur指向0的位置,prev指向cur-1的位置,key為a[size-1];當cur對應的值大于key值時,cur++,然后將++prev對應的值與cur對應的值交換。繼續比它大的值就跳過,找到a[cur]<key的值時,交換a[cur]和a[++prev]的值。直到cur指向最后一個元素,此時將a[++prev]和最后一個元素交換。此時的數組呈現出左邊的值都比key值小,右邊的值都比key值大。一次快排將數組分為兩個區間,我們再對每個區間進行上述的排序方式。直到每個小區間已不能再劃分。(即一個區間只有兩個元素)



代碼實現:

int PartSort2(int* a,int left,int right)
{int key = a[right];int cur = left;int prev = cur-1;while(cur < right){if(a[cur] < key && ++prev != cur)swap(a[cur],a[prev]);++cur;}swap(a[++prev],a[cur]);return prev;
}
void QuickSort(int* a,int left,int right)
{if(left < right){int div = PartSort2(a,left,right);QuickSort(a,left,div-1);QuickSort(a,div+1,right);}
}


以上就是快速排序的幾種方法。

當然,分析過時間復雜度和空間復雜度之后,在某些特定的情況下,快速排序依然不是很快。下面就給大家介紹幾種快速排序優化后的算法。

1.三數取中法

????? 在快排算法中,如果數組本來就有序,key值就不會是中間的數字,那么快排每次遍歷N次,時間復雜度就為O(N*N)為了避免快排遇到最壞的情況,我們采用三數取中法的方式,取到中間值的數與最后一個數交換,再進行快排方式。 這樣可以使數組的key值都在較中間的位置,趨向于二叉樹結構。時間復雜度也將提升到N*lgN。

代碼實現:

//三數取中法
int MidNum(int* a,int left,int right)
{int mid = left+((right-left)>>1);if(a[mid] < a[right]){if(a[mid] < a[right])return mid;else if(a[left] < a[right])return right;elsereturn left;}else{if(a[left] < a[right])return left;else if(a[mid] < a[right])return right;elsereturn mid;}
}int PartSortMid(int* a,int left,int right)
{int MidKey = MidNum(a,left,right);swap(a[MidKey],a[right]);int key = right;while(left < right){while(left < right && a[left] <= a[key])    //左邊如果比key位置的數小,則跳過++left;while(left < right && a[right] >= a[key])   //右邊如果比key位置的數大,則跳過--right;swap(a[left],a[right]);}swap(a[left],a[key]);return left;
}
void QuickSort(int* a,int left,int right)
{if(left < right){int div = PartSortMid(a,left,right);	QuickSort(a,left,div-1);QuickSort(a,div+1,right);}
}


2.小區間優化

????? 對于上述三數取中法的快排算法,每次都是將一小段區間進行快排算法,即使區間很小也重復快排算法。我們前面學過 插入算法,當數組接近有序時,時間復雜度就為O(N),那么在快排算法中,我們可以對小區間進行優化,區間很小時,我們可以將數組視為接近有序,此時用插入排序來代替快排,比如當right-left<一個小區間的值時(自己規定,一般為13或20較好),這樣就大大提高了快排的效率。

代碼實現:

//小區間優化
void QuickSort(int* a,int left,int right)
{if(left < right){if(right - left < 3)     //當區間比較小,接近有序時,適合使用插入排序{InsertSort(a,right-left+1);}int div = PartSort(a,left,right);QuickSort(a,left,div-1);QuickSort(a,div+1,right);}
}


1.之前寫的快排都是遞歸實現的。我們也可以用非遞歸實現快速排序。這里會用到棧。

代碼實現:

//用棧實現
#include<stack>
int MidNum(int* a,int left,int right)
{int mid = left+((right-left)>>1);if(a[mid] < a[right]){if(a[mid] < a[right])return mid;else if(a[left] < a[right])return right;elsereturn left;}else{if(a[left] < a[right])return left;else if(a[mid] < a[right])return right;elsereturn mid;}
}int PartSortMid(int* a,int left,int right)
{int MidKey = MidNum(a,left,right);swap(a[MidKey],a[right]);int key = right;while(left < right){while(left < right && a[left] <= a[key])++left;while(left < right && a[right] >= a[key])--right;swap(a[left],a[right]);}swap(a[left],a[key]);return left;
}void QuickSortNonR(int *a,int left,int right)
{stack<int> st;st.push(right);st.push(left);while(!st.empty()){if(right-left < 3)InsertSort(a,right-left+1);left = st.top();st.pop();right = st.top();st.pop();int div = PartSortMid(a,left,right);if(div-1 > left){st.push(div-1);     //注意入棧順序st.push(left);}if(div+1 < right){st.push(right);st.push(div+1);}}
}

運行結果:




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

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

相關文章

task_struct結構體查找

網上有很多解析task_struct結構體的文章&#xff0c;可是都沒有說這個結構體到底在哪里&#xff1f; 這個結構體位于頭文件 shced.h cd / find -name sched.h 顯示結果如下 注意只有 位于內核中的include 才是正確的。 /usr/src/kernels/2.6.32-431.el6.i686/include/linux…

使用python 創建快捷方式

import os import pythoncom from win32com.shell import shell from win32com.shell import shellcondef set_shortcut(): # 如無需特別設置圖標&#xff0c;則可去掉iconname參數try:filename r"D:\AppServ\timer\win_cron_zq\timer.exe" # 要創建快捷方式的文件…

python 各個模塊的簡單介紹 轉載

轉自 https://www.jianshu.com/p/f8c43e25c02e

鬧鐘函數alarm()的解釋與實踐

alarm 定義 也稱為鬧鐘函數&#xff0c;它可以在進程中設置一個定時器&#xff0c;當定時器指定的時間到時&#xff0c;它向進程發送SIGALRM信號。可以設置忽略或者不捕獲此信號&#xff0c;如果采用默認方式其動作是終止調用該alarm函數的進程。 #include "head.h&quo…

Linux下如何設置權限讓用戶只刪除自己的文件(粘滯位)

之前我們知道如何針對用戶和用戶組來設置文件權限。通常是用三個八進制來設置權限的&#xff0c;這里我要說的是&#xff0c;其實是由四個八進制表示的。其中第一個八進制我們通常是忽略的。第二個到第四個是對應于SUID,SGID,sticky-bit。 SUID&#xff1a;設置了SUID 位的文件…

CentOS安裝yum 鏡像 舉例阿里云鏡像

如何安裝yum 鏡像 CentOS 1、備份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 2、下載新的CentOS-Base.repo 到/etc/yum.repos.d/ CentOS 5 wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-5.r…

python在ubuntu執行sh腳本,提示權限不夠的解決方法, 轉載

https://blog.csdn.net/weixin_40320794/article/details/81772194

Vim簡單配置

vim配置&#xff1a; &#xff08;在Centos6.5下配置vim&#xff09; 1.找到用戶的主工作目錄&#xff0c;ls看是否有.vimrc文件&#xff0c;有的話打開即可。沒有的話自己touch一個。vim進入.vimrc中&#xff1a; set nu 設置行數 colorscheme desert syntax enabl…

運算符面試題(劍指offer,面試寶典,牛客網)

利用一個宏實現兩個數的交換&#xff1f;不使用if,?,switch或者其他判斷語句比較兩個變量的大小&#xff1f;利用位運算實現加法&#xff1f;以下程序輸出結果是&#xff1f;用位運算實現求平均數&#xff1f;不用循環判斷一個數是不是2的N次方&#xff1f; 利用一個宏實現兩個…

js 出現 replace 無法完全替換 指定字符串的時候的解決辦法

/{/g 通過這種方式替換掉 replace( /這里填寫需要被替換的字符串/g , "");

[WPS筆試題]實現棧的push,pop,max且時間復雜度為O(1)

今天做了一下WPS的筆試題&#xff0c;遇到了一道關于棧的題&#xff0c;覺得挺有意思的&#xff0c;就寫篇博客分享一下吧~~ 題目要求&#xff1a;要求實現棧的數據結構&#xff0c;在該類型中實現一個能夠得到棧的最大元素的max函數&#xff0c;在該棧中&#xff0c;調用max,…

MarkDown生成目錄索引

123 在第一行開頭寫[TOC] 必須是第一行&#xff0c;不可以在前面加別的東西。 1 2 3

ubuntu 如何用root身份進行登錄

公司有個小項目, 需要用python調用 sh腳本來執行一些東西, 執行腳本的時候需要輸入密碼 類似 sudo S paaswd 腳本, 但是給客戶部署的話, 再讓客戶客戶 保存密碼到配置文件, 就顯得麻煩, 就想到用root方式去登陸系統, 結果用了網上的方法, 還是登陸不進去, 最后結合簡書的一個方…

[劍指Offer]替換空格

今天看題的時候&#xff0c;遇到一個替換空格的題目&#xff0c;分析一下哈。 題目要求&#xff1a;把字符串中的每個空格替換成“%20”。例如輸入“we are happy”&#xff0c;則輸出“we%20are%20happy”。 解題思路&#xff1a;我們首先想到的是&#xff1a;移位思想。遇到…

C語言關鍵字 ISO/ANSI C90 C99 C11

面試考點 https://blog.csdn.net/csdn_kou/article/details/81113215 * 有的常用的我們都不知道是關鍵字&#xff0c;比如sizeof.這是面試中的考點&#xff0c;要注意。 * 同時當回答C語言中有多少關鍵字時&#xff0c;要回答前題條件&#xff0c;時針對哪一個版本

vm15 安裝 mac虛擬機的過程 轉載的

https://blog.csdn.net/weixin_43299649/article/details/82881567

task_struct解析

task_struct是Linux內核的一種數據結構&#xff0c;它用task_struct結構體來描述進程的信息。下面來剖析一下進程中保存的主要的信息有哪些&#xff1f; struct task_struct {//進程的運行時狀態volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */void …

ubuntu上有個小項目 ,需要調用xx.sh腳本, 出現無法識別 某些環境變量的解決辦法,僅供參考

項目是用python 調用 同事寫好的 xx.sh腳本&#xff0c; 在手動調用的時候 發現能正常調用&#xff0c; 當用python代碼的時候&#xff0c; 就不行了&#xff0c; 通過日志發現&#xff0c; python調用的時候 不識別 ADNROID_NDK這個環境變量&#xff0c; 在python中 我是通過&…

關于sudo

之前&#xff0c;我們使用sudo的時候&#xff0c;是因為其用戶本身具有root權限&#xff0c;所以可以sudo后執行相關操作&#xff0c;但是對于普通用戶來說&#xff0c;它是既不具有sudo權限&#xff0c;又不在sudo用戶組中&#xff0c;那么我們來研究一下如何將新創建的用戶添…