1. 程式人生 > >python中的冒泡、快速、堆排序及二分法查詢

python中的冒泡、快速、堆排序及二分法查詢

 

 

氣泡排序

它重複地走訪過要排序的元素列,依次比較兩個相鄰的元素,如果他們的順序(如從大到小、首字母從A到Z)錯誤就把他們交換過來。走訪元素的工作是重複地進行直到沒有相鄰元素需要交換,也就是說該元素已經排序完成。

第一種

def bubble_sort(list):
    for index,element in enumerate(list):
        for sub_index in range(index):
            if list[sub_index] > list[sub_index + 1]:
                list[sub_index],list[sub_index + 1] = list[sub_index + 1],list[sub_index]
    return list
print(bubble_sort([3,9,1,5,6,20])) #[1, 3, 5, 6, 9, 20]

 第二種

def bubble(bubbleList):
    listLength = len(bubbleList)
    while listLength > 0:
        for i in range(listLength - 1):
            if bubbleList[i] > bubbleList[i + 1]:
                bubbleList[i],bubbleList[i + 1]= bubbleList[i+1],bubbleList[i]
        listLength -= 1
    print(bubbleList) #[0, 1, 2, 3, 4, 5, 8]


if __name__ == '__main__':
    bubbleList = [3, 4, 1, 2, 5, 8, 0]
    bubble(bubbleList) 

快速排序

通過一趟排序將要排序的資料分割成獨立的兩部分,其中一部分的所有資料都比另外一部分的所有資料都要小,然後再按此方法對這兩部分資料分別進行快速排序,整個排序過程可以遞迴進行,以此達到整個資料變成有序序列

第一種

# 首先從列表中挑出一個元素作為基準值key,所有小於key的值放right,大於的方left,分別遞迴左右側元素
def quick_sort(list,left,right):
    # 在遞迴的過程在,如果發現left和right一致時,停滯遞迴,直接返回列表
    if left >= right:
        return list
    # 定義遊標
    low = left
    high = right

    # 取參考值,最左邊的列表
    key = list[low]
    while low < high:
        # 從最右側向左,依次和標誌元素對比,如果右側的元素大於標誌的元素
        while low < high and list[high] >= key:
            # 右側減一
            high -= 1
        # 不然就把high賦值給low
        list[low] = list[high]

        # 從最左側向右,依次和標誌元素對比,如果左側的元素大於標誌的元素
        while low < high and list[low] <= key:
            # 左側加一
            low += 1
        # 不然就把high賦值給low
        list[high] = list[low]
    # 最後給key的位置賦值
    list[high] = key

    # 處理左側的元素
    quick_sort(list,left,low-1)
    # 處理右側的元素
    quick_sort(list,low+1,right)
    return list
Dlist = [10,2,20,7,41,8,88,13]
print(quick_sort(Dlist,0,7)) #[2, 7, 8, 10, 13, 20, 41, 88]

 第二種

def quickSort(array):
    if len(array) < 2:  # 基線條件(停止遞迴的條件)
        return array
    else:  # 遞迴條件
        baseValue = array[0]  # 選擇基準值
        # 由所有小於基準值的元素組成的子陣列
        less = [m for m in array[1:] if m < baseValue]
        # 包括基準在內的同時和基準相等的元素,在上一個版本的百科當中,並沒有考慮相等元素
        equal = [w for w in array if w == baseValue]
        # 由所有大於基準值的元素組成的子陣列
        greater = [n for n in array[1:] if n > baseValue]
    return quickSort(less) + equal + quickSort(greater)
# 示例:
array = [2,3,5,7,1,4,6,15,5,2,7,9,10,15,9,17,12]
print(quickSort(array))
# 輸出為[1, 2, 2, 3, 4, 5, 5, 6, 7, 7, 9, 9, 10, 12, 15, 15, 17]

堆排序

是指利用這種資料結構所設計的一種排序演算法。堆是一個近似完全二叉樹的結構,並同時滿足堆積的性質:即子結點的鍵值或索引總是小於(或者大於)它的父節點。

在堆的資料結構中,堆中的最大值總是位於根節點(在優先佇列中使用堆的話堆中的最小值位於根節點)。堆中定義以下幾種操作:

  • 最大堆調整(Max Heapify):將堆的末端子節點作調整,使得子節點永遠小於父節點

  • 建立最大堆(Build Max Heap):將堆中的所有資料重新排序

  • 堆排序(HeapSort):移除位在第一個資料的根節點,並做最大堆調整的遞迴運算

第一種

def heap_sort(list):
    def adjust(start,end):
        '''最大堆調整'''
        root = start
        while True:
            child = 2 * root + 1
            # 孩子的索引值超過陣列最大長度
            if child > end:
                break
            # 確定最大的孩子節點的索引值
            if child + 1 <= end and list[child] < list[child + 1]:
                child += 1
            # 孩子節點最大值和根節點進行交換
            if list[root] < list[child]:
                list[root],list[child] = list[child],list[root]
                root = child
            else:
                break
    # 建立大根堆
    for start in range((len(list) - 2) // 2,-1,-1):
        adjust(start,len(list) - 1)

    for end in range(len(list) - 1,0,-1):
        # 首尾交換
        list[0],list[end] = list[end],list[0]
        # 重新排序
        adjust(0,end-1)
    return list
alist = [57,34,11,20,23,1,4,5]
print(heap_sort(alist)) #[1, 4, 5, 11, 20, 23, 34, 57]

第二種

def big_endian(arr, start, end):
    root = start
    while True:
        child = root * 2 + 1  # 左孩子
        if child > end:  # 孩子比最後一個節點還大 也就意味著最後一個葉子節點了 就得跳出去一次迴圈已經調整完畢
            break
        if child + 1 <= end and arr[child] < arr[child + 1]:  # 為了始終讓其跟子元素的較大值比較 如果右邊大就左換右,左邊大的話就預設
            child += 1
        if arr[root] < arr[child]:  # 父節點小於子節點直接換位置 同時座標也得換這樣下次迴圈可以準確判斷是否為最底層是不是調整完畢
            arr[root], arr[child] = arr[child], arr[root]
            root = child
        else:  # 父子節點順序正常 直接過
            break


def heap_sort(arr):
    # 無序區大根堆排序
    first = len(arr) // 2 - 1
    for start in range(first, -1, -1):  # 從下到上,從右到左對每個節點進調整 迴圈得到非葉子節點
        big_endian(arr, start, len(arr) - 1)  # 去調整所有的節點
    for end in range(len(arr) - 1, 0, -1):
        arr[0], arr[end] = arr[end], arr[0]  # 頂部尾部互換位置
        big_endian(arr, 0, end - 1)  # 重新調整子節點的順序  從頂開始調整
    return arr


def main():
    l = [3, 1, 4, 9, 6, 7, 5, 8, 2, 10]
    print(heap_sort(l))  # 原地排序 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]


if __name__ == "__main__":
    main()

二分法查詢

演算法:二分法查詢適用於資料量較大時,但是資料需要先排好順序。主要思想是:(設查詢的陣列區間為array[low, high])

確定該區間的中間位置K(2)將查詢的值T與array[k]比較。若相等,查詢成功返回此位置;否則確定新的查詢區域,繼續二分查詢。區域確定如下:a.array[k]>T 由陣列的有序性可知array[k,k+1,……,high]>T;故新的區間為array[low,……,K-1]b.array[k]<T 類似上面查詢區間為array[k+1,……,high]。每一次查詢與中間值比較,可以確定是否查詢成功,不成功當前查詢區間將縮小一半,遞迴查詢即可。

def dichotomy(list1, target):
    length = len(list1)
    index_low = 0
    index_high = length - 1

    while index_low <= index_high:
        index_midle = int((index_low + index_high) / 2)
        guess = list1[index_midle]
        if guess == target:
            return index_midle
        elif guess > target:
            index_high = index_midle - 1
        elif guess < target:
            index_low = index_midle + 1
    return None


list_1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
target_1 = 3
print(dichotomy(list_1, target_1)) #返回 2