您好,登錄后才能下訂單哦!
快速排序是一種使用性非常強的排序算法,雖然它最壞的情況下時間復雜度O(N^2),但平均時間復雜度是O(N*logN),并在內存的使用、程序算法的復雜性上表現優秀,尤其是對快速排序進行隨機化的可能,快速排序是最使用的一種算法之一。
算法思想:
1.創建一個臨時變量,把數組中最右邊的值保存起來,最右邊就形成一個坑。
2.然后找左邊大于臨時變量的那個值放到坑里,這樣左邊會形成新的坑。
3.在找右邊小于臨時變量的那個值放到新的坑里,就這樣一直找。
4.知道找完,最后把臨時變量放到最后形成的那個坑里。
5.在把這個數組分成兩個子序列,特點:左邊的子序列中的數小于等于右邊的子序列中的數。
6.在通過遞歸調用,來排序子序列。
5.知道子序列排完,然后合并。(由于子序列是就地序列,所以合并不需要操作,排序已經完成)
實現代碼:
Sort.h中
int SingleSort(int *a, int left, int right) { assert(a); int tmp = a[right];//臨時變量保存值 while (left < right) { //找左邊大于等于tmp的數 while (left < right&&tmp >= a[left]) { left++; } if (left < right) { a[right--] = a[left];//把值給右邊,然后-- } //找右邊小于等于tmp的值 while (left < right&&tmp <= a[right]) { right--; } if (left < right) { a[left++] = a[right];//把值給左邊,然后++ } } a[left] = tmp; return left; } void QuickSort(int *arr, int left, int right) { if (arr == NULL) { return; } if (left < right) { //遞歸調用 int div = SingleSort(arr, left, right); QuickSort(arr, left, div - 1); QuickSort(arr, div + 1, right); } } //打印函數 void Print(int *arr, int size) { for (int i = 0; i < size; i++) { cout << arr[i] << " "; } cout << endl; }
test.cpp中
#include<iostream> using namespace std; #include "Sort.h" void Test() { int arr[] = { 3, 9, 7, 6, 1, 2, 4, 8, 0, 5 }; QuickSort(arr, 0,sizeof(arr) / sizeof(arr[0])-1); Print(arr, sizeof(arr) / sizeof(arr[0])); } int main() { Test(); system("pause"); return 0; }
我曾經看過看過一篇博客,快速排序對小范圍數字排序會花費很多時間,通過我查詢資料得知,數字總量小于13,用直接插入排序表較好,超過這個數字用快速排序。然后我就把代碼改了一下.
//直接插入排序 void InsertSort(int *a, int size) { int end; int tmp; for (int i = 0; i < size - 1; i++) { end = i; tmp = a[end + 1]; while (end >= 0 && tmp<a[end]) { a[end + 1] = a[end]; end--; } a[end + 1] = tmp; } } void QuickSort(int *arr, int left, int right) { if (arr == NULL) { return; } if (right < 13) { InsertSort(arr, right + 1); } else { if (left < right) { //遞歸調用 int div = SingleSort(arr, left, right); QuickSort(arr, left, div - 1); QuickSort(arr, div + 1, right); } } }
上面的代碼還不夠好,如果快速排序是,你的運氣比較差,每次取出的數都是最大或者最小,這樣的話他就會變成最壞一種情況,時間復雜度為O(N^2),為了避免這種情況,我想到一種辦法,三數取中法,
它是什么意思?
三個數分別為最左邊,最右邊,中間這三個數,取得話,就取既不是最大也不是最小的這個數,這樣就能避免上面那種情況。
//三數取中 int Mid(int *a, int left, int right) { int mid = left - (left - right); if (a[left] < a[right]) { if (a[left]>a[mid]) { return a[left]; } else if (a[right] < a[mid]) { return a[right]; } else { return a[mid]; } } else { if (a[right] > a[mid]) { return a[right]; } else if (a[left] < a[mid]) { return a[left]; } else { return a[mid]; } } } int SingleSort(int *a, int left, int right) { assert(a); int tmp = Mid(a,left,right);//臨時變量保存值,三數取中 while (left < right) { //找左邊大于等于tmp的數 while (left < right&&tmp >= a[left]) { left++; } if (left < right) { a[right--] = a[left];//把值給右邊,然后-- } //找右邊小于等于tmp的值 while (left < right&&tmp <= a[right]) { right--; } if (left < right) { a[left++] = a[right];//把值給左邊,然后++ } } a[left] = tmp; return left; }
這樣就比較完善了,如果我不想用遞歸,該這么辦那?然后我就想到了借助棧來實現。
void QuickSort(int *arr, int left, int right) { stack<int> s; s.push(left);//壓棧數組的左下標 s.push(right);//壓棧數組的有下標 while (!s.empty()) { int tmpRight = s.top(); s.pop(); int tmpLeft = s.top(); s.pop(); //把數組排序成左區間的數小于等于有區間的數 int div = SingleSort(arr, tmpLeft, tmpRight); //壓棧左區間的左右兩個數的下標 if (tmpLeft < div - 1) { s.push(tmpLeft); s.push(div - 1); } //壓棧右區間的左右兩個數的下標 if (div + 1 < tmpRight) { s.push(div + 1); s.push(tmpRight); } } }
寫到這里,我有想到了另一種實現SingleSort()函數的方法,感覺比上面的更簡單,不過理解起來比較抽象。
思想:
1.定義一個cur為a[0]位置的下標
2.在定義一個prev為a[0]的前一個位置。
3.當a[0]位置的值小于最右邊的值。
4.++prev,然后交換prev和cur對應的值。
5.如果小于最右邊的值,++prev,prev和最右邊值交換。
6.一直進行下去,就會讓左邊的值小于等于右邊的值。
int SingleSort(int *arr, int left, int right) { int cur = left; int prev = cur - 1; int key = Mid(arr, left, right); swap(arr[right], key);//把key的值放到最右邊 while (cur < right) { //++prev != cur防止自己和自己交換 if (arr[cur]<=arr[right]&&++prev != cur) { swap(arr[prev], arr[cur]); } cur++; } swap(arr[++prev], arr[right]); return prev; }
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。