二叉树遍历线索化及树形结构输出
来源:互联网 发布:淘宝2017新规则 编辑:程序博客网 时间:2024/05/16 11:20
//很久以前自己整理的代码,也有部分参考了网络上前辈的经验#include <stdio.h>#include <stdlib.h>#define OVERFLOW -2#define OK 1#define ERROR 0#define MAX 100#include <math.h>#include <windows.h>//typedef enum { Link, Thread } PointerThr; // Link==0:指针,Thread==1:线索typedef struct BiThrNode{ int data; struct BiThrNode *lchild, *rchild; // 左右指针 int LTag, RTag; // 左右标志} BiThrNode, *BiThrTree;typedef struct QNode{ BiThrNode *data; struct QNode *next;}QNode, *QueuePtr;typedef struct{ QueuePtr front; QueuePtr rear;}LinkQueue;//以下为队列操作,用于层序遍历输出树形结构//构造一个空队列Qint InitQueue(LinkQueue &Q){ Q.front = Q.rear = (QNode *)malloc(sizeof(QNode)); if(!Q.front) return 0; Q.front->next = NULL; return OK;}//进队操作函数int EnQueue(LinkQueue &Q, BiThrNode *e){ QNode *p; p = (QNode *)malloc(sizeof(QNode)); if(!p) return 0; p->data = e; p->next = NULL; Q.rear->next = p; Q.rear = p; return OK;}//出队操作BiThrNode * DeQueue(LinkQueue &Q){ QNode *p; BiThrNode *e; if(Q.front == Q.rear) return NULL; p = Q.front->next; e = p->data; Q.front->next = p->next; if(Q.rear == p) Q.rear = Q.front; free(p); return e;}//二叉树深度int FindDepth(BiThrTree pRoot){ if(pRoot == NULL) return 0; else { int a = FindDepth(pRoot->lchild); int b = FindDepth(pRoot->rchild); return (a>b?a:b)+1; } //所以,如果给出二叉树的根结点,带入这个函数就能求出其深度了}//打印二叉树树形结构void PrintBiTree(BiThrTree T){ int row = FindDepth(T); BiThrNode *p = T; LinkQueue Q; InitQueue(Q); EnQueue(Q, T);//根进队 for(int i = 0; i < row; i++)//层序遍历,分层打印 { printf("=");//左边缘 for(int k = 0; k < pow(2,i); k++) { for(int j = 0; j < (pow(2,row - i - 1) - 1); j++)//从第一行开始缩进2^(row - i -1) - 1个空格 printf("="); p = DeQueue(Q);//出队 if(p) printf("%c",p->data);//当出队的结点存在时打印p->data else printf("@");//当结点不存在时打印@ if(!p)//当出对的元素为NULL时,入队2个NULL,模拟其的左右孩子(下次就会打印出@,最后一行的左右孩子无需再打印) { EnQueue(Q,NULL); EnQueue(Q,NULL); } else { if(p->lchild)//当结点的左右孩子存在时,左右孩子入队,不存在时NULL入队(下次出队时输出数据或@) EnQueue(Q,p->lchild); else EnQueue(Q,NULL); if(p->rchild) EnQueue(Q,p->rchild); else EnQueue(Q,NULL); } for(j = 0; j <= (pow(2,row - i - 1) - 1); j++) printf("="); } printf("\n");//每打完一层换行 }}//建立二叉树//先序建立二叉树void CreateBiTree(BiThrTree &pRoot) { char ch; scanf("%c",&ch); getchar(); if(ch == '@') //输入0 时代表空(叶子节点左右子树为空) { pRoot = NULL; } else //如果不是叶子结点 { pRoot = (BiThrNode *)malloc(sizeof(BiThrNode)); pRoot->data = ch; pRoot->lchild =NULL; pRoot->rchild =NULL; pRoot->LTag=0; pRoot->RTag=0; CreateBiTree(pRoot->lchild); //以这个结点的左孩子结点为根结点,以同样的方法再建立二叉树 CreateBiTree(pRoot->rchild); //左子树建立好后,以这个结点的右孩子结点为根结点,再建立二叉树 } //pRoot的左右子树都建立好后,整个二叉树就建立好了,函数结束}// 先序遍历二叉树void PreTravelBiTree(BiThrTree pRoot) //这里的参数没有用引用,当然也可以用引用{ if(pRoot == NULL) //如果当前结点为空 return ; else //如果访结点不为空 { printf("%c ",pRoot->data); //那么先输入这个结点里保存的数据,先做这一步,也是体现了“先序遍历” PreTravelBiTree(pRoot->lchild); //再以这个结点的左孩子为根结点,同样的方法访问其左子树 PreTravelBiTree(pRoot->rchild); //访问右子树 } } // 中序遍历二叉树void MidTravelBiTree(BiThrTree pRoot){ if(pRoot == NULL) return ; else { MidTravelBiTree(pRoot->lchild); //对当前结点pRoot来说,要先访问其左子树 printf("%c ",pRoot->data); //再输出当前结点pRoot中保存的内容 MidTravelBiTree(pRoot->rchild); //再访问其右子树 }}// 后序遍历二叉树void PostTravelBiTree(BiThrTree pRoot){ if(pRoot == NULL) return ; else { PostTravelBiTree(pRoot->lchild); //对当前结点pRoot来说,要先访问其左子树 PostTravelBiTree(pRoot->rchild); //再访问其右子树 printf("%c ",pRoot->data); //输出当前结点pRoot中保存的内容; }}//释放二叉树void FreeBiTree(BiThrTree pRoot){ if(!pRoot) return; free(pRoot->lchild); //如果没有返回,则说明该结点不为空,那么释放其左子树 free(pRoot->rchild); free(pRoot); } BiThrTree pre = NULL;//设置前驱 //将二叉树p中序线索化(确定各个节点之间的pre关系)void InOrderThreading(BiThrTree p) { if(p) { InOrderThreading(p -> lchild); //左子树中序线索化 if(p->lchild==NULL) p->LTag=1; //左孩子为NULL,建立左线索标志 if(p->rchild==NULL) p->RTag=1; if(pre!=NULL)//pre存在,即要满足以下要求: { if(pre->RTag==1) // 当当前节点p无右子树 pre->rchild=p; //(用pre空余的rchild指针(代表后继)指向p)即Pre为p的前驱 if(p->LTag==1) //当当前节点p无左子树 p->lchild=pre; //即p的前驱为pre } pre = p; //从而达到保持pre指向p的前驱的要求 InOrderThreading(p -> rchild); //右子树中序线索化 } } //查找中序的后继节点BiThrTree InOrderNext(BiThrTree p){ BiThrTree q; if(p->RTag==1) //优先确定是否可以直接找到后继(标志为1即有后继,右孩子为空) return(p->rchild); //直接返回后继即可 else { //p无法直接找到后继(RTag = 0) q=p->rchild; //从p的右孩子开始查找 while(q->LTag==0) //找到其最左孩子返回(中序遍历需要从最左开始) q=q->lchild; return(q); }}//中序遍历中序线索二叉树(即利用节点pre关系遍历输出,和普通的遍历有所区别)void InOrderTraverse_Thr(BiThrTree p){ printf("中序遍历中序线索化二叉树: "); if(p!=NULL) //非空树 { while(p->LTag==0) //有左孩子就一直找下去(查找中序序列的开始结点) p=p->lchild; do { printf("%c ",p->data); //访问结点p p=InOrderNext(p); //查找p的中序后继结点 } while(p!=NULL); } printf("\n\n");}#include "X.h"void main(){ BiThrTree pRoot = NULL,Thrt = NULL; printf("先序建立二叉树(字符@表示空):\n"); CreateBiTree(pRoot); printf("\n树形结构:\n"); PrintBiTree(pRoot); printf("\n二叉树的深度为:%d ",FindDepth(pRoot)); printf("\n前序遍历结果:"); PreTravelBiTree(pRoot); printf("\n中序遍历结果:"); MidTravelBiTree(pRoot); printf("\n后序遍历结果:"); PostTravelBiTree(pRoot); //FreeBiTree(pRoot); printf("\n\n"); //将二叉树T改变为其中序线索二叉树 InOrderThreading(pRoot); InOrderTraverse_Thr(pRoot); }