這篇博文用來介紹直接插入排序
直接插入排序基本思想:
每次將一個待排序的記錄插入到已經排好序的數據區中,直到全部插入完為止
直接插入排序算法思路:
在直接插入排序中,數據元素分為了有序區和無序區兩個部分,在這里我們將列表左邊部分作為有序區,列表右邊部分作為無序區,有序區和無序區的大小是隨着排序的進行而變化的。
如最開始列表是無序的,所以有序區長度為1,無序區長度為列表長度-1,排序結束后,列表變為有序,則有序區長度為列表長度,無序區長度為0.
具體步驟為:
排序過程中每次從無序區中取出第一個元素,將它插入到有序區中的適當位置(即該元素放在此位置,有序區仍然有序),使之成為新的有序區,重復n-1次可完成排序過程。
假設需要將列表從小到大排序
想要將從無序區中取出的第一個元素temp插入到有序區中的適當位置,需要有一個循環遍歷的過程,即從該元素位置處依次向前比較,會有兩種情況:
1,前面的元素waitsortlist[j-1]大於temp,則temp需要繼續向前比較,同時大於temp的元素需要后移一位
2,前面的元素waitsortlist[j-1]小於等於temp,則temp不需要繼續比較了,因為temp大於有序區中最大的元素,有序區伸展一位,包含temp
另外還需要考慮 j 的邊界問題,因為會用到 j-1,所以 j 需要>=1防止越界,對於無序區某一個元素temp的直接插入代碼如下:
temp=waitsortlist[j] while j>=1: if temp<waitsortlist[j-1]: waitsortlist[j]=waitsortlist[j-1] j=j-1 else: break waitsortlist[j]=temp
外層是一個列表的遍歷,加上上面的代碼為:
i=0 j=i+1 while j<len(waitsortlist): temp=waitsortlist[j] while j>=1: if temp<waitsortlist[j-1]: waitsortlist[j]=waitsortlist[j-1] j=j-1 else: break waitsortlist[j]=temp i=i+1 j=i+1
可以看出,列表的第一個元素必為有序區,遍歷的過程中不斷擴大有序區的范圍,對於列表某一個元素來說,就是將其插入在有序區中適當的位置,外層循環遍歷結束后,有序區也擴充為列表長度,即排序結束。
該算法的時間復雜度為O(n^2),因為有兩層循環,時間開銷比較大,空間復雜度為O(1),只是用了常數階的空間來存儲變量,用以直接插入排序
全部代碼為(實際上看了前面的相信你已經能寫出來了:D
''' 直接插入排序 ''' def DirectInsertionSort(waitsortlist): i=0 j=i+1 while j<len(waitsortlist): temp=waitsortlist[j] while j>=1: if temp<waitsortlist[j-1]: waitsortlist[j]=waitsortlist[j-1] j=j-1 else: break waitsortlist[j]=temp i=i+1 j=i+1 return waitsortlist if __name__=='__main__': waitsortlist=[9,8,7,6,5,4,3,2,1,0] print(DirectInsertionSort(waitsortlist))
運行結果為:
直接插入排序 (帶監視哨):
哨兵的概念:一切為簡化邊界條件而引入的附加結點(元素)均可稱為哨兵。
在上面的代碼我們可以看到有這一段:
while j>=1:
內循環每一次比較前都需要判斷 j 是否越界,有沒有不需要判斷的辦法呢?當然有,這就是哨兵的作用
將上面的代碼改為:
def DirectInsertionSortEye(waitsortlist): i=1 j=i+1 while j<len(waitsortlist): temp=waitsortlist[j] waitsortlist[0]=temp while temp<waitsortlist[j-1]: waitsortlist[j]=waitsortlist[j-1] j=j-1 waitsortlist[j]=temp i=i+1 j=i+1 return waitsortlist if __name__=='__main__': waitsortlist=[0,9,8,7,6,5,4,3,2,1,0] print(DirectInsertionSortEye(waitsortlist))
輸出的結果為:
我們將waitsortlist[0]設置為哨兵,傳入列表的時候,該位置也不能夠放置有效元素,用列表一個元素的空間判斷越界與否的比較時間。可以看出,一次循環少判斷一次,n次循環少判斷n次,當數據量較大時,很明顯是優於不帶監視哨的直接插入排序。
帶監視哨的直接插入排序思想也很簡單,在原有基礎上稍加修改即可,這里不再贅述。