python中结构分析_python数据结构之堆(heap)

本篇学习内容为堆的性质、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._swap(j, parent)

self._upheap(parent)

下沉(Demotion)

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

消除这种违反项:

把父节点的键值和比它大的子节点的键值做交换

重复这个操作直到堆的顺序恢复正常

删除最大值

def _downheap(self, j):#往下交换,递归比较三个值

ifself._has_left(j):

left=self._left(j)

small_child=leftifself._has_right(j):

right=self._right(j)if self._data[right]

small_child=rightif self._data[small_child]

self._swap(j, small_child)

self._downheap(small_child)

复杂度分析

Python构建堆的代码:

#该heap为min_heap,即根节点为最小值

classPriorityQueueBase:#抽象基类为堆

classItem:#轻量级组合来存储堆项目

__slots__ = '_key' , '_value'

def __init__(self, k, v):

self._key=k

self._value=vdef __lt__ (self, other): #比较大小

return self._key

self._data=[ ]def __len__(self):returnlen(self._data)defis_empty(self):return len(self) ==0def add(self, key, value): #在后面加上然后加上

self._data.append(self.Item(key, value))

self._upheap(len(self._data)- 1)defmin(self):ifself.is_empty():raise ValueError( "Priority queue is empty.")

item=self._data[0]return(item._key, item._value)defremove_min(self):ifself.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)

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._swap(j, parent)

self._upheap(parent)def _downheap(self, j):#往下交换,递归比较三个值

ifself._has_left(j):

left=self._left(j)

small_child=leftifself._has_right(j):

right=self._right(j)if self._data[right]

small_child=rightif self._data[small_child]

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 inheap._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

26minis:

(1, 'A')

remove min:

(1, 'A')

Now minis:

(2, 'B')

remove min:

(2, 'B')

Now minis:

(3, 'C')

Now minis:

(1, 'A')

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

'''heaqp模块提供了堆队列算法的实现,也称为优先级队列算法。

要创建堆,请使用初始化为[]的列表,或者可以通过函数heapify()将填充列表转换为堆。

提供以下功能:

heapq.heappush(堆,项目)

将值项推入堆中,保持堆不变。

heapq.heapify(x)

在线性时间内将列表x转换为堆。

heapq.heappop(堆)

弹出并返回堆中的最小项,保持堆不变。如果堆是空的,则引发IndexError。'''

importheapq#1 heappush生成堆+ heappop把堆从小到大pop出来

heap =[]

data= [1,3,5,7,9,2,4,6,8,0]for i indata:

heapq.heappush(heap,i)print(heap)

lis=[]whileheap:

lis.append(heapq.heappop(heap))print(lis)#2 heapify生成堆+ heappop把堆从小到大pop出来

data2 = [1,5,3,2,9,5]

heapq.heapify(data2)print(data2)

lis2=[]whiledata2:

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]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值