中国大学MOOC,数据结构与算法(Python版)学习笔记
课程网址:“https://www.icourse163.org/course/PKU-1206307812”
文章目录
一. 队列及其Python实现
什么是队列
队列是一种有次序的数据集合,其特征是新数据项的添加总发生在一端(通常称为“尾rear”端)而现存数据项的移除总发生在另一端(通常称为“首front”端)。
当数据项加入队列,首先出现在队尾,随着队首数据项的移除,它逐渐接近队首。新加入的数据项必须在数据集末尾等待,而等待时间最长的数据项则是队首。这种次序安排的原则称为(
F
I
F
O
:
F
i
r
s
t
−
i
n
f
i
r
s
t
−
o
u
t
FIFO:First-infirst-out
FIFO:First−infirst−out)先进先出或先到先服务(
f
i
r
s
t
−
c
o
m
e
f
i
r
s
t
−
s
e
r
v
e
d
first-come first-served
first−comefirst−served)。
队列仅有一个入口和一个出口不允许数据项直接插入队中,也不允许从中间移除数据项。
队列的Python实现
抽象数据结构Queue的实现如下:
class Queue:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def enqueue(self, item):
self.items.insert(0, item)
def dequeue(self):
return self.items.pop()
def size(self):
return len(self.items)
- Queue():创建一个空队列对象,返回值为Queue对象;
- enqueue(item):将数据项item添加到队尾,无返回值;
- dequeue():从队首移除数据项,返回值为队首数据项,队列被修改;
- isEmpty():测试是否空队列,返回值为布尔值
- size():返回队列中数据项的个数。
采用List来容纳Queue的数据项,将List首端作为队列尾端,List的末端作为队列首端;
enqueue()复杂度为
O
(
n
)
O(n)
O(n),dequeue()复杂度为
O
(
1
)
O(1)
O(1),首尾倒过来的实现,复杂度也倒过来。
队列的简单应用——热土豆问题
问题描述:
和 击 鼓 传 花 击鼓传花 击鼓传花差不多,把鼓去掉,把花换成烫手的土豆就成了热土豆问题了,固定传 n n n次土豆,第 n n n个拿土豆的淘汰。用队列来实现热土豆问题的算法,输入参加游戏的人名列表,以及传土豆次数 n u m num num,算法输出最后剩下的人名。
算法分析:
模拟程序采用队列来存放所有参加游戏的人名,按照传递土豆方向从队首排到队尾游戏时,队首始终是持有土豆的人;模拟游戏开始,只需要将队首的人出队,随即再到队尾入队,算是土豆的一次传递传递了 n u m num num次后,将队首的人移除,不再入队如此反复,直到队列中剩余1人。
Python实现:
def hotPotato(namelist, num):
namequeue = Queue()
for name in namelist: # 人名队列
namequeue.enqueue(name)
while namequeue.size() > 1:
for i in range(num):
namequeue.enqueue(namequeue.dequeue()) # 土豆传递一次
namequeue.dequeue() # 传递到num次的土豆拥有者被淘汰
return namequeue.dequeue()
print(hotPotato(["Alice", "Susan", "Ben", "Anny", "Bill"], 7))
二. 双端队列及其实现
什么是双端队列
双端队列
D
e
q
u
e
Deque
Deque是一种有次序的数据集,跟队列相似,其两端可以称作“首”“尾”端,但
D
e
q
u
e
Deque
Deque中数据项既可以从队首加入,也可以从队尾加入;数据项也可以从两端移除。某种意义上说,双端队列集成了栈和队列的能力。
但双端队列并不具有内在的
L
I
F
O
LIFO
LIFO或者
F
I
F
O
FIFO
FIFO特性如果用双端队列来模拟栈或队列需要由使用者自行维护操作的一致性。
双端队列的Python实现
class Deque:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def addFront(self, item):
self.items.append(item)
def addRear(self, item):
self.items.insert(0, item)
def removeFront(self):
return self.items.pop()
def removeRear(self):
return self.items.pop(0)
def size(self):
return len(self.items)
- Deque():创建一个空双端队列
- addFront(item):将item加入队首
- addRear(item):将item加入队尾
- removeFront():从队首移除数据项,返回值为移除的数据项
- removeRear():从队尾移除数据项,返回值为移除的数据项
- isEmpty():返回deque是否为空
- size():返回deque中包含数据项的个数
采用List实现,List下标0作为deque的尾端,List下标-1作为deque的首端;
操作复杂度
a
d
d
F
r
o
n
t
/
r
e
m
o
v
e
F
r
o
n
t
:
O
(
1
)
,
a
d
d
R
e
a
r
/
r
e
m
o
v
e
R
e
a
r
:
O
(
n
)
addFront/removeFront:O(1),addRear/removeRear:O(n)
addFront/removeFront:O(1),addRear/removeRear:O(n)
双端队列的简单应用——“回文词”判断
回文词:正读反读都一样的词
用双端队列很容易解决“回文词”问题:先将需要判定的词从队尾加入
D
e
q
u
e
Deque
Deque再从两端同时移除字符判定是否相同,直到
D
e
q
u
e
Deque
Deque中剩下0个或1个字符。
Python实现:
def palchecker(aString):
chardeque = Deque()
for ch in aString:
chardeque.addRear(ch)
stillEqual = True
while chardeque.size() > 1 and stillEqual:
first = chardeque.removeFront()
last = chardeque.removeRear()
if first != last:
stillEqual = False
return stillEqual
print(palchecker("lsdkjfskf"))