Python数据结构学习笔记——树和图
目录
- 一、树的概念
- 二、二叉树的实现
- (一)列表的列表
- (二)结点与引用
- 三、图的概念
- 四、图的实现
- (一)邻接矩阵
- (二)邻接表
一、树的概念
树是一种数据结构,树由结点及连接结点的边组成,每个树有且只有一个根结点
,除了根结点以外,其它每个结点都与其有唯一的父结点相连,其中根结点到其它每个结点也有且只有一条路径。
1、二叉树
若树中每个节点最多有两个子结点
,则称为二叉树,即每个结点的子结点不超过两个,由根结点分叉的两个结点中,左边称为左子树,右边称为右子树,如下图:
2、满二叉树
若一个深度
为k
的树,具有2k-1个结点
,则称该树为满二叉树,如下图该树的深度为k=3,其结点数为2k-1=23-1=7个:
而如下图这两个树都不是满二叉树:
3、完全二叉树
若一个深度
为k
的树,其结点
为n
个,对树中的结点按从上到下、从左到右的顺序进行编号,当每一个结点都与同样深度为k的满二叉树中的结点一一对应
时,则称该树为完全二叉树。
完全二叉树中,从根节点至倒数第二层满足满二叉树,其最后一层的结点可以不完全填满,可以说若一棵二叉树是满二叉树时,则它一定是完全二叉树,如下图这两个树都是完全二叉树,但它们不是满二叉树:
4、完满二叉树
无子结点的结点
称为叶子结点,若一个树的非叶子结点的结点数都为2,即都有两个子结点时,则称这个树为完满二叉树,如下图:
二、二叉树的实现
二叉树的python代码实现有两种方法,第一种称作“列表的列表”的形式,也就是列表的反复嵌套,第二种称作“结点与引用”,通过设置一个类。
(一)列表的列表
1、二叉树的结点实现和输出
在Python中,我们可以通过“列表的列表
”这种方式来实现树的python代码,即列表的多层嵌套,例如下面这个树的实现python代码:
Tree = ["1", ["2", ["4", [], []], ["5", [], []]], ["3", [], []]]
我们可以通过列表的索引和切片来输出树中的结点,如下代码:
Tree = ["1", ["2", ["4", [], []], ["5", [], []]], ["3", [], []]]
print(Tree[0]) # 输出根结点
print(Tree[1]) # 输出该树的左子树
print(Tree[2]) # 输出该树的右子树
print(Tree[1][0])
print(Tree[1][1])
print(Tree[1][1][0])
print(Tree[1][2][0])
print(Tree[1][1][1])
print(Tree[2:])
运行结果如下:
2、二叉树的创建
二叉树的创建通过创建一个列表,由于二叉树由根结点和左子树和右子树组成,一开始将左右子树定义为空列表,即根结点
为r
,左右子树
此时都为[]
。
定义一个函数BinaryTree()用于创建一个二叉树,如下代码:
def BinaryTree(r):return [r, [], []] # 返回二叉树
3、左右子树的结点添加
我们要向已经创建好的二叉树中添加左右子树(左右子树中的结点),所以要先获取当前的左或右子树对应的列表(可能为空),然后将新的左或右子树添加进去,从而实现在二叉树的任何位置实现结点添加。
定义两个函数insertLeft()与insertRight()分别用于左右子树的结点添加,如下代码:
def insertLeft(root, newBranch): # 新建一个左子树,将其作为当前结点的左子结点t = root.pop(1) # pop()函数用于删除列表中指定元素if len(t) > 1:root.insert(1, [newBranch, t, []]) # insert()函数用于将元素插入到列表的指定位置else:root.insert(1, [newBranch, [], []])return rootdef insertRight(root, newBranch): # 新建一个右子树,将其作为当前结点的右子结点t = root.pop(2) # pop()函数用于删除列表中指定元素if len(t) > 1:root.insert(2, [newBranch, [], t]) # insert()函数用于将元素插入到列表的指定位置else:root.insert(2, [newBranch, [], []])return root
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,以及空的左右子树,代码如下:
# 创建一个树BinaryTree类
class BinaryTree:# 定义一个构造方法用于创建新的结点,参数rootObj作为此时的根结点def __init__(self, rootObj):self.key = rootObj # 根结点self.leftChild = None # 此时左子树为空self.rightChild = None # 此时右子树为空
2、左右子树的结点添加
左右子树的结点添加要考虑两种情况,一是向无子结点的结点下添加,二是向已有子结点的结点下添加,如下以左结点添加为例:
在类下定义两个方法,insertLeft()和insertRight()分别用于添加左/右结点,都含有一个参数newNode用于接收结点,其代码实现如下:
# 插入左结点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 = t
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
如下是一个二叉树,通过程序实现:
代码如下:
tree = BinaryTree(1)
print(tree.getRootVal())
print(tree.getLeftChild())
tree.insertLeft(2)
tree.insertRight(3)
print(tree.getLeftChild().getRootVal())
print(tree.getRightChild().getRootVal())
tree.insertLeft(4)
tree.insertRight(5)
print(tree.getLeftChild().getRootVal())
print(tree.getRightChild().getRootVal())
tree.insertLeft(6)
print(tree.getLeftChild().getRootVal())
运行结果如下:
三、图的概念
图是一种数据结构,前面所讲的树其实就是一种特殊的图,图的两个顶点之间通过一条边
来使其联系,这里的边可以是单向或双向
,若一个图中所有的边都为单向,则称整个图为有向图
,如下(其中边上的数字代表权重):
1、图的定义和权重
图定义为G =(V,E)
,其中V是一个顶点集合
,E是一个边集合
,每一条边都是一个二元组(v,w),且v,w∈V,可以向边的二元组中再添加一个元素,用于表示权重
,即从图上一个顶点到另一个顶点所需的成本,若一个有向图带有权重,则称为带权有向图
。
例如,上图的带权有向图可以通过两个集合来描述该图:
V = {a, b, c, d, e, f}
E = {(a, f, 1), (f, e, 2), (e, d, 2), (b, a, 1), (b, c, 3), (c, d, 5), (c, g, 4), (g, a, 2)}
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实现代码 四.有序链表 实现步骤分析 五.有序链表的Python实现代码 结语 一.链表 链表中每一个元素都由为两部分构成:一是该 ...
- Python数据结构学习笔记——队列和双端队列
目录 一.队列的定义 二.队列 实现步骤分析 三.队列的Python实现代码 四.队列的应用 六人传土豆游戏 五.双端队列的定义 六.双端队列 实现步骤分析 七.双端队列的Python实现代码 八.双 ...
- Python数据结构学习笔记——栈
目录 一.栈的定义和特性 (一)栈的定义 (二)栈的反转特性 二.实现分析步骤 三.栈的Python实现代码 四.栈的应用 (一)匹配圆括号 (二)匹配符号 (三)模2除法(十进制转二进制) (四)进 ...
- 考研数据结构学习笔记.树的常考性质
树的常考性质 树作为重要的数据结构,通常在操作系统,算法等领域起着重要的作用.其特殊性质需要我们了解并且运用,在考研中他们通常会以选择题的形式出现,我们需要熟练掌握并且能够准确地计算. 一.结点数 = ...
- python数据结构学习笔记(五)
5 Array-Based Sequence 5.2.1 referential arrays 5.2.2 compact arrays in python array.array 5.3 dynam ...
- Python数据结构学习笔记——搜索与排序算法
目录 一.搜索 (一)搜索的方法 (二)顺序搜索 (三)二分搜索 二.排序 内排序和外排序 (一)冒泡排序 (二)选择排序 (三)插入排序 (四)希尔排序 (五)归并排序 (六)快速排序 总结 一.搜 ...
- 408数据结构学习笔记-树-①树的逻辑结构
目录 ①定义 ②结点间的关系描述 ③结点路径 ④结点,树的属性描述 ⑤有序树和无序树 ⑥森林 ⑦树的性质(6个性质) a.结点数=总度数+1 b.度为m的树和m叉树的区别 c.度为m的树第i层至多有 ...
- 数据结构学习笔记(3-5):树
附录:所有blog的链接 数据结构学习笔记(1):基本概念 数据结构学习笔记(2):线性结构 数据结构学习笔记(3-5):树 数据结构学习笔记(6-8):图 数据结构学习笔记(9-10):排序 数据结 ...
- 数据结构学习笔记:利用Python列表实现栈结构
数据结构学习笔记:利用Python列表实现栈结构 利用Python列表实现栈结构.有两种实现方式: 1.将列表的末尾(rear)作为栈顶(top) 2.将列表的前端(front)作为栈顶(top) 一 ...
最新文章
- SAP QM物料主数据里QM Material Authorization Group字段
- Java中变量、类初始化顺序
- ios LOL 英雄联盟 英雄头像展示
- 条件运算符(?:)和 $替代string.Format()
- java web 断点上传_使用WebUploader实现分片断点上传文件功能(二)
- 不染计算机演奏教程,全国计算机等级考试一级教程-第1章 计算机基础知识 .pdf...
- java 用户、角色、权限数据库设计
- 宠物医院app开发的功能有哪些?
- MATLAB中基于GUI的噪声抑制imnoise,medfilt2命令
- 抖音初始权重快速提升3大攻略,新人必看丨国仁网络资讯
- Prometheus邮件报警设置
- Error launching IEDA-启动IDEA报错解决(创建JVM失败提示)
- 香港理工大学计算机科学专业,香港理工大学计算机系包括哪些专业
- 有道云笔记迁移到Obsidian的方法(保留文件创建时间)
- 云南省2021年计算机二级,云南省2021年上半年计算机报考简章
- 错过这次,再等一年!视频云CDN全线折扣Hi购启动...
- 删除iphone4通讯录里的所有联系人
- Coin3d环境搭建(VS2019+QT),实现基于Open Inventor机器人图形交互
- 国科大学习资料--模式识别与机器学习(黄庆明)--2016期末考试题(含答案)
- 自己的故事自己讲--富士康之旅