成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

除了冒泡排序,你知道Python內建的排序算法嗎?

開發(fā) 開發(fā)工具 后端 算法
對于編程算法,可能很多讀者在學校第一個了解的就是冒泡排序,但是你真的知道 Python 內建排序算法 list.sort() 的原理嗎?

對于編程算法,可能很多讀者在學校***個了解的就是冒泡排序,但是你真的知道 Python 內建排序算法 list.sort() 的原理嗎?它使用的是一種快速、穩(wěn)定的排序算法 Timsort,其時間復雜度為 O(n log n),該算法的目標在于處理大規(guī)模真實數(shù)據(jù)。

Timsort 是一種對真實數(shù)據(jù)非常有效的排序算法。Tim Peters 在 2001 年為 Python 編程語言創(chuàng)造了 Timsort。Timsort 首先分析它要排序的列表,然后基于該分析選擇合理方案。

Timsort 自發(fā)明以來,就成為 Python、Java 、Android 平臺和 GNU Octave 的默認排序算法。

Timsort

圖源:http://bigocheatsheet.com/

Timsort 的排序時間與 Mergesort 相近,快于其他大多數(shù)排序算法。Timsort 實際上借鑒了插入排序和歸并排序的方法,后文將詳細介紹它的具體過程。

Peters 設計 Timsort 是為了利用大量存在于現(xiàn)實數(shù)據(jù)集中的有序元素,這些有序元素被稱為「natural runs」。總而言之,Timsort 會先遍歷所有數(shù)據(jù)并找到數(shù)據(jù)中已經(jīng)排好序的分區(qū),且每一個分區(qū)可以稱為一個 run,***再按規(guī)則將這些 run 歸并為一個。

數(shù)組中元素少于 64 個

如果排序的數(shù)組中元素少于 64 個,那么 Timsort 將執(zhí)行插入排序。插入排序是對小型列表最有效的簡單排序,它在大型列表中速度很慢,但是在小型列表中速度很快。插入排序的思路如下:

  • 逐個查看元素
  • 通過在正確的位置插入元素來建立排序列表

下面的跟蹤表說明了插入排序如何對列表 [34, 10, 64, 51, 32, 21] 進行排序的:

在這個示例中,我們將從左向右開始排序,其中黑體數(shù)字表示新的已排序子數(shù)組。在原數(shù)組每一個元素的排序中,它會從右到左對比已排序子數(shù)組,并插入適當?shù)奈恢谩S脛訄D來說明插入排序:

天然有序的區(qū)塊:run

如果列表大于 64 個元素,則 Timsort 算法首先遍歷列表,查找「嚴格」升序或降序的部分(Run)。如果一個部分遞減,Timsort 將逆轉這個部分。因此,如果 run 遞減,則如下圖所示(run 用粗體表示):

如果沒有遞減,則如下圖所示:

minrun 的大小是根據(jù)數(shù)組大小確定的。Timsort 算法選擇它是為了使隨機數(shù)組中的大部分 run 變成 minrun。當 run N 的長度等于或略小于 2 的倍數(shù)時,歸并 2 個數(shù)組更加高效。Timsort 選擇 minrun 是為了確保 minrun 等于或稍微小于 2 的倍數(shù)。

該算法選擇 minrun 的范圍為 32 ~ 64。當除以 minrun 時,使原始數(shù)組的長度等于或略小于 2 的倍數(shù)。

如果 run 的長度小于 minrun,則計算 minrun 減去 run 的長度。我們可以將 run 之外的新元素(minrun - run 個)放到 run 的后面,并執(zhí)行插入排序來創(chuàng)建新的 run,這個新的 run 長度和 minrun 相同。

如果 minrun 是 63,而 run 的長度是 33,那么可以獲取 63 - 33 = 30 個新元素。然后將這 30 個新元素放到 run 的末尾并作為新的元素,所以 run 的第 34 個元素 run[33] 有 30 個子元素。***只需要對后面 30 個元素執(zhí)行一個插入排序就能創(chuàng)建一個長度為 63 的新 run。

在這一部分完成之后,現(xiàn)在應該在一個列表中有一系列已排序的 run。

歸并

Timsort 現(xiàn)在需要執(zhí)行歸并排序來合并 run,需要確保在歸并排序的同時保持穩(wěn)定和平衡。為了保持穩(wěn)定,兩個等值的元素不應該交換,這不僅保持了它們在列表中的原始位置,而且使算法更快。

當 Timsort 搜索到 runs 時,它們會被添加到堆棧中。一個簡單的堆棧是這樣的:

簡單的堆棧

想象一堆盤子。你不能從底部取盤子,必須從頂部取,堆棧也是如此。

當歸并不同的 run 時,Timsort 試圖平衡兩個相互矛盾的需求。一方面,我們希望盡可能地延遲歸并,以便利用之后可能出現(xiàn)的模式。但我們更希望盡快歸并,以利用剛才發(fā)現(xiàn)的在內存層級中仍然排名很高的 run。我們也不能「過分」延遲合并,因為它記住未合并的運行需要消耗內存,而堆棧的大小是固定的。

為了得到折衷方案,Timsort 追蹤堆棧上最近的三個項,并為這些堆棧項創(chuàng)建了兩個必須保持為 True 的規(guī)則:

  • A > B + C
  • B > C

其中 A、B 和 C 是堆棧中最近的三個項。

用 Tim Peters 自己的話來說:

一個好的折衷方案是在堆棧項上維護兩個不變量,其中 A、B 和 C 是最右邊三個還未歸并片段的長度。

通常,將不同長度的相鄰 run 歸并在一起是很難的。更困難的是還必須要保持穩(wěn)定。為了解決這個問題,Timsort 設置了臨時內存。它將兩個 run 中較小的(同時調用 runA 和 runB)放在這個臨時內存中。

GALLOPING(飛奔模式)

當 Timsort 歸并 A 和 B 時,它注意到一個 run 已經(jīng)連續(xù)多次「獲勝」。如果 run A 的數(shù)值完全小于 run B,那么 run A 會回到原始位置。歸并這兩個 run 會耗費巨大工作量,而且還不會取得任何效果。

通常情況下,數(shù)據(jù)會有一些預設的內部結構。Timsort 假設,如果 run A 中的值大多低于 run B 的值,那么 A 的值可能就會小于 B。

然后 Timsort 將進入飛奔模式。Timsort 不是檢查 A[0] 和 B[0],而是二分法搜索 B[0] 在 A[0] 中的合理位置。這樣,Timsort 可以將 A 的整個部分移動到合適的位置。然后,Timsort 在 B 中搜索 A[0] 的適當位置。然后,Timsort 將立即移動整個 B 到合適的位置。

Timsort 檢查 B[0](值為 5),并使用二分法搜索查找其 A 中的正確位置。

現(xiàn)在 B[0] 在 A 列表的后面,Timsort 檢查 B 的正確位置是否有 A[0](即 1),所以我們要看 1 的位置。這個數(shù)在 B 的前部,現(xiàn)在我們知道 B 在 A 的后邊,A 在 B 的前邊。

如果 B[0] 的位置非常接近 A 的前端(反之亦然),那么這個操作就沒必要了。Timsort 也會注意到這一點,并通過增加連續(xù)獲得 A 或 B 的數(shù)量提高進入飛奔模式的門檻。如果飛奔模式合理,Timsort 使它更容易重新進入該模式。

簡而言之,Timsort 做了兩件非常好的事情:

  • 具有預設的內部結構的數(shù)組具有良好的性能
  • 能夠保持穩(wěn)定的排序

在此之前,為了實現(xiàn)穩(wěn)定的排序,必須將列表中的項壓縮為整數(shù),并將其排序為元組數(shù)組。

代碼

下面的源代碼基于我和 Nanda Javarma 的工作。源代碼并不完整,也不是類似于 Python 的官方 sort() 源代碼。這只是我實現(xiàn)的一個簡化的 Timsort,可以對 Timsort 有個整體把握。此外,Python 中的內置 Timsort 算法是在 C 中正式實現(xiàn)的,因此能獲得更好的性能。

Timsort 的原始源代碼:

https://github.com/python/cpython/blob/master/Objects/listobject.c。

  1. # based off of this code https://gist.github.com/nandajavarma/a3a6b62f34e74ec4c31674934327bbd3 
  2. # Brandon Skerritt 
  3. # https://skerritt.tech 
  4.  
  5. def binary_search(the_array, item, start, end): 
  6.     if start == end: 
  7.         if the_array[start] > item: 
  8.             return start 
  9.         else: 
  10.             return start + 1 
  11.     if start > end: 
  12.         return start 
  13.  
  14.     mid = round((start + end)/ 2) 
  15.  
  16.     if the_array[mid] < item: 
  17.         return binary_search(the_array, item, mid + 1, end) 
  18.  
  19.     elif the_array[mid] > item: 
  20.         return binary_search(the_array, item, start, mid - 1) 
  21.  
  22.     else: 
  23.         return mid 
  24.  
  25. """ 
  26. Insertion sort that timsort uses if the array size is small or if 
  27. the size of the "run" is small 
  28. """ 
  29. def insertion_sort(the_array): 
  30.     l = len(the_array) 
  31.     for index in range(1, l): 
  32.         value = the_array[index] 
  33.         pos = binary_search(the_array, value, 0, index - 1) 
  34.         the_arraythe_array = the_array[:pos] + [value] + the_array[pos:index] + the_array[index+1:] 
  35.     return the_array 
  36.  
  37. def merge(left, right): 
  38.     """Takes two sorted lists and returns a single sorted list by comparing the 
  39.     elements one at a time. 
  40.     [1, 2, 3, 4, 5, 6] 
  41.     """ 
  42.     if not left: 
  43.         return right 
  44.     if not right: 
  45.         return left 
  46.     if left[0] < right[0]: 
  47.         return [left[0]] + merge(left[1:], right) 
  48.     return [right[0]] + merge(left, right[1:]) 
  49.  
  50. def timsort(the_array): 
  51.     runs, sorted_runs = [], [] 
  52.     lenlength = len(the_array) 
  53.     new_run = [the_array[0]] 
  54.  
  55.     # for every i in the range of 1 to length of array 
  56.     for i in range(1, length): 
  57.         # if i is at the end of the list 
  58.         if i == length - 1: 
  59.             new_run.append(the_array[i]) 
  60.             runs.append(new_run) 
  61.             break 
  62.         # if the i'th element of the array is less than the one before it 
  63.         if the_array[i] < the_array[i-1]: 
  64.             # if new_run is set to None (NULL) 
  65.             if not new_run: 
  66.                 runs.append([the_array[i]]) 
  67.                 new_run.append(the_array[i]) 
  68.             else: 
  69.                 runs.append(new_run) 
  70.                 new_run = [] 
  71.         # else if its equal to or more than 
  72.         else: 
  73.             new_run.append(the_array[i]) 
  74.  
  75.     # for every item in runs, append it using insertion sort 
  76.     for item in runs: 
  77.         sorted_runs.append(insertion_sort(item)) 
  78.  
  79.     # for every run in sorted_runs, merge them 
  80.     sorted_array = [] 
  81.     for run in sorted_runs: 
  82.         sorted_array = merge(sorted_array, run) 
  83.  
  84.     print(sorted_array) 
  85.  
  86. timsort([2, 3, 1, 5, 6, 7]) 

Timsort 實際上在 Python 中已經(jīng)內建了,所以這段代碼只充當概念解釋。要使用 Timsort,只需在 Python 中寫:

  1. list.sort() 

或者:

  1. sorted(list) 

如果你想掌握 Timsort 的工作方式并對其有所了解,我強烈建議你嘗試自己實現(xiàn)它!

原文鏈接:

https://hackernoon.com/timsort-the-fastest-sorting-algorithm-youve-never-heard-of-36b28417f399

【本文是51CTO專欄機構“機器之心”的原創(chuàng)譯文,微信公眾號“機器之心( id: almosthuman2014)”】

戳這里,看該作者更多好文

責任編輯:趙寧寧 來源: 51CTO專欄
相關推薦

2011-04-20 14:07:37

冒泡排序

2023-10-04 00:02:00

本文將從入門到精通,冒泡排序

2023-03-06 08:10:52

數(shù)據(jù)結構算法數(shù)據(jù)

2022-11-21 07:58:10

Java排序冒泡排序

2023-03-02 08:15:13

2009-06-05 10:24:37

C#排序排序

2019-10-30 08:53:46

JavaScript冒泡排序選擇排序

2021-01-21 05:22:36

排序算法選擇

2020-07-05 09:12:42

java冒泡排序算法

2010-01-11 15:01:55

VB.NET冒泡排序

2009-09-10 16:30:11

C#排序函數(shù)

2012-10-31 10:25:52

排序

2009-12-11 16:44:33

PHP冒泡排序

2023-05-05 06:43:13

算法冒泡排序元素

2023-09-26 22:22:30

選擇排序Python

2017-03-25 21:13:38

JavaScript排序

2023-10-05 09:01:05

插入排序對象序列log2i

2009-08-10 16:19:37

C#冒泡排序

2021-10-14 06:52:47

算法校驗碼結構

2019-10-29 15:09:52

Python貪心算法代碼
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲精品一区二区三区 | av乱码| 一区二区三区国产 | 久久久精品视频免费看 | 欧美不卡| 色婷婷九月 | 国产高清免费视频 | 国产精品观看 | 一级做a爰片性色毛片 | 一区二区三区四区视频 | 国产成人综合亚洲欧美94在线 | 在线视频国产一区 | 成年网站在线观看 | 久久精品黄色 | 亚洲精品在线免费观看视频 | 精品中文字幕一区二区三区 | 日韩中文字幕在线观看 | 欧美一区二区三区在线看 | 操久久 | 亚洲精品一区二区三区丝袜 | 久久精彩视频 | 国产伦精品一区二区三毛 | 日韩精品一区二区三区 | 欧美一级二级视频 | 国产免费一区二区 | 精品久久国产 | 午夜精品在线观看 | 欧美视频一区二区三区 | 丁香婷婷久久久综合精品国产 | 69精品久久久久久 | 日韩欧美中文字幕在线观看 | 亚洲视频在线观看 | 成人免费视频网 | 99视频在线 | 亚洲一区二区三区四区av | 一级毛片免费视频观看 | 99久久99热这里只有精品 | 欧洲高清转码区一二区 | 欧美日韩高清免费 | 91伦理片| 伊人久久伊人 |