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

 #include<stdio.h>
#include<malloc.h>
typedef int ElemType; //数据类型 typedef struct BiTreeNode //二叉树结构体
{
ElemType date; //结点数据
struct BiTreeNode *lChild; //左指针
int lFlag; //左标记(==0时,左指针存储左孩子结点;==1时,左指针存储前驱结点)
struct BiTreeNode *rChild; //右指针
int rFlag; //右标记(==0时,右指针存储右孩子结点;==1时,右指针存储后继结点)
}*BiTree;
BiTree pre; typedef struct QNode //结点结构体
{
BiTree date; //结点数据
struct QNode *next; //结点指针
}*LinkQuePtr; //结点名 typedef struct //链队结构体
{
LinkQuePtr front; //队头结点
LinkQuePtr rear; //队尾结点
}LinkQue; //队名 LinkQuePtr head = (LinkQuePtr)malloc(sizeof(QNode)); //头结点 /*链队的入队操作*/
int EnQueue(LinkQue *Q, BiTree e)
{
LinkQuePtr s = (LinkQuePtr)malloc(sizeof(QNode)); //申请新结点空间
if(!s)
return ;
s->date = e; //新结点的数据等于e
s->next = NULL; //新结点的指针指向空
Q->rear->next = s; //原队尾结点的指针指向新结点
Q->rear = s; //队尾指针指向新结点(使新结点成为队尾结点)
return ;
} /*链队的出队操作*/
int DeQueue(LinkQue *Q)
{
if(Q->front == Q->rear) //判断队列是否为空
return ;
LinkQuePtr s = (LinkQuePtr)malloc(sizeof(QNode)); //申请结点空间s
s = Q->front->next; //s结点等于队头结点(头指针所指向的结点)
Q->front->next = s->next; //头结点的指针指向s结点的下一结点(使s结点的下一结点成为队头元素)
if(Q->rear == s) //判断s是否为队尾元素,若是,说明队列中仅有一个结点
Q->rear = Q->front; //使队尾结点指向头结点
free(s); //释放s结点
return ;
} /*创建二叉树函数*/
void CreatBiTree(BiTree *T)
{
ElemType e; //结点数据
scanf("%d", &e);
if(e == -) //如果输入为-1,当前结点为空
(*T) = NULL;
else
{
(*T) = (BiTree)malloc(sizeof(BiTreeNode)); //申请结点空间
(*T)->date = e; //为当前结点赋值
printf("请输入当前结点 %d 的左孩子,若没有左孩子,请输入-1\n", e);
CreatBiTree(&((*T)->lChild)); //递归创建左子树
printf("请输入当前结点 %d 的右孩子,若没有右孩子,请输入-1\n", e);
CreatBiTree(&((*T)->rChild)); //递归创建右子树
}
} /*先序遍历二叉树*/
void PreorderTraversal(BiTree T)
{
if(T == NULL) //判空
return;
printf("%d ", T->date); //打印当前结点
PreorderTraversal(T->lChild); //递归遍历左子树
PreorderTraversal(T->rChild); //递归遍历右子树
} /*中序遍历二叉树*/
void InorderTraversal(BiTree T)
{
if(T == NULL) //判空
return;
InorderTraversal(T->lChild); //递归左子树
printf("%d ", T->date); //打印当前结点
InorderTraversal(T->rChild); //递归右子树
} /*后序遍历二叉树*/
void PostorderTraversal(BiTree T)
{
if(T == NULL) //判空
return;
PostorderTraversal(T->lChild); //递归左子树
PostorderTraversal(T->rChild); //递归右子树
printf("%d ", T->date); //打印当前结点
} /*层序遍历二叉树*/
void LevelTraversal(BiTree T)
{
if(T == NULL) //判空
return;
LinkQue Q; //创建队Q
Q.front = head; //初始化队列
Q.rear = head;
EnQueue(&Q, T); //将根结点入队
while(Q.front != Q.rear) //判断队列是否为空
{
BiTree s = Q.front->next->date; //获得队列中第一个结点的数据
printf("%d ", s->date); //打印当前结点的数据
if(s->lChild) //若该结点有左孩子,将其左孩子入队
EnQueue(&Q, s->lChild);
if(s->rChild) //若该结点有右孩子,将其右孩子入队
EnQueue(&Q, s->rChild);
DeQueue(&Q); //将队列中第一个结点出队
}
} /*计算树的深度*/
int Depth(BiTree T)
{
if(T == NULL) //如果当前结点为空,返回0
return ;
int L = Depth(T->lChild); //遍历左子树
int R = Depth(T->rChild); //遍历右子树
if(L > R) //取最大值返回
return (L+);
else
return (R+);
} /*中序遍历线索化*/
void Inorder_Traversal_Cue(BiTree &T)
{
if(T)
{
Inorder_Traversal_Cue(T->lChild); //递归左子树
if(T->lChild == NULL) //左孩子为空
{
T->lFlag = ; //左标记为1
T->lChild = pre; //左指针指向前一结点
}
else
{
T->lFlag = ;
}
if(pre->rChild == NULL) //前一结点的右孩子为空
{
pre->rFlag = ; //前一结点的右标记为1
pre->rChild = T; //前一结点的右指针指向当前结点
}
else
{
T->rFlag = ;
}
pre = T; //使当前结点成为前一结点
Inorder_Traversal_Cue(T->rChild); //递归右子树
}
} /*添加头结点,将二叉树线索化*/
BiTree AddHead(BiTree &T)
{
BiTree head = (BiTree)malloc(sizeof(BiTreeNode)); //申请头结点
head->lFlag = ; //头结点左标记为0
head->rFlag = ; //右标记为1
if(!T) //若二叉树为空
{
head->lChild = head; //左指针回指
head->rChild = head; //右指针回指
return NULL;
}
pre = head; //前一结点指向头结点
head->lChild = T; //头结点的左孩子指向根结点
Inorder_Traversal_Cue(T); //中序线索化
pre->rChild = head; //为最后一个结点设置右指针指向头结点
pre->rFlag = ; //右标记为1
head->rChild = pre; //头结点的右指针指向尾结点
return head; //返回头结点
} /*遍历线索二叉树*/
void TreeCueTraversal(BiTree T)
{
BiTree p = T->lChild; //申请结点p指向根结点
while(p != T) //根结点不为空
{
while(p->lFlag == ) //一直寻找第一个左标记为1的结点
p = p->lChild;
printf("%d ", p->date); //打印第一个结点
while(p->rFlag == && p->rChild != T) //若右标记是1,且右孩子不是头结点
{
p = p->rChild; //一直遍历
printf("%d ", p->date);
}
p = p->rChild; //若右标记为0,p赋值为p的右子树
}
printf("\n");
} void main()
{
BiTree T; //声明一个树变量
int dep = ; //树深度变量 while(true)
{
printf("请选择对二叉树的操作:\n");
printf("1.创建\n");
printf("2.先序遍历\n");
printf("3.中序遍历\n");
printf("4.后序遍历\n");
printf("5.层序遍历\n");
printf("6.获取深度\n");
printf("7.中序线索化\n");
printf("8.遍历线索化二叉树\n");
printf("9.退出\n");
int a;
scanf("%d", &a);
switch(a)
{
case :
printf("请输入根节点:\n");
CreatBiTree(&T);
break;
case :
PreorderTraversal(T);
break;
case :
InorderTraversal(T);
break;
case :
PostorderTraversal(T);
break;
case :
LevelTraversal(T);
break;
case :
dep = Depth(T);
printf("树的深度为 %d\n", dep);
break;
case :
T = AddHead(T);
break;
case :
TreeCueTraversal(T);
break;
case :
return;
default:
printf("选择错误\n");
break;
}
}
}

二叉树的操作--C语言实现的更多相关文章

  1. 二叉树的基本操作(C语言版)

    今天走进数据结构之二叉树 二叉树的基本操作(C 语言版) 1 二叉树的定义 二叉树的图长这样: 二叉树是每个结点最多有两个子树的树结构,常被用于实现二叉查找树和二叉堆.二叉树是链式存储结构,用的是二叉 ...

  2. neo4j初次使用学习简单操作-cypher语言使用

    Neo4j 使用cypher语言进行操作 Cypher语言是在学习Neo4j时用到数据库操作语言(DML),涵盖对图数据的增删改查  neo4j数据库简单除暴理解的概念: Neo4j中不存在表的概念, ...

  3. 栈的实现与操作(C语言实现)

    栈的定义  1, 栈是一种特殊的线性表  2,栈仅能在线性表的一端进行操作  3,栈顶(Top): 同意操作的一端 同意操作的一端  4,栈底(Bottom): ,不同意操作的一端 不同意操作 ...

  4. C/C++二叉树搜索树操作集

    啥是二叉查找树 在数据结构中,有一个奇葩的东西,说它奇葩,那是因为它重要,这就是树.而在树中,二叉树又是当中的贵族.二叉树的一个重要应用是它们在查找中的应用,于是就有了二叉查找树. 使二叉树成为一颗二 ...

  5. 树和二叉树 -数据结构(C语言实现)

    读数据结构与算法分析 树的概念 一棵树是一些节点的集合,可以为空 由称做根(root)的节点以及0个或多个非空子树组成,子树都被一条来自根的有向边相连 树的实现 思路 孩子兄弟表示法:树中的每个节点中 ...

  6. Gremlin--一种支持对图表操作的语言

    Gremlin 是操作图表的一个非常有用的图灵完备的编程语言.它是一种Java DSL语言,对图表进行查询.分析和操作时使用了大量的XPath. Gremlin可用于创建多关系图表.因为图表.顶点和边 ...

  7. 面试题23从上到下打印二叉树+queue操作

    //本题思路就是层次遍历二叉树,使用一个队列来模拟过程 /* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *ri ...

  8. 动态单链表的传统存储方式和10种常见操作-C语言实现

    顺序线性表的优点:方便存取(随机的),特点是物理位置和逻辑为主都是连续的(相邻).但是也有不足,比如:前面的插入和删除算法,需要移动大量元素,浪费时间,那么链式线性表 (简称链表) 就能解决这个问题. ...

  9. 动态分配的顺序线性表的十五种操作—C语言实现

    线性表 定义:是最常用的,也是最简单的数据结构,是长度为n个数据元素的有序的序列. 含有大量记录的线性表叫文件 记录:稍微复杂的线性表里,数据元素为若干个数据项组成,这时把一个数据元素叫记录 结构特点 ...

随机推荐

  1. npm 学习笔记

    一.介绍 1.是什么 npm 全称是 Node Package Manager,即 Node 包管理工具. 但是发展到后来,并不仅是适用于 node.js 的包. 所以现在看 node_modules ...

  2. [2018-10-29] python开发个人资源共享网--第二天

    创建Django目录 startproject my_project 创建APP startapp my_app 手动创建的文件夹 log 日志 media 用户上传下载 static 静态文件 配置 ...

  3. [考试反思]0714/0716,NOIP模拟测试3/4

    这几天时间比较紧啊(其实只是我效率有点低我在考虑要不要坐到后面去吹空调) 但是不管怎么说,考试反思还是要写的吧. 第三次考试反思没写总感觉缺了点什么,但是题都刷不完... 一进图论看他们刷题好快啊为什 ...

  4. SpringBoot整合Swagger实战

    源码地址:https://github.com/laolunsi/spring-boot-examples 目前SpringBoot常被用于开发Java Web应用,特别是前后端分离项目.为方便前后端 ...

  5. Windows7下安装Linux双操作系统

    本文链接:https://blog.csdn.net/zh175578809/article/details/78576193 最近正在学习Linux系统的常用操作命令,于是心血来潮,想自己安装一个L ...

  6. 数据仓库ETL案例学习(一)

    来自课程案例学习   某跨国食品超市的信息管理系统,每天都会记录成千上万条各地连锁超市的销售数据.基于大数据的背景,该公司的管理层决定建立FoodMart数据仓库,期望能从庞大的数据中挖掘出有商业价值 ...

  7. haproxy+keepalived练习

    小的网站结构 说明:如果部署在云上,比如阿里云上,不需要自己部署keepalived,直接买阿里云的slb即可,slb然后分发流量到两台haproxy机器 一.先部署两个web服务器 编译安装ngin ...

  8. C#语音特性 很实用

    1.隐式类型 Var 2.匿名类型 new{} 3.自动属性 [prop TAB]  public string Title { get; set; } 4.初始化器  var myObj1 = ne ...

  9. [error]The command could not be located because '/usr/bin' is not included

    配置HBase环境变量的时候写错了,写成了如下: 之后便报错 解决: 系统命令找不到时,通常是路径不对,直接在命令行用全路径即可,配置环境变量时,加入自己的环境变量,还要附带上之前的变量.如最后加上: ...

  10. hdu 1087 Super Jumping! Jumping! Jumping!(动态规划DP)

    Super Jumping! Jumping! Jumping!Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 ...