JS数据结构之二叉树的遍历(递归、非递归)

二叉树的四种遍历方式:


  二叉树的遍历是指从根结点出发,按照某种次序依次访问二叉树中所有的结点,使得每个结点被访问依次且仅被访问一次。

  四种遍历方式分别为:先序遍历、中序遍历、后序遍历、层序遍历。树的遍历一般采用递归的方式更加的简介易懂,二叉树的递归遍历很好写,也很好理解。但因为是递归程序,不可避免地需要调用系统栈,耗时较长,这里我们也来探究一下二叉树的非递归遍历的算法,所以下面的介绍中会将递归算法和非递归算法一起介绍

  二叉树的可以用顺序存储方式和链式存储方法,其实顺序存储方法一般用于树中空缺结点比较少的树,如完全二叉树等,所以这里采用更具一般性的链式存储结构。
function BTNode(left, right, element) {
    this.left = left;
    this.right = right;
    this.element = element;
}

二叉树先序遍历:


  二叉树先序遍历的实现思想是:

访问根节点;

访问当前节点的左子树;

若当前节点无左子树,则访问当前节点的右子树;

递归方法:

function preOrderTraverse(BT) {
    if (BT) {
        console.log(BT.data);
        preOrderTraverse(BT.left);
        preOrderTraverse(BT.right);
    }

}

非递归方法


  非递归的方法需要采用栈,这是由于我们在先序访问一个结点时,先访问了它的根结点,然后去访问左子树,在我们访问左子树的时候我们就丢失了去访问右子树的途径,所以我们需要用一种方法去保存根结点,确保在左子树访问完需要访问右子树的时候,能通过访问根来访问右子树。而JS我们可以很方便的用数组的两个方法push和pop实现一个简易的栈结构。

1、入栈前,先输出本节点信息;

2、先左子树一次入栈,直到没有左子树的结点为止;

3、出栈栈顶元素,然后,找到右子树,继续①②操作,直到栈为空 且 结点为空。
function preOrderT(BT)//非递归先序遍历
{
    let Stack = [];
    let p = BT;
    while (p || Stack.length != 0) {
        while (p) {

            Stack.push(p);
            console.log(p.data);
            p = p.left;
        }

        if (Stack.length != 0) {
            p = Stack.pop();

            p = p.right;
        }
    }
}

二叉树中序遍历:


  二叉树中序遍历的实现思想是:

访问当前节点的左子树;

访问根节点;

访问当前节点的右子树;

递归方法:

function inOrderTraverse(BT) {
    if (BT) {
        inOrderTraverse(BT.left);
        console.log(BT.data);
        inOrderTraverse(BT.right);
    }
}

非递归方法


  类似于先序遍历,但是由于中序遍历的时候我们在第一次遇到结点时,我们要先对它的左子树进行访问,然后在对根结点进行访问,所以我们需要在出栈的时候对结点进行访问。

1、先左子树一次入栈,直到没有左子树的结点为止;

2、出栈栈顶元素,然后输出结点信息,找到右子树,继续①②操作,直到栈为空 且 结点为空。
function preOrderT(BT)//非递归先序遍历
{
    let Stack = [];
    let p = BT;
    while (p || Stack.length != 0) {
        while (p) {

            Stack.push(p);
            p = p.left;
        }

        if (Stack.length != 0) {
            p = Stack.pop();
            console.log(p.data);
            p = p.right;
        }
    }
}

二叉树后序遍历


  二叉树中序遍历的实现思想是:

访问当前节点的左子树;

访问当前节点的右子树;

访问根节点;

递归方法:

function lastOrderTraverse(BT) {
    if (BT) {
        lastOrderTraverse(BT.left);
        lastOrderTraverse(BT.right);
        console.log(BT.data);
    }
}

非递归方法


  后序遍历是二叉树三种遍历的非递归算法中最难实现的一种,因为在我们访问根结点时我们需要考虑两种情况:

1、右子树访问过了或者右子树为空,在访问根结点

2、右子树没有被访问过,先访问右子树

由于我们在访问更结点前访问的节点要不是左子树的根结点(右子树为空),要不是右子树的根结点,所以我们可以设置一个标志tag来标识上一步访问的节点,如果右子树为空,则访问根结点,如果不为空在根据tag看是否与右子树相同,来判断是否被访问过,如果被访问过,则可访问该节点,否则访问右子树。
function lastOrderT(BT)//非递归后序遍历
{
    let Stack = [];
    let p = BT;
    let tag;
    while (p || Stack.length != 0) {
        if (p) {
            Stack.push(p);
            p = p.left;
        }
        else {
            p = Stack[Stack.length - 1];
            if (p.right && tag != p.right) {
                p = p.right;
            }
            else {
                Stack.pop();
                console.log(p.data);
                tag = p;
                p = null;
            }
        }
    }
}

二叉树的层次遍历


要进行层次遍历,需要建立一个循环队列。先将二叉树头结点入队列,然后出队列,访问该结点,如果它有左子树,则将左子树的根结点入队:如果它有右子树,则将右子树的根结点入队。然后出队列,对出队结点访问,如此反复,直到队列为空为止。
function levelOrderTraverse(BT) {//层次遍历树
    let Queue = [];
    Queue.push(BT);
    let p;
    while (Queue.length != 0) {
        p = Queue.shift();
        console.log(p.data);
        if (p.left != null) {
            Queue.push(p.left);
        }
        if (p.right != null) {
            Queue.push(p.right);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值