1. 程式人生 > >使用python實現陣列、連結串列、佇列、棧

使用python實現陣列、連結串列、佇列、棧

引言

什麼是資料結構?

  1. 資料結構是指相互之間存在著一種或多種關係的資料元素的集合和該集合中資料元素之間的關係組成。
  2. 簡單來說,資料結構就是設計資料以何種方式組織並存儲在計算機中。
  3. 比如:列表,集合和字典等都是資料結構
  4. N.Wirth:“程式=資料結構+演算法”

資料結構按照其邏輯結構可分為線性結構、樹結構、圖結構

  1. 線性結構:資料結構中的元素存在一對一的互相關係。
  2. 樹結構:資料結構中的元素存在一對多的互相關係。
  3. 圖結構:資料結構中的元素存在多對多的互相關係。

陣列

在python中是沒有陣列的,有的是列表,它是一種基本的資料結構型別。

實現

class Array(object):
    def __init__(self, size=32):
        """
        :param size: 長度
        """
        self._size = size
        self._items = [None] * size

    # 在執行array[key]時執行
    def __getitem__(self, index):
        return self._items[index]

    # 在執行array[key] = value 時執行
    def __setitem__(self, index, value):
        self._items[index] = value

    # 在執行len(array) 時執行
    def __len__(self):
        return self._size
    
    # 清空陣列
    def clear(self, value=None):
        for i in range(len(self._items)):
            self._items[i] = value

    # 在遍歷時執行
    def __iter__(self):
        for item in self._items:
            yield item

使用

a = Array(4)
a[0] = 1
print(a[0]) # 1

a.clear()    
print(a[0]) # None

a[0] = 1
a[1] = 2
a[3] = 4
for i in a:
    print(i) # 1, 2, None, 4

連結串列

連結串列中每一個元素都是一個物件,每一個物件被稱為節點,包含有資料域value和指向下一個節點的指標next。

通過各個節點直接的相互連結,最終串成一個連結串列。

實現

class Node(object):
    def __init__(self, value=None, next=None):
        self.value, self.next = value, next


class LinkedList(object):
    def __init__(self, size=None):
        """
        :param size: int or None, 如果None,則該連結串列可以無限擴充
        """
        self.size = size
        # 定義一個根節點
        self.root = Node()
        # 尾節點始終指向最後一個節點
        self.tail_node = None
        self.length = 0

    def __len__(self):
        return self.length

    def append(self, value):
        # size 不為 None, 且長度大於等於size則連結串列已滿
        if self.size and len(self) >= self.size:
            raise Exception("LinkedList is full")
        # 構建節點
        node = Node(value)
        tail_node = self.tail_node
        # 判斷尾節點是否為空
        if tail_node is None:
            # 還沒有 append 過,length = 0, 追加到 root 後
            self.root.next = node
        else:
            # 否則追加到最後一個節點的後邊,並更新最後一個節點是 append 的節點
            tail_node.next = node
        # 把尾節點指向node
        self.tail_node = node
        # 長度加一
        self.length += 1

    # 往左邊新增
    def append_left(self, value):
        if self.size and len(self) >= self.size:
            raise Exception("LinkedList is full")
        # 構建節點
        node = Node(value)
        # 連結串列為空,則直接新增設定
        if self.tail_node is None:
            self.tail_node = node

        # 設定頭節點為根節點的下一個節點
        head_node = self.root.next
        # 把根節點的下一個節點指向node
        self.root.next = node
        # 把node的下一個節點指向原頭節點
        node.next = head_node
        # 長度加一
        self.length += 1

    # 遍歷節點
    def iter_node(self):
        # 第一個節點
        current_node = self.root.next
        # 不是尾節點就一直遍歷
        while current_node is not self.tail_node:
            yield current_node
            # 移動到下一個節點
            current_node = current_node.next
        # 尾節點
        if current_node is not None:
            yield current_node

    # 實現遍歷方法
    def __iter__(self):
        for node in self.iter_node():
            yield node.value

    # 刪除指定元素
    def remove(self, value):
        # 刪除一個值為value的節點,只要使該節點的前一個節點的next指向該節點的下一個
        # 定義上一個節點
        perv_node = self.root
        # 遍歷連結串列
        for current_node in self.iter_node():
            if current_node.value == value:
                # 把上一個節點的next指向當前節點的下一個節點
                perv_node.next = current_node.next
                # 判斷當前節點是否是尾節點
                if current_node is self.tail_node:
                    # 更新尾節點 tail_node
                    # 如果第一個節點就找到了,把尾節點設為空
                    if perv_node is self.root:
                        self.tail_node = None
                    else:
                        self.tail_node = perv_node
                # 刪除節點,長度減一,刪除成功返回1
                del current_node
                self.length -= 1
                return 1
            else:
                perv_node = current_node
        # 沒找到返回-1
        return -1

    # 查詢元素,找到返回下標,沒找到返回-1
    def find(self, value):
        index = 0
        # 遍歷連結串列,找到返回index,沒找到返回-1
        for node in self.iter_node():
            if node.value == value:
                return index
            index += 1
        return -1

    # 刪除第一個節點
    def popleft(self):
        # 連結串列為空
        if self.root.next is None:
            raise Exception("pop from empty LinkedList")
        # 找到第一個節點
        head_node = self.root.next
        # 把根節點的下一個節點,指向第一個節點的下一個節點
        self.root.next = head_node.next
        # 獲取刪除節點的value
        value = head_node.value
        # 如果第一個節點是尾節點, 則把尾節點設為None
        if head_node is self.tail_node:
            self.tail_node = None

        # 長度減一,刪除節點,返回該節點的值
        self.length -= 1
        del head_node
        return value

    # 清空連結串列
    def clear(self):
        for node in self.iter_node():
            del node
        self.root.next = None
        self.tail_node = None
        self.length = 0

    # 反轉連結串列
    def reverse(self):
        # 第一個節點為當前節點,並把尾節點指向當前節點
        current_node = self.root.next
        self.tail_node = current_node
        perv_node = None

        while current_node:
            # 下一個節點
            next_node = current_node.next
            # 當前節點的下一個節點指向perv_node
            current_node.next = perv_node

            # 當前節點的下一個節點為空,則把根節點的next指向當前節點
            if next_node is None:
                self.root.next = current_node

            # 把當前節點賦值給perv_node
            perv_node = current_node
            # 把下一個節點賦值為當前節點
            current_node = next_node

使用

ll = LinkedList()

ll.append(0)
ll.append(1)
ll.append(2)
ll.append(3)
print(len(ll)) # 4
print(ll.find(2)) # 2
print(ll.find(-1)) # -1

ll.clear()
print(len(ll)) # 0
print(list(ll)) # []

迴圈連結串列

雙鏈表中每一個節點有兩個指標,一個指向後面節點、一個指向前面節點。

迴圈連結串列實現

class Node(object):
    def __init__(self, value=None, prev=None, next=None):
        self.value = value
        self.prev = prev
        self.next = next


class CircularDoubleLinkedList(object):
    """
    雙向迴圈連結串列
    """

    def __init__(self, maxsize=None):
        self.maxsize = maxsize
        node = Node()
        node.prev = node
        node.next = node
        self.root = node
        self.length = 0

    def __len__(self):
        return self.length

    def head_node(self):
        return self.root.next

    def tail_node(self):
        return self.root.prev

    # 遍歷
    def iter_node(self):
        if self.root.next is self.root:
            return
        current_node = self.root.next
        while current_node.next is not self.root:
            yield current_node
            current_node = current_node.next
        yield current_node

    def __iter__(self):
        for node in self.iter_node():
            yield node.value

    # 反序遍歷
    def iter_node_reverse(self):
        if self.root.prev is self.root:
            return
        current_node = self.root.prev
        while current_node.prev is not self.root:
            yield current_node
            current_node = current_node.prev
        yield current_node

    def append(self, value):
        if self.maxsize is not None and len(self) >= self.maxsize:
            raise Exception("LinkedList is full")
        node = Node(value)
        tail_node = self.tail_node() or self.root
        tail_node.next = node
        node.prev = tail_node
        node.next = self.root
        self.root.prev = node
        self.length += 1

    def append_left(self, value):
        if self.maxsize is not None and len(self) >= self.maxsize:
            raise Exception("LinkedList is full")
        node = Node(value)
        if self.root.next is self.root:
            self.root.next = node
            node.prev = self.root
            node.next = self.root
            self.root.prev = node
        else:
            node.next = self.root.next
            self.root.next.prev = node
            self.root.next = node
            node.prev = self.root
        self.length += 1

    def remove(self, node):
        if node is self.root:
            return
        node.next.prev = node.prev
        node.prev.next = node.next
        self.length -= 1
        return node

迴圈連結串列的使用

dll = CircularDoubleLinkedList()

dll.append(0)
dll.append(1)
dll.append(2)

assert list(dll) == [0, 1, 2]
print(list(dll)) # [0, 1, 2]

print([node.value for node in dll.iter_node()]) # [0, 1, 2]
print([node.value for node in dll.iter_node_reverse()]) # [2, 1, 0]

headnode = dll.head_node()
print(headnode.value) # 0
dll.remove(headnode)
print(len(dll)) # 2

佇列

佇列(Queue)是一個數據集合,僅允許在列表的一端進行插入,另一端進行刪除。

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

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

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

基於陣列實現環形佇列

class Array(object):
    def __init__(self, size=32):
        """
        :param size: 長度
        """
        self._size = size
        self._items = [None] * size

    # 在執行array[key]時執行
    def __getitem__(self, index):
        return self._items[index]

    # 在執行array[key] = value 時執行
    def __setitem__(self, index, value):
        self._items[index] = value

    # 在執行len(array) 時執行
    def __len__(self):
        return self._size
    
    # 清空陣列
    def clear(self, value=None):
        for i in range(len(self._items)):
            self._items[i] = value

    # 在遍歷時執行
    def __iter__(self):
        for item in self._items:
            yield item


class ArrayQueue(object):
    def __init__(self, maxsize):
        self.maxsize = maxsize
        self.array = Array(maxsize)
        self.head = 0
        self.tail = 0

    def __len__(self):
        return self.head - self.tail

    # 入隊
    def push(self, value):
        if len(self) >= self.maxsize:
            raise Exception("Queue is full")
        self.array[self.head % self.maxsize] = value
        self.head += 1

    # 出隊
    def pop(self):
        value = self.array[self.tail % self.maxsize]
        self.tail += 1
        return value

使用

size = 5
q = ArrayQueue(size)
for i in range(size):
    q.push(i)

print(len(q)) # 5

print(q.pop()) # 0
print(q.pop()) # 1

雙向佇列

兩端都可以進行插入,刪除。

基於雙向連結串列實現雙向佇列

class Node(object):
    def __init__(self, value=None, prev=None, next=None):
        self.value = value
        self.prev = prev
        self.next = next


class CircularDoubleLinkedList(object):
    """
    雙向迴圈連結串列
    """

    def __init__(self, maxsize=None):
        self.maxsize = maxsize
        node = Node()
        node.prev = node
        node.next = node
        self.root = node
        self.length = 0

    def __len__(self):
        return self.length

    def head_node(self):
        return self.root.next

    def tail_node(self):
        return self.root.prev

    # 遍歷
    def iter_node(self):
        if self.root.next is self.root:
            return
        current_node = self.root.next
        while current_node.next is not self.root:
            yield current_node
            current_node = current_node.next
        yield current_node

    def __iter__(self):
        for node in self.iter_node():
            yield node.value

    # 反序遍歷
    def iter_node_reverse(self):
        if self.root.prev is self.root:
            return
        current_node = self.root.prev
        while current_node.prev is not self.root:
            yield current_node
            current_node = current_node.prev
        yield current_node

    def append(self, value):
        if self.maxsize is not None and len(self) >= self.maxsize:
            raise Exception("LinkedList is full")
        node = Node(value)
        tail_node = self.tail_node() or self.root
        tail_node.next = node
        node.prev = tail_node
        node.next = self.root
        self.root.prev = node
        self.length += 1

    def append_left(self, value):
        if self.maxsize is not None and len(self) >= self.maxsize:
            raise Exception("LinkedList is full")
        node = Node(value)
        if self.root.next is self.root:
            self.root.next = node
            node.prev = self.root
            node.next = self.root
            self.root.prev = node
        else:
            node.next = self.root.next
            self.root.next.prev = node
            self.root.next = node
            node.prev = self.root
        self.length += 1

    def remove(self, node):
        if node is self.root:
            return
        node.next.prev = node.prev
        node.prev.next = node.next
        self.length -= 1
        return node


# 雙向佇列
class Deque(CircularDoubleLinkedList):
    # 從右邊出隊
    def pop(self):
        if len(self) <= 0:
            raise Exception("stark is empty!")
        tail_node = self.tail_node()
        value = tail_node.value
        self.remove(tail_node)
        return value

    # 從左邊出隊
    def popleft(self):
        if len(self) <= 0:
            raise Exception("stark is empty!")
        head_node = self.head_node()
        value = head_node.value
        self.remove(head_node)
        return value

雙向佇列的使用

dq = Deque()
dq.append(1)
dq.append(2)
print(list(dq)) # [1, 2]

dq.appendleft(0)
print(list(dq)) # [0, 1, 2]

dq.pop()
print(list(dq)) # [0, 1]

dq.popleft()
print(list(dq)) # [1]

dq.pop()
print(len(dq)) # 0

棧(Stack)是一個數據集合,可以理解為只能在一端插入或刪除操作的連結串列。

棧的特點:後進先出(Last-in, First-out)

棧的概念:

  1. 棧頂
  2. 棧底

棧的基本操作:

  1. 進棧(壓棧):push
  2. 出棧:pop

基於雙向佇列實現

class Node(object):
    def __init__(self, value=None, prev=None, next=None):
        self.value = value
        self.prev = prev
        self.next = next


class CircularDoubleLinkedList(object):
    """
    雙向迴圈連結串列
    """
    def __init__(self, maxsize=None):
        self.maxsize = maxsize
        node = Node()
        node.prev = node
        node.next = node
        self.root = node
        self.length = 0

    def __len__(self):
        return self.length

    def head_node(self):
        return self.root.next

    def tail_node(self):
        return self.root.prev

    # 遍歷
    def iter_node(self):
        if self.root.next is self.root:
            return
        current_node = self.root.next
        while current_node.next is not self.root:
            yield current_node
            current_node = current_node.next
        yield current_node

    def __iter__(self):
        for node in self.iter_node():
            yield node.value

    # 反序遍歷
    def iter_node_reverse(self):
        if self.root.prev is self.root:
            return
        current_node = self.root.prev
        while current_node.prev is not self.root:
            yield current_node
            current_node = current_node.prev
        yield current_node

    def append(self, value):
        if self.maxsize is not None and len(self) >= self.maxsize:
            raise Exception("LinkedList is full")
        node = Node(value)
        tail_node = self.tail_node() or self.root
        tail_node.next = node
        node.prev = tail_node
        node.next = self.root
        self.root.prev = node
        self.length += 1

    def append_left(self, value):
        if self.maxsize is not None and len(self) >= self.maxsize:
            raise Exception("LinkedList is full")
        node = Node(value)
        if self.root.next is self.root:
            self.root.next = node
            node.prev = self.root
            node.next = self.root
            self.root.prev = node
        else:
            node.next = self.root.next
            self.root.next.prev = node
            self.root.next = node
            node.prev = self.root
        self.length += 1

    def remove(self, node):
        if node is self.root:
            return
        node.next.prev = node.prev
        node.prev.next = node.next
        self.length -= 1
        return node


class Deque(CircularDoubleLinkedList):
    def pop(self):
        if len(self) <= 0:
            raise Exception("stark is empty!")
        tail_node = self.tail_node()
        value = tail_node.value
        self.remove(tail_node)
        return value

    def popleft(self):
        if len(self) <= 0:
            raise Exception("stark is empty!")
        head_node = self.head_node()
        value = head_node.value
        self.remove(head_node)
        return value


class Stack(object):
    def __init__(self):
        self.deque = Deque() 
    
    # 壓棧
    def push(self, value):
        self.deque.append(value)

    # 出棧
    def pop(self):
        return self.deque.pop()

使用

s = Stack()
s.push(0)
s.push(1)
s.push(2)

print(s.pop()) # 2
print(s.pop()) # 1
print(s.pop()) # 0

~>.<~