排序学习笔记(二)堆排序

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]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值