树的定义
二叉树
满二叉树与完全二叉树
完全二叉树=满二叉树拿走几个(只能右边拿走,左边必须充满的)
例如:1.在下图的b中删去12号也是完全二叉树
2.在下图的b中删去12,11也是完全二叉树
3.在下图的b中删去9不是完全二叉树
就是横过来读
公式*2:1.已知父节点下标为i,左子节点下标为2*i+1,右子节点下标为2*i+2
2.已知子节点(左右都一样)下标为j,父节点下标为(j-1)//2
堆的定义:以下单独来看都可称之为堆,把堆比作行政机关的话,上一级的人员的能力值都比下一级(自己控制区域)的人员能力值高,称为大根堆。同理,上一级的人员的能力值都比下一级(自己控制区域)的人员能力值低,称为小根堆
堆的性质——向下调整性质
如何理解见下
比如这个省长2的“能力值”不太行,但是他的下面的县都是堆(合理控制的县)所以向下调整2的位置
把9,7之间较大的一个挪到省长的位置,然后发现2连县长都当不了,就把8,5中更大的挪到县长位置。
最后发现2连村长都当不了,所以最终成为村民(即堆的最底层)
堆排序过程:
1.建立堆(“农村包围城市”从乡县开始建)
2.得到堆顶元素为最大元素
3.去掉堆顶,将堆最后一个元素放到堆顶,此时可通过一次调整重新使堆有序
4.堆顶元素为第二大元素
5.重复步骤三,直到堆变空
但一般为了节省空间复杂度,会将树此时的最大元素直接与最后一个元素交换,然后标记i来确定有序区与树,进而有序区不参与下一轮向下调整。
算法的代码实现
第一步:写出向下调整函数
def sift(li,low,high):#向下调整函数
'''
li:列表
low:堆的根节点位置
high:堆的最后一个元素的位置
'''
i=low #i最开始指向根节点
j=2*i+1 #j开始是左孩子
tmp=li[low] #把堆顶封存起来
while j<=high: #只要j位置有数(i->父亲 j->孩子)
if j+1<=high and li[j+1]>li[j]: #如果有右孩子并且比较大
j=j+1 #j指向右孩子,不能左右交换,0->6.5
if li[j]>tmp:
li[i]=li[j]
i=j #往下看一层
j=2*i+1 #j=2*j+1同。tmp更大,把tmp放到i的位置上
else: #把tmp放到某一级领导位置上
break
li[i]=tmp #把tmp放到某一级领导位置上(不满足while条件,即j超过high说明i是最后一层)
#while 完->j 指向孩子中大的
第二步 排序算法的完成:
1.建立堆(农村包围城市)
def heap_sort(li):
n=len(li)
for i in range((n-2)//2,-1,-1): #i表示建堆的时候调整的部分的根的下标
sift(li,i,n-1) # 建堆完成了,这里用n-1原因是j超过上面的high放缩为j超过下面的high,更方便求
2.完成234步
def heap_sort(li):
n=len(li)
for i in range((n-2)//2,-1,-1): #i表示建堆的时候调整的部分的根的下标
sift(li,i,n-1) # 建堆完成了,这里用n-1原因是j超过上面的high放缩为j超过下面的high,更方便求
for i in range (n-1,-1,-1): #i指向当前堆的最后一个元素
li[0],li[i]=li[i],li[0]
sift(li,0,i-1) #i-1是新的high
第三步,整体实现
def sift(li,low,high):#向下调整函数
'''
li:列表
low:堆的根节点位置
high:堆的最后一个元素的位置
'''
i=low #i最开始指向根节点
j=2*i+1 #j开始是左孩子
tmp=li[low] #把堆顶封存起来
while j<=high: #只要j位置有数(i->父亲 j->孩子)
if j+1<=high and li[j+1]>li[j]: #如果有右孩子并且比较大
j=j+1 #j指向右孩子,不能左右交换,0->6.5
if li[j]>tmp:
li[i]=li[j]
i=j #往下看一层
j=2*i+1 #j=2*j+1同。tmp更大,把tmp放到i的位置上
else: #把tmp放到某一级领导位置上
break
li[i]=tmp #把tmp放到某一级领导位置上(不满足while条件,即j超过high说明i是最后一层)
#while 完->j 指向孩子中大的
def heap_sort(li):
n=len(li)
for i in range((n-2)//2,-1,-1): #i表示建堆的时候调整的部分的根的下标
sift(li,i,n-1) # 建堆完成了,这里用n-1原因是j超过上面的high放缩为j超过下面的high,更方便求
for i in range (n-1,-1,-1): #i指向当前堆的最后一个元素
li[0],li[i]=li[i],li[0]
sift(li,0,i-1) #i-1是新的high
from random import *
from time import time
start_time=time()
a=[i for i in range(10000)]
shuffle(a)
print(a)
heap_sort(a)
end_time=time()
used_time=end_time-start_time
print(a)
print(used_time)
运行结果展示
时间复杂度O(nlogn)
另附:python自带的树模块的函数应用
heapify建堆函数,默认为小根堆
部分图片参考自b站IT编程界的扛把子的python算法学习视频,本文仅供个人学习使用,特此声明