二叉树的操作--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个数据元素的有序的序列. 含有大量记录的线性表叫文件 记录:稍微复杂的线性表里,数据元素为若干个数据项组成,这时把一个数据元素叫记录 结构特点 ...
随机推荐
- [Java]Java类和对象内存分配详解
描述 代码说明: 一.当Person p1 = new Person();第一次被调用时需要做两件事: 1.先判断类加载器是否加载过Person类,如果没有则加载到Person类型到方法区 2.在堆中 ...
- 无聊的 邮递员 插头dp
邮递员想知道,如果他每天都用不同路线走过10×20个点阵邮筒,他必须活过多少个世纪才能走遍所有方案? 7:00 改完T1,开始肝插头dp 7:10 放弃,颓博客 7:20 学习插头dp 7:21 放弃 ...
- 前端与算法 leetcode 1. 两数之和
目录 # 前端与算法 leetcode 1. 两数之和 题目描述 概要 提示 解析 解法一:暴力法 解法二:HashMap法 算法 传入[1, 2], [11, 1, 2, 3, 2]的运行结果 执行 ...
- 实测Maven上传jar包到私服的方法归纳
Hello,各位小伙伴大家好,我是小栈君.好久不见,最近因为工作的缘故,导致了更新变慢,但是小栈君也在积极的做素材的规划,毕竟学习知识点的归纳和提炼需要一定的时间. 所以还请大家多多见谅,下一期的分享 ...
- csps模拟测试70
又炸了,T1没开$long long$,炸掉$50pts$,昨天因为SB错误挂掉$100pts$. 我kuku了,以后细心点吧.
- Python脚本之——API自动化框架总结
学完了Python脚本接口自动化之后,一直没有对该框架做总结,今天终于试着来做一份总结了. 框架结构如下图: 来说一下每个目录的作用: Configs:该目录下存放的是.conf,.ini文件格式的配 ...
- php 下载图片并打包成Zip格式压缩包
前言:最近公司有个需要下载多个图片并打包成压缩包的需求,下面来看看具体是怎么做的 1.没什么说的,懒得说啥,直接看代码 /** * 下载图片并生成压缩包 * @param $data 图片数组,一维 ...
- 『题解』洛谷P3384 【模板】树链剖分
Problem Portal Portal1: Luogu Description 如题,已知一棵包含\(N\)个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作\(1\): ...
- linux 相关指令
modinfo *.ko 显示驱动文件的信息.
- python经典算法面试题1.5:如何找出单链表中的倒数第K个元素
本题目摘自<Python程序员面试算法宝典>,我会每天做一道这本书上的题目,并分享出来,统一放在我博客内,收集在一个分类中. [微软笔试题] 难度系数:⭐⭐⭐ 考察频率:⭐⭐⭐⭐⭐ 题目描 ...