第06章 树和二叉树(java版)

52
数数数数 Java 数 )( 3数第6第 第第第第第 6.1 第第第第第第第第第 6.2 第第第第第第第第第第第 6.3 第第第第第第第第第 6.4 第第第第第 6.5 Huffman 第第第 Huffman 6.6 第第第第第第第 第第第第第第第第第第第第第第 第第第第第第第 第第第第第第第第第第 ,, 第第第第第第第第第 第第第第第第第第第第第第第第第第第第 第第第第第第第第第第第第第第第 ,。

Upload: yan-li

Post on 15-Jun-2015

811 views

Category:

Documents


11 download

TRANSCRIPT

Page 1: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

第 6 章 树和二叉树6.1 树及其抽象数据类型6.2 二叉树及其抽象数据类型6.3 二叉树的表示和实现6.4 线索二叉树6.5 Huffman编码与Huffman树6.6 树的表示和实现

本章是数据结构课程的重中之重,也是难点所在,表现为二叉链表存储结构和递归算法相结合。链式存储结构和递归算法本身就是两个难 点,建立二叉树需要将它们有机结合。

Page 2: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

目的和要求 目的:理解树型结构;掌握链式存储结构表达 非

线性结构,掌握递归算法设计。• 内容:二叉树的定义、性质、存储结构,二叉链

表表示的二叉树类;中序线索二叉树;Huffman 树;树的定义、存储结构和实现。

• 要求:理解树和二叉树概念,掌握树和二叉树的表示和实现,掌握递归算法设计。

• 重点:二叉链表表示的二叉树类; Huffman 树;树 的定义、存储结构和构造算法。

• 难点:链式存储结构表达非线性结构;递归算法 设计。

• 实验:树和二叉树的基本操作,链式存储结构表示树和二叉树;递归算法。

Page 3: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

6.1 树及其抽象数据类型6.1.1 树定义 6.1.2 树的术语6.1.3 树的表示法 6.1.4 树抽象数据类型

Page 4: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

6.1.1 树定义树( tree )是由 n( n≥0 )个结点组成的

有限集合。 n=0 的树称为空树; n>0 的树 T :根( root )结点,它没有前驱结点。其他结点分为 m 棵互不相交的子树。

Page 5: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

6.1.2 树的术语

1. 父母、孩子与兄弟结点2. 度 3. 结点层次、树的高度4. 边、路径 5. 无序树、有序树 6. 森林

Page 6: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

6.1.3 树的表示法

1. 图示法2. 横向凹入表示法

AB

EF

CG

DHIJ

3. 广义表表示 A(B(E, F), C(G), D(H, I,

J))

Page 7: 第06章  树和二叉树(java版)

《数据结构( 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); // 删除孩子}

Page 8: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

6.2 二叉树及其抽象数据类型

6.2.1 二叉树定义

6.2.2 二叉树性质

6.2.3 二叉树的遍历

6.2.4 二叉树抽象数据类型

Page 9: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

6.2.1 二叉树定义

二叉树( binary tree )是 n 个结点的有限集合: 空二叉树; 由一个根结点、两棵互不相交的左子树和右子

树组成。

Page 10: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

6.2.2 二叉树性质

性质 1 :若根结点的层次为 1 ,则二叉树第 i层最多有 2i1 ( i≥1 )个结点。

性质 2 :在高度为 k 的二叉树中,最多有2k1 个结点( k≥0 )。

性质 3 :设一棵二叉树的叶子结点数为 n0, 2度结点数为 n2 ,则 n0=n2+1 。

Page 11: 第06章  树和二叉树(java版)

《数据结构( 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

Page 12: 第06章  树和二叉树(java版)

《数据结构( 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

Page 13: 第06章  树和二叉树(java版)

《数据结构( 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(); }

Page 14: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

6.3 二叉树的表示和实现

6.3.1 二叉树的存储结构

6.3.2 二叉树的二叉链表实现

6.3.3 三叉树的二叉链表实现

Page 15: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

6.3.1 二叉树的存储结构

1. 二叉树的顺序存储结构

Page 16: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

2. 二叉树的链式存储结构

二叉链表

三叉链表

Page 17: 第06章  树和二叉树(java版)

《数据结构( 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; // 根结点 }

Page 18: 第06章  树和二叉树(java版)

《数据结构( 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 】 构造并遍历二叉树。

Page 19: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

4. 基于遍历的操作

① 求结点个数 ② 求高度 ③ 查找 ④ 获得父母结点

Page 20: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

5. 构造二叉树

( 1 )先根和中根序列表示

Page 21: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

( 2 )标明空子树的先根序列表示

【例 6.2 】 输出二叉树中指定结点的所有祖先结点。

Page 22: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

( 3 )广义表表示

Page 23: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

( 4 )以完全二叉树的层次遍历序列构造链式存储结构的完全二叉树

【例 6.3 】 建立二叉链表表示的完全二叉树。BinaryTTree二叉树接口

BinaryTree二叉链表存储的二叉树类

实现

CompleteBinaryTree完全二叉树类

继承

Page 24: 第06章  树和二叉树(java版)

《数据结构( 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

qq

Page 25: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

7. 二叉树遍历的非递归算法

Page 26: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

8. 二叉树的层次遍历

Page 27: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

6.3.3 三叉树的二叉链表实现

1. 二叉树的三叉链表结点类 public class TriNode<T>

{ public T data; // 数据域 public TriNode<T> parent, left,

right; // 父母结点、左和右孩子结点

public int level; // 结点的层次}

Page 28: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

2.三叉链表表示的二叉树类

public class TriBinaryTree<T>

{

public TriNode<T> root; // 根结点

}

( 1 )构造二叉树

Page 29: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

( 2 )插入结点

例6.4 输出三叉链表存储二叉树的一条直径。

p

(a)插入值为Xr的结点q作为p的左孩子,原p的左孩子D作为q的左孩子

p

∧X

(b) 插入值为X结点q作为p的右孩子,原p的右孩子F作为q的右孩子

∧ X

qq

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

Page 30: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

6.4 线索二叉树6.4.1 线索二叉树定义

0 leftÖ¸Ïò ×óº¢×Óltag

1 left Ϊ Ï ßË÷ £ ¬ Ö Ï̧ò Ç°Çý½ áµãC

0 rightrtag

1 right Ϊ Ï ßË÷ £ ¬ Ö¸Ïò º ó ¼ Ì½ áµãC

Page 31: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

6.4.2 中序线索二叉树

1. 二叉树的中序线索化 2. 中序线索二叉树类 3. 中根次序遍历中序线索二叉树

【例 6.5 】 构造中序线索二叉树并进行中根次序遍历。

4. 先根次序遍历中序线索二叉树5. 后根次序遍历中序线索二叉树

Page 32: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

1. 二叉树的中序线索化

Page 33: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

2. 中序线索二叉树类

public class ThreadBinaryTree<T>

{

public ThreadNode<T> root;

}

3. 中根次序遍历中序线索二叉树

Page 34: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

4. 先根次序遍历中序线索二叉树

Page 35: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

5. 后根次序遍历中序线索二叉树

Page 36: 第06章  树和二叉树(java版)

《数据结构( 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

Page 37: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

6.5.2 Huffman 树

1. 二叉树的路径长度

1

0

PLn

iil

Page 38: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

2. 二叉树的外路径长度

Page 39: 第06章  树和二叉树(java版)

《数据结构( 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

Page 40: 第06章  树和二叉树(java版)

《数据结构( 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

Page 41: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

构造 Huffman 树并获得 Huffman编码

5. Huffman 编码的译码

Page 42: 第06章  树和二叉树(java版)

《数据结构( 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树

Page 43: 第06章  树和二叉树(java版)

《数据结构( 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编码

Page 44: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

<2> 存储 Huffman 编码

Page 45: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

6.6 树的表示和实现

6.6.1 树的遍历

6.6.2 树的存储结构

6.3.3 树的孩子兄弟链表实现

Page 46: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

6.6.1 树的遍历

1. 树的先根遍历算法描述如下:① 访问根结点。② 按照从左到右的次序先根遍历根的每一棵子树。

2. 树的后根遍历算法描述如下:① 按照从左到右的次序后根遍历根的每一棵子树。② 访问根结点。

Page 47: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

6.6.2 树的存储结构

1. 孩子链表

2. 孩子兄弟链表

childroot

A ∧

data sibling

B ∧ C D ∧

∧ E ∧ G ∧∧ F ∧

Page 48: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

6.3.3 树的孩子兄弟链表实现

1. 树的孩子兄弟链表结点类 public class TreeNode<T>{ public T data; // 数据域 public TreeNode<T> child,

sibling; // 孩子、兄弟结点

}

Page 49: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

2. 树类声明 public class Tree<T> implements

TTree<T>{ public TreeNode<T> root; // 根结

点}3. 树的遍历 4. 返回结点

① 返回最后一个兄弟结点 ② 返回最后一个孩子结点

TTree树接口

Tree孩子兄弟链表存储的树类

实现

Page 50: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

5. 插入结点

1. 插入根结点2. 插入兄弟结点

Page 51: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

6. 以横向凹入表示构造树或森林

例 6.8 以树的横向凹入表示构造树或森林。 root 中国 ∧

∧ 北京 江苏

∧ 南京 ∧ 苏州 ∧

∧∧

child

root 中国 ∧

data sibling root 中国 ∧

∧ 北京 ∧ 江苏 ∧

root 中国

∧ 北京 江苏

∧ 南京 ∧ 苏州 ∧

韩国 ∧

∧ 首尔 ∧

(a)插入根结点(没有前缀\t)(b)插入省份(1个前缀\t)作为根的最后一个孩子结点 (c)插入城市(2个前缀\t)作为省份的最后一个孩子

(e)再插入结点作为根最后一个兄弟的孩子

root 中国

∧ 北京 江苏

∧ 南京 ∧ 苏州 ∧

∧ 韩国 ∧

(d)插入国名(没有前缀\t)作为根的最后一个兄弟结点

Page 52: 第06章  树和二叉树(java版)

《数据结构( Java 版)(第 3 版)》

7. 树的广义表表示

例 6.9 树的广义表表示及构造。 中国 ( 北京 , 上海 , 江苏 ( 南京 , 苏州 , 无锡 ), 浙江 ( 杭州 , 宁波 ,温州 ), 广东( 广州 )),韩国 ( 首尔 ),美国 ( 华盛顿 )

元素 树(

)树