每一个点开我的文章的小伙伴大家好!
在发这篇文章的时候,我是一名大一的学生,我将在博客记载我的学习之路!
这是我的第二篇博客文章,是关于C语言数据结构的二叉树的操作。
希望你们多多关注我以及把我推荐给你们身边的朋友,我会一个星期发至少一篇文章的!
接下来我会把各个操作给分解 文章末尾附上源码(Visual Studio2022完美运行)!
先给小伙伴们看一下页面:
我们直接进入正题吧!
一、首先是代码开头的各种定义:
#define _CRT_SECURE_NO_WARNINGS //加上这个,我们就不用scanf_s,可以用scanf了
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_NODE 50
typedef char ElemType;
typedef struct BTnode
{
ElemType data;
struct BTnode* Lchild, * Rchild;
}BTNode;
二、就是树结点的输出:(这个在后续的输出会经常用上)
void visit(BTNode*T) //输出操作
{
printf("%c", T->data); // 要用%c是因为我们自己设置输入进去结点的是字母
}
三:建立二叉树:
这里我用方法是先构造出一个节点内的值都是空的满二叉树,也就是说我们得往对应编号的结点内填数据 就像这样的,往对应编号的节点内填数据
当节点编号为0时就停止建立
BTNode* Creat_BiTree() //建立二叉树
{
BTNode* T, * p, * s[MAX_NODE]; //数组栈
ElemType ch;
T = NULL;
int i, j;
system("cls");
while (1)
{
printf("输入节点的编号:\n");
scanf("%d", &i);
if (i == 0) break; //当输入节点的编号为0时就停止建立
printf("输入节点的值:\n");
getchar(); //防止回车键破坏输入
scanf("%c", &ch);
p = (BTNode*)malloc(sizeof(BTNode));
p->data = ch;
p->Lchild = p->Rchild = NULL; //不断构造空的完全二叉树
s[i] = p;
if (i == 1) T = p;
else {
j = i / 2;
if (i % 2 == 0)
s[j]->Lchild = p;
else
s[j]->Rchild=p;
}
i++;
}
system("cls");
printf("输入成功\n");
return T;
}
四、先序遍历二叉树(非递归)
void PreorderTraverse(BTNode* T)
/*非递归先序遍历二叉树T*/
{
BTNode* s[MAX_NODE], * p,*q; //用数组模拟栈
int top=0;
p = T;
system("cls");
if (T == NULL) printf("该树为空树\n");
else {
while (p && top != -1)
{
visit(p);
q = p->Rchild;
if (q != NULL)
s[++top] = q;
p = p->Lchild;
if (p == NULL)
p = s[top--];
}
}
}
五、中序遍历二叉树(非递归)
void InorderTraverse(BTNode* T)
/*非递归中序遍历二叉树*/
{
BTNode* s[MAX_NODE], * p; //数组模拟栈
int top = 0;
int flag = 1;
system("cls");
p = T;
if (T == NULL) printf("该树为空树\n");
else {
do {
while (p)
{
s[++top] = p;
p = p->Lchild;
}
if (top == 0) flag = 0;
else {
p = s[top--];
visit(p);
p = p->Rchild;
}
} while (flag != 0);
}
}
六、递归后序遍历:
void PostorderTraverse(BTNode* T)
/*后续遍历二叉树T*/
{
if (T != NULL)
{
system("cls");
PostorderTraverse(T->Lchild);
PostorderTraverse(T->Rchild);
visit(T); /* 访问根结点 */
}
}
七、层次遍历二叉树:
void LevelorderTraverse(BTNode* T) //层次遍历二叉树
{
BTNode* DL[MAX_NODE], * p; //数组模拟队列
int rear=0, front=0;
system("cls");
p = T;
if (p != NULL) //其实就是队尾指向空的时候就退出
{
DL[++rear] = p;
while (front < rear)
{
p = DL[++front];
visit(p);
if (p->Lchild != NULL)
DL[++rear] = p->Lchild;
if (p->Rchild != NULL)
DL[++rear] = p->Rchild;
}
}
}
八、求二叉树的深度:
int search_depth(BTNode* T)
{
BTNode* Queue[MAX_NODE], * p = T;
int front = 0, rear = 0, depth = 0, level;
/* level总是指向访问层的最后一个结点在队列的位置 */
if (T != NULL)
{
Queue[++rear] = p; /* 根结点入队 */
level = rear; /* 根是第1层的最后一个节点 */
while (front < rear)
{
p = Queue[++front];
if (p->Lchild != NULL) // 左子结点非空,入队
Queue[++rear] = p->Lchild;
if (p->Rchild != NULL) // 右子结点非空,入队
Queue[++rear] = p->Rchild;
if (front == level) // 访问当前层最后一个结点
{
depth++;
level = rear;
}
}
}
return depth;
}
九、输出叶子节点和非叶子节点:
void leaves(BTNode* T)
/*输出叶子节点和非叶子节点*/
{
BTNode* DL[MAX_NODE], * p = T; //数组队列
int front = 0, rear = 0;
system("cls");
if (p != NULL)
{
DL[++rear] = p;
front = 1;
while (front <= rear) {
if (p->Lchild == NULL && p->Rchild == NULL)
printf("叶子节点:%c\n", p->data);
else {
printf("非叶子节点:%c\n", p->data);
if (p->Lchild != NULL)
DL[++rear] = p->Lchild;
if (p->Rchild != NULL)
DL[++rear] = p->Rchild;
}
p = DL[++front];
}
}
}
十、判断二叉树是否为完全二叉树:
int Judge(BTNode* T)//判断该二叉树是否为完全二叉树(层次遍历)
{
BTNode* DL[MAX_NODE],*p; //队列数组
int rear = 0, front = 0;
system("cls");
p = T;
if (p != NULL)
{
DL[++rear] = p;
while (front < rear) {
p = DL[++front];
if ( p->Lchild == NULL && p->Rchild != NULL) //当左子树为空,右子树不为空时,就不符合完全二叉树的性质
return 0;
else {
if (p->Lchild != NULL)
DL[++rear] = p->Lchild;
if (p->Rchild != NULL)
DL[++rear] = p->Rchild;
}
}
}
return 1;
}
十一、main函数的:
做了个菜单:
int main()
{
BTNode* T = NULL;
char ch[10];
while (1)
{
printf("\n======================================================\n");
printf("| 1.建立二叉树T |\n");
printf("| 2.用非递归方式先序遍历方式输出树T的结点 |\n");
printf("| 3.用非递归方式中序遍历方式输出树T的结点 |\n");
printf("| 4.用后序遍历方式输出树T的结点 |\n");
printf("| 5.用层次遍历方式输出树T的结点 |\n");
printf("| 6.输出树T的深度 |\n");
printf("| 7.输出树T的叶子结点和非叶子结点 |\n");
printf("| 8.判断该二叉树是否为完全二叉树(层次遍历) |\n");
printf("| 0.退出程序 |\n");
printf("======================================================\n");
printf("请输入要进行的操作:");
scanf("%s", ch);
if (strcmp(ch, "1") == 0)
T = Creat_BiTree();
else if (strcmp(ch, "2") == 0)
PreorderTraverse(T);
else if (strcmp(ch, "3") == 0)
InorderTraverse(T);
else if (strcmp(ch, "4") == 0)
{
system("cls");
PostorderTraverse(T);
}
else if (strcmp(ch, "5") == 0)
LevelorderTraverse(T);
else if (strcmp(ch, "6") == 0)
{
int depth = search_depth(T);
system("cls");
printf("该二叉树的深度为:%d", depth);
}
else if (strcmp(ch, "7") == 0)
leaves(T);
else if (strcmp(ch, "8") == 0)
{
int n = 0;
n=Judge(T);
if (n == 0)
printf("该树不是完全二叉树\n");
else printf("该树是完全二叉树\n");
}
else if (strcmp(ch, "0") == 0)
{
system("cls");
printf("感谢使用!\n\n");
break;
printf("程序退出失败!\n");
exit(0);
}
else
{
system("cls");
printf("\n非法输入!\n\n");
}
}
}
这里输入建立二叉树是选择编号和填数据的操作可以是这样,当然你们也可以自己创建一个自己的二叉树
最后附上我的源码:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_NODE 50
typedef char ElemType;
typedef struct BTnode
{
ElemType data;
struct BTnode* Lchild, * Rchild;
}BTNode;
void visit(BTNode*T) //输出操作
{
printf("%c", T->data);
}
BTNode* Creat_BiTree() //建立二叉树
{
BTNode* T, * p, * s[MAX_NODE]; //数组栈
ElemType ch;
T = NULL;
int i, j;
system("cls");
while (1)
{
printf("输入节点的编号:\n");
scanf("%d", &i);
if (i == 0) break;
printf("输入节点的值:\n");
getchar(); //防止回车键破坏输入
scanf("%c", &ch);
p = (BTNode*)malloc(sizeof(BTNode));
p->data = ch;
p->Lchild = p->Rchild = NULL; //不断构造空的完全二叉树
s[i] = p;
if (i == 1) T = p;
else {
j = i / 2;
if (i % 2 == 0)
s[j]->Lchild = p;
else
s[j]->Rchild=p;
}
i++;
}
system("cls");
printf("输入成功\n");
return T;
}
void PreorderTraverse(BTNode* T)
/*非递归先序遍历二叉树T*/
{
BTNode* s[MAX_NODE], * p,*q;
int top=0;
p = T;
system("cls");
if (T == NULL) printf("该树为空树\n");
else {
while (p && top != -1)
{
visit(p);
q = p->Rchild;
if (q != NULL)
s[++top] = q;
p = p->Lchild;
if (p == NULL)
p = s[top--];
}
}
}
void InorderTraverse(BTNode* T)
/*非递归中序遍历二叉树*/
{
BTNode* s[MAX_NODE], * p;
int top = 0;
int flag = 1;
system("cls");
p = T;
if (T == NULL) printf("该树为空树\n");
else {
do {
while (p)
{
s[++top] = p;
p = p->Lchild;
}
if (top == 0) flag = 0;
else {
p = s[top--];
visit(p);
p = p->Rchild;
}
} while (flag != 0);
}
}
void PostorderTraverse(BTNode* T)
/*后续遍历二叉树T*/
{
if (T != NULL)
{
system("cls");
PostorderTraverse(T->Lchild);
PostorderTraverse(T->Rchild);
visit(T); /* 访问根结点 */
}
}
void LevelorderTraverse(BTNode* T) //层次遍历二叉树
{
BTNode* DL[MAX_NODE], * p;
int rear=0, front=0;
system("cls");
p = T;
if (p != NULL) //其实就是队尾指向空的时候就退出
{
DL[++rear] = p;
while (front < rear)
{
p = DL[++front];
visit(p);
if (p->Lchild != NULL)
DL[++rear] = p->Lchild;
if (p->Rchild != NULL)
DL[++rear] = p->Rchild;
}
}
}
int search_depth(BTNode* T)
{
BTNode* Queue[MAX_NODE], * p = T;
int front = 0, rear = 0, depth = 0, level;
/* level总是指向访问层的最后一个结点在队列的位置 */
if (T != NULL)
{
Queue[++rear] = p; /* 根结点入队 */
level = rear; /* 根是第1层的最后一个节点 */
while (front < rear)
{
p = Queue[++front];
if (p->Lchild != NULL) // 左子结点非空,入队
Queue[++rear] = p->Lchild;
if (p->Rchild != NULL) // 右子结点非空,入队
Queue[++rear] = p->Rchild;
if (front == level) // 访问当前层最后一个结点
{
depth++;
level = rear;
}
}
}
return depth;
}
void leaves(BTNode* T)
/*输出叶子节点和非叶子节点*/
{
BTNode* DL[MAX_NODE], * p = T; //数组队列
int front = 0, rear = 0;
system("cls");
if (p != NULL)
{
DL[++rear] = p;
front = 1;
while (front <= rear) {
if (p->Lchild == NULL && p->Rchild == NULL)
printf("叶子节点:%c\n", p->data);
else {
printf("非叶子节点:%c\n", p->data);
if (p->Lchild != NULL)
DL[++rear] = p->Lchild;
if (p->Rchild != NULL)
DL[++rear] = p->Rchild;
}
p = DL[++front];
}
}
}
int Judge(BTNode* T)//判断该二叉树是否为完全二叉树(层次遍历)
{
BTNode* DL[MAX_NODE],*p; //队列数组
int rear = 0, front = 0;
system("cls");
p = T;
if (p != NULL)
{
DL[++rear] = p;
while (front < rear) {
p = DL[++front];
if ( p->Lchild == NULL && p->Rchild != NULL) //当左子树为空,右子树不为空时,就不符合完全二叉树的性质
return 0;
else {
if (p->Lchild != NULL)
DL[++rear] = p->Lchild;
if (p->Rchild != NULL)
DL[++rear] = p->Rchild;
}
}
}
return 1;
}
int main()
{
BTNode* T = NULL;
char ch[10];
while (1)
{
printf("\n======================================================\n");
printf("| 1.建立二叉树T |\n");
printf("| 2.用非递归方式先序遍历方式输出树T的结点 |\n");
printf("| 3.用非递归方式中序遍历方式输出树T的结点 |\n");
printf("| 4.用后序遍历方式输出树T的结点 |\n");
printf("| 5.用层次遍历方式输出树T的结点 |\n");
printf("| 6.输出树T的深度 |\n");
printf("| 7.输出树T的叶子结点和非叶子结点 |\n");
printf("| 8.判断该二叉树是否为完全二叉树(层次遍历) |\n");
printf("| 0.退出程序 |\n");
printf("======================================================\n");
printf("请输入要进行的操作:");
scanf("%s", ch);
if (strcmp(ch, "1") == 0)
T = Creat_BiTree();
else if (strcmp(ch, "2") == 0)
PreorderTraverse(T);
else if (strcmp(ch, "3") == 0)
InorderTraverse(T);
else if (strcmp(ch, "4") == 0)
{
system("cls");
PostorderTraverse(T);
}
else if (strcmp(ch, "5") == 0)
LevelorderTraverse(T);
else if (strcmp(ch, "6") == 0)
{
int depth = search_depth(T);
system("cls");
printf("该二叉树的深度为:%d", depth);
}
else if (strcmp(ch, "7") == 0)
leaves(T);
else if (strcmp(ch, "8") == 0)
{
int n = 0;
n=Judge(T);
if (n == 0)
printf("该树不是完全二叉树\n");
else printf("该树是完全二叉树\n");
}
else if (strcmp(ch, "0") == 0)
{
system("cls");
printf("感谢使用!\n\n");
break;
printf("程序退出失败!\n");
exit(0);
}
else
{
system("cls");
printf("\n非法输入!\n\n");
}
}
}