Localhost8080

知行合一,自强不息

 

二叉树的各种遍历

上周数据结构课在讲二叉树的遍历,老师只讲递归算法,没有什么技术含量,遂自己琢磨非递归算法实现...

前序遍历:先访问根节点,再访问左子树,最后访问右子树。设置一个栈,出栈即为访问节点。先将根节点进栈,在栈不空时一直如下循环:出栈,访问,将其右孩子进栈,再将左孩子进栈。

中序遍历:先访问左子树,再访问根节点,最后访问右子树。设置一个栈,出栈即为访问节点。先将根节点的左节点全部进栈,然后出栈一个节点,访问。将该节点的右孩子节点进栈,再将右孩子节点的所有左节点全部进栈...如此这般直到栈空为止。

后序遍历:先访问左子树,再访问右子树,最后访问根节点。设置一个栈。先将根节点的左节点全部进栈。出栈一个节点,将该节点的右孩子进栈,再将右孩子的左节点全部进栈...当一个节点的左、右孩子都被访问过后再访问该节点,如此这般直到栈空为止。(判断某节点的右孩子是否被访问,需要单独设置一个指针跟踪刚刚访问的节点。在后序遍历中,某节点的右孩子节点一定刚好在该节点之前被访问)

因为代码的重点是非递归遍历,所以建立二叉树的过程我就使用了"前序递归"。对于如下一棵树,以"#"代表空节点,前序递归建立二叉树需要的输入数据和前序遍历的顺序是一样的,且每个叶子节点的左右孩子均为"#"。

输入:ABDH##I##EJ##K##CF#L##G##
前序遍历:A B D H I E J K C F L G
中序遍历:H D I B J E K A F L C G
后序遍历:H I D J K E B L F G C A

#include <stdio.h>
#include 
<stdlib.h>
 
#define MAXSIZE 200
 
/* 定义二叉树节点类型 */
typedef 
struct node
{
    
char data;
    
struct node *lchild, *rchild;
}BTNode;
 
/* 函数声明 */
BTNode
* CreatBitTree();
void PreOrder(BTNode*);
void InOrder(BTNode*);
void PostOrder(BTNode*);
 
/* 主函数 */
int main()
{
    BTNode 
*root = NULL;
    root 
= CreatBitTree();
    PreOrder(root);
    InOrder(root);
    PostOrder(root);
    system(
"pause");
    
return 0;
}
 
/* 递归前序建立二叉树 */
BTNode
* CreatBitTree()
{
    
char ch;
    BTNode 
*b;
    scanf(
"%c"&ch);
    
/* 遇到空节点停止递归 */
    
if (ch == '#')
    {
        b 
= NULL;
    }
    
else
    {
        b 
= (BTNode*) malloc(sizeof(BTNode));
        
/* 建立根节点 */
        b
->data = ch;
        
/* 递归先序建立左子树 */
        b
->lchild = CreatBitTree();
        
/* 递归先序建立右子树 */
        b
->rchild = CreatBitTree();
    }
    
return b;
}
 
/* 非递归前序遍历二叉树 */
void PreOrder(BTNode* b)
{
    BTNode 
*stack[MAXSIZE], *p;
    
int top = -1;
    
if (b != NULL)
    {
        
/* 根节点入栈 */
        top
++;
        stack[top] 
= b;
        
/* 栈不空时循环 */
        
while (top > -1)
        {
            
/* 出栈并访问该节点 */
            p 
= stack[top];
            top
--;
            printf(
"%c ", p->data);
            
/* 右孩子入栈 */
            
if (p->rchild != NULL)
            {
                top
++;
                stack[top] 
= p->rchild;
            }
            
/* 左孩子入栈 */
            
if (p->lchild != NULL)
            {
                top
++;
                stack[top] 
= p->lchild;
            }
        }
        printf(
"\n");
    }
}
 
/* 非递归中序遍历二叉树 */
void InOrder(BTNode* b)
{
    BTNode 
*stack[MAXSIZE], *p;
    
int top = -1;
    
if (b != NULL)
    {
        p 
= b;
        
while (top > -1 || p != NULL)
        {
            
/* 扫描p的所有左节点并入栈 */
            
while (p != NULL)
            {
                top
++;
                stack[top] 
= p;
                p 
= p->lchild;
            }
            
if (top > -1)
            {
                
/* 出栈并访问该节点 */
                p 
= stack[top];
                top
--;
                printf(
"%c ", p->data);
                
/* 扫描p的右孩子 */
                p 
= p->rchild;
            }
        }
        printf(
"\n");
    }
}
 
/* 非递归后序遍历二叉树 */
void PostOrder(BTNode* b)
{
    BTNode 
*stack[MAXSIZE], *p;
    
int sign, top = -1;
    
if (b != NULL)
    {
        
do
        {
            
/* b所有左节点入栈 */
            
while (b != NULL)
            {
                top
++;
                stack[top] 
= b;
                b 
= b->lchild;
            }
            
/* p指向栈顶前一个已访问节点 */
            p 
= NULL;
            
/* 置b为已访问 */
            sign 
= 1;
            
while (top != -1 && sign)
            {
                
/* 取出栈顶节点 */
                b 
= stack[top];
                
/* 右孩子不存在或右孩子已访问则访问b */
                
if (b->rchild == p)
                {
                    printf(
"%c ", b->data);
                    top
--;
                    
/* p指向被访问的节点 */
                    p 
= b;
                }
                
else
                {
                    
/* b指向右孩子节点 */
                    b 
= b->rchild;
                    
/* 置未访问标记 */
                    sign 
= 0;
                }
            }
        }
while (top != -1);
        printf(
"\n");
    }
}


其他实现:
#ifndef TREE_H
#define TREE_H


#include 
<stdio.h>
#include 
<malloc.h>
#include 
<stack>
#include 
<queue>
#include 
<assert.h>

using namespace std;



typedef 
int ElemType;

typedef 
struct treeT
{
    ElemType key;
    
struct treeT* left;
    
struct treeT* right;
}treeT, 
*pTreeT;




/**//*===========================================================================
* Function name:    visit
* Parameter:        root:树根节点指针
* Precondition:        
* Description:        
* Return value:        
* Author:            Liu Qi, //-
===========================================================================
*/
static void visit(pTreeT root)
{
    
if (NULL != root)
    {
        printf(
" %d\n", root->key);
    }
}



/**//*===========================================================================
* Function name:  BT_MakeNode    
* Parameter:      target:元素值    
* Precondition:      None    
* Postcondition:  NULL != pTreeT 
* Description:      构造一个tree节点,置左右指针为空,并且返回指向新节点的指针    
* Return value:      指向新节点的指针    
* Author:            Liu Qi,  [12/30/2005]
===========================================================================
*/
static pTreeT BT_MakeNode(ElemType target)
{
    pTreeT pNode 
= (pTreeT) malloc(sizeof(treeT));

    assert( NULL 
!= pNode ); 

    pNode
->key   = target;
    pNode
->left  = NULL;
    pNode
->right = NULL;
    
    
return pNode;
}


/**//*===========================================================================
* Function name:    BT_Insert
* Parameter:        target:要插入的元素值, pNode:指向某一个节点的指针
* Precondition:         NULL != ppTree 
* Description:        插入target到pNode的后面
* Return value:        指向新节点的指针
* Author:            Liu Qi,  [12/29/2005]
===========================================================================
*/
pTreeT BT_Insert(ElemType target, pTreeT
* ppTree)
{
    pTreeT Node;

    assert( NULL 
!= ppTree ); 

    Node 
= *ppTree;
    
if (NULL == Node)
    {
        
return *ppTree = BT_MakeNode(target);
    }

    
if (Node->key == target)    //不允许出现相同的元素
    {
        
return NULL;
    }
    
else if (Node->key > target)    //向左
    {
        
return BT_Insert(target, &Node->left);
    }
    
else
    {
        
return BT_Insert(target, &Node->right);
    }
}




/**//*===========================================================================
* Function name:    BT_PreOrder
* Parameter:        root:树根节点指针
* Precondition:        None
* Description:        前序遍历
* Return value:        void
* Author:            Liu Qi,  [12/29/2005]
===========================================================================
*/
void BT_PreOrder(pTreeT root)
{
    
if (NULL != root)
    {
        visit(root);
        BT_PreOrder(root
->left);
        BT_PreOrder(root
->right);
    }    
}


/**//*===========================================================================
* Function name:    BT_PreOrderNoRec
* Parameter:        root:树根节点指针
* Precondition:        Node
* Description:        前序(先根)遍历非递归算法
* Return value:        void
* Author:            Liu Qi,  [1/1/2006]
===========================================================================
*/
void BT_PreOrderNoRec(pTreeT root)
{
    stack
<treeT *> s;

    
while ((NULL != root) || !s.empty())
    {
        
if (NULL != root)
        {
            visit(root);
            s.push(root);
            root 
= root->left;
        }
        
else
        {
            root 
= s.top();
            s.pop();
            root 
= root->right;
        }
    }
}



/**//*===========================================================================
* Function name:    BT_InOrder
* Parameter:        root:树根节点指针
* Precondition:        None
* Description:        中序遍历
* Return value:        void
* Author:            Liu Qi,  [12/30/2005]
===========================================================================
*/
void BT_InOrder(pTreeT root)
{
    
if (NULL != root)
    {
        BT_InOrder(root
->left);
        visit(root);
        BT_InOrder(root
->right);
    }
}


/**//*===========================================================================
* Function name:    BT_InOrderNoRec
* Parameter:        root:树根节点指针
* Precondition:        None
* Description:        中序遍历,非递归算法
* Return value:        void
* Author:            Liu Qi,  [1/1/2006]
===========================================================================
*/
void BT_InOrderNoRec(pTreeT root)
{
    stack
<treeT *> s;
    
while ((NULL != root) || !s.empty())
    {
        
if (NULL != root)
        {
            s.push(root);
            root 
= root->left;
        }
        
else
        {
            root 
= s.top();
            visit(root);
            s.pop();
            root 
= root->right;
        }
    }
}



/**//*===========================================================================
* Function name:    BT_PostOrder
* Parameter:        root:树根节点指针
* Precondition:        None
* Description:        后序遍历
* Return value:        void
* Author:            Liu Qi,  [12/30/2005]
===========================================================================
*/
void BT_PostOrder(pTreeT root)
{
    
if (NULL != root)
    {
        BT_PostOrder(root
->left);
        BT_PostOrder(root
->right);
        visit(root);    
    }
}


/**//*===========================================================================
* Function name:    BT_PostOrderNoRec
* Parameter:        root:树根节点指针
* Precondition:        None
* Description:        后序遍历,非递归算法
* Return value:        void
* Author:            Liu Qi, //  [1/1/2006]
===========================================================================
*/
void BT_PostOrderNoRec(pTreeT root)
{
//学习中,尚未明白
}


/**//*===========================================================================
* Function name:    BT_LevelOrder
* Parameter:        root:树根节点指针
* Precondition:        NULL != root
* Description:        层序遍历
* Return value:        void
* Author:            Liu Qi,  [1/1/2006]
===========================================================================
*/
void BT_LevelOrder(pTreeT root)
{
    queue
<treeT *> q;
    treeT 
*treePtr;

    assert( NULL 
!= root ); 

    q.push(root);

    
while (!q.empty())
    {
        treePtr 
= q.front();
        q.pop();
        visit(treePtr);

        
if (NULL != treePtr->left)
        {
            q.push(treePtr
->left);    
        }
        
if (NULL != treePtr->right)
        {
            q.push(treePtr
->right);
        }    
            
    }
}


#endif

测试代码:
#include <stdio.h>
#include 
<stdlib.h>
#include 
<time.h>
#include 
"tree.h"

#define MAX_CNT 5
#define BASE  100

int main(int argc, char *argv[])
{
    
int i;
    pTreeT root 
= NULL;
    
    srand( (unsigned)time( NULL ) ); 
    
    
for (i=0; i<MAX_CNT; i++)
    {
        BT_Insert(rand() 
% BASE, &root);
    }

    
//前序
    printf("PreOrder:\n");
    BT_PreOrder(root);
    printf(
"\n");

    printf(
"PreOrder no recursion:\n");
    BT_PreOrderNoRec(root);
    printf(
"\n");
    
    
//中序
    printf("InOrder:\n");
    BT_InOrder(root);
    printf(
"\n");

    printf(
"InOrder no recursion:\n");
    BT_InOrderNoRec(root);
    printf(
"\n");

    
//后序
    printf("PostOrder:\n");
    BT_PostOrder(root);
    printf(
"\n");

    
//层序
    printf("LevelOrder:\n");
    BT_LevelOrder(root);
    printf(
"\n");
    
    
return 0;
}


补充一个后续遍历非递归版:
void BT_PostOrderNoRec(pTreeT root) 

    stack
<treeT *> s; 
    pTreeT pre 
= NULL; 
    pTreeT top 
= NULL; 

    
while ((NULL != root) || !s.empty()) 
    { 
        
if (NULL != root) 
        { 
            s.push(root); 
            root 
= root->left; 
        } 
        
else 
        { 
            top 
= s.top(); 
            
if(top->right != NULL && top->right != pre) 
                root 
= top->right; 
            
else 
            { 
                visit(top); 
                pre 
= top; 
                s.pop(); 
            } 
        } 
    } 
}

posted on 2010-10-18 20:17 superKiki 阅读(355) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


导航

统计

常用链接

留言簿

随笔档案

文章分类

我的好友

一些常去的网站

搜索

最新评论

阅读排行榜

评论排行榜