超清晰-数据结构之树与二叉树

  前几天被面试官问到了二叉树,因为没有去复习所以回答的很糟糕,数据结构是大二的时候学的,在平时的web开发我能用到的机会其实不多,所以也没有去整理,但是数据结构也是程序的灵魂架构,是需要认真研究的,故在此继续进行整理复习。

  一、什么是树?

1.1  树是n(n>=0)个结点的有限集,根据结点数可分为空树(n=0)或非空树(n>0),对于非空的树T,有着两个定义:

(1)有且仅有一个称之为根的结点;

(2)除根结点以外的其余结点可分为m(m>0)个互不相交的有限集T1,T2,...,Tm,其中每个集合本身又是一个树,并且又称之为根的子树。

常见的树如下图:

1.2 常见的树基本术语:

(1)结点:树中的一个独立单位。包含一个数据元素及若干指向其子树的分支,如图中的每个字母都是一个结点。

(2)结点的度:结点所拥有的子树数称为结点的度,如D的度为3,E的度数为1。

(3)树的度:树的度是树内各结点度的最大值,上图的树的度为3.

(4)叶子:度为0的结点称为叶子或终端结点。如上图的G,H,I,J,F.

(5)非终端结点:度不为0的结点称为非终端结点或分支结点。除根结点之外,也称为内部结点。如上图的A,B,C,D,E.

(6)双亲和孩子:若一个结点含有子结点,则这个结点称为其子节点的双亲节点。如上图的D的双亲结点为B

(7)兄弟:具有同个双亲的结点互为兄弟结点。如上图的G,I,H

(8)祖先:从根到该结点所经分支上的所有结点。如上图的J的祖先为A,C,E

(9)子孙:以某个结点为根的子树中的任一结点都是该根结点的子孙。如上图B的子孙有D,G,H,I

(10)层次:结点的层次从根开始定义,如上图的层次说明。

(11)堂兄弟:双亲在同一层的结点互为堂兄弟。例如结点D的堂兄弟为E,F.

(12)树的深度:树中结点的最大层次称之为树的深度或高度。如上图的深度为4.

(13)有序树和无序树:如果将树中结点的各子树看成从左至右是由次序的,则称该树的为有序树,否则为无序树。

 

二、什么是二叉树?

 2.1  二叉树是一种特殊的树,主要有着以下两个特点:

(1)有且仅有一个称之为根的结点;

(2)除根结点以外的其余结点分为两个互不相交的子集T1和T2,分别称为T的左子树和右子树,且T1和T2本身又都是二叉树。

2.2 二叉树的遍历

三种遍历方式:

①先序遍历(根左右)②中序遍历(左根右)③后序遍历 (左右根)        (这个面试有问到。)

 (1)先序遍历:1.访问根结点  2.先序遍历左子树  3.先序遍历右子树

如上图的先序遍历为:ABDGCEF

(2)中序遍历:1.中序遍历左子树 2.访问根结点 3.中序遍历右子树

如上图的中序遍历为:DGBAECF

(3)后序遍历:1.后序遍历左子树 2.后序遍历右子树  3.访问根结点

如上图的后序遍历为:GDBEFCA

三、 二叉树的存储结构

3.1 ①顺序存储结构  ②链式存储结构

(1)顺序存储结构

实际上就是用一个一维数组按照自上而下,自左至右的将每一层的结点放入数组中,

二叉树的顺序存储表示:

#define MAXSIZE 100
typedef TElemType SqBiTree[MAXSIZE];
SqBiTree bt;

这时候如果你对c的typedef不熟悉的话可能不是很明白上面的这种写法。实际上这里用到了typedef定义数组的方式。

假设为 typedef int sqBiTree[10]  ,SqBiTree bt ,相当于定义一个int bt[10].

如上图的图示顺序存储结构差不多是这样的。

图画的很丑将就点看吧,其中0表示为空,我们可以很直观就可以看出这种存储方式的弊端,如果二叉树不是完全二叉树的话,是会有很大的空间浪费的。这种方式唯一的特点就是比较简单容易理解,但是实际上,我们很少会使用顺序存储方式,

(2)链式存储方式

实际上就是一个链表,链表的结点至少得包含三个域:数据域和左右指针域(为了方便找到结点的双亲,还可以在结点的结构中增加一个指向其双亲结点的指针域)

二叉树的链式存储表示:

typedef struct BiTNode{
  TElemType data;        //结点的数据域
  struct BiTNode *lchild,*rchild; //左右孩子指针
}BiTNode,*BiTree;

把上面的图复制下来:

3.2 二叉树的三种遍历伪代码实现(递推形式)

先序:

void preOrder(BitTree t)      //先序遍历
{
    if(t)             //树不为空
    {
        visit(t->data );        //访问节点数据,自定义访问函数visit
        preOrder (t->lchild );      //递归遍历左子树
        preOrder (t->rchild );      //递归遍历右子树
    }
}

中序:

void inOrder(BitTree t)       //中序遍历
{ 
    if(t)          //树不为空
    {
        inOrder (t->lchild );
        visit(t->data );        //访问节点数据
        inOrder (t->rchild );
    }
}

后序:

void postOrder(BitTree t)     //后序遍历
{
    if(t)           //树不为空
    {
        postOrder (t->lchild );
        postOrder (t->rchild );
        visit(t->data );        //访问节点数据
    }
}

未完待续。

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MClink

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值