排序算法之插入排序及其優化

#插入排序html


其餘排序方法:選擇排序冒泡排序歸併排序快速排序插入排序希爾排序python


##思想 先將數組第一個元素做爲一個排好序的序列,而後將數組中剩下的元素從左往右一個一個地按照大小插進此序列裏,所插位置後面的元素都日後移一位,直到元素所有插完。 這個很好理解,就像咱們玩撲克牌的時候,一張一張地摸牌,剛摸到手的一張牌,找到合適的位置後,插進去,右邊的牌就要挪個位置。算法

##圖解 再次借用一下百科的圖emmm: shell

##性能 插入排序最好的狀況就是你每次插入的元素都恰好是插在最後,那就只用進行n-1次比較就好了,時間複雜度爲O(n); 最壞狀況的時間複雜度顯然是O(n2),平均時間複雜度也爲O(n2)。數組

##代碼 在找出正確的插入位置時,先比較先後元素位置是否正確,正確的話就結束循環;不正確的話,前面的元素日後移一位,繼續比較前一位。 有兩種方式,一種就是每比較一次就互換位置,另外一種就是先記住須要插入的元素,須要換位置的時候就先把前一位元素後移一位,等找到合適的位置在插入。 這時候有些人就會圖方便(譬如我),選擇第一種方式,這樣代碼寫起來好看,也容易理解,但這樣子效率會比第二種方式低。 因此仍是推薦使用第二種方式。數據結構

# 插入排序
def insertionSort1(arr):
    for i in range(1, len(arr)):
        j = i
        while j > 0:
            if arr[j] < arr[j - 1]:
                arr[j], arr[j - 1] = arr[j - 1], arr[j] #這裏能夠改進一下
                j -= 1
            else:
                break

def insertionSort2(arr):
    for i in range(1, len(arr)):
        key = arr[i]
        j = i
        while j > 0:
            if arr[j - 1] > key:
                arr[j] = arr[j - 1]
                j -= 1
            else:
                break
        if (i != j): arr[j] = key

##優化 上面的排序算法也叫直接插入排序,那也就是說有不那麼直接的插入排序咯。 直接插入排序是從後往前一個個地進行比較來找出插入位置的。學過查找算法的人都知道這樣並不高效,咱們能夠利用其餘查找方法來代替它。性能

###優化一 二分插入排序 二分插入排序是指在簡單插入排序的基礎上用二分查找算法來找出插入位置的排序算法。大數據

# 二分查找
# size 爲有序部分大小
def binarySearch(arr, size, key):
    # 最左下標爲0, 最右下標爲size-1
    left, right = 0, size - 1
    while left <= right:
        # mid爲中間元素的下標
        mid = left + right >> 1
        # 中間元素恰好與插入元素相同時,返回中間元素後一位的下標
        if key == arr[mid]:
            return mid + 1
        elif key < arr[mid]:
            # 查找左半邊
            right = mid - 1
        else:
            # 查找右半邊
            left = mid + 1
    # 結束循環時,left一定等於right+1
    # 最後一次查找若是是查找左半邊,則key比arr[mid]小,key應該插入到mid的位置,而mid等於如今的right+1等於left
    # 最後一次查找若是是查找右半邊,則key比arr[mid]大,key應該插入到mid+1的位置,而mid+1等於如今的left
    # 因此只需返回left
    return left


# 二分插入排序(插入排序優化一)
def binarySort(arr):
    for i in range(1, len(arr)):
        # 須要插入的元素
        key = arr[i]
        # 利用二分查找來找到插入的位置
        pos = binarySearch(arr, i, key)
        j = i
        # 插入位置後面的元素所有後移一位
        while j > pos:
            arr[j] = arr[j - 1]
            j -= 1
        # 插入元素
        arr[j] = key

###優化二 希爾排序 直接插入排序在找到插入位置時,須要一個一個地日後移動元素。有沒有什麼辦法能夠一會兒移動多個呢?答案是不能夠哈哈。 由於元素已是有序的,新的元素插到中間,那其右邊的元素一定都要日後移一位。 咱們換個角度來想,有序不行,那就在元素仍是無序的時候,跳着來移動。這就要提到希爾排序算法了。優化

希爾排序大概就是,選一組遞減的整數做爲增量序列。最小的增量必須爲1:\(D_M>D_{M-1}>...>D_1=1\)spa

  • 先用第一個增量把數組分爲若干個子數組,每一個子數組中的元素下標距離等於增量;
  • 而後對每一個子數組進行簡單插入排序
  • 再使用第二個增量,繼續一樣的操做,直到增量序列裏的增量都使用過一次。 (增量爲1時,其實就是對整個數組進行簡單插入排序)

看圖更容易理解吧: (借用一下慕課的浙大數據結構課件。由於課件本來是ppt,而我只有pdf,因此顏色沒有上齊,請將就將就emmm)

希爾排序快不快主要取決於咱們怎麼取增量序列,最多見的取法就是:\(D_M=\lfloor N/2 \rfloor, D_k=\lfloor D_{k+1}/2 \rfloor\)

# 希爾排序
# 增量序列爲D(M)=N/2, D(k)=D(k+1)/2 向下取整
def shellSort(arr):
    size = len(arr)
    # 正整數右移一位至關於除以2且向下取整
    step = size >> 1
    while step > 0:
        for i in range(step, size):
            j = i
            tmp = arr[j]
            while j >= step:
                if tmp < arr[j - step]:
                    arr[j] = arr[j - step]
                    j -= step
                else:
                    break
            arr[j] = tmp
        step = step >> 1

這就是原始希爾排序,關於希爾排序的其餘增量序列我會在下一篇文章再做介紹:希爾排序


其餘排序方法:選擇排序冒泡排序歸併排序快速排序插入排序希爾排序

相關文章
相關標籤/搜索