数据结构二叉树之闲死攻略


这是一篇闲狗都能看懂的二叉树教程,因为是闲狗写的。




1 二叉树的概念

1.1 二叉树是what?

二叉树:每个结点至多拥有两棵子树(即不存在度大于2的结点)

二叉树的子树有左右之分,其次序不能任意颠倒

1.2 二叉树的五种基本形态

1.3 二叉树的相关术语

层数:根为第 0 层,其他结点的层数等于其父结点的层数加 1

深度:层数最大的叶结点的层数

高度:层数最大的叶结点的层数加 1

1.4 完美二叉树(Perfect Binary Tree)

A Perfect Binary Tree(PBT) is a tree with all leaf nodes(译成结点而非节点) at the same depth. All internal nodes have degree 2.


1.5 满二叉树(Full Binary Tree)

A Full Binary Tree (FBT) is a tree in which every node other than the leaves has two children. 所有非叶子结点的度都是2


1.6 完全二叉树(Complete Binary Tree)

A Complete Binary Tree (CBT) is a binary tree in which every level, except possibly the last, is completely filled, and all nodes are as far left as possible.
完全二叉树从根结点到倒数第二层满足完美二叉树,最后一层可以不完全填充,其叶子结点都靠左对齐。

1.7 扩充二叉树Extended binary tree

所有空子树,都增加空树叶
外部路径长度 E 和内部路径长度 I,满足:E = I + 2n (n 是内部结点个数)

E = 2 + 3 * 2 + 4 * 4 + 5 * 8 = 64

I = 1 * 2 + 2 * 3 + 3 * 4 + 4 * 4 = 36

E = I + 2n = 36 + 2 * 14 = 64

1.8 二叉树的主要性质

性质1. 在二叉树中,第i层上最多有 2i 个结点(i≥0)

性质2. 深度为 k 的二叉树至多有 2k+1-1个结点(k≥0),其中深度(depth)定义为二叉树中层数最大的叶结点的层数

性质3. 一棵二叉树,若其终端结点数为 n0,度为2的结点数为 n2, 则 n0=n2+1

性质4. 满二叉树定理:非空满二叉树树叶数目等于其分支结点数加1

性质5. 满二叉树定理推论:一个非空二叉树的空子树数目等于其结点数加1

累了累了,看下小姐姐轻松一下

2 二叉树的遍历(周游traversal)

2.1 深度优先遍历二叉树

2.1.1 前序法 (preorder traversal,根左右)

遍历过程为:
访问根结点
先序遍历其左子树
先序遍历其右子树
A(B D F E )(C G H I)
先序遍历=> A B D F E C G H I

(1)递归实现

(2)非递归实现

使用堆栈

  • 遇到一个结点,就访问该结点,并把此结点的非空右结点推入栈中,然后下降去遍历它的左子树;
  • 遍历完左子树后,从栈顶托出一个结点,并按照它的右链接指示的地址再去遍历该结点的右子树结构。

入栈序列 C F I H

先序序列 A(C入栈) B(F入栈) D F(F出栈) E C(C出栈,I入栈) G(H入栈) H(H出栈) I(I出栈)

2.1.2 中序法 (inorder traversal,左根右)

遍历过程为:

中序遍历其左子树
访问根结点
中序遍历其右子树
(D B E F) A (G H C I)
中序遍历=> D B E F A G H C I

(1)递归实现

(2)非递归实现

入栈序列 A B D F E C G H I

2.1.3 后序法 (postorder traversal,左右根)

遍历过程为:

(D E F B )( H G I C) A
后序遍历=> D E F B H G I C A

(1)递归实现

2.2 宽度优先遍历二叉树——层序遍历

2.3 应用

3 二叉树的存储结构

二叉树的各结点随机地存储在内存空间中,结点之间的逻辑关系用指针来链接。

3.1 二叉链表

3.2 三叉链表

博文短才会有人看的。其实,不管长还是短都没人看你的。

但也不要难过,毕竟数据结构是很有趣的,很......


4 二叉搜索树(Binary Search Tree)

4.1 BST的特性

4.2 BST的查找

查找22,22>16,跳到16的右子树,22<25,跳到25的左子树,22>19,跳到19的右子树,找到了22。

查找的效率决定于树的高度,若树的高度是h,那么查找过程的时间复杂度就是O(h)


4.2 BST的插入

关键是要找到元素应该插入的位置,可以采用与Find类似的方法

4.3 BST的删除

考虑三种情况

(1)要删除的是叶结点

直接删除,并再修改其父结点指针---置为NULL

(2)要删除的结点只有一个孩子结点

将其父结点的指针指向要删除结点的孩子结点

(3)要删除的结点有左、右两棵子树

用另一结点替代被删除结点:右子树的最小元素 或者 左子树的最大元素


5 线索二叉树

传统的链式存储仅能表现一种父子关系,不能直接得到结点在遍历中的前驱或后继。

为了加快查找前驱和后继的速度,引入了线索二叉树。

线索二叉树的结点结构

以中序线索二叉树的建立为例(BDAEC)

pre指向中序遍历时上一个刚刚访问过的结点。

二叉树是一种逻辑结构,线索二叉树是加上线索(指针)后的链表结构,是二叉树在计算机内部的一种存储结构,所以是一种物理结构


6 优先队列与堆

发送到打印机的作业一般会被放到队列中,但这未必是最好的做法。例如,有一项作业特别重要,希望只要打印机一空闲就来处理这项作业,这时就需要为该作业赋予优先权。这种应用的实现需要一类特殊的队列,称之为优先队列

优先队列(Priority Queue):特殊的“队列”,取出元素的顺序是依照元素的优先权(关键字)大小,而不是元素进入队列的先后顺序。

5.1 如何实现优先队列?

5.1.1 采用数组或链表实现优先队列

5.1.2 采用二叉堆实现优先队列

二叉堆简称为堆。

堆有两个特性:

(1)结构性

堆本质上是一棵用数组表示的完全二叉树。

对于一棵有n个结点的完全二叉树,对其结点按层序编号,从上到下,从左到右,对任一结点i (1 = i <= n)有:

  1. 如果i = 1,则结点i是二叉树的根,无父结点;如果i > 1,则其父结点的位置是⌊i / 2⌋(向下取整)。
  2. 如果2i > n,则结点i无左孩子(结点i为叶子结点);否则其左孩子是结点2i。
  3. 如果2i + 1 > n,则结点i无右孩子;否则其右孩子是结点2i + 1。

得益于二叉树的严格定义,我们只需要把完全二叉树按层序遍历依次把结点存入一维数组中,其数组下标就能够体现出父子结点关系(数组第0位不使用)。

(2)有序性

任一结点的关键字是其子树所有结点的最大值(或最小值)
最大堆(MaxHeap),也称“大顶堆”:最大值

最小堆(MinHeap),也称“小顶堆” :最小值

栗子:对最小堆用筛选法SiftDown调整

根结点72在其左右子子结点里找到最小的结点,与之交换。72 - 05

72 - 16

最大堆的建立

建最小堆

从23开始,05与71换

接着调73,shiftdown

此时72的左右子树都已经是子堆了

最小堆删除元素

栗子1:删除68

首先拿位于最后的元素45去替换

对45进行shiftup

栗子2:删除16

还是拿位于最后的元素45去替换

对45进行shiftdown

建堆效率分析

最小堆操作效率

优先队列的操作(等价于对堆进行插入与删除操作):



本文参考自:

张铭《数据结构与算法》

程杰《大话数据结构》

陈越,何钦铭《数据结构》


举报
评论 0