人妖在线一区,国产日韩欧美一区二区综合在线,国产啪精品视频网站免费,欧美内射深插日本少妇

新聞動(dòng)態(tài)

Linux靜態(tài)鏈接庫(kù)使用類模板的快速排序算法

發(fā)布日期:2022-04-26 12:11 | 文章來(lái)源:gibhub

快速排序的本質(zhì)是從數(shù)組中選一個(gè)參考值ref,比該參考值的大的,將其放在ref的右邊,比ref小的放在左邊,然后不斷的對(duì)兩邊重復(fù)執(zhí)行該動(dòng)作

我們先列出來(lái)快速排序的步驟:

1.從數(shù)組中選一個(gè)參考值ref,比該參考值的大的,將其放在ref的右邊,

上面的動(dòng)作將數(shù)組劃分為兩部分:

A ref B

A是比ref小的數(shù)組元素集合,它仍然是數(shù)組,B是比ref大的元素集合,它也仍然是數(shù)組

2.在對(duì)ref左右兩邊的元素重復(fù)上述動(dòng)作,直到A和B都只剩下一個(gè)元素,那么排序就算完成了。

重點(diǎn)是如何分別選出來(lái)兩個(gè)集合A和B。算法導(dǎo)論里面把這個(gè)步驟叫做partition動(dòng)作。

先把算法導(dǎo)論里面的偽代碼貼出來(lái),大家先看一下:

先看第一種ref的選擇方法,即ref = a[r]

partition(a[], p, r)
{
i = p
j = p-1
ref = a[r]
for(; i<r; i++)
{  
if(a[i]<ref)
{
j++
exchange(a[i], a[j])
}
}
exchange(a[r], a[j+1])
return j+1;
}

首先找一個(gè)參考值,ref = a[r],為了簡(jiǎn)單起見(jiàn),這里取最后一個(gè)作為參考值,實(shí)際上可以去任意一個(gè)值作為參考值。這個(gè)我們一會(huì)再說(shuō)。

然后找定義兩個(gè)游標(biāo),分別是i 和j。i=p, j=p-1。為什么要這么定義呢?原因是我們既然選的是第一個(gè),也就是a[p],同時(shí)表示是從數(shù)組的第一個(gè)元素開(kāi)始遍歷的。

選取j的目的是,我們要時(shí)刻知道當(dāng)前最近一次比ref小的值的位置。由于我們選取的是a[r],作為參考值,且從第一個(gè)元素開(kāi)始遍歷,為了跟蹤最近一次比ref小的數(shù)的游標(biāo),暫時(shí)j=p-1。大家可以仔細(xì)體會(huì)一下這個(gè)做的意義。

觀察上述代碼可以看到,j總是記錄著最近一次比ref小的數(shù)的游標(biāo),因此最后return j+1,所有比ref小的數(shù)的游標(biāo)均小于j+1,所有比ref大的數(shù)的游標(biāo)均大于j+2。

總之我們執(zhí)行partition的目的就是為了得到A,B,以及中間數(shù)的游標(biāo),這樣我們就可以分別對(duì)A和B重復(fù)執(zhí)行上述動(dòng)作。

接下來(lái)我們考慮另外兩種選取ref的方法。從上面選取最后一個(gè)值a[r],作為參考值,并且在最后,將a[r]和a[j+1]交換的動(dòng)作可以知道,我們總是希望知道我們選取參考值在partition過(guò)程中的位置,以便我們可以在最后一步,將a[refId] 和 a[j+1]的值交換。這里的refId表示選取ref值在a[]中的游標(biāo)。

如果我們選取ref為最后一個(gè)值,那么在所有的partition過(guò)程中,這個(gè)值的位置是固定的。但是,假如我們選取的ref的refId是p到r范圍內(nèi)的一個(gè)隨機(jī)數(shù)呢?

顯然,假如我們隨機(jī)選取ref的值,那么在partition過(guò)程中,refId對(duì)于的ref就有可能和其他值交換。這時(shí)候我們就需要更新ref對(duì)應(yīng)的游標(biāo)。

這樣一來(lái),思路就很清晰了。

先給出partition的偽代碼:

partition(a[], p, r){
refId = random(p,r)
i = p
j = p-1
for(; i<=r; i++)
{
if(a[i]<ref)
{
j++ if(j == refId)//此時(shí)j剛好等refId,并且要和a[i]交換,則更新refId { refId = i }
exchange(a[i], a[j])
}
}
exchange(a[j+1], a[refId])
return j+1
}

從三種選擇ref的方法可以看到本質(zhì)上都是一樣的,都為用一個(gè)游標(biāo)j記錄最近一次遍歷到的比ref小的數(shù)據(jù)的游標(biāo),然后將ref和a[j+1]交換,返回j+1。

下面給出C++的代碼實(shí)現(xiàn)

#include <iostream>
#include <stack>
#include"stdlib.h"
#include <time.h>
using namespace std;
template<class T>
class SORT
{
public:
static void myQsort(T a[], int p, int r);
static void myQsortNoRecur(T a[], int p, int r);
private:
static int partition(T a[], int p, int r);
static void exchange(T a[], int i, int j);
};
template<class T>
void SORT<T>::exchange(T a[], int i, int j)
{
T temp = a[i];
a[i] = a[j];
a[j] = temp;
return;
}
template<class T>
int SORT<T>::partition(T a[],int p,int r)
{
int i = p;
int j = p-1;
T ref = a[p];
int refId = p;
srand((unsigned)time(NULL));
refId = (rand() % (r-p+1))+ p;
//cout<<refId<<endl;
ref = a[refId];
for(; i<=r; i++)
{
if(a[i] < ref)
{
j++;
exchange(a, i, j);
if(j == refId)
{
refId = i;
}
}
}
exchange(a, j+1, refId);
return j+1;
}
template<class T>
void SORT<T>::myQsort(T a[],int p,int r)
{
int q = 0;
if(p<r)
{
q = partition(a, p, r);
myQsort(a, p, q-1);
myQsort(a, p+1, r);
}
return;
}
template<class T>
void SORT<T>::myQsortNoRecur(T a[], int p, int r)
{
int start = p;
int end = r;
int mid = 0;
std::stack<int> sortStk;
sortStk.push(p);
sortStk.push(r);
while(!sortStk.empty())
{
end = sortStk.top();
sortStk.pop();
start = sortStk.top();
sortStk.pop();
if(start < end)
{
mid = partition(a, start, end);
sortStk.push(start);
sortStk.push(mid -1);
sortStk.push(mid + 1);
sortStk.push(end);
}
}
}
int main(int argc, char** argv)
{
int a[10];
int b[10];
srand((unsigned)time(NULL));
for(int i=0; i<9; i++)
{
a[i] = rand();
}
srand((unsigned)time(NULL));
for(int i=0; i<9; i++)
{
b[i] = rand();
}
SORT<int>::myQsort(a,0, 9);
SORT<int>::myQsortNoRecur(b,0, 9);
for(int i=0; i<10; i++)
{
cout<<a[i]<<" ";
}
cout<<endl;
for(int i=0; i<10; i++)
{
cout<<b[i]<<" ";
}
return 0;
}

上面的代碼我直接給出了快速排序的遞歸和非遞歸實(shí)現(xiàn)。
遞歸的實(shí)現(xiàn)方式很好理解,但是加入別人正在面試你快速排序算法的時(shí)候,多半會(huì)讓你用非遞歸的方式實(shí)現(xiàn)給他看。下面我們就討論一下。

先觀察一下遞歸算法的運(yùn)行過(guò)程,即每次都去對(duì)一段更小的范圍去調(diào)用partition函數(shù)。所以我們需要知道每一次調(diào)用partition函數(shù)的start和end游標(biāo),同時(shí),每一次partition調(diào)用都會(huì)產(chǎn)生新的start和end游標(biāo)。

template<class T>
void SORT<T>::myQsort(T a[],int p,int r)
{
int q = 0;
if(p<r)
{
q = partition(a, p, r);
myQsort(a, p, q-1);
myQsort(a, p+1, r);
}
return;
}

這樣的話,我們就可以用一個(gè)通用容器去存放每次調(diào)用partition生成的start和end游標(biāo)。知道雖有的合法的start和end游標(biāo)都作為參數(shù)調(diào)用了partition函數(shù)。所謂合法的start和end就是start < end。。。。。

關(guān)于遞歸算法的非遞歸實(shí)現(xiàn),第一個(gè)想到的數(shù)據(jù)結(jié)構(gòu)肯定是棧。其實(shí)別的數(shù)據(jù)結(jié)構(gòu),例如隊(duì)列,也是可以實(shí)現(xiàn)。這里給出基于stl內(nèi)的stack的實(shí)現(xiàn)方法。代碼如下

template<class T>
void SORT<T>::myQsortNoRecur(T a[], int p, int r)
{
int start = p;
int end = r;
int mid = 0;
std::stack<int> sortStk;
sortStk.push(p);
sortStk.push(r);
while(!sortStk.empty())
{
end = sortStk.top();
sortStk.pop();
start = sortStk.top();
sortStk.pop();
if(start < end)
{
mid = partition(a, start, end);
sortStk.push(start);
sortStk.push(mid -1);
sortStk.push(mid + 1);
sortStk.push(end);
}
}
}

上面代碼的運(yùn)行過(guò)程就是每次循環(huán),從容器內(nèi)拿一個(gè)start和end,如果是合法的,就依次將他們?cè)俅畏湃肴菀?,知道這個(gè)容器為空未知。

給個(gè)運(yùn)行實(shí)例吧,我在代碼里面實(shí)現(xiàn)的是實(shí)現(xiàn)隨機(jī)數(shù)排序,ref采用隨機(jī)選取的方式。

版權(quán)聲明:本站文章來(lái)源標(biāo)注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請(qǐng)保持原文完整并注明來(lái)源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非www.sddonglingsh.com所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來(lái)源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來(lái),僅供學(xué)習(xí)參考,不代表本站立場(chǎng),如有內(nèi)容涉嫌侵權(quán),請(qǐng)聯(lián)系alex-e#qq.com處理。

相關(guān)文章

實(shí)時(shí)開(kāi)通

自選配置、實(shí)時(shí)開(kāi)通

免備案

全球線路精選!

全天候客戶服務(wù)

7x24全年不間斷在線

專屬顧問(wèn)服務(wù)

1對(duì)1客戶咨詢顧問(wèn)

在線
客服

在線客服:7*24小時(shí)在線

客服
熱線

400-630-3752
7*24小時(shí)客服服務(wù)熱線

關(guān)注
微信

關(guān)注官方微信
頂部