算法与数据结构——堆

C++实现及理论https://www.cnblogs.com/polly333/category/720001.html

https://github.com/liuyubobobo/Play-with-Algorithms

python实现https://github.com/ShiveryMoon/Imooc-Algorithm-PythonEdition


优先队列

二叉堆(若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。

最大堆:对于从1开始索引


从0开始索引


class MaxHeap(object):
    def __init__(self,max=100000):
        self.heapList=[0]
        self.currentSize=0
        self.maximum=max

    def shiftUp(self,i):#2.然后向上移动变成最大堆
        currentvalue=self.heapList[i]
        while i//2>0:#i的父节点>0
            if self.heapList[i//2] < currentvalue:
                self.heapList[i]=self.heapList[i//2]   #优化:赋值替代交换
                i=i//2
            else:
                break
        self.heapList[i]=currentvalue

    def insert(self,k):#1.插入,入堆(向堆中插入新元素到末尾),
        self.heapList.append(k)
        self.currentSize+=1
        self.shiftUp(self.currentSize)
        if self.currentSize>self.maximum:  #在最大堆中这个操作会保留m个最小的元素。
            self.delFirst()

    def shiftDown(self,i):#2然后向下移动变成最大堆
        currentvalue=self.heapList[i]
        while i*2<=self.currentSize:#当i有子节点(左子节点)
            mc=self.maxChild(i)#i是否有右子节点,有则比较i的子节点大小
            if currentvalue < self.heapList[mc]:#当前值<较大的那个子节点,交换,然后继续循环
                self.heapList[i]=self.heapList[mc]
                i=mc
            else:
                break
        self.heapList[i]=currentvalue

    def maxChild(self,i):
        if i*2+1>self.currentSize:#i没有右子节点
            return i*2
        else:#i有右子节点,比较两子节点大小
            if self.heapList[i*2]>self.heapList[i*2+1]:#左子节点>右子节点
                return i*2
            else:
                return i*2+1

    # 之所以叫delFirst是因为这个函数可以兼容最大堆和最小堆
    def delFirst(self): #1出堆(根节点出堆,最末子节点补到根节点位置),
        retval=self.heapList[1]
        if self.currentSize==1:#二叉堆只有一个节点时
            self.currentSize-=1
            self.heapList.pop()
            return retval
        self.heapList[1]=self.heapList[self.currentSize]#二叉堆末尾的节点覆盖到根节点
        self.heapList.pop()#删除末尾元素
        self.currentSize-=1
        self.shiftDown(1)#下移
        return retval

    def buildHeap(self,alist): #heapify O(n)级别
        self.heapList=[0]+alist[:]#首元素为0,将列表从顺序1加入到堆中
        self.currentSize=len(alist)
        i=self.currentSize//2
        while i>0:
            self.shiftDown(i)
            i-=1
        overflow=self.currentSize-self.maximum
        for i in range(overflow):
            self.delFirst()

    def HeapSort(self,alist):
        self.buildHeap(alist)
        sortedList=[self.delFirst() for x in range(self.currentSize)]#循环返回最大堆的根节点(根节点值是最大的)直到堆里没有元素
        sortedList.reverse()#从小到大排序
        return sortedList

    def HeapSortInPlace(self,alist):#原地堆排序,将末尾元素与根节点交换然后shiftDown,然后重复
        self.buildHeap(alist)
        while self.currentSize>1:
            self.heapList[1],self.heapList[self.currentSize]=self.heapList[self.currentSize],self.heapList[1]
            self.currentSize-=1
            self.shiftDown(1)
        return self.heapList[1:]

最小堆:#在N个元素中选出前M个元素

class MinHeap(MaxHeap): #最小堆,继承自MaxHeap,覆盖了父类的上浮和下沉操作,酌情使用。
    def __init__(self):
        super(MaxHeap, self).__init__()

    def shiftUp(self,i):
        currentvalue=self.heapList[i]
        while i//2 > 0:
            if self.heapList[i//2] > currentvalue:
                self.heapList[i]=self.heapList[i//2]
                i//2
            else:
                break
        self.heapList[i] = currentvalue

    def shiftDown(self,i):
        currentvalue=self.heapList[i]
        while i*2<=self.currentSize:
            mc=self.minChild(i)
            if currentvalue > self.heapList[mc]:
                self.heapList[i]=self.heapList[mc]
                i=mc
            else:
                break
        self.heapList[i]=currentvalue

    def minChild(self,i):
        if i*2+1>self.currentSize:
            return i*2
        else:
            if self.heapList[i*2] <self.heapList[i*2+1]:
                return i*2
            else:
                return i*2+1


索引堆:比较data,交换index

表格中第一行代表i、第二行indexList[i],第三行items[indexList[i]]


#直接使用python的dict对象可以非常容易地实现索引堆。

# 在buildHeap中  将key关键字列表化,这样i对应的列表的索引,index对应的列表值,data就是字典的value
# 比较的是data,交换的是列表的值即index,字典中的值没有发生改变,然后通过index在字典中查找
class IndexMaxHeap(object):
    def __init__(self):
        self.indexList=[0]
        self.items={}
        self.currentSize=0

    def shiftUp(self,i):
        currentvalue=self.items[self.indexList[i]]#当前值
        currentindex=self.indexList[i]#当前值对应的用户索引
        while i//2>0:
            if self.items[self.indexList[i//2]] < currentvalue:
                self.indexList[i]=self.indexList[i//2]#交换字典索引
                i=i//2
            else:
                break
        self.indexList[i]=currentindex

    def insert(self,k,value):
        self.indexList.append(k)
        self.items[k]=value
        self.currentSize+=1
        self.shiftUp(self.currentSize)

    def shiftDown(self,i):
        currentvalue=self.items[self.indexList[i]]
        currentindex=self.indexList[i]
        while i*2<=self.currentSize:#当i有子节点(左子节点)
            mc=self.maxChild(i)#i是否有右子节点,有则比较i的子节点大小
            if currentvalue < self.items[self.indexList[mc]]:#当前值<较大的那个子节点,交换,然后继续循环
                self.indexList[i]=self.indexList[mc]
                i=mc
            else:
                break
        self.indexList[i]=currentindex

    def maxChild(self,i):
        if i*2+1>self.currentSize:
            return i*2
        else:
            if self.items[self.indexList[i*2]]>self.items[self.indexList[i*2+1]]:
                return i*2
            else:
                return i*2+1

    def delFirst(self):
        retval=self.items[self.indexList[1]]
        del self.items[self.indexList[1]]#删除字典元素
        if self.currentSize==1:
            self.currentSize-=1
            self.indexList.pop()
            return retval
        self.indexList[1]=self.indexList[self.currentSize]#将末尾元素的索引赋值到根节点
        self.indexList.pop()#删除末尾元素的索引
        self.currentSize-=1
        self.shiftDown(1)#进行下移
        return retval

    def buildHeap(self,items):
        self.items=items

        self.indexList=[0]+list(self.items.keys())
        self.currentSize=items.__len__()
        i=self.currentSize//2
        while i>0:
            self.shiftDown(i)
            i-=1

    def getItem(self,i):#这里的i就是key
        return self.items[i]

    def maxItemIndex(self):
        return self.indexList[1]

    def change(self,k,newValue):
        if k not in self.indexList:
            raise Exception('%s is not exist!' % k)
        self.items[k]=newValue
        #index() 函数用于从列表中找出某个值第一个匹配项的索引位置。
        i=self.indexList.index(k)  #index方法的复杂度是O1,根本不需要实现reverse列表。我猜python内部就是靠reverse列表来实现这个index方法的。
        self.shiftDown(i)#如果变小下移
        self.shiftUp(i)#如果变大上移
        return True
测试用例:
heap=IndexMaxHeap()
items={'John':21,'Lucy':14,'Jesscia':17,'张三':32,'李四':11} #按照分数构成最大堆
heap.buildHeap(items)
heap.insert('Dark',15)
print('最高分: %s %s' % (heap.maxItemIndex(),heap.items[heap.maxItemIndex()]))
print('Lucy多少分? %s' % heap.getItem('Lucy'))
#将Lucy的分数提高到50
heap.change('Lucy',50)
print('最高分: %s %s' % (heap.maxItemIndex(),heap.items[heap.maxItemIndex()]))
heap.delFirst()
print('最高分: %s %s' % (heap.maxItemIndex(),heap.items[heap.maxItemIndex()]))

猜你喜欢

转载自blog.csdn.net/u012084802/article/details/80356486