看了大量网络相关的理论和程序,多数的C++ 写的,这里使用devC++
编程语言 C语言; 整合王道考研答案和理论, 还有小甲鱼的数据结构, 郝斌的数据结构,各有特点吧
最值得研究的还是后序遍历的非递归算法, 当时想了使用flag, 想到了多用一个栈, 想到了很多种方式,最后都以失败告终,经过网络查找,
感谢 https://www.cnblogs.com/rain-lei/p/3705680.html
这里使用的一个栈每个结点两次入栈,解决了后序遍历与父结点遍历的冲突,相信只有仔细思考过这个问题的朋友才会明白多有意思.
话不多说,直接上代码, 复制粘贴可用.
#include "stdio.h"
#include "stdlib.h"
#include "malloc.h"
#include "string.h"
#include "stdbool.h"
/* 变量声明区 */
typedef char elemType;
/* 结构体声明 */
typedef struct BitTree{ //树
elemType data;
struct BitTree *lChild, *rChild;
int lTag, rTag;
}*PBitTree, BitTreeN;
#define STACK_MAX_SIZE 50
typedef struct Stack{ //栈
PBitTree data[STACK_MAX_SIZE];
int top;
}Stack, *PStack;
/*
注意 top=-1为空 top=max为满
*/
#define QUEUE_MAX_SIZE 50
typedef struct Queue{ //队列
PBitTree data[QUEUE_MAX_SIZE];
int rear,front;
}Queue, *PQueue;
/*
注意 rear=front为空 (rear+1)%max = front为满
*/
/* 函数声明区 */
//common bit tree
void CreateBieTr_Pre(PBitTree*T); /* 动态创建先序二叉树 */
/*使用递归方式,判断的输入的字符是否为' ',然后递归&(*T)->lChild,在rChild*/
PBitTree CreateBT(void); //静态建立二叉树
/*创建结点,在将结点相互关联到一起*/
PBitTree InitBitTree_Pre(elemType pre[], int pre0, int pren, elemType in[], int in0, int inn);
/*将先序和中序合并成先序, 使用遍历算法,
先找到先序的第一个结点,用第一个查找中序的位置,确定好中序中间位置到两端的长度,
作为递归确定左右孩子的参数, 当找不到中点表示为NULL*/
//递归遍历
void visit(elemType ch, int level);
void PreOrder_Recursion(PBitTree T, int level); /* 先序遍历二叉树 */
void MedOrder_Recursion(PBitTree T, int level); /* 中序遍历二叉树 */
void PostOrder_Recursion(PBitTree T, int level);/* 后序遍历二叉树 */
//非递归遍历
void InOrder2(PBitTree T); //使用栈 中序遍历 非递归
void PreOrder2(PBitTree T); //使用栈 先序遍历 非递归
void PostOrder2(PBitTree T); //使用栈 后序遍历 非递归
void PostOrder2_2(PBitTree T); //双次入栈 后序遍历 非递归
void LevelOrder_from_H_to_L_L_to_R(PBitTree T); //使用队列 层次遍历 非递归
void main()
{
int i;
PBitTree T = NULL;
char val;
int int_val;
int level=1;
//初始化二叉树1
// printf("下面进行动态先序生成二叉树,使用空格作为NULL标记:\n");
// CreateBieTr_Pre( &T );
//初始化二叉树2
// T =CreateBT();
//初始化二叉树3
elemType pre[] = "ABCDEF";
elemType in[] = "CBDAEF";
T = InitBitTree_Pre(pre, 0, 6, in, 0, 6);
printf("普通二叉树的前序遍历\n"); PreOrder_Recursion(T, level);
printf("普通二叉树的中序遍历\n"); MedOrder_Recursion(T, level);
printf("普通二叉树的后序遍历\n"); PostOrder_Recursion(T, level);
InOrder2(T); //中序非递归二叉树的遍历
PreOrder2(T);
PostOrder2(T);
PostOrder2_2(T);
LevelOrder_from_H_to_L_L_to_R(T);
return;
}
/* 函数实现区 */ //---------------------------------------------------------------
//动态 先序创建树
void CreateBieTr_Pre(PBitTree*T)
{
elemType ch;
scanf("%c",&ch);
if(' ' == ch)
{
*T = NULL;
return;
}
else
{
(*T) = (PBitTree)malloc(sizeof(BitTreeN));
(*T)->data = ch;
CreateBieTr_Pre(&(*T)->lChild);
CreateBieTr_Pre(&(*T)->rChild);
return;
}
}
/* 静态建立二叉树 */
PBitTree CreateBT(void)
{
PBitTree PA = (PBitTree)malloc(sizeof(BitTreeN)); PA->data = 'A';
PBitTree PB = (PBitTree)malloc(sizeof(BitTreeN)); PB->data = 'B';
PBitTree PC = (PBitTree)malloc(sizeof(BitTreeN)); PC->data = 'C';
PBitTree PD = (PBitTree)malloc(sizeof(BitTreeN)); PD->data = 'D';
PBitTree PE = (PBitTree)malloc(sizeof(BitTreeN)); PE->data = 'E';
PBitTree PF = (PBitTree)malloc(sizeof(BitTreeN)); PF->data = 'F';
PA->lChild = PB; PA->rChild = PE;
PB->lChild = PC; PB->rChild = PD;
PE->lChild = NULL; PE->rChild = PF;
PC->lChild = PC->rChild = NULL;
PD->lChild = PD->rChild = NULL;
PF->lChild = PF->rChild = NULL;
return PA;
}
/* 给出先序和中序,求先序的二叉链表 Pre是先序 给出数组中0-n表示的位置 In是中序 */
PBitTree InitBitTree_Pre(elemType pre[], int pre0, int pren, elemType in[], int in0, int inn)
{
// if()return;
PBitTree Root = (PBitTree)malloc(sizeof(BitTreeN));
Root->data = pre[pre0];
int i;
int lLen,rLen;
for(i=in0; in[i] != Root->data; i++); //找到中间值
lLen = i-in0; //左子树长度
rLen = inn-i; //右子树长度
printf("in0=%d, inn=%d pr0=%d, pren=%d data %c zuo %d zyo %d \n",pre0, pren, in0, inn, Root->data,lLen,rLen);
if(lLen)
{
Root->lChild = InitBitTree_Pre(pre, pre0+1, pre0+lLen, in, in0, in0+lLen-1);//建立左子树
}
else
{
Root->lChild = NULL;
}
if(rLen)
{
Root->rChild = InitBitTree_Pre(pre, pren-rLen+1, pren, in, inn-rLen+1, inn);//建立左子树
}
else
{
Root->rChild = NULL;
}
return Root;
}
//-----以下为common Bit Tree的三种遍历----------------------------------------------------------------------------//
void visit(elemType ch, int level)
{
printf("树 %c 位于第 %d 层\n", ch, level);
return;
}
/* 先序遍历二叉树 */
void PreOrder_Recursion(PBitTree T, int level)
{
if(NULL != T) //递归缺点 浪费空间,运行时间长
{
visit(T->data, level);//访问根节点
if(NULL != T->lChild) PreOrder_Recursion(T->lChild, level+1); //先左子树
if(NULL != T->rChild) PreOrder_Recursion(T->rChild, level+1); //后右子树
}
return;
}
/* 中序遍历二叉树 */
void MedOrder_Recursion(PBitTree T, int level)
{
if(NULL != T) //递归缺点 浪费空间,运行时间长
{
if(NULL != T->lChild) MedOrder_Recursion(T->lChild, level+1); //先左子树
visit(T->data, level);//访问根节点
if(NULL != T->rChild) MedOrder_Recursion(T->rChild, level+1); //后右子树
}
}
/* 后序遍历二叉树 */
void PostOrder_Recursion(PBitTree T, int level)
{
if(NULL != T) //递归缺点 浪费空间,运行时间长
{
if(NULL != T->lChild) PostOrder_Recursion(T->lChild, level+1); //先左子树
if(NULL != T->rChild) PostOrder_Recursion(T->rChild, level+1); //后右子树
visit(T->data, level);//访问根节点
}
}
/* 普通二叉树 非递归 中序遍历 */
void InOrder2(PBitTree T)
{
printf("普通二叉树 非递归 中序遍历:\n");
PBitTree P = T; //P是遍历指针
PStack S = (PStack)malloc(sizeof(Stack)); S->top = -1; //初始化栈
while( P || ( S->top != -1 ) ) //栈不空 P不空
{
if( P )
{
if(S->top != STACK_MAX_SIZE) //栈不满
{
S->data[ ++S->top ] = P;
P = P->lChild;
}
}
else
{
if(S->top != -1) //栈不空
{
P = S->data[ S->top--]; //出栈
printf("%c ",P->data);
P = P->rChild;
}
}
}
printf("\n");
return;
}
/* 普通二叉树 非递归 先序遍历 */
void PreOrder2(PBitTree T)
{
printf("普通二叉树 非递归 先序遍历:\n");
PBitTree P = T; //P是遍历指针
PStack S = (PStack)malloc(sizeof(Stack)); S->top = -1; //初始化栈
while( P || ( S->top != -1 ) )
{
if( P ) //遍历左孩子
{
printf("%c ",P->data);
S->data[++S->top] = P; //入栈
P = P->lChild;
} //出来是遇到了空
else
{
P = S->data[S->top--]; //出栈
P = P->rChild;
}
}
printf("\n");
return;
}
/* 普通二叉树 非递归 后序遍历 */
void PostOrder2(PBitTree T)
//重点在于判定指针是从左子树返回的还是右子树, 若右子树则该结点已经到顶了
{
printf("普通二叉树 非递归 后序遍历:\n");
PBitTree P = T; //P是遍历指针
PBitTree R = NULL; //辅助指针
PStack S = (PStack)malloc(sizeof(Stack)); S->top = -1; //初始化栈
while( P || (S->top!=-1) )
{
if(P) // 一直遍历到最左下面
{
S->data[++S->top] = P;
P = P->lChild;
}
else
{
P = S->data[S->top];
if(P->rChild != NULL && P->rChild!=R ) //如果右子树存在且未被访问过
{
P = P->rChild;
S->data[++S->top] = P;
P = P->lChild;
}
else
{
P = S->data[S->top--];
printf("%c ",P->data);
R = P;
P = NULL;
}
}
}
printf("\n");
return;
}
void PostOrder2_2(PBitTree T)
{
if(T == NULL)
{
return;
}
printf("通普二叉树 非递归 后序遍历\n");
PBitTree P = T;
PStack S = (PStack)malloc(sizeof(Stack));
S->top = -1;
S->data[++S->top] = T; //树根节点 双次入栈
S->data[++S->top] = T;
while(S->top != -1)
{
P = S->data[S->top--];
if(S->top!=-1 && P==S->data[S->top])//栈不为空,且 曾经的栈 前两层相同
{
//栈顶的左右孩子如果还有,则下次循环 曾经的栈 前两层相同 继续寻找最左边
//结点的左右孩子,然后继续寻找直到找到左右孩子都没有了,就开始打印
/*
对于每个结点都压栈两次,在循环中,每次弹出的一个结点赋给P,如果P仍然等于
栈的头结点,说明P的孩子们还有没被操作过的,应该把他的孩子们入栈,否则,访问P
也就是说, 第一次弹出, 将P的孩子压栈, 第二次弹出, 访问P
*/
if(P->rChild != NULL)
{
S->data[++S->top] = P->rChild;
S->data[++S->top] = P->rChild;
}
if(P->lChild != NULL)
{
S->data[++S->top] = P->lChild;
S->data[++S->top] = P->lChild;
}
}
else //曾经的栈 前两层不相同
{
printf("%c ",P->data);
}
}
printf("\n");
return;
}
/* 普通二叉树的遍历 从上到下,从左到右 */
void LevelOrder_from_H_to_L_L_to_R(PBitTree T)
{
if(!T)return; //防止空树
printf("普通二叉树的遍历 从上到下,从左到右\n");
PBitTree P = T;
PQueue Q = (PQueue)malloc(sizeof(Queue)); //新建队列
Q->front = Q->rear =0;
Q->data[Q->rear] = P; Q->rear = (Q->rear+1)%QUEUE_MAX_SIZE; //根结点入队
while( Q->rear != Q->front )
{
P = Q->data[Q->front]; Q->front = (Q->front+1)%QUEUE_MAX_SIZE; //出队
printf("%c ",P->data);
//注意 如果需要层次遍历 从下到上,从右到左 可以在这里入栈,到最后在出栈
if(P->lChild)
{
Q->data[Q->rear] = P->lChild; //入队
Q->rear = (Q->rear+1)%QUEUE_MAX_SIZE;
}
if(P->rChild)
{
Q->data[Q->rear] = P->rChild;
Q->rear = (Q->rear+1)%QUEUE_MAX_SIZE;
}
}
printf("\n");
return;
}