二叉树的非递归遍历 C语言版

文章作者:Slyar 文章来源:Slyar Home (www.slyar.com) 转载请注明,谢谢合作。

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

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

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

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

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

输入: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

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/*
Slyar
http://www.slyar.com
2009.5.16
*/
#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");
    }
}

你可能感兴趣的:(C语言)