二叉树的操作--C语言实现
树是一种比较复杂的数据结构,它的操作也比较多。常用的有二叉树的创建,遍历,线索化,线索化二叉树的遍历,这些操作又可以分为前序,中序和后序。其中,二叉树的操作有递归与迭代两种方式,鉴于我个人的习惯,在这里我是使用递归来操作的,另外,层序遍历需要借助队列来实现。代码亲测,可执行。
#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语言实现的更多相关文章
- 二叉树的基本操作(C语言版)
今天走进数据结构之二叉树 二叉树的基本操作(C 语言版) 1 二叉树的定义 二叉树的图长这样: 二叉树是每个结点最多有两个子树的树结构,常被用于实现二叉查找树和二叉堆.二叉树是链式存储结构,用的是二叉 ...
- neo4j初次使用学习简单操作-cypher语言使用
Neo4j 使用cypher语言进行操作 Cypher语言是在学习Neo4j时用到数据库操作语言(DML),涵盖对图数据的增删改查 neo4j数据库简单除暴理解的概念: Neo4j中不存在表的概念, ...
- 栈的实现与操作(C语言实现)
栈的定义 1, 栈是一种特殊的线性表 2,栈仅能在线性表的一端进行操作 3,栈顶(Top): 同意操作的一端 同意操作的一端 4,栈底(Bottom): ,不同意操作的一端 不同意操作 ...
- C/C++二叉树搜索树操作集
啥是二叉查找树 在数据结构中,有一个奇葩的东西,说它奇葩,那是因为它重要,这就是树.而在树中,二叉树又是当中的贵族.二叉树的一个重要应用是它们在查找中的应用,于是就有了二叉查找树. 使二叉树成为一颗二 ...
- 树和二叉树 -数据结构(C语言实现)
读数据结构与算法分析 树的概念 一棵树是一些节点的集合,可以为空 由称做根(root)的节点以及0个或多个非空子树组成,子树都被一条来自根的有向边相连 树的实现 思路 孩子兄弟表示法:树中的每个节点中 ...
- Gremlin--一种支持对图表操作的语言
Gremlin 是操作图表的一个非常有用的图灵完备的编程语言.它是一种Java DSL语言,对图表进行查询.分析和操作时使用了大量的XPath. Gremlin可用于创建多关系图表.因为图表.顶点和边 ...
- 面试题23从上到下打印二叉树+queue操作
//本题思路就是层次遍历二叉树,使用一个队列来模拟过程 /* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *ri ...
- 动态单链表的传统存储方式和10种常见操作-C语言实现
顺序线性表的优点:方便存取(随机的),特点是物理位置和逻辑为主都是连续的(相邻).但是也有不足,比如:前面的插入和删除算法,需要移动大量元素,浪费时间,那么链式线性表 (简称链表) 就能解决这个问题. ...
- 动态分配的顺序线性表的十五种操作—C语言实现
线性表 定义:是最常用的,也是最简单的数据结构,是长度为n个数据元素的有序的序列. 含有大量记录的线性表叫文件 记录:稍微复杂的线性表里,数据元素为若干个数据项组成,这时把一个数据元素叫记录 结构特点 ...
随机推荐
- NOIP模拟测试25
这次考试后面心态爆炸了...发现刚了2h的T2是假的之后就扔掉了,草率地打了个骗分 T1只会搜索和m=0 最先做的T3,主要是发现部分分很多,当时第一眼看上去有87分(眼瞎了). 后来想了想,感觉一条 ...
- docker安装制定版本-centos7
# 安装依赖包 yum install -y yum-utils device-mapper-persistent-data lvm2 # 添加Docker软件包源 yum-config-manage ...
- 小白学 Python(21):生成器基础
人生苦短,我选Python 前文传送门 小白学 Python(1):开篇 小白学 Python(2):基础数据类型(上) 小白学 Python(3):基础数据类型(下) 小白学 Python(4):变 ...
- ORACLE存储过程的创建和执行的简单示例和一些注意点
此示例的主要目的主要是为了了解在PL/SQL环境下怎么创建和执行存储过程. 存储过程所涉及的DataTable: 第一步:创建游标变量 游标是ORACLE系统在内存中开辟的一个工作区,主要用来存储SE ...
- C/C++企业链表的实现
首先 先介绍企业链表 和Linux内核链表 和 之前我发的一篇单项链表的区别 结构体变量名是结构体的首地址吗? 这个问题会在待会链表实现中体现!! 答案:有些编译器 支持用结构体变量名做地址的方式但一 ...
- one of neural network
map source:https://github.com/microsoft/ai-edu Fundamental Principle inputs: characteristic value th ...
- java 深拷贝与浅拷贝
yls 2019年11月07日 拷贝分为引用拷贝和对象拷贝 深拷贝和浅拷贝都属于对象拷贝 浅拷贝:通过Object默认的clone方法实现 实现Cloneable接口 public class She ...
- springboot封装JsonUtil,CookieUtil工具类
springboot封装JsonUtil,CookieUtil工具类 yls 2019-9-23 JsonUtil public class JsonUtil { private static Obj ...
- lqb 基础练习 特殊的数字
基础练习 特殊的数字 时间限制:1.0s 内存限制:512.0MB 问题描述 153是一个非常特殊的数,它等于它的每位数字的立方和,即153=1*1*1+5*5*5+3*3*3.编程求所有 ...
- 力扣(LeetCode)找不同 个人题解
给定两个字符串 s 和 t,它们只包含小写字母. 字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母. 请找出在 t 中被添加的字母. 示例: 输入: s = "abcd&quo ...