排序演算法總結

2021-09-13 23:08:12 字數 4612 閱讀 5271

本文總結一下氣泡排序,選擇排序,插入排序,快速排序,歸併排序,堆排序,主要從原理,**實現,穩定性,時間複雜度,空間複雜度這幾方面來介紹。

每輪排序,從第乙個數開始,依次和後乙個位置的數比較,如果左邊的數大於右邊的,交換兩個數。這樣,第i輪排序,就會挑選出乙個第i大的值。

public

static

void

bubblesort

(int

a,int n)}}

}

屬於穩定排序,因為只有前面乙個數大於後面時,才會交換,所以相等的兩個數的相對位置不會改變。

最好:o(n),原因是當第一次遍歷時沒有發生任何交換時,可以認為陣列本身有序,不再執行後面的操作。**稍作修改如下:

public

static

void

bubblesort

(int

a,int n)}if(}}

最壞:o(n2)

平均:o(n2)

o(1)

每次選擇無序序列中最小的,然後將這個數和位置i的數進行交換。

public

static

void

selectsort

(int

a,int n)}if

(i != index)

}}

不穩定,交換的時候可能改變兩個相等元素的相對位置

例如9 2 394 7 1

第一輪排序之後變為

1 2 394 7 9

最好,最壞,平均都是o(n2)

o(1)

每次將無序陣列中的第乙個元素插入到有序陣列的合適的位置,這裡定位合適的位置時既可以從前往後,也可以從後往前。如果當前元素比較大的話,從後往前定位合適,反之,從前往後合適。這裡,兩種寫法都給出來。

從前往後

public

static

void

insertsort

(int

a,int n)

a[j]

= temp;

//插入當前元素

break;}}}}

從後往前:

public

static

void

insertsort

(int

a,int n)

}int temp = a[i]

;for

(int k = i -

1; k > j; k--

) a[j +1]

= temp;

//插入當前元素

}}

可以看出從前往後的**比較好理解,而從後往前稍微複雜一些。從前往後:第二個for迴圈中沒有找到位置,其實就相當於當前元素最大,就什麼也不做就可以了。從後往前,第二個for迴圈中沒有找到位置,說明當前元素最小,需要後移所有元素,所以比較麻煩,需要把移動元素的這個操作單獨出來,不能寫在for迴圈之內。本人更喜歡寫從前往後定位的方法。

屬於穩定排序,從前往後時,當元素相等時,會繼續往後走,保證,相等的元素的相對位置不變。從後往前時,如果元素相等,直接插入。

最好,最壞,平均都是o(n2)

快速排序,每次以待排序陣列的第乙個元素為切分點,把陣列分為兩部分,大於等於這個元素的在後面,反之在前面,依次遞迴,直至整個陣列有序。

public

static

void

quicksort

(int

a,int begin,

int end)

int temp = a[begin]

;int i = begin;

int j = end;

while

(i < j)

a[i]

= temp;

quicksort

(a, begin, i -1)

;quicksort

(a, i +

1, end)

;}

屬於不穩定排序,因為基於交換,且不同於冒泡,它不是相鄰元素的交換,所以會改變相等元素的相對位置。

舉個例子:

例如:6 1 2 3 8 5 92

經過第一輪快排之後變為:

21 2 3 5 6 9 8

最好:o(nlogn) 最壞:o(n2) 平均:o(nlogn)

最壞的情況是陣列本身有序的情況,這樣一輪快排並不能把陣列分為元素數量基本相等的兩部分

最好:o(logn) 最壞:o(n) 平均:o(logn)

最壞的情況同上

使用遞迴,把兩個有序陣列合併為乙個有序陣列,注意部分有序的時候要記得複製回原陣列。

public

static

void

mergesort

(int

a,int begin,

int end)

int mid = begin +

(end - begin)/2

;//從中間將陣列一分為二,遞迴呼叫歸併排序使得左右兩個陣列有序

mergesort

(a, begin, mid)

;mergesort

(a, mid +

1, end)

;merge

(a, begin, mid, end)

;//合併兩個有序陣列

}public

static

void

merge

(int

a,int begin,

int mid,

int end)

else

}while

(i <= mid)

while

(j <= end)

for(k = begin; k <= end; k++

)}

屬於穩定排序,在兩個陣列合併時,如果兩個元素相等,取左邊陣列中的元素,保證相等元素的相對位置不會改變。

最好,最壞,平均都是o(nlogn)

因為需要乙個輔助陣列b,所以空間複雜度為o(n)。

如果要從小到大排序,那麼使用大頂堆,堆用陣列來儲存。

構造大頂堆的方式是自底向上,從第乙個非葉子節點開始,調整元素位置,使得每乙個非葉子節點都大於等於它的左右子節點。所以,建堆的時間複雜度為o(n),因為自底向上,只需往下走一層即可,即使有元素交換,也不會打亂下面的關係,因為即使有元素交換,也是把大的換到下面,當然滿足大頂堆的性質了。

下面開始真正的排序,排序就是把位置為0的元素和位置為i的元素交換,然後調整堆(0到i-1),使其重新滿足大頂堆的性質。這樣,每執行一輪,就會把當前最大的元素放到後面。這個過程的時間複雜度為o(nlogn)。

public

static

void

heapsort

(int

a)for(

int i = len -

1; i >

0; i--)}

public

static

void

adjustheap

(int

a,int parent,

int end)

if(temp >= a[i]

) a[parent]

= a[i]

;//反之,把最大值放到parent的位置

parent = i;

//parent指向i,繼續向下遍歷

} a[parent]

= temp;

//找到位置或者遍歷到最後,那麼把temp放到parent的位置

}

屬於不穩定排序,舉例,左面的是構造大頂堆之後的狀態,右面的是經過第一輪排序之後的狀態,兩個2的相對位置改變了:

最好,最壞,平均都是o(nlogn)

o(1)

最後,總結一下上面6種排序演算法。

排序演算法

穩定性最好時間複雜度

最壞時間複雜度

平均時間複雜度

空間複雜度冒泡是

o(n)

o(n2)

o(n2)

o(1)選擇否

o(n2)

o(n2)

o(n2)

o(1)插入是

o(n2)

o(n2)

o(n2)

o(1)快排否

o(nlogn)

o(n2)

o(nlogn)

o(logn)歸併是

o(nlogn)

o(nlogn)

o(nlogn)

o(n)堆排否

o(nlogn)

o(nlogn)

o(nlogn)

o(1)

排序演算法總結

1 直接插入排序 1 穩定性 穩定 2 適用情況 待排記錄規模較小,或者記錄已經基本有序 2 希爾排序 1 穩定性 不穩定 2 特點 希爾排序的執行時間依賴於增量序列,它的效率比直接插入排序有較大的改進。3 氣泡排序 1 穩定性 穩定 2 特點 當待排記錄基本有序是,氣泡排序是不錯的選擇 但由於氣泡...

排序演算法總結

1 選擇排序 選擇排序的思想是依次從待排序數列中選擇最大 小 的 第二大 小 的等等,然後依次重新排列為有序數列。void selectionsort int a,int n if min i 時間複雜度o n 2 2 歸併排序 void merge int a,int left,int mid,i...

排序演算法總結

學習了這麼多的排序演算法,還沒有做個總結,呵呵 氣泡排序 氣泡排序是最慢的排序演算法。在實際運用中它是效率最低的演算法。它通過一趟又一趟地比較陣列中的每乙個元素,使較大的資料下沉,較小的資料上公升。它是 o n 2 的演算法。快速排序 快速排序是乙個就地排序,分而治之,大規模遞迴的演算法。從本質上來...