c语言二叉树根节点存储什么,动画:二叉树有几种存储方式?

原标题:动画:二叉树有几种存储方式?

来自公众号:小鹿动画学编程

写在前边

今天和大家主要分享的是树这种数据结构。

树这种数据结构不像数组、链表一样,它是一种非线性结构,学起来可能比其他数据结构比较吃力,但是它在数据结构中占有很重要的地位,也是面试中的频繁考点,尤其是二叉树,一定注重起来。

由题目抛出的问题,树到底怎么存储呢?二叉树有几种存储方式呢?如果带着好奇心学习,学习更加的高效,一颗树横七竖八的,咋表示?一起来探索。

1

什么是树?

顾名思义,第一想到的就是路边的树,有树干、树根、树叶,数据结构中的树也是这样延伸过来的,只不过专用名词不一样,直接上图。

3422dedaee9fbda7e0db38a2346571f8.png

有一些树的专属名词我们总结下,A 是 B 的父节点,B 是 A 的子节点,D 是 B 的兄弟节点,C 和 D 称为叶子节点,A 为根节点。

是树它就有高度,数据结构中的树不仅有高度的概念,还有树的深度、层,节点的高度、深度等,一些最基本的知识点。

高度

树的高度就是根节点到叶子节点的最长路径。节点的高度就是节点到叶子节点的高度。

深度

节点的深度就是该节点到根节点的路径,也就是边的数量。

根节点为第一层,依次往下递增。

PS:注意各个概念的方向和起始值。

9f8b5238fb87e630d1277436f975d2bb.gif

2

什么是二叉树?

我们知道什么是树了,二叉树的概念,就是给树做了一个限制,除了叶子结点,其余每个节点仅且只有两个子节点(也就是只有两个叉)。

441b5c8418b3c92fdf9d02245ab7146f.png

二叉树有两个很重要的形态就是满二叉树和完全二叉树。

满二叉树:叶子节点全都在最底层,除了叶子节点之外,每个节点都有左右两个子节点,这种二叉树就叫作满二叉树。

127157b107366089e2236774c87e4351.png

完全二叉树:叶子节点都在最底下两层 ,最后一层的叶子节点都靠左排列,并且除了最后一层,其他层的节点个数都要达到最大。

b0ad562edf0e8dce57c1ead51f894bdd.png

3

二叉树的存储方式有几种?

既然我们都基本了解了二叉树的概念和基本常识,那我们要用,就要进行存储,如何存储一颗二叉树呢?

还记不记得小鹿之前的几篇文章一直强调说过,所有基本常见的数据结构都是由数组和链表演变而来,栈有顺序栈和链式栈、队列有顺序队列和链式队列,那么树可以用数组存储也可以用链表存储呀。

链式存储法

基于指针的链式存储,每个树的节点都是由数据域和两个指针域组成的。数据域用来存储数据,指针域用来存储左右两个子节点。

3787b1e00bbe572e301782735cff53ad.png

顺序存储法

顺序存储就是用数组来存储的,虽然不如指针域那么直观,但是存储的方法挺好理解的。根节点存储在下标 i = 1的位置;左子节点存储在下标i * 2 = 2的位置,右子节点存储在i * 2 + 1 =3的位置。

40eca2b9ab8eb36107213dbdc4177278.png

你会问,两种方式有什么区别,这个问题其实你早就知道了,如果你看到过小鹿之前写的文章,就知道区别就是数组和链表的区别。

数组的方式存储不需要开辟额外的指针空间,但是数组需要的内存空间是连续的,如果连续的内存空间不足,就无法进行存储。

4

二叉树的遍历

既然存储方式你也学会了,那么我们看看二叉树存储的数据,我们如何遍历出来呢?

共有四种遍历的方式,分别为前序遍历、中序遍历、后序遍历、按层遍历。

这个前、中、后遍历,初学者最不容易理解,当初小鹿学习的时候也是这样,那我用最简单的步骤和图来讲述一下。

我们以前序遍历为例子,首先我要告诉你前序遍历的规则,就是先遍历根节点、然后遍历左子节点最后遍历右子节点,上图:

89b930f402a7c276a4ba27ec0902a889.png

这个图,你很快就能知道前序遍历的顺序,答案为:A->B->C

但是我换一张图,你来前序遍历下。

17966a537f43bb04c39e77d71871ef41.png

你可能就懵逼了,咋和刚才的不一样?我就是按照刚才那样遍历的?无论你是否成功遍历,小鹿来讲一下自己的思路。

我们还是看根节点的三个节点,按照根、左、右,我们知道先输出根节点 A、然后输出左子节点,因为 B 作为 D 和 E 的根节点先输出,然后 B 的左子节点是 D,D 作为 F 的根节点也要输出 D。

然后开始遍历左子节点,D 根节点的左子节点为 F,所以输出 F, B 的左子节点已经输出完毕,所以遍历右子节点 E。那么整个 A 的左子节点已经全部输出完毕,开始遍历 A 额右子节点。

还是按照左、根、右的遍历方法,依次输出去 C、H。整体的前序遍历为:A->B->D->F->E->C->H。动画如下:

10dfc803ddf4860df3d7c6d6ed9e10a7.gif

前序遍历小鹿讲的很详细了,剩下的中序遍历和后续遍历的规则不一样。中序遍历先遍历左子节点,然后是根节点,最后是右子节点。而后序遍历的顺序是先遍历左子结点,然后遍历右子节点,最后遍历根节点。

其实和前序遍历道理都是一样的,只不过是换汤不换药,我把动图放到下放了,自己可以对照着遍历一下。

601d5bfe845f97b5936aec14f8b9044f.gif

74ace2871f7c7c6cb0132fd69225cb41.gif

5

代码实现

Java 版本

1//遍历二叉查找树

2//前序遍历

3preorderTraversal = (tree) =>{

4//判断树是否为空

5if(tree == null) returnfalse;

6//根节点

7console.log(tree. data)

8//左子树

9this.preorderTraversal(tree.left)

10//右子树

11this.preorderTraversal(tree.right)

12}

13

14//中序遍历

15inorderTraversal = (tree) =>{

16//判断树是否为空

17if(tree == null) returnfalse;

18//左子树

19this.inorderTraversal(tree.left);

20//根节点

21console.log(tree. data)

22//右节点

23this.inorderTraversal(tree.right);

24}

25

26//后序遍历

27postorderTraversal = (tree) =>{

28//判断树是否为空

29if(tree == null) returnfalse;

30//左子树

31this.postorderTraversal(tree.left);

32//右子树

33this.postorderTraversal(tree.right);

34//根节点

35console.log(tree. data)

36}

Java 版本

1/**

2* 时间:2019/2/24

3* 功能:前序遍历

4* @param root 树的根节点

5*/

6publicvoidpreorderTraversal(Node root){

7//如果树为空

8if(root == null) return;

9//根节点

10System. out.print(root.data + " ");

11//左子树

12inorderTraversal(root.left);

13//右子树

14inorderTraversal(root.right);

15

16}

17

18/**

19* 时间:2019/2/24

20* 功能:中序遍历

21* @param root 树的根节点

22*/

23publicvoidinorderTraversal(Node root){

24//如果树为空

25if(root == null) return;

26//左子树

27inorderTraversal(root.left);

28//根节点

29System. out.print(root.data + " ");

30//右子树

31inorderTraversal(root.right);

32

33}

34

35/**

36* 时间:2019/2/24

37* 功能:后序遍历

38* @param root 树的根节点

39*/

40publicvoidpostorderTraversal(Node root){

41//如果树为空

42if(root == null) return;

43//左子树

44inorderTraversal(root.left);

45//右子树

46inorderTraversal(root.right);

47//根节点

48System. out.print(root.data + " ");

49

50}

Python 版本

1classBTree(object):

2def__init__(self):

3self._root = None

4self._size = 0

5

6defpreOrder(self):

7'''

8先遍历顺序:前序遍历

91,根节点

102,遍历左子树

113,遍历右子树

12'''

13btree = []

14

15defrecurse(node):

16ifnode != None:

17btree.append(node.data)

18recurse(node.lft)

19recurse(node.rgt)

20

21recurse(self._root)

22returnbtree

23

24classBTree(object):

25def__init__(self):

26self._root = None

27self._size = 0

28

29defpreOrder(self):

30'''

31先遍历顺序:中序遍历

321,根节点

332,遍历左子树

343,遍历右子树

35'''

36btree = []

37

38defrecurse(node):

39ifnode != None:

40btree.append(node.data)

41recurse(node.lft)

42recurse(node.rgt)

43

44recurse(self._root)

45returnbtree

46

47classBTree(object):

48def__init__(self):

49self._root = None

50self._size = 0

51

52# 后序遍历

53defpostOrder(self):

54'''

55后序遍历顺序:后续遍历

561,遍历左子树

572,遍历右子树

583,根节点

59'''

60btree = []

61

62defrecurse(node):

63ifnode != None:

64recurse(node.lft)

65recurse(node.rgt)

66btree.append(node.data)

67

68recurse(self._root)

69returnbtree

C 语言版本

1#include

2#include

3

4/* 定义数据类型 */

5typedefcharTypeData ;

6

7/* 定义二叉树 */

8typedefstructstBiTreeNode

9{

10TypeData data;

11structstBiTreeNode*lchild, *rchild;

12}BITREENODE;

13

14/* 初始化二叉树 */

15BITREENODE* createBiTree

16{

17charchTempData = 0;

18

19BITREENODE *pstNewNode = NULL;

20

21scanf( "%c",&chTempData);

22if(chTempData == '#')

23{

24pstNewNode = NULL;

25}

26else

27{

28/* 分配内存 */

29pstNewNode = (BITREENODE*) malloc( sizeof(BITREENODE) + 1);

30pstNewNode->data = chTempData;

31

32/* 递归调用产生二叉树 */

33pstNewNode->lchild = createBiTree;

34pstNewNode->rchild = createBiTree;

35}

36

37returnpstNewNode;

38}

39

40/* 前序遍历二叉树 */

41intpreVisitBiTree(BITREENODE* InRoot)

42{

43if(InRoot)

44{

45/* 先遍历根节点 */

46printf( "%c ",InRoot->data);

47

48/* 遍历左子树 */

49preVisitBiTree(InRoot->lchild);

50

51/* 遍历右子树 */

52preVisitBiTree(InRoot->rchild);

53

54}

55return0;

56}

57

58

59/* 中序遍历二叉树 */

60intinVisitBiTree(BITREENODE* InRoot)

61{

62if(InRoot)

63{

64/* 遍历左子树 */

65preVisitBiTree(InRoot->lchild);

66

67

68/* 先遍历根节点 */

69printf( "%c ",InRoot->data);

70

71/* 遍历右子树 */

72preVisitBiTree(InRoot->rchild);

73

74}

75return0;

76}

77

78/* 后序遍历二叉树 */

79intpostVisitBiTree(BITREENODE* InRoot)

80{

81if(InRoot)

82{

83/* 遍历左子树 */

84preVisitBiTree(InRoot->lchild);

85

86

87/* 遍历右子树 */

88preVisitBiTree(InRoot->rchild);

89

90

91/* 先遍历根节点 */

92printf( "%c ",InRoot->data);

93

94}

95return0;

96}

6

小结

今天小鹿分享了二叉树的基础部分,二叉树的基本概念以及二叉树的存储方式,还有二叉树的前中后遍历,最后留一个问题就是,二叉树除了前中后序遍历外,还有按层遍历,可以自己去探索一下二叉树按层是怎么遍历的?

●编号1081,输入编号直达本文返回搜狐,查看更多

责任编辑:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值