5堆排序
1树与二叉树
树是一种数据结构,可以用递归来定义
树是由n个节点组成的集合:如果n=0,则是一个空树;如果n>0,则存在1个节点作为树的根节点,其他节点可以分为m个集合,每个集合本身又是一棵树。
二叉树:度不超过2的树;
每个节点最多有两个孩子节点,两个孩子节点被区分为左孩子节点和右孩子节点。
满二叉树:一个二叉树,如果每一个层的结点都达到了最大值。
完全二叉树:叶子节点只能出现在最下层和次下层,并且最小面一层节点都集中在该层最左边的若干位置的二叉树。
2二叉树的存储方式
1链式存储方式
2顺序存储方式
如果已知子节点的编号,可以通过:(子节点编号-1)/2(整除以2)得到父节点的编号。
3堆
特殊的完全二叉树结构
大根堆:一颗完全二叉树,满足任意节点都比其孩子节点大;
小根堆:一颗完全二叉树,满足任意节点都比其孩子节点小。
堆的向下调整:
4堆排序过程
(1)建立堆
(2)得到堆顶元素,为最大元素
(3)去掉堆顶,将堆最后一个元素放到堆顶,此时可通过依次调整重新使堆有序
(4)堆顶元素为第二大元素
(5)重复步骤3,直到堆变空
堆排序过程的视频演示:
https://www.bilibili.com/video/BV1uA411N7c5?p=22&share_source=copy_web
def sift(list,first,last): # list:列表 first:堆的根节点位置 last:堆的最后一个元素位置
## 向下调整函数
i=first
j=2*i+1
tmp=list[first]
while j<=last:
if j+1<=last and list[j+1]>list[j]:
j=j+1
if list[j]>tmp:
list[i]=list[j]
i=j
j=2*i+1
else:
list[i]=tmp # 把tmp放到非叶子节点上
break
else:
list[i]=tmp # 把tmp放到叶子节点上
def heapsort(list,first,last):
n=len(list)
for i in range((n-2)//2 ,-1, -1):
sift(list,i,n-1) # last可以简化被赋为n-1,last在代码中的作用仅为判断j编号是否越界,因此并不影响是否越界的判断,因为一旦出现子节点,其编号比然大于最后一个节点的编号。
# 完成了堆的构建
for i in range(n-1,-1,-1):
list[0],list[i]=list[i],list[0]
sift(list,0,i-1) # i-1是新的last 原来的last已经放进了被排除堆的i
import random
list=[random.randint(10,100) for i in range(15)]
print(list)
heapsort(list,0,len(list)-1)
print(list)
```![在这里插入图片描述](https://img-blog.csdnimg.cn/0d7186e11ea042e7b6245b9192b59fe2.png)
5堆排序的时间复杂度
O(nlogn)
6堆的内置模块
```python
import heapq
import random
list=list(range(15))
print(list)
random.shuffle(list)
print(list)
heapq.heapify(list) # 建堆
n=len(list)
for i in range(n):
print(heapq.heappop(list),end=',') # 排序
堆排序应用——topk问题
现在有n个数,设计算法得到前k大的数(k<n)
解决思路:
1排序后切片 O(nlogn)
2冒泡、选择、插入排序 O(kn)
3堆排序 O(nlogk)
def sift(list,first,last): # list:列表 first:堆的根节点位置 last:堆的最后一个元素位置
## 向下调整函数
i=first
j=2*i+1
tmp=list[first]
while j<=last:
if j+1<=last and list[j+1]<list[j]:
j=j+1
if list[j]<tmp:
list[i]=list[j]
i=j
j=2*i+1
else:
list[i]=tmp # 把tmp放到非叶子节点上
break
else:
list[i]=tmp # 把tmp放到叶子节点上
def topk(list,k):
heap=list[0:k]
for i in range((k-2)//2,-1,-1):
sift(heap,i,k-1)
## 构建堆
for i in range(k,len(list)):
if list[i]>heap[0]:
heap[0]=list[i]
sift(heap,0,k-1)
## 遍历 将列表中剩下的n-k个数与heap[0]一一对照
for i in range(k-1,-1,-1):
heap[0],heap[i]=heap[i],heap[0]
sift(heap,0,i-1)
## 输出 按从大到小进行排序
return heap
import random
list=[1,4,32,0,23,76,3,8,999]
print(list)
print(topk(list,5))
``
# 结果:
输入[25, 66, 27, 49, 33, 43, 91, 43, 40, 943]
输出[943, 91, 66, 49, 43]