# 树与堆排序
# 树是一种数据结构
# 比如:目录结构
# 树是一种可以递归定义的数据结构
# 树是由n个节点组成的集合:
# 如果n=0,那这是一棵空树;
# 如果>0,那存在1个节点作为树的根节点,其他节点可以分为m个集合,每个集合本身又是一棵树。
# A
# B C D E F H
# I J K L
# 一些概念
# 根节点、叶子节点
# 树的深度(高度)
# 树的度
# 孩子节点/父节点
# 子树
# 满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。
# 完全二叉树:叶节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树。
# 二叉树的存储方式(表示方式)
# 链式存储方式
# 顺序存储方式【列表】
# 什么是堆?
# 堆:一种特殊的完全二叉树结构
# 大根堆:一棵完全二叉树,满足任一节点都比其孩子节点大(上层比下面一层大)
# 小根堆:一棵完全二叉树,满足任一节点都比其孩子节点小(上层比下层小)
# 堆排序一一堆的向下调整性质
# 假设:节点的左右子树都是堆,但自身不是堆
# 当根节点的左右子树都是堆时,可以通过一次向下的调整来将其变换成一个堆。
# 1.建立堆。
# 2.得到堆顶元素,为最大元素
# 3.去掉堆顶,将堆最后一个元素放到堆顶,此时可通过一次调整重新使堆有序。
# 4.堆顶元素为第二大元素。
# 5.重复步骤3,直到堆变空
# 堆排序调整 代码(时间复杂读O logn)
def sift(li, low, hight):
""""
:param li:列表
:param low: 堆的根节点(第一层的数字)
:param: hight:堆最后一层,最后的元素
第一层元素(i表示)与第二层左边(j表示)元素的关系:j = i*2+1
第一层元素(i表示)与第二层右边边(j表示)元素的关系:j = i*2+2
"""
i = low # i用来代表第一层(根节点)的元素
j = 2 * i +1 # j用来表示第二层。 第一层元素(i表示)与第二层左边(j表示)元素的关系:j = i*2+1
tmp = li[low] # 我们把堆顶(第一层)数字存起来
while j <= hight: # hight表示堆最后一层,最后的元素,j <= hight就能保证在J的位置上有数字。
if j + 1 <= hight and li[j + 1] > li[j]:
# 如果 下边一层+1 小于等于 最后一个元素 并且 列表[下面一层的第二个元素] 大于 列表
j = j + 1 # 选择 列表[下面一层的第二个元素]
if li[j] > tmp: # 如果列表下面一层 大于 上一层的数字
li[i] = li[j] # 把下面一层[j]写到上面一层来[i]
i = j # 再把 上面一层i的数字,写到第二层空白[之前的j]的位置
j = 2 * i + 1 # 继续进行第二层与第三层数字之间的关系判断
else: # li[j] < tmp 第一层tmp大于第二层li[j]的数字。
li[i] = tmp # 就把数字写回原来的位置li[i] = tmp
break #结束循环
else: #j > hight就能保证在J的位置上没有数字。
li[i] = tmp # 就把数字写回原来的位置li[i] = tmp
#建立堆
def heap_sort(li):
n = len(li) #n 表示列表的长度个数
for i in range((n-2)//2, -1, -1):
'''
i:表示建堆时调整的部分的根的下标(索引)
(n-1-1)//2: n-1表示索引列表总长度,n-1-1:表示索引最后一个数的位置的位置。(n-1-1)//2:索引最后一个数位置上一层的数的位置
第一个-1 表示范围:全部
第二个-1 表示步长:-1
'''
sift(li, i, n-1)
'''
li:列表
low(第一个元素):i 因为循环出来的i 为索引
hight(最后一个元素): n-1 临界值,就是从哪一个数开始区分。我们从列表的最后一个数字区分,索引为:n-1
'''
#对堆建立完成
for i in range(n-1, -1, -1):
# i 表示建堆最后一个元素
# n - 1表示索引列表总长度,第一个-1 表示范围:全部 第二个-1 表示步长:-1
li[0], li[i] = li[i], li[0]
# li[0] 表示堆第一个元素,li[i]:表示堆最后一个元素。
# 两个数进行交换位置。当第一个数li[0],确定后。我们就把它存到空位上li[i],确定的数就能排序了
sift(li, 0, i-1)
#li:列表,开始:0,最后一个数:i-1(因为我们每确定一个数,就要往前移动一个位置)
li = [i for i in range(100)] # 创建一个列表
import random # 导入随机函数
random.shuffle(li) # 利用随机函数把列表里的值打乱顺序
print(li)
heap_sort(li) # 调用堆函数,建立堆
print(li)