zoukankan      html  css  js  c++  java
  • 二叉树的操作--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
    ", e);
     68         CreatBiTree(&((*T)->lChild));        //递归创建左子树
     69         printf("请输入当前结点 %d 的右孩子,若没有右孩子,请输入-1
    ", 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("
    ");
    205 }
    206 
    207 void main()
    208 {
    209     BiTree T;                        //声明一个树变量
    210     int dep = 0;                    //树深度变量
    211 
    212     while(true)
    213     {
    214         printf("请选择对二叉树的操作:
    ");
    215         printf("1.创建
    ");
    216         printf("2.先序遍历
    ");
    217         printf("3.中序遍历
    ");
    218         printf("4.后序遍历
    ");
    219         printf("5.层序遍历
    ");
    220         printf("6.获取深度
    ");
    221         printf("7.中序线索化
    ");
    222         printf("8.遍历线索化二叉树
    ");
    223         printf("9.退出
    ");
    224         int a;
    225         scanf("%d", &a);
    226         switch(a)
    227         {
    228             case 1:
    229                 printf("请输入根节点:
    ");
    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
    ", 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("选择错误
    ");
    258                 break;
    259         }
    260     }
    261 }
  • 相关阅读:
    vs2015 系统找不到指定的文件(异常来自HRESULT:0x80070002)问题的解决方法
    Quartz定时任务和IIS程序池闲置超时时间冲突解决方案
    怎样设置IIS6.0的闲置超时时间
    C#窗体如何通过keybd_event()函数模拟键盘按键(组合键)产生事件
    安装完DevExpress14.2.5,如何破解它呢?
    IIS6.0发布后对路径“D:xxxxxxxweb.config”的访问被拒绝问题的解决方法
    CentOS7 nginx+tomcat实现代理访问java web项目让项目支持jsp和php
    col-xs , col-sm , col-md , col-lg是什么意思?什么时候用?
    Linux 防火墙命令的操作命令CentOS
    Linux(centos)新建,删除,移动,重命名文件夹和文件的命令
  • 原文地址:https://www.cnblogs.com/yurui/p/10359388.html
Copyright © 2011-2022 走看看