一般所說的排序是指內部排序,即在內存裏進行排序。相對應的有外部排序,當待排序數據比較多時,排序過程須要使用閃存。算法
排序算法大致可分爲兩種:
一種是比較排序,時間複雜度O(nlogn) ~ O(n^2),主要有:冒泡排序,選擇排序,插入排序,歸併排序,堆排序,快速排序等。
另外一種是非比較排序,時間複雜度能夠達到O(n),主要有:計數排序,基數排序,桶排序等。數組
排序算法穩定性說明:若是待排序序列A中兩個元素相等,即Ai = Aj,排序前Ai在Aj以前,排序後Ai還在Aj以前,則稱這種排序算法是穩定的。就是保證排序先後兩個相等的元素的相對順序不變ui
如下爲各算法的時間複雜度等對比spa
排序 | 平均 | 最優 | 最差 | 輔助空間 | 是否穩定 |
冒泡排序 | O(n2) | O(n) | O(n2) | O(1) | 穩定 |
簡單選擇排序 | O(n2) | O(n2) | O(n2) | O(1) | 不穩定 |
直接插入排序 | O(n2) | O(n) | O(n2) | O(1) | 穩定 |
快速排序 | O(nlogn) | O(nlogn) | O(n2) | O(logn)-O(n) | 不穩定 |
希爾排序 | O(nlogn)-O(n2) | O(n1.3) | O(n2) | O(1) | 不穩定 |
歸併排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 穩定 |
堆排序 | O(nlogn) | O(nlogn) | O(nlogn) | O(n) | 不穩定 |
main包用來執行,myAlgo包爲具體方法實現3d
//如下爲共用方法 //交換兩個元素位置 package myAlgo func exchange(arr []int, a int, b int) { temp := arr[a] arr[a] = arr[b] arr[b] = temp } //返回序列最小值下標 func selectMin(arr []int, i int) int { length := len(arr) minKey := i minValue := arr[minKey] //從下標爲i及以後的元素中找出值最小的元素 for k := minKey + 1; k < length; k++ { if minValue > arr[k] { //修改下標 minKey = k minValue = arr[k] } } return minKey }
冒泡排序算法運行方式以下:
假設待排序序列有n個元素
第一次循環
1.從首元素開始比較相鄰的元素,若是順序不對,就把它們兩個調換位置,直至最後一個,此時能夠保證最後一個元素是最大的(或最小的)
2.重複以上操做,每次循環均可以將無序序列(序列無序元素數量每次循環後都在減小)最大(最小)的一個元素移至最右邊,因此第k次循環後前n-k個元素是無序的,後k個元素是有序且依次遞增(遞減)的code
示意圖blog
package main import ( "fmt" "myAlgo" ) func main() { arr := []int{15, 45, 42, 25, 20, 63, 23, 20, 29, 100, 9} myALgo.BubbleSort(arr); } package myAlgo import "fmt" func bubbleSort(arr []int) { length := len(arr) for j := length - 1; j > 0; j-- { //外層循環控制循環次數 for i := 0; i < j; i++ { //內層循環控制交換 if arr[i] > arr[i+1] { //交換順序 exchange(arr, i, i+1) } } fmt.Println(arr) } }
結果以下排序
思路以下:
1.首先,找到序列中最小的那個元素,將它和第一個元素交換位置。
2.在剩下的元素中找到最小元素,將它與序列的第二個元素交換位置
3.按照以上方式如此往復,直至將整個序列排序。
由於它在不斷的選擇剩餘元素之中的最小者,因此叫選擇排序。遞歸
示意圖圖片
go實現
package main import "fmt" func main() { arr := []int{15, 45, 42, 25, 20, 63, 23, 20, 29, 100, 9} fmt.Println(arr) myAlgo.SelectSort(arr) } package myAlgo import "fmt" func SelectSort(arr []int) { fmt.Println("開始排序") length := len(arr) for i := 0; i < length; i++ { //每循環一次都找出當前未排序元素中的最小值,和當前元素進行交換 minKey := selectMin(arr, i) exchange(arr, i, minKey) } fmt.Println(arr) }
執行結果
這個相似於玩撲克牌,一張一張的將牌拿出來插到部分已經有序序列中的合適位置,具體以下:
1.第一個元素能夠當作是有序的
2.從有序序列下一個元素開始,用這個元素a從後向前,依次和有序序列元素b進行比較,若是元素a小於元素b,則將元素a插入到元素b以前,原有序序列b以後的元素均向後移動一個位置,此時生成一個新的有序序列。
3.重複操做2
示意圖
go實現
package main import ( "fmt" "myAlgo" ) func main() { arr := []int{15, 45, 42, 25, 20, 63, 23, 20, 29, 100, 9} fmt.Println(arr) myAlgo.InsertSort(arr) } package myAlgo import "fmt" func InsertSort(arr []int) { fmt.Println("開始排序") //獲取當前數組長度 length := len(arr) for i := 1; i < length; i++ { //當前值 now := arr[i] //若是當前元素小於以前序列中的某一個元素的值,則序列今後元素向後總體移動一位 for j := i - 1; j >= 0; j-- { if now < arr[j] { arr[j+1] = arr[j] arr[j] = now } else { arr[j+1] = now break } } fmt.Println(arr) } }
運行結果
算法原理:
將未排序元素根據一個做爲基準的「主元」(Pivot)分爲兩個子序列,其中一個子序列的記錄均大於主元,而另外一個子序列均小於主元,而後遞歸地對這兩個 子序列用相似的方法進行排序。本質上,快速排序使用分治法,將問題的規模減少,而後再分別進行處理。
示意圖
go實現
package main import ( "fmt" "myAlgo" ) func main() { arr := []int{40, 45, 42, 25, 20, 63, 23, 20, 50, 29, 100, 9} fmt.Println(arr) myAlgo.QuickSort(arr, 0, len(arr) - 1) } package myAlgo import "fmt" func QuickSort(arr []int, left int, right int) { //設置基準數,選擇第一個做爲基準數 baseKey := left baseValue := arr[baseKey] fmt.Println("當前序列", arr[left:right+1],"基準值爲",baseValue) fmt.Println("開始排序") i := left j := right for i < j { //先從右向左找,直到找到一個小於基準數的值 for (arr[j] >= baseValue) && (i < j) { j-- } if i < j { //將j的值放到i的空位上 arr[i] = arr[j] } //從左向右找,直到找到一個大於基準數的值 for (i < j) && (arr[i] < baseValue) { i++ } if i < j { //將此時的i放到以前j產生的空位上 arr[j] = arr[i] } fmt.Println(arr[left:right+1]) } arr[i] = baseValue fmt.Println("子序列結果", arr[left:right+1]) fmt.Println("總序列", arr) fmt.Println("--------------------") if left < i-1 { QuickSort(arr, left, i-1) } if i+1 < right { QuickSort(arr, i+1, right) } }
運行結果