试题1(王道5.3.3节第16题):
设计算法将二叉树的叶结点按从左到右的顺序连成单链表,连接时使用叶结点的右指针域存放单链表指针。
借助遍历算法完成:
- //根据二叉树层次遍历序列构造单链表
- void LevelOrdertoLinkList(BiTree &T){
- Queue q;
- InitQueue(q);
- BiTree p = T;
- BiTree pre = NULL;
- InsertQueue(q, p);
- while(!IsQueueEmpty(q)){
- p = DeleteQueue(q, p);
- if(p->lchild!=NULL)
- InsertQueue(q, p->lchild);
- if(p->rchild!=NULL)
- InsertQueue(q, p->rchild);
- if(pre!=NULL){
- pre->lchild = NULL;
- pre->rchild = p;
- }
- pre = p;
- }
- }
-
- //单链表打印函数,作为验证
- void PrintLinkTree(BiTree T){
- BiTree p = T;
- while(p!=NULL){
- printf("%c", p->data);
- p = p->rchild;
- }
- }
-
- int main(){
- BiTree T;
- printf("输入二叉树的前序序列,#代表空子树:\n");
- CreateBiTree(T);
- printf("二叉树创建成功!\n");
- LevelOrdertoLinkList(T);
- PrintLinkTree(T); //打印生成的单链表
- return 0;
- }
输出:
- 输入二叉树的前序序列,#代表空子树:
- ABDF###E##C##
- 二叉树创建成功!
- ABCDEF
试题2(王道5.3.3节第17题):
设计算法判断两棵二叉树是否相似。
- //判断两个二叉树是否相似
- bool Similar(BiTree T1,BiTree T2){
- if(T1 != NULL&&T2 == NULL){
- return false;
- }
- else if(T1 == NULL&&T2 != NULL){
- return false;
- }
- else if(T1 == NULL&&T2 == NULL)
- return true;
- else{
- return Similar(T1->lchild, T2->lchild) && Similar(T1->rchild, T2->rchild);
- }
- }
-
- int main(){
- BiTree T1;
- printf("输入二叉树T1的前序序列,#代表空子树:\n");
- CreateBiTree(T1);
- printf("二叉树T1创建成功!\n");
-
- while (getchar() != '\n'); //清空缓存区
-
- BiTree T2;
- printf("输入二叉树T2的前序序列,#代表空子树:\n");
- CreateBiTree(T2);
- printf("二叉树T2创建成功!\n");
-
- printf("%d", Similar(T1, T2));
- return 0;
- }
输出:
- 输入二叉树T1的前序序列,#代表空子树:
- AB##C##
- 二叉树T1创建成功!
- 输入二叉树T2的前序序列,#代表空子树:
- DE##F##
- 二叉树T2创建成功!
- 1
试题3(王道5.3.3节第18题):
写出在中序线索二叉树中查找指定结点在后序的前驱结点的算法。
我们先把二叉线索树写出来:
- //二叉线索树的结构体定义
- typedef struct BiTNode{
- ElemType data; //数据域
- BiTNode *lchild; //指向左子树根节点的指针
- BiTNode *rchild; //指向右子树根节点的指针
- int ltag, rtag;
- }BiTNode, *BiTree;
-
- //建立中序线索二叉树
- void InThread(BiTree &T,BiTree &pre){
- BiTree p = T;
- if(p!=NULL){
- InThread(p->lchild,pre);
- if(pre!=NULL && pre->rchild==NULL){
- pre->rchild = p;
- pre->rtag = 1;
- }
- if(p->lchild == NULL){
- p->lchild = pre;
- p->ltag = 1;
- }
- pre = p;
- InThread(p->rchild,pre);
- }
- }
-
- BiTree FirstNode(BiTree T){ //获取中序序列的第一个结点
- BiTree p = T;
- while(p->ltag == 0){
- p = p->lchild;
- }
- return p;
- }
-
- BiTree NextNode(BiTree p){ //求解结点在中序序列下的下一个结点
- if(p->rtag = 0)
- return FirstNode(p->rchild);
- else
- return p->rchild;
- }
-
- BiTree LastNode(BiTree p){ //求解结点在中序序列下的上一个结点
- if(p->ltag =0)
- return FirstNode(p->lchild);
- else
- return p->lchild;
- }
-
- //有了前两个函数我们就可以在中序线索二叉树中输出中序遍历序列
- void InorderTraverse3(BiTree T){
- BiTree p = FirstNode(T);
- printf("%c", p->data);
- while(p->rchild!=NULL){
- p = NextNode(p);
- printf("%c", p->data);
- }
- }
-
- int main(){
- BiTree T;
- BiTree p = NULL;
- printf("输入二叉树的前序序列,#代表空子树:\n");
- CreateBiTree(T);
- printf("二叉树创建成功!\n");
- InThread(T,p);
- p = FirstNode(T);
- printf("二叉树中序序列的第一个结点是:%c\n", p->data);
- printf("二叉树的中序遍历序列是:");
- InorderTraverse3(T);
- return 0;
- }
输出:
- 输入二叉树的前序序列,#代表空子树:
- ABDF###E##C##
- 二叉树创建成功!
- 二叉树中序序列的第一个结点是:F
- 二叉树的中序遍历序列是:FDBEAC
分以下几种情况:
(1)结点有右孩子——右孩子就是后序遍历的前驱结点;
(2)结点只有左孩子——左孩子是后序遍历的前驱结点;
(3)结点没有左右孩子——找中序遍历前驱结点的左孩子结点,找不到就继续往前直到找到有左孩子结点,或者就是第一个结点(左孩子指针为空)返回NULL。
- //求在中序线索二叉树中查找指定结点后序遍历的前驱
- BiTree FindPast(BiTree p){
- if(p->rtag == 0 && p->rchild != NULL)
- return p->rchild;
- else if(p->ltag == 0)
- return p->lchild;
- else if(p->ltag == 1 && p->lchild == NULL)
- return NULL;
- else{ //叶子结点
- while(p->ltag == 1 && p->lchild != NULL){
- p = p->lchild; //回溯
- }
- if(p->ltag == 0)
- return p->lchild;
- else
- return NULL;
- }
- }
-
- int main(){
- BiTree T;
- BiTree p = NULL;
- printf("输入二叉树的前序序列,#代表空子树:\n");
- CreateBiTree(T);
- printf("二叉树创建成功!\n");
- printf("二叉树的中序遍历序列是:");
- InOrderTraverse(T);
- printf("\n");
- printf("二叉树的后序遍历序列是:");
- PostOrderTraverse(T);
- printf("\n");
- InThread(T,p); //线索化
- BiTree q = T->rchild; //这行代码找测试结点,实际需要根据用例修改
- printf("结点%c的后序遍历序列的前驱结点是:%c", q->data, FindPast(q)->data);
- return 0;
- }
输出:
- 输入二叉树的前序序列,#代表空子树:
- A#B#C##
- 二叉树创建成功!
- 二叉树的中序遍历序列是:ABC
- 二叉树的后序遍历序列是:CBA
- 结点B的后序遍历序列的前驱结点是:C
-
- 输入二叉树的前序序列,#代表空子树:
- AB##C##
- 二叉树创建成功!
- 二叉树的中序遍历序列是:BAC
- 二叉树的后序遍历序列是:BCA
- 结点C的后序遍历序列的前驱结点是:B
试题4(2014年统考真题):

直接递归:
- //前序序列建立二叉树
- void CreateBiTree(BiTree &T){
- char ch;
- scanf("%c", &ch);
- if (ch == '#')
- T = NULL; //保证是叶结点
- else{
- T = (BiTree)malloc(sizeof(BiTNode));
- T->data = (int)ch; //生成结点(这里偷个懒直接强制转换)
- printf("%d", T->data);
- CreateBiTree(T->lchild); //构造左子树
- CreateBiTree(T->rchild); //构造右子树
- }
- }
-
-
- int WPLBiTree(BiTree T,int depth){
- if(T==NULL)
- return 0;
- else
- return T->data * depth + WPLBiTree(T->lchild, depth + 1) + WPLBiTree(T->rchild, depth + 1);
- }
-
- int main(){
- BiTree T;
- CreateBiTree(T);
- printf("二叉树建立成功!");
- printf("二叉树的带权路径长度是:%d", WPLBiTree(T,1));
- return 0;
- }
输出:
- 32##4##
- 515052二叉树建立成功!二叉树的带权路径长度是:255
试题5(2017年统考真题):

此题很显然要利用到二叉树的中序遍历算法。除根结点和叶结点外,遍历到其他结点时在遍历左子树前加上左括号,遍历完右子树后加上右括号。
- //本算法给表达式加括号
- void InOrderExpression(BiTree T){
- if(T!=NULL){
- if((T->lchild!=NULL||T->rchild!=NULL))
- printf("(");
- InOrderExpression(T->lchild);
- printf("%c", T->data);
- InOrderExpression(T->rchild);
- if((T->lchild!=NULL||T->rchild!=NULL))
- printf(")");
- }
- }
-
- int main(){
- BiTree T;
- printf("输入中缀表达式二叉树的前序序列:");
- CreateBiTree(T);
- printf("二叉树建立成功!\n");
- printf("二叉树的中序序列是:");
- InOrderTraverse(T);
- printf("\n");
- printf("二叉树的中序序列(加括号)是:");
- InOrderExpression(T);
- printf("\n");
- return 0;
- }
输出:
- 输入中缀表达式二叉树的前序序列:*+A##B##*C##-#D##
- 二叉树建立成功!
- 二叉树的中序序列是:A+B*C*-D
- 二叉树的中序序列(加括号)是:((A+B)*(C*(-D)))
试题6(王道5.4.4节第4题):
编程求以孩子兄弟表示法存储的森林的叶子结点数。
分析:二叉树中(1)叶子结点(2)只有右孩子没有左孩子的结点是原森林的叶子结点。随便一种遍历方式,对遍历的结点加以判断即可。
- //求森林的叶子结点数
- int num = 0;
- int Numofleafknots(BiTree T){
- if (T!=NULL){
- Numofleafknots(T->lchild);
- if(T->lchild==NULL&&T->rchild!=NULL)
- num = num + 1;
- else if(T->lchild==NULL&&T->rchild==NULL)
- num = num + 1;
- else{
-
- }
- Numofleafknots(T->rchild);
- }
- return num;
- }
-
- int main(){
- BiTree T;
- printf("输入森林对应二叉树的前序序列:");
- CreateBiTree(T);
- printf("二叉树建立成功!\n");
- printf("此森林的叶子结点数是:%d",Numofleafknots(T));
- return 0;
- }
输出(这里以书上图5.17做验证):
- 输入森林对应二叉树的前序序列:AB#C#D##EF##GH#I###
- 二叉树建立成功!
- 此森林的叶子结点数是:6
试题7(王道5.4.4节第5题):
以孩子兄弟链表为存储结构,请设计递归算法求树的深度。
从树转化成二叉树:左孩子向下走相当于深度+1,右孩子向下走相当于访问同深度兄弟结点。
- //求森林的叶子结点数
- int DepthofForest(BiTree T){
- if(T==NULL)
- return 0;
- else{
- return 1 + DepthofForest(T->lchild) > DepthofForest(T->rchild) ? 1 + DepthofForest(T->lchild) : DepthofForest(T->rchild);
- }
- }
-
- int main(){
- BiTree T;
- printf("输入树对应二叉树的前序序列:");
- CreateBiTree(T);
- printf("二叉树建立成功!\n");
- printf("此树的深度是:%d",DepthofForest(T));
- return 0;
- }
输出(这里以书上图5.14,图5.15做验证):
- 输入森林对应二叉树的前序序列:RAD#E##B#CFG#H#K#####
- 二叉树建立成功!
- 此树的深度是:4
试题8(王道5.4.4节第6题):
已知一棵树的层次序列和每个结点的度,编写算法构造此树的孩子-兄弟链表。
此题借助辅助空间会好做很多:
- //构造数组存放层次序列和度的信息
- struct Node{
- char data;
- int degree;
- } a[10] = {{'R', 3}, {'A', 2}, {'B', 0}, {'C', 1}, {'D', 0}, {'E', 0}, {'F', 3}, {'G', 0}, {'H', 0}, {'K', 0}}; //仍然以图5.14,5.15为例
-
- BiTree BuildBiTree(Node a[]){
- int x = 0; //记录当前结点的孩子
- BiTree bitree[10];
- for (int i = 0; i < 10;i++){
- bitree[i] = (BiTree)malloc(sizeof(BiTNode));
- bitree[i]->data = a[i].data;
- bitree[i]->lchild = NULL; //初始全为空
- bitree[i]->rchild = NULL;
- } //这一步生成了10个结点
- for (int i = 0; i < 10;i++){
- for (int j = 0; j < a[i].degree;j++){
- x = x + 1; //此时x指向i的第一个孩子
- if(j==0)
- bitree[i]->lchild = bitree[x];
- else
- bitree[x - 1]->rchild = bitree[x];
- }
- }
- return bitree[0];
- }
-
- int main(){
- printf("此树的深度是:%d\n",DepthofForest(BuildBiTree(a)));
- printf("此树对应的二叉树深度是:%d", Depth(BuildBiTree(a)));
- return 0;
- }
输出:
- 此树的深度是:4
- 此树对应的二叉树深度是:8