1. 程式人生 > >資料結構筆記-棧與佇列python實現

資料結構筆記-棧與佇列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]