【C语言】【数据结构】菜鸟学习日志(四) 用二叉树实现非递归排序
唉,由于要备战考研,这篇博文可能是我这一年最后一次更新啦!
其实断断续续的也没有写很多,而且大多都是很初级、很简单的东西,没有和大家分享什么高阶的东西。这也正应了我们《菜鸟学习日志》的标题嘛!
不过说回来我还是很喜欢写博文的。一方面总结学到的知识,以后也可以自己看看别做了就忘了;另一方面,写博文也让我在学习的过程中更加认真,以免分享了错误的知识。
写的东西好不好呢是一说,好像有一些点击量,不过看的人估计也不多。只是我还算乐在其中吧!
大学生活说到底过得有点浪了,导致我苦逼地走向了考研的不归路……
这次分享的博文也没什么高深的东西。今年和我一起选修了C语言的同学一看就明白为什么我要写这个了~
反正很简单,我也不多解释了了,直接上代码。代码中已经给出了详细的注释,全是干货。
这个代码算是写的比较健壮一些了,如果你觉得太麻烦也可以精简掉一些部分。
另外,如果有什么不明白或者可以改进的地方,都可以给我留言!
更多的博文,我们明年见吧!:)
-------------------------------------------
/*
binary_tree.c
将给定文件中的数据按照中序由小到大的顺序在二叉树中排序,再写入到文件中
这个程序采用非递归的算法(老师要求)
假设源文件和目标文件是两个不同的文件
假设文件中的数据为整型数
假设数据之间用空格符隔开
假设没有重复的数据
*/
#include <stdio.h>
#include <stdlib.h>
#define SFILE "/home/arcane/C_learning/binary_tree/num_1" //源文件
#define OFILE "/home/arcane/C_learning/binary_tree/num_2" //目标文件
#define MAXNODES 50 //栈能存放的最大节点数
//定义了二叉树节点的结构体
struct node
{
int data;
struct node *plc;
struct node *prc;
};
//用于遍历时存放节点的栈(数组)
struct node *nodes[MAXNODES];
//记录栈中节点的个数
int count = 0;
//用于创建节点
struct node *createNode(int data);
//根据值的大小在二叉树中插入节点
struct node *addNode(int value, struct node *pn);
//栈操作,压栈
int push(struct node *pn);
//栈操作,出栈
struct node *pop();
int main(void)
{
FILE *fp; //文件指针
struct node *proot = NULL; //指向根节点的指针
struct node *pn; //指向任意节点的指针
struct node *p; //用于辅助释放分配的空间
int num = 0; //计算和记录从文件中读出的数字
//把数据按顺序读入二叉树
//打开文件
if((fp = fopen(SFILE, "r")) == NULL)
{
printf("文件打开失败!\n");
exit(1);
}
//读取数字并建立二叉树
while((fscanf(fp, "%d", &num)) == 1)
{
if(num != ' ')
{
if(proot == NULL)
proot = createNode(num);
else
addNode(num,proot);
}
}
//关闭文件
fclose(fp);
//将二叉树按中序写入文件,顺便释放给树分配的空间
//打开目标文件
if((fp = fopen(OFILE, "w")) == NULL)
{
printf("文件打开失败!\n");
exit(1);
}
//用循环而非递归的中序遍历,其中用到了栈
pn = proot;
while(1)
{
if(pn->plc != NULL) //左子树存在
{
if(push(pn) == 1)
{
printf("栈溢出!\n");
exit(1);
}
pn = pn->plc;
}
else //左子树不存在
{
//把节点的值写入文件中
fprintf(fp, "%d", pn->data);
if(pn->prc != NULL) //右子树存在
{
putc(' ', fp);
p = pn; //中序遍历,当开始考虑右子树前,这个节点的信息已经写入文件了,所以可以释放了
pn = pn->prc;
free(p);
}
else //右子树不存在
{
free(pn); //左右子树都不存在,这个节点可以释放了
if((pn = pop()) != NULL)
{
putc(' ', fp);
pn->plc = NULL;
}
else
break;
}
}
}
//关闭目标文件
fclose(fp);
return 0;
}
/*
创建一个节点
其值为 value,左右节点为 NULL
*/
struct node *createNode(int value)
{
struct node *pn = (struct node *)malloc(sizeof(struct node));
pn->data = value;
pn->plc = pn->prc = NULL;
return pn;
}
/*
向给定的二叉树中插入一个值为 value 的节点
规则是按中序由小到大的顺序
*/
struct node *addNode(int value, struct node *pn)
{
struct node *p = pn;
//利用循环而非递归的插入
while(1)
{
if(p == NULL) //二叉树不存在
return createNode(value);
if(value < p->data) //属于二叉树的左子树
{
if(p->plc == NULL)
{
p->plc = createNode(value);
return p->plc;
}
else
{
p = p->plc;
}
}
else //属于二叉树的右子树
{
if(p->prc == NULL)
{
p->prc = createNode(value);
return p->prc;
}
else
{
p = p->prc;
}
}
}
}
/*
压栈操作
成功返回0,失败返回1
*/
int push(struct node *pn)
{
if(count == (MAXNODES - 1))
return 1;
nodes[count] = pn;
count++;
return 0;
}
/*
出栈操作
成功返回节点指针,失败返回NULL
*/
struct node *pop()
{
if(count > 0)
return nodes[--count];
return NULL;
}