二叉堆和堆排序的python实现

一 二叉堆的实现

二叉堆本质上是一种完全二叉数:

  • 最大堆:根节点为最大节点,任意的父节点都不小于其所有子节点
  • 最小堆:根节点为最小节点,任意的父节点都不大于其所有子节点

二叉堆创建:
根据原数组,然后从最后一个非叶子节点开始,依次下沉,得到最后序列

二叉堆操作:

  • 插入节点,位置为最后,然后根据情况上浮调整;
  • 删除一般为堆顶的节点,然后最后节点临时补到堆顶位置,然后下沉调整

图比较麻烦就不画了,可以参考这篇文章:二叉堆图解

# 1.二叉堆实现
'''
存储方式:利用数组顺序存储
定位方法:利用数组下标进行定位(父节点Parent,左子树:2*Parent+1,右子树:2*Parent+2)
'''
class MinHeap:
    
    def __init__(self):
        self.heap=[]
    
    #上浮调整函数
    def shift_up(self):
        ChildIndex = len(self.heap)-1
        ParentIndex = (ChildIndex-1)//2
        #temp 保存插入的子节点的值,用于最后赋值
        temp = self.heap[ChildIndex]
        while ChildIndex>0 and temp<self.heap[ParentIndex]:
            self.heap[ChildIndex] = self.heap[ParentIndex]
            ChildIndex = ParentIndex
            ParentIndex = (ChildIndex-1)//2
        self.heap[ChildIndex] = temp
    #下沉调整函数,节点id:ParentIndex
    def shift_down(self,ParentIndex):
        #temp保存父节点的值,用于最后赋值
        temp = self.heap[ParentIndex]
        ChildIndex = 2*ParentIndex+1
        while ChildIndex<len(self.heap):
            #如果有右孩子且左孩子大于右孩子,则定位到右孩子
            if ChildIndex+1< len(self.heap) and self.heap[ChildIndex]>self.heap[ChildIndex+1]:
                ChildIndex += 1
            #如果父节点小于任一子节点,则退出循环
            if temp<=self.heap[ChildIndex]:
                break
            self.heap[ParentIndex] = self.heap[ChildIndex]
            ParentIndex = ChildIndex
            ChildIndex = ParentIndex*2+1
        self.heap[ParentIndex] = temp
    
    #构造推
    def buildheap(self,alist):
        #从最后一个非叶子节点开始,依次下沉
        self.heap = alist
        for i in range((len(self.heap)-2)//2,-1,-1):
               self.shift_down(i)
                
    #定义插入节点函数,
    def insert(self,num):
        self.heap.append(num)
        self.shift_up()  
    
    #删除堆顶元素
    def delMin(self):
        retrval = self.heap[0]
        self.heap[0] = self.heap[len(self.heap)-1]      
        self.heap.pop()
        self.shift_down(0)
        return retrval

检验

bh = MinHeap()
bh.insert(1)
bh.insert(8)
bh.insert(4)
bh.insert(3)
bh.insert(2)
bh.heap

[1, 2, 4, 8, 3]

bh1 = MinHeap()
bh1.buildheap([1,8,4,3,2])
bh1.heap

[1, 2, 4, 3, 8]

bh1.insert(5)
bh1.insert(6)
bh1.heap

[1, 2, 4, 3, 8, 5, 6]

bh1.delMin()
# 返回 1
bh1.delMin()
# 返回 2
bh1.heap
# 返回 [3, 5, 4, 6, 8]

时间复杂度分析

插入和删除的操作都是 O(logn)
生成二叉树的操作为 O(n),至于为什么为O(n),可以参照以下文章
https://www.zhihu.com/question/264693363?sort=created

二 堆排序

堆排序利用了二叉堆的堆顶为最大或最小的特性。
算法步骤

  • 将无序数组构造成二叉堆。如果需要从小到大排序,则构造最大堆,如果需要从大到小排序,则构造最小堆
  • 循环删除堆顶元素,替换到二叉堆的末尾,调整堆产生新的堆顶。
    代码实现
    可以删除insert和delMin函数,增加Sort函数
#堆排序(降序)
# 生成最小堆
class HeapSort:  
  
    def __init__(self):
        self.heap=[]
            
    #上浮调整函数
    def shift_up(self):
        ChildIndex = len(self.heap)-1
        ParentIndex = (ChildIndex-1)//2
        #temp 保存插入的子节点的值,用于最后赋值
        temp = self.heap[ChildIndex]
        while ChildIndex>0 and temp<self.heap[ParentIndex]:
            self.heap[ChildIndex] = self.heap[ParentIndex]
            ChildIndex = ParentIndex
            ParentIndex = (ChildIndex-1)//2
        self.heap[ChildIndex] = temp
    #下沉调整函数,节点id:ParentIndex
    def shift_down(self,ParentIndex,length):
        #temp保存父节点的值,用于最后赋值
        temp = self.heap[ParentIndex]
        ChildIndex = 2*ParentIndex+1
        while ChildIndex< length :
            #如果有右孩子且左孩子大于右孩子,则定位到右孩子
            if ChildIndex+1< length and self.heap[ChildIndex]>self.heap[ChildIndex+1]:
                ChildIndex += 1
            #如果父节点小于任一子节点,则退出循环
            if temp<=self.heap[ChildIndex]:
                break
            self.heap[ParentIndex] = self.heap[ChildIndex]
            ParentIndex = ChildIndex
            ChildIndex = ParentIndex*2+1
        self.heap[ParentIndex] = temp
    
    #构造推
    def buildheap(self,alist):
        #从最后一个非叶子节点开始,依次下沉
        self.heap = alist
        for i in range((len(self.heap)-2)//2,-1,-1):
               self.shift_down(i,len(self.heap))   
                               
    def Sort(self,array):
        # 1.构造二叉堆
        self.buildheap(array)
        # 2.循环删除堆顶,移到尾部,调整产生新的堆顶
        for i in range(len(self.heap)-1,-1,-1):
            temp = self.heap[i]
            self.heap[i] = self.heap[0]
            self.heap[0] = temp
            # 下沉调整堆顶
            self.shift_down(0,i)
        return self.heap     
             
HS = HeapSort()
HS.Sort([1,5,2,8,4,9,7]) 
# [9, 8, 7, 5, 4, 2, 1]
  • 时间复杂度:O(nlogn)
  • 空间复杂度:O(1)

三 Leetcode题解

你可能感兴趣的:(算法与数据结构)