《算法导论》读书笔记之第10章 基本数据结构之二叉树.docx

上传人:b****3 文档编号:4472681 上传时间:2022-12-01 格式:DOCX 页数:17 大小:18.89KB
下载 相关 举报
《算法导论》读书笔记之第10章 基本数据结构之二叉树.docx_第1页
第1页 / 共17页
《算法导论》读书笔记之第10章 基本数据结构之二叉树.docx_第2页
第2页 / 共17页
《算法导论》读书笔记之第10章 基本数据结构之二叉树.docx_第3页
第3页 / 共17页
《算法导论》读书笔记之第10章 基本数据结构之二叉树.docx_第4页
第4页 / 共17页
《算法导论》读书笔记之第10章 基本数据结构之二叉树.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

《算法导论》读书笔记之第10章 基本数据结构之二叉树.docx

《《算法导论》读书笔记之第10章 基本数据结构之二叉树.docx》由会员分享,可在线阅读,更多相关《《算法导论》读书笔记之第10章 基本数据结构之二叉树.docx(17页珍藏版)》请在冰豆网上搜索。

《算法导论》读书笔记之第10章 基本数据结构之二叉树.docx

《算法导论》读书笔记之第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模板 > 图表模板

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1