zoukankan      html  css  js  c++  java
  • 最小堆实现优先队列:Python实现

    堆是一种数据结构,因为Heapsort而被提出。除了堆排序,“堆”这种数据结构还可以用于优先队列的实现。

    堆首先是一个完全二叉树:它除了最底层之外,树的每一层的都是满的,且最底层中的节点处于左边,相互之间没有“跳变”;其次,堆有次序属性:每个节点中的数据项都大于或者等于其子女的数据项(如果是记录,则这些记录中的某个关键域必须满足这一属性)。 当然,这是指大顶堆,小顶堆则是父节点比子节点都要小。

    所谓队列,就是一个FIFO表(first in, first out)。优先队列,就是在队列的基础上,每个元素加一个优先级,last in的元素可能会first out,这就是优先级在起作用。

    我想实现这样一个优先队列:

      元素为整数

      元素值小的优先级反而大

      有入队操作,每次进入一个元素

      出队操作,也行每次一个元素

    那么,我的小根堆Heap应该这样考虑:

      每当插入元素时,在原有Heap的最后一个叶子节点后面插入新元素val,并持续比较val和其父节点的值之间是否满足堆的次序属性,直到满足

      每当删除元素时,删除的是值最小的元素,也就是根结点root,则将root和最后一个叶子节点lastleaf互换,然后删除交换后的new_lastleaf ,并从new_root开始调整堆,使满足堆的次序属性。

    这样一来,代码就不难写出:

    #coding:utf8
    #author:HaxtraZ
    #description:优先队列,用堆实现
    #修改自《算法导论》2nd Edition
    
    
    class ZHeap:
        def __init__(self, item=[]):
            # 初始化。item为数组
            self.items = item
            self.heapsize = len(self.items)
    
        def LEFT(self, i):
            return 2 * i + 1
    
        def RIGHT(self, i):
            return 2 * i + 2
    
        def PARENT(self, i):
            return (i - 1) / 2
    
        def MIN_HEAPIFY(self, i):
            # 最小堆化:使以i为根的子树成为最小堆
            l = self.LEFT(i)
            r = self.RIGHT(i)
            if l < self.heapsize and self.items[l] < self.items[i]:
                smallest = l
            else:
                smallest = i
    
            if r < self.heapsize and self.items[r] < self.items[smallest]:
                smallest = r
    
            if smallest != i:
                self.items[i], self.items[smallest] = self.items[smallest], self.items[i]
                self.MIN_HEAPIFY(smallest)
    
        def INSERT(self, val):
            # 插入一个值val,并且调整使满足堆结构
            self.items.append(val)
            idx = len(self.items) - 1
            parIdx = self.PARENT(idx)
            while parIdx >= 0:
                if self.items[parIdx] > self.items[idx]:
                    self.items[parIdx], self.items[idx] = self.items[idx], self.items[parIdx]
                    idx = parIdx
                    parIdx = self.PARENT(parIdx)
                else:
                    break
            self.heapsize += 1
    
        def DELETE(self):
            last = len(self.items) - 1
            if last < 0:
                # 堆为空
                return None
            # else:
            self.items[0], self.items[last] = self.items[last], self.items[0]
            val = self.items.pop()
            self.heapsize -= 1
            self.MIN_HEAPIFY(0)
            return val
    
    
        def BUILD_MIN_HEAP(self):
            # 建立最小堆, O(nlog(n))
            i = self.PARENT(len(self.items) - 1)
            while i >= 0:
                self.MIN_HEAPIFY(i)
                i -= 1
    
        def SHOW(self):
            print self.items
    
    
    class ZPriorityQ(ZHeap):
        def __init__(self, item=[]):
            ZHeap.__init__(self, item)
    
        def enQ(self, val):
            ZHeap.INSERT(self, val)
    
        def deQ(self):
            val = ZHeap.DELETE(self)
            return val
    
    
    a = [1, 3, 2, 4, 8, 6, 22, 9]
    pq = ZPriorityQ()
    n = len(a)
    for i in range(n):
        pq.enQ(a[i])
        pq.SHOW()
    
    for i in range(n):
        pq.deQ()
        pq.SHOW()
    

      其中,ZHeap表示小根堆,ZPriorityQ表示优先队列,deQ表示退队,enQ表示入队。

      我们发现以下结论:大根堆用于升序排序,小根堆用于降序排序。

      为什么用堆来实现优先队列?原因只有一个:复杂度低。

        如果使用列表(存放在list中),插入为O(1),删除为O(n);

        如果使用按照优先级排好序的有序列表,插入和线性插入排序一样,O(n),删除则为O(1)

      使用堆的时候,无论你删除还是插入,都是O(lg n)时间复杂度,对于插入和删除都比较频繁的操作来讲,这是最好不过的了。

      如果认为有不正确的地方欢迎拍砖。

  • 相关阅读:
    15.scrapy中selenium的应用
    14.UA池和代理池
    17.基于scrapy-redis两种形式的分布式爬虫
    08.Python网络爬虫之图片懒加载技术、selenium和PhantomJS
    05.Python网络爬虫之三种数据解析方式
    06.Python网络爬虫之requests模块(2)
    04.Python网络爬虫之requests模块(1)
    16.Python网络爬虫之Scrapy框架(CrawlSpider)
    10.scrapy框架简介和基础应用
    Python网络爬虫第三弹《爬取get请求的页面数据》
  • 原文地址:https://www.cnblogs.com/zjutzz/p/3278790.html
Copyright © 2011-2022 走看看