O(nlogn)排序算法之快速排序

1.選擇數組中的一個元素

2.進行一次Partition,將數組分為小于該元素和大于該元素的兩個部分

3.分別在兩個部分中選取元素遞歸第1-2步至有序即可


  • 核心操作Partition:

我們通常會使用整個數組的第一個元素v作為整個數組的分界點

其中:

指向數組分界點元素v的指針記為l(小寫L);

大于v和小于v的分界線上的元素給個指針記為j;

正在判斷的當前元素e的指針為i;

即:

arr[l+1, j] < v

arr[j +1,i -1] > v

此時判斷e與v的大小:

若e > v,則 i++即可把e放入大于v的范圍中

若e < v,則交換j+1與i所指元素的位置,然后j++,即可把e放入小于v的范圍中

當所有排序結束后,只需要將l與j所指元素交換位置即可讓分界點位于其應該在的位置

image.png
image.png

//返回p, 使得arr[l...p - 1] < arr[p]; arr[p + 1...r] > arr[p]
template<typename T>
int __partition(T arr[], int l, int r){

    T v = arr[l];

    //arr[l + 1...j]<v; arr[j + 1...i)>v
    int j = l;
    for (int i = l + 1; i <= r; i++){
        if (arr[i] < v){
            swap(arr[j + 1], arr[i]);
            j++;
        }
    }

    swap(arr[j], arr[l]);

    return j;
}
  • 未優(yōu)化quicksort
template<typename T>
void __quickSort(T arr[], int l, int r){

    if (l > r)
        return;

    int p = __partition(arr, l, r);
    __quickSort(arr, l, p - 1);
    __quickSort(arr, p + 1, r);
}

  • 優(yōu)化1:隨機選中一個元素作為數組的分界點
    發(fā)現(xiàn)問題:對近乎有序的數組進行排序時:
    n較大恶座,quicksort出現(xiàn)stackoverflow内舟。
    n較小边臼,快速排序的時間遠大于歸并排序的時間肢专。
int __partition(T arr[], int l, int r){

    int s = rand() % (r - l + 1) + l;
    swap(arr[l], arr[s]);
    T v = arr[l];

    //arr[l + 1...j]<v; arr[j + 1...i)>v
    int j = l;
    for (int i = l + 1; i <= r; i++){
        if (arr[i] < v){
            swap(arr[j + 1], arr[i]);
            j++;
        }
    }

    swap(arr[j], arr[l]);

    return j;
}

  • 優(yōu)化2:雙路快速排序法
    問題分析:由于待排數組中出現(xiàn)大量重復元素,導致一旦分界點選擇過大或過小,就會造成大規(guī)模的不平衡堂淡。
    甚至由于有大量重復元素,就算分界點選中了正中間的5,也有大量的5聚集在大于v的節(jié)點中(因為判斷條件是arr[i]<v余掖,才進行交換贿肩,等于v時苍凛,j++),仍會導致分配不均的問題出現(xiàn)。
image.png

image.png

image.png
template<typename T>
int __partition2(T arr[], int l, int r){

    swap(arr[l], arr[rand() % (r - l + 1) + l]);
    T v = arr[l];

    //arr[l+1...i)<=v;arr(j...r]>=v
    int i = l + 1, j = r;
    while (true){
        while (i <= r&&arr[i] < v) i++;
        while (j >= l + 1 && arr[j] > v) j--;
        if (i > j) break;
        swap(arr[i], arr[j]);
        i++;
        j--;
    }
    swap(arr[l], arr[j]);
    return j;
}

  • 優(yōu)化3:三路快速排序
    e<v


    image.png
image.png

lt++;
i++;


e>v


image.png

image.png

gt--;


處理完后


image.png

image.png

  • while版
template<typename T>
void __quickSort3Ways(T arr[], int l, int r){

    if (r - l <= 15){
        insertionSort2(arr, l, r);
        return;
    }

    //partition
    swap(arr[l], arr[rand() % (r - l + 1) + l]);
    T v = arr[l];
    
    int lt = l; //arr[l+1...lt]<v
    int gt = r + 1; //arr[gt..r]>v
    int i = l + 1; //arr[lt+1...i)=v
    while (i < gt){
        if (arr[i] < v){
            swap(arr[i], arr[lt + 1]);
            lt++;
            i++;
        }
        else if (arr[i] > v){
            swap(arr[i], arr[gt - 1]);
            gt--;
        }
        else{
            i++;
        }
    }
    swap(arr[l], arr[lt]);

    __quickSort3Ways(arr, l, lt - 1);
    __quickSort3Ways(arr, gt, r);
}

  • 自己寫的for版
template<typename T>
void __quickSort3Ways(T arr[], int l, int r){

    if (r - l <= 15){
        insertionSort2(arr, l, r);
        return;
    }

    //partition
    swap(arr[l], arr[rand() % (r - l + 1) + l]);
    T v = arr[l];
    
    int lt = l; //arr[l+1...lt]<v
    int gt = r + 1; //arr[gt..r]>v
    int i = l + 1; //arr[lt+1...i)=v
    for (int i = l + 1; i < gt; i++){
        
        if (arr[i] < v){
            swap(arr[i], arr[lt + 1]);
            lt++;
        }
        else if (arr[i] > v){
            swap(arr[i], arr[gt - 1]);
            gt--;
            --i;
        }   
    }
    swap(arr[l], arr[lt]);

    __quickSort3Ways(arr, l, lt - 1);
    __quickSort3Ways(arr, gt, r);
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末捡鱼,一起剝皮案震驚了整個濱河市八回,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌驾诈,老刑警劉巖缠诅,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異乍迄,居然都是意外死亡管引,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門闯两,熙熙樓的掌柜王于貴愁眉苦臉地迎上來褥伴,“玉大人谅将,你說我怎么就攤上這事≈芈” “怎么了饥臂?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長似踱。 經常有香客問我隅熙,道長,這世上最難降的妖魔是什么核芽? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任囚戚,我火速辦了婚禮,結果婚禮上轧简,老公的妹妹穿的比我還像新娘驰坊。我一直安慰自己,他們只是感情好哮独,可當我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布拳芙。 她就那樣靜靜地躺著,像睡著了一般借嗽。 火紅的嫁衣襯著肌膚如雪态鳖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天恶导,我揣著相機與錄音浆竭,去河邊找鬼。 笑死惨寿,一個胖子當著我的面吹牛邦泄,可吹牛的內容都是我干的。 我是一名探鬼主播裂垦,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼顺囊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蕉拢?” 一聲冷哼從身側響起特碳,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎晕换,沒想到半個月后午乓,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡闸准,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年益愈,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡蒸其,死狀恐怖敏释,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情摸袁,我是刑警寧澤钥顽,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站但惶,受9級特大地震影響耳鸯,放射性物質發(fā)生泄漏。R本人自食惡果不足惜膀曾,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望阳啥。 院中可真熱鬧添谊,春花似錦、人聲如沸察迟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扎瓶。三九已至所踊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間概荷,已是汗流浹背秕岛。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留误证,地道東北人继薛。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像愈捅,于是被迫代替她去往敵國和親遏考。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內容

  • 選擇排序 選擇排序是一種簡單直觀的排序算法蓝谨,無論什么數據進去都是 O(n?) 的時間復雜度灌具。所以用到它的時候,數據...
    無灃閱讀 1,324評論 0 0
  • oncontextmenu="window.event.returnValue=false" 將徹底屏蔽鼠標右鍵 ...
    逍遙至尊灬寳閱讀 1,237評論 0 43
  • 數據結構與算法——快速排序 快速排序譬巫,顧名思義咖楣,它速度很快,針對一般應用中各種不同的輸入都要比其他排序算法快很多缕题,...
    sunhaiyu閱讀 3,280評論 0 3
  • 零基礎,學web已經半個月了,到現(xiàn)在css的定位都搞不懂.求大神教教. 還有我的單詞也是硬傷,如何才能更容易記住單...
    一克拉的html閱讀 246評論 7 0
  • Margaret是我們大一的另一位外教截歉,是位特別親切的奶奶。為了讓我們讀到純正的英文讀物烟零,Margaret從美國帶...
    晨寧Chinadoll閱讀 492評論 0 0