树、二叉树、二叉搜索树的实现和特性

点赞再看,养成习惯,微信搜一搜【一角钱小助手】关注更多原创技术文章。
本文 GitHub github.com/JavaStudy 已收录,有我的系列文章。

前言

本篇先回顾树、二叉树、二叉搜索树的实现和特性,《AVL 树和红黑树的实现和特性》可以阅读这篇。另外,树的面试题解法一般都是递归 为什么? 我们在后面总结。

一维结构:数组、链表、跳表、栈、队列等,这些结构都是 线性存储结构

二维结构:树、图,是一种非线性存储结构,存储的是具有 “一对多”关系的数据元素的集合。

树 Tree

树的结点

结点:使用树结构存储的每一个数据元素都被称为“结点”。

父结点(双亲结点)、子结点和兄弟结点:对于图D是H、I结点的父结点(也称为“双亲结点”),而H、I都是D结点的子结点(也称“孩子结点”)。对于B、C来说,它们都有相同的父结点,所以它们互为兄弟结点。

树根结点(简称“根结点”):每个非空树都有且只有一个被称为根的结点。

叶子结点:如果结点没有任何子结点,那么此结点称为叶子结点(叶结点)。

子树和空树

子树:单个结点也是一棵树,只不过根结点就是它本身。知道了子树的概念后,树也可以这样定义:树是由根结点和若干个子树构成的。

空树:如果集合本身为空,那么构成的树就被称为空树。空树中没有结点。

结点的度和层次

对于一个结点,拥有的子树数(结点有多少分支)称为结点的度(Degree)

结点的层次:从一颗树根开始,树根所在层为第一层,根的孩子结点所在的层为第二层,以此类推。

有序树和无序数

如果树中结点的子树从左到右看,谁在左边,谁在右边,是有规定的,这颗树称为 有序树,反之称为 无序树

在有序树中,一个结点最左边的子树称为 “第一个孩子”,最右边的称为 “最后一个孩子”。

森林

由 m(m >= 0)个互不相交的树组成的集合被称为 森林

小结

树型存储结构类似于家族的族谱,各个结点之间也同样可能具有父子、兄弟、表兄弟的关系。需要重点理解树的根结点和子树的定义,同时要会计算树中各个结点的度和层次,以及树的深度。

二叉树 Binary Tree

简单地理解,满足以下两个条件的树就是二叉树:

  1. 本身是有序树;
  2. 树中包含的各个结点的度不能超过2,即只能是0、1或者2.

二叉树的性质

二叉树具有以下几个性质:

  1. 二叉树中,第 i 层最多有 2^{i-1} 个结点。
  2. 如果二叉树的深度为 k ,那么此二叉树最多有 2^k -1 个结点。
  3. 二叉树中,终端结点数(叶子结点数)为 n_0,度为2的结点数为 n_2,则 n_0 = n_2 + 1

二叉树还可以继续分类,衍生出 满二叉树完全二叉树

满二叉树

如果二叉树中除了叶子结点,每个结点的度都为2,则此二叉树称为 满二叉数

满二叉树除了满足普通二叉树的性质,还具有以下性质:

  1. 满二叉树中,第 i 层最多有 2^{i-1} 个结点。
  2. 深度为 k 的满二叉树2^k -1 个结点,叶子数为 2^{k - 1}
  3. 满二叉树中不存在度为1 的结点,每一个分支点中都有两颗深度相同的子树,且叶子结点都在对底层。
  4. 具有 n 个结点的满二叉树的深度为
    log2 ^{(n+1)}

完全二叉树

如果二叉树中除去最后一层结点为满二叉树,且最后一层的结点依次从左到右分布,则此二叉树被称为 完全二叉树

完全二叉树除了具有普通二叉树的性质,它自身也具有一些独特的性质,比如说,n 个结点的完全二叉树的深度为 [log2^n] + 1

对于任意一个完全二叉树来说,如果将含有的结点按照层次从左到右依次标号,对于任意一个结点 i ,完全二叉树还有以下几个结论成立:

  1. 当 i > 1 时,父亲结点为结点 [i/2] 。(i = 1 时,表示的是根结点,无父亲结点)。
  2. 如果 2 * i>n (总结点的个数) ,则结点 i 肯定没有左孩子(为叶子结点),否则其左孩子是结点 2 * i 。
  3. 如果 2 * i+1>n , 则结点 i 肯定没有右孩子,否则右孩子是结点 2 * i+1 。

二叉树遍历

  1. 前序(Pre-order):根-左-右
  2. 中序(In-order):左-根-右
  3. 后序(Post-order):左-右-根

示例代码:

def preorder(self, root):
  if root:
    self.traverse_path.append(root.val)
    self.preorder(root.left)
    self.preorder(root.right)

def inorder(self, root):
  if root:
    self.inorder(root.left)
    self.traverse_path.append(root.val)
    self.inorder(root.right)

def postorder(self, root):
  if root:
    self.postorder(root.left)
    self.postorder(root.right)
    self.traverse_path.append(root.val)

二叉搜索树 Binary Search Tree

二叉搜索树,也称二叉搜索树、有序二叉树(Ordered Binary Tree)、排序二叉树(Sorted Binary Tree),是指一颗空树或者具有下列性质的二叉树:

  • 左子树上所有结点的值均小于它的根结点的值;
  • 右子树上所有结点的值均大于它的根结点的值;
  • 以此类推,左、右子树也分别为二叉查找树(这就是重复性!)

中序遍历:升序排列

树和链表没有本质上的区别,当一个链表的话,当它分出两个 next 的话,我们就把它称为树,所以它的数据结构就是从一维空间扩散到二维空间了,这种扩散的好处就是引入了二叉搜索树。当它本身是有序的话,那么每一次的话就可以根据它和当前结点的大小关系分出来它只走左分支还是只走右分支,这样的话查询插入和搜索的效率就从 O(n)的变成了 log2n 的时间复杂度。

二叉搜索树常见操作

  1. 查询
  2. 插入新结点(创建)
  3. 删除

Demo: https://visualgo.net/zh/bst

如何查找结点

假设我们要查找 10,首先来和根相比,如果是小于 9 的话,只要去左子树就行了,10 是大于 9 的,那就去右子树,10 是小于 13 的就去左子树,10 是小于 11 的再去左子树就找到 10 了,而找不到的话也就是找不到。这时候你会发现查找的时间复杂度就是这个树的深度。如何这个树本身有 n 层的话,那么它的时间复杂度是 n,但是一般我们定义 n 为树的总的结点个数,这个时候它的时间复杂度平均来说就是 log2n,这里的 n 表示树里面总的结点个数。


极端情况

基于上面介绍可能会出现一种极端情况,这种极端情况的话就是在你维护二叉搜索树的时候,没有特殊处理的话,在极端情况下它会变成一根棍子,这根棍子的话就是你在插入的时候始终插在左边,这个时候二叉搜索树就退化成一个链表了。

如何优化可以阅读《AVL 树和红黑树的实现和特性》这篇。

复杂度分析

image.png

图片来源:http://www.bigocheatsheet.com/

实战题目

  1. https://leetcode-cn.com/problems/binary-tree-inorder-traversal/
  2. https://leetcode-cn.com/problems/binary-tree-preorder-traversal/
  3. https://leetcode-cn.com/problems/n-ary-tree-postorder-traversal/
  4. https://leetcode-cn.com/problems/n-ary-tree-preorder-traversal/
  5. https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/

总结

树的数据结构决定了递归是最好的解法,这是因为

  1. 树的结构与递归类似,递归的自调用就相当于让树的子树们再进行一次同样的操作;
  2. 递归的代码结构更加简单明了,也是树这么一个高维数据结构所带来的优势之一;
  3. 对于一种数据结构来说,无非就是查找插入和删除,在进行遍历这个反复循环的动作时,对于树的结构来说递归非常实用。
树、二叉树、二叉搜索树
部分图片来源于网络,版权归原作者,侵删。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335