Python數(shù)據(jù)結(jié)構(gòu)與算法17:基本結(jié)構(gòu):雙端隊(duì)列及其應(yīng)用

:本文如涉及到代碼,均經(jīng)過(guò)Python 3.7實(shí)際運(yùn)行檢驗(yàn),保證其嚴(yán)謹(jǐn)性。

本文閱讀時(shí)間約為5分鐘。

雙端隊(duì)列Deque

雙端隊(duì)列(Deque)是一種有次序的數(shù)據(jù)集,跟隊(duì)列相似,其兩端可以稱作“首”、“尾”端,但deque中數(shù)據(jù)項(xiàng)既可以從隊(duì)首加入,也可以從隊(duì)尾加入,同時(shí)數(shù)據(jù)項(xiàng)也可以從兩端移除。

某種意義上說(shuō),雙端隊(duì)列集成了棧和隊(duì)列的能力。但是,雙端隊(duì)列并不具有內(nèi)在的后進(jìn)先出(LIFO)或先進(jìn)先出(FIFO)的特性。如果要用雙端隊(duì)列來(lái)模擬棧或隊(duì)列,那么需要使用者自行維護(hù)操作的一致性。

雙端隊(duì)列的Python實(shí)現(xiàn)及操作

跟棧、隊(duì)列一樣,我們選擇使用Python的列表來(lái)實(shí)現(xiàn)雙端隊(duì)列。
代碼如下:

# deque.py

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)

注意,上述代碼對(duì)雙端隊(duì)列的實(shí)現(xiàn)是:列表的隊(duì)首是雙端隊(duì)列的隊(duì)尾,列表的隊(duì)尾是雙端隊(duì)列的隊(duì)首,即list[0]是雙端隊(duì)列的隊(duì)尾,list[-1]是雙端隊(duì)列的隊(duì)首。

上述操作的時(shí)間復(fù)雜度:

addFront/removeFront——O(1)。

addRear/removeRear——O(n)。

雙端隊(duì)列(deque)的操作如下:

  • Deque()——?jiǎng)?chuàng)建一個(gè)空雙端隊(duì)列。
  • .addFront(item)——將item加入隊(duì)首。
  • .addRear(item)——將item加入隊(duì)尾。
  • .removeFront()——從隊(duì)首移除數(shù)據(jù)項(xiàng),返回值為移除的數(shù)據(jù)項(xiàng)。
  • .removeRear()——從隊(duì)尾移除數(shù)據(jù)項(xiàng),返回值為移除的數(shù)據(jù)項(xiàng)。
  • .isEmpty()——返回deque是否為空的布爾值。
  • .size()——返回deque中包含數(shù)據(jù)項(xiàng)的個(gè)數(shù)。
  • .items——以列表形式返回deque中所有元素。

操作的代碼示例如下:

# deque.py

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)

d = Deque()

d.isEmpty()
Out[12]: True

d.addRear(4)

d.addRear('dog')

d.addFront('cat')

d.items  #查看雙端隊(duì)列d中的所有元素。
Out[17]: ['dog', 4, 'cat']

d.addFront(True)

d.items
Out[19]: ['dog', 4, 'cat', True]

d.isEmpty()
Out[20]: False

d.size()
Out[21]: 4

d.addRear(8.4)

d.removeRear()
Out[23]: 8.4

d.removeFront()
Out[24]: True

d.items
Out[25]: ['dog', 4, 'cat']
雙端隊(duì)列示意圖
雙端隊(duì)列的應(yīng)用:句子回文結(jié)構(gòu)的判定

對(duì)句子回文結(jié)構(gòu)的判定是雙端隊(duì)列的一個(gè)典型應(yīng)用。

這里回文結(jié)構(gòu)指的是一個(gè)字符串是對(duì)稱的,該字符串從左到右讀和從右到左讀是完全一樣的。有一句很出名的回文結(jié)構(gòu)的句子,'able was i ere i saw elba',傳言是拿破侖說(shuō)的,翻譯成中文意思是"看到Elba島之前我無(wú)所不能",Elba島是拿破侖最后一次戰(zhàn)敗后被流放的一個(gè)小島,而且最后他死在了Elba島。

回文結(jié)構(gòu)的句子例子還有很多,比如'radar'、'madam'、'toot'、'山東落花生花落東山'、'上海自來(lái)水來(lái)自海上'、北京輸油管油輸京北'等。

回文結(jié)構(gòu)的特殊性使得雙端隊(duì)列很容易對(duì)其進(jìn)行處理。分兩步解決回文結(jié)構(gòu)的判定:

第一步,將需要判定的回文結(jié)構(gòu)的字符串按順序提取出來(lái)加入到雙端隊(duì)列中。

第二步,同時(shí)從兩端移除單個(gè)字符,看其是否相同,直到雙端隊(duì)列中剩下的字符串的長(zhǎng)度為0或1。字符串的長(zhǎng)度為奇數(shù)還是偶數(shù),不影響對(duì)其回文結(jié)構(gòu)的判定。

具體判定的代碼如下:

# deque.py

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)

def palchecker(aString):
    chardeque = Deque()  # 新建一個(gè)雙端隊(duì)列。
    
    # 將需要判定的回文結(jié)構(gòu)的字符串按順序提取出來(lái)加入到雙端隊(duì)列中
    for ch in aString:
        chardeque.addRear(ch)
        
    stillEqual = True
    
    # 同時(shí)從兩端移除單個(gè)字符,看其是否相同,直到雙端隊(duì)列中剩下的字符串的長(zhǎng)度為0或1。
    while chardeque.size() > 1 and stillEqual:
        first = chardeque.removeFront()
        last = chardeque.removeRear()
        if first != last:
            stillEqual = False
    
    return stillEqual

print(palchecker('lsfdfa'))
print(palchecker('abbccbba'))        

<<<
False
True
<<<

To be continued.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容