赞
踩
用一组连续的存储单元自上而下,自左至右存储完全二叉树上的结点元素,完全二叉树上编号为i的结点元素存储在一维数组中下标为i-1的分量中,即数组的第0位存储根结点。
满二叉树和完全二叉树,用顺序存储比较合适,树中结点的序号可以位移反映出结点简的逻辑关系,这样既能最大可能得节省存储空间,又可以利用数组元素的下标,确定结点在二叉树中的位置以及结点间的逻辑关系。
例:将如下二叉树使用顺序存储:
其存储结果如下:
链式存储结构的示意图如下:
其中:lchild用于指向结点的左孩子,rchild用于指向结点的右孩子
链式存储结构的结构体如下:
tyepedef struct BiNode{
ElemType data;
struct BiNode *lchild;
struct BiNode *rchild;
}BiNode,*BITree;
树的链式存储示意图如下图所示:
1.先序遍历
访问顺序:根结点-左子树-右子树
void PreOrder (BiTree T){
if(T!=NULL){
visit(T); //实际运行代码的时候可以写成printf(.....)
preorder(T->lchild); //访问左子树
preorder(T->rchild); //访问右子树
}
}
2.中序遍历
访问顺序:左子树-根结点-右子树
void InOrder (BiTree T){
if(T!=NULL){
InOrder(T->lchild);
visit(T); //实际运行代码的时候可以写成printf(.....)
InOrder(T->rchild);
}
}
3.后序遍历
访问顺序:左子树-右子树-根结点
void PostOrder(BiTree T){
if(T!=NULL){
PostOrder(T->lchild;)
PostOrder(T->rchild;)
visit(T); //实际运行代码的时候可以写成printf(.....)
}
}
1.先序非递归遍历:
基本思路:
1.遇到一个顶点,访问,然后压栈,并遍历左子树。
2.左子树遍历结束后,从栈顶弹出该结点并指向其右孩子,继续步骤1。
3.当所有的结点访问完即最后访问的树结点为空且栈空时,停止。
void preorder2(BiTree ti){
InitStack(s); //初始化栈
Bitree t=ti;
while(t||!IsEmpty(s)){
while(t){
printf("%d\n",t->data); //访问结点
push(s,t); //进栈
t=t->lchild;
}
if(!IsEmpty(s)){
pop(s,t); //出栈
t=t->rchild;
}
}
}
2.中序非递归遍历
中序递归遍历路径与先序遍历完全一样,思路与先序遍历也非常相似,其主要的不同点是访问结点顺序不同,中序遍历结点的访问顺序为:左孩子-根结点-右孩子
void InOrder2(BiTree ti){
InitStack(s); //初始化栈
Bitree t=ti;
while(t||!IsEmpty(s)){
while(t){
push(s,t); //进栈
t=t->lchild;
}
if(!IsEmpty(s)){
pop(s,t); //出栈
printf("%d\n",t->data); //访问结点
t=t->rchild;
}
}
}
3.后序非递归遍历
对于一个结点而言,要实现顺序为左孩子-右孩子-根结点,也可以利用栈,在结点不为空的前提下,依次将根结点-右孩子-左孩子压栈,然后出栈即可得到序列左孩子-右孩子-根结点(即后序遍历的顺序),所以可以直接按照根结点-右孩子-左孩子这个顺序遍历整个树,然后将遍历结果依次压栈,然后再统一出栈即可。我们知道,先序遍历的遍历顺序是根结点-左孩子-右孩子,与我们需要的顺序的差别仅仅是先访问左孩子还是右孩子的问题,因此我们可以参考先序遍历的结构,将先序遍历的左右调换顺序即可。然后我们将得到结果入栈即可。接下来我们考虑问题,在先序遍历中,我们是将访问结点的结果直接打印出来,但是在后序遍历中我们需要结果入栈,即我们还需将先序遍历中的访问方式(printf)修改为压入另一个栈中即可,其代码如下:
void postorder2(BiTree ti){ InitStack(s1); //s1用于存储结点 InitStack(s2); //s2用于存储访问结果 Bitree t=ti; while(t||!IsEmpty(s1)){ while(t){ //printf("%d\n",t->data); //先序遍历中的printf(...),现在改成push(s2,t); push(s2,t); //将访问结果依次入栈 push(s1,t); //将结点依次入栈 t=t->rchild; //先访问右子树 } if(!IsEmpty(s1)){ pop(s1,t); t=t->lchild; //访问右子树以后访问左子树 } } while(!IsEmpty(s2)){ //将s2存储的访问结果依次出栈,得到左孩子-右孩子-根结点的序列 pop(s2,t); printf("%d\n",t->data); t=s2.top(); } }
二叉树的层次遍历实现方式:现将二叉树的根结点入队,然后出队,访问刚才出队的结点,如果该结点有左子树,则将左子树入栈,如果该结点有右子树,再将右子树入栈;然后将对头结点出队,然后访问该结点,然后判断该节点的左右子树情况,不断重复这个过程,直至队列为空为止。
其代码如下:
void levelorder(Bitree ti){
Bitree t=ti;
InitQueue(Q); //初始化队列
EnQueue(t); //根结点入队
while(!IsEmpty(Q)){
DeQueue(Q,t); //队头元素出队
visit(t); //访问该结点
if(t->lchild!=NULL){ //判断左子树情况
EnQueue(t->lchild);
}
if(t->rchild!=NULL){ //判断右子树情况
EnQueue(t->rchild);
}
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。