#pragma once
typedef char ElemType;
//二叉链表
typedef struct BTNode
{
ElemType data;//1.数据域
struct BTNode* leftchild;//2.左孩子指针域
struct BTNode* rightchild;//3.右孩子指针域
}BTNode;
/*
//三叉链表
typedef struct BTNode
{
ElemType data;//1.数据域
struct BTNode* leftchild;//2.左孩子指针域
struct BTNode* rightchild;//3.右孩子指针域
struct BTNode* parent;//4.双亲指针
}BTNode;
*/
//前中后序遍历(递归方式实现)
void preOrder(BTNode* root);
void inOrder(BTNode* root);
void postOrder(BTNode* root);
//二叉树的构建函数1(按图索骥)
BTNode* Create1();
//购买新节点
BTNode* BuyNode(ElemType val);
//前中后序遍历(非递归方式实现)
void preOrder_NoRecursion(BTNode* root);
void inOrder_NoRecursion(BTNode* root);
void postOrder_NoRecursion1(BTNode* root);
void postOrder_NoRecursion2(BTNode* root);
//层序遍历
void Level_Traverse(BTNode* root);
void S_Level_Traverse(BTNode* root);//正S
void ReverseS_Level_Traverse(BTNode* root);//倒S
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <memory.h>
#include "BinaryTree.h"
//前中后序遍历(递归方式实现)
void preOrder(BTNode* root) //根左右
{
if (root == NULL)
return;
printf("%c ", root->data);//处理根
preOrder(root->leftchild);//处理左
preOrder(root->rightchild);//处理右
}
void inOrder(BTNode* root)//左根右
{
if (root == NULL)
return;
inOrder(root->leftchild);//处理左
printf("%c ", root->data);//处理根
inOrder(root->rightchild);//处理右
}
void postOrder(BTNode* root)
{
if (root == NULL)
return;
postOrder(root->leftchild);//处理左
postOrder(root->rightchild);//处理右
printf("%c ", root->data);//处理根
}
//二叉树的构建函数1(按图索骥)
BTNode* Create1()
{
BTNode* root = BuyNode('A');
root->leftchild = BuyNode('B');
root->rightchild = BuyNode('G');
root->leftchild->leftchild = BuyNode('C');
root->leftchild->rightchild = BuyNode('D');
root->rightchild->rightchild = BuyNode('H');
root->leftchild->rightchild->leftchild = BuyNode('E');
root->leftchild->rightchild->rightchild = BuyNode('F');
return root;
}
//购买新节点
BTNode* BuyNode(ElemType val)
{
BTNode* pnewnode = (BTNode*)malloc(sizeof(BTNode));
if (NULL == pnewnode)
exit(EXIT_FAILURE);
pnewnode->data = val;
pnewnode->leftchild = pnewnode->rightchild = NULL;
return pnewnode;
}
//前中后序遍历(非递归方式实现)
#include <stack>
using namespace std;
void preOrder_NoRecursion(BTNode* root)
{
if (root == NULL)
return;
//用一个栈(单栈法)
//1.申请一个栈,并将根节点入栈
std::stack<BTNode*> st;
st.push(root);
//2.进入while循环中,循环条件是栈不空即可
while (!st.empty())
{
//3.将此时栈顶节点取出,并将其值打印处理
BTNode* tmp = st.top();
st.pop();
printf("%c ", tmp->data);
// 序进行判断,如果存在则压入栈中
if (tmp->rightchild != NULL)
st.push(tmp->rightchild);
if (tmp->leftchild != NULL)
st.push(tmp->leftchild);
}
//5.当while进不去,栈空的时候,此时整体遍历结束
}
void inOrder_NoRecursion(BTNode* root)
{
if (root == NULL)
return;
//要一个栈(单栈法)
//1.申请一个栈,并将根节点入栈,额外申请一个标签bool tag(用来表示栈顶
// 节点是不是第一次遇见)
std::stack<BTNode*> st;
st.push(root);
bool tag = true;
//2.进入while循环,循环条件是栈不空即可
while (!st.empty())
{
//3.需要对当前栈顶节点进行判定,如果该栈顶节点是第一次遇见,则说明
// 其"左"未被处理过,则先对其"左"半边处理一遍(处理一遍指的是将
// 其左半绺捋一边)
while (tag && st.top()->leftchild != NULL)
st.push(st.top()->leftchild);
//6.如果此时栈顶节点不是第一次遇见,则说明其左半边已经被处理过了,此时
// 是回退回来第二次遇见该节点,则其"左"相当于也处理完了,则此时也可以
// 将该节点取出打印
//4.当捋完之后,停下来,此时的栈顶节点一定左孩子为NULL,则此时相当于
// 其"左"已经处理了,此时可以将其取出打印(处理其"根")
BTNode* tmp = st.top();
st.pop();
printf("%c ", tmp->data);
//5.再对刚取出打印的节点的右孩子做判断是否存在,如果存在则压入栈中
//如果该节点有右孩子,则压入栈中,并将tag赋值为true
//如果该节点没有右孩子,则while重新进入后的栈顶节点一定是老东西,说
// 明其左半边已经被处理过了,则将tag赋值头false
if (tmp->rightchild != NULL)
{
st.push(tmp->rightchild);
tag = true;
}
else
tag = false;
}
//7.当while循环进不去,即栈为空时,则整体遍历结束
}
void postOrder_NoRecursion1(BTNode* root)
{
if (root == NULL)
return;
//1.申请一个栈,额外申请一个bool tag,再额外申请一个BTNode * preNode
std::stack<BTNode*> st;
bool tag = true;
BTNode* preNode = NULL;
//2.将根节点入栈,tag给true, preNode给NULL
st.push(root);
//3.进入while循环,循环条件是栈不空即可
while (!st.empty())
{
//4.此时栈顶节点不能立刻取出打印,而是先得对其"左"进行判定
//4.1如果当前tag为true,则说明栈顶节点是新节点(第一次遇见),则需要将其
// 左半绺捋一遍,当捋完时,则标志着当前最新栈顶节点的左孩子不存在,相当于
// 其"左"已经被处理完了,则接下来该处理其"右"了
while (tag && st.top()->leftchild!=NULL)
st.push(st.top()->leftchild);
//4.2如果当前tag为false,则说明栈顶节点是老节点(不是第一次遇见),则标志
// 着当前最新栈顶节点的左孩子存在但是已经被处理过了,则接下来该该处理
// 其"右"了
//5.此时栈顶节点处理其"右"的前提是先对其"右"做判定
//5.1如果当前栈顶节点的右孩子存在但是不等于preNode,则说明栈顶节点
// 的"右"还没有被处理过,则接下来将右孩子压入栈中(别忘了修改tag为真)
if (st.top()->rightchild != NULL && st.top()->rightchild != preNode)
{
st.push(st.top()->rightchild);
tag = true;
}
//5.2如果当前栈顶节点的右孩子不存在或者存在但是等于preNode,则说明栈顶
// 节点的"右"已经被处理过了,则接下来该处理栈顶节点的"根"
else
{
//6.左右都处理完之后,此时该处理栈顶节点的根,则此时可以将栈顶节点取出并打
// 印(别忘了修改tag为假,并且别忘了修改preNode为刚打印处理的节点)
BTNode* tmp = st.top();
st.pop();
printf("%c ", tmp->data);
tag = false;
preNode = tmp;
}
}
//7.当while循环结束,表示栈此时为空,也标志着整体遍历结束
}
void postOrder_NoRecursion2(BTNode* root)
{
if (root == NULL)
return;
//要两个栈:
//1.申请两个栈S1和S2 S1用来遍历全部的节点S2用来存储后序遍历结果
std::stack<BTNode*> S1, S2;
S1.push(root);
//3.进入while循环,循环条件为栈S1不空即可
while (!S1.empty())
{
//4.将S1的栈顶节点取出,放到S2里面去(此时先不打印处理)
BTNode* tmp = S1.top();
S1.pop();
S2.push(tmp);
//5.再对刚刚存储到S2里面的节点的两个孩子按照先左再右的顺序判断是否存
// 在,如果存在则压入栈S1
if (tmp->leftchild != NULL)
S1.push(tmp->leftchild);
if (tmp->rightchild != NULL)
S1.push(tmp->rightchild);
}
//6.当while循环结束,说明栈S1此时空了,也说明我们要的后序遍历结果刚好在
// S2里面存在,则对栈S2将值依次取出打印即可
while (!S2.empty())
{
printf("%c ", S2.top()->data);
S2.pop();
}
}
#include <queue>
//层序遍历
void Level_Traverse(BTNode* root)
{
if (root == NULL)
return;
//1.申请一个队列,并将根节点入队
std::queue<BTNode*> qu;
qu.push(root);
//2.进入while循环,循环条件是队列不空即可
while (!qu.empty())
{
//3.取出队头结点将其打印处理,然后将其两个孩子按照
// "先左再右"的顺序进行判定,如果存在则压入队列中
BTNode* tmp = qu.front();
qu.pop();
printf("%c ", tmp->data);
if (tmp->leftchild != NULL)
qu.push(tmp->leftchild);
if (tmp->rightchild != NULL)
qu.push(tmp->rightchild);
}
//4.当while循环进不去,也就是队列空的时候,整体遍历结束
}
void S_Level_Traverse(BTNode* root)//正S
{
if (root == NULL)
return;
//1.申请两个栈S1和S2, 分别用来描述奇数层和偶数层的运行规则
std::stack<BTNode*> S1, S2;
S1.push(root);
//3.进入while循环,循环条件栈S1和栈S2只要有一个不空即可
while (!S1.empty() || !S2.empty())
{
//4.具体分辨是哪一个栈空了,哪一个栈没空
//5.如果是栈S1不空,栈S2空,则此时需要将栈S1里面的节点依次取出打印,并顺
// 带着将取出处理的每一个节点的两个孩子都按照"先右再左"的顺序进行判定,如
// 果存在则压入栈S2
while (!S1.empty())
{
BTNode* tmp = S1.top();
S1.pop();
printf("%c ", tmp->data);
if (tmp->rightchild != NULL)
S2.push(tmp->rightchild);
if (tmp->leftchild != NULL)
S2.push(tmp->leftchild);
}
//6.如果是栈S2不空,栈S1空,则此时需要将栈S2里面的节点依次取出打印,并顺
// 带着将取出处理的每一个节点的两个孩子都按照"先左再右"的顺序进行判定,如
// 果存在则压入栈S2
while (!S2.empty())
{
BTNode* tmp = S2.top();
S2.pop();
printf("%c ", tmp->data);
if (tmp->leftchild != NULL)
S1.push(tmp->leftchild);
if (tmp->rightchild != NULL)
S1.push(tmp->rightchild);
}
}
//7.当while循环进不去,则表示栈S1和栈S2都空了,也标志着整体遍历结束
}
void ReverseS_Level_Traverse(BTNode* root)//倒S
{
if (root == NULL)
return;
//1.申请两个栈S1和S2, 分别用来描述奇数层和偶数层的运行规则
std::stack<BTNode*> S1, S2;
S1.push(root);
//3.进入while循环,循环条件栈S1和栈S2只要有一个不空即可
while (!S1.empty() || !S2.empty())
{
//4.具体分辨是哪一个栈空了,哪一个栈没空
//5.如果是栈S1不空,栈S2空,则此时需要将栈S1里面的节点依次取出打印,并顺
// 带着将取出处理的每一个节点的两个孩子都按照"先左再右"的顺序进行判定,如
// 果存在则压入栈S2
while (!S1.empty())
{
BTNode* tmp = S1.top();
S1.pop();
printf("%c ", tmp->data);
if (tmp->leftchild != NULL)
S2.push(tmp->leftchild);
if (tmp->rightchild != NULL)
S2.push(tmp->rightchild);
}
//6.如果是栈S2不空,栈S1空,则此时需要将栈S2里面的节点依次取出打印,并顺
// 带着将取出处理的每一个节点的两个孩子都按照"先右再左"的顺序进行判定,如
// 果存在则压入栈S2
while (!S2.empty())
{
BTNode* tmp = S2.top();
S2.pop();
printf("%c ", tmp->data);
if (tmp->rightchild != NULL)
S1.push(tmp->rightchild);
if (tmp->leftchild != NULL)
S1.push(tmp->leftchild);
}
}
//7.当while循环进不去,则表示栈S1和栈S2都空了,也标志着整体遍历结束
}
int main()
{
BTNode* root = Create1();
printf("前中后序遍历打印(递归版)\n");
preOrder(root); printf("\n");
inOrder(root); printf("\n");
postOrder(root); printf("\n");
printf("前中后序遍历打印(非递归版)\n");
preOrder_NoRecursion(root); printf("\n");
inOrder_NoRecursion(root); printf("\n");
postOrder_NoRecursion2(root); printf("\n");
postOrder_NoRecursion1(root); printf("\n");
printf("层序遍历打印(非递归版)\n");
Level_Traverse(root); printf("\n");
S_Level_Traverse(root); printf("\n");
ReverseS_Level_Traverse(root); printf("\n");
return 0;
}