排序>>交換排序>>地精排序
List:
1 2 3 4 |
0.概念+虛擬碼+示例分析 1.地精排序實現 2.改進 3.Question |
- start
基本概念:
維基百科:http://en.wikipedia.org/wiki/Gnome_sort(目前只有英文版的)
地精排序又稱侏儒排序,類似於插入排序,但是將一個數放入其正確位置的交換同氣泡排序(一系列交換)
簡單,只有一層迴圈,
時間複雜度O(n^2),最優複雜度O(n),平均時間複雜度O(n^2)
其實思想很簡單,往前冒泡,一旦發生資料交換,就往回冒泡,直到把被交換數字放入正確位置,之後,繼續前進
虛擬碼(來自於維基百科)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
procedure gnomeSort(a[]) pos := 1 while pos < length(a) if (a[pos] >= a[pos-1]) pos := pos + 1 else swap a[pos] and a[pos-1] if (pos > 1) pos := pos - 1 else pos := pos + 1 end if end if end while end procedure |
例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
[5, 3, 2, 4] #輸入陣列 i=0, i=i+1=1 #初始,i=0 ,直接i+=1 cmp l[0]= 5 l[1]= 3 change -> [3, 5, 2, 4] swap, i=i-1=0 #發生交換,i=i-1 i=0, i=i+1=1 #i=0,i+=1 cmp l[0]= 3 l[1]= 5 no swap, i=i+1=1 #無交換,i+=1 cmp l[1]= 5 l[2]= 2 change -> [3, 2, 5, 4] #交換 swap, i=i-1=1 #i=i-1,反向冒泡開始 cmp l[0]= 3 l[1]= 2 change -> [2, 3, 5, 4] swap, i=i-1=0 # 交換 i=0, i=i+1=1 cmp l[0]= 2 l[1]= 3 no swap, i=i+1=1 #無交換,i+=1 cmp l[1]= 3 l[2]= 5 no swap, i=i+1=2 #無交換,i+=1 cmp l[2]= 5 l[3]= 4 change -> [2, 3, 4, 5] swap, i=i-1=2 #交換,i-=1 cmp l[1]= 3 l[2]= 4 no swap, i=i+1=2 cmp l[2]= 4 l[3]= 5 no swap, i=i+1=3 #結束排序 |
1 start
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#!/usr/bin/python # -*- coding:utf-8 -*- # 地精排序 #@author: wklken@yeah.net def gnome_sort(l): i = 0 while i < len(l): if i == 0 or l[i - 1] < l[i]: #i=0或者正序不需交換,i+1 i += 1 else: #否則,交換兩數,i回退 l[i - 1], l[i] = l[i], l[i - 1] i -= 1 |
- start
觀察上面例子,是不是發現有些彆扭…….
1 2 3 4 5 6 |
[3, 5, 2, 4] #比較 5,2 [3, 2, 5, 4] #交換 [3, 2,5, 4] #比較 3,2 [2, 3, 5, 4] #交換 [2, 3, 5, 4] #比較2,3 [2, 3, 5, 4] #比較3,5 |
沒錯,若是到了b存在交換,反向冒泡,直至把被交換數冒泡放到其有序位置a,然後再從a->b進行比較冒泡
其實,a->b這一段序列已經是有序的,不需要浪費比較次數在這上面
所以我們進行jump
即,記錄b的位置,當發現反序冒泡沒有交換時(冒泡結束),jump到b位置,繼續正序冒泡
程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
def gnome_sort2(l): i = 0 current_index = 0 #儲存反向冒泡前位置 back_noswap = True #標識反向冒泡是否完成 while i < len(l): if i == 0 or l[i - 1] < l[i]: #i=0或者正序不需交換,i+1 i += 1 back_noswap = True else: #否則,交換兩數,i回退 l[i - 1], l[i] = l[i], l[i - 1] current_index = i + 1 #開始反序,記錄位置,跳轉回來後比較就是 i i+1兩個數的比較,之前數已有序 back_noswap = False i -= 1 print "change ->", l if current_index and back_noswap: #滿足 當前是反序冒泡,且未發資料交換,代表已結束,可以跳回 i = current_index current_index = 0 print "jump",i |
實際過程:
1 |
[5, 3, 2, 4] |
cmp 5 3
1 2 |
change -> [3, 5, 2, 4] jump 2 #這裡jump的位置是i+1 |
cmp 5 2
1 |
change -> [3, 2, 5, 4] |
cmp 3 2
1 |
change -> [2, 3, 5, 4] |
jump 2
cmp 3 5
cmp 5 4
1 |
change -> [2, 3, 4, 5] |
cmp 3 4
jump 4
相同例子的序列,改進前比較次數12,改進後只需要9次
- start
A.地精排序概念,過程描述?
B.時間複雜度?空間複雜度?是否是穩定排序?
C.適用場景,何種情況下表現最優
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!
任選一種支付方式