資料結構、python實現
1.資料結構:線性表和連結串列、堆疊和佇列、樹和二叉樹、圖、字典和集合、B樹、雜湊表
連結串列
1)含義:連結串列(Linked list)是一種常見的基礎資料結構,是一種線性表,但是並不會按線性的順序儲存資料,而是在每一個節點裡存到下一個節點的指標(Pointer)。由於不必須按順序儲存,連結串列在插入的時候可以達到O(1)的複雜度,比另一種線性表順序錶快得多,但是查詢一個節點或者訪問特定編號的節點則需要O(n)的時間,而順序表相應的時間複雜度分別是O(logn)和O(1)
2)特點:使用連結串列結構可以克服陣列連結串列需要預先知道資料大小的缺點,連結串列結構可以充分利用計算機記憶體空間,實現靈活的記憶體動態管理。但是連結串列失去了陣列隨機讀取的優點,同時連結串列由於增加了結點的指標域,空間開銷比較大
3)操作:
is_empty() 連結串列是否為空 length() 連結串列長度 travel() 遍歷連結串列 add(item) 連結串列頭部新增 append(item) 連結串列尾部新增 insert(pos, item) 指定位置新增 remove(item) 刪除節點 search(item) 查詢節點是否存在 # -*- coding: utf-8 -*-
# -*- coding: utf-8 -*- class Node(object): """雙向連結串列節點""" def __init__(self, item): self.item = item self.next = None self.prev = None class DLinkList(object): """雙向連結串列""" def __init__(self): self._head = None def is_empty(self): """判斷連結串列是否為空""" return self._head == None def length(self): """返回連結串列的長度""" cur = self._head count = 0 while cur != None: count += 1 cur = cur.next return count def travel(self): """遍歷連結串列""" cur = self._head while cur != None: print cur.item cur = cur.next def add(self, item): """頭部插入元素""" node = Node(item) if self.is_empty(): # 如果是空連結串列,將_head指向node self._head = node else: # 將node的next指向_head的頭節點 node.next = self._head # 將_head的頭節點的prev指向node self._head.prev = node # 將_head 指向node self._head = node def append(self, item): """尾部插入元素""" node = Node(item) if self.is_empty(): # 如果是空連結串列,將_head指向node self._head = node else: # 移動到連結串列尾部 cur = self._head while cur.next != None: cur = cur.next # 將尾節點cur的next指向node cur.next = node # 將node的prev指向cur node.prev = cur def search(self, item): """查詢元素是否存在""" cur = self._head while cur != None: if cur.item == item: return True cur = cur.next return False def insert(self, pos, item): """在指定位置新增節點""" if pos <= 0: self.add(item) elif pos > (self.length()-1): self.append(item) else: node = Node(item) cur = self._head count = 0 # 移動到指定位置的前一個位置 while count < (pos-1): count += 1 cur = cur.next # 將node的prev指向cur node.prev = cur # 將node的next指向cur的下一個節點 node.next = cur.next # 將cur的下一個節點的prev指向node cur.next.prev = node # 將cur的next指向node cur.next = node def remove(self, item): """刪除元素""" if self.is_empty(): return else: cur = self._head if cur.item == item: # 如果首節點的元素即是要刪除的元素 if cur.next == None: # 如果連結串列只有這一個節點 self._head = None else: # 將第二個節點的prev設定為None cur.next.prev = None # 將_head指向第二個節點 self._head = cur.next return while cur != None: if cur.item == item: # 將cur的前一個節點的next指向cur的後一個節點 cur.prev.next = cur.next # 將cur的後一個節點的prev指向cur的前一個節點 cur.next.prev = cur.prev break cur = cur.next ll = DLinkList() ll.add(1) ll.add(2) ll.append(3) ll.insert(2, 4) ll.insert(4, 5) ll.insert(0, 6) print '----------------1-----------------' print "length:",ll.length() print '----------------2-----------------' ll.travel() print '----------------3-----------------' print ll.search(3) print ll.search(4) print '----------------4-----------------' ll.remove(1) print "length:",ll.length() print '----------------5-----------------' ll.travel()
4)輸出:
堆疊
1.含義:堆疊(英語:stack),也可直接稱棧,在電腦科學中,是一種特殊的串列形式的資料結構,它的特殊之處在於只能允許在連結串列或陣列的一端(稱為堆疊頂端指標,英語:top)進行加入資料(英語:push)和輸出資料(英語:pop)的運算。另外堆疊也可以用一維陣列或連結串列的形式來完成。堆疊的另外一個相對的操作方式稱為佇列;由於堆疊資料結構只允許在一端進行操作,因而按照後進先出(LIFO, Last In First Out)的原理運作
2.特點:先入後出,後入先出;除頭尾節點之外,每個元素有一個前驅,一個後繼
3.操作:
is_empty:判斷棧是否為空 peek:返回棧頂元素 size:返回棧的大小 push:把新的元素堆進棧裡面 pop:把棧頂元素丟出去 # -*- coding: utf-8 -*-
class Stack(object):
__slots__ = ('__items') #限定Stack類的成員只有__items(類成員)
# 初始化棧為空列表
def __init__(self):
self.__items = []
# 判斷棧是否為空,返回布林值
def is_empty(self):
return self.__items == []
# 返回棧頂元素
def peek(self):
return self.__items[len(self.__items) - 1]
# 返回棧的大小
def size(self):
return len(self.__items)
# 把新的元素堆進棧裡面(程式設計師喜歡把這個過程叫做壓棧,入棧,進棧……)
def push(self, item):
self.__items.append(item)
# 把棧頂元素丟出去(程式設計師喜歡把這個過程叫做出棧……)
def pop(self):
return self.__items.pop()
# 初始化一個棧物件
my_stack = Stack()
# 把'h'丟進棧裡
my_stack.push('h')
# 把'a'丟進棧裡
my_stack.push('a')
# 看一下棧的大小(有幾個元素)
print my_stack.size()
# 列印棧頂元素
print my_stack.peek()
# 把棧頂元素丟出去,並打印出來
print my_stack.pop()
# 再看一下棧頂元素是誰
print my_stack.peek()
# 這個時候棧的大小是多少?
print my_stack.size()
# 再丟一個棧頂元素
print my_stack.pop()
# 看一下棧的大小
print my_stack.size
# 棧是不是空了?
print my_stack.is_empty()
4)輸出:
佇列
1)含義:和堆疊類似,唯一的區別是佇列只能在隊頭進行出隊操作,所以佇列是是先進先出(FIFO, First-In-First-Out)的線性表
2)特點:先入先出,後入後出;除尾節點外,每個節點有一個後繼;(可選)除頭節點外,每個節點有一個前驅
3)操作:
inqueue():一次入隊一個 many_in_queue():一次入隊多個 outqueue():出隊 show():顯示佇列 head():佇列的頭部 tail():佇列的尾部 isempty():判斷佇列是否為空 length():佇列長度 # -*- coding: utf-8 -*-
class queue(object):
def __init__(self):
self.queue = []
# 一次入隊一個
def inqueue(self,item):
self.queue.append(item)
# 一次入隊多個
def many_in_queue(self,*args):
self.queue.extend(args)
# 出隊
def outqueue(self):
if not self.queue == []:
self.queue.pop(0)
else:
return None
# 顯示佇列
def show(self):
for i in self.queue:
print i
# 佇列的頭部
def head(self):
if not self.queue == [] :
print self.queue[0]
else :
return None
# 佇列的尾部
def tail(self):
if not self.queue == []:
print self.queue[-1]
else :
return None
# 是否為空
def isempty(self):
return self.queue == []
# 長度
def length(self):
print len(self.queue)
q1 = queue()
q1.inqueue(1)
q1.show()
print '----------1-----------'
q1.many_in_queue(3,4,5)
q1.show()
print '----------1-----------'
q1.outqueue()
q1.show()
print '----------1-----------'
q1.head()
print '----------1-----------'
q1.tail()
print '----------1-----------'
q1.length()
q1.isempty()
4)輸出:
二叉樹
1)定義:二叉樹是每個結點最多有兩個子樹的樹結構。它有五種基本形態:二叉樹可以是空集;根可以有空的左子樹或右子樹;或者左、右子樹皆為空
2)特點:性質1:二叉樹第i層上的結點數目最多為2i-1(i>=1);性質2:深度為k的二叉樹至多有2k-1個結點(k>=1);性質3:包含n個結點的二叉樹的高度至少為(log2n)+1;性質4:在任意一棵二叉樹中,若終端結點的個數為n0,度為2的結點數為n2,則n0=n2+1
3)操作
# -*- coding: utf-8 -*-
class Node(object):
def __init__(self,item):
self.item = item
self.child1 = None
self.child2 = None
class Tree(object):
def __init__(self):
self.root = None
def add(self, item):
node = Node(item)
if self.root is None:
self.root = node
else:
q = [self.root]
while True:
pop_node = q.pop(0)
if pop_node.child1 is None:
pop_node.child1 = node
return
elif pop_node.child2 is None:
pop_node.child2 = node
return
else:
q.append(pop_node.child1)
q.append(pop_node.child2)
def traverse(self): # 層次遍歷
if self.root is None:
return None
q = [self.root]
res = [self.root.item]
while q != []:
pop_node = q.pop(0)
if pop_node.child1 is not None:
q.append(pop_node.child1)
res.append(pop_node.child1.item)
if pop_node.child2 is not None:
q.append(pop_node.child2)
res.append(pop_node.child2.item)
return res
def preorder(self,root): # 先序遍歷
if root is None:
return []
result = [root.item]
left_item = self.preorder(root.child1)
right_item = self.preorder(root.child2)
return result + left_item + right_item
def inorder(self,root): # 中序序遍歷
if root is None:
return []
result = [root.item]
left_item = self.inorder(root.child1)
right_item = self.inorder(root.child2)
return left_item + result + right_item
def postorder(self,root): # 後序遍歷
if root is None:
return []
result = [root.item]
left_item = self.postorder(root.child1)
right_item = self.postorder(root.child2)
return left_item + right_item + result
t = Tree()
for i in range(10):
t.add(i)
print u'層序遍歷:',t.traverse()
print u'先序遍歷:',t.preorder(t.root)
print u'中序遍歷:',t.inorder(t.root)
print u'後序遍歷:',t.postorder(t.root)
4)輸出: