纯c代码——构建二叉排序树+层序输出(通过“结构指针”队列)

本文提供了一段使用纯C语言构建二叉搜索树并进行层序遍历的代码示例,旨在帮助C语言初学者更好地理解和掌握数据结构。代码通过VS2019编译,附带详细注释,解释了二叉树的插入操作及层序遍历过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于网上的数据结构大都以C++,或是更抽象的伪代码呈现,造成纯c入门新手学数据结构十分苦恼,特此给出学习过程的一段代码笔记,以帮助c新手入门数据结构
本段代码可通过vs2019编译通过运行

输入样式
10
8 15 3 4 1 5 12 10 18 6
输出结果
8 3 15 1 4 12 18 5 10 6
#pragma warning(disable:4996)
#include <stdio.h>
#include<stdlib.h>//从而使用malloc函数
#define max 30
typedef struct BTNode {
	int key;
	struct BTNode* lchild;
	struct BTNode* rchild;
}BiTree;

BiTree* BstInsert(BiTree* T, int k);
void PrintTree(BiTree* root);

int main() {
	int number = 0;
	scanf("%d", &number);
	int a[30], i = 1;//vs不支持数组用变量定义
	for (; i <= number; i++)
		scanf("%d", &a[i]);
	BiTree* root = NULL;//定义头指针
	int o = 1;
	while (o <= number) {
		root = BstInsert(root, a[o]);
		//由于root会在函数中改变,并要传递回去,因此要root=,而不能单独挂函数
		//传递的是指针本身,因此也不用&,进行取地址多此一举	
		o++;
	}
	PrintTree(root);//有借有还再借不难
	return 0;
}

BiTree* BstInsert(BiTree* T, int k) {//返回的root是一个指针类型,因此要*
	if (T == NULL) {
		T = (BiTree*)malloc(sizeof(BiTree));//malloc默认返回void,因此要强制类型转换
		T->key = k;
		T->lchild = T->rchild = NULL;
	}
	else if (k < T->key)
		T->lchild = BstInsert(T->lchild, k);
	else if (k > T->key)
		T->rchild = BstInsert(T->rchild, k);
	return T;//这句很重要。。要把改变/连起来的树传递回去
}

void PrintTree(BiTree* T) {
	int front = 0, rear = 0;
	BiTree* b[max];
	//定义并初始化
	//一个BiTree指针队列(用来存放BiTree指针)“企业级代码”
	BiTree* q;//指针临时存放点
	if (T != NULL) {
		rear = (rear + 1) % max;
		b[rear] = T;
		//根结点入队
		while (front != rear) {//队列不空循环
			front = (front + 1) % max;
			q = b[front];
			//出队
			printf("%d ", q->key);
			//访问
			if (q->lchild != NULL) {
				rear = (rear + 1) % max;
				b[rear] = q->lchild;
			}
			//左子树根节点入队
			if (q->rchild != NULL) {
				rear = (rear + 1) % max;
				b[rear] = q->rchild;
			}
			//右子树根节点入队
		}
	}
}

层序输出过程解析

未进入循环前,rear将根节点存放在b1,
进入1轮循环
(front读出)根节点交给临时指针q,同时输出该指针的key
在然后将根结点的2个儿子存放在b2,b3
2轮循环
输出b2(根节点左儿子)
并将其2个儿子存放在b4,b5
3轮循环
输出b3(根节点右儿子)
并将其2个儿子存放在b6,b7
因此 front是输出端,rear是进入端
每次循环输出1个,输入至多2个
当front和rear贴到一起,则循环结束(说明没有输入了)

题外话1

为何我说 结构指针 是“企业级代码”
原因在于目前层序输出大多采用 王道书上那种偏模块化函数的写法
个人理解如果只是做个层序输出,完全没有必要嵌套那么多层函数,写起来相对繁琐。上述写法相对更清晰明了
而这种技巧实质是十分常见的。
详情可看 中国大学MOOC《翁恺老师——C语言程序结构设计》第14周链表第3课 其中有讲到返回结构类型的3种办法

题外话2

c入坑多少还是要再学C++的,毕竟C++直接封装了队列,栈这类常用函数,相对程序运行也会更快更稳定,写起来也容易,记忆也会更容易

STL库函数层序输出版本

相对而言更为简洁,更容易理解

#include<queue>
using namespace std;//头上加一段
void PrintTree(BiTree* T) {
	queue<BiTree*> b;
	if (T != NULL) {
		b.push(T);
		while (b.empty() != true) {//队列不空循环
			if (b.front()->lchild != NULL)
				b.push(b.front()->lchild);
				//不空则左子树入队
			if (b.front()->rchild != NULL)
				b.push(b.front()->rchild);
			printf("%d ", b.front()->key);//输出队头元素(队头也就是先进的)
			b.pop();//当父结点的2个子结点全都入队,并print过了,任务完成出队
		}
	}
}

如果有心去内存看STL的队列实现方式
会发现这种队列确实会更高效
原因他实现更像是链表,可以进行动态的删除(出队)插入(入队)
而传统的队列实现更多是依靠数组,所谓插入删除也只是数组下标的变动罢了,本质是数据还是存在内存,占据了空间
当然队列也是可以构造链表来实现,但是相应的插入删除也变得更为复杂

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值