快速排序是很常用的排序方法,它的時間複雜度較理想,平均時間複雜度為o(nlogn)(注:最壞情況下時間複雜度與氣泡排序相同,都是o(n²))。快速排序的本質是二分思想:將一系列數按照某個基準,分為大於它的數和小於它的數,將這兩組數分出來後,再用遞迴的思想使用相同的一段**再次分數,直到最後完成排序。
選擇乙個基準數;基準就是判斷標準,它決定了大於它和小於它的數會在每一次遞迴快速排序中被分到基準的兩側(這兩側在下一次遞迴中分開處理);一般情況下,基準可以任選,只要它出現在了所需要排序的數字中即可,一般選擇陣列的第乙個元素作為基準,簡單方便;
設計交換方法:這裡需要使用兩個迭代器(即for迴圈中的i和j),想象它們是哨兵;兩個哨兵指向陣列的[0]和最後乙個元素,讓遠離基準一側的哨兵首先工作:它通過while或for來檢測它每一步遇到的陣列元素的大小,如果元素比基準大,那麼繼續走下一步(這種元素不需要交換,因為它們比基準大,它們現在的位置就是合理的位置);如果比基準小,那麼停下來;接下來讓基準那一側的哨兵出發,檢測遇到的數,如果小於基準,則跳過;如果大於基準,則停下來;當兩個哨兵沒有相遇的時候(使用if判斷i!=j),則交換它們指向的元素。
重複交換步驟多次,直到兩個哨兵相遇(用while迴圈控制),當哨兵相遇的時候(i==j),表明這個時候已經找到了基準應該在的位置,因此讓基準與這個位置交換,令基準就位,這時,基準和它兩邊的數都已經初步就位了(表現在基準左側都小於基準,右側皆大於基準)。注意,這並不表明基準左右兩側已經擁有正確的順序,只是說大小關係;即1、4、2都在基準6的左邊,但是不能確定2比4小就以為2在4的左邊;
遞迴,將基準左側和基準右側的元素分別使用遞迴來處理;
這種演算法的思想可以理解為不斷地將每一次遞迴的基準放到中間,要明白每一次遞迴的基準都是在改變的(每一次遞迴都將子集的第乙個元素作為基準)
特別注意:必須讓遠離基準一側的』哨兵』先走,否則你得到的結果是不正確的[解釋見下]
每一次排序是為了將基準放到它應該在的位置,對其他元素的移動是為了滿足大小順序要求,並不是為了使基準外的其他元素有正確的順序,只是希望他們滿足大小關係而已
考慮這種情況:當i和j相遇前的最後乙個元素是小於基準的情況。
先說結果:如果基準這一側的哨兵現行,會導致錯過『基準應有的位置』,導致基準會被交換到乙個不正確的位置,並且這個位置上的數交換到基準的位置之後,會使得基準兩側的大小關係不正確;
例子:我寫了乙個簡單的示例描述這種問題:為了簡單明瞭地描述這個問題,我僅僅使用了快速排序的第一步來描述,並沒有進入到遞迴的環節,因為問題就出在第一步,而且遞迴裡面也是這種問題的重複而已;
對它們排序:6,1,2,7,9,3,4,5,10,8:
[不論使用遠離一側還是靠近基準一側的哨兵先行,前幾步排序的結果是相同的]:如下:進行第一次交換:得到6,1,2,5,9,3,4,7,10,8(5和7交換)
第二次:得到6,1,2,5,4,3,9,7,10,8(4和9交換)
此時焦點聚集到中間的三個數字:4,3,9,此時i指向4且j指向9。
問題出現了:如果錯誤地讓i先走,則此時i依次讀取4、3、9三個數,我們把4稱為i,3稱為i+1而9稱為j,此時i+1小於基準(數值6),因此被跳過,而i遇到j的時候停止移動,不僅是因為j大於基準,還因為兩個哨兵相遇必須停止(因為哨兵相遇表明基準就應該交換到這裡)。這時按照哨兵相遇時的處理辦法,將這個位置與哨兵交換,得到結果就是j與陣列[0]交換(即j的位置與基準交換,注意此時i == j),最終結果就是乙個大於基準的數跑到了基準的左側,導致快速排序錯誤失敗。
總結:當哨兵相遇之前,如果出現相遇位置的數值剛好讓左側哨兵跳過了,那麼實際相遇位置不是正確的應該的相遇位置
解決:讓遠離基準一側的哨兵先行可以完全避免這種邏輯上的問題
/*
class:quicksort
author:zhy
ide:windows 10 vscode
complire:mingw(gcc-4.8.1)
*/#include
#include
//交換陣列的元素
int swap_array_value(int *a,int *b)
/*quicksort*/
//注意,該函式使用了遞迴,請小心你的堆疊空間的大小、空間複雜度
int quick_sort(int left,int right,int arr)
if(i >= j)
base_value = arr[base]; //(在每一次遞迴的陣列中)取得基準數值
while(i != j) //左右兩側的'哨兵'相遇的時候,停止,因為此時已經成功令基準就位
/*跳出while迴圈,此時i == j*/
}/*將基準放到它應該在的位置,將基準與i做交換*/
swap_array_value(arr+base,arr+i);
/*可以實現同樣的交換功能的**:*/
//arr[base] = arr[i];
//arr[i] = base_value;
/*相同:*/
//swap_array_value(arr+base,arr+j);
//遞迴,將基準左側的所有元素作為乙個新的範圍再進行一次步驟相同的快速排序
quick_sort(left,i-1,arr); //注意,此時基準的位置就是i的位置,不再是base了
quick_sort(i+1,right,arr);
return0;}
int main(int argc,char *argv)
; quick_sort(0,sizeof(arr)/sizeof(int)-1,arr);
//注意,第二個引數必須減一,否則超出緩衝區
for(iter=0;iterprintf("%d\t",arr[iter]);
return
0;}
快速排序思想及C 實現
ste p1.step 1.step1.通過一趟排序把資料分成兩部分,其 中 color 其中一部分的所有資料都要比另一部分的所有資料小,基準資料 稱為樞軸 排在這兩個子串行的中間 s te p2.step 2.step2.對這兩個子串行遞 歸 color 遞迴地呼叫排序演算法 int partit...
快速排序原理及C 實現
原理 快速排序,說白了就是給基準資料找其正確索引位置的過程.如下圖所示,假設最開始的基準資料為陣列第乙個元素23,則首先用乙個臨時變數去儲存基準資料,即tmp 23 然後分別從陣列的兩端掃瞄陣列,設兩個指示標誌 low指向起始位置,high指向末尾.首先從後半部分開始,如果掃瞄到的值大於基準資料就讓...
快速排序 C與C 實現
題目 隨機產生10個0 9的整數,用快速排序法對其進行排序。公升序 演算法分析 c define crt secure no warnings include include void quicksort int array,int start,int end 填坑 if low high 從左往右...