本实验取材于浙江大学《数据结构》
在中序遍历非递归遍历算法中,采用了堆栈存储结构。步数如下:
- 遇到一个结点,就把它压栈,并去遍历它的左子树;
- 当左子树遍历结束后,从栈顶弹出这个结点并访问它;
- 然后按其指针再去中序遍历该结点的右子树。
如果按照树的模型来看,在沿着左子树深入时,进入一个结点就将其压入堆栈。若为中序遍历,则此时访问该结点,然后从该结点的右子树继续深入
void InOrderTraveral(BinTree BT)
{
BinTree T = BT;
Stack S = CreateStack(MaxSize1);
while(T || !IsEmpty(S)){
while(T){//一直向左并将沿途结点压入堆栈
Push(S,T);
T = T->Left;
}
if(!IsEmpty(S))
{
T=(struct TNode *)Pop(S);//结点弹出堆栈
printf("%5d",T->Data);//访问打印结点
T = T->Right;
}
}
}
若是先序遍历,则在入栈之前访问之,当沿左分支深入不下去时,则返回,即从堆栈中弹出前面压入的结点。
void PreorderTraversal( BinTree BT )
{
BinTree T = BT;
Stack S = CreateStack(MaxSize1);
while(T || !IsEmpty(S)){
while(T){//一直向左并将沿途结点压入堆栈
printf("%5d",T->Data);//访问打印结点
Push(S,T);
T = T->Left;
}
if(!IsEmpty(S))
{
T=(struct TNode *)Pop(S);//结点弹出堆栈
T = T->Right;
}
}
}
这样看起来还差一个后序遍历,后序遍历则将此结点二次入栈,然后从该结点右子树继续深入,与前面类同,仍为进入一个结点入栈一个结点,深入不下去再返回,直到第二次从栈里弹出该结点,才访问之。因为两次入栈,比较繁杂,因此,先给出两种遍历!
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define ERROR -1
#define MaxSize1 10
//中序遍历的非递归算法
//一个结点,就把它压栈,并去遍历它的左子树
//当左子树遍历结束后,从栈顶弹出这个结点并访问它
//然后按其右指针再去中序遍历该节点的右子树
typedef struct SNode *PtrToStack;
typedef int ElementType;
typedef struct TNode *Position;
typedef Position BinTree; /* 二叉树类型 */
struct TNode{ /* 树结点定义 */
ElementType Data; /* 结点数据 */
BinTree Left; /* 指向左子树 */
BinTree Right; /* 指向右子树 */
};
struct SNode{
ElementType *Data;
int Top;
int MaxSize;
};
typedef PtrToStack Stack;
Stack CreateStack(int MaxSize);//生成空堆栈,其最大长度为Maxsize
int IsFull(Stack S);//判断堆栈S是否已满
int Push(Stack S,Position X);//将元素item压入堆栈
int IsEmpty(Stack S);//判断堆栈S是否为空
ElementType Pop(Stack S);//删除并返回栈顶元素
Stack CreateStack(int MaxSize){
Stack S=(Stack)malloc(sizeof(struct SNode));
S->Data = (ElementType *)malloc(MaxSize*sizeof(ElementType));
S->Top = -1;
S->MaxSize = MaxSize;
return S;
}
int IsFull(Stack S){
return (S->Top==S->MaxSize-1);
}
int Push(Stack PtrS,Position X)
{
if(IsFull(PtrS)){
printf("堆栈满");
return ERROR;
}else{
PtrS->Data[++(PtrS->Top)] = (int )X;
return PtrS->Data[PtrS->Top];
}
}
int IsEmpty(Stack S){
return (S->Top==-1);
}
ElementType Pop(Stack PtrS)
{
if(PtrS->Top==-1){
printf("堆栈空");
return ERROR;
}else{
return (PtrS->Data[(PtrS->Top)--]);
}
}
void InOrderTraveral(BinTree BT)
{
BinTree T = BT;
Stack S = CreateStack(MaxSize1);
while(T || !IsEmpty(S)){
while(T){//一直向左并将沿途结点压入堆栈
Push(S,T);
T = T->Left;
}
if(!IsEmpty(S))
{
T=(struct TNode *)Pop(S);//结点弹出堆栈
printf("%5d",T->Data);//访问打印结点
T = T->Right;
}
}
}
void PreorderTraversal( BinTree BT )
{
BinTree T = BT;
Stack S = CreateStack(MaxSize1);
while(T || !IsEmpty(S)){
while(T){//一直向左并将沿途结点压入堆栈
printf("%5d",T->Data);//访问打印结点
Push(S,T);
T = T->Left;
}
if(!IsEmpty(S))
{
T=(struct TNode *)Pop(S);//结点弹出堆栈
T = T->Right;
}
}
}
int main()
{
BinTree Bt = (BinTree)malloc(sizeof(struct TNode));
BinTree Bt1 = (BinTree)malloc(sizeof(struct TNode));
BinTree Bt2 = (BinTree)malloc(sizeof(struct TNode));
BinTree Bt3 = (BinTree)malloc(sizeof(struct TNode));
BinTree Bt4 = (BinTree)malloc(sizeof(struct TNode));
Bt->Data = 1;
Bt1->Data=2;
Bt2->Data=3;
Bt3->Data=4;
Bt4->Data=5;
Bt->Left = Bt1;
Bt->Right = Bt2;
Bt1->Left = NULL;
Bt1->Right = NULL;
Bt2->Left = Bt3;
Bt2->Right = Bt4;
Bt3->Left = NULL;
Bt3->Right = NULL;
Bt4->Left = NULL;
Bt4->Right = NULL;
printf("\nzhong xu bian li\n");
InOrderTraveral(Bt);
printf("\nxian xu bian li \n");
PreorderTraversal(Bt);
printf("\n");
return 0;
}