數據結構——線性結構(列表、棧、隊列)


一、列表/數組

  列表(其他語言稱數組)是一種基本數據結構。

1、列表的元素是如何存儲的?

  c的數組和python的列表有兩點不同:

  (1)數組元素類型要相同,列表元素類型可以不一樣。

    python存的不是真實的值而是存的內存地址。

    32位機器上一個地址占4個字節,64位機器上一個地址占用8個字節。

  (2)數組長度固定,python是長度不夠了就自動開新的內存地址,把原來的內容拷過來。

2、列表基本操作時間復雜度?

  append:不考慮python做得復制操作,大概是O(1)

  insert:時間復雜度是O(n),在插入后,后面的元素都要往后挪動。

  pop\remove:pop最后一個是O(1),寫了參數則是O(n),前面的刪了后,后面的都要往前挪。

二、棧(Stack)

1、棧的定義和特點

  棧的定義:棧是一個數據集合,可以理解為只能在一端進行插入或刪除操作的列表。

  棧的特點:后進先出(last-in,first-out), 簡稱LIFO表。類似一摞書:

  

2、棧的概念和基本操作

  棧的概念:

    棧頂:允許插入和刪除的這一端稱為棧頂。

    棧底:另外固定的這一端稱為棧底。

    空棧:不含任何元素的棧稱為空棧。

  棧的基本操作:

    進棧(壓棧):push

    出棧:pop

    取棧頂:gettop(查看棧頂元素,但不取走)  li[-1]

  

3、棧的python實現

  使用一般的列表結構即可實現棧:

    • 進棧:li.append
    • 出棧:li.pop
    • 取棧頂:li[-1]    
class Stack:
    """棧"""
    def __init__(self):
        self.stack = []

    def push(self, element):
        self.stack.append(element)

    def pop(self):
        if len(self.stack) > 0:
            return self.stack.pop()
        else:
            print("棧已經空了")

    def get_top(self):
        if len(self.stack) > 0:  # 判斷棧是否為空
            return self.stack[-1]
        else:
            return None


stack = Stack()
stack.push(1)
stack.push(2)
stack.push(6)
print(stack.pop())   # 6

  更簡單的方式實現棧的方法:創建一個列表,只使用append和pop方法進行操作。

4、棧的應用——括號匹配問題

  括號匹配問題:給一個字符串,其中包含小括號、中括號、大括號,求該字符串中的括號是否匹配。

  例如:

()()[]{}      匹配
([{()}])      匹配
[](             不匹配
[(])            不匹配

  代碼實現如下所示:

class Stack:
    """棧"""
    def __init__(self):
        self.stack = []

    def push(self, element):
        self.stack.append(element)

    def pop(self):
        if len(self.stack) > 0:
            return self.stack.pop()
        else:
            print("棧已經空了")

    def get_top(self):
        if len(self.stack) > 0:  # 判斷棧是否為空
            return self.stack[-1]
        else:
            return None

    def is_empty(self):
        """判斷是否為空"""
        return len(self.stack) == 0


def brace_match(s):
    """括號匹配"""
    match = {'}':'{', ']':'[', ')':'('}    # 右括號為鍵,左括號為值
    stack = Stack()
    for ch in s:   # 獲取一個個字符
        if ch in {'(','[','{'}:
            stack.push(ch)
        else:   # ch in {')',']','}'}
            if stack.is_empty():  # 如果棧為空
                return False
            elif stack.get_top() == match[ch]:
                stack.pop()
            else:   # stack.get_top() != match[ch]
                return False

    if stack.is_empty():  # 如果棧是空的了
        return True
    else:
        return False

print(brace_match('(){}[{()}]'))     # True
print(brace_match('(){}[{[(])}]'))   # False

三、隊列(Queue)

1、隊列概念

  隊列是一個數據集合,僅允許在列表的一端進行插入,另一端進行刪除

  進行插入的一端稱為隊尾(rear),插入動作稱為進隊或入隊

  進行刪除的一端稱為隊頭(front),刪除動作稱為出隊

  隊列的性質:先進先出(First-in,First-out)

  

2、思考隊列能否用列表簡單實現?

  初步設想:列表+兩個下標指針;創建一個列表和兩個變量,front變量指向隊首,rear變量指向隊尾。初始時,front和rear都為0。

  進隊操作:元素寫到li[rear]的位置,rear自增1。

  出隊操作:返回li[front]的元素,front自減1。

  

  這種實現方式不好,在一次次增減中,前面的大量內存空間都被浪費了。

3、隊列的實現方式——環形隊列

  

實現方式:取余數運算

注意:隊滿狀態下還空着一個位子,之所以不填上,是為了防止不能判別出來隊到底是空的還是滿的。

  環形隊列:當隊尾指針front == Maxsize - 1時,再前進一個位置就自動到0。

  • 隊首指針前進1:front = (front + 1) % MaxSize
  • 隊尾指針前進1:rear = (rear + 1) % MaxSize
  • 隊空條件:rear == front
  • 隊滿條件:(rear + 1) % MaxSize == front

4、隊列代碼實現

class Queue:
    """隊列"""
    def __init__(self, size=100):
        self.queue = [0 for _ in range(size)]   # 創建固定長的列表作為隊列
        self.size = size
        self.rear = 0    # 隊尾指針
        self.front = 0   # 隊首指針

    def push(self, element):
        """進隊"""
        if not self.is_filled():
            self.rear = (self.rear + 1) % self.size    # 隊尾指針前進一
            self.queue[self.rear] = element            # 添加元素
        else:
            raise IndexError("Queue is filled")

    def pop(self,):
        """出隊"""
        if not self.is_empty():
            self.front = (self.front + 1) % self.size  # 隊首指針前進1
            return self.queue[self.front]              # 返回新的front值
        else:
            raise IndexError("Queue is empty")  # 隊列為空拋出錯誤

    def is_empty(self):
        """判斷隊空"""
        return self.rear == self.front    # 隊空條件:rear == front

    def is_filled(self):
        """判斷隊滿"""
        return (self.rear + 1) % self.size == self.front   # 隊滿條件:(rear + 1) % MaxSize == front


q = Queue(5)
for i in range(4):
    q.push(i)

print(q.is_filled())   # True
print(q.pop())    # 0
q.push(3)
print(q)   # <__main__.Queue object at 0x10401ae48>

5、雙向隊列

  雙向隊列的兩端都支持進隊和出隊操作。

  雙向隊列的基本操作:隊首進隊/隊首出隊、隊尾進隊/隊尾出隊。

  

6、python隊列內置模塊

  之前學習過的queue是用來保證線程安全的,使用方法:from collections import deque,在collections中有一些數據結構,其中就包含了deque(雙向隊列)。

  • 創建隊列:queue = deque(li)
  • 進隊:append
  • 出隊:popleft
  • 雙向隊列隊首進隊:appendleft
  • 雙向隊列隊尾進隊:pop
from collections import deque

"""
deque([iterable[, maxlen]])   
    參數:列表、最大隊列
"""
# q = deque()  # 創建隊列
q = deque([1,2,3], 5)
q.append(1)    # 隊尾進隊
print(q.popleft())  # 1    隊首出隊


# 用於雙向隊列
q.appendleft(1)   # 隊首進隊
q.pop()    # 隊尾出隊

  可以使用這個內置模塊來模擬一個linux系統的tail命令來讀取文件的最后幾行:

from collections import deque

def tail(n):
    with open('test.txt', 'r') as f:
        q = deque(f, n)
        return q

for line in tail(5):
    print(line, end='')
"""
23e234
2342352
dfe232
dwwdwewew
wedwewf
"""

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM