二叉树的遍历(前中后,层次)——legend
2014-08-19 14:26
232 查看
二叉树的遍历:traverse
(1)深度优先遍历 :(递归与非递归)
(1.1)先序 (先根):preOrder(WithRecusion/WithoutRecusion)
(1.2)中序 (中根):inOrder(WithRecusion/WithoutRecusion)
(1.3)后序 (后根):postOrder(WithRecusion/WithoutRecusion)
(注意:非递归的深度优先遍历中:栈中的字段有top,以及节点指针数组BTNode* array[Maxsize] )
----
(2)广度优先遍历 :
(2.1)层次遍历 :leverOrder
(注意:层次遍历中队列中的字段有 front ,rear 以及 节点指针数组 BTNode* array[Maxsize] )
1.如果在队列中加入一个字段 int levelArray[Maxsize]可以记录下每个节点的层次。
2.如果在队列中的的数组的每个元素为typedef struct Element { BTNode * pnode ,int parentIndex};(parentIndex表示当前节点pnode的父节点所在的下标)
然后队列为{ front ,rear, Element array[Maxsize] },则可以根据由某个节点快速的查找到父节点,对于查找路径方便。
-----
(3)祖先节点与 到根节点的路径:
---------------------------------
(一)先序:先访根节点,再访问左子树,再访问右子树。
(1)递归:
void PreOrder(BTNode* b){
if(b!=NULL){
visit(b->data);
PreOrder(b->lchild);
PreOrder(b->rchild);
}
}
(2)非递归:
思想:先根,然后左子树,然后右子树。
所以:先将根节点进栈,在栈非空时循环:出栈p,访问p,将其右孩子节点进栈,再左孩子节点接栈。
void preOrder(BTNode *b){
BTNode* stack[Maxsize];
BTNode * p;
int top=-1;
if(b!=NULL){
top++;
stack[top]=b;//根节点进栈
while(top>-1){
//栈非空
p=stack[top];
top--;//出栈
visit(p->data);//访问
if(p->rchild!=NULL){
//右孩子非空,则进栈
top++;
stack[top]=p->rchild;
}
//必须先判断右子树,然后再判断左子树,右孩子先进栈。
if(p->lchild!=NULL){
//左孩子非空,则进栈
top++;
stack[top]=p->lchild;
}
}
}
}
注意:非递归的先序遍历中,必须是先是右孩子进栈,然后孩子进栈,顺序不可以颠倒,否则就是根右左。
-----------
(二)中序:先左子树,然后跟节点,然后右子树。
(1)递归:
void inOrder(BTNode * b){
if(b!=NULL){
inOrder(b->lchild);
visit(b->data);
inOrder(b->rchild);
}
}
(2)非递归:
思想:
1)先扫描根节点的所有左节点并将它们一一压栈,
2)然后出栈一个节点p,当前新出栈的节点p必然没有左孩子或者左孩子以及被访问过,然后访问节点p,
3)然后扫描节点p的右孩子,然后将p的右孩子的所有左孩子一一压栈,与1)重复,直至栈空。
void inOrder(BTNode * b){
BTNode* stack[Maxsize];
BTNode* p;
int top=-1;
if(b!=NULL){
p=b;
while(p!=NULL || top>-1){
while(p){
//根节点p的左孩子不断进栈
top++;
stack[top]=p;
p=p->lchild;
}
if(top>-1){
//栈非空时
p=stack[top];
top--;//出栈
visit(p->data);//访问
p=p->rchild;//p的右子树作为新的p,让p的右子树的左孩子逐个进栈
}
}
}
}
-----------
(三)后续:先左子树,然后右子树,然后根节点。
(1)递归:
void postOrder(BTNode *b){
if(b){
postOrder(b->lchild);
postOrder(b->rchild);
visit(b->data);
}
}
(2)非递归:
思想:
1)先扫描一个根节点的所有的左孩子并一一进栈
2)出栈一个节点p,然后扫描节点p的右孩子并进栈,在扫描p的右孩子的所有左孩子并一一进栈。即将p的右孩子作为1)中的跟节点,重复1)
3)当一个节点的左右孩子均访问过,才访问该节点。直至栈空。
难点:如何判断节点p的右孩子已经访问过了,用q保存右子树中刚刚访问过的节点(初值为null),若p->rchild=q,说明p节点的左右子树都已经访问过了,然后就可以访问p了。如果不成立,说明p的右子树没有访问完。
void postOrder(BTNode *b){
BTNode* stack[Maxsize];
BTNode* p=b,*pre;
int flag,top=-1;
if(b){
do{
while(p){//节点p的所有左孩子进栈
top++;
stack[top]=p;
p=p->lchild;
}
pre=NULL;//pre指向栈顶节点前一个已经访问过的节点。
flag=1;
while(top!=-1 && flag==1){
p=stack[top];//取栈顶,但不出栈
if(p->rchild==pre){
top--;//出栈
visit(p->data);//访问
pre=p;//更新已经访问过的 节点。
}
else{
//否则将p节点的右孩子的所有左孩子进栈。
p=p->rchild;
flag=0;//跳出当前循环
}
}
}while(top!=-1);
}
}
---------------
(四)层次遍历:levelOrder
#include "queue.h"
void levelOrder(BTNode * T){
BTNode * p;
Queue Q;
initQueue(Q);
enQueue(Q,T);
while(!isEmpty(Q)){
deQueue(Q,p);
visit(p->data);
if(p->lchild) enQueue(Q,p->lchild);
if(p->rchild) enQueue(Q,p->rchild);
}
}
或者:
void levelOrder(BTNode* b){
BTNode* queue[Maxsize];
int front=rear=-1;
BTNode* pnode;
rear++;
queue[rear]=b;//进队
while(rear!=front){//队列非空
front=(front+1)%Maxsize;
pnode=queue[front];//出队
visit(pnode->data);//访问
if(pnode->lchild) {
rear++;
queue[rear]=pnode->lchild;//左孩子进队
}
if(pnode->rchild) {
rear++;
queue[rear]=pnode->rchild;//右孩子进队
}
}
}
---------
(5)补充:路径与祖先节点。
1.某个节点的祖先节点 即 从该节点到根节点的路径;
2. 非递归的后序遍历中,栈中栈顶节点的下面的节点为栈顶节点的祖先节点,,即 将栈 中各个元素出栈可以得到栈顶节点到根结点的路径。
二叉树的遍历:traverse
(1)深度优先遍历 :(递归与非递归)
(1.1)先序 (先根):preOrder(WithRecusion/WithoutRecusion)
(1.2)中序 (中根):inOrder(WithRecusion/WithoutRecusion)
(1.3)后序 (后根):postOrder(WithRecusion/WithoutRecusion)
(注意:非递归的深度优先遍历中:栈中的字段有top,以及节点指针数组BTNode* array[Maxsize] )
----
(2)广度优先遍历 :
(2.1)层次遍历 :leverOrder
(注意:层次遍历中队列中的字段有 front ,rear 以及 节点指针数组 BTNode* array[Maxsize] )
1.如果在队列中加入一个字段 int levelArray[Maxsize]可以记录下每个节点的层次。
2.如果在队列中的的数组的每个元素为typedef struct Element { BTNode * pnode ,int parentIndex};(parentIndex表示当前节点pnode的父节点所在的下标)
然后队列为{ front ,rear, Element array[Maxsize] },则可以根据由某个节点快速的查找到父节点,对于查找路径方便。
-----
(3)祖先节点与 到根节点的路径:
---------------------------------
(一)先序:先访根节点,再访问左子树,再访问右子树。
(1)递归:
void PreOrder(BTNode* b){
if(b!=NULL){
visit(b->data);
PreOrder(b->lchild);
PreOrder(b->rchild);
}
}
(2)非递归:
思想:先根,然后左子树,然后右子树。
所以:先将根节点进栈,在栈非空时循环:出栈p,访问p,将其右孩子节点进栈,再左孩子节点接栈。
void preOrder(BTNode *b){
BTNode* stack[Maxsize];
BTNode * p;
int top=-1;
if(b!=NULL){
top++;
stack[top]=b;//根节点进栈
while(top>-1){
//栈非空
p=stack[top];
top--;//出栈
visit(p->data);//访问
if(p->rchild!=NULL){
//右孩子非空,则进栈
top++;
stack[top]=p->rchild;
}
//必须先判断右子树,然后再判断左子树,右孩子先进栈。
if(p->lchild!=NULL){
//左孩子非空,则进栈
top++;
stack[top]=p->lchild;
}
}
}
}
注意:非递归的先序遍历中,必须是先是右孩子进栈,然后孩子进栈,顺序不可以颠倒,否则就是根右左。
-----------
(二)中序:先左子树,然后跟节点,然后右子树。
(1)递归:
void inOrder(BTNode * b){
if(b!=NULL){
inOrder(b->lchild);
visit(b->data);
inOrder(b->rchild);
}
}
(2)非递归:
思想:
1)先扫描根节点的所有左节点并将它们一一压栈,
2)然后出栈一个节点p,当前新出栈的节点p必然没有左孩子或者左孩子以及被访问过,然后访问节点p,
3)然后扫描节点p的右孩子,然后将p的右孩子的所有左孩子一一压栈,与1)重复,直至栈空。
void inOrder(BTNode * b){
BTNode* stack[Maxsize];
BTNode* p;
int top=-1;
if(b!=NULL){
p=b;
while(p!=NULL || top>-1){
while(p){
//根节点p的左孩子不断进栈
top++;
stack[top]=p;
p=p->lchild;
}
if(top>-1){
//栈非空时
p=stack[top];
top--;//出栈
visit(p->data);//访问
p=p->rchild;//p的右子树作为新的p,让p的右子树的左孩子逐个进栈
}
}
}
}
-----------
(三)后续:先左子树,然后右子树,然后根节点。
(1)递归:
void postOrder(BTNode *b){
if(b){
postOrder(b->lchild);
postOrder(b->rchild);
visit(b->data);
}
}
(2)非递归:
思想:
1)先扫描一个根节点的所有的左孩子并一一进栈
2)出栈一个节点p,然后扫描节点p的右孩子并进栈,在扫描p的右孩子的所有左孩子并一一进栈。即将p的右孩子作为1)中的跟节点,重复1)
3)当一个节点的左右孩子均访问过,才访问该节点。直至栈空。
难点:如何判断节点p的右孩子已经访问过了,用q保存右子树中刚刚访问过的节点(初值为null),若p->rchild=q,说明p节点的左右子树都已经访问过了,然后就可以访问p了。如果不成立,说明p的右子树没有访问完。
void postOrder(BTNode *b){
BTNode* stack[Maxsize];
BTNode* p=b,*pre;
int flag,top=-1;
if(b){
do{
while(p){//节点p的所有左孩子进栈
top++;
stack[top]=p;
p=p->lchild;
}
pre=NULL;//pre指向栈顶节点前一个已经访问过的节点。
flag=1;
while(top!=-1 && flag==1){
p=stack[top];//取栈顶,但不出栈
if(p->rchild==pre){
top--;//出栈
visit(p->data);//访问
pre=p;//更新已经访问过的 节点。
}
else{
//否则将p节点的右孩子的所有左孩子进栈。
p=p->rchild;
flag=0;//跳出当前循环
}
}
}while(top!=-1);
}
}
---------------
(四)层次遍历:levelOrder
#include "queue.h"
void levelOrder(BTNode * T){
BTNode * p;
Queue Q;
initQueue(Q);
enQueue(Q,T);
while(!isEmpty(Q)){
deQueue(Q,p);
visit(p->data);
if(p->lchild) enQueue(Q,p->lchild);
if(p->rchild) enQueue(Q,p->rchild);
}
}
或者:
void levelOrder(BTNode* b){
BTNode* queue[Maxsize];
int front=rear=-1;
BTNode* pnode;
rear++;
queue[rear]=b;//进队
while(rear!=front){//队列非空
front=(front+1)%Maxsize;
pnode=queue[front];//出队
visit(pnode->data);//访问
if(pnode->lchild) {
rear++;
queue[rear]=pnode->lchild;//左孩子进队
}
if(pnode->rchild) {
rear++;
queue[rear]=pnode->rchild;//右孩子进队
}
}
}
---------
(5)补充:路径与祖先节点。
1.某个节点的祖先节点 即 从该节点到根节点的路径;
2. 非递归的后序遍历中,栈中栈顶节点的下面的节点为栈顶节点的祖先节点,,即 将栈 中各个元素出栈可以得到栈顶节点到根结点的路径。
相关文章推荐
- 二叉树的简单操作(前中后序遍历,层次遍历,树高,叶子数,交换二叉树等)
- 数据结构 学习笔记(四):树(上):树的表示,二分查找,二叉树,先中后层次遍历
- 二叉链树的创建结点,递归构造二叉树、非递归构造二叉树、递归进行前、中、后遍历,非递归进行前中后遍历、层次遍历
- 二叉树的建立&&前中后遍历(递归实现)&&层次遍历
- 二叉树的前中后层次遍历(递归+非递归)、创建树(数组、前序+中序、中序加后序)
- java实现二叉树的建立,前中后序遍历,层次遍历,深度,节点个数等
- 二叉树前中后序遍历的递归版本和非递归版本、队列实现的层次遍历
- 天梯赛 树的遍历 玩转二叉树 (前中求后 中后求前 层次遍历 镜面反转)
- 数据结构--二叉树--层次遍历二叉树(顺序遍历)
- UVA 122 Trees on the level (二叉树层次遍历)
- 二叉树的 前中后遍历
- C++数据结构--按层次遍历二叉树
- java 实现二叉树的构建,先序,中序,后序,层次,递归,非递归的遍历
- LintCode 二叉树的层次遍历
- 二叉树的层次遍历方法
- 树之二叉树的建立与四种遍历(前序,中序, 后序, 层次)及树的深度
- 算法实验-二叉树的创建和前序-中序-后序-层次 遍历
- LeetCode: 102_Binary Tree Level Order Traversal | 二叉树自顶向下的层次遍历 | Easy
- 二叉树之层次遍历(js)
- 102. Binary Tree Level Order Traversal (二叉树层次遍历)