-
Notifications
You must be signed in to change notification settings - Fork 1
/
heap.py
171 lines (140 loc) · 4.18 KB
/
heap.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File : heap.py
# @Author: 投笔从容
# @Date : 2018/5/23
# @Desc : 堆 和 堆排序
'''
|—使用堆实现优先队列:
对于总共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
'''
import random
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: object) -> object:
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)