二叉树的操作--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 }

 

posted @ 2019-02-10 16:16  哈哈瑞  阅读(3440)  评论(0编辑  收藏  举报