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

1、列表/數組

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

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

  c的數組和python的列表有兩點不一樣:linux

  (1)數組元素類型要相同,列表元素類型能夠不同。數組

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

    32位機器上一個地址佔4個字節,64位機器上一個地址佔用8個字節。數據結構

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

二、列表基本操做時間複雜度?

  append:不考慮python作得複製操做,大概是O(1)學習

  insert:時間複雜度是O(n),在插入後,後面的元素都要日後挪動。spa

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

2、棧(Stack)

一、棧的定義和特色

  棧的定義:棧是一個數據集合,能夠理解爲只能在一端進行插入或刪除操做的列表。指針

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

  

二、棧的概念和基本操做

  棧的概念:

    棧頂:容許插入和刪除的這一端稱爲棧頂。

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

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

  棧的基本操做:

    進棧(壓棧):push

    出棧:pop

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

  

三、棧的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方法進行操做。

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

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

  例如:

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

  代碼實現以下所示:

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

3、隊列(Queue)

一、隊列概念

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

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

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

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

  

二、思考隊列可否用列表簡單實現?

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

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

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

  

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

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

  

實現方式:取餘數運算

注意:隊滿狀態下還空着一個位子,之因此不填上,是爲了防止不能判別出來隊究竟是空的仍是滿的。

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

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

四、隊列代碼實現

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>

五、雙向隊列

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

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

  

六、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
"""
相關文章
相關標籤/搜索