摘要:插入排序插入排序應該算是最簡單和容易理解的排序算法。平均來說插入排序算法復雜度為。在最好的情況,冒泡排序需要次交換,而插入排序只要最多交換。因此很多現代的算法教科書避免使用冒泡排序,而用插入排序替換之。快速排序也是一種分治的遞歸算法。
插入排序(insertion sort)計算的 時間復雜度(最差、平均、和最好性能),依據列表(list)的大小(n)。一般而言,好的性能是O(n log n),且壞的性能是O(n^2)。對于一個排序理想的性能是O(n)。僅使用一個抽象關鍵比較運算的排序算法總平均上總是至少需要O(n log n)。
插入排序應該算是最簡單和容易理解的排序算法。它的工作原理是通過構建有序序列,對于未排序數據,在已排序序列中從后向前掃描,找到相應位置并插入。具有n個元素時它需要經過n-1趟排序。對于p = 1到p = n-1趟,插入排序保證從位置0到位置p上的元素為已排序狀態。它就是基于這個事實來排序的。
function sort(arr) { if(arr.length <= 1) { return arr } for(var i=0; i=0; j--) { if(arr[j+1] < arr[j]) { var temp = arr[j+1]; arr[j+1] = arr[j]; arr[j] = temp } } } return arr }
如果目標是把n個元素的序列升序排列,那么采用插入排序存在最好情況和最壞情況。最好情況就是,序列已經是升序排列了,在這種情況下,需要進行的比較操作需(n-1)次即可。最壞情況就是,序列是降序排列,那么此時需要進行的比較共有n(n-1)/2次。插入排序的賦值操作是比較操作的次數減去(n-1)次。平均來說插入排序算法復雜度為O(n^2)。因而,插入排序不適合對于數據量比較大的排序應用。但是,如果需要排序的數據量很小,例如,量級小于千,那么插入排序還是一個不錯的選擇。 插入排序在工業級庫中也有著廣泛的應用,在STL的sort算法和stdlib的qsort算法中,都將插入排序作為快速排序的補充,用于少量元素的排序(通常為8個或以下)
冒泡排序(bubble sort)冒泡排序是與插入排序擁有相等的運行時間,但是兩種算法在需要的交換次數卻很大地不同。在最好的情況,冒泡排序需要O(n^2)次交換,而插入排序只要最多O(n)交換。冒泡排序的實現(類似下面)通常會對已經排序好的數列拙劣地運行O(n^2),而插入排序在這個例子只需要O(n)個運算。因此很多現代的算法教科書避免使用冒泡排序,而用插入排序替換之。冒泡排序如果能在內部循環第一次運行時,使用一個旗標來表示有無需要交換的可能,也可以把最好的復雜度降低到O(n)。在這個情況,已經排序好的數列就無交換的需要。若在每次走訪數列時,把走訪順序反過來,也可以稍微地改進效率。有時候稱為雞尾酒排序,因為算法會從數列的一端到另一端之間穿梭往返。
冒泡排序算法的運作如下:
比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最后一對。這步做完后,最后的元素會是最大的數。
針對所有的元素重復以上的步驟,除了最后一個。
持續每次對越來越少的元素重復上面的步驟,直到沒有任何一對數字需要比較。
由于它的簡潔,冒泡排序通常被用來對于程序設計入門的學生介紹算法的概念。
function bubbleSort(arr) { if(arr.length <= 1) { return arr; } for(var j=0; j選擇排序(selection sort)arr[i+1]) { var tmp = arr[i]; arr[i] = arr[i+1]; arr[i+1] = tmp; } } } return arr; }
選擇排序(Selection sort)是一種簡單直觀的排序算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再從剩余未排序元素中繼續尋找最小(大)元素,然后放到已排序序列的末尾。以此類推,直到所有元素均排序完畢。
選擇排序的主要優點與數據移動有關。如果某個元素位于正確的最終位置上,則它不會被移動。選擇排序每次交換一對元素,它們當中至少有一個將被移到其最終位置上,因此對n個元素的表進行排序總共進行至多n-1次交換。在所有的完全依靠交換去移動元素的排序方法中,選擇排序屬于非常好的一種。
選擇排序的交換操作介于 0 和(n-1)次之間。選擇排序的比較操作為n(n-1)/2次之間。選擇排序的賦值操作介于0和3(n-1)次之間。比較次數O(n^2),比較次數與關鍵字的初始狀態無關,總的比較次數 N=(n-1)+(n-2)+...+1=n(n-1)/2。交換次數O(n),最好情況是,已經有序,交換0次;最壞情況是,逆序,交換n-1次。交換次數比冒泡排序較少,由于交換所需CPU時間比比較所需的CPU時間多, n值較小時,選擇排序比冒泡排序快。
原地操作幾乎是選擇排序的唯一優點,當空間復雜度要求較高時,可以考慮選擇排序;實際適用的場合非常罕見。
function selectionSort(arr) { if(arr.length <= 1) { return arr } var i, j, min; var temp; for (i = 0; i < arr.length - 1; i++) { min = i; for (j = i + 1; j < arr.length; j++) { if (arr[min] > arr[j]) min = j; temp = arr[min]; arr[min] = arr[i]; arr[i] = temp; } } return arr }快速排序(quick sort)
快速排序使用分治法(Divide and conquer)策略來把一個序列(list)分為兩個子序列(sub-lists)。
步驟為:
從數列中挑出一個元素,稱為"基準"(pivot),
重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的后面(相同的數可以到任一邊)。在這個分區結束之后,該基準就處于數列的中間位置。這個稱為分區(partition)操作。
遞歸地(recursive)把小于基準值元素的子數列和大于基準值元素的子數列排序。
遞歸的最底部情形,是數列的大小是零或一,也就是永遠都已經被排序好了。雖然一直遞歸下去,但是這個算法總會結束,因為在每次的迭代(iteration)中,它至少會把一個元素擺到它最后的位置去。
正如它的名字,快速排序是在時間中最快的已知排序算法,它的平均運行時間是O(NlogN)。快速排序也是一種分治的遞歸算法。將數組S排序的基本算法由下列簡單的四步組成:
如果S中元素個數是0或1,則返回
取S中任一元素v,稱之為樞紐元
將S - {v}分成兩個不相交的集合:S1 = {x∈S - {v} | x ≤ v}和S2 = {x∈S - {v} | x ≥ v}
返回{quicksort(S1)},繼續v,繼而quicksort(S2)
由于對樞紐元的處理會導致第三步中的分割不唯一,因此,我們希望把等于樞紐元的大約一半的關鍵字分到S1中,而另外一半分到S2中,那怎么去選擇一個好的樞紐元呢?
選取樞紐元
一種錯誤的方法
通常的,沒有經過充分考慮的選擇是將第一個元素用作樞紐元。如果輸入是隨機的,那么這是可以接受的,但是如果輸入是預排序或是反序的,那么這樣的樞紐元就會產生一個劣質的分割,因為所有的元素不是都被劃入S1就是被劃入S2。
一種安全的作法
一種安全的方針是隨機選取樞紐元。但是另一方面,隨機數的生成一般是昂貴的,根本減少不了算法奇遇部分的平均運行時間。
三數中值分割法
一組N個數的中值是第Math.ceil(N/2)個最大的數。樞紐元的最好的選擇是數組的中值。不幸的是,這很難算出,且會減慢快速排序的速度。因此一般的做法是使用左端、右端和中心位置上的三個元素的中值作為樞紐元。例如,輸入為8, 1, 4, 9, 6, 3, 5, 2, 7, 0,它的左邊元素是8,右邊元素是0,中心位置為Math.floor((left + right) / 2)上的元素是6,于是樞紐元v=6。
function quickSort(arr) { if (arr.length <= 1) { return arr.slice(0); } var left = []; var right = []; var mid = [arr[0]]; //first number as a pivot for (var i = 1; i < arr.length; i++) { if (arr[i] < mid[0]) { left.push(arr[i]); } else { right.push(arr[i]); } } return quickSort(left).concat(mid.concat(quickSort(right))); }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/82136.html
馬上就要開始啦這次共組織15個組隊學習 涵蓋了AI領域從理論知識到動手實踐的內容 按照下面給出的最完備學習路線分類 難度系數分為低、中、高三檔 可以按照需要參加 - 學習路線 - showImg(https://segmentfault.com/img/remote/1460000019082128); showImg(https://segmentfault.com/img/remote/...
摘要:排序嚴格來說不算數據結構,更應該歸于算法一類,因為數據結構指的是數據與數據之間的關系,排序參與其中,更多的是讓數據狀態發生了改變。 排序嚴格來說不算數據結構,更應該歸于算法一類,因為數據結構指的是數據與數據之間的關系,排序參與其中,更多的是讓數據狀態發生了改變。于是,我們開始用PHP來聊聊算法。 引子 其實有一句話說的是不錯的,不必重復造輪子,所以下面我將引用別人的文章作為本文的引文,...
摘要:穩定與不穩定算法示例以下圖片解釋了穩定和不穩定的排序是如何工作的這就是穩定和不穩定排序算法之間的區別。穩定排序算法的一些常見示例是合并排序,插入排序和冒泡排序。 showImg(https://segmentfault.com/img/remote/1460000018913243); 來源 | 愿碼(ChainDesk.CN)內容編輯 愿碼Slogan | 連接每個程序員的故事 網...
摘要:數據結構試題前言這里是數據結構系列文章,主要介紹計算機二級考試中的涉及到數據結構的知識點數據結構在計算機科學中處處都有存在,例如編譯系統要使用棧散列表語法樹等操作系統要使用隊列存儲管理表目錄樹等等。 數據結構 試題前言這里是 數據結構 系列文章,主要介紹計算機二級考試中的涉及到數據結構的知識點 /數據結構在計算...
閱讀 1416·2021-10-11 10:59
閱讀 3114·2019-08-30 15:54
閱讀 2735·2019-08-30 13:19
閱讀 2464·2019-08-30 13:02
閱讀 2377·2019-08-30 10:57
閱讀 3355·2019-08-29 15:40
閱讀 986·2019-08-29 15:39
閱讀 2311·2019-08-29 12:40