Python数据结构学习笔记——树和图
目錄
- 一、樹的概念
- 二、二叉樹的實現
- (一)列表的列表
- (二)結點與引用
- 三、圖的概念
- 四、圖的實現
- (一)鄰接矩陣
- (二)鄰接表
一、樹的概念
樹是一種數據結構,樹由結點及連接結點的邊組成,每個樹有且只有一個根結點,除了根結點以外,其它每個結點都與其有唯一的父結點相連,其中根結點到其它每個結點也有且只有一條路徑。
1、二叉樹
若樹中每個節點最多有兩個子結點,則稱為二叉樹,即每個結點的子結點不超過兩個,由根結點分叉的兩個結點中,左邊稱為左子樹,右邊稱為右子樹,如下圖:
2、滿二叉樹
若一個深度為k的樹,具有2k-1個結點,則稱該樹為滿二叉樹,如下圖該樹的深度為k=3,其結點數為2k-1=23-1=7個:
而如下圖這兩個樹都不是滿二叉樹:
3、完全二叉樹
若一個深度為k的樹,其結點為n個,對樹中的結點按從上到下、從左到右的順序進行編號,當每一個結點都與同樣深度為k的滿二叉樹中的結點一一對應時,則稱該樹為完全二叉樹。
完全二叉樹中,從根節點至倒數第二層滿足滿二叉樹,其最后一層的結點可以不完全填滿,可以說若一棵二叉樹是滿二叉樹時,則它一定是完全二叉樹,如下圖這兩個樹都是完全二叉樹,但它們不是滿二叉樹:
4、完滿二叉樹
無子結點的結點稱為葉子結點,若一個樹的非葉子結點的結點數都為2,即都有兩個子結點時,則稱這個樹為完滿二叉樹,如下圖:
二、二叉樹的實現
二叉樹的python代碼實現有兩種方法,第一種稱作“列表的列表”的形式,也就是列表的反復嵌套,第二種稱作“結點與引用”,通過設置一個類。
(一)列表的列表
1、二叉樹的結點實現和輸出
在Python中,我們可以通過“列表的列表”這種方式來實現樹的python代碼,即列表的多層嵌套,例如下面這個樹的實現python代碼:
我們可以通過列表的索引和切片來輸出樹中的結點,如下代碼:
運行結果如下:
2、二叉樹的創建
二叉樹的創建通過創建一個列表,由于二叉樹由根結點和左子樹和右子樹組成,一開始將左右子樹定義為空列表,即根結點為r,左右子樹此時都為[]。
定義一個函數BinaryTree()用于創建一個二叉樹,如下代碼:
3、左右子樹的結點添加
我們要向已經創建好的二叉樹中添加左右子樹(左右子樹中的結點),所以要先獲取當前的左或右子樹對應的列表(可能為空),然后將新的左或右子樹添加進去,從而實現在二叉樹的任何位置實現結點添加。
定義兩個函數insertLeft()與insertRight()分別用于左右子樹的結點添加,如下代碼:
4、另外定義幾個函數用于返回二叉樹以及結點存儲的對象,getRootVal()函數給出參數root從而返回當前結點存儲的對象;setRootVal()函數給出參數root和newVal在當前結點存儲參數newVal的對象;getLeftChild()和getRightChild()函數給出參數root用于返回當前結點的左/右結點所對應的子二叉樹,如下代碼:
def getRootVal(root): # 返回當前結點存儲的對象return root[0]def setRootVal(root, newVal): # 在當前結點中存儲參數newVal的對象root[0] = newValdef getLeftChild(root): # 返回當前結點的左子結點所對應的子二叉樹return root[1]def getRightChild(root): # 返回當前結點的右子結點所對應的子二叉樹return root[2](二)結點與引用
另外一種對樹的定義方法是通過定義一個類,類中含有根結點以及左右子樹的屬性,如下圖:
1、BinaryTree類的創建
通過創建一個BinaryTree類作為樹的初始化,其中包括根結點rootObj,以及空的左右子樹,代碼如下:
2、左右子樹的結點添加
左右子樹的結點添加要考慮兩種情況,一是向無子結點的結點下添加,二是向已有子結點的結點下添加,如下以左結點添加為例:
在類下定義兩個方法,insertLeft()和insertRight()分別用于添加左/右結點,都含有一個參數newNode用于接收結點,其代碼實現如下:
3、另外定義幾個函數用于返回二叉樹以及結點存儲的對象,getRootVal()函數返回當前結點存儲的對象;setRootVal()函數給出參數obj用于在當前結點存儲對象;getLeftChild()和getRightChild()函數給出參數用于返回當前結點的左/右結點所對應的子二叉樹,如下代碼:
def getRightChild(self):return self.rightChilddef getLeftChild(self):return self.leftChilddef setRootVal(self, obj):self.key = objdef getRootVal(self):return self.key程序的完整代碼如下:
# 創建一個樹BinaryTree類 class BinaryTree:# 定義一個構造方法用于創建新的結點,參數rootObj作為此時的根結點def __init__(self, rootObj):self.key = rootObj # 根結點self.leftChild = None # 此時左子樹為空self.rightChild = None # 此時右子樹為空# 插入左結點def insertLeft(self, newNode):if self.leftChild is None: # 無左結點時self.leftChild = BinaryTree(newNode)else:t = BinaryTree(newNode) # 實例化對象,創建新的結點t.left = self.leftChildself.leftChild = t# 插入右結點def insertRight(self, newNode):if self.rightChild is None: # 無右結點時self.rightChild = BinaryTree(newNode)else:t = BinaryTree(newNode) # 實例化對象,創建新的結點t.left = self.rightChildself.rightChild = tdef getRightChild(self):return self.rightChilddef getLeftChild(self):return self.leftChilddef setRootVal(self, obj):self.key = objdef getRootVal(self):return self.key如下是一個二叉樹,通過程序實現:
代碼如下:
運行結果如下:
三、圖的概念
圖是一種數據結構,前面所講的樹其實就是一種特殊的圖,圖的兩個頂點之間通過一條邊來使其聯系,這里的邊可以是單向或雙向,若一個圖中所有的邊都為單向,則稱整個圖為有向圖,如下(其中邊上的數字代表權重):
1、圖的定義和權重
圖定義為G =(V,E),其中V是一個頂點集合,E是一個邊集合,每一條邊都是一個二元組(v,w),且v,w∈V,可以向邊的二元組中再添加一個元素,用于表示權重,即從圖上一個頂點到另一個頂點所需的成本,若一個有向圖帶有權重,則稱為帶權有向圖。
例如,上圖的帶權有向圖可以通過兩個集合來描述該圖:
2、路徑
路徑是由邊連接的頂點組成的序列,不帶權重的圖的路徑長度是路徑上的邊數,帶權重的圖的路徑長度是路徑上邊的權重之和,例如上圖中,從c到a的路徑是頂點序列(c,g,a),其相對應的邊是{(c, g, 4), (g, a, 2)},如下:
3、環
環是有向圖中的一條起點和終點為同一個頂點的路徑,比如下圖的路徑(a,b,c,d,e,f,a)就是一個環。
若一個圖沒有環,則稱為無環圖,沒有環的有向圖稱為有向無環圖,也稱為DAG,例如前面的這個圖就是一個DAG:
四、圖的實現
圖的實現有兩種常用的方法實現,分別是鄰接矩陣和鄰接表,鄰接矩陣適合有很多邊的圖,而鄰接表適合稀疏連接的圖。
(一)鄰接矩陣
通過鄰接矩陣實現圖,具體步驟是通過一個二維矩陣表示,其中的數字代表頂點到頂點的權重,如下:
(二)鄰接表
具體代碼如下:
class Vertex:def __init__(self, key):self.id = keyself.connectedTo = {}def addNeighbor(self, nbr, weight=0):self.connectedTo[nbr] = weightdef __str__(self):return str(self.id) + ' connectedTo: ' + str([x.id for x in self.connectedTo])def getConnections(self):return self.connectedTo.keys()def getId(self):return self.iddef getWeight(self, nbr):return self.connectedTo[nbr]class Graph:def __init__(self):self.vertList = {}self.numVertices = 0def addVertex(self, key):self.numVertices = self.numVertices + 1newVertex = Vertex(key)self.vertList[key] = newVertexreturn newVertexdef getVertex(self, n):if n in self.vertList:return self.vertList[n]else:return Nonedef __contains__(self, n):return n in self.vertListdef addEdge(self, f, t, cost=0):if f not in self.vertList:nv = self.addVertex(f)if t not in self.vertList:nv = self.addVertex(t)self.vertList[f].addNeighbor(self.vertList[t], cost)def getVertices(self):return self.vertList.keys()def __iter__(self):return iter(self.vertList.values())g = Graph() for i in range(7):g.addVertex(i) g.addEdge("a", "f", 1) g.addEdge("f", "e", 2) g.addEdge("e", "d", 2) g.addEdge("b", "a", 1) g.addEdge("b", "c", 3) g.addEdge("c", "d", 5) g.addEdge("c", "g", 4) g.addEdge("g", "a", 2) for v in g:for w in v.getConnections():print("( %s , %s )" % (v.getId(), w.getId()))運行結果如下:
總結
以上是生活随笔為你收集整理的Python数据结构学习笔记——树和图的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python数据结构学习笔记——搜索与排
- 下一篇: Python绘制三维散点图