参考王道《2023年数据结构考研复习指导》
#include <iostream>
typedef int ElemType;
// 链式存储二叉树
typedef struct BiTNode {
ElemType data;
struct BiTNode* lchild, * rchild;
} BiTNode, * BiTree;
// 链式队列结点(存储二叉树结点指针)
typedef struct LinkNode {
BiTNode* data; // 类型为二叉树结点指针
struct LinkNode* next;
} LinkNode;
// 链式队列
typedef struct LinkQueue {
LinkNode* front, * rear;
} LinkQueue;
// 链栈(带头结点)
typedef struct LiStackNode {
BiTNode* data;
struct LiStackNode* next;
} LiStackNode, * LiStack;
bool CreateTree(BiTree& T, ElemType* datagroup, int length);
bool PreTree(BiTree& T, ElemType* datagroup, int length, int& i);
void visit(BiTNode* p);
void PreOrder(BiTree T);
void InOrder(BiTree T);
void PostOrder(BiTree T);
bool InitQueue(LinkQueue& Q);
bool IsEmpty(LinkQueue Q);
bool EnQueue(LinkQueue& Q, BiTNode* x);
bool DeQueue(LinkQueue& Q, BiTNode*& x);
void DestroyQueue(LinkQueue& Q);
void LevelOrder(BiTree T);
void BuildTreeByPreOrderAndInOrder(BiTree& T, ElemType* preOrder, ElemType* inOrder, int preb, int pree, int inb, int ine);
void BuildTreeByInOrderAndPostOrder(BiTree& T, ElemType* inOrder, ElemType* postOrder, int inb, int ine, int postb, int poste);
bool InitStack(LiStack& S);
bool StackEmpty(LiStack S);
bool Push(LiStack& S, BiTNode* p);
bool Pop(LiStack& S, BiTNode*& p);
bool GetTop(LiStack S, BiTNode*& p);
void DestroyStack(LiStack& S);
void InOrder2(BiTree T);
void PreOrder2(BiTree T);
void PostOrder2(BiTree T);
int main() {
BiTree T;
ElemType datagroup[] = { 1, 2, 4, -1, -1, 5, -1, -1, 3, 6, -1, 7, -1, -1, -1 };
CreateTree(T, datagroup, sizeof(datagroup) / sizeof(datagroup[0]));
PreOrder(T);
std::cout << std::endl;
InOrder(T);
std::cout << std::endl;
PostOrder(T);
std::cout << std::endl;
LevelOrder(T);
std::cout << std::endl;
ElemType preOrder[] = { 1, 2, 4, 5, 3, 6, 7 };
ElemType inOrder[] = { 4, 2, 5, 1, 6, 7, 3 };
ElemType postOrder[] = { 4, 5, 2, 7, 6, 3, 1 };
BiTree T2;
BuildTreeByPreOrderAndInOrder(T2, preOrder, inOrder, 0, 6, 0, 6);
PreOrder(T2);
std::cout << std::endl;
BiTree T3;
BuildTreeByInOrderAndPostOrder(T3, inOrder, postOrder, 0, 6, 0, 6);
PreOrder(T3);
std::cout << std::endl;
InOrder2(T);
std::cout << std::endl;
PreOrder2(T);
std::cout << std::endl;
PostOrder2(T);
std::cout << std::endl;
system("pause");
return 0;
}
// 创建二叉树
// datagroup数组的元素的值作为树中各个节点的数据,并规定如果某个元素的值为-1,表示对应的节点是NULL节点。
bool CreateTree(BiTree& T, ElemType* datagroup, int length) {
int i = 0; // 数组指针
return PreTree(T, datagroup, length, i);
}
// 创建二叉树(按照先序遍历方式,组成一个棵树)
bool PreTree(BiTree& T, ElemType* datagroup, int length, int& i) {
if (i >= length || datagroup[i] == -1) {
T = NULL;
i++;
return true;
}
T = (BiTNode*)malloc(sizeof(BiTNode));
if (T == NULL)
return false;
T->data = datagroup[i++];
return PreTree(T->lchild, datagroup, length, i) && PreTree(T->rchild, datagroup, length, i);
}
/*==================================================================*/
// 访问二叉树结点的操作
void visit(BiTNode* p) {
std::cout << p->data << " ";
}
// 先序遍历
void PreOrder(BiTree T) {
if (T != NULL) {
visit(T);
PreOrder(T->lchild);
PreOrder(T->rchild);
}
}
// 中序遍历
void InOrder(BiTree T) {
if (T != NULL) {
InOrder(T->lchild);
visit(T);
InOrder(T->rchild);
}
}
// 后序遍历
void PostOrder(BiTree T) {
if (T != NULL) {
PostOrder(T->lchild);
PostOrder(T->rchild);
visit(T);
}
}
/*==================================================================*/
// 初始化队列(带头结点)
bool InitQueue(LinkQueue& Q) {
Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
if (Q.front == NULL)
return false;
Q.front->next = NULL;
return true;
}
// 判断队列是否为空
bool IsEmpty(LinkQueue Q) {
if (Q.front == Q.rear)
return true;
else
return false;
}
// 入队(带头结点)
bool EnQueue(LinkQueue& Q, BiTNode* x) {
LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
if (s == NULL)
return false;
s->data = x;
s->next = NULL;
Q.rear->next = s;
Q.rear = s;
return true;
}
// 出队(带头结点)
bool DeQueue(LinkQueue& Q, BiTNode*& x) {
if (IsEmpty(Q))
return false;
LinkNode* p = Q.front->next;
x = p->data;
Q.front->next = p->next;
if (p == Q.rear) // 若此时是最后一个结点出队
Q.rear = Q.front;
free(p);
return true;
}
void DestroyQueue(LinkQueue& Q) {
LinkNode* p = Q.front->next;
LinkNode* q;
while (p != NULL) {
q = p;
p = p->next;
free(q);
}
free(Q.front);
Q.front = Q.rear = NULL;
}
/*==================================================================*/
// 层序遍历
void LevelOrder(BiTree T) {
LinkQueue Q;
InitQueue(Q);
EnQueue(Q, T);
BiTNode* p;
while (!IsEmpty(Q)) {
DeQueue(Q, p);
visit(p);
if (p->lchild != NULL)
EnQueue(Q, p->lchild);
if (p->rchild != NULL)
EnQueue(Q, p->rchild);
}
DestroyQueue(Q);
}
/*==================================================================*/
// 根据先序序列和中序序列构造二叉树
// preb和pree分别指示了这个树的先序序列在preOrder中的起始和终止位置
// inb和ine分别指示了这个树的中序序列在inOrder中的起始和终止位置
void BuildTreeByPreOrderAndInOrder(BiTree& T, ElemType* preOrder, ElemType* inOrder, int preb, int pree, int inb, int ine) {
T = (BiTNode*)malloc(sizeof(BiTNode));
if (T == NULL)
return;
T->data = preOrder[preb];
int i = inb, k;
while (inOrder[i] != preOrder[preb] && i <= ine) // 找到根节点在中序序列中的位置
i++;
k = i - inb; // 左子树中结点个数
if (i == inb) // 说明没有左子树
T->lchild = NULL;
else
BuildTreeByPreOrderAndInOrder(T->lchild, preOrder, inOrder, preb + 1, k + preb, inb, i - 1); // 构造左子树
if (i == ine) // 说明没有右子树
T->rchild = NULL;
else
BuildTreeByPreOrderAndInOrder(T->rchild, preOrder, inOrder, k + preb + 1, pree, i + 1, ine); // 构造右子树
}
/*==================================================================*/
// 根据先序序列和后序序列构造二叉树
// inb和ine分别指示了这个树的中序序列在inOrder中的起始和终止位置
// postb和poste分别指示了这个树的后序序列在postOrder中的起始和终止位置
void BuildTreeByInOrderAndPostOrder(BiTree& T, ElemType* inOrder, ElemType* postOrder, int inb, int ine, int postb, int poste) {
T = (BiTNode*)malloc(sizeof(BiTNode));
if (T == NULL)
return;
T->data = postOrder[poste];
int i = inb, k;
while (inOrder[i] != postOrder[poste] && i <= ine) // 找到根节点在中序序列中的位置
i++;
k = i - inb; // 左子树中结点个数
if (i == inb) // 说明没有左子树
T->lchild = NULL;
else
BuildTreeByInOrderAndPostOrder(T->lchild, inOrder, postOrder, inb, i - 1, postb, postb + k - 1); // 构造左子树
if (i == ine) // 说明没有右子树
T->rchild = NULL;
else
BuildTreeByInOrderAndPostOrder(T->rchild, inOrder, postOrder, i + 1, ine, postb + k, poste - 1); // 构造右子树
}
/*==================================================================*/
// 初始化链栈(带头结点)
bool InitStack(LiStack& S) {
S = (LiStackNode*)malloc(sizeof(LiStackNode));
if (S == NULL) // 内存分配失败
return false;
S->next = NULL;
return true;
}
// 判断栈空
bool StackEmpty(LiStack S) {
if (S->next == NULL)
return true;
else
return false;
}
// 进栈操作——新元素入栈
bool Push(LiStack& S, BiTNode* p) {
LiStackNode* q = (LiStackNode*)malloc(sizeof(LiStackNode));
if (q == NULL) // 内存分配失败
return false;
q->data = p;
q->next = S->next;
S->next = q;
return true;
}
// 出栈操作
bool Pop(LiStack& S, BiTNode*& p) {
if (S->next == NULL) // 栈空,报错
return false;
LiStackNode* q = S->next;
p = q->data;
S->next = q->next;
free(q);
return true;
}
// 读栈顶操作
bool GetTop(LiStack S, BiTNode*& p) {
if (S->next == NULL) // 栈空,报错
return false;
p = S->next->data;
return true;
}
// 销毁链栈
void DestroyStack(LiStack& S) {
LiStackNode* p = S->next;
LiStackNode* q;
while (p != NULL) {
q = p;
p = p->next;
free(q);
}
free(S);
S = NULL;
}
/*==================================================================*/
// 中序遍历的非递归算法
void InOrder2(BiTree T) {
LiStack S;
InitStack(S);
BiTNode* p = T;
while (p || !StackEmpty(S)) { // 栈不空或p不空时循环
if (p) { // 一路向左
Push(S, p); // 当前节点入栈
p = p->lchild; // 左孩子不空,一直向左走
}
else { // 出栈,并转向出栈结点的右子树
Pop(S, p); // 栈顶元素出栈
visit(p); // 访问出栈结点
p = p->rchild; // 向右子树走,下一步找右子树第一个访问的结点(最左下角第一个结点)
}
}
DestroyStack(S);
}
// 先序遍历的非递归算法
void PreOrder2(BiTree T) {
LiStack S;
InitStack(S);
BiTNode* p = T;
while (p || !StackEmpty(S)) { // 栈不空或p不空时循环
if (p) { // 一路向左
visit(p); // 访问当前结点(根节点)
Push(S, p); // 当前节点入栈(当左孩子访问完后,访问右孩子)
p = p->lchild; // 左孩子不空,一直向左走(先序遍历左子树)
}
else { // 出栈,并转向出栈结点的右子树
Pop(S, p); // 栈顶元素出栈
p = p->rchild; // 向右子树走,p赋值为当前结点的右孩子
}
}
DestroyStack(S);
}
// 后序遍历的非递归算法
void PostOrder2(BiTree T) {
LiStack S;
InitStack(S);
BiTNode* p = T;
BiTNode* pre = NULL; // 记录前驱结点
while (p || !StackEmpty(S)) { // 栈不空或p不空时循环
if (p) { // 一路向左
Push(S, p); // 当前节点入栈(当左孩子访问完后,访问右孩子)
p = p->lchild; // 左孩子不空,一直向左走(后序遍历左子树)
}
else { // 向右
GetTop(S, p); // 读栈顶元素(因为根节点最后访问,当右子树还未访问时,根节点不能出栈)
if (p->rchild && p->rchild != pre) // 当右子树存在,且未被访问过(根节点的前驱为它的右孩子,pre记录上一个访问的结点)
p = p->rchild; // 转向右子树,后序遍历右子树
else { // 当右子树不存在,或者右子树被访问过
Pop(S, p); // 将根节点弹出
visit(p); // 访问根节点
pre = p; // 更新前驱结点
p = NULL; // 结点访问完后,重置p指针(因为根节点左右子树都被访问过了,下一个访问的结点是该根节点的父节点或右兄弟子树)
}
}
}
DestroyStack(S);
}