堆的概念及堆排序(答案有点问题)

堆的概念

是什么?

堆(Heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵完全二叉树的数组对象即堆是一种特殊的二叉树。我们所讨论的堆一般特指为二叉堆,二叉堆是完全二叉树或者是近似完全二叉树。

特性?

如下图所示:

堆排序

是什么?

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。通俗说,就是将一串乱序的数组当成二叉树,并将二叉树进行一定的改动,使之特殊化,成为堆(大顶堆和小顶堆)。

特性?

如下图所示:

步骤1:堆化

1.数组堆化(小顶堆的堆化):

将数组堆化的大致步骤是:(如下图所示可以知道)

 

def shuzuxiaoduihua(a,i,n):// a为数组,i为根节点,n为数组的长度
    lefttree=2*i+1 //lefttree表示左子树根节点的逻辑下标(即数组下标)
    righttree=2*i+2//righttree表示右子树根节点的逻辑下标(即数组下标)
    if lefttree>=n: //因为lefttree和righttree不仅仅只是左子树的逻辑下标,也是表示在数组中的位置,因而lefttree的逻辑地址应该在数组长度之内,当左子树lefttree的逻辑下标超出数组的下标,那么右子树righttree更加超出了数组的下标,那么意味着根节点i没有左右子树,那么不用调整就满足了小顶堆。
        return //退出数组堆化函数
    if a[i]<=a[lefttree] and a[i]<=a[righttree]: //若根节点的值小于左右子树的值,那么这就构成了小顶堆,则跳出数组堆化函数
        return
    else: //否则,说明了根节点的值大于左右子树值的其中一个,则需要从左右子树值中选出最小的一个值,与根节点进行值的交换。
        if a[lefttree]<=a[righttree]:
            a[i],a[lefttree]=a[lefttree],a[i]
            next1=lefttree //交换后则需要保存交换的左子树的逻辑下标
        else:
            a[i],a[righttree]=a[righttree],a[i]
            next1=righttree//交换后则需要保存交换的左子树的逻辑下标
shuzuxiaoduihua(a,next1,n) //进行递归调用,防止根节点与左右子树交换值后,使得左子树或右子树不满足小顶堆的要求
a=[]
for i in input().split(' '):
a.append(eval(i))
b=len(a)
gen=len(a)//2
for j in range(gen-1,-1,-1):
shuzuxiaoduihua(a,j,b)

2.数组堆化(大顶堆的堆化):

将数组堆化的大致步骤是:(如下图所示可以知道)

def shuzudaduihua(a,b):
gen=b//2
for j in range(gen,-1,-1):
shuzuduihua1(a,j,b)
def shuzudaduihua1(a,i,n):// a为数组,i为根节点,n为数组的长度
    lefttree=2*i+1 //lefttree表示左子树根节点的逻辑下标(即数组下标)
    righttree=2*i+2//righttree表示右子树根节点的逻辑下标(即数组下标)
    if lefttree>=n: //因为lefttree和righttree不仅仅只是左子树的逻辑下标,也是表示在数组中的位置,因而lefttree的逻辑地址应该在数组长度之内,当左子树lefttree的逻辑下标超出数组的下标,那么右子树righttree更加超出了数组的下标,那么意味着根节点i没有左右子树,那么不用调整就满足了小顶堆。
        return //退出数组堆化函数
    if a[i]>=a[lefttree] and a[i]>=a[righttree]: //若根节点的值大于等于左右子树的值,那么这就构成了大顶堆,不需要大顶堆堆化,则跳出数组堆化函数
        return
    else: //否则,说明了根节点的值小于左右子树值的其中一个,则需要从左右子树值中选出最大的一个值,与根节点进行值的交换。
        if a[lefttree]>=a[righttree]:
            a[i],a[lefttree]=a[lefttree],a[i]
            next1=lefttree //交换后则需要保存交换的左子树的逻辑下标
        else:
            a[i],a[righttree]=a[righttree],a[i]
            next1=righttree//交换后则需要保存交换的左子树的逻辑下标
    shuzuduihua(a,next1,n) //进行递归调用,防止根节点与左右子树交换值后,使得左子树或右子树不满足大顶堆的要求
a=[]
for i in input().split(' '):
    a.append(eval(i))
b=len(a)
shuzudaduihua(a,b)

步骤2:实现堆排序

实现堆排序大约进行如下几步:
如图所示可以知道:

 

def duipaixu(a,b):
    shuzudaduihua(a,b)
    c=len(a)-1
    n=b
    m=0
    for i in range(c,-1,-1):
        a[i],a[m]=a[m],a[i]
        n=n-1
        shuzudaduihua(a,n)
        
def shuzudaduihua(a,b):
    gen=b//2
    for j in range(gen-1,-1,-1):
        shuzudaduihua1(a,j,b)
        
def shuzudaduihua1(a,i,n):
    lefttree=2*i+1 
    righttree=2*i+2
    if lefttree>=n:
        return
    if a[i]>=a[lefttree] and a[i]>=a[righttree]:
        return
    else:
        if a[lefttree]>=a[righttree]:
            a[i],a[lefttree]=a[lefttree],a[i]
            next1=lefttree 
        else:
            a[i],a[righttree]=a[righttree],a[i]
            next1=righttree
    shuzudaduihua1(a,next1,n)
    
a=[]
for i in input().split(' '):
    a.append(eval(i))
b=len(a)
duipaixu(a,b)
print(a)
    

 

注意:类似于这类的问题,我们可以先将自己的思路先用自己中文描述一遍,将相当于将自己思考所得到解题方法给表示出来,再根据我们中文所描述的情况来编写代码。这样可以高效的进行代码的书写,不会出现什么问题。最后只要我们在确定一下我们的边界就可以了。根据自己的亲身经历而言,这样写代码更快。

 

posted @ 2022-03-05 23:12  天空之城—我的理想国  阅读(285)  评论(0编辑  收藏  举报