標籤:
python資料結構之線性表
python內建了很多進階資料結構,list,dict,tuple,string,set等,在使用的時候十分舒心。但是,如果從一個初學者的角度利用python學習資料結構時,這些進階的資料結構可能給我們以迷惑。比如,使用list實現queue的時候,入隊操作append()時間複雜度可以認為是O(1),但是,出隊操作pop(0)的時間複雜度就是O(n)。如果是想利用python學學資料結構的話,我覺得還是自己實現一遍基本的資料結構為好。
1.鏈表在這裡,我想使用類似於c語言鏈式儲存的形式,藉助於class,分別構成無序鏈表以及有序鏈表。我們先看看鏈表節點的定義:
class ListNode(object): def __init__(self, data): self.data = data self.next = None def getData(self): return self.data def setData(self, newData): self.data = newData def getNext(self): return self.next def setNext(self, nextNode): self.next = nextNode
利用鏈表節點,組成無序鏈表類:
class UnorderedList(object): def __init__(self): self.head = None def getHead(self): return self.head def isEmpty(self): return self.head is None def add(self, item): node = ListNode(item) node.next = self.head self.head = node # the head is the most recently added node def size(self): current = self.head count = 0 while current is not None: count += 1 current = current.getNext() return count def search(self, item): current = self.head found = False while current is not None and not found: if current.getData() == item: found = True else: current = current.getNext() return found def append(self, item): node = ListNode(item) if self.isEmpty(): self.head = node else: current = self.head while current.getNext() is not None: current = current.getNext() current.setNext(node) def remove(self, item): current = self.head previous = None found = False while not found: if current.getData() == item: found = True else: previous = current current = current.getNext() if previous is None: self.head = current.getNext() else: previous.setNext(current.getNext())
在上面的鏈表中,每次添加元素都直接添加在鏈表頭部,add()的時間複雜度為O(1),而append()操作在隊尾,其時間複雜度為O(n)。有沒有前後加入操作的時間複雜度都為O(1)的鏈表呢,當然是有的:
class UnorderedList(object): def __init__(self): self.head = None self.tail = None def getHead(self): return self.head def isEmpty(self): return self.head is None and self.tail is None def add(self, item): node = ListNode(item) if self.isEmpty(): self.head = self.tail = node else: node.next = self.head self.head = node # the head is the most recently added node def size(self): current = self.head count = 0 while current is not None: count += 1 current = current.getNext() return count def search(self, item): current = self.head found = False while current is not None and not found: if current.getData() == item: found = True else: current = current.getNext() return found def append(self, item): node = ListNode(item) self.tail.setNext(node) self.tail = node def remove(self, item): current = self.head previous = None found = False while not found: if current.getData() == item: found = True else: previous = current current = current.getNext() if current.getNext() is None: self.tail = previous if previous is None: self.head = current.getNext() else: previous.setNext(current.getNext())
對無序鏈表類加入一個屬性,引用鏈表末尾節點,即可。做出了這樣的改變,在add和remove操作也應作出相應變化。下面再看看有序鏈表。有序鏈表在插入節點的時候便尋找適合節點的位置。
class OrderedList(object): def __init__(self): self.head = None def isEmpty(self): return self.head is None def search(self, item): stop = False found = False current = self.head while current is not None and not found and not stop: if current.getData() > item: stop = True elif current.getData() == item: found = True else: current = current.getNext() return found def add(self, item): previous = None current = self.head stop = False while current is not None and not stop: if current.getData() >item: stop = True else: previous = current current = current.getNext() node = ListNode(item) if previous is None: node.getNext(current) self.head = node else: previous.setNext(node) node.setNext(current)
2.棧stack對於棧來說,python內建的列表已經可以滿足棧的要求。入棧操作為append(),出棧操作為pop()。它們的時間複雜度都為O(1).
class Stack(object): def __init__(self): self._items = [] def is_empty(self): return self._items == [] def push(self, item): self._items.append(item) def pop(self): return self._items.pop() def peek(self): return self._items[-1]
當然了,我們也可以自己實現鏈棧,跟鏈表的實作類別似。
class StackNode(object): """docstring for StackNode""" def __init__(self, value): self.value = value self.next = Noneclass Stack(object): """docstring for Stack""" def __init__(self, top=None): self.top = top def get_top(self): return self.top def is_empty(self): return self.top is None def push(self, val): if self.is_empty(): self.top = StackNode(val) return else: node = StackNode(val) node.next = self.top.next self.top = node return def pop(self): if self.is_empty(): print("Stack is Empty, cannot pop anymore.\n") return node = self.top self.top = self.top.next return node3.隊列queue隊列如果利用鏈表實現的話會,出現文章開頭提及的問題。所以隊列可以用鏈表實現。
class QueueNode(object): def __init__(self, value): self.value = value self.next = Noneclass Queue(object): def __init__(self): self.front = None self.rear = None def is_empty(self): return self.front is None and self.rear is None def enqueue(self, num): node = QueueNode(num) if self.is_empty(): self.front = node self.rear = node else: self.rear.next = node self.rear = node def dequeue(self): if self.front is self.rear: node = self.front self.front = None self.rear = None return node.value else: node = self.front self.front = node.next return node.value
在python的庫中,比如collections以及Queue中都有deque模組。deque模組顧名思義,可以做雙端隊列。所以,deque模組也可以做隊列,和棧。dq = deque([1,2,3,4,5,6,7,8,9])dq.pop() # pop 9 dq.popleft() #pop 1dq.apend(9) # append 9dq.appendleft(1) #insert 1 in index 0在多線程,多進程編程時,經常使用Queue模組的Queue類。其實:假設q = Queue.Queue() 那麼 q.queue就是一個deque。這個以後再談。
[筆記]python資料結構之線性表:linkedlist鏈表,stack棧,queue隊列