C实现二叉树(模块化集成,遍历的递归与非递归实现)
C实现二叉树模块化集成
实验源码介绍(源代码的总体介绍):
header.h : 头文件链栈,循环队列,二叉树的结构声明和相关函数的声明。
LinkStack.c : 链栈的相关操作函数定义。
Queue.c : 循环队列的相关操作函数定义。
BinTree.c : 二叉树的相关操作的函数定义,层序序列生成二叉树,二叉树的前序序列、中序序列、后序序列的递归和非递归实现,求叶子结点的递归与非递归实现,求树高。
由于我还是学生(初学者)且第一次写类似的博客,文章中难免会有错误!如发现错误,望各路大神能够指出!
详见源代码!
源代码:header.h
/**
* header.h
*/
/**
* BinTree
*/
typedef int BinTree_Type;
typedef struct TreeNode BinTree;
struct TreeNode {
BinTree_Type Data;
BinTree *Left;
BinTree *Right;
}; /**
* Queue
*/
#define MaxSize 50
typedef BinTree * Q_ElementType;
typedef struct {
Q_ElementType Data[MaxSize];
int front;
int rear;
} Queue; extern Queue * InitQueue();
extern void Destory(Queue * q);
extern int IsQueueEmpty(Queue *q);
extern void EnQueue(Queue *q, Q_ElementType e);
extern Q_ElementType DeQueue(Queue* q); /**
* LinkStack
*/
typedef BinTree * L_ElementType;
typedef struct Node {
L_ElementType Data;
struct Node *next;
} LinkStack; extern LinkStack * InitStack();
extern int IsStackEmpty(LinkStack *s);
extern void Push(LinkStack *s, L_ElementType e);
extern L_ElementType Pop(LinkStack *s);
extern L_ElementType getTop(LinkStack *s);
header.h
源代码:LinkStack.c
#include <stdio.h> //standard input output 标准输入输出头文件
#include <malloc.h> //memory allocation分配
#include "header.h" /**
* 初始化一个头结点为空的Stack
* init a stack with a NULL head
*/
LinkStack * InitStack() {
LinkStack *s = (LinkStack *) malloc(sizeof(LinkStack));
s->next = NULL;
return s;
} /**
* 若stack为空返回1,否则返回0
*/
int IsStackEmpty(LinkStack *s) {
return s->next == NULL;
} /**
* 入栈
*/
void Push(LinkStack *s, L_ElementType e) {
struct Node *p;
p = (LinkStack *) malloc(sizeof(LinkStack));
p->Data = e;
p->next = s->next;
s->next = p;
} /**
* 出栈
*/
L_ElementType Pop(LinkStack *s) {
if (s->next == NULL) {
printf("Stack is NULL");
return NULL;
}
L_ElementType TopElem;
struct Node *top;
top = s->next;
s->next = top->next;
TopElem = top->Data;
free(top);
return TopElem;
} /**
* 返回栈顶元素
*/
L_ElementType getTop(LinkStack *s) {
if (s->next == NULL) {
printf("Stack is NULL");
return NULL;
}
return s->next->Data;
}
LinkStack.c
源代码:Queue.c
#include <stdio.h>
#include <malloc.h>
#include "header.h" /**
* 初始化循环队列
*/
Queue * InitQueue() {
Queue *q = (Queue *) malloc(sizeof(Queue));
q->front = q->rear = ;
return q;
} /**
* 销毁队列
*/
void Destory(Queue * q) {
free(q);
} /**
* 判断队列是否为空
*/
int IsQueueEmpty(Queue *q) {
return q->front == q->rear;
} /**
* 入队
*/
void EnQueue(Queue *q, Q_ElementType e) {
if ((q->rear + ) % MaxSize == q->front) {
printf("队列满了");
return;
}
q->rear = (q->rear + ) % MaxSize;
q->Data[q->rear] = e;
} /**
* 出队
*/
Q_ElementType DeQueue(Queue* q) {
if (q->front == q->rear) {
printf("队列空了!");
return NULL;
}
q->front = (q->front + ) % MaxSize;
return q->Data[q->front];
}
Queue.c
源代码:BinTree.c
#include <stdio.h>
#include <malloc.h>
#include "header.h" /**
* 访问
*/
void Visited(BinTree *BT) {
printf("%d ", BT->Data);
} /**
* 层序生成二叉树
*/
BinTree *CreateBinTree() {
BinTree_Type Data;
BinTree *BT = NULL, *T = NULL;
Queue * Q = NULL;
Q = InitQueue(); /* 生成一个队列 */
scanf("%d", &Data); /* 建立第一个结点,即根节点 */
if (Data) { /* 分配结点单元,并将结点地址入队 */
BT = (BinTree *) malloc(sizeof(BinTree));
BT->Data = Data;
EnQueue(Q, BT);
} else {
return NULL; /* 若第一个数据就是0,则返回空树 */
}
while (!IsQueueEmpty(Q)) {
T = DeQueue(Q); /* 从队列中取出一结点地址 */
scanf("%d", &Data); /* 读入T的左孩子 */
if (Data) { /* 分配新结点,作为出对结点左孩子 */
T->Left = (BinTree *) malloc(sizeof(BinTree));
T->Left->Data = Data;
EnQueue(Q, T->Left); /* 新结点入队 */
} else {
T->Left = NULL;
}
scanf("%d", &Data); /* 读入T的右孩子 */
if (Data) { /* 分配新结点,作为出对结点右孩子 */
T->Right = (BinTree *) malloc(sizeof(BinTree));
T->Right->Data = Data;
EnQueue(Q, T->Right); /* 新结点入队 */
} else {
T->Right = NULL;
}
} /* 结束while */
return BT;
} /**
* 遍历二叉树 递归算法
*/
void PreOrderTraversal(BinTree *BT) {
if (BT) { //BT != NULL
Visited(BT);
PreOrderTraversal(BT->Left);
PreOrderTraversal(BT->Right);
}
} void InOrderTraversal(BinTree *BT) {
if (BT) {
InOrderTraversal(BT->Left);
Visited(BT);
InOrderTraversal(BT->Right);
}
} void PostOrderTraversal(BinTree *BT) {
if (BT) {
PostOrderTraversal(BT->Left);
PostOrderTraversal(BT->Right);
Visited(BT);
}
} /**
* 遍历二叉树 非递归算法
*/
/**
* 前序遍历非递归算法
*/
void PreOrderTraversal_Iter(BinTree *BT) {
BinTree *T;
LinkStack * S = InitStack(); /* 生成一个堆栈 */
T = BT;
while (T || !IsStackEmpty(S)) {
while (T) { /* 一直向左并访问沿途结点后压入堆栈S */
Visited(T);
Push(S, T);
T = T->Left;
}
if (!IsStackEmpty(S)) {
T = Pop(S); /* 结点弹出堆栈 */
T = T->Right; /* 转向右子树 */
}
}
} /**
* 中序遍历非递归算法
*/
void InOrderTraversal_Iter(BinTree *BT) {
BinTree *T;
LinkStack * S = InitStack(); /* 生成一个堆栈 */
T = BT;
while (T || !IsStackEmpty(S)) {
while (T) { /* 一直向左并将沿途结点后压入堆栈S */
Push(S, T);
T = T->Left;
}
if (!IsStackEmpty(S)) {
T = Pop(S); /* 结点弹出堆栈 */
Visited(T);
T = T->Right; /* 转向右子树 */
}
}
} /**
* 后序遍历非递归算法一
* 此思路来源于数据结构教程(李春葆主编)
*/
void PostOrderTraversal_Iter1(BinTree *BT) {
if (BT == NULL)
return;
BinTree *p, *T;
LinkStack * S = InitStack();
T = BT;
int flag = ;
do {
while (T) { /* 一直向左并将沿途结点后压入堆栈S */
Push(S, T);
T = T->Left;
}
/* 执行到此处,栈顶元素没有做孩子或左子树均已访问过 */
flag = ; /* 表示 T的左孩子已访问或为空 */
p = NULL; /* p指向栈顶结点的前一个已访问的结点 */
while (!IsStackEmpty(S) && flag) {
T = getTop(S); /* 获取当前的栈顶元素,不是删除 */
/**
* 若p=NULL,表示T的右孩子不存在,而左孩子不存在或已经被访问过,所以访问T;
* 若p≠NULL,表示T的右孩子已访问(原因是p指向T的右子树中刚访问过的结点,而p是T的右孩子,
* p一定是T的右子树中后序序列的最后一个结点),所以可以访问T.
*/
if (p == T->Right) {
Visited(T); /* 访问 */
p = Pop(S); /* 弹出刚访问的结点并将p指向刚访问的结点 */
} else {
T = T->Right; /* T指向T的右孩子 */
flag = ; /* 表示T的右孩子尚未被访问过 */
}
}
} while (!IsStackEmpty(S)); } /**
* 后序遍历非递归算法二
* 思路:要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点p,先将其入栈。
* 如果p不存在左孩子和右孩子,则可以直接访问它;
* 或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。
* 若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,
* 左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。
* (此思路来源于博客园海子!!!)
*/
void PostOrderTraversal_Iter2(BinTree *BT) {
if (!BT)
return;
BinTree *p, *cur;
LinkStack *S = InitStack();
p = NULL;
cur = NULL;
Push(S, BT);
while (!IsStackEmpty(S)) {
cur = getTop(S);
if ((!cur->Left && !cur->Right) /* NULL==cur->Left && NULL==cur->Right */
|| (p && (p == cur->Left || p == cur->Right))) {
Visited(cur);
p = Pop(S);
} else {
if (cur->Right) {
Push(S, cur->Right);
}
if (cur->Left) {
Push(S, cur->Left);
}
}
}
} /**
* 层序遍历
*/
void LevelOrderTraversal(BinTree *BT) {
BinTree *T;
T = BT;
if (!T) {
return;
}
Queue *Q = InitQueue(); /* 生成一个队列 */
EnQueue(Q, T); /* 根节点入队 */
while (!IsQueueEmpty(Q)) { /* 队列不为空,弹出一个元素 */
T = DeQueue(Q);
Visited(T); /* 访问 */
if (T->Left) /* 左子树不为空入队 */
EnQueue(Q, T->Left);
if (T->Right) /* 右子树不为空入队 */
EnQueue(Q, T->Right);
}
} /**
* 访问叶子结点的递归算法
*/
void getOrderPrintLeaves(BinTree *BT) {
if (BT) {
if (!BT->Left && !BT->Right) {
Visited(BT);
}
getOrderPrintLeaves(BT->Left);
getOrderPrintLeaves(BT->Right);
}
} /**
* 访问叶子结点的非递归算法
*/
void getOrderPrintLeaves_Iter(BinTree *BT) {
BinTree *T;
LinkStack *S = InitStack();
T = BT;
while (T || !IsStackEmpty(S)) {
while (T) {
Push(S, T);
T = T->Left;
}
if (!IsStackEmpty(S)) {
T = Pop(S);
if (!T->Left && !T->Right) { /* 当该结点的左子树和右子树都为空,访问 */
Visited(T);
}
T = T->Right;
}
}
} /**
* 求树高
*/
int PostOrderGetHeight(BinTree *BT) {
int LH, RH, MaxH;
if (BT) {
LH = PostOrderGetHeight(BT->Left);
RH = PostOrderGetHeight(BT->Right);
MaxH = (LH > RH ? LH : RH);
return MaxH + ;
}
return ;
}
源代码:Test.c
#include <stdio.h>
#include <stdlib.h>
#include "header.h" extern BinTree *CreateBinTree();
extern void PreOrderTraversal(BinTree *BT);
extern void InOrderTraversal(BinTree *BT);
extern void PreOrderTraversal(BinTree *BT);
extern void InOrderTraversal(BinTree *BT);
extern void PostOrderTraversal(BinTree *BT);
extern void PreOrderTraversal_Iter(BinTree *BT);
extern void InOrderTraversal_Iter(BinTree *BT);
extern void PostOrderTraversal_Iter1(BinTree *BT);
extern void PostOrderTraversal_Iter2(BinTree *BT);
extern void LevelOrderTraversal(BinTree *BT);
extern void getOrderPrintLeaves(BinTree *BT);
extern void getOrderPrintLeaves_Iter(BinTree *BT);
extern int PostOrderGetHeight(BinTree *BT); int main() {
puts("START!!!"); printf("\n层序序列生成二叉树,请输入层序序列(类型为int,0代表为树的位置为NULL):\n");
BinTree * BT = CreateBinTree(); printf("PreOrderTraversal: ");
PreOrderTraversal(BT);
printf("\n"); printf("InOrderTraversal: ");
InOrderTraversal(BT);
printf("\n"); printf("PostOrderTraversal: ");
PostOrderTraversal(BT);
printf("\n"); printf("PreOrderTraversal_Iter: ");
PreOrderTraversal_Iter(BT);
printf("\n"); printf("InOrderTraversal_Iter: ");
InOrderTraversal_Iter(BT);
printf("\n"); printf("PostOrderTraversal_Iter1: ");
PostOrderTraversal_Iter1(BT);
printf("\n"); printf("PostOrderTraversal_Iter2:");
PostOrderTraversal_Iter2(BT);
printf("\n"); printf("LevelOrderTraversal: ");
LevelOrderTraversal(BT);
printf("\n"); printf("getOrderPrintLeaves: ");
getOrderPrintLeaves(BT);
printf("\n"); printf("getOrderPrintLeaves_Iter: ");
getOrderPrintLeaves_Iter(BT);
printf("\n"); printf("PostOrderGetHeight: %d",PostOrderGetHeight(BT));
printf("\n"); puts("END!!!");
return EXIT_SUCCESS;
}
Test.c
运行结果:
版权声明:本文为博主原创文章,未经博主允许不得转载。
C实现二叉树(模块化集成,遍历的递归与非递归实现)的更多相关文章
- 数据结构二叉树的递归与非递归遍历之java,javascript,php实现可编译(1)java
前一段时间,学习数据结构的各种算法,概念不难理解,只是被C++的指针给弄的犯糊涂,于是用java,web,javascript,分别去实现数据结构的各种算法. 二叉树的遍历,本分享只是以二叉树中的先序 ...
- 二叉树3种递归和非递归遍历(Java)
import java.util.Stack; //二叉树3种递归和非递归遍历(Java) public class Traverse { /******************一二进制树的定义*** ...
- Java二叉树实现及递归与非递归遍历实现
树的遍历分两种:1.深度优先遍历 1.1 递归算法实现 2.2 非递归算法实现(使用栈存储)2.广度优先遍历(使用队列存储) import java.util.*; /** * 类功能描述: 二叉树遍 ...
- JAVA递归、非递归遍历二叉树(转)
原文链接: JAVA递归.非递归遍历二叉树 import java.util.Stack; import java.util.HashMap; public class BinTree { priva ...
- 二叉树的创建、遍历(递归和非递归实现)、交换左右子数、求高度(c++实现)
要求:以左右孩子表示法实现链式方式存储的二叉树(lson—rson),以菜单方式设计并完成功能任务:建立并存储树.输出前序遍历结果.输出中序遍历结果.输出后序遍历结果.交换左右子树.统计高度,其中对于 ...
- 二叉树前中后/层次遍历的递归与非递归形式(c++)
/* 二叉树前中后/层次遍历的递归与非递归形式 */ //*************** void preOrder1(BinaryTreeNode* pRoot) { if(pRoot==NULL) ...
- Java实现二叉树的先序、中序、后序、层序遍历(递归和非递归)
二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的.对于二叉树,有前序.中序以及后序三种遍历方法.因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易 ...
- 玩透二叉树(Binary-Tree)及前序(先序)、中序、后序【递归和非递归】遍历
基础预热: 结点的度(Degree):结点的子树个数:树的度:树的所有结点中最大的度数:叶结点(Leaf):度为0的结点:父结点(Parent):有子树的结点是其子树的根节点的父结点:子结点/孩子结点 ...
- Java - 二叉树递归与非递归
树的定义具有递归特性,因此用递归来遍历比较符合特性,但是用非递归方式就比较麻烦,主要是递归和栈的转换. import java.util.Stack; /** * @author 李文浩 * @ver ...
随机推荐
- git 配置文件
设置记住密码(默认15分钟): git config --global credential.helper cache 如果想自己设置时间,可以这样做: git config credential.h ...
- genymotion 模拟器 真是牛叉了 速度超快啊!!! 不解释了!建议大家速度去体验一把吧!
已经有人写了blog了 我就不再赘述了,详情去这里看去吧!! android genymotion模拟器怎么使用以及和google提供的模拟器性能对比 http://blog.csdn.net/ ...
- 权威指南学习心得-浏览器中的js
window对象:表示web了浏览器的一个窗口或窗体(winow属性引用自身) 含有以下属性:location包含Location对象,指定当前显示在窗口中URL,允许脚本往窗口里载入新的URL 含有 ...
- 我的小前端 (2)—— JQ和zepto
没有什么特别新技术,就是记录我做移动端遇到的问题 2016-02-16 关于JS库 JQ很简单,网上很多插件效果都依赖它,但JQ库很大 zepto.js用简单效果,很好用 <script src ...
- JavaScript之面向对象学习一
1.通过Object构造函数和对象字面量来创建对象缺点:使用同一个接口创建很多的对象,会产生大量的重复代码.比如我需要创建人的对象,并且需要三类人,医生.工程师.老师,他们可以抽象出很多属性,比如姓名 ...
- hive join 优化
common join : 即reducer join,瓶颈在shuffle阶段,会产生较大的网络io: map join:即把小表放前面,扫描后放入每个节点的内存,在map阶段进行匹配: 开启map ...
- 提供一段Excel获取Title的标题,类似于A、AA、AAA,我们操作Excel的时候通常根据次标题来获取一定的操作范围。
/******************************************** FormatExcelColumTitle Purpose Get excel title like &qu ...
- BZOJ 3170: [Tjoi 2013]松鼠聚会( sort )
题目的距离为max(|x1-x2|, |y1-y2|) (切比雪夫距离). 切比雪夫距离(x, y)->曼哈顿距离((x+y)/2, (x-y)/2) (曼哈顿(x, y)->切比雪夫(x ...
- linux杂记(十一)Bash Shell的使用环境
Bash Shell使用环境 Bash Shell使用环境 1.登录讯息显示数据:/etc/issue,/etc/motd 我们在终端机接口(tty1~tty6)登入的时候,会有几行提示的字符串,那个 ...
- 星际SC地图制作中生成随机位置,也包括所有需要随机的效果
星际SC地图制作中生成随机位置,也包括所有需要随机的效果 利用单位 kakaru T 开头那个, kakaru是随机变化位置 注意kakaru的放置位置和占用格子大小,kakaru周围放上LOCATI ...