数据结构----二叉树的遍历

0 阅读4分钟

二叉树的遍历

按照某种路径对二叉树的每个节点进行逐个访问

二叉树的层次遍历

按层次进行遍历,把二叉树的每一层从左到右遍历.

image.png

#include<stdio.h>
#include<stdlib.h>
//链式队列
//队列节点结构
typedef struct QNode {
	char data;//树节点的数据域入队
	struct QNode* next;
}QNode;
//队列
typedef struct Queue {
	QNode* f;
	QNode* r;
}Queue;

Queue InitQueue() {
	Queue q;
	q.f = (QNode*)malloc(sizeof(QNode));
	if (q.f == NULL) {
		printf("内存申请失败\n");
		return q;
	}
	q.f->next = NULL;
	q.r = q.f;
	return q;
}

void EnQueue(Queue* q, char x) {
	QNode* s = (QNode*)malloc(sizeof(QNode));
	if (s == NULL) {
		printf("内存申请失败\n");
		return;
	}
	s->data = x;
	s->next = NULL;
	q->r->next = s;
	q->r = s;
	return;
}

int empty(Queue* q) {
	if (q->f->next == NULL) {
		return 1;
	}
	return 0;
}

char DeQueue(Queue* q) {
	char x = ' ';
	if (empty(q)) {
		printf("队列为空无法出队\n");
		return x;
	}
	else {
		QNode* p = q->f->next;
		x = p->data;
		if (q->f->next == q->r)//队列中只有一个节点
		{
			q->r = q->f;
		}
		q->f->next = p->next;
		free(p);
		p = NULL;
	}
	return x;
}



//树的结构----二叉链表
//节点结构
typedef struct BTNode {
	char data;
	struct BTNode* l;
	struct BTNode* r;
}BTNode,*BTree;

BTree InitTree(char root) {
	BTNode* rt = (BTNode*)malloc(sizeof(BTNode));
	if (rt == NULL) {
		printf("内存申请失败\n");
		return rt;
	}
	rt->data = root;
	rt->l = NULL;
	rt->r = NULL;
	return rt;
}

BTNode* Find(BTree root, char x) {
	if (root == NULL) {
		return NULL;
	}
	if (root->data == x) {
		return root;
	}
	if (root->l != NULL) {
		BTNode* ans = Find(root->l,x);
		if (ans != NULL && ans->data == x) {
			return ans;
		}
	}
	if (root->r != NULL) {
		BTNode* ans = Find(root->r,x);
		if (ans != NULL && ans->data == x) {
			return ans;
		}
	}
	return NULL;
}

BTree Insert(BTree root, char x, char fx, int flag) {
	BTNode* f = Find(root, fx);//父亲节点的位置
	BTNode* s = (BTNode*)malloc(sizeof(BTNode));
	if (s == NULL) {
		printf("内存申请失败\n");
		return root;
	}
	s->data = x;
	s->l = NULL;
	s->r = NULL;
	if (flag == 0)//左孩子
	{
		f->l = s;
	}
	else {
		f->r = s;
	}
	return root;
}
//-------------------------------------------------------------
//层次遍历
void LevelOrderBT(BTree root) {
	Queue q = InitQueue();
	EnQueue(&q,root->data);
	char x;
	BTNode* p = NULL;
	while (!empty(&q)) {
		x = DeQueue(&q);
		printf("%c ", x);
		p = Find(root, x);
		if (p->l != NULL) {
			EnQueue(&q, p->l->data);
		}
		if (p->r != NULL) {
			EnQueue(&q, p->r->data);
		}
	}
}

//先序遍历
void PreOrderBT(BTree root) {
	if (root == NULL) {
		return NULL;
	}
	//1.访问根节点
	printf("%c ", root->data);
	//先序遍历左子树
	PreOrderBT(root->l);
	//先序遍历右子树
	PreOrderBT(root->r);
}

//中序遍历
void InOrderBT(BTree root) {
	if (root == NULL) {
		return NULL;
	}
	//中序遍历左子树
	InOrderBT(root->l);
	//访问根节点
	printf("%c ", root->data);
	//中序遍历右子树
	InOrderBT(root->r);
}

//后序遍历
void PostOrderBT(BTree root) {
	if (root == NULL) {
		return NULL;
	}
	//后序遍历左子树
	PostOrderBT(root->l);
	//后序遍历右子树
	PostOrderBT(root->r);
	//访问根节点
	printf("%c ", root->data);
}
int main() {
	int n;
	int flag;//0是左孩子 1是右孩子
	scanf("%d", &n);
	getchar();
	char x, fx;
	scanf("%c", &x);
	BTree root = InitTree(x);
	for (int i = 0; i < n - 1; i++) {
		getchar();
		scanf("%c %c %d", &x, &fx,&flag);
		Insert(root, x, fx, flag);
	}
	LevelOrderBT(root);
	printf("\n");
	PreOrderBT(root);
	printf("\n");
	InOrderBT(root);
	printf("\n");
	PostOrderBT(root);
	printf("\n");
	return 0;
}

/*
9
A
B A 0
E A 1
C B 1
F E 1
D C 0
G F 0
H G 0
K G 1
*/

首先先搭建队列的结构,这里采用链式的队列.

队列的节点数据域有两种选择:1.直接记录节点的数据.优点是队列的结构简单明了.缺点在于进行后续出队操作时需要通过Find函数找到相对应的节点.2.记录节点地址.优点缺点与前者相反.在这里我们选择第一种方法.队列的结构只需要一个头指针和一个尾指针即可.队列操作 树的二叉链表以及初始化操作均在以前的博客中提及,需要了解的读者可自行阅读,本文重点在于深度层级遍历.

层级遍历: 初始化队列q后,先将根节点入队.只要队列不空那么就让队首元素出队 访问,同时把队首元素的左右子节点分别入队.直到队列为空,整棵树都遍历完毕.

二叉树的深度遍历

二叉树的深度遍历分为三种:前序遍历 中序遍历 后序遍历

二叉树可以抽象为根节点,左子树,右子树.而这三种遍历方式的区别就是遍历这三者的顺序,例如前序遍历就是先遍历根节点再遍历左子树最后遍历右子树.而对不同节点的操作逻辑都是相同的,所以我们可以用递归来操作.

//先序遍历
void PreOrderBT(BTree root) {
	if (root == NULL) {
		return NULL;
	}
	//1.访问根节点
	printf("%c ", root->data);
	//先序遍历左子树
	PreOrderBT(root->l);
	//先序遍历右子树
	PreOrderBT(root->r);
}

//中序遍历
void InOrderBT(BTree root) {
	if (root == NULL) {
		return NULL;
	}
	//中序遍历左子树
	InOrderBT(root->l);
	//访问根节点
	printf("%c ", root->data);
	//中序遍历右子树
	InOrderBT(root->r);
}

//后序遍历
void PostOrderBT(BTree root) {
	if (root == NULL) {
		return NULL;
	}
	//后序遍历左子树
	PostOrderBT(root->l);
	//后序遍历右子树
	PostOrderBT(root->r);
	//访问根节点
	printf("%c ", root->data);
}

先判断根节点是否为空,然后分别按照不同的顺序递归调用本函数.