前几天被面试官问到了二叉树,因为没有去复习所以回答的很糟糕,数据结构是大二的时候学的,在平时的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 ); //访问节点数据
}
}
未完待续。