上次我们介绍了线性的数据结构,数组,链表,栈,队列,这次我们来看看非线性的数据结构。

非线性的数据结构主要是:树(Tree),图(Graph),堆(Heap),散列表(Hash)

树(Tree)

谈到树,先给大家看幅图:

上图就是一个简单的家谱图,这就是一个简单的树。在数据结构中,树的定义是:它是由n(n>0)个有限节点组成一个具有层次关系的集合。

就像上图一样,家谱中的每个人都是一个节点,每个节点又可以再生出其他节点。作为树,应该包含下面几个特点:

1、家谱中都有应该最原始的祖先,也就是这个家中的第一人(即每个树都有固定的根节点

2、家谱中的每个人都可以有自己的孩子或者不生孩子(即每个节点都只有有限个子节点或者没有子节点

3、每个人在家谱中都只有唯一的父母(非根结点只有唯一的一个父节点

4、家谱中的每个人都可以组成自己的家庭,他们都是自己家庭里最有辈分的那个人(树中的每个非根节点,都可以有自己的子树,例如上图中的女儿和外孙女就可以构成一个子树)

5、家谱里的人不可以近亲结婚或者乱伦(树里面没有环路

以上便是数据结构中树的介绍,但是在常用的数据结构中,我们会经常使用一个特别的树————二叉树。二叉树是什么意思呢?就是树中的每个节点最多只能有两个孩子节点(换个说法就是在家谱里,你最多只能生个二胎,不能再生更多了!)

如上图,每个根节点最多只能有两个孩子节点,这就是二叉树,二叉树也有两个很特别的形式,一个叫满二叉树,也就是上图,每个节点都有两个孩子。另外一个叫完全二叉树,完全二叉树是什么意思呢?将所有节点按照上图进行编号,1-15,如果有新的树按照上面这样的形式编号,并且每个节点的编号都和上图的编号一样,这就是完全二叉树,(例如上图,我把L和M节点去掉,K以及之前的的编号都不变,N和O的编号变成了12,13,那N,O和之前的编号不一样了,所以他们就不是完全二叉树,如果把N和O节点去掉,我们发现因为他们是末尾的节点,根本不需要改变前面节点的编号,所以还是原来的编号,这就是完全二叉树)说白了就是,要么就全满,如果缺了,那后面就都不能再有了。

关于二叉树,我们可以使用什么物理结构来存储呢?链表和数组都是可以实现的。

下面我们来使用python代码来构建一个二叉树:

# 二叉树类
class BTree(object):# 初始化def __init__(self, data=None, left=None, right=None):self.data = data    # 数据域self.left = left    # 左子树self.right = right  # 右子树# 二叉树的高度def height(self):# 空的树高度为0, 只有root节点的树高度为1if self.data is None:return 0elif self.left is None and self.right is None:return 1elif self.left is None and self.right is not None:return 1 + self.right.height()elif self.left is not None and self.right is None:return 1 + self.left.height()else:return 1 + max(self.left.height(), self.right.height())# 二叉树的叶子节点def leaves(self):if self.data is None:return Noneelif self.left is None and self.right is None:print(self.data, end=' ')elif self.left is None and self.right is not None:self.right.leaves()elif self.right is None and self.left is not None:self.left.leaves()else:self.left.leaves()self.right.leaves()

这样我们也就初步构建好了一个二叉树,下面我们来聊聊,二叉树常见的几种遍历方式。遍历(遍历的意思就是沿着某条搜索路线,依次对节点进行访问)主要有两种方式,深度优先遍历广度优先遍历

深度优先遍历一共有三种,分别是前序、中序、后序遍历。

前序遍历:先输出根节点,再输出左子树,最后输出右子树。

对应上图的顺序是:ABDECFG

    # 前序遍历def preorder(self):if self.data is not None:print(self.data, end=' ')if self.left is not None:self.left.preorder()if self.right is not None:self.right.preorder()

中序遍历:先输出左子树,在输出根节点,最后输出右子树。

对应上图的顺序是:DBEAFCG

     # 中序遍历def inorder(self):if self.left is not None:self.left.inorder()if self.data is not None:print(self.data, end=' ')if self.right is not None:self.right.inorder()

后序遍历:先输出左子树,再输出右子树,最后输出根节点。

对应上图的顺序是:DEBFGCA

    # 后序遍历def postorder(self):if self.left is not None:self.left.postorder()if self.right is not None:self.right.postorder()if self.data is not None:print(self.data, end=' ')

除了深度优先遍历,还有广度优先遍历,层序遍历就是属于广度优先遍历。

层序遍历:比较简单,一层一层的遍历即可。当层遍历结束进入下一层

对应上图的顺序是:ABCDEFG

    # 层序遍历def levelorder(self):# 返回某个节点的左孩子def Left_Child_Of_Node(node):return node.left if node.left is not None else None# 返回某个节点的右孩子def Right_Child_Of_Node(node):return node.right if node.right is not None else None# 层序遍历列表level_order = []# 是否添加根节点中的数据if self.data is not None:level_order.append([self])# 二叉树的高度height = self.height()if height >= 1:# 对第二层及其以后的层数进行操作, 在level_order中添加节点而不是数据for _ in range(2, height + 1):level = []  # 该层的节点for node in level_order[-1]:# 如果左孩子非空,则添加左孩子if Left_Child_Of_Node(node):level.append(Left_Child_Of_Node(node))# 如果右孩子非空,则添加右孩子if Right_Child_Of_Node(node):level.append(Right_Child_Of_Node(node))# 如果该层非空,则添加该层if level:level_order.append(level)# 取出每层中的数据for i in range(0, height):  # 层数for index in range(len(level_order[i])):level_order[i][index] = level_order[i][index].datareturn level_order

堆(Heap)

堆的存储方式就是上面我们介绍的完全二叉树。堆主要分为最大堆和最小堆,这个很好区分,最大值都放在堆顶,且任何一个子节点的值都必须小于或者等于父节点的值,这就是最大堆。最小堆正好相反。(堆的根节点我们叫做堆顶)

堆的两个特性:

1、堆中某个节点的值总是不大于或不小于其父节点的值

2、堆总是一棵完全二叉树

堆里面也有特别的————二叉堆,二叉堆是一种特殊的堆,是一棵完全二叉树或者是近似完全二叉树,并且同时还满足堆的特性:父节点的键值总是保持固定的序关系于任何一个子节点的键值,且每个节点的左子树和右子树都是一个二叉堆。

如何去构建一个堆呢?我们看下图,用一个数组作为例子:

首先我们需要将数组构建成一个完全二叉树,之后我们将完全二叉树做成一个最大堆:

接下来呢,我们需要将无序的完全二叉树构建成有序的最大堆,操作的主要内容就是让所有的非叶子节点往下走,一直走到适合自己的位置。

下面我们使用Python代码来构建一个堆:

class BinHeap:def __init__(self):self.heapList = [0]self.currentSize = 0def up_adjust(self, i): # 二叉堆上浮操作while i // 2 > 0:if self.heapList[i] <= self.heapList[i // 2]:self.heapList[i], self.heapList[i // 2] = self.heapList[i // 2], self.heapList[i]i = i // 2def insert_value(self, k):self.heapList.append(k)self.currentSize = self.currentSize + 1self.up_adjust(self.currentSize)def down_adjust(self, i): # 二叉堆下沉操作while (i * 2) <= self.currentSize:mc = self.get_min_child(i)if self.heapList[i] > self.heapList[mc]:tmp = self.heapList[i]self.heapList[i] = self.heapList[mc]self.heapList[mc] = tmpi = mcdef get_min_child(self, i):# 获取最小值if i * 2 > self.currentSize:return i * 2else:if self.heapList[i * 2] < self.heapList[i * 2 + 1]:return i * 2else:return i * 2 + 1def del_min(self):# 删除最小值retval = self.heapList[1]self.heapList[1] = self.heapList[self.currentSize]self.currentSize = self.currentSize - 1self.heapList.pop()self.down_adjust(1)return retvaldef build_heap(self, array):# 构建堆i = len(array) // 2self.currentSize = len(array)self.heapList = [0] + array[:]while i > 0:self.down_adjust(i)i = i - 1为节点类,要具备一些常用的方法,获取节点数据,获取下个节点,更新节点的数据,更新下个节点,这些都可以定义在node类里面。

堆的主要用途就是实现堆排序和优先队列。

图(Graph)

图,也是一种非线性的数据结构,是数据结构中最强大的结构之一,树就属于图的一种。

在图的结构中,任意两个结点之间都可能相关,即结点之间的邻接关系是任意的。而在树形结构中,结点之间具有层次关系,每一层结点只能和上一层中的至多一个结点相关,但可能和下一层的多个结点相关。图的结构可以描述多种复杂的数据对象,应用较为广泛。图的结构非常多,例如:邻接矩阵、邻接表、十字链表和邻接多重表等。

在生活中,图的应用也是十分广泛的,下面两个例子就是最常用的图的思想:

图对我们来说,其实主要是一种思想,了解了图的思想之后,再选择对应的物理存储结构去解决问题。

# 图的一种:邻接矩阵
class Graph:def __init__(self, n_vertices):self._n_vertices = n_verticesself._adj = [[] for _ in range(n_vertices)]def add_edge(self, s, t):self._adj[s].append(t)

散列表(Hash)

散列表,又叫哈希表。它在python里面存在的主要形式就是字典了,根据key来查找对应value的值。通过计算key的函数,将需要查询的值映射到一个固定的位置。这个映射就是散列表。最常见的用途就是哈希函数,例如MD5,SHA1等。

哈希表的本质其实也是一个数组,和数组不同的是我们需要通过一些中间函数进行转换,转换过后取到对应的值。而这个中间函数就是哈希函数。

哈希表的更新,删除,取值对应的python种字典的对应操作:

谈到哈希表,我们有个问题就不得不说一下,那就是哈希冲突。

什么是哈希冲突呢?我们来看下图:

我们要在五个箱子内放六个球,每个箱子只能放入一个球。但我们发现,如果真的想把球都放进去,就必须要有一个箱子里面装两个,这就冲突了。那对于哈希表而言,也可能会出现这样的情况,当存储区域小于需要存储数据的时候,就会发生哈希冲突。

如何解决哈希冲突呢?我们右两种办法:链表法和开放寻址法。

链表法:哈希表的每个元素不仅是对象,也是一个链表的头节点,每个对象通过next指针指向下个对象节点,当新的元素进来产生冲突时,只需要将其插入到对应的链表中就OK了。

开放寻址法:当某个哈希值已经被占用的情况下,继续寻找下一个空着的位置。以此类推。直到找到空的为止。python里面的字典就是采用的该方法。

以上,便是非线性数据结构的python版本的介绍,欢迎大家「转发」「点赞」「在看」三连!“扫一扫,关注我吧”

Python带你了解数据结构【二】相关推荐

  1. ML之XGBoost:XGBoost参数调优的优秀外文翻译—《XGBoost中的参数调优完整指南(带python中的代码)》(二)

    ML之XGBoost:XGBoost参数调优的优秀外文翻译-<XGBoost中的参数调优完整指南(带python中的代码)>(二) 目录 2. xgboost参数/XGBoost Para ...

  2. 【天池龙珠计划】Python训练营 Task02 Python基础练习:数据结构大汇总

    [天池龙珠计划]Python训练营 Task02 Python基础练习:数据结构大汇总 文章目录 [天池龙珠计划]Python训练营 Task02 Python基础练习:数据结构大汇总 一.列表 1. ...

  3. python对财务人员的帮助-还不熟练VBA的财务人,让Python带你弯道超车!

    原标题:还不熟练VBA的财务人,让Python带你弯道超车! 相信做财务的同学肯定对VBA这门编程语言并不感到陌生. VBA可以帮助我们快速的处理大量的数据,一些复杂的逻辑或需要重复操作的处理也可以用 ...

  4. Algorithm:【Algorithm算法进阶之路】之数据结构二十多种算法演示

    Algorithm:[Algorithm算法进阶之路]之数据结构二十多种算法演示 目录 一.数据结构算法 1.顺序表 2.链表 3.栈和队列 4.串的模式匹配 5.稀疏矩阵 6.广义表 7.二叉树 8 ...

  5. Python中的高级数据结构详解

    这篇文章主要介绍了Python中的高级数据结构详解,本文讲解了Collection.Array.Heapq.Bisect.Weakref.Copy以及Pprint这些数据结构的用法,需要的朋友可以参考 ...

  6. 参数匹配模型——Python学习之参数(二)

    参数匹配模型--Python学习之参数(二) 文章目录 参数匹配模型--Python学习之参数(二) 位置参数:从左至右进行匹配 关键字参数:通过参数名进行匹配 默认参数:为没有传入值的参数定义参数值 ...

  7. Python基础概念_7_数据结构

    数据结构 8 数据结构 8.1简介 数据结构是什么?它是计算机存储.组织数据的方式.Python 中有常用的数据结构: 列表.元组.字典和集合. 8.2 列表 列表(list)是一种按顺序存储的数据结 ...

  8. Python机器视觉编程常用数据结构与示例

    Python机器视觉编程常用数据结构与示例 本文总结了使用Python进行机器视觉(图像处理)编程时常用的数据结构,主要包括以下内容: 数据结构 通用序列操作:索引(indexing).分片(slic ...

  9. python遍历树结构_python 数据结构与算法——树的遍历

    1.广度优先遍历 2.深度优先遍历 先序遍历:把根放在最前面 中序遍历:把根放在中间 后序遍历:把根放在后面 # -*- coding: utf-8 -*- """ Cr ...

最新文章

  1. 【camera】5.相机内嵌图像处理(ISP)介绍
  2. BZOJ 4665: 小w的喜糖
  3. Java多线程系列(五):线程池的实现原理、优点与风险、以及四种线程池实现
  4. 服务器winsxs文件夹怎么清理工具,winsxs,教您winsxs文件夹清理方法
  5. 云服务器的发展历程,盘点微软Azure云服务器的发展历程
  6. stauml工具怎么导入文件_小伙教大家怎么剪辑短视频,1小时就学会添加字幕,值得收藏哦...
  7. 392. 判断子序列(javascript)
  8. javascript中的原型
  9. 「小程序JAVA实战」小程序页面的上拉下拉刷新(50)
  10. java编程找异数,异类Outliers_又名异数Malcolm_Gladwell.pdf
  11. 勤哲excel服务器端口协议,勤哲Excel服务器技术支持|Excel服务器常见问题解答
  12. [读书笔记]《你的灯亮着吗?》
  13. unity资源管理器error refreshing assets
  14. “你还有什么事想问”——作为程序员如何回答面试官的问题
  15. Excel单元格引用
  16. Android基础课程:第三方视频播放器(播放网络资源)
  17. 共享汽车管理系统设计软便件研究
  18. 移动端可移动小图标(vue版)
  19. Canoe-OSEK网络管理自动化测试脚本CAPL 这适用于主流osek nm的测试用例
  20. 山东大学软件学院众智科学与网络化产业(网络、群体与市场)复习笔记

热门文章

  1. AI 一键抠图助你快速打造活动宣传海报
  2. 硬核FutureTask解析
  3. Linux 1.debain 忘记root密码(修改root密码)2.debian 默认不允许 root 登录 解决办法 3.终端快捷键的设置 (超级详细)
  4. 微信公众号自动回复机器人
  5. Kafka能作为数据库使用吗
  6. octagam® 10%治疗皮肌炎患者的ProDERM研究达到主要终点的阳性结果将在ACR 2020年会上呈报
  7. Open Cascade 多视图-多个3D视图
  8. oracle去除字段里的汉字
  9. fatal error LNK1120: 1个无法解析的外部命令
  10. 开发一个app应用的流程有哪些