Upload
yan-li
View
811
Download
11
Embed Size (px)
Citation preview
《数据结构( Java 版)(第 3 版)》
第 6 章 树和二叉树6.1 树及其抽象数据类型6.2 二叉树及其抽象数据类型6.3 二叉树的表示和实现6.4 线索二叉树6.5 Huffman编码与Huffman树6.6 树的表示和实现
本章是数据结构课程的重中之重,也是难点所在,表现为二叉链表存储结构和递归算法相结合。链式存储结构和递归算法本身就是两个难 点,建立二叉树需要将它们有机结合。
《数据结构( Java 版)(第 3 版)》
目的和要求 目的:理解树型结构;掌握链式存储结构表达 非
线性结构,掌握递归算法设计。• 内容:二叉树的定义、性质、存储结构,二叉链
表表示的二叉树类;中序线索二叉树;Huffman 树;树的定义、存储结构和实现。
• 要求:理解树和二叉树概念,掌握树和二叉树的表示和实现,掌握递归算法设计。
• 重点:二叉链表表示的二叉树类; Huffman 树;树 的定义、存储结构和构造算法。
• 难点:链式存储结构表达非线性结构;递归算法 设计。
• 实验:树和二叉树的基本操作,链式存储结构表示树和二叉树;递归算法。
《数据结构( Java 版)(第 3 版)》
6.1 树及其抽象数据类型6.1.1 树定义 6.1.2 树的术语6.1.3 树的表示法 6.1.4 树抽象数据类型
《数据结构( Java 版)(第 3 版)》
6.1.1 树定义树( tree )是由 n( n≥0 )个结点组成的
有限集合。 n=0 的树称为空树; n>0 的树 T :根( root )结点,它没有前驱结点。其他结点分为 m 棵互不相交的子树。
《数据结构( Java 版)(第 3 版)》
6.1.2 树的术语
1. 父母、孩子与兄弟结点2. 度 3. 结点层次、树的高度4. 边、路径 5. 无序树、有序树 6. 森林
《数据结构( Java 版)(第 3 版)》
6.1.3 树的表示法
1. 图示法2. 横向凹入表示法
AB
EF
CG
DHIJ
3. 广义表表示 A(B(E, F), C(G), D(H, I,
J))
《数据结构( Java 版)(第 3 版)》
6.1.4 树抽象数据类型
public interface TTree<T> // 树接口{ boolean isEmpty(); // 判断是否空树 TreeNode<T> getChild(TreeNode<T> p,int i);// 返回 p 第 i 个孩子 TreeNode<T> getParent(TreeNode<T> node);// 返回 node 的父
母 int count(); // 树的结点个数 int height(); // 树的高度 TreeNode<T> search(T x); // 查找并返回元素为 x 的结点 void preOrder(); // 先根次序遍历树 void postOrder(); // 后根次序遍历树 void levelOrder(); // 按层次遍历树 void insertRoot(T x); // 插入元素 x 作为根结点 TreeNode<T> insertChild(TreeNode<T> p,T x,int i);// 插入孩子 void removeChild(TreeNode<T> p, int i); // 删除孩子}
《数据结构( Java 版)(第 3 版)》
6.2 二叉树及其抽象数据类型
6.2.1 二叉树定义
6.2.2 二叉树性质
6.2.3 二叉树的遍历
6.2.4 二叉树抽象数据类型
《数据结构( Java 版)(第 3 版)》
6.2.1 二叉树定义
二叉树( binary tree )是 n 个结点的有限集合: 空二叉树; 由一个根结点、两棵互不相交的左子树和右子
树组成。
《数据结构( Java 版)(第 3 版)》
6.2.2 二叉树性质
性质 1 :若根结点的层次为 1 ,则二叉树第 i层最多有 2i1 ( i≥1 )个结点。
性质 2 :在高度为 k 的二叉树中,最多有2k1 个结点( k≥0 )。
性质 3 :设一棵二叉树的叶子结点数为 n0, 2度结点数为 n2 ,则 n0=n2+1 。
《数据结构( Java 版)(第 3 版)》
性质 4 : n 个结点完全二叉树的高度是 。性质 5 :一棵具有 n 个结点的完全二叉树,对序号为
i( 0≤i<n )的结点,有:① 若 i=0 ,则 i 为根结点,无父母结点;若 i >0 ,则 i 的父母
结点序号为。② 若 2i+1<n ,则 i 的左孩子结点序号为 2i+1 ;否则 i 无左
孩子。③ 若 2i+2<n ,则 i 的右孩子结点序号为 2i+2 ;否则 i 无右
孩子。
1log2 nk
《数据结构( Java 版)(第 3 版)》
6.2.3 二叉树的遍历
先根次序:访问根结点,遍历左子树,遍历右子树。中根次序:遍历左子树,访问根结点,遍历右子树。后根次序:遍历左子树,遍历右子树,访问根结点。
先根遍历序列: A B D G C E F H
中根遍历序列: D G B A E C H F
后根遍历序列: G D B E H F C A
《数据结构( Java 版)(第 3 版)》
6.2.4 二叉树抽象数据类型public interface BinaryTTree<T> { boolean isEmpty(); // 判断是否空 int count(); // 返回结点个数 int height(); // 返回高度 void preOrder(); // 先根次序遍历 void inOrder(); // 中根次序遍历 void postOrder(); // 后根次序遍历 void levelOrder(); // 按层次遍历 BinaryNode<T> search(T key); // 查找 BinaryNode<T> getParent(BinaryNode<T> node);// 返回父母 void insertRoot(T x); // 插入元素 x 作为根结点 BinaryNode<T> insertChild(BinaryNode<T> p, T x, boolean
leftChild); void removeChild(BinaryNode<T> p, boolean leftChild); void removeAll(); }
《数据结构( Java 版)(第 3 版)》
6.3 二叉树的表示和实现
6.3.1 二叉树的存储结构
6.3.2 二叉树的二叉链表实现
6.3.3 三叉树的二叉链表实现
《数据结构( Java 版)(第 3 版)》
6.3.1 二叉树的存储结构
1. 二叉树的顺序存储结构
《数据结构( Java 版)(第 3 版)》
2. 二叉树的链式存储结构
二叉链表
三叉链表
《数据结构( Java 版)(第 3 版)》
6.3.2 二叉树的二叉链表实现
1. 二叉树的二叉链表结点类public class BinaryNode<T>
{ T data; // 数据元素 BinaryNode<T> left, right; // 左、右孩子}
2. 二叉树类public class BinaryTree<T> implements
BinaryTTree<T>
{ BinaryNode<T> root; // 根结点 }
《数据结构( Java 版)(第 3 版)》
3. 二叉树三种次序遍历的递归算法 // 先根次序遍历以 p 结点为根的子树private void preOrder(BinaryNode<T> p)
{ if (p!=null) // 若二叉树不空 { System.out.print(p.data+" "); // 访问当前结
点 preOrder(p.left); // 按先根次序遍历左子树 preOrder(p.right); // 按先根次序遍历右子树 } }
【例 6.1 】 构造并遍历二叉树。
《数据结构( Java 版)(第 3 版)》
4. 基于遍历的操作
① 求结点个数 ② 求高度 ③ 查找 ④ 获得父母结点
《数据结构( Java 版)(第 3 版)》
5. 构造二叉树
( 1 )先根和中根序列表示
《数据结构( Java 版)(第 3 版)》
( 2 )标明空子树的先根序列表示
【例 6.2 】 输出二叉树中指定结点的所有祖先结点。
《数据结构( Java 版)(第 3 版)》
( 3 )广义表表示
《数据结构( Java 版)(第 3 版)》
( 4 )以完全二叉树的层次遍历序列构造链式存储结构的完全二叉树
【例 6.3 】 建立二叉链表表示的完全二叉树。BinaryTTree二叉树接口
BinaryTree二叉链表存储的二叉树类
实现
CompleteBinaryTree完全二叉树类
继承
《数据结构( Java 版)(第 3 版)》
6. 二叉树的插入和删除操作
( 1 )插入一个结点
( 2 )删除一棵子树
rootA
B ∧ C
∧ E ∧
F ∧∧ D
∧ H ∧∧ G ∧
p
(a)创建值为X结点并作为p的左孩子,原p的左孩子D作为X结点的左孩子
rootA
B
∧ D
∧ G ∧
p
∧X X ∧
(b)创建值为Y结点并作为p的右孩子,原p的右孩子F作为Y结点的右孩子
∧ Y
《数据结构( Java 版)(第 3 版)》
7. 二叉树遍历的非递归算法
《数据结构( Java 版)(第 3 版)》
8. 二叉树的层次遍历
《数据结构( Java 版)(第 3 版)》
6.3.3 三叉树的二叉链表实现
1. 二叉树的三叉链表结点类 public class TriNode<T>
{ public T data; // 数据域 public TriNode<T> parent, left,
right; // 父母结点、左和右孩子结点
public int level; // 结点的层次}
《数据结构( Java 版)(第 3 版)》
2.三叉链表表示的二叉树类
public class TriBinaryTree<T>
{
public TriNode<T> root; // 根结点
}
( 1 )构造二叉树
《数据结构( Java 版)(第 3 版)》
( 2 )插入结点
例6.4 输出三叉链表存储二叉树的一条直径。
p
(a)插入值为Xr的结点q作为p的左孩子,原p的左孩子D作为q的左孩子
p
∧X
(b) 插入值为X结点q作为p的右孩子,原p的右孩子F作为q的右孩子
∧ X
A
parentroot
∧
data right
B ∧
left
D∧
G ∧∧
Aroot
∧
C
E ∧∧
F ∧
H ∧∧
1
level
2 2
1
4
5
3 3 3
4
5
《数据结构( Java 版)(第 3 版)》
6.4 线索二叉树6.4.1 线索二叉树定义
0 leftÖ¸Ïò ×óº¢×Óltag
1 left Ϊ Ï ßË÷ £ ¬ Ö Ï̧ò Ç°Çý½ áµãC
0 rightrtag
1 right Ϊ Ï ßË÷ £ ¬ Ö¸Ïò º ó ¼ Ì½ áµãC
《数据结构( Java 版)(第 3 版)》
6.4.2 中序线索二叉树
1. 二叉树的中序线索化 2. 中序线索二叉树类 3. 中根次序遍历中序线索二叉树
【例 6.5 】 构造中序线索二叉树并进行中根次序遍历。
4. 先根次序遍历中序线索二叉树5. 后根次序遍历中序线索二叉树
《数据结构( Java 版)(第 3 版)》
1. 二叉树的中序线索化
《数据结构( Java 版)(第 3 版)》
2. 中序线索二叉树类
public class ThreadBinaryTree<T>
{
public ThreadNode<T> root;
}
3. 中根次序遍历中序线索二叉树
《数据结构( Java 版)(第 3 版)》
4. 先根次序遍历中序线索二叉树
《数据结构( Java 版)(第 3 版)》
5. 后根次序遍历中序线索二叉树
《数据结构( Java 版)(第 3 版)》
6.5 Huffman 编码与Huffman 树 6.5.1 Huffman编码
存储“ AAAABBBCDDBBAAA” ,字符集[A、 B、D 、C] ,字符出现次数为 7 、 5 、 2 、 1 ,频率为 0.47、 0.33、 0.13、 0.07 ,哈夫曼编码过程为:
A A A A B B B C D D B B A A A
0 0 0 0 10 10 10 111
110
110
10 10 0 0 0
《数据结构( Java 版)(第 3 版)》
6.5.2 Huffman 树
1. 二叉树的路径长度
1
0
PLn
iil
《数据结构( Java 版)(第 3 版)》
2. 二叉树的外路径长度
《数据结构( Java 版)(第 3 版)》
3. 二叉树的带权外路径长度1
0
WPL ( )n
i ii
w l
7 5 1 2 7
(b)WPL=7×2+5×3+1×3+2×1=34
5 1
2
DCBA
(a)WPL=7×2+5×2+1×2+2×2=30
D
CB
A
7
5
2 1
A
B
D C
(c)WPL=7×1+5×2+2×3+1×3=26
2
1
5 7
D
C
B A
(d)WPL=2×1+1×2+5×3+7×3=40
《数据结构( Java 版)(第 3 版)》
4. Huffman 算法
哈夫曼树定义为带权外路径长度最短的二叉树。哈夫曼树不唯一
5
(c)
2 1
7 A
CD
B
7
5
2 1
A
B
D C
(d)
A
B
D C
7A
5
1 2C A
B
(a) (b)
5
2
7
1
《数据结构( Java 版)(第 3 版)》
构造 Huffman 树并获得 Huffman编码
5. Huffman 编码的译码
《数据结构( Java 版)(第 3 版)》
例 6.6 构造 Huffman 树并获得Huffman 编码。
85 -1 -10
…n个叶子结点
rightdata parent left
1329 -1 -11
97 -1 -12
98 -1 -13
1114 -1 -14
1223 -1 -15
83 -1 -16
1011 -1 -17
108 6 08
1115 2 39
1219 8 710
1329 4 911
1442 10 512
1458 1 1113
-1100 12 1314
-15 -1 -10
… n-1个2度结点
rightdata parent left
-129 -1 -11
-17 -1 -12
-18 -1 -13
-114 -1 -14
-123 -1 -15
-13 -1 -16
-111 -1 -17
8
9
10
11
12
13
14
n
2n-2
n-1
根结点
(a)初始状态 (b)最终状态
<1> 采用静态三叉链表存储 Huffman树
《数据结构( Java 版)(第 3 版)》
图 6-44 Huffman 树和 Huffman编码
若权值集合 {5,29,7,8,14,23,3,11} 对应字符 A ~H
19
42
23 F
8 11
3 5G A
H
10
10
G:0000A:0001H:001F:01B:10E:110C:1110D:1111
10
10010
15
7 8C
10
D
29
14E
10
58
29B
10
Huffman编码
《数据结构( Java 版)(第 3 版)》
<2> 存储 Huffman 编码
《数据结构( Java 版)(第 3 版)》
6.6 树的表示和实现
6.6.1 树的遍历
6.6.2 树的存储结构
6.3.3 树的孩子兄弟链表实现
《数据结构( Java 版)(第 3 版)》
6.6.1 树的遍历
1. 树的先根遍历算法描述如下:① 访问根结点。② 按照从左到右的次序先根遍历根的每一棵子树。
2. 树的后根遍历算法描述如下:① 按照从左到右的次序后根遍历根的每一棵子树。② 访问根结点。
《数据结构( Java 版)(第 3 版)》
6.6.2 树的存储结构
1. 孩子链表
2. 孩子兄弟链表
childroot
A ∧
data sibling
B ∧ C D ∧
∧ E ∧ G ∧∧ F ∧
《数据结构( Java 版)(第 3 版)》
6.3.3 树的孩子兄弟链表实现
1. 树的孩子兄弟链表结点类 public class TreeNode<T>{ public T data; // 数据域 public TreeNode<T> child,
sibling; // 孩子、兄弟结点
}
《数据结构( Java 版)(第 3 版)》
2. 树类声明 public class Tree<T> implements
TTree<T>{ public TreeNode<T> root; // 根结
点}3. 树的遍历 4. 返回结点
① 返回最后一个兄弟结点 ② 返回最后一个孩子结点
TTree树接口
Tree孩子兄弟链表存储的树类
实现
《数据结构( Java 版)(第 3 版)》
5. 插入结点
1. 插入根结点2. 插入兄弟结点
《数据结构( Java 版)(第 3 版)》
6. 以横向凹入表示构造树或森林
例 6.8 以树的横向凹入表示构造树或森林。 root 中国 ∧
∧ 北京 江苏
∧ 南京 ∧ 苏州 ∧
∧∧
child
root 中国 ∧
data sibling root 中国 ∧
∧ 北京 ∧ 江苏 ∧
root 中国
∧ 北京 江苏
∧ 南京 ∧ 苏州 ∧
∧
韩国 ∧
∧ 首尔 ∧
(a)插入根结点(没有前缀\t)(b)插入省份(1个前缀\t)作为根的最后一个孩子结点 (c)插入城市(2个前缀\t)作为省份的最后一个孩子
(e)再插入结点作为根最后一个兄弟的孩子
root 中国
∧ 北京 江苏
∧ 南京 ∧ 苏州 ∧
∧
∧ 韩国 ∧
(d)插入国名(没有前缀\t)作为根的最后一个兄弟结点
《数据结构( Java 版)(第 3 版)》
7. 树的广义表表示
例 6.9 树的广义表表示及构造。 中国 ( 北京 , 上海 , 江苏 ( 南京 , 苏州 , 无锡 ), 浙江 ( 杭州 , 宁波 ,温州 ), 广东( 广州 )),韩国 ( 首尔 ),美国 ( 华盛顿 )
元素 树(
,
)树