二叉树的基本操作
1、定义二叉树的数据结构,包含数据域,左子树和右子树
```cpp
#include <stdio.h>
#include <stdlib.h>
#include<stack>
using namespace std;
typedef struct BTNode{
int data;
struct BTNode *lChild;
struct BTNode *rChild;
}BiTNode;
2、创建二叉树的基本函数
//先序创建二叉树,递归实现
void CreateBiTree(BiTNode **T){
int ch;
scanf("%d",&ch);
if(ch==-1){
*T=NULL;
return;
}else{
*T=(BiTNode*)malloc(sizeof(BiTNode));
(*T)->data=ch;
printf("输入%d左子结点",ch);
//scanf("%d",&ch);
CreateBiTree(&((*T)->lChild));
printf("输入%d右子结点",ch);
//scanf("%d",&ch);
CreateBiTree(&((*T)->rChild));
}
return;
}
//先序遍历二叉树,递归
void PreOrderBiTree(BiTNode *T){
if(T==NULL) return;
else{
printf("%d",T->data);
PreOrderBiTree(T->lChild);
PreOrderBiTree(T->rChild);
}
}
//中序遍历二叉树,递归
void MiddleOrderBiTree(BiTNode *T){
if(T==NULL) return;
else{
MiddleOrderBiTree(T->lChild);
printf("%d",T->data);
MiddleOrderBiTree(T->rChild);
}
}
//后序遍历二叉树,递归
void PostOrderBiTree(BiTNode *T){
if(T==NULL) return;
else{
PostOrderBiTree(T->lChild);
PostOrderBiTree(T->rChild);
printf("%d",T->data);
}
}
//先序遍历二叉树,栈
void PreOrderTraverse(BiTNode *T){ //严蔚敏数据结构中的算法
stack<BiTNode*> S;
BiTNode* p;
p=T;
while(p||!S.empty()){
if(p){
printf("%d",p->data);
S.push(p);
p=p->lChild;
}else{
p=S.top();
S.pop();
p=p->rChild;
}
}
}
void preTraversal(BiTNode* T){ //个人感觉用while循环更容易实现
if(T==NULL)return;
BiTNode*p=T;
stack<BiTNode*>S;
S.push(p);
while(!S.empty()){
p = S.top();
printf("%d",p->data);
S.pop();
if(p->rChild!=NULL)
S.push(p->rChild);
if(p->lChild!=NULL)
S.push(p->lChild);
}
}
//中序遍历二叉树,栈
void InOrderTraverse(BiTNode *T){ //课本算法
stack<BiTNode*> S;
BiTNode* p;
p=T;
//根指针进栈,遍历左子树
while(p||!S.empty()){
if(p) {
S.push(p);
p = p->lChild;
}else{ //根指针退栈,访问根节点,遍历右子树
p=S.top();
S.pop();
printf("%d", p->data);
p=p->rChild;
}
}
}
void inorderTraversal(BiTNode *T){ //while高级算法
if(T==NULL)return;
stack<BiTNode*> S;
S.push(T);
while(!S.empty()){
//该过程一直找到没有左节点的节点才停止
while(S.top()->lChild!=NULL){
S.push(S.top()->lChild);
}
//此时的S.top()是一个没有left的节点,按照中序遍历的特性,可以将其直接输出。
//while循环会一直将栈顶输出,直到遇到有右节点的节点,这样能保证栈中元素不会重复寻找左孩子
while(!S.empty()){
BiTNode *p = S.top();
printf("%d",p->data);
S.pop();
if(p->rChild){
S.push(p->rChild);
break;
}
}
}
}
//后序遍历二叉树,栈
/*
1、如果栈顶元素非空且左节点存在,将其入栈,重复该过程。若不存在则进入第2步(该过程和中序遍历一致)
2、判断上一次出栈节点是否当前节点的右节点,或者当前节点是否存在右节点,满足任一条件,将当前节点输出,并出栈。否则将右节点压栈。跳至第1步
*/
void PostOrderTraverse(BiTNode *T){
stack<BiTNode*>S;
S.push(T);
BiTNode* lastPopNode=NULL;
while(!S.empty()){
while(S.top()->lChild!=NULL){ //向左走到尽头
S.push(S.top()->lChild);
}
while(!S.empty()){
if(lastPopNode==S.top()->rChild||S.top()->rChild==NULL){ //如果栈顶右节点指针为空,或者是上一次出栈结点的右节点,则输出
printf("%d",S.top()->data);
lastPopNode=S.top();
S.pop();
}
else if(S.top()->rChild){ //如果栈顶指针有右节点,右节点入栈,结束当前循环
S.push(S.top()->rChild);
break;
}
}
}
}
void posordertraverse(BiTNode *T){ //课本算法
stack<BiTNode*> S;
int StackMark[100]; //模拟栈,用于标志访问次数
int k=-1; //模拟栈的顺序
BiTNode* p;
p=T;
while(1){
while(p){ //向左走到尽头
S.push(p);
k++; //标志栈,用于标志访问到的元素
StackMark[k]=1; //向左是第一次访问,访问次数为1
p=p->lChild;
}
while(!p&&!S.empty()){
p=S.top();
if(StackMark[k]==1){ //已访问过一次,当前是第二次访问
StackMark[k]=2; //标志数记为2,访问右结点
p=p->rChild;
}else{ //已访问过两次,当前是第三次访问
printf("%d",p->data); //第三次访问时打印元素
StackMark[k]=0; //该标志位记为0
k--; //退栈
S.pop();
p=NULL; //为了继续取栈顶元素,将p置位空
}
}
if(S.empty()) break;
}
}
//二叉树d深度
int TreeDeep(BiTNode *T){
int deep=0;
if(T!=NULL){
int leftdeep=TreeDeep(T->lChild);
int rightdeep=TreeDeep(T->rChild);
deep=leftdeep>=rightdeep?leftdeep+1:rightdeep+1;
}
return deep;
}
//叶子结点个数
int LeafCount(BiTNode *T){
static int count;
if(T!=NULL){
if(T->rChild==NULL&&T->lChild==NULL)
count++;
LeafCount(T->lChild);
LeafCount(T->rChild);
}
return count;
}
//二叉树所有结点在左右子树互换
void SwapTree(BiTNode **T){
if(*T==NULL) return;
if((*T)->lChild==NULL&&(*T)->rChild==NULL){
return;
}else{
BiTNode *p, *q, *t;
p = (*T)->lChild;
q = (*T)->rChild;
(*T)->rChild=p;
(*T)->lChild=q;
SwapTree(&p);
SwapTree(&q);
}
}
//先序序列和中序序列构造二叉树
void PreInOrd(int preord[],int inord[],int i,int j,int k,int h,BiTNode **T){
//先序序列从i到j,中序序列从k到h,建立一颗二叉树放在t中
int m;
(*T)=(BiTNode*)malloc(sizeof(BiTNode));
(*T)->data=preord[i]; //二叉树的根
m=k;
while(inord[m]!=preord[i]) m++; //在中序序列中定位树根
if(m==k)
(*T)->lChild=NULL; //左子树空
else
PreInOrd(preord,inord,i+1,i+m-k,k,m-1,&((*T)->lChild)); //递归调用建立左子树
if(m==h)
(*T)->rChild=NULL; //右子树空
else
PreInOrd(preord,inord,i+m-k+1,j,m+1,h,&((*T)->rChild)); //递归调用建立右子树
}
//后序序列和中序序列构造二叉树
void PosInOrd(int posord[],int inord[],int i,int j,int k,int h,BiTNode **T){
int m;
(*T)=(BiTNode*)malloc(sizeof(BiTNode));
(*T)->data=posord[j];
m=k;
while(posord[j]!=inord[m]) m++; //中序序列中定位根的位置
if(m==h)
(*T)->rChild=NULL; //右子树空
else
PosInOrd(posord,inord,j-h+m,j-1,m+1,h,&((*T)->rChild)); //递归调用建立右子树
if(m==k)
(*T)->lChild=NULL; //左子树空
else
PosInOrd(posord,inord,i,j-h+m-1,k,m-1,&((*T)->lChild)); //递归调用建立左子树
}
//层次遍历
void LevelOrder(BiTNode *T)
{
queue<BiTNode*> Queue;
BiTNode* p;
if(T==NULL) return;
Queue.push(T); //根节点入队列
while(!Queue.empty()){
p=Queue.front();
printf("%d",p->data);
Queue.pop();
if(p->lChild){ //如果有左孩子,左孩子入队
Queue.push(p->lChild);
}
if(p->rChild){ //如果有右孩子,右孩子入队
Queue.push(p->rChild);
}
}
}
//层次序列和中序序列构建二叉树
typedef struct{
int lel; //指向当前处理的元素在层次序列中的位置
int low,high; //中序序列的上下界
BiTNode *parent; //层次序列中当前结点的双亲结点指针
int lr; //判断左右子树,1为左,2为右
}Sq;
void LevelInOrd(int levelord[],int inord[],int n,BiTNode **T){ //有n个元素
Sq q;
queue <Sq> Q;
if(n<1)
T=NULL; //二叉树为空
else
{
int i, s;
i = s = 0; //s指向层次序列中当前处理的元素,i用来寻找当前处理的元素在中序序列中的位置
*T = (BiTNode *) malloc(sizeof(BiTNode));
(*T)->data = levelord[0];
(*T)->lChild = NULL;
(*T)->rChild = NULL;
while (inord[i] != levelord[0])
i++; //寻找当前元素在中序序列中的位置
if (i == 0 && i == n - 1) return; //只有一个根节点
//处理除根节点外的第一个节点
if (i == 0) //没有左子树
{
(*T)->lChild = NULL;
q.lel = ++s;
q.low = 1;
q.high = n - 1;
q.lr = 2;
q.parent = (*T);
Q.push(q);
} else if (i == n - 1) //没有右子树
{
(*T)->rChild = NULL;
q.lel = ++s;
q.low = 0;
q.high = i - 1;
q.lr = 1;
q.parent = (*T);
Q.push(q);
} else {
q.lel = ++s;
q.low = 0;
q.high = i - 1;
q.lr = 1;
q.parent = (*T);
Q.push(q);
q.lel = ++s;
q.low = i + 1;
q.high = n - 1;
q.lr = 2;
q.parent = (*T);
Q.push(q);
}
while(!Q.empty())
{
q=Q.front(); Q.pop();
BiTNode* fat=q.parent;
i=q.low;
BiTNode* p=(BiTNode*)malloc(sizeof(BiTNode));
p->data=levelord[q.lel];
p->lChild=p->rChild=NULL;
if(q.lr==1)
fat->lChild=p;
else
fat->rChild=p; //连接当前节点与双亲节点
while(inord[i]!=levelord[q.lel]) //寻找当前元素在中序序列中的位置
i++;
if(i==q.low && i==q.high) //叶子结点,无孩子
{
p->lChild=p->rChild=NULL;
continue;
}
else if(i==q.low) //没有左孩子
{
p->lChild=NULL;
q.lel=++s; q.low=i+1; q.parent=p; q.lr=2; //处理下一个元素,q.high不变
Q.push(q);
}
else if(i==q.high) //没有右孩子
{
p->rChild=NULL;
q.lel=++s; q.high=i-1; q.parent=p; q.lr=1; //处理下一个元素,q.low不变
Q.push(q);
}
else
{
int high=q.high; //备份一下
q.lel=++s; q.high=i-1; q.parent=p; q.lr=1;
Q.push(q);
q.lel=++s; q.low=i+1; q.high=high; q.parent=p; q.lr=2;
Q.push(q);
}
}
}
}
3、测试函数
int main() {
BiTNode *T;
int depth,leafCount=0;
printf("请输入第一个节点的值,-1表示没有结点:\n");
CreateBiTree(&T);
printf("栈方法先序遍历二叉树");
PreOrderTraverse(T);
printf("\n");
printf("栈方法中序遍历二叉树");
InOrderTraverse(T);
printf("\n");
printf("栈方法后序遍历二叉树");
PostOrderTraverse(T);
printf("\n");
printf("栈方法后序遍历二叉树,使用标志栈");
posordertraverse(T);
printf("\n");
printf("递归先序遍历二叉树");
PreOrderBiTree(T);
printf("\n");
printf("递归中序遍历二叉树");
MiddleOrderBiTree(T);
printf("\n");
printf("递归后序遍历二叉树");
PostOrderBiTree(T);
printf("\n");
printf("层次遍历二叉树");
LevelOrder(T);
printf("\n");
depth=TreeDeep(T);
printf("树的深度:%d\n",depth);
leafCount=LeafCount(T);
printf("叶子结点个数:%d\n",leafCount);
printf("交换二叉树的左右子树,");
SwapTree(&T);
printf("先序遍历结果为");
PreOrderBiTree(T);
printf("\n");
printf("由先序和中序序列构建二叉树,");
BiTNode* t;
int pre[7]={1,2,3,4,5,6,7};
int in[7]={3,2,4,1,5,7,6};
PreInOrd(pre,in,0,6,0,6,&t);
printf("先序输出结果:");
PreOrderBiTree(t);
printf("\n");
printf("由后序和中序序列构建二叉树,");
BiTNode* f;
int pos[8]={4,5,3,2,8,7,6,1};
int inn[8]={2,4,3,5,1,6,8,7};
PosInOrd(pos,inn,0,7,0,7,&f);
printf("先序输出结果:");
PreOrderBiTree(f);
printf("\n");
printf("由层次和中序序列构建二叉树,");
BiTNode* ff;
int lev[10]={1,2,3,4,5,6,7,8,9,10};
int innn[10]={4,2,7,5,8,10,1,3,9,6};
LevelInOrd(lev,innn,10,&ff);
printf("先序输出结果:");
PreOrderBiTree(ff);
printf("\n");
return 0;
}
//测试数据 p125页图6.4 1 2 4 -1 -1 5 6 -1 -1 7 -1 -1 3 -1 -1
4、输出结果