C语言数据结构学习——二叉树遍历法

本文详细介绍了如何使用C语言进行二叉树的前序、中序和后序遍历。通过实例代码解析,帮助读者理解递归和非递归遍历方法,深入掌握数据结构中的二叉树操作。

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

#include <stdio.h>
#include <string.h>
#define TElemType int

int top = -1; // top变量时刻表示栈顶元素所在位置

//初始化队头和队尾指针开始时都为0
int front = 0, rear = 0;

//构造结点的结构体
typedef struct BiTNode {
	TElemType data; // 数据域
	struct BiTNode* lchild, * rchild; //左右孩子指针
}BiTNode,*BiTree;

// 初始化树的函数
void createBiTree(BiTree *T) {
	*T = (BiTNode*)malloc(sizeof(BiTNode));
	(*T)->data = 1;
	(*T)->lchild = (BiTNode*)malloc(sizeof(BiTNode));
	(*T)->rchild = (BiTNode*)malloc(sizeof(BiTNode));

	(*T)->lchild->data = 2;
	(*T)->lchild->lchild = (BiTNode*)malloc(sizeof(BiTNode));
	(*T)->lchild->rchild = (BiTNode*)malloc(sizeof(BiTNode));
	(*T)->lchild->rchild->data = 5;
	(*T)->lchild->rchild->lchild = NULL;
	(*T)->lchild->rchild->rchild = NULL;

	(*T)->rchild->data = 3;
	(*T)->rchild->lchild = (BiTNode*)malloc(sizeof(BiTNode));
	(*T)->rchild->lchild->data = 6;
	(*T)->rchild->lchild->lchild = NULL;
	(*T)->rchild->lchild->rchild = NULL;

	(*T)->rchild->rchild = (BiTNode*)malloc(sizeof(BiTNode));
	(*T)->rchild->rchild->data = 7;
	(*T)->rchild->rchild->lchild = NULL;
	(*T)->rchild->rchild->rchild = NULL;
	(*T)->lchild->lchild->data = 4;
	(*T)->lchild->lchild->lchild = NULL;
	(*T)->lchild->lchild->rchild = NULL;
}

// 模拟操作节点元素的函数, 输出节点本身的数值
void displayElem(BiTNode* elem) {
	printf("%d ", elem->data);
}

//前序遍历使用的进栈函数
void push(BiTNode** a, BiTNode* elem) {
	a[++top] = elem;
}

// 弹栈函数
void pop() {
	if (top == -1) {
		return;
	}
	top --;
}

// 入队函数
void enQueue(BiTree *a, BiTree node) {
	a[rear++] = node;
}

BiTNode* deQueue(BiTNode** a) {
	return a[front++];
}

// 拿到栈顶元素
BiTNode* getTop(BiTNode**a) {
	return a[top];
}

// 递归先序遍历
void preOrderTraverse1(BiTree T) {
	if (T) {
		displayElem(T); //调用操作结点数据的函数方法
		preOrderTraverse1(T->lchild); // 访问该节点的左孩子
		preOrderTraverse1(T->rchild); // 访问该结点的右孩子
	}
	// 如果节点为空, 返回上一层
	return;
}

// 递归中序遍历
void inOrderTraverse1(BiTree T) {
	if (T) {
		inOrderTraverse1(T->lchild); //遍历左孩子
		displayElem(T); //调用操作结点数据的函数方法
		inOrderTraverse1(T->rchild); //遍历右孩子
	}
	// 如果结点为空 返回上一层
	return;
}

// 递归后序遍历
void postOrderTraverse1(BiTree T) {
	if (T) {
		postOrderTraverse1(T->lchild); // 遍历左孩子
		postOrderTraverse1(T->rchild); // 遍历右孩子
		displayElem(T); //调用操作结点数据的函数方法
	}
	// 如果结点为空,返回上一层
	return;
}

// 非递归先序遍历
void preOrderTraverse2(BiTree T) {
	BiTNode* a[20]; // 定义一个顺序栈
	BiTNode* p; //临时指针
	push(a, T); //根结点进栈
	while (top != -1) {
		p = getTop(a); // 取栈顶元素
		pop(); // 弹栈
		while (p) {
			displayElem(p); // 调用节点的操作函数
			//如果该结点有右孩子,右孩子进栈
			if (p->rchild) {
				push(a, p->rchild);
			}
			p = p->lchild;// 一直指向根结点最后一个左孩子
		}
	}
}

// 非递归中序遍历1
void inOrderTraverse2(BiTree T) {
	BiTNode* a[20]; //定义一个顺序栈
	BiTNode * p; //临时指针
	push(a, T); // 根结点进栈
	while (top != -1) { // top != -1说明栈内不为空,程序继续运行
		while ((p = getTop(a)) && p) {//取栈顶元素,且不能为NULL
			push(a, p->lchild); // 将该结点的左孩子进栈, 如果没有左孩子,NULL进栈
		}
		pop(); //跳出循环,栈顶元素肯定为NULL, 将NULL弹栈
		if (top != -1){
			p = getTop(a); // 取栈顶元素
			pop(); //栈顶元素弹栈
			displayElem(p);
			push(a, p->rchild); // 将p指向的结点的右孩子进栈

		}
	}
}

// 非递归中序遍历2
void inOrderTraverse3(BiTree T) {
	BiTNode* a[20]; //定义一个顺序栈
	BiTNode * p; //临时指针
	p = T;
	// 当p为NULL或者栈为空时, 表明树遍历完成
	while (p || top != -1) {
		// 如果p不为NULL, 将其压栈并遍历其左子树
		if (p) { 
			push(a, p);
			p = p->lchild;
		}
		// 如果p==NULL,表面左子树遍历完成,需要遍历上一层结点的右子树
		else {
			p = getTop(a);
			pop();
			displayElem(p);
			p = p->rchild;
		}
	}
}

typedef struct SNode {
	BiTree p;
	int tag;
}SNode;

// 后序遍历使用的进栈函数
void postPush(SNode *a, SNode sdata) {
	a[++top] = sdata;
}

// 非递归后序遍历
void postOrderTraverse2(BiTree T) {
	SNode a[20]; // 定义一个顺序栈
	BiTNode * p; // 临时指针
	int tag;
	SNode sdata;
	p = T;
	while (p || top != -1){
		while (p) {
			// 为该节点入栈做准备
			sdata.p = p;
			sdata.tag = 0; //由于遍历是左孩子,设置标志位为0
			postPush(a, sdata);//压栈
			p = p->lchild; // 以该结点为根节点,遍历左孩子
		}
		sdata = a[top]; // 取栈顶元素
		pop(); // 栈顶元素弹栈
		p = sdata.p;
		tag = sdata.tag;
		// 如果tag==0,说明该节点换没有遍历他的左孩子
		if (tag == 0) {
			sdata.p = p;
			sdata.tag = 1;
			postPush(a, sdata);// 更改该结点的标志位,重新压栈
			p = p->rchild; //以该结点的右孩子为根节点,重新循环
		}
		// 如果取出来的栈顶元素的tag == 1,说明此结点左右子树都遍历完了,可以调用操作函数了
		else {
			displayElem(p);
			p = NULL;
		}
	}
}

// 层次遍历
void levelTraverse(BiTree T) {
	BiTNode* p; // 临时指针
	BiTree a[20]; // 采用顺序队列,初始化创建队列数组
	//根节点入队
	enQueue(a, T);
	// 当队头和队尾相等时, 表示队列为空
	while (front < rear) {
		//队头结点出队
		p = deQueue(a);
		displayElem(p);
		//将队头结点的左右孩子依次入队
		if (p->lchild != NULL) {
			enQueue(a, p->lchild);
		}
		if (p->rchild != NULL) {
			enQueue(a, p->rchild);
		}
	}
	return 0;
}


int main() {
	BiTree tree;
	createBiTree(&tree);
	printf("\n先序遍历递归:\n");
	preOrderTraverse1(tree);
	printf("\n先序非遍历递归:\n");
	preOrderTraverse2(tree);
	printf("\n中序递归遍历:\n");
	inOrderTraverse1(tree);
	printf("\n中序非递归遍历1:\n");
	inOrderTraverse2(tree);
	printf("\n中序非递归遍历2:\n");
	inOrderTraverse3(tree);
	printf("\n后序递归遍历:\n");
	postOrderTraverse1(tree);
	printf("\n后序非递归遍历:\n");
	postOrderTraverse2(tree);
	printf("\n层次遍历:\n");
	levelTraverse(tree);

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值