基础数据结构01python

发布于:2024-12-18 ⋅ 阅读:(64) ⋅ 点赞:(0)

堆(Heap)是一种特殊的完全二叉树数据结构,满足以下特性:

1.完全二叉树:堆是一棵完全二叉树,即除最后一层外,其他层的节点都被元素填满,且最后一层的节点尽可能地从左到右排列

2.堆序性质:在最大堆中,每个节点的值都大于或等于其子节点的值;在最小堆中,每个节点的值都小于或等于其子节点的值

堆通常通过数组来实现,因为完全二叉树可以高效地映射到数组中

在数组表示中,假设根节点存储在数组的第一个位置(索引为0),对于任意一个节点,其父节点和子节点的位置可以通过以下公式计算:

父节点索引:parent(i) = (i - 1) // 2

左子节点索引:left(i) = 2 * i + 1

右子节点索引:right(i) = 2 * i + 2

堆的常见操作包括:

1.插入元素:将新元素添加到堆中,并通过上浮操作(sift up)维护堆的性质。

2.删除堆顶元素:移除堆顶元素(最大堆的最大值或最小堆的最小值),并通过下沉操作(sift down)重新平衡堆。

3.构建堆:将无序数组转换为堆结构,常用的方法是从最后一个非叶子节点开始,依次对每个节点进行下沉操作。

eg:

使用list表示一个堆

1.将无序List转换成最小堆:

heapq.heapify(a)

2.最小堆a中添加元素x:

heapq.heappush(a, x)

3.弹出并返回最小元素:

heapq.heappop(a)

4.弹出并返回最小元素,同时添加元素x:

heapq.heapreplace(a, x)

import heapq
a = [11,7,9,10,8,5]
# 将列表a转换成最小堆
heapq.heapify(a)
print('a=',a)
# 将元素4放入堆a中
heapq.heappush(a,4)
print('a=',a)
# 当a非空,一直弹出并返回a的堆顶(最小元素)
while len(a):
    print(heapq.heappop(a),end=' ')

代码例子a添加元素4过程

删除最小元素过程

注意图中元素9元素6还要进行换位,然后9再和8换位,输出序列形式呈现[4,8,9,7,6,11]

堆在计算机科学中有广泛的应用,例如:

优先队列:使用堆实现的优先队列可以高效地获取和删除优先级最高的元素。

堆排序:利用堆的性质对数组进行排序,时间复杂度为O(n log n)。

图算法:在Dijkstra算法等图算法中,堆用于快速获取当前最短路径的节点

优先队列

优先队列(Priority Queue)是一种特殊的队列数据结构,其中每个元素都关联有一个优先级。与传统的先进先出(FIFO)队列不同,优先队列总是优先处理优先级最高的元素

主要特点:

元素出队顺序:每次出队操作都会移除并返回当前优先级最高的元素。

实现方式:优先队列通常使用堆(Heap)数据结构实现,最常见的是二叉堆。在二叉堆中,最小堆用于实现最小优先队列,最大堆用于实现最大优先队列。

一般我们使用优先队列采用queue库中的PriorityQueue

定义优先队列:

from queue import PriorityQueue

pq =PriorityQueue()

元素x入队:

pq.put(3)

pq.put(2)

pq.put(1)

获取最小元素:

print(pq.queue[0])

取出最小元素:

print(pq.get())

print(pq.get())

print(pq.get())

底层实现仍然是先前的heapq

from queue import PriorityQueue
pq = PriorityQueue()
# 元素x入队
pq.put(6)
pq.put(4)
pq.put(2)
# 获取最小元素 2
print(pq.queue[0])
print(pq.queue[2]) # [2,6,4]
# 取出最小元素 2
print(pq.get())
# pq 本身无法直接通过 print(pq) 来显示其内部的队列内容,因为 PriorityQueue 是一个线程安全的类
print(pq.queue)
print(pq.get())

例题

蓝桥账户中心

每一个打印任务都有其重要性,小蓝用一个 11 到 99 的数字来表示,数字越大表示这个任务越重要。复印机的运行规则如下:从待打印任务队列中取出一个任务,如果队列中还有比这个任务更重要的任务,那么就把这个任务放回队列的尾部,等待下一次打印;否则就开始打印这个任务。需要注意的是,一旦开始打印任务,就不会再把它放回打印队列。我们假设每个打印任务都需要 11 分钟才能完成。

# 涉及队列中元素的优先级 -- 优先队列
# 用一个 1到9的数字来表示,数字越大表示这个任务越重要 -- 最大堆 取负号后再放入优先队列中

from queue import Queue,PriorityQueue 
# 普通队列模拟任务(先进先出),优先队列模拟‘神奇复印机’的工作方式
N,X = map(int,input().split())
# x是要确定的优先级
a = list(map(int,input().split()))
q = Queue()
pq = PriorityQueue()

# 添加任务到普通队列
for i,x in enumerate(a):
  q.put((i,x))
  # 取负号,维护最大堆
  pq.put(-x)

wait = 0
while True:
  # 模拟一开始的任务顺序
  i,x = q.get()
  # 最大堆堆顶,即优先级最高的‘任务’(元素)
  if -x == pq.queue[0]:
    pq.get()
    wait += 1
    # 是小桥的任务 不能写:x == a[X],因为值不一定唯一但位置是唯一的
    if i == X:
      print(wait)
      break
  # 如果这次任务不是优先级最高的任务就要放回普通任务中,否则会出现任务丢失的情况
  else:
    # q一直保持原长度,避免丢掉任务
    q.put((i,x))


网站公告

今日签到

点亮在社区的每一天
去签到