目录

  • 一、树的概念
  • 二、二叉树的实现
    • (一)列表的列表
    • (二)结点与引用
  • 三、图的概念
  • 四、图的实现
    • (一)邻接矩阵
    • (二)邻接表

一、树的概念

是一种数据结构,树由结点及连接结点的边组成,每个树有且只有一个根结点,除了根结点以外,其它每个结点都与其有唯一的父结点相连,其中根结点到其它每个结点也有且只有一条路径。
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数据结构学习笔记——树和图相关推荐

  1. Python数据结构学习笔记——链表:无序链表和有序链表

    目录 一.链表 二.无序链表 实现步骤分析 三.无序链表的Python实现代码 四.有序链表 实现步骤分析 五.有序链表的Python实现代码 结语 一.链表 链表中每一个元素都由为两部分构成:一是该 ...

  2. Python数据结构学习笔记——队列和双端队列

    目录 一.队列的定义 二.队列 实现步骤分析 三.队列的Python实现代码 四.队列的应用 六人传土豆游戏 五.双端队列的定义 六.双端队列 实现步骤分析 七.双端队列的Python实现代码 八.双 ...

  3. Python数据结构学习笔记——栈

    目录 一.栈的定义和特性 (一)栈的定义 (二)栈的反转特性 二.实现分析步骤 三.栈的Python实现代码 四.栈的应用 (一)匹配圆括号 (二)匹配符号 (三)模2除法(十进制转二进制) (四)进 ...

  4. 考研数据结构学习笔记.树的常考性质

    树的常考性质 树作为重要的数据结构,通常在操作系统,算法等领域起着重要的作用.其特殊性质需要我们了解并且运用,在考研中他们通常会以选择题的形式出现,我们需要熟练掌握并且能够准确地计算. 一.结点数 = ...

  5. python数据结构学习笔记(五)

    5 Array-Based Sequence 5.2.1 referential arrays 5.2.2 compact arrays in python array.array 5.3 dynam ...

  6. Python数据结构学习笔记——搜索与排序算法

    目录 一.搜索 (一)搜索的方法 (二)顺序搜索 (三)二分搜索 二.排序 内排序和外排序 (一)冒泡排序 (二)选择排序 (三)插入排序 (四)希尔排序 (五)归并排序 (六)快速排序 总结 一.搜 ...

  7. 408数据结构学习笔记-树-①树的逻辑结构

    目录 ①定义 ②结点间的关系描述 ③结点路径 ④结点,树的属性描述 ⑤有序树和无序树 ⑥森林 ⑦树的性质(6个性质) a.结点数=总度数+1 b.度为m的树和m叉树的区别 c.度为m的树第i层至多有 ...

  8. 数据结构学习笔记(3-5):树

    附录:所有blog的链接 数据结构学习笔记(1):基本概念 数据结构学习笔记(2):线性结构 数据结构学习笔记(3-5):树 数据结构学习笔记(6-8):图 数据结构学习笔记(9-10):排序 数据结 ...

  9. 数据结构学习笔记:利用Python列表实现栈结构

    数据结构学习笔记:利用Python列表实现栈结构 利用Python列表实现栈结构.有两种实现方式: 1.将列表的末尾(rear)作为栈顶(top) 2.将列表的前端(front)作为栈顶(top) 一 ...

最新文章

  1. SAP QM物料主数据里QM Material Authorization Group字段
  2. Java中变量、类初始化顺序
  3. ios LOL 英雄联盟 英雄头像展示
  4. 条件运算符(?:)和 $替代string.Format()
  5. java web 断点上传_使用WebUploader实现分片断点上传文件功能(二)
  6. 不染计算机演奏教程,全国计算机等级考试一级教程-第1章 计算机基础知识 .pdf...
  7. java 用户、角色、权限数据库设计
  8. 宠物医院app开发的功能有哪些?
  9. MATLAB中基于GUI的噪声抑制imnoise,medfilt2命令
  10. 抖音初始权重快速提升3大攻略,新人必看丨国仁网络资讯
  11. Prometheus邮件报警设置
  12. Error launching IEDA-启动IDEA报错解决(创建JVM失败提示)
  13. 香港理工大学计算机科学专业,香港理工大学计算机系包括哪些专业
  14. 有道云笔记迁移到Obsidian的方法(保留文件创建时间)
  15. 云南省2021年计算机二级,云南省2021年上半年计算机报考简章
  16. 错过这次,再等一年!视频云CDN全线折扣Hi购启动...
  17. 删除iphone4通讯录里的所有联系人
  18. Coin3d环境搭建(VS2019+QT),实现基于Open Inventor机器人图形交互
  19. 国科大学习资料--模式识别与机器学习(黄庆明)--2016期末考试题(含答案)
  20. 自己的故事自己讲--富士康之旅

热门文章

  1. 再见,Navicat!这个IDEA的兄弟,真香!
  2. 这代码写的跟狗屎一样!怎么优化?
  3. Kafka主题中的分区数越多吞吐量就越高?BULLSHIT!!!
  4. Spring+Mybatis多数据源配置(二)——databaseIdProvider的使用
  5. 【大会】声音叫醒耳朵,语音连接网络
  6. UCloud裴志伟:最小价值模型,技术迭代与客户需求可以达成平衡
  7. 从根本上了解异步编程体系
  8. 去除git mergetool不产生*.orig文件
  9. 接口返回时间较长,如何提高响应速度?
  10. 马蜂窝数据仓库设计与实践