zoukankan      html  css  js  c++  java
  • 堆和索引堆的实现(python)

    '''
    索引堆
    '''
    '''
    
    实现使用2个辅助数组来做.有点像dat.用哈希表来做修改不行,只是能找到这个索引,而需要change操作
    还是需要自己手动写.所以只能用双数组实现.
    
    #引入索引堆的核心就是为了改变堆里面任意一个元素的值,然后继续维护这个堆.
    '''
    
    
    '''下面手动写堆'''
    '''做大根堆然后输出升序排列'''#感觉之前写的都不对,heapify太弱了,不能按方向调整.
    #需要修改成带shift up,shift down操作的堆,最终目标实现双辅助数组的最大索引堆
    class Maxheap():
        def __init__(self,capacity):#capacity是最大容量
            self.data=[0]*capacity
            self.count=0
            self.capacity=capacity
        def size(self):
            return self.count
        def empty(self):
            return self.count==0
    
        def shiftup(self,count):
            while count>0 and self.data[(count-1)//2]<self.data[count]:
                self.data[(count-1)//2],self.data[count]=self.data[count],self.data[(count-1)//2]
                count=(count-1)//2
    
        def shiftdown(self,k):#把堆的k索引的元素进行shiftdown操作,
                              #每一次这个操作都能把k位置作为head的子树给heapify了.
            while 2*k+1<=self.count-1 :
               left=2*k+1
               right=min(2*k+2,self.count-1)
               tmpindex=k
               if self.data[left]>self.data[k]:
                   tmpindex=left
               if self.data[right]>self.data[tmpindex]:
                   tmpindex=right
               if tmpindex==k:
                   return 
               else:
                   self.data[tmpindex],self.data[k]=self.data[k],self.data[tmpindex]
                   k=tmpindex
    
    
            
    
    
        def insert(self,item):#建立只需要shift up
            self.data[self.count]=item
            
            self.shiftup(self.count)#把count位置的元素向上移动维护堆
            self.count+=1
    
    
        def pop(self):#弹出堆定元素
            self.data[0],self.data[self.count-1]=self.data[self.count-1],self.data[0]
            output=self.data[self.count-1]
            self.count-=1
            if self.count>0:
             self.shiftdown(0)#把索引为0的进行shiftdown操作
            return output
        def show_data(self):#因为堆,需要不动态删除,为了速度.所以不要的元素只是把它放到count-1 这个
                          #index后面而已,通过show_data来读取data中有效元素
            a=self.data[:self.count]
            return a
        def heapify(self,list1):#把数组直接建立成一个最大堆
            self.data=list1#python的列表动态的,直接赋值即可.不用管capacity
            self.capacity=len(list1)
            self.count=self.capacity
            for i in range((self.capacity-2)//2,-1,-1):
                self.shiftdown(i)
            return self.data
        def heapsort(self,list1):#直接pop 就实现了.因为前面都已经写好了
            self.heapify(list1)
            while self.count>1:
             self.pop()#弹出一个
    
            return self.data
    
    
    
    
    #下面是测试
    a=Maxheap(10)
    
    
    aa=a.heapify([1,4,5,6,7,8,9,-1])
    print(aa)
    
    aaa=a.heapsort([1,4,5,6,7,8,9,-1])
    print(aaa)
    View Code         堆的实现
    '''
    索引堆   通过liubobo老师的c++算法与数据结构  (慕课网)
             结构还是很复杂的,当然比dat和红黑树要简单多了.通过2个辅助数组来实现的
             如果看不懂可以参考上面的视频课程的第4章的内容.里面讲解很详细,我只是把c++代码修改
             成了python而已.非常强大,比如在图论中经常需要维护一个可以随意修改里面元素的堆结构.
             这时候索引堆就非常管用了.最短路径特斯拉算法,liubobo就是这么实现的.
    '''
    '''
    
    实现使用2个辅助数组来做.有点像dat.用哈希表来做修改不行,只是能找到这个索引,而需要change操作
    还是需要自己手动写.所以只能用双数组实现.
    
    #引入索引堆的核心就是为了改变堆里面任意一个元素的值,然后继续维护这个堆.
    '''
    
    
    '''下面手动写堆'''
    '''做大根堆然后输出升序排列'''#感觉之前写的都不对,heapify太弱了,不能按方向调整.
    #需要修改成带shift up,shift down操作的堆,最终目标实现双辅助数组的最大索引堆
    
    '''
    下面我们把这个堆改成索引堆,叫index_max_heap
    初始化时候.把数据这个list给index_max_heap对象里面的data这个属性是隐含的数据
    同时索引index数组,是暴露给用户访问的.data[i]=item,index[count+1]=i
    然后,我们之后的插入操作是插入索引为i,内容为item的元素,
    
    总之:我们用索引i来替换item来进行堆里面的swap操作,然后最后堆里面第一个位置存index[0],表示
    存的是data[index[0]].也就是index[i]表示的是堆里面第i个位置在data数据集里面的下表.(说起来很绕).
    堆里面第几个元素就去index[几]里面找钥匙.然后去data[钥匙]里面去提取内容.
    '''
    class Maxheap():
        def __init__(self,capacity):#capacity是最大容量
            self.data=[0]*capacity  #这个默认插入0非常不好,比如我索引只插入了1,'wo'2,'we'
                                   #但是堆里面还是有10个元素.但是你如果不插入元素的画,
                                   #你建立堆时候给的元素少了会发生bug.没法比较进行堆维护.
                                   #所以使用的时候一定要注意,用多少capacity就给多少.
                                   #如果需要占位的时候,空余的占位要自己补上default值.
            self.indexes=[-1]*capacity #因为索引不可能是负的,所以用-1占位
            self.reverse=[-1]*capacity #因为索引不可能是负的,所以用-1占位
            self.count=0
            self.capacity=capacity
        def size(self):
            return self.count
        def empty(self):
            return self.count==0
    
        def shiftup(self,count):
            while count>0 and self.data[self.indexes[(count-1)//2]]<self.data[self.indexes[count]]:
                
                self.indexes[(count-1)//2],self.indexes[count]=self.indexes[count],self.indexes[(count-1)//2]#这一步只是交换index提高了交换效率
                #下面2行是公里,因为上面变了,所以下面需要跑一下这2行.坐下对应修复
                self.reverse[self.indexes[(count-1)//2]]=(count-1)//2
                self.reverse[self.indexes[count]]=count
    
                count=(count-1)//2
    
        def shiftdown(self,k):#把堆的k索引的元素进行shiftdown操作,
                              #每一次这个操作都能把k位置作为head的子树给heapify了.
            while 2*k+1<=self.count-1 :
               left=2*k+1
               right=min(2*k+2,self.count-1)
               tmpindex=k
               if self.data[self.indexes[left]]>self.data[self.indexes[k]]:
                   tmpindex=left
               if self.data[self.indexes[right]]>self.data[self.indexes[tmpindex]]:
                   tmpindex=right
               if tmpindex==k:
                   return 
               else:
                   self.indexes[tmpindex],self.indexes[k]=self.indexes[k],self.indexes[tmpindex]
                   self.reverse[self.indexes[tmpindex]]=tmpindex
                   self.reverse[self.indexes[k]]=k
                   k=tmpindex
    
    
            
    
                   #插入索引为i的数据是item
        def insert(self,i,item):#建立只需要shift up
            assert(self.count+1<=self.capacity)
            assert(i>=0 and i<self.capacity)
            self.data[i]=item
            self.indexes[self.count]=i
            self.reverse[i]=self.count
            
            
            self.shiftup(self.count)#把count位置的元素向上移动维护堆
            self.count+=1
    
    
        def pop(self):#弹出堆定元素
            assert(self.count>0)
            self.indexes[0],self.indexes[self.count-1]=self.indexes[self.count-1],self.indexes[0]
            self.reverse[self.indexes[0]]=0
            self.reverse[self.indexes[self.count-1]]=-1#pop就不会被访问了所以给-1
    
            output=self.data[self.indexes[self.count-1]]
            self.count-=1
            if self.count>0:
             self.shiftdown(0)#把索引为0的进行shiftdown操作
            return output
    
    
        def pop_index(self):#弹出堆定元素
            assert(self.count>0)
            self.indexes[0],self.indexes[self.count-1]=self.indexes[self.count-1],self.indexes[0]
            self.reverse[self.indexes[0]]=0
            self.reverse[self.indexes[self.count-1]]=-1#pop就不会被访问了所以给-1
            output=self.indexes[self.count-1]
            self.count-=1
            if self.count>0:
             self.shiftdown(0)#把索引为0的进行shiftdown操作
            return output
    
        def show_data(self):#因为堆,需要不动态删除,为了速度.所以不要的元素只是把它放到count-1 这个
                          #index后面而已,通过show_data来读取data中有效元素
                          #利用index来遍历更准确和不会bug
            out=[]
            index_now=self.indexes[:self.size()]
            for i in index_now:
                if i!=-1:
                    out.append(self.data[i])
            out
    
            return out
        def heapify(self,list1):#把数组直接建立成一个最大堆
            self.data=list1#python的列表动态的,直接赋值即可.不用管capacity
            self.capacity=len(list1)
            self.count=self.capacity
            for i in range((self.capacity-2)//2,-1,-1):
                self.shiftdown(i)
            return self.data
        def heapsort(self,list1):#直接pop 就实现了.因为前面都已经写好了
            self.heapify(list1)
            while self.count>1:
             self.pop()#弹出一个
    
            return self.data
        def get_item(self,i):
            return self.data[i]
        def change(self,i,newitem):#需要返回索引i在堆中的第几个坐标上.比如堆中第一个元素是10,那么change(10)返回0
            #这种操作,叫反向查找技术,非常牛逼class,实现不难,思想牛逼.常用.思想很像dat
            #先修改data
            self.data[i]=newitem
            j=self.reverse[i]
            self.shiftup(j)
            self.shiftdown(j)
    
    
            return self.data[i]
    
    
    
    #下面是测试
    a=Maxheap(10)
    
    a.insert(0,'wo')#0是索引,'wo'是value.对value比较大小来建堆,但是堆里面的元素都是index.
    a.insert(1,'we')
    
    a.insert(3,'a')
    a.change(3,'jjk')
    print(a.pop_index())
    print(a.indexes)#弹出的元素不会彻底删除,而只是把它的索引放到self.size后面了.
    print(a.show_data()) #从这里面就看出来之前最大的wo已经被弹出了.
                         #并且indexMaxheap也已经效果出来了.可以随意修改index为3的元素了,并且
                         #自动维护这个堆.
    View Code            索引堆
  • 相关阅读:
    PHP生成PDF并转换成图片爬过的坑
    PHAR系列之导言
    Linux学习之路(三)Shell脚本初探
    Linux学习之路(二)
    php 隐藏手机号中间几位
    tp 递归菜单列表【树状】
    php导出excel封装类
    php 导出Excel表格
    php字符串之翻转单词顺序列
    laravel实现跳转其他控制器
  • 原文地址:https://www.cnblogs.com/zhangbo2008/p/9184166.html
Copyright © 2011-2022 走看看