二叉树遍历
二叉树遍历
递归遍历
前序
void preOrder(BTree root){
if(root == NULL)
return ;
visit(root);
preOrder(root->left);
preOrder(root->right);
}
后序
void postOrder(BTree root){
if(root == NULL){
return ;
}
postOrder(root->left);
postOrder(root->right);
visit(root);
}
中序
void inOrder(BTree root){
if(root == NULL)
return ;
inOrder(root->left);
visit(root);
inOrder(root->right);
}
非递归遍历
前序
借助栈来实现,注意左右孩子的入栈顺序
先右孩子,再左孩子,这样出栈的时候就是先左再右
void preOrder(BTree root){
BTree stack[MaxSize];
int top = -1;
BTree p = NULL;
if(root) //根节点不为空 将其入栈
stack[++top] = root;
while(top != -1){
p = stack[top--]; //弹出栈顶节点并访问
visit(p);
if(p->right) //先右孩子
stack[++top] = p->right;
if(p->left) //再左孩子
stack[++top] = p->left;
}
}
后序
版本一
在非递归先序遍历的基础上实现
先序:根左右
后序:左右根
逆后序:根右左
可以得知,逆后序和先序遍历序列仅仅是左右顺序不同
而在先序遍历算法中,左右的顺序取决于将左右孩子入栈的顺序,因此调换先序遍历算法中左右孩子入栈顺序,即先左孩子入栈,再右孩子入栈即可得逆后序遍历序列,再将逆后序遍历序列反转即可得后序。
void postOrder(BTree root){
BTree s1[MaxSize]; //栈1用来得逆后序
int top1 = -1;
BTree s2[MaxSize]; //栈2用来反转逆后序
int top2 = -1;
BTree p = NULL;
if(root)
s1[++top1] = root;
while(top1 != -1){
p = s1[top1--];
s2[++top2] = p;
if(p->left){
s1[++top1] = p->left;
}
if(p->right){
s1[++top1] = p->right;
}
}//遍历完成s2中存放即为后序遍历序列
while(top2 != -1){
visit(s2[top2--]);
}
}
版本二
借助栈和尾指针模拟后序遍历流程,先左再根再右
-
从根节点开始,沿左孩子依次入栈,直到左孩子为空
-
取栈顶节点p
-
根据p右孩子的情况进行处理
-
p没有右孩子
弹出并访问p
-
p有右孩子
-
右孩子已被访问过
弹出并访问p
-
右孩子未被访问过
转去右孩子执行
-
-
void postOrder(BTree root){
BTree stack[MaxSize];
int top = -1;
BTree p = root; //当前指针p 初始为根节点
BTree r = NULL; //尾指针r 初始为空
while(p || top != -1){
if(p){
stack[++top] = p;
p = p->left;
}
else{
p = stack[top]; //读栈顶节点p
if(p->right && r->right != r){ //判断是否要转去右孩子执行
p = p->right;
}
else{
visit(p); //此时栈中记录的即为从根结点到p的路径
top--; //弹出栈顶节点并访问
r = p; //r记录上一次访问过的节点
p = NULL; //每次访问完p都要置空
}
}
}
}
后序遍历版本二算法可以应用在求从根节点到树中某个节点的路径
当访问到某个节点时,当前栈中存放的节点即为从根节点到该节点的路径
中序
生疏,重点理解记忆
void inOrder(BTree root){
BTree stack[MaxSize];
int top = -1;
BTree p = root;
while(p || top != -1){
if(p){ //这段逻辑和后序相同,一直往左走
stack[++top] = p;
p = p->left;
}
else{ //左边走到头不需要再判断右孩子,直接访问然后转去右子树即可
visit(stack[top]);
p = stack[top]->right;
top--;
}
}
}
层序
void levelOrder(BTree root){
BTree que[MaxSize];
int front = 0, rear = 0;
BTree p = NULL;
if(root){
que[rear++] = root;
}
while(front != rear){
p = que[front++];
visit(p);
if(p->left){
que[rear++] = p->left;
}
if(p->right){
que[rear++] = p->right;
}
}
}
在此框架的基础上,相关的应用有:求二叉树的层数、求每一层节点数、求每一层节点关键字平均值......
以上应用需要在遍历的过程中区分二叉树的层次
思路:增设一个指向当前层最后一个节点的指针q,当遍历到q时就进行相关分层处理。
如何维护指针q?
初始q=root,每遍历一个节点p时,判断并将p的左右节点入队之后,检查p是否等于q,若p=q,则当前队列尾节点即为下一层最后一个节点,更新q=que[rear-1],即当访问到当前层最后一个节点时,将q指向下一层最后一个节点。
void levelOrder(BTree root){
BTree que[MaxSize];
int front = 0, rear = 0;
BTree p = NULL, q = root; //q指向当前层最后一个节点,初始为root
if(root){
que[rear++] = root;
}
int level = 0; //当前层数
int cnt = 0; //当前层内节点数
while(front != rear){
p = que[front++];
visit(p);
if(p->left){
que[rear++] = p->left;
}
if(p->right){
que[rear++] = p->right;
}
//分层操作
if(p == q){
q = que[rear - 1]; //更新q,指向下一层最后一个节点,即此时的队尾节点
//其他需要的操作...
level++;
cnt = 0;
}
}
}