1. 程式人生 > >資料結構之內部排序--希爾排序

資料結構之內部排序--希爾排序

概要

-IDE:Pycharm
-Python版本:python3.x
-演算法分類:內部排序->插入類排序->希爾排序

演算法思想

希爾排序又稱縮小增量排序法,是一種基於插入思想的排序方法。它利用了直接插入排序的最佳性質,首先,將待排序的關鍵字序列分成若干個較小的序列,對子序列進行直接的插入排序,使整個待排序列排好序。
過程如下:
1.首先選定記錄間的距離$d_i(i=1)$,在整個待排序記錄序列中將所有間隔為$d_1$的記錄分成一組,進行組內直接插入排序。
2.然後選取$i=i+1$,記錄間的距離為$d_i(d_i<d_i-_1)$,在整個待排序記錄序列中,將所有間隔為$d_i$的記錄分成一組,進行組內直接插入排序。
3.重複步驟2直至記錄間的距離$d_i=1$,此時整個只有一個子序列,對該序列進行直接插入排序,完成整個排序過程。

演算法要點

增量取法

關於增量$d$的取法,最初希爾提出取$d=[n/2]$,再取$d=[d/2]$,直到$d=1$為止。該思路的缺點是,奇數位置的元素在最後一步才會與偶數位元素進行比較,使得排序效率低。後來Knuth提出$d=[d/3]+1$。此外還有多種取法,但無法證明那種最優。

逆轉數

為了分析希爾排序的優越性,這裡引入逆轉數的概念。對於待排序列中的某個記錄的關鍵字,它的逆轉數是指在它之前比此關鍵字大的關鍵字個數。
假設:被調換位置的兩個關鍵字之間有$l$個介於兩個關鍵字之間的數。逆轉數之和一定會減小$2l+1$
當逆轉數為$0$時則表明整個排序完成。

穩定性與時間複雜度

排序演算法 穩定性 時間複雜度 最好情況 最壞情況 空間複雜度
希爾排序 不穩定 $O(n^{1.5})$ $O(1)$

Python程式碼清單

# !/usr/bin/python3
# _*_  coding:utf-8  _*_
# 希爾排序
 
import random, time, sys
 
 
def SS(number,maxNumber):
    # 生成隨機數
    timeStart = time.time()
    listA = [0]  # 0位 一般都空出來,防止out of index 或者做監視哨或者備份某個值。
    for i in range(number):
        listA.append(random.randint(0, maxNumber))  # 新增生成的值。
 
    timeEnd = time.time()
    timeIs = timeEnd - timeStart
    listD = [0, int(number/2)]  # listD用於存放增量d,第0位用0佔位,我們從第一位開始迴圈。
    while True:
        if listD[-1] != 1:  # 判斷最後一個元素(增量)是否是1,若不是繼續計算增量。
            listD.append(int(listD[-1]/3)+1)  # 計算增量
        else:
            break  # 若是1,則退出迴圈。
 
    print('生成%d個數的時間是%f' % (number, timeIs))
    # print(listA[1:])  # 從第一位開始輸出。0位不顯示。
    # print(listD[1:])  # 輸出d的增量的列表
    ####################################################
    # 希爾排序演算法。  我認為 右邊是前,左邊是後。
    timeStart = time.time()  # 開始記錄時間
    #  演算法開始
    for d in listD[1:]:  # 設定迴圈的次數,與d有關係。
        base = 1 + d  # 從前向後找,從哦能通過d+1位開始。
        for item in range(base, len(listA)):  # 每次增加一位
            if listA[item] < listA[item-d]:  # 如果遇到前面小,後面大的數,
                listA[0] = listA[item]  # 複製前面的數
                aim = item-d  # 選定目標的位置。
                while True:  # 開始迴圈查詢序列。
                    if aim > 0 and listA[0] < listA[aim]:  # 這裡應設定條件,以防無限迴圈。
                        listA[aim + d] = listA[aim]  # 將選定目標位的數後移。
                        aim = aim - d   # 每次向前查詢,步長為d
                    else:
                        break  # 條件不符合 break 出
                listA[aim+d] = listA[0]  # 把目標值放入目標位。加d是因為在迴圈時多減了d。
    #  演算法結束
    timeEnd = time.time()  # 記錄結束時間。
    timeIs = timeEnd - timeStart  # 排序花費的時間
    print('排序%d個數,花費的時間是%f' % (number, timeIs))
    # print(listA[1:])  # 列印最後排序的列表。
 
 
if __name__ == '__main__':
 
    helpInfo = '''
           This program is for Shell's Sort.
           How to use it! Follow the example!
 
           python Shell's_Sort.py 10 100
 
           The 10 representative will generate ten numbers.
           100 representative the max-number you make.
 
       '''
 
    command = sys.argv[0:]  # 獲取從鍵盤輸入的值。
    if len(command) != 3 or 'help' in command:  # 判斷是否合法,或包含help
        print(helpInfo)  # 列印幫助文字。
    else:
        try:  # 嘗試將輸入轉化為整數。
            number = int(command[1])
            maxNumber = int(command[2])
        except ValueError:  # 數值型錯誤。
            print(helpInfo)  # 列印幫助。
            sys.exit(1)  # 退出程式。
        SS(number, maxNumber)  # 一切完好,呼叫函式。

有什麼問題請聯絡我

QQ:3116316431 (請附上資訊)
E-mail:[email protected]