⬅用Python 與 串列 來實現 Queue(佇列)

閱讀時間約 1 分鐘

在之前的教學中,已經學會了Node和Linked List的實作,

用Python實現了單向鏈結串列Singly linked list雙向鏈結串列Doubly linked list


今天要承接之前打下的基礎,用雙向鏈結串列來實作Queue(佇列 或稱 隊列)。


定義

是一個線性長條狀的資料結構。

規定推入資料都是從尾端(Rear)進入取出資料都必須在頭部(Front)取出


(就像去餐廳吃飯,或者 排隊買東西,
新客人從隊伍的尾巴開始排隊,而商家從隊伍最前面的客人開始服務。)


也由於這項規定,Queue先天具有先進先出First-in First-out的這種特質。


raw-image

支援的操作與介面


queue.enqueue(data)

推入一筆新資料data進入queue的尾端。

raw-image




queue.front()

取得queue頭部目前的資料。


raw-image



queue.dequeue()

取得queue頭部目前的資料,並且將此資料從queue移除。


raw-image



len( queue )

取得queue的大小,也就是現在有幾筆資料存在queue裡。


raw-image



queue.is_empty()

判斷stack是否為空。


raw-image



優點

1.在尾巴新增資料O(1) 常數時間

2.在頭部取得資料O(1) 常數時間

3.在頭部移除資料O(1) 常數時間

4.可以根據需求動態延伸或縮短,有效利用記憶體空間。


缺點

1.不支援random acess,不支援Queue[ index ] 這種操作。

2.如果要取得內部的資料,必須先將頭部的資料依序移除


Queue的class定義 與 建構子(初始化函式)

class Queue:

  def __init__(self):
    self.queue = LinkedList()

Queue常見的function實現


1.在queue尾巴插入新玩素


直接在queue尾巴放入新元素,對應的底層實作就是在尾巴串上新結點。


時間複雜度: O(1) 常數時間

  def enqueue(self, data):

    self.queue.insertAtTail(data)
    return

2.讀取queue頭部玩素


直接返回queue頭部的元素,對應的底層實作就是在返回頭部結點的資料。

實作上有個細節需要留意,假如stack是空的,直接返回None即可。


時間複雜度: O(1) 常數時間

  def front(self):

    if self.queue.head is None:
      return None

    return self.queue.head.data

3.從queue頭部取出舊元素


直接返回並且移除queue頭部的元素,

對應的底層實作就是返回並且移除頭部結點的資料。


時間複雜度: O(1) 常數時間

  def dequeue(self):

    return self.queue.removeAtHead()

4.取得queue的長度


返回queue的長度,也代表queue內部資料的總數量。

對應的底層實作就是在返回串列的長度。


時間複雜度: O(1) 常數時間

  def __len__(self):

    return len(self.queue)

5.檢查queue是否為空


如果queue的長度為0,代表queue是空的,內部沒有任何資料。


時間複雜度: O(1) 常數時間

  def is_empty(self):

    return 0 == self.queue.size

完整的Queue實作和程式碼,
底層是Doubly Linked List雙向鏈結串列。

class Node:

def __init__(self, data):
# 儲存節點的資料
self.data = data

# 指向下一個節點,初始化為空 None
self.next = None

# 指向前一個節點,初始化為空 None
self.prev = None


class LinkedList:
def __init__(self):

# 頭部節點初始化為空
self.head = None
# 尾巴節點初始化為空
self.tail = None

# 串列長度初始化為0
self.size = 0


def insertAtHead(self,data):
new_node = Node(data)

self.size += 1

# If the list is empty
if self.tail is None:
self.head = new_node
self.tail = new_node
else:

# Update linkage
new_node.next = self.head
self.head.prev = new_node

self.head = new_node
return


def insertAtTail(self, data):
new_node = Node(data)

self.size += 1

# If the list is empty
if self.head is None:
self.head = new_node
self.tail = new_node
else:

# Update linkage
self.tail.next = new_node
new_node.prev = self.tail

self.tail = new_node

return


def removeAtHead(self):
if self.head is None:
return
else:
self.size -= 1
oldHead = self.head

# Update linkage
if self.head == self.tail:
self.tail = None
self.head = None
else:
self.head = self.head.next

# Break linkage
oldHead.next = None

if self.head:
self.head.prev = None

return oldHead


def removeAtTail(self):
if self.tail is None:
return
else:
self.size -= 1
oldTail = self.tail

# Update linkage
if self.tail == self.head:
self.tail = None
self.head = None
else:
self.tail = self.tail.prev

# Break linkage
oldTail.prev = None

if self.tail:
self.tail.next = None

return oldTail


def traverse(self):

print("Forward traversal")
cur = self.head

while cur:
print(cur.data, end=' <-> ')
cur = cur.next
print("None")

print(f"Size of singly linked list: {self.size} \n", )
return


def backward_traverse(self):

print("Backward traversal")
cur = self.tail

while cur:
print(cur.data, end=' <-> ')
cur = cur.prev
print("None")

print(f"Size of singly linked list: {self.size} \n", )
return

def search(self, target):
cur = self.head
while cur:
if cur.data == target:
return cur

cur = cur.next

return None


def removeAfter(self, node):

self.size -= 1

removed = node.next
the_one_after_removal = node.next.next if node.next else None

# Update linkage
if the_one_after_removal:
the_one_after_removal.prev = node

node.next = the_one_after_removal
# Break linkage
if removed:
removed.next = None
removed.prev = None

return removed


def insertAfter(self, node, new_node):

self.size += 1

the_one_after_insertion = node.next

# Update linkage
node.next = new_node
new_node.prev = node

the_one_after_insertion.prev = new_node
new_node.next = the_one_after_insertion
return


def __contains__(self, item):

cur = self.head
while cur:
if cur.data == item:
return True

cur = cur.next

return False

def __len__(self):
return self.size


class Queue:
def __init__(self):
self.queue = LinkedList()


def enqueue(self, data):
self.queue.insertAtTail(data)
return


def dequeue(self):
return self.queue.removeAtHead()


def front(self):
if self.queue.head is None:
return None

return self.queue.head.data


def is_empty(self):
return 0 == self.queue.size


def __len__(self):
return len(self.queue)


def __contains__(self, item):
return item in self.queue


def traverse(self):
self.queue.traverse()
return


def test():

print(f"Empty queue\n")
queue = Queue()

for i in range(1, 5):
print(f"Push {i}...")
queue.enqueue(i)

print()
print(f"Is stack empty? {queue.is_empty()}")
print(f"Size of stack: { len(queue) } ")
print()

for i in range(1,6):
print(f"Is {i} in stack? = { i in queue}")

print()
queue.traverse()

for _ in range( len(queue) ):
print(f"Front of queue = {queue.front()}")
print(f"Dequeue {queue.front()} ...\n")
queue.dequeue()

print(f"Is stack empty? {queue.is_empty()}")

return

if __name__ == "__main__":
test()

測試輸出

Empty queue

Push 1...
Push 2...
Push 3...
Push 4...

Is stack empty? False
Size of stack: 4

Is 1 in stack? = True
Is 2 in stack? = True
Is 3 in stack? = True
Is 4 in stack? = True
Is 5 in stack? = False

Forward traversal
1 <-> 2 <-> 3 <-> 4 <-> None
Size of singly linked list: 4

Front of queue = 1
Dequeue 1 ...

Front of queue = 2
Dequeue 2 ...

Front of queue = 3
Dequeue 3 ...

Front of queue = 4
Dequeue 4 ...

Is stack empty? True

結語


這篇我們透過Linked List作為底層的輔助資料結構,來實現完整的Queue class 和 interface function。


讀者可以搭配先前的教學文章,一起復習相關的資料結構。

也可以和Stack做一個對照,比較兩者之間的相同和相異之處。


Queue相關的演算法練習題與詳解


應用題 用Queue實作Stack_Leetcode #225 Implement Stack using Queues


應用題 用Stack實作Queue_Leetcode #232 Implement Queue using Stacks


資料結構實作題 環狀佇列 Design Circular Queue Leetcode #622


83會員
425Content count
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
留言0
查看全部
發表第一個留言支持創作者!
在之前的教學中,已經學會了Node和Linked List的實作, 用Python實現了單向鏈結串列Singly linked list、雙向鏈結串列Doubly linked list。 今天要承接之前打下的基礎,用雙向鏈結串列來實作Stack 堆疊。
在資料結構與演算法裡, 最簡單的線性資料結構除了array之外就是linked list鏈結串列了。 Linked list又有分為單向Singly linked list 和雙向Doubly linked list
在這次的BMI(身體質量指標)計算教學裡, 將學會如何用python來接收使用者輸入的訊息,並且做一些簡單的四則運算。
從範例學python的目標讀者: 針對剛進入的初學者,想學習Python語言。 有基礎本數學邏輯基礎即可。 從小遊戲學python的目標讀者: 針對已經有經驗的C/C++, Python, 或其他有程式基礎的讀者。 想實作一些小專案,從實做中學習如何分析需求、元件分拆、到底層實作
在程式語言裡,最基本的第一堂課通常就是最簡單也最直接的輸入和輸出, 今天,會從大家耳熟能詳的"Hello Wolrd"這個經典範例開始介紹 Python的基本的輸出print語法,最後以冷笑話的範例作為結尾的Demo。 從電腦的視角來看,什麼叫做Output輸出?
在資料結構與演算法裡, 最簡單的線性資料結構除了list之外就是linked list鏈結串列了。 Linked list又有分為單向Singly linked list 和雙向Doubly linked list 在這篇文章,會從最基礎的Singly linked list開始講起。 定義
在之前的教學中,已經學會了Node和Linked List的實作, 用Python實現了單向鏈結串列Singly linked list、雙向鏈結串列Doubly linked list。 今天要承接之前打下的基礎,用雙向鏈結串列來實作Stack 堆疊。
在資料結構與演算法裡, 最簡單的線性資料結構除了array之外就是linked list鏈結串列了。 Linked list又有分為單向Singly linked list 和雙向Doubly linked list
在這次的BMI(身體質量指標)計算教學裡, 將學會如何用python來接收使用者輸入的訊息,並且做一些簡單的四則運算。
從範例學python的目標讀者: 針對剛進入的初學者,想學習Python語言。 有基礎本數學邏輯基礎即可。 從小遊戲學python的目標讀者: 針對已經有經驗的C/C++, Python, 或其他有程式基礎的讀者。 想實作一些小專案,從實做中學習如何分析需求、元件分拆、到底層實作
在程式語言裡,最基本的第一堂課通常就是最簡單也最直接的輸入和輸出, 今天,會從大家耳熟能詳的"Hello Wolrd"這個經典範例開始介紹 Python的基本的輸出print語法,最後以冷笑話的範例作為結尾的Demo。 從電腦的視角來看,什麼叫做Output輸出?
在資料結構與演算法裡, 最簡單的線性資料結構除了list之外就是linked list鏈結串列了。 Linked list又有分為單向Singly linked list 和雙向Doubly linked list 在這篇文章,會從最基礎的Singly linked list開始講起。 定義
你可能也想看
Google News 追蹤
Thumbnail
本專欄將提供給您最新的市場資訊、產業研究、交易心法、優質公司介紹,以上內容並非個股分析,還請各位依據自身狀況作出交易決策。歡迎訂閱支持我,獲得相關內容,也祝您的投資之路順遂! 每年 $990 訂閱方案👉 https://reurl.cc/VNYVxZ 每月 $99 訂閱方案👉https://re
Thumbnail
若沒有這一分鐘,也許大人們永遠不會與中學生有所交集; 但有了這一分鐘,也許思想的交集將成為開創未來的契機。 「Talk Folk Dance」是個讓大人和中學生們進行對話的活動。每一題,每人只有一分鐘的時間談論自己的想法。同時也提供了一個當地居民和中學生對話的場域。
Thumbnail
近期幣圈大盤表現不好,BTC 於8/18凌晨直接下殺跌破28,000 的支撐,山寨幣也普遍走弱,在盤勢尚位穩定之前,除了做套利交易,本篇文章也會介紹一個方式,能透過 Bybit 交易所的 0 成本借貸功能,在建立底倉的同時,透過挖礦增加收益。(若還沒有Bybit帳戶的讀者,可以考慮用呢喃
Thumbnail
前文參考: 兩張圖回顧一週大盤與個股結構,再談一般人目前最安穩的獲利模式。 2月17日 然後,大家會發現,前文提到的比較現象,在最近幾日更為明確:
Thumbnail
選前消極防守賺太少,選後台股萬一意外續強,該如何? 11月17日 從11月初消極防守的應對到現在,明天(11月26日)即將選舉。 個人不談政治,只談幾乎旁觀的這個月所觀察到的一些重點,以及選後可能的第一筆個人新增投機:
Thumbnail
大富翁式旅行,不是像大富翁一樣的奢華旅行,而是使用玩桌遊大富翁的方式,隨機決定你要前往的車站;再以該站為圓心,走訪附近一帶。雖然範圍被局限,卻可能會在有限之中,不經意發現過去被錯過的亮點,打開你的眼界。
Thumbnail
公職考試的作文題,不時出現一些八股題目,原本寫作能力不佳的考生遇到它就已經夠頭大的了;讀了補習班提供的範文,非但沒有放下心來,這些有看沒有懂的文章,反而讓考生更加憂心…… 就大膽把這些範文全扔了吧!只要掌握「用例」的竅門,作文白痴也可以寫出有吸睛度,也有深度的好文哦。
Thumbnail
網路謠言滿天飛,用更客觀的科學知識強身健體吧! 方格子健康月,匯集各大領域的健康保健專題,日常防護、皮膚保養、身體排毒、心理療癒——即刻啟動閱讀,讓你從裡到外補充滿滿能量,照顧好自己的身心靈!4/30前訂閱或購買健康月精選專題,輸入折扣碼health2020,精選專題全面8折起。
Thumbnail
方格子無廣告簡潔的介面非常適合用關燈模式進行閱讀或創作 身為一個宅宅工程師,螢幕打開應該就是要黑黑 der 才算是稱職(?) 方格子的介面因為沒有廣告也夠簡單,因此特別適合用關燈模式進行創作或是閱讀,在 Chrome 上面有許多外掛可以使用,新版的 Chrome 也可以選擇黑暗模式
Thumbnail
本專欄將提供給您最新的市場資訊、產業研究、交易心法、優質公司介紹,以上內容並非個股分析,還請各位依據自身狀況作出交易決策。歡迎訂閱支持我,獲得相關內容,也祝您的投資之路順遂! 每年 $990 訂閱方案👉 https://reurl.cc/VNYVxZ 每月 $99 訂閱方案👉https://re
Thumbnail
若沒有這一分鐘,也許大人們永遠不會與中學生有所交集; 但有了這一分鐘,也許思想的交集將成為開創未來的契機。 「Talk Folk Dance」是個讓大人和中學生們進行對話的活動。每一題,每人只有一分鐘的時間談論自己的想法。同時也提供了一個當地居民和中學生對話的場域。
Thumbnail
近期幣圈大盤表現不好,BTC 於8/18凌晨直接下殺跌破28,000 的支撐,山寨幣也普遍走弱,在盤勢尚位穩定之前,除了做套利交易,本篇文章也會介紹一個方式,能透過 Bybit 交易所的 0 成本借貸功能,在建立底倉的同時,透過挖礦增加收益。(若還沒有Bybit帳戶的讀者,可以考慮用呢喃
Thumbnail
前文參考: 兩張圖回顧一週大盤與個股結構,再談一般人目前最安穩的獲利模式。 2月17日 然後,大家會發現,前文提到的比較現象,在最近幾日更為明確:
Thumbnail
選前消極防守賺太少,選後台股萬一意外續強,該如何? 11月17日 從11月初消極防守的應對到現在,明天(11月26日)即將選舉。 個人不談政治,只談幾乎旁觀的這個月所觀察到的一些重點,以及選後可能的第一筆個人新增投機:
Thumbnail
大富翁式旅行,不是像大富翁一樣的奢華旅行,而是使用玩桌遊大富翁的方式,隨機決定你要前往的車站;再以該站為圓心,走訪附近一帶。雖然範圍被局限,卻可能會在有限之中,不經意發現過去被錯過的亮點,打開你的眼界。
Thumbnail
公職考試的作文題,不時出現一些八股題目,原本寫作能力不佳的考生遇到它就已經夠頭大的了;讀了補習班提供的範文,非但沒有放下心來,這些有看沒有懂的文章,反而讓考生更加憂心…… 就大膽把這些範文全扔了吧!只要掌握「用例」的竅門,作文白痴也可以寫出有吸睛度,也有深度的好文哦。
Thumbnail
網路謠言滿天飛,用更客觀的科學知識強身健體吧! 方格子健康月,匯集各大領域的健康保健專題,日常防護、皮膚保養、身體排毒、心理療癒——即刻啟動閱讀,讓你從裡到外補充滿滿能量,照顧好自己的身心靈!4/30前訂閱或購買健康月精選專題,輸入折扣碼health2020,精選專題全面8折起。
Thumbnail
方格子無廣告簡潔的介面非常適合用關燈模式進行閱讀或創作 身為一個宅宅工程師,螢幕打開應該就是要黑黑 der 才算是稱職(?) 方格子的介面因為沒有廣告也夠簡單,因此特別適合用關燈模式進行創作或是閱讀,在 Chrome 上面有許多外掛可以使用,新版的 Chrome 也可以選擇黑暗模式