0二叉树也可以采用两种存储方式:顺序存储结构和链式存储结构
1. 顺序存储结构
这种存储结构适用于完全二叉树。其存储形式为:用一组连续的存储单元按照完全二叉树的每个结点编号的顺序存放结点内容。下面是一棵二叉树及其相应的存储结构。
2. 链式存储结构
在顺序存储结构中,利用编号表示元素的位置及元素之间孩子或双亲的关系,因此对于非完全二叉树,需要将空缺的位置用特定的符号填补,若空缺结点较多,势必造成空间利用率的下降。在这种情况下,就应该考虑使用链式存储结构。
这种存储结构的特点是寻找孩子结点容易,双亲比较困难。因此,若需要频繁地寻找双亲,可以给每个结点添加一个指向双亲结点的指针域,其结点结构如下所示。
二叉树的遍历:
二叉树是一种非线性的数据结构,在对它进行操作时,总是需要逐一对每个数据元素实施操作,
这样就存在一个操作顺序问题,由此提出了二叉树的遍历操作。
所谓遍历二叉树就是按某种顺序访问二叉树中的每个结点一次且仅一次的过程。
这里的访问可以是输出、比较、更新、查看元素内容等等各种操作。
二叉树的遍历方式分为两大类:一类按根、左子树和右子树三个部分进行访问;
另一类按层次访问。
1. 按根、左子树和右子树三部分进行遍历
TLR(根左右)、LTR(左根右)和LRT(左右根)根据根访问的位置不同分别被称为先序遍历、中序遍历和后序遍历。
(1)先序遍历:
若二叉树为空,则结束遍历操作;否则按照顺序:
访问根结点;
先序遍历左子树;
先序遍历右子树。
(2)中序遍历
若二叉树为空,则结束遍历操作;否则按照顺序:
中序遍历左子树;
访问根结点;
中序遍历右子树。
(3)后序遍历
若二叉树为空,则结束遍历操作;否则按照顺序:
后序遍历左子树;
后序遍历右子树;
访问根结点。
注意:
上面三中的遍历方法中,若某个结点缺少左孩子或者右孩子的话,就将其补齐
可以用“空”补齐,补齐之后再用上面的三种方法更加思路清晰
都是按照先左后右的顺序进行的
先序序列: ABDGCEF
中序序列: 空DGB空AECF
简化之后即为: DGBAECF
后序序列: 空GD空BEFCA
简化之后即为: GDBEFCA
由此可以看出:
(1)遍历操作实际上是将非线性结构线性化的过程,其结果为线性序列,
并根据采用的遍历顺序分别称为先序序列、中序序列或后序序列;
(2)遍历操作是一个递归的过程,因此,这三种遍历操作的算法可以用递归函数实现。
2. 按层次遍历二叉树
实现方法为从上层到下层,每层中从左侧到右侧依次访问每个结点。下面我们将给出一棵二叉树及其按层次顺序访问其中每个结点的遍历序列。
层次遍历算法设计思路:
使用一个队列
1、将根结点进队;
2、队不空时循环:从队列中出列一个结点p,访问它;
若它有左孩子结点,将左孩子结点进队;
若它有右孩子结点,将右孩子结点进队。
二叉树的建立:
如何把二叉树存入电脑内?
例:将下面的二叉树以二叉链表形式存入计算机内。
注意:标空的先序遍历序列能够唯一确定一颗二叉树
建树算法:
Status CreateBiTree( BiTree &T ){ //构造二叉树T
scanf("%c",&ch);
if(ch==' ')T=NULL;
else{
if(!(T=( BiTNode*)malloc(sizeof(BiTNode))))exit(overflow);
T->data=ch; //生成根结点
CreateBiTree(T->lchild); //构造左子树
CreateBiTree(T->rchild); //构造右子树
} return OK;
} //CreateBiTree
已知一棵二叉树的先根和中根遍历序列如下,画出此二叉树。
先根遍历序列:A B C I D E H F J G
中根遍历序列:B I C A H E J F G D
二叉树中序遍历的非递归算法:
void InOrder1(BTNode *b)
{ BTNode *p; SqStack *st; //定义一个顺序栈指针st
InitStack(st); //初始化栈st
p=b;
while (!StackEmpty(st) || p!=NULL)
{ while (p!=NULL) //扫描结点p的所有左下结点并进栈
{ Push(st,p); //结点p进栈
p=p->lchild; //移动到左孩子
}
//以下考虑栈顶结点
if (!StackEmpty(st)) //若栈不空
{ Pop(st,p); //出栈结点p,访问结点p
printf("%c ",p->data);
p=p->rchild; //转向处理其右子树
}
}
printf("\n");
DestroyStack(st); //销毁栈
}
如何确定一颗唯一的二叉树?
有如下几种方法:
标空的先序序列
标空的后序序列
先序序列+中序序列
后序序列+中序序列