本文總結一下氣泡排序,選擇排序,插入排序,快速排序,歸併排序,堆排序,主要從原理,**實現,穩定性,時間複雜度,空間複雜度這幾方面來介紹。
每輪排序,從第乙個數開始,依次和後乙個位置的數比較,如果左邊的數大於右邊的,交換兩個數。這樣,第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 的演算法。快速排序 快速排序是乙個就地排序,分而治之,大規模遞迴的演算法。從本質上來...