0.简介
二叉树的遍历可以分为先序、中序、后序和按层遍历。前三者可以用递归的方式实现,也可以借助栈非递归地遍历。按曾遍历则是借助队列来实现。递归版非常简单,这里只介绍非递归版,该方式均在循环中完成。
先序遍历:(+-8/625)如果当前节点不为空,输出当前节点的值。如果其左节点不为空,则将当前节点入栈,再移动到其左节点;如果左节点为空,从栈中取出一个节点作为当前节点(栈空则结束循环),再移动到其右节点。
中序遍历:(8-6/2+5)当前节点的左节点非空,则当前节点入栈,否则输出当前节点的值(左节点为空,当前节点就是中间节点)。然后判断栈是否为空,是则退出循环,否则取出一个节点作为当前节点,输出其值(栈中的节点的左节点已经被访问,因此都是中间节点),再移动到其右节点。
后续遍历:(862/-5+)该方式需要借助标记左、右节点是否存在或被访问,因此需要借助额外变量辅助。当前节点的左节点存在且未被访问,则将当前节点的左节点标记为被访问,将当前节点和其状态入栈,并移动到左节点;如果左节点为空,但右节点存在且未被访问,则将当前节点的右节点标记为被访问,将当前节点和其状态入栈,并移动到右节点;如果左右节点为空或是被访问,则输出当前节点的值,此时栈为空则结束循环,否则取出一个节点未当前节点。
按层遍历:(+-58/62)
二叉树的结构
//结构
struct Node {
char val;
struct Node* rnext;
struct Node* lnext;
Node() {
val = NULL;
rnext = NULL;
lnext = NULL;
}
};
//状态
struct NodeState {
Node* p;
int state; //0 未访问 1 访问左节点 2 访问右节点
};
1.先序遍历
void preorderTraversal(Node* head) {
if (head != NULL) {
cout << head->val;
preorderTraversal(head->lnext);
preorderTraversal(head->rnext);
}
}
//先序遍历
void preorderTraversal(Node* head) {
stack<Node*> stk;
Node* p = head;
while (p != NULL) {
//先输出节点的值,如果左节点不为空,移动到左节点;
//如果左节点为空且栈不为空,从栈中取出一个节点,移动到该节点的右节点;
//如果栈为空结束循环。
cout << p->val;
if (p->lnext != NULL) {
stk.push(p);
p = p->lnext;
}
else if (!stk.empty()) {
p = stk.top();
stk.pop();
p=p->rnext;
}
else break;
}
}
2.中序遍历
void inorderTraversal(Node* head) {
if (head != NULL) {
inorderTraversal(head->lnext);
cout << head->val;
inorderTraversal(head->rnext);
}
}
//中序遍历
void inorderTraversal(Node* head) {
stack<Node*> stk;
Node* p = head;
while (p != NULL) {
if (p->lnext != NULL) {
stk.push(p);
p=p->lnext;
}
else {
//遍历左节点,左节点为空,输出当前节点的值;
//从栈中取出一个节点,先输出该节点的值,如果该节点的右节点不为空,移动到右节点;
//如果栈为空,结束循环。
cout << p->val;
if (!stk.empty()) {
p = stk.top();
stk.pop();
cout << p->val;
p = p->rnext;
}
else break;
}
}
}
3.后序遍历
void postorderTraversal(Node* head) {
if (head != NULL) {
postorderTraversal(head->lnext);
postorderTraversal(head->rnext);
cout << head->val;
}
}
//后序遍历
void postorderTraversal(Node* head) {
stack<NodeState> stk;
NodeState ns = { head,0 };
while (ns.p != NULL) {
if (ns.p->lnext != NULL && ns.state <1) {//节点未访问
stk.push({ns.p,1});
ns = { ns.p->lnext ,0 };
}
else if (ns.p->rnext != NULL && ns.state <2) {//节点未访问或只访问了左节点
stk.push({ ns.p,2 });
ns = { ns.p->rnext ,0 };
}
else {
//如果左节点未访问,标记左节点被访问,当前节点入栈,移动到左节点;
//如果左节点为空,从栈中取出节点作为当前节点(栈为空结束循环);
//标记右节点被访问,当前节点入栈,移动到其右节点;
//如果左、右节点皆为空或被访问,输出该节点。
cout << ns.p->val;
if (!stk.empty()) {
ns = stk.top();
stk.pop();
}
else break;
}
}
}
4.按层遍历
//按层遍历
void layerTraversal(Node* head) {
queue<Node*> que;
que.push(head);
while (!que.empty()) {
Node* p = que.front();
que.pop();
cout << p->val;
if (p->lnext != NULL) que.push(p->lnext);
if (p->rnext != NULL) que.push(p->rnext);
}
}