對於總共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)