資料結構筆記-棧與佇列python實現
概述
棧與佇列是程式設計中被廣泛應用的兩種重要的資料結構,都是在特定範圍的儲存單元記憶體儲資料,這些資料都可以被重新取出使用,與線性表相比,他們的插入和刪除受到更多的約束,固又稱限定性的線性表結構。他們是最簡單的快取結構,他們只支援資料項的儲存與訪問,不支援資料項之間的任何關係。因此,這兩種資料集合都很小,很簡單,其中最重要的操作就是元素的存入與取出。作為資料結構,他們還需要幾個任何資料結構都需要的操作,如結構的建立,檢查是否為空狀態等。
在計算中,中間資料物件的生成有早有晚,存在時間上的先後順序。在後面使用這些元素時,也可能需要考慮他們的生成時間順序。
→棧是保證元素後進先出(後存入者先使用,Last In First Out,LIFO)關係的結構。
→佇列是保證元素先進先出(先存入者先使用,First In First Out)關係的結構。
1.棧
棧是一種容器,可存入資料,訪問元素,刪除元素等。存入棧中的元素相互之間沒有任何具體關係,只有到來的時間先後順序。在這裡沒有元素的位置,元素的前後順序等概念。棧的基本性質保證,在任何時刻可以訪問,刪除的元素都是在此之前的最後存入的那個元素。因此,棧確定了一種預設元素的訪問順序,訪問數無需其他資訊。
1_1.棧的抽象資料型別描述:
ADT Stack: Stack(self) #建立空棧 is_empty(self) #判斷棧是否為空,空時返回True否則返回False push(self,e) #將元素elem加入棧,稱為壓入或推入 pop(self) #刪除棧裡最後壓入的元素並將其返回,常稱為彈出 top(self) #取得棧裡最後壓入的元素,不彈出
1_2.棧的陣列實現
把陣列的首元素當做棧底,同時記錄棧中的個數size,假設陣列的首地址為arr,壓棧的操作就是將元素放入arr[size],彈棧就是取陣列arr[size-1]的元素,然後執行size減一,根據這個原理實現棧。
#!/usr/bin/python # -*- coding:utf-8 -*- #實現棧 #方法一:陣列實現棧 class MyStack: __slots__ = ('items')#該屬性僅對當前類有用 繼承類沒用 #模擬棧 def __init__(self): self.items = [] #判斷棧是否為空 def is_empty(self): return len(self.items)==0 #返回棧的大小 def size(self): return len((self.items)) #返回棧頂元素 def top(self): if not self.is_empty(): return self.items[len(self.items)-1] else: return None #彈棧 def pop(self): if len(self.items)>0: return self.items.pop() else: print('棧已經為空') return None #壓棧 def push(self,item): self.items.append(item) if __name__ == "__main__": s = MyStack() s.push(4) s.push(3) s.push(2) s.push(1) print('棧頂元素: '+str(s.top())) print('棧大小為: '+str(s.size())) s.pop() print('彈棧成功')
棧頂元素: 1
棧大小為: 4
彈棧成功
[Finished in 0.1s]
1_3.棧的列表實現
由於陣列的初始大小會佔用多餘的記憶體,且在元素量未知的情況下可能會出現擴容的情況,因此也可以使用連結串列實現棧,但相應的增加了空間代價記錄指標位置,但也是一種方法。在執行壓棧操作時,只需把連結串列首節點的next指標指向當前壓入元素,再把當前元素next指標指向之前首節點指向的元素地址即可,彈出元素就更簡單了,只需修改首節點指標到head.next.next的位置,顯示head.next.data即可完成彈棧操作。
#方法二:連結串列實現
class LNode:
def __init__(self,x,next_=None):
self.data = x
self.next = next_
class MyStack:
def __init__(self):
#pHead=LNode()
self.data = None
self.next = None
#判斷stack是否為空,如果空返回true,否則返回false
def empty(self):
if self.next ==None:
return True
else:
return False
#獲取棧中元素個數
def size(self):
size = 0
p = self.next
while p != None:
p = p.next
size += 1
return size
#入棧:放入棧頂
def push(self,e):
p = LNode(e)
p.next = self.next#None
self.next = p
def pop(self):
tmp = self.next
if tmp != None:
self.next = tmp.next
return tmp.data
print('棧已空')
return None
def top(self):
if self.next != None:
return self.next.data
print('棧已空')
return None
if __name__ == '__main__':
stack = MyStack()
stack.push(4)
stack.push(3)
stack.push(2)
stack.push(1)
print('棧頂元素為: '+str(stack.top()))
print('棧大小為: '+str(stack.size()))
stack.pop()
print('彈棧成功')
與前面陣列不同的是,這裡需要自定義連結串列結構LNode.
棧頂元素為: 1
棧大小為: 4
彈棧成功
[Finished in 0.1s]
2.佇列
佇列也稱為隊,佇列中也沒有位置的概念,只支援預設的元素存入與取出,其特點就是保證在任何時候訪問或刪除的元素,都是在此前最早存入佇列且尚未刪除的那個元素。可以借用資料的儲存順序表示資料的儲存時間的先後關係,用線性表作為佇列的實現結構,利用元素的儲存順序表示其訪問順序。
2_1.佇列的抽象資料型別描述:
ADT Queue:
Queue(self) #建立空佇列
is_empty(self) #判斷佇列是否為空,空返回True否則返回False
enqueue(self,e) #將元素elem加入佇列,稱為入隊
dequeue(self) #刪除隊裡最早進入的元素,稱為出隊
peek(self) #檢視佇列最早進入的元素,不刪除
2_2.佇列的陣列實現
用兩個指標front和rear記錄佇列的首尾元素位置,入隊只需將入隊元素放到rear的位置,同時執行rear+,出隊時只需執行front+的操作即可。
#!/usr/bin/python
# -*- coding:utf-8 -*-
#方法一:佇列實現
class MyQueue:
def __init__(self):
self.arr = []
self.front = 0#佇列頭
self.rear = 0#佇列尾
def isEmpty(self):
return self.front == self.rear
#返回佇列的大小
def size(self):
return self.rear - self.front
#返回佇列首元素
def getFront(self):
if self.isEmpty():
return None
return self.arr[self.front]
#返回隊尾元素
def getBack(self):
if self.isEmpty():
return None
return self.arr[self.rear-1]
#刪除佇列頭元素
def deQueue(self):
if self.rear>self.front:
self.front +=1
else:
print("佇列已空")
#增加佇列元素
def enQueue(self,item):
self.arr.append(item)
self.rear += 1
if __name__ == '__main__':
queue = MyQueue()
queue.enQueue(1)
queue.enQueue(2)
print('佇列首元素'+str(queue.getFront()))
print('隊尾元素'+str(queue.getBack()))
print('佇列大小:'+str(queue.size()))
佇列首元素1
隊尾元素2
佇列大小:2
[Finished in 0.1s]
2_3.佇列的連結串列實現
採用連結串列實現佇列與實現棧方法類似,通過使用頭指標pHead與尾指標pEnd指向對首先與隊尾元素,新元素入隊只需將pEnd指標指向新元素並修改pEnd+1,出隊則需要修改pHead指標到pHead.next.next,其他不變。
#方法二:連結串列實現
class LNode:
def __init__(self,x,next_=None):
self.data = x
self.next = next_
class MyQueue:
#分配頭結點
def __init__(self):
self.pHead = None
self.pEnd = None
#判斷佇列是否為空
def isEmpty(self):
if self.pHead == None:
return True
else:
return False
#獲取棧中元素
def size(self):
size = 0
p = self.pHead
while p != None:
p = p.next
size += 1
return size
#入佇列:向佇列加入元素e
def enQueue(self,e):
p = LNode(e)
p.next = None
if self.pHead == None:
self.pHead = self.pEnd = p
else:
self.pEnd.next = p
self.pEnd = p
#出佇列
def deQueue(self):
if self.pHead == None:
print("出佇列失敗,佇列為空")
print('出隊元素:'+str(self.pHead.data))
self.pHead = self.pHead.next
if self.pHead == None:
self.pEnd = None
#取得佇列首元素
def getFront(self):
if self.pHead == None:
print("佇列為空")
return None
return self.pHead.data
#取得隊尾元素
def getBack(self):
if self.pEnd == None:
print("佇列為空")
return None
return self.pEnd.data
if __name__ == "__main__":
queue = MyQueue()
queue.enQueue(1)
queue.enQueue(2)
print('佇列首元素'+str(queue.getFront()))
print('隊尾元素'+str(queue.getBack()))
print('佇列大小:'+str(queue.size()))
佇列首元素1
隊尾元素2
佇列大小:2
[Finished in 0.1s]