二叉树的操作--C语言实现


树是一种比较复杂的数据结构,它的操作也比较多。常用的有二叉树创建遍历线索化线索化二叉树的遍历,这些操作又可以分为前序中序后序。其中,二叉树的操作有递归迭代两种方式,鉴于我个人的习惯,在这里我是使用递归来操作的,另外,层序遍历需要借助队列来实现。代码亲测,可执行。

 1 #include<stdio.h>
 2 #include<malloc.h>
 3 typedef int ElemType;                    //数据类型
 4 
 5 typedef struct BiTreeNode                //二叉树结构体
 6 {  7     ElemType date;                        //结点数据
 8     struct BiTreeNode *lChild;            //左指针
 9     int lFlag;                            //左标记(==0时,左指针存储左孩子结点;==1时,左指针存储前驱结点)
 10     struct BiTreeNode *rChild;            //右指针
 11     int rFlag;                            //右标记(==0时,右指针存储右孩子结点;==1时,右指针存储后继结点)
 12 }*BiTree;  13 BiTree pre;  14 
 15 typedef struct QNode                    //结点结构体
 16 {  17     BiTree date;                        //结点数据
 18     struct QNode *next;                    //结点指针
 19 }*LinkQuePtr;                            //结点名
 20 
 21 typedef struct                            //链队结构体
 22 {  23     LinkQuePtr front;                    //队头结点
 24     LinkQuePtr rear;                    //队尾结点
 25 }LinkQue;                                //队名
 26 
 27 LinkQuePtr head = (LinkQuePtr)malloc(sizeof(QNode));                        //头结点
 28 
 29 /*链队的入队操作*/
 30 int EnQueue(LinkQue *Q, BiTree e)  31 {  32     LinkQuePtr s = (LinkQuePtr)malloc(sizeof(QNode));            //申请新结点空间
 33     if(!s)  34         return 0;  35     s->date = e;                        //新结点的数据等于e
 36     s->next = NULL;                        //新结点的指针指向空
 37     Q->rear->next = s;                    //原队尾结点的指针指向新结点
 38     Q->rear = s;                        //队尾指针指向新结点(使新结点成为队尾结点)
 39     return 1;  40 }  41 
 42 /*链队的出队操作*/
 43 int DeQueue(LinkQue *Q)  44 {  45     if(Q->front == Q->rear)                //判断队列是否为空
 46         return 0;  47     LinkQuePtr s = (LinkQuePtr)malloc(sizeof(QNode));        //申请结点空间s
 48     s = Q->front->next;                    //s结点等于队头结点(头指针所指向的结点)
 49     Q->front->next = s->next;            //头结点的指针指向s结点的下一结点(使s结点的下一结点成为队头元素)
 50     if(Q->rear == s)                    //判断s是否为队尾元素,若是,说明队列中仅有一个结点
 51         Q->rear = Q->front;                //使队尾结点指向头结点
 52     free(s);                            //释放s结点
 53     return 1;  54 }  55 
 56 /*创建二叉树函数*/
 57 void CreatBiTree(BiTree *T)  58 {  59     ElemType e;                        //结点数据
 60     scanf("%d", &e);  61     if(e == -1)                        //如果输入为-1,当前结点为空
 62         (*T) = NULL;  63     else
 64  {  65         (*T) = (BiTree)malloc(sizeof(BiTreeNode));        //申请结点空间
 66         (*T)->date = e;                        //为当前结点赋值
 67         printf("请输入当前结点 %d 的左孩子,若没有左孩子,请输入-1\n", e);  68         CreatBiTree(&((*T)->lChild));        //递归创建左子树
 69         printf("请输入当前结点 %d 的右孩子,若没有右孩子,请输入-1\n", e);  70         CreatBiTree(&((*T)->rChild));        //递归创建右子树
 71  }  72 }  73 
 74 /*先序遍历二叉树*/
 75 void PreorderTraversal(BiTree T)  76 {  77     if(T == NULL)                            //判空
 78         return;  79     printf("%d ", T->date);                    //打印当前结点
 80     PreorderTraversal(T->lChild);            //递归遍历左子树
 81     PreorderTraversal(T->rChild);            //递归遍历右子树
 82 }  83 
 84 /*中序遍历二叉树*/
 85 void InorderTraversal(BiTree T)  86 {  87     if(T == NULL)                            //判空
 88         return;  89     InorderTraversal(T->lChild);            //递归左子树
 90     printf("%d ", T->date);                    //打印当前结点
 91     InorderTraversal(T->rChild);            //递归右子树
 92 }  93 
 94 /*后序遍历二叉树*/
 95 void PostorderTraversal(BiTree T)  96 {  97     if(T == NULL)                            //判空
 98         return;  99     PostorderTraversal(T->lChild);            //递归左子树
100     PostorderTraversal(T->rChild);            //递归右子树
101     printf("%d ", T->date);                    //打印当前结点
102 } 103 
104 /*层序遍历二叉树*/
105 void LevelTraversal(BiTree T) 106 { 107     if(T == NULL)                            //判空
108         return; 109     LinkQue Q;            //创建队Q
110     Q.front = head;        //初始化队列
111     Q.rear = head; 112     EnQueue(&Q, T);                            //将根结点入队
113     while(Q.front != Q.rear)                //判断队列是否为空
114  { 115         BiTree s = Q.front->next->date;            //获得队列中第一个结点的数据
116         printf("%d ", s->date);                    //打印当前结点的数据
117         if(s->lChild)                            //若该结点有左孩子,将其左孩子入队
118             EnQueue(&Q, s->lChild); 119         if(s->rChild)                            //若该结点有右孩子,将其右孩子入队
120             EnQueue(&Q, s->rChild); 121         DeQueue(&Q);                            //将队列中第一个结点出队
122  } 123 } 124 
125 /*计算树的深度*/
126 int Depth(BiTree T) 127 { 128     if(T == NULL)                        //如果当前结点为空,返回0
129         return 0; 130     int L = Depth(T->lChild);            //遍历左子树
131     int R = Depth(T->rChild);            //遍历右子树
132     if(L > R)                            //取最大值返回
133         return (L+1); 134     else
135         return (R+1); 136 } 137 
138 /*中序遍历线索化*/
139 void Inorder_Traversal_Cue(BiTree &T) 140 { 141     if(T) 142  { 143         Inorder_Traversal_Cue(T->lChild);            //递归左子树
144         if(T->lChild == NULL)                        //左孩子为空
145  { 146             T->lFlag = 1;                            //左标记为1
147             T->lChild = pre;                        //左指针指向前一结点
148  } 149         else
150  { 151             T->lFlag = 0; 152  } 153         if(pre->rChild == NULL)                        //前一结点的右孩子为空
154  { 155             pre->rFlag = 1;                            //前一结点的右标记为1
156             pre->rChild = T;                        //前一结点的右指针指向当前结点
157  } 158         else
159  { 160             T->rFlag = 0; 161  } 162         pre = T;                                    //使当前结点成为前一结点
163         Inorder_Traversal_Cue(T->rChild);            //递归右子树
164  } 165 } 166 
167 /*添加头结点,将二叉树线索化*/
168 BiTree AddHead(BiTree &T) 169 { 170     BiTree head = (BiTree)malloc(sizeof(BiTreeNode));        //申请头结点
171     head->lFlag = 0;                //头结点左标记为0
172     head->rFlag = 1;                //右标记为1
173     if(!T)                            //若二叉树为空
174  { 175         head->lChild = head;        //左指针回指
176         head->rChild = head;        //右指针回指
177         return NULL; 178  } 179     pre = head;                        //前一结点指向头结点
180     head->lChild = T;                //头结点的左孩子指向根结点
181     Inorder_Traversal_Cue(T);        //中序线索化
182     pre->rChild = head;                //为最后一个结点设置右指针指向头结点
183     pre->rFlag = 1;                    //右标记为1
184     head->rChild = pre;                //头结点的右指针指向尾结点
185     return head;                    //返回头结点
186 } 187 
188 /*遍历线索二叉树*/
189 void TreeCueTraversal(BiTree T) 190 { 191     BiTree p = T->lChild;                //申请结点p指向根结点
192     while(p != T)                        //根结点不为空
193  { 194         while(p->lFlag == 0)            //一直寻找第一个左标记为1的结点
195             p = p->lChild; 196         printf("%d ", p->date);            //打印第一个结点
197         while(p->rFlag == 1 && p->rChild != T)        //若右标记是1,且右孩子不是头结点
198  { 199             p = p->rChild;                //一直遍历
200             printf("%d ", p->date); 201  } 202         p = p->rChild;                //若右标记为0,p赋值为p的右子树
203  } 204     printf("\n"); 205 } 206 
207 void main() 208 { 209     BiTree T;                        //声明一个树变量
210     int dep = 0;                    //树深度变量
211 
212     while(true) 213  { 214         printf("请选择对二叉树的操作:\n"); 215         printf("1.创建\n"); 216         printf("2.先序遍历\n"); 217         printf("3.中序遍历\n"); 218         printf("4.后序遍历\n"); 219         printf("5.层序遍历\n"); 220         printf("6.获取深度\n"); 221         printf("7.中序线索化\n"); 222         printf("8.遍历线索化二叉树\n"); 223         printf("9.退出\n"); 224         int a; 225         scanf("%d", &a); 226         switch(a) 227  { 228             case 1: 229                 printf("请输入根节点:\n"); 230                 CreatBiTree(&T); 231                 break; 232             case 2: 233  PreorderTraversal(T); 234                 break; 235             case 3: 236  InorderTraversal(T); 237                 break; 238             case 4: 239  PostorderTraversal(T); 240                 break; 241             case 5: 242  LevelTraversal(T); 243                 break; 244             case 6: 245                 dep = Depth(T); 246                 printf("树的深度为 %d\n", dep); 247                 break; 248             case 7: 249                 T = AddHead(T); 250                 break; 251             case 8: 252  TreeCueTraversal(T); 253                 break; 254             case 9: 255                 return; 256             default: 257                 printf("选择错误\n"); 258                 break; 259  } 260  } 261 }

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM