1. 程式人生 > >Python用列表實現棧,佇列(二)

Python用列表實現棧,佇列(二)

用列表實現佇列

       佇列和棧實現的功能差不多,無非是入佇列,出佇列,佇列長度等等。其中,入佇列可以用列表的append()來實現,出佇列可以使用pop(0)來實現。由於這個實現方法比較簡單,因此它也是最低效的。append方法入佇列和棧實現分析的一樣,每次新增元素都有可能要換底層陣列,所以效率不高;pop(0)操作的呼叫總是最壞情況,因為第一個元素移除,後面的所有元都需要往前移一位。
       對於append的低效,我們可以用改進棧的方法來改進佇列實現:具體參考Python用列表實現棧,佇列(一)

。而對於pop(0)的低效,我們可以用空的指標來代替移除的元素,這樣後面的元素就不會往前移動。但是這樣的操作也有缺點:隨著佇列的使用,底層陣列的大小會增長到 m m m m 是從佇列建立以來所有新增到佇列的元素(前面都是空指標),這樣會佔用大量的記憶體。對此,我們可以迴圈使用陣列來解決:假設預設佇列大小為 N
N
(索引為 0 N 1 0-N-1 ),並設_front為佇列第一個元素的索引,_size為當前佇列的大小。

  • 入佇列操作:給索引為(_front+_size)% N N 賦值;
  • 出佇列操作:給索引為_front賦值為None,並且第一個元素的索引後移一位:(_front+1)% N N
    具體程式如下:
class Empty(Exception):
    def __init__(self, m):
        super().__init__(self)
        self.message = m

    def __str__(self):
        return self.message


class ArrayQueue:
    DEFAULT_CAPACITY = 10

    def __init__(self):
        self._data = [None] * self.DEFAULT_CAPACITY
        self._size = 0
        self._front = 0

    def __len__(self):
        return self._size

    def is_empty(self):
        return self._size == 0

    def first(self):
        if self.is_empty():
            raise Empty('Queue is empty')
        return self._data[self._front]

    def dequeue(self):
        if self.is_empty():
            raise Empty('Queue is empty')

        data = self._data[self._front]
        self._data[self._front] = None
        self._front = (self._front + 1) % len(self._data)
        self._size -= 1
        return data

    def enqueue(self, e):
        if self._size == len(self._data):
            self._resize(2 * len(self._data))

        index = (self._front + self._size) % len(self._data)
        self._data[index] = e
        self._size += 1

    def _resize(self, cap):
        old = self._data
        self._data = [None] * cap
        walk = self._front
        for k in range(self._size):
            self._data[k] = old[walk]
            walk = (walk + 1) % len(old)
        self._front = 0

測試程式:

from ArrayQueue import *

Q = ArrayQueue()
try:
    print(Q.is_empty())
    Q.enqueue(0)
    Q.enqueue(1)
    print(Q.first())
    print(len(Q))
    print(Q.dequeue())
    print(Q.dequeue())
    Q.dequeue()
    Q.enqueue(1)
except Empty as e:
    print(e)

測試結果:
程式結果
以上程式碼中,_resize()方法是對列表的擴充套件,當然我們也可以新增一些程式碼,使其當儲存元素降低到陣列總儲存能力的四分之一的時候,列表容量縮小到當前的一半。(和之前Python列表實現棧一樣)

if self._size <= len(self._data)/4
	self._resize(len(self._data)//2)

最後總結一下Python列表實現的佇列的效率:

操作 執行時間
Q.enqueue(e) Q ( 1 ) Q(1)^*
Q.dequeue() Q ( 1 ) Q(1)^*
Q.first() Q ( 1 ) Q(1)
Q.is_empty() Q ( 1 ) Q(1)
len(Q) O ( 1 ) O(1)

* 攤銷

以上是Python列表實現的佇列,如有錯誤,歡迎指教