快速排序的改進

2021-06-22 06:39:56 字數 3675 閱讀 9158

快速排序最壞情況下,要比較o(n^2)次,但平均效能為nlogn,基本達到了比較類排序所需時間的的下界。核心**為:

void qsort(int *data, int begin, int end)

int pivot, i, j;

if(begin>=end)

return;

i = begin;

j = end;

pivot = data[i];

while(iwhile(i=pivot)

j--;

data[i] = data[j];

while(ii++;

data[j] = data[i];

data[i] = pivot;

qsort(data, begin, i-1);

qsort(data, i+1, end);

一種改進:對於乙個已排好序的序列來說,插入排序應該是最快了,時間複雜度為o(n)。插入排序**為:

void isort(int *data, int begin, int end)

int i,j,tmp;

for(i=begin+1;i<=end;i++)

j = i-1;

tmp = data[i];

while(j>=begin && data[j]>tmp)

data[j+1] = data[j];

j--;

data[j+1] = tmp;        

return;

由於快速排序演算法在處理小規模資料集時表現的不是很好(可能是因為存在遞迴呼叫),因此在資料規模小到一定程度時,改用插入排序。另一方面考慮,對於大規模資料來說,前期採用的快速排序已經將一些元素放到了正確的位置上,因此當規模降低到一定程度時,可以認為一些元素已經基本有序了。對基本有序的序列進行排序,插入排序是最好的選擇,不光比較次數少,還免去了遞迴呼叫的過程。因此,第一種改進方法為:

當資料規模小於一定程度時,改用插入排序。具體小到何種規模時,採用插入排序,這個理論上還不解,一些文章中說是5到25之間。sgi stl中的快速排序採用的值是10.

第二個有改進空間的地方是:中軸元素的選取。如果簡單的只是選擇第乙個或最後乙個作為中軸元素,這樣當待排序序列基本有序的時候,它就退化為o(n^2)的時間複雜度。因此,第二中改進方法為:

可以取最左邊、最右邊、中間這三個位置的元素中的中間值作為中軸元素,來避免這種情況。

對於乙個每個元素都完全相同的乙個序列來講,快速排序也會退化到o(n^2)。要將這種情況避免到,可以這樣做:

在分割槽的時候,將序列分為3堆,一堆小於中軸元素,一堆等於中軸元素,一堆大於中軸元素,下次遞迴呼叫快速排序的時候,只需對小於和大於中軸元素的兩堆資料進行排序,中間等於中軸元素的一堆已經放好。

總結一下,主要有3點有改進空間:

1 問題降到一定規模時,改用插入排序

2 中軸元素的選取

3 分成3堆,一方面避免相同元素這種情況,另一方面也可以降低子問題的規模。這個感覺有點想dfs中尋找剪枝條件來降低搜尋規模一樣。

從以上3點出來,完成新的快速排序,**如下:

#include

#include

#define m 10

void exchange(int *data, int p1, int p2)

int tmp;

tmp = data[p1];

data[p1] = data[p2];

data[p2] = tmp;

void compexch(int *data, int p1, int p2)

if(data[p1]>data[p2])

exchange(data, p1, p2);

void isort(int *data, int begin, int end)

int i,j,tmp;

for(i=begin+1;i<=end;i++)

j = i-1;

tmp = data[i];

while(j>=begin && data[j]>tmp)

data[j+1] = data[j];

j--;

data[j+1] = tmp;        

return;

//完成一次分割槽 

int partition(int *data, int begin, int end)

int i,j,pivot; 

i = begin;

j = end;

pivot = data[i];

while(iwhile(i=pivot)

j--;

data[i] = data[j];

while(ii++;

data[j] = data[i];

data[i] = pivot;

return i;

void qsort(int *data, int begin, int end)

int pi, povit; 

int i, left, right;

if(begin >= end)

return;

if(end-begin <= m) 

isort(data, begin, end);

else

//1 選擇中軸元素,將其設定到 begin+1 的位置上 

exchange(data, begin+1, (begin+end)/2);

compexch(data, begin, begin+1);

compexch(data, begin, end);

compexch(data, begin+1, end);

//2 分割槽。此時 begin 和 end 兩個位置已經不影響本次分割槽了

pi = partition(data, begin+1, end-1);

povit = data[pi];

//3 構建等於中軸元素的中間堆

left = pi;

right = pi;

for(i=begin;iif(data[i] == povit)

exchange(data, i, --left);

for(i=end;i>right;i--)

if(data[i] == povit)

exchange(data, i, ++right);

//4 遞迴呼叫快速排序

qsort(data, begin, left-1);

qsort(data, right+1, end);        

int main()

int data[20];

int n;

int i,j;

scanf("%d",&n);

for(i=0;iscanf("%d",&data[i]);

qsort(data, 0, n-1);

for(i=0;iprintf("%d ",data[i]);

printf("\n");

system("pause");

return 0;

學習,永無止境!知道、會用乙個演算法,遠遠不夠,掌握它,改進它,and 不斷的改進它!

快速排序的改進

改寫partition演算法。要求 一次partition之後,小於基準元素key的數在左邊,等於key的在中間,大於key的在右邊 思路一 參照演算法導論上的思想,做出改進 i指向小於基準元素的序列的末尾,j指向等於基準元素的序列的末尾,k指向當前遍歷到的元素。include include us...

快速排序的改進

快速排序是用途最廣的排序演算法之一,但是在最壞的情況下快速排序會退化成直接插入排序時間複雜度也就將為了o n 2 因此快速排序的改進也就是在選擇key元素上的選擇,選取乙個中位數可以保證快速排序演算法的效率。改進方法 1.選取中衛數作為key 2.排序前可以先將key和最後乙個元素交換,將key元素...

快速排序改進

快速排序平均複雜度為o nlgn 最壞情況為o n 2 即陣列已經有序或大致有序的情況下,每次劃分只能減少乙個元素,快速排序將不幸退化為氣泡排序,所以快速排序時間複雜度下界為o nlogn 最壞情況下為o n 2 1.如果在排序時選取最後乙個元素為基準,則可以通過以下方法來避免劃分的不平衡。int ...