快速排序(dart實現(xiàn))

快速排序

[toc]

快速排序1960年由查爾斯安東尼理查德霍爾(Charles Antony Richard Hoare,縮寫為C. A. R. Hoare)提出的
作者行業(yè)內(nèi)昵稱為東尼霍爾(Tony Hoare)

執(zhí)行流程

  1. 從序列中選擇一個軸點元素 (pivot)
    • 段設(shè)每次選擇0位置的元素為軸點元素
  2. 利用pivot將序列分割成2個子序列
    • 將小于pivot的元素放在pivot前面(左側(cè))
    • 將大于pivot的元素放在pivot后面(右側(cè))
    • 等于pivot的元素放哪邊都可以
  3. 對子序列進行1坦辟、2操作
    • 直到不能再分割(子序列中只剩下1個元素)

本質(zhì):逐漸將每一個元素都轉(zhuǎn)化成軸點元素

選擇軸點流程

如圖


image.png
  1. 構(gòu)造兩個索引begin和end,begin指向頭元素蕴侧,end指向末尾元素,選擇將第一個元素變成軸點6a嘉赎,備份6a
  2. 從末尾開始掃描辜羊,也就是從end開始掃描涕蜂,發(fā)現(xiàn)7>6酷鸦,讓end--鳞尔,end指向5,如圖第2行
  3. 再比較5<6,讓5覆蓋6a元素的位置盗扇,begin++笼裳,如圖第3行,5是黑色表示是垃圾數(shù)據(jù)粱玲,該位置隨時可能會被覆蓋
  4. 再開始begin開始掃描,發(fā)現(xiàn)8>6,讓8覆蓋黑色5的位置拜轨,原來8的位置變成黑色抽减,如果第4行,執(zhí)行end--橄碾,end指向9
  5. 再比較9>6,直接讓end--,end指向4卵沉,如果5行
  6. 再比較4<6,讓4覆蓋8a黑色位置,如圖6行法牲,begin++史汗,end變成黑色即為垃圾位置
  7. 再比較8b>6,讓8b覆蓋4的位置,并執(zhí)行end--拒垃,如圖行7
  8. 比較6b=6a,可以不動停撞,也可以移動,這里讓6b移動悼瓮,也就是放入8b黑色的位置戈毒,并執(zhí)行begin++,如圖行8
  9. 比較2<6,直接begin++横堡,如圖行9
  10. 此時begin==end埋市,將6a放入此位置,軸點生成完成

代碼


class QuickSort<T extends Comparable<T>> extends Sort<T> {
  @override
  sort() {
    int begin = 0;
    int end = list.length;
    _sort(begin,end);
  }

  ///
  /// Author: liyanjun
  /// description:
  ///對[[begin,end)],左閉右開的命贴,范圍內(nèi)元素進行快速排序
  _sort(int begin, int end) {
    //元素必須大于2
    if (end - begin < 2) return;
    int mid = _pivotIndex(begin, end);//O(n)
    _sort(begin, mid); //左邊子序列快速排序 
    _sort(mid + 1, end); //右邊子序列快速排序
  }

  ///
  /// Author: liyanjun
  /// description:
  /// 構(gòu)造出 [begin, end) 范圍的軸點元素,返回軸點元素的最終位置
  ///
  int _pivotIndex(int begin, int end) {
    //將begin元素備份
    T pivot = list[begin];
    //由于是左閉右開道宅,所以要讓end--
    end--;
    while (begin < end) {//確定變換方向后繼續(xù)執(zhí)行
      while (begin < end) {//后面掃描
        if (cmpElement(list[end], pivot) > 0) {
          //右邊元素大于軸點元素
          end--;
        } else {
          //右邊元素小于等于軸點元素
          list[begin++] = list[end];
          break;
        }
      }
      while (begin < end) {//前面掃描
        if (cmpElement(list[begin], pivot) < 0) {
          //左邊元素小于軸點元素
          begin++;
        } else {
          //右邊元素>=軸點元素
          list[end--] = list[begin];
          break;
        }
      }
    }
    list[begin] = pivot; //// 將軸點元素放入最終的位置
    return begin; //此時begin==end
  }
}

驗證


main(List<String> args) {
  // List<int> list = IntergerTools.random(10000, 1, 20000); //生成10000個數(shù)食听,最小是1,最大是20000
  List<int> list = IntergerTools.random(10, 1, 20); //生成10000個數(shù)污茵,最小是1樱报,最大是20000
  List<Sort> sortList = [
    // HeapSort<num>(),
    // SelectSort<num>(),
    // BubbleSort2<num>(),
    // BubbleSort1<num>(),
    // BubbleSort<num>(),
    // InsertSort<num>(),
    // InsertSort1<num>(),
    // InsertSort2<num>(),
    // MergeSort<num>(),
    QuickSort<num>()
  ];
  testSorts(list, sortList);
}

void testSorts(List<int> list, List<Sort> sorts) {
  print('排序前 :$list');
  for (Sort sort in sorts) {
    List<int> newList = List.from(list);
    sort.setList(newList);
    sort.sortPrint();
    Asserts.test(IntergerTools.isAscOrder(sort.list));
     print('排序后 :${sort.list}');
  }
  sorts.sort(); //比較
  for (Sort sort in sorts) {
    print(sort);
  }
}

執(zhí)行結(jié)果

排序前 :[7, 9, 6, 15, 10, 19, 16, 18, 18, 6]
排序后 :[6, 6, 7, 9, 10, 15, 16, 18, 18, 19]
【QuickSort<num>】
耗時:0.001s (1ms)     比較:22    交換:0
-----------------

時間復(fù)雜度

  • 在軸點左右元素數(shù)量比較均勻的情況下,同時也是最好的情況
    • 左邊T(n/2)省咨,右邊T(n/2)
    • \therefore T(n) = 2 ? T(n/2) + O (n) = O(nlogn)
  • 如果軸點左右元素數(shù)量極度不均勻肃弟,最壞情況
    • 假如左邊n-1個,右邊1個
    • 左邊T(n-1)零蓉,右邊左邊T(1)
    • \therefore T(n) = T(n-1) + O (n) = O(n^2)
  • 最好笤受、平均時間復(fù)雜度:O(nlogn)
  • 最壞時間復(fù)雜度:O(n^2)
  • 由于遞歸調(diào)用的緣故,空間復(fù)雜度:O(logn)
  • 屬于不穩(wěn)定排序

為了降低最壞情況的出現(xiàn)概率敌蜂,一般采取的做法是

隨機選擇軸點元素

優(yōu)化代碼

 ///
  /// Author: liyanjun
  /// description:
  /// 構(gòu)造出 [begin, end) 范圍的軸點元素,返回軸點元素的最終位置
  ///
  int _pivotIndex(int begin, int end) {
    
  // 隨機選擇一個元素跟begin位置進行交換
    //因為 Random().nextInt(max)是包括max的箩兽,所以應(yīng)該end-1
        swap(begin, begin + Random().nextInt(end-1-begin));
    //將begin元素備份
    T pivot = list[begin];
    //由于是左閉右開,所以要讓end--
    end--;
    while (begin < end) {//確定變換方向后繼續(xù)執(zhí)行  思想章喉,掉頭用兩個while循環(huán)
      while (begin < end) {//后面掃描
        if (cmpElement(list[end], pivot) > 0) {
          //右邊元素大于軸點元素
          end--;
        } else {
          //右邊元素小于等于軸點元素
          list[begin++] = list[end];
          break;
        }
      }
      while (begin < end) {//前面掃描
        if (cmpElement(list[begin], pivot) < 0) {
          //左邊元素小于軸點元素
          begin++;
        } else {
          //右邊元素>=軸點元素
          list[end--] = list[begin];
          break;
        }
      }
    }
    list[begin] = pivot; //// 將軸點元素放入最終的位置
    return begin; //此時begin==end
  }
}

與軸點相等的元素

cmp 位置的判斷分別改為 ≤汗贫、≥ 會起到什么效果
假如原數(shù)組為
[3,3,3,3,3,3]
如果判斷為 ≤、≥ 秸脱,則會導(dǎo)致軸點元素處于兩端落包,造成最壞情況的時間復(fù)雜度,所以不用

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末摊唇,一起剝皮案震驚了整個濱河市咐蝇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌巷查,老刑警劉巖有序,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異岛请,居然都是意外死亡旭寿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門崇败,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盅称,“玉大人,你說我怎么就攤上這事后室∥⑶” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵咧擂,是天一觀的道長逞盆。 經(jīng)常有香客問我,道長松申,這世上最難降的妖魔是什么云芦? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任俯逾,我火速辦了婚禮,結(jié)果婚禮上舅逸,老公的妹妹穿的比我還像新娘桌肴。我一直安慰自己,他們只是感情好琉历,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布坠七。 她就那樣靜靜地躺著,像睡著了一般旗笔。 火紅的嫁衣襯著肌膚如雪彪置。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天蝇恶,我揣著相機與錄音拳魁,去河邊找鬼。 笑死撮弧,一個胖子當著我的面吹牛潘懊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播贿衍,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼授舟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了贸辈?” 一聲冷哼從身側(cè)響起志鹃,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤狰挡,失蹤者是張志新(化名)和其女友劉穎毕骡,沒想到半個月后花竞,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體署浩,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡揉燃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了筋栋。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片炊汤。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖弊攘,靈堂內(nèi)的尸體忽然破棺而出抢腐,到底是詐尸還是另有隱情,我是刑警寧澤襟交,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布迈倍,位于F島的核電站,受9級特大地震影響捣域,放射性物質(zhì)發(fā)生泄漏啼染。R本人自食惡果不足惜宴合,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望迹鹅。 院中可真熱鬧卦洽,春花似錦、人聲如沸斜棚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽弟蚀。三九已至蚤霞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間粗梭,已是汗流浹背争便。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留断医,地道東北人滞乙。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像鉴嗤,于是被迫代替她去往敵國和親斩启。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355