一波二叉树遍历问题的C++解答实例分享
题目一:
输入一颗二元树,从上往下按层打印树的每个节点,同一层按照从左往右的顺序打印。
输入样例:
8 // 610 //// 57911
输出样例:
861057911
思路分析:
把一颗二叉树抽象成三个节点:根节点、左节点、右节点。
先序遍历即可得到按行输出的效果。
对于左子树只要保存其根节点,既保存了整个左子树。(右子树一样)
对于根节点之外的两个子树来说说,始终是先访问左子树的根节点,再访问右子树的根节点。
因此可以使用队列存储。
代码实现(GCC编译通过):
#include"stdio.h" #include"stdlib.h" //二叉树节点 #definesize7 //二叉树节点定义 typedefstructnode { intdata; structnode*left; structnode*right; }BTree; intprintLine(BTree*root); BTree*CreatTree(inta[],intn); intmain(void) { intarray[size]={8,6,10,5,7,9,11}; BTree*root; root=CreatTree(array,size); printLine(root); printf("\n"); return0; } intprintLine(BTree*root) { BTree*queue[size],*p; intfront,rear; front=rear=0; rear=(rear+1)%size; queue[rear]=root; //循环结束为队列为空 while(front!=rear) { //根出队列 front=(front+1)%size; p=queue[front]; printf("%3d",p->data); //左孩子不空,队不满入队 if(p->left&&((rear+1)%size!=front)) { rear=(rear+1)%size; queue[rear]=p->left; } //右孩子不空,队不满入队 if(p->right&&((rear+1)%size!=front)) { rear=(rear+1)%size; queue[rear]=p->right; } //队满,报错 if((rear+1)%size==front) { printf("队列空间不足,错误....\n"); return0; } } return1; } //根据数组创建二叉排序树 BTree*CreatTree(inta[],intn) { BTree*root,*p,*cu,*pa; inti; root=(BTree*)malloc(sizeof(BTree)); root->data=a[0]; root->left=root->right=NULL; for(i=1;i<n;i++) { p=(BTree*)malloc(sizeof(BTree)); p->data=a[i]; p->left=p->right=NULL; cu=root; while(cu) { pa=cu; if(cu->data>p->data) cu=cu->left; else cu=cu->right; } if(pa->data>p->data) pa->left=p; else pa->right=p; } returnroot; }
题目二:
输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果。
如果是返回true,否则返回false。
例如输入5、7、6、9、11、10、8,由于这一整数序列是如下树的后序遍历结果:
8 /\ 610 /\/\ 57911
因此返回true。
如果输入7、4、6、5,没有哪棵树的后序遍历的结果是这个序列,因此返回false。
思路:
二叉查找的特征:左子树的各个值均小于根,右子树的各个值均大于跟
后序遍历的特征:最后一个是根,便利顺序,左右跟。递归
好了,总结可以得到:
最后一个是根,最开始连续若干个数小于根的是左子树的节点,之后连续若干个大于根的是右子树的节点(左右子树都可能为空),然后递归描述。
代码描述如下(GCC编译通过):
#include"stdio.h" #include"stdlib.h" intisPostorderResult(inta[],intn); inthelper(inta[],ints,inte); intmain(void) { inta[7]={5,7,6,9,11,10,8}; intb[4]={7,4,6,5}; inttmp; tmp=isPostorderResult(a,7); printf("%d",tmp); return0; } intisPostorderResult(inta[],intn) { returnhelper(a,0,n-1); } inthelper(inta[],ints,inte) { inti,j,root; if(s==e) return1; for(i=0;i<e&&a[i]<a[e];i++); if(i!=0&&helper(a,s,i-1)==0) return0; for(j=i;j<e&&a[j]>a[e];j++); if(j==e&&helper(a,i,j-1)==1) return1; else return0; }
题目三:
输入一颗二元查找树,将该树转换为它的镜像,即在转换后的二元查找树中,左子树的结点都大于右子树的结点。
用递归和循环两种方法完成树的镜像转换。
例如输入:
8 /\ 610 /\/\ 57911
输出:
8 /\ 106 /\/\ 11975
分析:
递归程序设计比较简单
访问一个节点,只要不为空则交换左右孩子,然后分别对左右子树递归。
非递归实质是需要我们手动完成压栈,思想是一致的
代码如下(GCC编译通过):
#include"stdio.h" #include"stdlib.h" #defineMAXSIZE8 typedefstructnode { intdata; structnode*left; structnode*right; }BTree; voidswap(BTree**x,BTree**y);//交换左右孩子 voidmirror(BTree*root);//递归实现函数声明 voidmirrorIteratively(BTree*root);//非递归实现函数声明 BTree*CreatTree(inta[],intn);//创建二叉树(产生二叉排序树) voidIorder(BTree*root);//中序遍历查看结果 intmain(void) { intarray[MAXSIZE]={5,3,8,7,2,4,1,9}; BTree*root; root=CreatTree(array,MAXSIZE); printf("变换前:\n"); Iorder(root); printf("\n变换后:\n");//两次变换,与变化前一致 mirror(root); mirrorIteratively(root); Iorder(root); printf("\n"); return0; } voidswap(BTree**x,BTree**y) { BTree*t=*x; *x=*y; *y=t; } voidmirror(BTree*root) { if(root==NULL)//结束条件 return; swap(&(root->left),&(root->right));//交换 mirror(root->left);//左子树递归 mirror(root->right);//右子树递归 } voidmirrorIteratively(BTree*root) { inttop=0; BTree*t; BTree*stack[MAXSIZE+1]; if(root==NULL) return; //手动压栈、弹栈 stack[top++]=root; while(top!=0) { t=stack[--top]; swap(&(t->left),&(t->right)); if(t->left!=NULL) stack[top++]=t->left; if(t->right!=NULL) stack[top++]=t->right; } } //产生二叉排序树 BTree*CreatTree(inta[],intn) { BTree*root,*p,*cu,*pa; inti; root=(BTree*)malloc(sizeof(BTree)); root->data=a[0]; root->left=root->right=NULL; for(i=1;i<n;i++) { p=(BTree*)malloc(sizeof(BTree)); p->data=a[i]; p->left=p->right=NULL; cu=root; while(cu) { pa=cu; if(cu->data>p->data) cu=cu->left; else cu=cu->right; } if(pa->data>p->data) pa->left=p; else pa->right=p; } returnroot; } //中序遍历 voidIorder(BTree*root) { if(root) { Iorder(root->left); printf("%3d",root->data); Iorder(root->right); } }