【資料結構】快速排序(遞迴)
阿新 • • 發佈:2018-12-19
概念: 快速排序是Hoare於1962年提出的一種二叉樹結構的交換排序方法。
基本思想為:任取待排序元素序列中的某元素作為基準值,按照該排序碼將待排序集合分割成兩子序列,左子序列中所有元素均小於基準值,右子序列中所有元素均大於基準值,然後最左右子序列重複該過程,直到所有元素都排列在相應位置上為止。
將區間按照基準值劃分為左右兩半部分的常見方式有:
1. hoare版本
具體程式碼如下:
//hoare版本 void Swap(int* a, int* b) { int tmp = *a; *a = *b; *b = tmp; } int PartSort1(int* a, int begin, int end) { int key = a[0]; int start = begin; while (begin < end) { //end從後面走,找到比key小的就停下來 while (begin < end && a[end] >= key) { end--; } //begin從前面走,找到比key大的就停下來 while (begin < end && a[begin] <= key) { begin++; } //交換begin和end Swap(&a[begin], &a[end]); } //此時begin和end相遇 Swap(&a[begin], &a[start]); return begin; } void QuickSort(int* a, int left, int right) { if (left >= right) { return; } int div = PartSort1(a, left, right); //在以div為基準的左邊區間去找新的key //左邊區間:[left,div-1] QuickSort(a, left, div - 1); //在以div為基準的右邊區間去找新的key //右邊區間:[div+1,right] QuickSort(a, div + 1, right); }
優化後的程式碼:
int GetMidIndex(int* a, int begin, int end) { int mid = begin + ((end - begin) >> 1); if (a[begin] < a[mid]) { if (a[mid] < a[end]) { return mid; } else if (a[begin]>a[end]) { return begin; } else//end<mid { return end; } } else//begin>mid { if (a[mid] > a[end]) { return mid; } else if (a[begin] < a[end]) { return begin; } else//end>mid { return end; } } } //為防止所給資料直接有序,進行三數取中的優化 int PartSort(int* a, int begin, int end) { //三數取中 int midindex = GetMidIndex(a, begin, end); Swap(&a[begin], &a[midindex]); int key = a[begin]; int start = begin; while (begin < end) { //end從後面走,找到比key小的就停下來 while (begin < end && a[end] >= key) { end--; } //begin從前面走,找到比key大的就停下來 while (begin < end && a[begin] <= key) { begin++; } //交換begin和end Swap(&a[begin], &a[end]); } //此時begin和end相遇 Swap(&a[begin], &a[start]); return begin; } //小區間優化 void QuickSort(int* a, int left, int right) { if (left >= right) { return; } if ((right - left + 1) < 10) { InsertSort(a + left, right - left + 1); } else { int div = PartSort(a, left, right); //在以div為基準的左邊區間去找新的key //左邊區間:[left,div-1] QuickSort(a, left, div - 1); //在以div為基準的右邊區間去找新的key //右邊區間:[div+1,right] QuickSort(a, div + 1, right); } }
2.挖坑法
具體程式碼:
//挖坑法 int PartSort2(int* a, int begin, int end) { int key = a[begin]; while (begin < end) { //end找比key小的資料 while (begin < end && a[end] >= key) { end--; } //當end找到比key小的資料後,用此時的end填begin這個坑,end就變成了新的坑 a[begin] = a[end]; //begin找比key大的資料 while (begin < end && a[begin] <= key) { begin++; } //當begin找到比key大的資料後,用此時的begin填end這個坑,begin又變成了新的坑 a[end] = a[begin]; } a[begin] = key; return begin; } void QuickSort2(int* a, int left, int right) { if (left >= right) { return; } int div = PartSort(a, left, right); //在以div為基準的左邊區間去找新的key //左邊區間:[left,div-1] QuickSort(a, left, div - 1); //在以div為基準的右邊區間去找新的key //右邊區間:[div+1,right] QuickSort(a, div + 1, right); }
3.前後指標
具體程式碼如下:
//前後指標法
int PartSort3(int* a, int begin, int end)
{
int key = a[begin];
int prev = begin;
int cur = begin + 1;
while (cur <= end)
{
if (a[cur] < key && (++prev) != a[cur])//當cur小於key時,且++prev的值不等於cur的值時,才發生交換,當cur>key時,不交換,繼續向前走
{
Swap(&a[prev], &a[cur]);
}
cur++;
}
Swap(&a[begin], &a[prev]);
return prev;
}
void QuickSort(int* a, int left, int right)
{
if (left >= right)
{
return;
}
int div = PartSort3(a, left, right);
//在以div為基準的左邊區間去找新的key
//左邊區間:[left,div-1]
QuickSort(a, left, div - 1);
//在以div為基準的右邊區間去找新的key
//右邊區間:[div+1,right]
QuickSort(a, div + 1, right);
}
以上就是快速排序遞迴的幾種思想及程式碼,
注:需要說明的是,如果要在vs下面執行的話,得有標頭檔案,交換函式和測試資料等等,直接是執行不出來的.