A question about how to travel a binary tree in layer sequence

select a right data structure can solve it easily

Posted by Maizi on 2016-09-15 with time read

怎么按层的先后顺序且每层按从左至右的顺序遍历二叉树

问题描述如下:

设计一个算法,按层级的先后顺序来遍历二叉树,且每层元素的遍历顺序也是按从左到右的次序

算法描述:


①使用链表来实现队列(用该队列来实现按层访问).

②首先将二叉树的根节点放入队列.获取首元素在二叉树中的左右孩子节点,将首元素出队列,然后将左右孩子(存在的话)依次序入队列并维护队列的首位指针的指向.

③重复执行 中的操作.直到队列为空,则说明已遍历完了整棵二叉树.

最后贴上代码:

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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
#include <stdio.h>
#include <stdlib.h>
typedef struct btree bt;
//二叉树的节点结构定义
struct btree {
int _val;
int _count;//此处优化结构,当元素重复时将该节点的计数器加一
bt *_lc;
bt *_rc;
};
/**
* 挂载节点
* @param head 二叉树的根节点的指针
* @param val 待插叙节点的值
*/
void insert(bt *const head, int const val) {
bt *node = malloc(sizeof(bt));
node->_val = val;
node->_count = 1;
node->_lc = NULL;
node->_rc = NULL;
bt *tmp = head;
while (1) {
if (tmp->_val == val) {
tmp->_count++;
return;
} else if (tmp->_val > val) {
if (tmp->_lc == NULL)
break;
else
tmp = tmp->_lc;
} else {
if (tmp->_rc == NULL)
break;
else
tmp = tmp->_rc;
}
}
if (tmp->_val > val)
tmp->_lc = node;
else
tmp->_rc = node;
}
/**
* 构建二叉树
* @param arr 构建二叉树的输入-数组
* @param len 数组的长度
* @return 二叉树根节点的指针
*/
bt *buildTree(int const * const arr, size_t const len) {
bt *head = malloc(sizeof(bt));
head->_val = *arr;
head->_count = 1;
head->_lc = NULL;
head->_rc = NULL;
int i;
for (i = 1; i < len; ++i) {
insert(head, *(arr + i));
}
return head;
}
/**
* 中序遍历(采用的递归算法)
* @param node 当前的"根"节点指针
*/
void travelMidSeq(bt const * const node) {
if (node->_lc != NULL)
travelMidSeq(node->_lc);
int i;
int len = node->_count;
for (i = 0; i < len; ++i)
printf("%d ", node->_val);
if (node->_rc != NULL)
travelMidSeq(node->_rc);
}
/**
* 释放资源(递归算法)---实质就是后续遍历的算法
* @param node 当前需要处理的节点指针
*/
void releaseTree(bt *node) {
if (node->_lc != NULL)
releaseTree(node->_lc);
if (node->_rc != NULL)
releaseTree(node->_rc);
free(node);
}
typedef struct linkNode ln;
//单链表的节点结构定义
struct linkNode {
bt *_node;
ln *_next;
};
typedef struct linkList mQueue;
//队列定义(链表实现)
struct linkList {
ln *_head;
ln *_tail;
//移除队列(链表实现)首元素并添加该首元素在二叉树中的两个子节点入队列的函数指针
ln *(*removeFirstAndAddItsChilds)(mQueue const * const queue);
};
/**
* 按传入的二叉树节点指针构造一个新的链表节点
* @param bt_node 二叉树节点指针
* @return 构造的新链表节点指针
*/
ln *makeNode(bt const * const bt_node) {
ln *node = (ln *) malloc(sizeof(ln));
node->_node = bt_node;
return node;
}
/**
* 移除队列(链表实现)首元素并添加该首元素在二叉树中的两个子节点入队列的函数指针
* @param queue 队列的指针
* @return 移除的队列元素的指针
*/
ln *removeFirstAndAddItsChilds(mQueue const *queue) {
ln *first = queue->_head->_next;
//判断即将移出的元素是否有左、右孩子节点
ln *nl = NULL;
ln *nr = NULL;
if (first->_node->_lc)
nl = makeNode(first->_node->_lc);
if (first->_node->_rc)
nr = makeNode(first->_node->_rc);
ln *curTail = queue->_tail->_next;
if (queue->_tail->_next) {
if (queue->_head->_next == queue->_tail->_next) {
//说明队列中当前只有一个元素
if (nl) {//左孩子不为空
queue->_head->_next = nl;
if (nr)//右孩子不为空
queue->_tail->_next = queue->_head->_next->_next = nr;
else
queue->_tail->_next = nl;
} else if (nr)//左孩子为空,右孩子不为空
queue->_tail->_next = queue->_head->_next = nr;
else //说明这是队列的最后一个元素了
queue->_head->_next = queue->_tail->_next = NULL;
} else {//当前队列中元素大于一个
queue->_head->_next = first->_next;
if (nl) {//左孩子不为空
queue->_tail->_next->_next = nl;
if (nr)//右孩子不为空
queue->_tail->_next = queue->_tail->_next->_next->_next = nr;
else
queue->_tail->_next = nl;
} else if (nr)//左孩子为空,右孩子不为空
queue->_tail->_next = queue->_tail->_next->_next = nr;
}
}
return first;
}
/**
* 二叉树的按层遍历
* @param root 二叉树根节点的指针
* @param head 队列的头指针
* @param tail 队列的位置针
*/
void layerTravel(bt const * const root, ln *const head, ln *const tail) {
mQueue queue = {head, tail, removeFirstAndAddItsChilds};
ln *n = makeNode(root);
n->_node = root;
n->_next = NULL;
head->_next = n;
tail->_next = n;
while (queue._head->_next) {//当队列的头指针指向空时说明已经没有元素了
ln *result = queue.removeFirstAndAddItsChilds(&queue);
int i;
int len = result->_node->_count;
for (i = 0; i < len; ++i)
printf("%d ", result->_node->_val);
free(result);//释放系统资源
}
}
int main(void) {
int arr[] = {8, 4, 12, 2, 6, 10, 14, 1, 3, 5, 7, 9, 11, 13, 15};
int len = sizeof(arr) / sizeof(int);
bt *tree = buildTree(arr, len);
printf("middle sequence travel result :\n");
travelMidSeq(tree);
printf("\nlayer sequence travel result:\n");
ln head = {NULL, NULL};
ln tail = {NULL, NULL};
layerTravel(tree, &head, &tail);
releaseTree(tree);
return 0;
}

附上测试结果:

1
2
3
4
middle sequence travel result :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
layer sequence travel result:
8 4 12 2 6 10 14 1 3 5 7 9 11 13 15


2016-09-15
— Maizi