另一种使用栈实现二叉树层序遍历的方法

使用队列是比较方便的实现二叉树层序遍历的常用方法,通过栈来实现也是可以的,以下给出一个使用栈实现二叉树层序遍历的方法。

使用三个栈实现二叉树的层次遍历

int  LayerOrderByStackTraverse(BiTree T,int (*Visit)(TreeElemType d))
{ 
    //s1存储每层的所有树节点,次序是逆序(左边的节点在栈下方)
    //s2是存储当前层节点的下层所有节点,次序也是逆的
    //s3是为了正确顺序输出节点,从s1反序而来的,左边的节点在栈上方)
    //temp是s2和s1的中转变量,为了下次循环能够处理下一层节点。
    LinkStack s1,s2,s3,temp;
    initStack(&s1);
    initStack(&s2);
    initStack(&s3);

    BiNode * node;

    if(T==NULL)
        return ERROR;
    pushStack(s1,T);

    while(lenStack(s1)){

        while(lenStack(s1)){  //从s1反序生成s3,左边的节点在栈上方)
            popStack(s1,&node);
            pushStack(s3,node);
        }
        while(lenStack(s3)){  //从s3出栈并输出节点,是层序的正确顺序
            popStack(s3,&node);
            printTreeNode(node);
            //按层序正确顺序将当前层的下层结点压入s2,s2中左边的节点在栈下方
            if(node->l)
                pushStack(s2,node->l);      
            if(node->r)
                pushStack(s2,node->r);

        } //循环结束后,s2中保存了下一层节点信息

        //以下交换s2和s1所指向的栈,以便下次循环通过s1来处理下一层节点
        temp=s1;
        s1=s2;
        s2=temp;        
    }

    return OK;
}

两个栈实现二叉树的层次遍历

以上代码写好后,发现了以下文章:
双栈法对二叉树进行层序遍历
https://blog.csdn.net/qq_46477898/article/details/110142364

从而精简掉s3栈,且省略了交换两个栈的过程。

精简后的代码:

int  LayerOrderByStackTraverse2(BiTree T,int (*Visit)(TreeElemType d))
{ 
    //s1存储每层的所有树节点,次序是逆序(左边的节点在栈下方)
    //s2是为了正确顺序输出节点,从s1反序而来的,左边的节点在栈上方)
    LinkStack s1,s2;
    initStack(&s1);
    initStack(&s2);

    BiNode * node;

    if(T==NULL)
        return ERROR;
    pushStack(s1,T);

    while(lenStack(s1)){

        while(lenStack(s1)){  //从s1反序生成s2,左边的节点在栈上方)
            popStack(s1,&node);
            pushStack(s2,node);
        }
        while(lenStack(s2)){  //从s2出栈并输出节点,是层序的正确顺序
            popStack(s2,&node);
            printTreeNode(node);
            //按层序正确顺序将当前层的下层结点压入s1,s1中左边的节点在栈下方
            if(node->l)
                pushStack(s1,node->l);      
            if(node->r)
                pushStack(s1,node->r);

        } //循环结束后,s1中保存了下一层节点信息     
    }

    return OK;
}

完整的代码如下:


#include <stdio.h>
#include <conio.h>
#include <malloc.h>

#define ERROR 0
#define OK 1

typedef int TreeElemType;

typedef struct BinaryTree
{
    TreeElemType data;
    struct BinaryTree *l;
    struct BinaryTree *r;
}*BiTree,BiNode;

typedef BiNode *StackElemType;

struct SNODE
{
    StackElemType data;
    struct SNODE *next;
};

typedef struct SNODE SNode;
typedef struct SNODE *LinkStack;


int initStack(LinkStack *L)
{
    *L=(SNode *)malloc(sizeof(SNode));
    if(!L)
        exit(ERROR);
    (*L)->next=NULL;
    return OK;
}

int lenStack(LinkStack L)
{
    int j=0;
    while (L->next)
    {
        L=L->next;
        j++;
    }
    return j;
}

int popStack(LinkStack L,StackElemType *e)
{
    LinkStack p;
    SNode *temp;
    p=L;
    if(p->next){
        *e=p->next->data;
        temp=p->next;
        p->next=temp->next;
        free(temp);
        return OK;
    }else
        return ERROR;
}

int topStack(LinkStack L,StackElemType *e)
{
    LinkStack p;
    p=L;
    if(p->next){
        *e=p->next->data;
        return OK;
    }else
        return ERROR;
}

int pushStack(LinkStack L,StackElemType e)
{
    LinkStack p,s;
    p=L;
    s=(LinkStack)malloc(sizeof(SNode));
    s->data=e;
    s->next=p->next;
    p->next=s;
    return OK;
}

int printTreeElem(TreeElemType d)
{
    printf("%d ",d);
    return OK;
}

int printTreeNode(BiNode *node)
{
    printf("curNode:%p   L:%p,  data:%2d,  R:%p\n",node,node->l,node->data,node->r);
}

int printStack(LinkStack L)
{
    LinkStack p;
    p=L;
    if(p->next==NULL)
        printf("当前栈为空");
    while(p->next)
    {
        p=p->next;
        printTreeNode((BiNode*)p->data);
    }
    printf("end of stack----------------\n");
    return 0;
}

//------------------------------------------

BiNode * newNode()
{
    return( (BiNode *)malloc(sizeof(BiNode)) );
}

int CreateSubTree(BiTree *T,TreeElemType *all,int i)
{
    if ((all[i]==0)||i>15)
    {
        *T=NULL;
        return OK;
    }
    *T=newNode();
    if(*T==NULL) return ERROR;
    (*T)->data=all[i];
    CreateSubTree(&((*T)->l),all,2*i);
    CreateSubTree(&((*T)->r),all,2*i+1);
}

/*                0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15*/
TreeElemType allNode[16]={0,1,2,3,0,0,4,5,0,0, 0, 0, 6, 0, 0, 0};
//TreeElemType allNode[16]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};

void CreateBiTree(BiTree *T)
{
    /*
               1
              / \
            2    3
                / \
               4   5
              /
             6
     */
    /*                0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15*/
    //TreeElemType allNode[16]={0,1,2,3,0,0,4,5,0,0, 0, 0, 6, 0, 0, 0};

     /*
               1
           /        \
          2          3
         / \       /   \
        4   5     6     7
       / \  /\   / \   / \
      8  9 10 11 12 13 14 15
     */ 
    /*                          0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15*/ 
    //TreeElemType allNode[16]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};


    CreateSubTree(T,allNode,1);
}


/*1 2 3 4 6 5*/
int PreOrderTraverse(BiTree T,int (*Visit)(TreeElemType d))
{
    if(T){
        if(Visit(T->data))
            if(PreOrderTraverse(T->l,Visit))
                if(PreOrderTraverse(T->r,Visit)) 
                    return OK;
        return ERROR;
    } else  return OK;
}

/*2 6 4 5 3 1 */
int PostOrderTraverse(BiTree T,int (*Visit)(TreeElemType d))
{
    if(T){
        if(T->l)
            PostOrderTraverse(T->l,Visit);
        if(T->r)
            PostOrderTraverse(T->r,Visit);
        if(Visit(T->data)){
            return OK;
        }else
            return ERROR;
    } else  return OK;
}

/*2 1 6 4 3 5 */
int InOrderTraverse(BiTree T,int (*Visit)(TreeElemType d))
{
    if(T){
        if(T->l)
            InOrderTraverse(T->l,Visit);
        if(Visit(T->data)){
            if(T->r)
                InOrderTraverse(T->r,Visit);
            return OK;
        }else
            return ERROR;

    } else  return OK;
}

//请参考随后函数的注释
/*1 2 3 4 5 6 */
int  LayerOrderByStackTraverse2(BiTree T,int (*Visit)(TreeElemType d))
{ 
    //s1存储每层的所有树节点,次序是逆序(左边的节点在栈下方)
    //s2是为了正确顺序输出节点,从s1反序而来的,左边的节点在栈上方)
    LinkStack s1,s2;
    initStack(&s1);
    initStack(&s2);

    BiNode * node;

    if(T==NULL)
        return ERROR;
    pushStack(s1,T);

    while(lenStack(s1)){

        while(lenStack(s1)){  //从s1反序生成s2,左边的节点在栈上方)
            popStack(s1,&node);
            pushStack(s2,node);
        }
        while(lenStack(s2)){  //从s2出栈并输出节点,是层序的正确顺序
            popStack(s2,&node);
            printTreeNode(node);
            //按层序正确顺序将当前层的下层结点压入s1,s1中左边的节点在栈下方
            if(node->l)
                pushStack(s1,node->l);      
            if(node->r)
                pushStack(s1,node->r);

        } //循环结束后,s1中保存了下一层节点信息     
    }

    return OK;
}

/*
  以下代码写好后,发现了以下文章:
  双栈法对二叉树进行层序遍历
  https://blog.csdn.net/qq_46477898/article/details/110142364

    typedef struct BinaryTree
    {
        char  data;
        struct BinaryTree* lchild;//左孩子
        struct BinaryTree* rchild;//右孩子
    }BinaryTree,*Bitree;

    void flow_traverse(Bitree T)//层序遍历
    {
        stack<Bitree>s1,s2;//定义两个栈
        Bitree p = T;
        cout << p->data;
        s1.push(p->rchild);
        s1.push(p->lchild);//将根结点的左右孩子压入栈1
        while (1)
        {
            if (s1.empty() && s2.empty())//循环结束条件
                break;
            while(!s2.empty())
            {
                if (s2.top()->rchild != NULL)
                    s1.push(s2.top()->rchild);
                if(s2.top()->lchild != NULL)
                    s1.push(s2.top()->lchild);
                s2.pop();
            }
            while (!s1.empty())
            {
                cout << s1.top()->data;
                s2.push(s1.top());
                s1.pop();
            }
        }
    }

  从而精简掉s3栈,且省略了交换两个栈的过程。
  精简后的代码为函数:LayerOrderByStackTraverse2  
 */
/*1 2 3 4 5 6 */
int  LayerOrderByStackTraverse(BiTree T,int (*Visit)(TreeElemType d))
{ 
    //s1存储每层的所有树节点,次序是逆序(左边的节点在栈下方)
    //s2是存储当前层节点的下层所有节点,次序也是逆的
    //s3是为了正确顺序输出节点,从s1反序而来的,左边的节点在栈上方)
    //temp是s2和s1的中转变量,为了下次循环能够处理下一层节点。
    LinkStack s1,s2,s3,temp;
    initStack(&s1);
    initStack(&s2);
    initStack(&s3);

    BiNode * node;

    if(T==NULL)
        return ERROR;
    pushStack(s1,T);

    while(lenStack(s1)){

        while(lenStack(s1)){  //从s1反序生成s3,左边的节点在栈上方)
            popStack(s1,&node);
            pushStack(s3,node);
        }
        while(lenStack(s3)){  //从s3出栈并输出节点,是层序的正确顺序
            popStack(s3,&node);
            printTreeNode(node);
            //按层序正确顺序将当前层的下层结点压入s2,s2中左边的节点在栈下方
            if(node->l)
                pushStack(s2,node->l);      
            if(node->r)
                pushStack(s2,node->r);

        } //循环结束后,s2中保存了下一层节点信息

        //以下交换s2和s1所指向的栈,以便下次循环通过s1来处理下一层节点
        temp=s1;
        s1=s2;
        s2=temp;        
    }

    return OK;
}

int main()
{
    printf("              0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15\n");
    printf("allNode[16]={");
    for(int i=0;i<16;i++)
        printf("%2d,",allNode[i]);
    printf("};\n");

    printf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
        "    1",
        "   / \\",
        "  2    3",
        "      / \\",
        "     4   5",
        "    /",
        "   6"
    );

    printf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
    "          1",
    "      /      \\",
    "    2          3",
    "   / \\       /   \\",
    "  4   5     6     7",
    " / \\  /\\   / \\   / \\",
    "8  9 10 11 12 13 14 15 "
    );


    BiTree root;
    CreateBiTree(&root);
    printf("PreOrder:\n");
    PreOrderTraverse(root,printTreeElem);
    printf("\n");

    printf("InOrder:\n");
    InOrderTraverse(root,printTreeElem);
    printf("\n");

    printf("PostOrder:\n");
    PostOrderTraverse(root,printTreeElem);
    printf("\n");

    printf("LayerOrderByStackTraverse:\n");
    LayerOrderByStackTraverse2(root,printTreeElem);
    printf("\n");

    getch();
    return 0;
}

zmofun@163.com 于 2023-4-15

标签: C语言, 数据结构, 二叉树, 层序遍历

评论已关闭