二叉树的遍历

一、先序遍历

1.1 步骤

  1. 访问根节点
  2. 先序遍历左子树
  3. 先序遍历右子树

1.2 递归代码

void PreOrder(BiTree T) {
    if(T != NULL) {
        visit(T);
        PreOrder(T->lchild);
        PreOrder(T->rchild);
    }
}

1.3 非递归代码

void PreOrder(BiTree T) {
    BiTree p = T; 								// p是遍历指针
    InitStack(S); 								// 初始化栈S
    while(p || !IsEmpty(S)) { 					// 栈不空或者p不空时循环
       if(p) {
       		visit(p);							// 访问指针指向的元素
       		Push(s, p);							// 将指针指向的结点压入栈中
       		p = p->lchild;						// 向左子树走,p赋值为当前节点的左孩子
       } else {
       		Pop(s, p);							// 出栈	
       		p = p->rchild;						// 向右子树走,p赋值为当前节点的右孩子
       	}
    }
}

二、中序遍历

2.1 步骤

  1. 中序遍历左子树
  2. 访问根节点
  3. 中序遍历右子树

2.2 递归代码

void InOrder(BiTree T) {
    if(T != NULL) {
    	InOrder(T->lchild);
        visit(T);
        InOrder(T->rchild);
    }
}

2.3 非递归代码

  • 沿着根的左孩子,依次入栈,直到左孩子为空
  • 栈顶元素出栈并访问,若其右孩子为空,继续执行第二步;若其右孩子不为空,将右子树转执行第一步。
void PreOrder(BiTree T) {
    BiTree p = T; 								// p是遍历指针
    InitStack(S); 								// 初始化栈S
    while(p || !IsEmpty(S)) { 					// 栈不空或者p不空时循环
       if(p) {
       		Push(s, p);							// 将指针指向的结点压入栈中
       		p = p->lchild;						// 向左子树走,p赋值为当前节点的左孩子
       } else {
       		Pop(s, p);							// 出栈	
       		visit(p);							// 访问指针指向的元素
       		p = p->rchild;						// 向右子树走,p赋值为当前节点的右孩子
       	}
    }
}

三、后序遍历

3.1 步骤

  1. 后序遍历左子树
  2. 后序遍历右子树
  3. 访问根节点

3.2 递归代码

void PostOrder(BiTree T) {
    if(T != NULL) {
    	PostOrder(T->lchild);
        PostOrder(T->rchild);
        visit(T);
    }
}

3.3 非递归代码

  • 从根节点开始,将其入栈,然后沿其左子树一直往下探索,直到搜索到没有左孩子的结点
  • 此时不能出栈并访问,因为如果其有右子树,还需按照相同的规则对其右子树进行处理
  • 当操作进行不下去,若栈顶元素想要出栈被访问,要么右子树为空,要么右子树刚被访问完(此时左子树早已访问完)
void PostOrder(BiTree T) {
    InitStack(S); 
    BiTNode *p = T;
    BiTNode *r = NULL;
    while(p || !IsEmpty(S)) {
        if(p) {
            Push(S, p);
            p = p->lchild;
        } else {
            GetTop(S, p);						//读栈顶结点(非出栈)
            if(p->rchild && p->lchild != r) { 	//若右子树存在且未被访问过
                p = p->rchild;					//转向右
            } else {							//否则,弹出结点并访问
                Pop(S, p);						//出栈
                visit(p);						//访问该节点
                r = p; 							//记录最近访问过的结点
                p = NULL; 						//结点访问完后,重置p指针
            }
        }
    }
}
  • 每次出栈访问完一个结点就相当于遍历完以该节点为根的子树,需要将 p p p置为 N U L L NULL NULL

3.4 复杂度

  • 三种遍历算法的时间复杂度均为 O ( n ) O(n) O(n)
  • 空间复杂度为 O ( n ) O(n) O(n)

四、层次遍历

4.1 步骤

  • 将二叉树根节点入队,然后出队,访问出队结点;
  • 若有左子树,则将左子树根节点入队;
  • 若有右子树,则将右子树根节点入队;
  • 完成入队后出队,访问出队结点;
  • 如此反复,直到队列为空。

4.2 代码

void LevelOrder(BiTree T) {
    InitQueue(Q);
    BiTree p;
    EnQueue(Q, T);
    while(!IsEmpty(Q)) {
        DeQueue(Q, p);
        visit(p);
        if(p->lchild != NULL) EnQueue(Q, p->lchild);
        if(p->rchild != NULL) EnQueue(Q, p->rchild);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值