鏈表
(單鏈表 雙鏈表 循環鏈表)只是一個定義的結構而已 (數據結構不一樣而已)
具體的對這個定義的操作要到這個定義實現的類當中去調用而已
概念區分
-
頭結點:是爲了方便操作鏈表而附設的,頭結點數據域通常用來保存跟鏈表有關的信息,比如鏈表的長度;
-
首元結點:就是鏈表裏“正式”的第一個結點,即鏈表的開始結點。形如a1,a2,a3,…an;
-
頭指針:頭指針是指向鏈表的基地址。如果鏈表存在頭結點則頭指針就是指向頭結點的地址,反之指向首元結點的地址。
#定義節點類型
class Node(object):
def __init__(self,elem,next_=None):
self.elem=elem
self.next=next_
#定義單鏈表
class Linklist(object):
def __init__(self,none=None):
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.elem,end=" ")
cur =cur.next
#輸出一個換行
print('')
#首部加元素
def add(self,item):
#將數據轉換爲節點類型
node=Node(item)
#新的節點指向首元節點
node.next=self.head
#新的節點變成首元節點
self.head=node
#尾部加元素
def append(self,item):
node=Node(item)
#判斷是否爲空
if self.is_empty():
#爲空此節點就是首元節點
self.head=node
else:
cur=self.head
while cur.next!=None:
# 遍歷到最後一個節點
cur=cur.next
cur.next=node
#在指定位置添加節點
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.next=cur.next
cur.next=node
#刪除指定值的節點
def remove(self,item):
cur=self.head
pre=None
while cur != None:
if cur.elem==item:
#如果當前節點的值符合要求
if cur==self.head:
#如果符合的節點是首元節點
self.head=cur.next
break
else:
#從當前節點的前一個節點直接指向當前節點的下一個節點
pre.next=cur.next
break
else:
#當前節點不符合
pre=cur#記錄當前節點的位置
cur=cur.next
#查詢某個值是否存在
def search(self,item):
cur=self.head
while cur!=None:
if cur.elem==item:
return True
else:
cur=cur.next
return False
if __name__=='__main__':
linklist=Linklist()
for i in range(5):
linklist.append(i)
linklist.travel()
linklist.insert(3,7)
linklist.travel()
print(linklist.search(4))
linklist.remove(7)
linklist.travel()
棧
特點:插入和刪除操作只能在一個位置進行的表,該位置是表的末端,稱爲棧的頂(top)。
先進後出
具體操作
- Stack() 創建一個新的空棧
- push(item) 添加一個新的元素item到棧頂
- pop() 彈出棧頂元素
- peek() 返回棧頂元素
- is_empty() 判斷棧是否爲空
- size() 返回棧的元素個數
"""
Stack() 創建一個新的空棧
push(item) 添加一個新的元素item到棧頂
pop() 彈出棧頂元素
peek() 返回棧頂元素
is_empty() 判斷棧是否爲空
size() 返回棧的元素個數
"""
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):
if self.is_empty():
raise IndexError
self.items.pop()
#返回棧頂元素
def peek(self):
return self.items[self.size()-1]
#獲取棧長度
def size(self):
return len(self.items)
if __name__=='__main__':
stack=Stack()
for i in range(0,10):
stack.push(i)
print(stack.size())
print(stack.is_empty())
print(stack.peek())
stack.pop()
print(stack.peek())
隊列
特點:插入和刪除在不同的端進行。隊列的基本操作是Enqueue(入隊),在表的末端(rear)插入一個元素,還有出列(Dequeue),刪除表開頭的元素。
先進先出.
"""
Queue() 創建一個新的空棧
enqueue(item) 添加一個新的元素item到隊列底部
delqueue() 彈出隊首元素
is_empty() 判斷隊列是否爲空
size() 返回隊列的元素個數
"""
class Queue(object):
def __init__(self):
self.queues=[]
def is_empty(self):
return self.queues==[]
def enqueue(self,queue):
self.queues.append(queue)
def delqueue(self):
if self.is_empty():
raise IndexError
val=self.queues[0]
self.queues.remove(val)
return val
def size(self):
return len(self.queues)
if __name__=='__main__':
queue=Queue()
print(queue.is_empty())
for i in range(10):
queue.enqueue(i)
print(queue.size())
print(queue.delqueue())
print(queue.delqueue())
樹
(英語:tree)是一種抽象數據類型(ADT)或是實作這種抽象數據類型的數據結構,用來模擬具有樹狀結構性質的數據集合。它是由n(n>=1)個有限節點組成一個具有層次關係的集合。把它叫做“樹”是因爲它看起來像一棵倒掛的樹,也就是說它是根朝上,而葉朝下的。它具有以下的特點:
- 每個節點有零個或多個子節點;
- 沒有父節點的節點稱爲根節點;
- 每一個非根節點有且只有一個父節點;
- 除了根節點外,每個子節點可以分爲多個不相交的子樹;
樹的術語
- 節點的度:一個節點含有的子樹的個數稱爲該節點的度;
- 樹的度:一棵樹中,最大的節點的度稱爲樹的度;
- 葉節點或終端節點:度爲零的節點;
- 父親節點或父節點:若一個節點含有子節點,則這個節點稱爲其子節點的父節點;
- 孩子節點或子節點:一個節點含有的子樹的根節點稱爲該節點的子節點;
- 兄弟節點:具有相同父節點的節點互稱爲兄弟節點;
- 節點的層次:從根開始定義起,根爲第1層,根的子節點爲第2層,以此類推;
- 樹的高度或深度:樹中節點的最大層次;
- 堂兄弟節點:父節點在同一層的節點互爲堂兄弟;
- 節點的祖先:從根到該節點所經分支上的所有節點;
- 子孫:以某節點爲根的子樹中任一節點都稱爲該節點的子孫。
- 森林:由m(m>=0)棵互不相交的樹的集合稱爲森林;
樹的種類
- 無序樹:樹中任意節點的子節點之間沒有順序關係,這種樹稱爲無序樹,也稱爲自由樹;
- 有序樹:樹中任意節點的子節點之間有順序關係,這種樹稱爲有序樹;
- 二叉樹:每個節點最多含有兩個子樹的樹稱爲二叉樹;
- 完全二叉樹:對於一顆二叉樹,假設其深度爲d(d>1)。除了第d層外,其它各層的節點數目均已達最大值,且第d層所有節點從左向右連續地緊密排列,這樣的二叉樹被稱爲完全二叉樹x
- 滿二叉樹:所有分支節點的度都是2
- 平衡二叉樹(AVL樹):當且僅當任何節點的兩棵子樹的高度差不大於1的二叉樹;
- 排序二叉樹(二叉查找樹(英語:Binary Search Tree),也稱二叉搜索樹、有序二叉樹);
- 霍夫曼樹(用於信息編碼):帶權路徑最短的二叉樹稱爲哈夫曼樹或最優二叉樹;
- B樹:一種對讀寫操作進行優化的自平衡的二叉查找樹,能夠保持數據有序,擁有多餘兩個子樹。
樹的存儲與表示
順序存儲:將數據結構存儲在固定的數組中,然在遍歷速度上有一定的優勢,但因所佔空間比較大,是非主流二叉樹。二叉樹通常以鏈式存儲。
常見的一些樹的應用場景
- xml,html等,那麼編寫這些東西的解析器的時候,不可避免用到樹
- 路由協議就是使用了樹的算法
- mysql數據庫索引
- 文件系統的目錄結構
- 所以很多經典的AI算法其實都是樹搜索,此外機器學習中的decision tree也是樹結構
#定義樹的節點
class Node(object):
def __init__(self,item):
self.elem=item
self.lchild=None
self.rchild=None
#定義樹
class Tree():
def __init__(self):
self.root=None
#添加樹
def add(self,item):
node=Node(item)
if self.root==None:
#如果根節點爲空
self.root=node
else:
queue=[]
queue.append(self.root)
while queue:
cur_node=queue.pop(0)
#取出列表第一個元素額
if cur_node.lchild is None:
cur_node.lchild=node
return
else:
#如果當前節點的左子樹不爲空將其添加至列表中
queue.append(cur_node.lchild)
if cur_node.rchild is None:
cur_node.rchild =node
return
else:
queue.append(cur_node.rchild)
#廣度遍歷非遞歸
def breadth_travel(self):
if self.root==None:
return
queue=[]
queue.append(self.root)
while queue:
node=queue.pop(0)
print(node.elem,end=' ')
if node.lchild!=None:
queue.append(node.lchild)
if node.rchild!=None:
queue.append(node.rchild)
print('')
def breadth_travel_two(self):
if self.root==None:
return
queue=[]
queue.append(self.root)
while queue:
length=len(queue)
for i in range(length):
node=queue.pop(0)
print(node.elem,end=' ')
if node.lchild != None:
queue.append(node.lchild)
if node.rchild != None:
queue.append(node.rchild)
print('')
#深度遍歷 非遞歸 前序遍歷 根 左 右
def deep_travel_qianxu(self):
if self.root==None:
return
queue=[]
queue.append(self.root)
while queue:
cur=queue.pop()
print(cur.elem,end=' ')
#前序遍歷 根 左 右
#先放入右節點再放入作節點
if cur.rchild is not None:
queue.append(cur.rchild)
if cur.lchild is not None:
queue.append(cur.lchild)
print('')
#左根右
"""
1. 使用一個棧保存結點(列表實現);
2. 如果結點存在,入棧,然後將當前指針指向左子樹,直到爲空;
3. 當前結點不存在,則出棧棧頂元素,並把當前指針指向棧頂元素的右子樹;
4. 棧不爲空,循環2、3。
"""
def deep_travel_zhongxu(self):
if not self.root:
return
stack = []
cur=self.root
while cur or stack:
#將當前節點的左節點都入棧
while cur:
stack.append(cur)
cur = cur.lchild
# 獲取當前最左節點
if stack:
a = stack.pop()
cur = a.rchild
print(a.elem,end=' ')
print('')
#左 右 根
def deep_travel_houxu(self):
cur=self.root
stack = [cur]
stack2 = []
while len(stack) > 0:
cur = stack.pop()
stack2.append(cur)
if cur.lchild:
stack.append(cur.lchild)
if cur.rchild:
stack.append(cur.rchild)
while len(stack2) > 0:
node = stack2.pop()
print(node.elem,end=' ')
print('')
#深度遍歷遞歸
def preorder(self, node):
# 先序遍歷 根 左 右
if node == None:
return
print(node.elem, end=" ")
self.preorder(node.lchild)
self.preorder(node.rchild)
def inorder(self, node):
# 中序遍歷 左 根 右
if node == None:
return
self.inorder(node.lchild)
print(node.elem, end=" ")
self.inorder(node.rchild)
def proorder(self, node):
# 後序遍歷 左 右 根
if node == None:
return
self.inorder(node.lchild)
self.inorder(node.rchild)
print(node.elem, end=" ")
if __name__=='__main__':
tree=Tree()
for i in range(7):
tree.add(i)
tree.breadth_travel_two()
print("*"*20)
tree.deep_travel_qianxu()
print("*" * 20)
tree.deep_travel_zhongxu()
print("*"*20)
tree.deep_travel_houxu()