二叉树的非递归算法因为涉及到栈和队列,所以写的时候总是受到伪代码的干扰,要完整的补全栈和队列的结构有些麻烦,这里借鉴了一些大佬的思想,发现可以直接在树中模拟栈和队列的存在,这给非递归的完整代码带来了很大的便利,与我而言,深受启发!
1.先序创建二叉树
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
//定义二叉树的结构体
typedef struct BiNode {
char data;
struct BiNode* lchild;
struct BiNode* rchild;
}BiNode, * BiTree;
//先序创建二叉树
BiTree CreateBiTree() {
BiNode* T = NULL;
char ch;
ch = getchar();//先序输入树的各个节点值
if (ch != '#') {
T = (BiNode*)malloc(sizeof(BiNode));
T->data = ch;
T->lchild = CreateBiTree();
T->rchild = CreateBiTree();
}
else {
T = NULL;
}
return T;
}
2.非递归先序遍历二叉树
//非递归先序遍历二叉树
void PreOrder(BiTree T) {
BiTree stack[MAXSIZE], node;//模拟栈
int top = 0;
if (T == NULL) {
printf("树为空树!\n");
return;
}
else {
top++;
stack[top] = T;
while (top > 0) {
//出栈
node = stack[top--];
printf("%c ", node->data);
//先把右子树放进去,再放左子树,栈先进后出,左先出
if (node->rchild != NULL) {
stack[++top] = node->rchild;//入栈
}
if (node->lchild != NULL) {
stack[++top] = node->lchild;
}
}
}
}
3.非递归中序遍历二叉树
//非递归中序遍历二叉树
void InOrder(BiTree T) {
BiTree stack[MAXSIZE], node;
int top = 0;
if (T == NULL) {
printf("树为空树!\n");
return;
}
node = T;
while (node != NULL || top > 0) {
//将所有的左子树节点入栈
while (node != NULL) {
stack[++top] = node;
node = node->lchild;
}
//此时指针指向节点的左孩子为空节点,访问节点
node = stack[top--];
printf("%c ", node->data);
//指针指向右孩子
node = node->rchild;
}
}
4.非递归后序遍历二叉树
//非递归后序遍历二叉树
void PostOrder(BiTree T) {
BiNode* p = T;
BiNode* stack[MAXSIZE];
BiNode* r = NULL;//辅助指针,记录被访问过的节点
int top = 0;
while (p || top > 0) {
while (p) { //走到最左边
stack[top++] = p;
p = p->lchild;
}
p = stack[top - 1]; //指针指向最后一个入栈的左节点
if (NULL== p->rchild || p->rchild == r) {//此节点没有右孩子或者右孩子已经访问过
printf("%c ", p->data);//访问该节点值
top--;
r = p; //记录最近访问过的节点
p = NULL; //节点访问完后重置p指针
}
else {
p = p->rchild; //右孩子存在则指向右孩子,重复上面操作
}
}
}
5.非递归层序遍历二叉树
//非递归层序遍历二叉树
void InvertLevel(BiTree T) {
BiTree stack[MAXSIZE],node;//栈
node = T;
int front = 0;//模拟队列队头
int rear = 0;//模拟队列队尾
stack[rear++] = node;
if (T == NULL) {
printf("树为空树!\n");
return;
}
while (front != rear) {//队列不为空
node = stack[front++];//先获取队头元素,然后再指向队列的下一位元素
printf("%c ", node->data);//访问节点元素
if (node->lchild) {
stack[rear++] = node->lchild; //此节点左孩子不空,则入队列
}
if (node->rchild) {
stack[rear++] = node->rchild; //此节点右孩子不空,则入队列
}
} //自上而下,从左到右依次遍历
}
6.非递归层序遍历求解二叉树的高度
//非递归层序遍历求解二叉树的高度
int TreeDepth(BiTree T) {
if (!T)
return 0; //树空,高度为0
BiTree Q[MAXSIZE]; //设置队列Q
int front = -1, rear = -1; //队头和队尾指针
int last = 0,level = 0; //last指向每层的最后一个节点的位置
Q[++rear] = T; //根节点入队
BiTree p; //工作指针
while (front < rear) { //队列不为空,则循环
p = Q[++front]; //队列元素出队,对其进行访问
if (p->lchild)
Q[++rear] = p->lchild; //左孩子入队
if (p->rchild)
Q[++rear] = p->rchild; //右孩子入队
if (front == last) { //处理该层的最右结点
level++;
last = rear; //last指向下一层
}
}
return level;
}
7.完整代码+测试运行
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 100
//定义二叉树的结构体
typedef struct BiNode {
char data;
struct BiNode* lchild;
struct BiNode* rchild;
}BiNode, * BiTree;
//先序创建二叉树
BiTree CreateBiTree() {
BiNode* T = NULL;
char ch;
ch = getchar();//先序输入树的各个节点值
if (ch != '#') {
T = (BiNode*)malloc(sizeof(BiNode));
T->data = ch;
T->lchild = CreateBiTree();
T->rchild = CreateBiTree();
}
else {
T = NULL;
}
return T;
}
//非递归先序遍历二叉树
void PreOrder(BiTree T) {
BiTree stack[MAXSIZE], node;//模拟栈
int top = 0;
if (T == NULL) {
printf("树为空树!\n");
return;
}
else {
top++;
stack[top] = T;
while (top > 0) {
//出栈
node = stack[top--];
printf("%c ", node->data);
//先把右子树放进去,再放左子树,栈先进后出,左先出
if (node->rchild != NULL) {
stack[++top] = node->rchild;//入栈
}
if (node->lchild != NULL) {
stack[++top] = node->lchild;
}
}
}
}
//非递归中序遍历二叉树
void InOrder(BiTree T) {
BiTree stack[MAXSIZE], node;
int top = 0;
if (T == NULL) {
printf("树为空树!\n");
return;
}
node = T;
while (node != NULL || top > 0) {
//将所有的左子树节点入栈
while (node != NULL) {
stack[++top] = node;
node = node->lchild;
}
//此时指针指向节点的左孩子为空节点,访问节点
node = stack[top--];
printf("%c ", node->data);
//指针指向右孩子
node = node->rchild;
}
}
//非递归后序遍历二叉树
void PostOrder(BiTree T) {
BiNode* p = T;
BiNode* stack[MAXSIZE];
BiNode* r = NULL;//辅助指针,记录被访问过的节点
int top = 0;
if (T == NULL) {
printf("树为空树!\n");
return;
}
while (p || top > 0) {
while (p) { //走到最左边
stack[top++] = p;
p = p->lchild;
}
p = stack[top - 1]; //指针指向最后一个入栈的左节点
if (NULL== p->rchild || p->rchild == r) {//此节点没有右孩子或者右孩子已经访问过
printf("%c ", p->data);//访问该节点值
top--;
r = p; //记录最近访问过的节点
p = NULL; //节点访问完后重置p指针
}
else {
p = p->rchild; //右孩子存在则指向右孩子,重复上面操作
}
}
}
//非递归层序遍历二叉树
void InvertLevel(BiTree T) {
BiTree stack[MAXSIZE],node;//栈
node = T;
int front = 0;//模拟队列队头
int rear = 0;//模拟队列队尾
stack[rear++] = node;
if (T == NULL) {
printf("树为空树!\n");
return;
}
while (front != rear) {//队列不为空
node = stack[front++];//先获取队头元素,然后再指向队列的下一位元素
printf("%c ", node->data);//访问节点元素
if (node->lchild) {
stack[rear++] = node->lchild; //此节点左孩子不空,则入队列
}
if (node->rchild) {
stack[rear++] = node->rchild; //此节点右孩子不空,则入队列
}
} //自上而下,从左到右依次遍历
}
//非递归层序遍历求解二叉树的高度
int TreeDepth(BiTree T) {
if (!T)
return 0; //树空,高度为0
BiTree Q[MAXSIZE]; //设置队列Q
int front = -1, rear = -1; //队头和队尾指针
int last = 0,level = 0; //last指向每层的最后一个节点的位置
Q[++rear] = T; //根节点入队
BiTree p; //工作指针
while (front < rear) { //队列不为空,则循环
p = Q[++front]; //队列元素出队,对其进行访问
if (p->lchild)
Q[++rear] = p->lchild; //左孩子入队
if (p->rchild)
Q[++rear] = p->rchild; //右孩子入队
if (front == last) { //处理该层的最右结点
level++;
last = rear; //last指向下一层
}
}
return level;
}
int main() {
BiTree T = CreateBiTree();
// BiTree T = create_tree();
printf("非递归先序遍历二叉树:\n");
PreOrder(T);
printf("\n");
printf("非递归中序遍历二叉树:\n");
InOrder(T);
printf("\n");
printf("非递归后序遍历二叉树:\n");
PostOrder(T);
printf("\n");
printf("非递归层序遍历二叉树:\n");
InvertLevel(T);
printf("\n");
printf("非递归计算二叉树的深度为:\n");
printf("树的深度为:%d\n", TreeDepth(T));
return 0;
}