![](https://i-blog.csdnimg.cn/blog_migrate/ba75c63c84f04933b7f6c5f4ef149c53.png)
function.h
#pragma once
#include <stdio.h>
#include <stdlib.h>
typedef char BiElemType;
//二叉树结点的结构体定义
typedef struct BiTNode {
BiElemType c;//c就是书上的data
struct BiTNode* lchild;
struct BiTNode* rchild;
}BiTNode, * BiTree;//12个字节的空间
//辅助队列结点的结构体定义
typedef struct tag {
BiTree p;//树的某一个结点的地址值
struct tag* pnext;
}tag_t, * ptag_t;//链表,放的是指针的类型,原因:存放的是树的某一个结点的地址值
//为什么要用辅助队列:当没次建树加结点的时候,
//栈的相关数据结构
#define MaxSize 50
typedef BiTree ElemType;
typedef struct {
ElemType data[MaxSize];
int top;
}SqStack;
//声明放在头文件中的目的:声明一次即可,在其他文件中要引用函数时,#include 头文件即可,不用多次声明
void InitStack(SqStack& S);
bool StackEmpty(SqStack& S);
bool Push(SqStack& S, ElemType x);
bool Pop(SqStack& S, ElemType& x);
bool GetTop(SqStack& S, ElemType& x);
//队列的相关数据结构(链队)
typedef struct LinkNode {
ElemType data;
struct LinkNode* next;
}LinkNode;
//单独定义队头、队尾的指针
typedef struct {
LinkNode* front, * rear;
}LinkQueue;
void InitQueue(LinkQueue& Q);
bool IsEmpty(LinkQueue Q);
void EnQueue(LinkQueue& Q, ElemType x);
bool DeQueue(LinkQueue& Q, ElemType& x);
main.cpp
#include "function.h"
#define _CRT_SECURE_NO_WARNINGS
//递归实现
//abdhiejcfg
void preOrder(BiTree p)//前序遍历,先序遍历,(深度优先遍历)先打印当前节点,再打印左孩子,然后打印右孩子。考纲要求
{//把一颗树传进来。
if (p != NULL)
{
putchar(p->c);//等价于visit函数
preOrder(p->lchild);
preOrder(p->rchild);
}
}
//中序遍历 hdibjeafcg先打印左孩子,再打印父亲,再打印右孩子。考纲要求
void InOrder(BiTree p)
{
if (p != NULL)
{
InOrder(p->lchild);
putchar(p->c);
InOrder(p->rchild);
}
}
//hidjebfgca
void PostOrder(BiTree p)//后序遍历,先打印左孩子,再打印右孩子,最后打印父亲。考纲要求
{
if (p != NULL)
{
PostOrder(p->lchild);
PostOrder(p->rchild);
putchar(p->c);
}
}
//中序遍历非递归,非递归执行效率更高,考的概率很低。考纲无要求
void InOrder2(BiTree T)
{
SqStack S;
InitStack(S); BiTree p = T;//p是遍历指针
while (p || !StackEmpty(S))//p非空或者栈非空
{
if (p)
{
Push(S, p);//一个结点不为空,不断将左孩子压栈的过程,找最左孩子
p = p->lchild;//一路向左,找到最左结点
}
else {//找到最左结点后,接着要依次访问其父结点及其右兄弟(中序遍历),弹出栈中元素并打印,获取打印元素的右结点
Pop(S, p); putchar(p->c);//putchar(p->c)相当于visit(p)函数
p = p->rchild;
}
}
}
//层次遍历,广度优先遍历,一层一层的打。考纲无要求
void LevelOrder(BiTree T)
{
LinkQueue Q;
InitQueue(Q);
BiTree p = T;
EnQueue(Q, T);//树根入队
while (!IsEmpty(Q))
{
DeQueue(Q, p);//出队列的头元素
putchar(p->c);//打印有头元素
if (p->lchild != NULL)
EnQueue(Q, p->lchild);//入队左孩子
if (p->rchild != NULL)
EnQueue(Q, p->rchild);//入队右孩子
}
}
//不用栈实现二叉树的中序遍历 hdibjeafcg。考纲要求
void bst_morris_inorder( BiTree root)//root相当于tree
{
BiTree tmp,p = root;
while (p) {
if (p->lchild == NULL) {
printf("%c", p->c);
p = p->rchild;
}
else {
tmp = p->lchild;//tree左子树赋给tmp
while (tmp->rchild != NULL && tmp->rchild != p)
tmp = tmp->rchild;
if (tmp->rchild == NULL) {
tmp->rchild = p;
p = p->lchild;
}
else {
printf("%c", p->c);
tmp->rchild = NULL;
p = p->rchild;
}
}
}
}
//层序建树——借助逻辑上的辅助队列
int main() {
BiTree tree = NULL;//树的根结点
BiTree tpnew;//指向树的新结点的指针
ptag_t phead = NULL, ptail = NULL, listpnew = NULL, pcur = NULL;
//phead是队列头,ptail是队列尾部,通过pcur访问到p,再由p访问到ptail和phead;pcur->p->ptail/phead
char c;
//辅助队列中的队头,队尾结点,指向新结点的listpnew,指向当前插入位置的父结点的pcur
//abcdefg
while (scanf_s("%c", &c) != EOF)
{
if ('\n' == c)
{
break;//结束循环
}//当一次性输入多个元素后,因为回车,这跳出循环,不需要再进行ctrl+z结束循环
//分配空间
tpnew = (BiTree)calloc(1, sizeof(BiTNode));//给树结点分配空间,并且每个的空间都赋值为NULL
tpnew->c = c;//输入的元素放入树结点中c相当于data
listpnew = (ptag_t)calloc(1, sizeof(tag_t));//给队列结点分配空间
listpnew->p = tpnew;//树的结点地址放入队列结点中
//tpnew代表的是树的某一个结点,Listpnew代表的是一个链表,存放tree的某一个结点,和*(地址)
if (NULL == tree) {
tree = tpnew;
phead = listpnew;//队列头
ptail = listpnew;//队列尾
pcur = listpnew;//pcur始终指向插入位置的父结点
continue;//继续下一轮循环,跳出这个if语句,回到while读取scanf
}
else {
ptail->pnext = listpnew;
ptail = listpnew;//队列中使用尾插法,ptail指向队列尾部
}
if (NULL == pcur->p->lchild) {//通过队列找到树中结点,把结点放入树
pcur->p->lchild = tpnew;//把新结点插入到要插入结点的左边
}//pcur始终指向要插入的结点的位置
else if (NULL == pcur->p->rchild) {
pcur->p->rchild = tpnew;//把新节点放入到要插入结点的右边
pcur = pcur->pnext;//以a为根节点的左右子树已经插好,逻辑上需要将a出队,插入位置的父节点由a变为了b,所以pcur要后移
}//左右都放了结点后,pcur指向队列的下一个,并没有出队操作
}
printf("\n");
printf("-----------前序遍历---------\n");
preOrder(tree);
printf("\n");
printf("-----------中序遍历---------\n");
InOrder(tree);
printf("\n");
printf("-----------后序遍历---------\n");
PostOrder(tree);
printf("\n");
printf("-----------中序遍历非递归使用栈---------\n");
InOrder2(tree);
printf("\n");
printf("-----------层次遍历---------\n");
LevelOrder(tree);
printf("\n");
printf("-----------中序遍历非递归未使用栈---------\n");
bst_morris_inorder(tree);
}
queue.cpp
#include "function.h"
//带头结点的链队——头结点的下一个节点才有数据
//初始化
void InitQueue(LinkQueue& Q)
{
Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
Q.front->next = NULL;
}
//判空
bool IsEmpty(LinkQueue Q)
{
if (Q.front == Q.rear)
return true;
else
return false;
}
//入队、出队操作当作链表处理
//入队——尾插法
void EnQueue(LinkQueue& Q, ElemType x)
{
LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = x; s->next = NULL;
Q.rear->next = s;
Q.rear = s;
}
//出队——头部删除法
bool DeQueue(LinkQueue& Q, ElemType& x)
{
if (Q.front == Q.rear) return false;//队空不出
LinkNode* p = Q.front->next;//头结点什么都没存,所以头结点的下一个节点才有数据(带头结点的链队)
x = p->data;
Q.front->next = p->next;
if (Q.rear == p)
Q.rear = Q.front;
free(p);
return true;
}
stack.cpp
#include "function.h"
void InitStack(SqStack& S)
{
S.top = -1;
}
bool StackEmpty(SqStack& S)
{
if (S.top == -1)
return true;
else
return false;
}
//入栈
bool Push(SqStack& S, ElemType x)
{
if (S.top == MaxSize - 1)
{
return false;
}
S.data[++S.top] = x;
return true;
}
//出栈
bool Pop(SqStack& S, ElemType& x)
{
if (-1 == S.top)
return false;
x = S.data[S.top--];
return true;
}
//读取栈顶元素
bool GetTop(SqStack& S, ElemType& x)
{
if (-1 == S.top)
return false;
x = S.data[S.top];
return true;
}