堆存儲、堆排序 python實現

|—使用堆實現優先隊列:
    對於總共N個請求 使用普通數組或者順序數組 最差情況O(N^2)
    使用堆 O(N*Log N)


|-堆的基本實現
    二叉堆:任何一個子節點都不大於他的父節點
            必須是一棵完全二叉樹
            用數組存儲二叉堆:
|-shift up
|-shift down
|-基礎堆排序
    heapSort1
|-heapify 堆排序
    建堆的過程直接構建 不用挨個元素插入
    新建一個堆的構造函數 , 傳入一個數組arr 和 該數組長度n


|-原地堆排序
    堆的索引從數組下標0開始
    無需額外的空間
    parent(i) = (i-1)/2
    left child(i) = 2*i +1

    right child(i) = 2*i +2

源代碼:
https://github.com/lzneu/Algrithm_python

import random
import numpy as np
import datetime

def genNearlyOrderArray(n, swapTimes):
    arr = list(range(n))
    for i in range(swapTimes):
        x = random.randint(0, n)
        y = random.randint(0, n)
        swap(arr, x, y)
    return arr


def genRandomArray(n, start=0, end=10000):
    return np.random.randint(start, end, size=n)


def aTestSort(sortName, arr, n):
    t_start = datetime.datetime.now()
    sortName(arr, n)
    t_end = datetime.datetime.now()  # 記錄函數結束時間)
    long = (t_end - t_start).total_seconds()
    if isSorted(arr, n):
        print("sortName: %s, time: %f s" % (sortName.__name__, long))
    else:
        print('Sort ERROR!')


def swap(arr, i, j):
    temp = arr[i]
    arr[i] = arr[j]
    arr[j] = temp

def isSorted(arr, n):
    for i in range(n - 1):
        if (arr[i] > arr[i + 1]):
            return False
    return True
from tools import *
import sorting_advanced


class MaxHeap:

    def __init__(self):
        self.__data = [0]
        self.__count = 0

    # 構造函數 給定一個數組創建一個最大堆 時間複雜度O(n)
    def buildHeap(self, arr):
        n = len(arr)
        self.__count = n
        self.__data = [0]
        self.__data.extend(arr)
        for i in range(n // 2):
            index = n // 2 - i
            self.__shiftDown(index)

    def size(self):
        return self.__count

    def isEmpty(self):
        return self.__count == 0

    def __swap(self, i, j):
        temp = self.__data[i]
        self.__data[i] = self.__data[j]
        self.__data[j] = temp

    # 最大堆核心輔助函數
    def __shiftUp(self, k):
        while (k > 1) and (self.__data[(k // 2)] < self.__data[k]):
            self.__swap(k // 2, k)
            k = k // 2

    def insert(self, item):
        self.__data.append(item)
        self.__count += 1
        self.__shiftUp(self.__count)

    def __shiftDown(self, k):
        # 判斷有無左孩子
        while (2 * k <= self.__count):
            j = 2 * k  # 在此輪循環中 data[k] 與 data[j] 交換位置
            if (j + 1 <= self.__count and self.__data[j + 1] > self.__data[j]):
                j += 1
            if (self.__data[k] >= self.__data[j]):
                break
            self.__swap(k, j)
            k = j

    # 從隊中去除堆頂元素 即堆中所存儲的最大元素
    def extractMax(self):
        if self.__count <= 0:
            raise IndexError
        ret = self.__data[1]
        self.__swap(1, self.__count)
        self.__data.pop(self.__count)
        self.__count -= 1
        self.__shiftDown(1)
        return ret


def heapSort1(arr, n):
    maxHeap = MaxHeap()
    for i in range(n):
        maxHeap.insert(arr[i])
    for i in range(n):
        index = n - 1 - i
        arr[index] = maxHeap.extractMax()


def heapSort2(arr, n):
    maxHeap = MaxHeap()
    maxHeap.buildHeap(arr)
    for i in range(n):
        index = n - 1 - i
        arr[index] = maxHeap.extractMax()


def __shiftDown2(arr, n, k):
    temp = arr[k]
    # 判斷有無孩子
    while (2 * k + 1 <= n - 1):
        j = 2 * k + 1
        if j + 1 < n and arr[j + 1] > arr[j]:
            j += 1
        if temp >= arr[j]:
            break
        arr[k] = arr[j]
        k = j
    arr[k] = temp


# 原地堆排序
def heapSort(arr, n):
    # 從最後一個非葉子節點開始 n-1-1 // 2
    for i in range((n - 1 - 1) // 2, -1, -1):
        __shiftDown2(arr, n, i)
    for i in range(n - 1, 0, -1):
        swap(arr, i, 0)
        __shiftDown2(arr, i, 0)


if __name__ == '__main__':
    # # 測試堆的數據結構
    # maxHeap = MaxHeap()
    # print(maxHeap.size())
    # for i in range(50):
    #     a = random.randint(0, 100)
    #     maxHeap.insert(a)
    #     # print(a)
    #
    # while(maxHeap.size() != 0):
    #     num = maxHeap.extractMax()
    #     print(num)

    n = 100000
    start = 0
    end = 100000
    # arr = genNearlyOrderArray(n, swapTimes=100)
    arr = genRandomArray(n, start, end)
    arr2 = arr.copy()
    arr3 = arr.copy()
    arr4 = arr.copy()
    arr5 = arr.copy()
    aTestSort(heapSort1, arr, n)
    aTestSort(heapSort2, arr2, n)
    aTestSort(sorting_advanced.quickSort2, arr3, n)
    aTestSort(sorting_advanced.quickSort3Ways, arr4, n)
    aTestSort(heapSort, arr5, n)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章