本篇学习内容为堆的性质、python实现插入与删除操作、堆复杂度表、python内置方法生成堆。

区分堆(heap)与栈(stack):堆与二叉树有关,像一堆金字塔型泥沙;而栈像一个直立垃圾桶,一列下来。

堆(heap)

又被为优先队列(priority queue)。尽管名为优先队列,但堆并不是队列。回忆一下,在队列中,我们可以进行的限定操作是dequeue和enqueue。

dequeue是按照进入队列的先后顺序来取出元素。而在堆中,我们不是按照元素进入队列的先后顺序取出元素的,而是按照元素的优先级取出元素。

性质

堆的实现通过构造二叉堆(binary heap),实为二叉树的一种;由于其应用的普遍性,当不加限定时,均指该数据结构的这种实现。这种数据结构具有以下性质。

  • 任意节点小于(或大于)它的所有后裔,最小元(或最大元)在堆的根上(堆序性)。
  • 堆总是一棵完全树。即除了最底层,其他层的节点都被元素填满,且最底层尽可能地从左到右填入。

实现

  • 堆的主要操作是插入和删除最小元素(元素值本身为优先级键值,小元素享有高优先级)
  • 在插入或者删除操作之后,我们必须保持该实现应有的性质: 1. 完全二叉树 2. 每个节点值都小于或等于它的子节点

上浮(Promotion)

情境: 子节点的键值变为比父节点的键值大;如下面添加字节点

消除这种违反项:

  • 交换子节点的键和父节点的键
  • 重复这个过程直到堆的顺序恢复正常

堆的添加:

def _upheap(self, j):#往上交换
parent = self._parent(j)
if j > 0 and self._data[j] < self._data[parent]:
self._swap(j, parent)
self._upheap(parent)

下沉(Demotion)

情境:父节点的键值变得比子节点(一个或者2个) 的键值还小 ,如下面删除了根节点后拿了个小子节点补充上来的情况

消除这种违反项:

  • 把父节点的键值和比它大的子节点的键值做交换
  • 重复这个操作直到堆的顺序恢复正常

删除最大值

def _downheap(self, j):#往下交换,递归比较三个值
if self._has_left(j):
left = self._left(j)
small_child = left
if self._has_right(j):
right = self._right(j)
if self._data[right] < self._data[left]:
small_child = right
if self._data[small_child] < self._data[j]:
self._swap(j, small_child)
self._downheap(small_child)

复杂度分析

Python构建堆的代码:

#该heap为min_heap,即根节点为最小值
class PriorityQueueBase:
#抽象基类为堆 class Item:
#轻量级组合来存储堆项目
__slots__ = '_key' , '_value' def __init__ (self, k, v):
self._key = k
self._value = v def __lt__ (self, other): #比较大小
return self._key < other._key def is_empty(self):
return len(self) == 0 def __str__(self):
return str(self._key) class HeapPriorityQueue(PriorityQueueBase): def __init__ (self):
self._data = [ ] def __len__ (self):
return len(self._data) def is_empty(self):
return len(self) == 0 def add(self, key, value): #在后面加上然后加上
self._data.append(self.Item(key, value))
self._upheap(len(self._data) - 1) def min(self):
if self.is_empty():
raise ValueError( "Priority queue is empty." )
item = self._data[0]
return (item._key, item._value) def remove_min(self):
if self.is_empty():
raise ValueError( "Priority queue is empty." )
self._swap(0, len(self._data) - 1)
item = self._data.pop( )
self._downheap(0)
return (item._key, item._value) def _parent(self, j):
return (j - 1) // 2 def _left(self, j):
return 2 * j + 1 def _right(self, j):
return 2 * j + 2 def _has_left(self, j):
return self._left(j) < len(self._data) def _has_right(self, j):
return self._right(j) < len(self._data) def _swap(self, i, j):
self._data[i], self._data[j] = self._data[j], self._data[i] def _upheap(self, j):#往上交换
parent = self._parent(j)
if j > 0 and self._data[j] < self._data[parent]:
self._swap(j, parent)
self._upheap(parent) def _downheap(self, j):#往下交换,递归比较三个值
if self._has_left(j):
left = self._left(j)
small_child = left
if self._has_right(j):
right = self._right(j)
if self._data[right] < self._data[left]:
small_child = right
if self._data[small_child] < self._data[j]:
self._swap(j, small_child)
self._downheap(small_child) heap = HeapPriorityQueue()
heap.add(4, "D")
heap.add(3, "C")
heap.add(1, "A")
heap.add(5, "E")
heap.add(2, "B")
heap.add(7, "G")
heap.add(6, "F")
heap.add(26, "Z") for item in heap._data:
print(item) print("min is: ")
print(heap.min())
print() print("remove min: ")
print(heap.remove_min())
print("Now min is: ")
print(heap.min())
print() print("remove min: ")
print(heap.remove_min())
print("Now min is: ")
print(heap.min())
print() heap.add(1, "A")
print("Now min is: ")
print(heap.min())
print() #输出结果
1
2
3
5
4
7
6
26
min is:
(1, 'A') remove min:
(1, 'A')
Now min is:
(2, 'B') remove min:
(2, 'B')
Now min is:
(3, 'C') Now min is:
(1, 'A')

python内置方法创建堆有两种方式,heappush()和heapify()

'''
heaqp模块提供了堆队列算法的实现,也称为优先级队列算法。
要创建堆,请使用初始化为[]的列表,或者可以通过函数heapify()将填充列表转换为堆。
提供以下功能:
heapq.heappush(堆,项目)
将值项推入堆中,保持堆不变。
heapq.heapify(x)
在线性时间内将列表x转换为堆。
heapq.heappop(堆)
弹出并返回堆中的最小项,保持堆不变。如果堆是空的,则引发IndexError。
'''
import heapq #1 heappush生成堆+ heappop把堆从小到大pop出来
heap = []
data = [1,3,5,7,9,2,4,6,8,0]
for i in data:
heapq.heappush(heap,i)
print(heap) lis = []
while heap:
lis.append(heapq.heappop(heap))
print(lis) #2 heapify生成堆+ heappop把堆从小到大pop出来
data2 = [1,5,3,2,9,5]
heapq.heapify(data2)
print(data2) lis2 = []
while data2:
lis2.append(heapq.heappop(data2))
print(lis2) #输出结果
[0, 1, 2, 6, 3, 5, 4, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 5, 9, 5]
[1, 2, 3, 5, 5, 9]

 

python数据结构之堆(heap)的更多相关文章

  1. 算法与数据结构基础 - 堆(Heap)和优先级队列(Priority queue)

    堆基础 堆(Heap)是具有这样性质的数据结构:1/完全二叉树 2/所有节点的值大于等于(或小于等于)子节点的值: 图片来源:这里 堆可以用数组存储,插入.删除会触发节点shift_down.shif ...

  2. 数据结构之堆Heap

    1. 概述 堆(也叫优先队列),是一棵完全二叉树,它的特点是父节点的值大于(小于)两个子节点的值(分别称为大顶堆和小顶堆).它常用于管理算法执行过程中的信息,应用场景包括堆排序,优先队列等. 2. 堆 ...

  3. Python数据结构2-----队列和堆

    一.线性结构:栈.队列.双端队列.列表 二.非线性结构:树.图.堆 [算法中看堆是非线性的,因为其相当于完全二叉树,但堆的存储元素是采用线性的顺序表数组来实现的] 三.队列: 1.队列类型:FIFO. ...

  4. 数据结构 - 堆(Heap)

    数据结构 - 堆(Heap) 1.堆的定义 堆的形式满足完全二叉树的定义: 若 i < ceil(n/2) ,则节点i为分支节点,否则为叶子节点 叶子节点只可能在最大的两层出现,而最大层次上的叶 ...

  5. python数据结构与算法

    最近忙着准备各种笔试的东西,主要看什么数据结构啊,算法啦,balahbalah啊,以前一直就没看过这些,就挑了本简单的<啊哈算法>入门,不过里面的数据结构和算法都是用C语言写的,而自己对p ...

  6. 算法手记 之 数据结构(堆)(POJ 2051)

    一篇读书笔记 书籍简评:<ACM/ICPC 算法训练教程>这本书是余立功主编的,代码来自南京理工大学ACM集训队代码库,所以小编看过之后发现确实很实用,适合集训的时候刷题啊~~,当时是听了 ...

  7. 堆heap和栈Stack(百科)

    堆heap和栈Stack 在计算机领域,堆栈是一个不容忽视的概念,堆栈是两种数据结构.堆栈都是一种数据项按序排列的数据结构,只能在一端(称为栈顶(top))对数据项进行插入和删除.在单片机应用中,堆栈 ...

  8. iOS中的堆(heap)和栈(stack)的理解

    操作系统iOS 中应用程序使用的计算机内存不是统一分配空间,运行代码使用的空间在三个不同的内存区域,分成三个段:“text segment “,“stack segment ”,“heap segme ...

  9. Python之数据类型-[bisect,heap]

    bisect >>> import bisect >>> >>> b = [ 20, 34, 35, 65, 78 ] >>> ...

随机推荐

  1. javaScript判断手机型号

    window.onload = function () { alert("1"); var u = navigator.userAgent; if (u.indexOf('Andr ...

  2. SQL ALTER TABLE 语句

    ALTER TABLE 语句 ALTER TABLE 语句用于在已有的表中添加.修改或删除列. SQL ALTER TABLE 语法 如需在表中添加列,请使用下列语法: ALTER TABLE tab ...

  3. ESP8266当中继

    WiFi推原理(转) http://jb.tongxinmao.com/Article/Detail/id/412 https://www.anywlan.com/thread-409913-1-1. ...

  4. (四)Exploring Your Cluster

    The REST API Now that we have our node (and cluster) up and running, the next step is to understand ...

  5. JS 面向对象 ~ 继承的7种方式

    前言: 继承 是 OO 语言中的一个最为人津津乐道的概念.许多 OO 语言都支持两种继承方式:接口继承 和 实现继承.接口继承只继承方法签名,而实现继承则继承实际的方法.如前所述,由于函数没有签名,在 ...

  6. Linux Crontab Shell脚本实现秒级定时任务

    一.编写Shell脚本crontab.sh #!/bin/bash step=1 #间隔的秒数,不能大于60 for (( i = 0; i < 60; i=(i+step) )); do $( ...

  7. Django create和save方法

    Django的模型(Model)的本质是类,并不是一个具体的对象(Object).当你设计好模型后,你就可以对Model进行实例化从而创建一个一个具体的对象.Django对于创建对象提供了2种不同的s ...

  8. vue2.0 子组件和父组件之间的传值(转载)

    Vue是一个轻量级的渐进式框架,对于它的一些特性和优点在此就不做赘述,本篇文章主要来探讨一下Vue子父组件通信的问题 首先我们先搭好开发环境,我们首先得装好git和npm这两个工具(如果有不清楚的同学 ...

  9. mybatis 使用事务处理

    mybatis默认开启事务 以前使用JDBC的时候,如果要开启事务,我们需要调用conn.setAutoCommit(false)方法来关闭自动提交,之后才能进行事务操作,否则每一次对数据库的操作都会 ...

  10. Java 如何存取MySQL datetime类型

    1 在java中只有Date类型,这样数据存储到MySQL会出现问题,前台提交的数据,比如2018-03-20 17:30:59,后台用Date接受的时候,由于Date只精确到天,所以默认接收时间为2 ...