《算法导论》读书笔记之第10章 基本数据结构之二叉树.docx
- 文档编号:4472681
- 上传时间:2022-12-01
- 格式:DOCX
- 页数:17
- 大小:18.89KB
《算法导论》读书笔记之第10章 基本数据结构之二叉树.docx
《《算法导论》读书笔记之第10章 基本数据结构之二叉树.docx》由会员分享,可在线阅读,更多相关《《算法导论》读书笔记之第10章 基本数据结构之二叉树.docx(17页珍藏版)》请在冰豆网上搜索。
《算法导论》读书笔记之第10章基本数据结构之二叉树
《算法导论》读书笔记之第10章基本数据结构之二叉树
摘要
书中第10章10.4小节介绍了有根树,简单介绍了二叉树和分支数目无限制的有根树的存储结构,而没有关于二叉树的遍历过程。
为此对二叉树做个简单的总结,介绍一下二叉树基本概念、性质、二叉树的存储结构和遍历过程,主要包括先根遍历、中根遍历、后根遍历和层次遍历。
1、二叉树的定义
二叉树(BinaryTree)是一种特殊的树型结构,每个节点至多有两棵子树,且二叉树的子树有左右之分,次序不能颠倒。
由定义可知,二叉树中不存在度(结点拥有的子树数目)大于2的节点。
二叉树形状如下下图所示:
2、二叉树的性质
(1)在二叉树中的第i层上至多有2^(i-1)个结点(i>=1)。
备注:
^表示此方
(2)深度为k的二叉树至多有2^k-1个节点(k>=1)。
(3)对任何一棵二叉树T,如果其终端结点数目为n0,度为2的节点数目为n2,则n0=n2+1。
满二叉树:
深度为k且具有2^k-1个结点的二叉树。
即满二叉树中的每一层上的结点数都是最大的结点数。
完全二叉树:
深度为k具有n个结点的二叉树,当且仅当每一个结点与深度为k的满二叉树中的编号从1至n的结点一一对应。
可以得到一般结论:
满二叉树和完全二叉树是两种特殊形态的二叉树,满二叉树肯定是完全二叉树,但完全二叉树不不一定是满二叉树。
举例如下图是所示:
(4)具有n个节点的完全二叉树的深度为log2n+1。
3、二叉树的存储结构
可以采用顺序存储数组和链式存储二叉链表两种方法来存储二叉树。
经常使用的二叉链表方法,因为其非常灵活,方便二叉树的操作。
二叉树的二叉链表存储结构如下所示:
1typedefstructbinary_tree_node
2{
3intelem;
4structbinary_tree_node*left;
5structbinary_tree_node*right;
6}binary_tree_node,*binary_tree;
举例说明二叉链表存储过程,如下图所示:
从图中可以看出:
在还有n个结点的二叉链表中有n+1个空链域。
4、遍历二叉树
遍历二叉树是按照指定的路径方式访问书中每个结点一次,且仅访问一次。
由二叉树的定义,我们知道二叉数是由根结点、左子树和右子树三部分构成的。
通常遍历二叉树是从左向右进行,因此可以得到如下最基本的三种遍历方法:
(1)先根遍历(先序遍历):
如果二叉树为空,进行空操作;否则,先访问根节点,然后先根遍历左子树,最后先根遍历右子树。
采用递归形式实现代码如下:
1voidpreorder_traverse_recursive(binary_treeroot)
2{
3if(NULL!
=root)
4{
5printf("%d\t",root->elem);
6preorder_traverse_recursive(root->left);
7preorder_traverse_recursive(root->right);
8}
9}
具体过程如下图所示:
(2)中根遍历(中序遍历):
如果二叉树为空,进行空操作;否则,先中根遍历左子树,然后访问根结点,最后中根遍历右子树。
递归过程实现代码如下:
1voidinorder_traverse_recursive(binary_treeroot)
2{
3if(NULL!
=root)
4{
5inorder_traverse_recursive(root->left);
6printf("%d\t",root->elem);
7inorder_traverse_recursive(root->right);
8}
9}
具体过程如下图所示:
(3)后根遍历(后序遍历):
如果二叉树为空,进行空操作;否则,先后根遍历左子树,然后后根遍历右子树,最后访问根结点。
递归实现代码如下:
1voidpostorder_traverse_recursive(binary_treeroot)
2{
3if(NULL!
=root)
4{
5postorder_traverse_recursive(root->left);
6postorder_traverse_recursive(root->right);
7printf("%d\t",root->elem);
8}
9}
具体过程如下图所示:
写一个完整的程序练习二叉树的三种遍历,采用递归形式创建二叉树,然后以递归的形式遍历二叉树,后面会接着讨论如何使用非递归形式实现这三种遍历,程序采用C语言实现,完整程序如下:
1#include<stdio.h>
2#include<stdlib.h>
3
4//thestructureofbinarytree
5typedefstructbinary_tree_node
6{
7intelem;
8structbinary_tree_node*left;
9structbinary_tree_node*right;
10}binary_tree_node,*binary_tree;
11
12voidinit_binary_tree(binary_tree*root);
13voidcreate_binary_tree(binary_tree*root);
14
15//previousroot
16voidpreorder_traverse_recursive(binary_treeroot);
17//inorderroot
18voidinorder_traverse_recursive(binary_treeroot);
19//postorderroot
20voidpostorder_traverse_recursive(binary_treeroot);
21
22intmain()
23{
24binary_treeroot;
25init_binary_tree(&root);
26create_binary_tree(&root);
27preorder_traverse_recursive(root);
28inorder_traverse_recursive(root);
29postorder_traverse_recursive(root);
30exit(0);
31}
32
33voidinit_binary_tree(binary_tree*root)
34{
35*root=NULL;
36}
37
38voidcreate_binary_tree(binary_tree*root)
39{
40intelem;
41printf("Enterthenodevalue(0isend):
");
42scanf("%d",&elem);
43if(elem==0)
44*root=NULL;
45else
46{
47*root=(binary_tree)malloc(sizeof(binary_tree_node));
48if(NULL==root)
49{
50printf("mallocerror.\n");
51exit(-1);
52}
53(*root)->elem=elem;
54printf("Creatingtheleftchildnode.\n");
55create_binary_tree(&((*root)->left));
56printf("Createingtherightchildnode.\n");
57create_binary_tree(&((*root)->right));
58}
59}
60
61voidpreorder_traverse_recursive(binary_treeroot)
62{
63if(NULL!
=root)
64{
65printf("%d\t",root->elem);
66preorder_traverse_recursive(root->left);
67preorder_traverse_recursive(root->right);
68}
69}
70
71voidinorder_traverse_recursive(binary_treeroot)
72{
73if(NULL!
=root)
74{
75inorder_traverse_recursive(root->left);
76printf("%d\t",root->elem);
77inorder_traverse_recursive(root->right);
78}
79}
80
81voidpostorder_traverse_recursive(binary_treeroot)
82{
83if(NULL!
=root)
84{
85postorder_traverse_recursive(root->left);
86postorder_traverse_recursive(root->right);
87printf("%d\t",root->elem);
88}
89}
程序测试结果如下:
现在来讨论一下如何采用非递归实现这以上三种遍历。
将递归形式转换为非递归形式,引入了额外的辅助结构栈。
另外在讨论一次二叉树的层次遍历,可以借助队列进行实现。
具体讨论如下:
(1)先根遍历非递归实现
先根遍历要求顺序是根左右,可以借助栈s来实现。
先将根root入栈,然后循环判断s是否为空,非空则将结点出栈,记为节点p,然后依次先将结点p的右子树结点入栈,然后将结点p的左子树结点入栈,循环操作直到栈中所有元素都出栈为止,出栈顺序即是先根遍历的结果。
采用C++中模板库stack实现先根遍历如下:
1voidpreorder_traverse(binary_treeroot)
2{
3if(NULL!
=root)
4{
5stack<binary_tree_node*>s;
6binary_tree_node*ptmpnode;
7s.push(root);
8while(!
s.empty())
9{
10ptmpnode=s.top();
11cout<<ptmpnode->elem<<"";
12s.pop();
13if(NULL!
=ptmpnode->right)
14s.push(ptmpnode->right);
15if(NULL!
=ptmpnode->left)
16s.push(ptmpnode->left);
17
18}
19}
20}
(2)中根遍历非递归实现
中根遍历要求顺序是左根右,借助栈s实现。
先将根root入栈,接着从根root开始查找最左的子孩子结点直到为空为止,然后将空节点出栈,再将左子树节点出栈遍历,然后判断该左子树的右子树节点入栈。
循环此过程,直到栈为空为止。
此时需要注意的是入栈过程中空结点也入栈了,用以判断左孩子是否结束和左孩子是否有右孩子结点。
采用C++中模板库stack实现先根遍历如下:
1voidinorder_traverse(binary_treeroot)
2{
3if(NULL!
=root)
4{
5stack<binary_tree_node*>s;
6binary_tree_node*ptmpnode;
7s.push(root);
8while(!
s.empty())
9{
10ptmpnode=s.top();
11while(NULL!
=ptmpnode)
12{
13s.push(ptmpnode->left);
14ptmpnode=s.top();
15}
16s.pop();//空结点出栈
17if(!
s.empty())
18{
19ptmpnode=s.top();
20cout<<ptmpnode->elem<<"";
21s.pop();
22//右子树结点如栈
23s.push(ptmpnode->right);
24}
25}
26}
27}
另外一种简洁的实现方法如下:
1voidinorder_traverse_two(binary_treeroot)
2{
3if(NULL!
=root)
4{
5stack<binary_tree_node*>s;
6binary_tree_node*ptmpnode;
7ptmpnode=root;
8while(NULL!
=ptmpnode||!
s.empty())
9{
10//将左子树结点入栈
11if(NULL!
=ptmpnode)
12{
13s.push(ptmpnode);
14ptmpnode=ptmpnode->left;
15}
16else
17{
18//出栈遍历
19ptmpnode=s.top();
20s.pop();
21cout<<ptmpnode->elem<<"";
22//右子树结点
23ptmpnode=ptmpnode->right;
24}
25}
26}
27}
(3)后根遍历递归实现
后根遍历要求访问顺序是左右根,采用辅助栈实现时,需要一个标记,判断结点是否访问了,因为右子树是通过跟结点的信息得到的。
实现过程是先将根结点及其左子树入栈,并初始标记为0,表示没有访问,然后通过判断栈是否为空和标记的值是否为1来判断是否访问元素。
参考:
采用C++模板库stack具体实现程序如下:
1voidpostorder_traverse(binary_treeroot)
2{
3if(NULL!
=root)
4{
5stack<binary_tree_node*>s;
6binary_tree_node*ptmpnode;
7intflags[100];
8ptmpnode=root;
9while(NULL!
=ptmpnode||!
s.empty())
10{
11//将结点左子树结点入栈
12while(NULL!
=ptmpnode)
13{
14s.push(ptmpnode);
15flags[s.size()]=0;//标记未访问
16ptmpnode=ptmpnode->left;
17}
18//输出访问的结点
19while(!
s.empty()&&flags[s.size()]==1)
20{
21ptmpnode=s.top();
22s.pop();
23cout<<ptmpnode->elem<<"";
24}
25//从右子树开始遍历
26if(!
s.empty())
27{
28ptmpnode=s.top();
29flags[s.size()]=1;//登记访问了
30ptmpnode=ptmpnode->right;
31}
32else
33break;
34}
35}
36}
(4)层次遍历实现
层次遍历要求从根向下、从左向右进行访问,可以采用队列实现。
先将根入队,然后队列进程出队操作访问结点p,再将结点p的左子树和右子树结点入队,循环执行此过程直到队列为空。
出队顺序即是层次遍历结果。
采用C++的模板库queue实现如下:
1voidlevelorder_traverse(binary_treeroot)
2{
3if(NULL!
=root)
4{
5queue<binary_tree_node*>q;
6binary_tree_node*ptmpnode;
7q.push(root);
8while(!
q.empty())
9{
10ptmpnode=q.front();
11q.pop();
12cout<<ptmpnode->elem<<"";
13if(NULL!
=ptmpnode->left)
14q.push(ptmpnode->left);
15if(NULL!
=ptmpnode->right)
16q.push(ptmpnode->right);
17}
18}
19}
综合上面的分析过程写个完整的程序测试二叉树遍历的非递归实现,采用C++语言,借助stack和queue实现,完整程序如下所示:
1#include<iostream>
2#include<stack>
3#include<queue>
4#include<cstdlib>
5usingnamespacestd;
6
7typedefstructbinary_tree_node
8{
9intelem;
10structbinary_tree_node*left;
11structbinary_tree_node*right;
12}binary_tree_node,*binary_tree;
13
14voidinit_binary_tree(binary_tree*root);
15voidcreate_binary_tree(binary_tree*root);
16voidpreorder_traverse(binary_treeroot);
17voidinorder_traverse(binary_treeroot);
18voidinorder_traverse_two(binary_treeroot);
19voidpostorder_traverse(binary_treeroot);
20voidlevelorder_traverse(binary_treeroot);
21
22intmain()
23{
24binary_treeroot;
25create_binary_tree(&root);
26cout<<"preodrertraverse:
";
27preorder_traverse(root);
28cout<<"\ninodrertraverse:
";
29inorder_traverse_two(root);
30cout<<"\npostodrertraverse:
";
31postorder_traverse(root);
32cout<<"\nleverordertraverse:
";
33levelorder_traverse(root);
34exit(0);
35}
36
37voidinit_binary_tree(binary_tree*root)
38{
39*root=NULL;
40}
41
42voidcreate_binary_tree(binary_tree*root)
43{
44intelem;
45cout<<"Enterthenodevalue(0isend):
";
46cin>>elem;
47if(elem==0)
48*root=NULL;
49else
50{
51*root=(binary_tree)malloc(sizeof(binary_tree_node));
52if(NULL==root)
53{
54cout<<"mallocerror.\n";
55exit(-1);
56}
57(*root)->elem=elem;
58cout<<"Creatingtheleftchildnode.\n";
59create_binary_tree(&((*root)->left));
60cout<<"Createingtherightchildnode.\n";
61create_binary_tree(&((*root)->right));
62}
63}
64
65voidpreorder_traverse(binary_treeroot)
66{
67if(NULL!
=root)
68{
69stack<binary_tree_node*>s;
70binary_tree_node*ptmpnode;
71s.push(root);
72while(!
s.empty())
73{
74ptmpnode=s.top();
75cout<<ptmpnode->elem<<"";
76s.pop();
77if(NULL!
=ptmpnode->right)
78s.push(ptmpnode->right);
79if(NULL!
=ptmpnode->left)
80s.push(ptmpnode->left);
81
82}
83}
84}
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法导论 算法导论读书笔记之第10章 基本数据结构之二叉树 算法 导论 读书笔记 10 基本 数据结构 二叉