二叉树和二叉查找树

以前学过二叉树,是用c语言实现的,当时虽然听懂了,但是自己用c语言实现,还是有点困难的,现在学习了前端,发现二叉树还是很简单的。今天就来说一说。

二叉树是一种常用的数据结构,树也是一种非线性的数据结构,以分层的方式存储数据,树被用来存储具有层级关系的数据,比如系统中的文件,还有前端经常说到的dom树。现在我们研究的是一种特殊的树。

下面我们看看用js怎么实现二叉树,首先需要一个节点

function Node (data, left, right) {
    this.data = data;
    this.left = left;
    this.right = right;
    this.show = show;
}

这里的show是用来显示保存在节点里面的数据

function show () {
 return this.data;
}

有了节点之后,我们需要有一颗二叉查找树BST(Binary Search Tree)

function BST () {
    this.root = null;
    this.insert = insert;
    this.inOrder = inorder;
}

insert是插入数据的方法

/*插入数据的算法是
我们先新建一个节点,把当前的数据放到这个节点中去
我们先判读当前的树是否为空,如果为空,就把该节点作为根节点
如果不为空,就需要遍历BST了,找到要插入的位置,用一个变量存储当前的节点,一层层的进行遍历
进入BST后,我们要决定将节点放置到哪个位置,找到正确的插入点,就后跳出循环
算法如下
(1)设根节点为当前节点
(2)如果待插入节点保存的数据小于当前节点,就设新的当前节点为原节点的左节点,否则,执行第四步
(3)如果当前节点的左节点为null,就将新的节点插入这个位置,退出循环,反之继续执行下一次循环
(4)设新的节点为原节点的右节点
(5)如果当前节点的右节点为null,就将新的节点插入到这个位置,退出循环,反之,进行下一次循环
*/
function insert(data) {
    var n = new Node(data, null, null);
    if (this.root = null) {
        this.root = n;
    }else {
        var current = this.root;
        var parent;
        while(true) {
         parent = current;
         if (data < current.data) {
             currnet = current.left;
             if (current == null) {
                 parent.left = n;
                 break;
             }
        } else {
            current = current.right;
            if (current == null) {
                parent.right = n;
                break;
            }
        }
    }
}

现在二叉树初步成型,我们需要有能力遍历BST,这样就可以按照不同的顺序,比如按照数字的大小先后,显示节点上的数据

有三种遍历BST的方式,中序、先序和后序。中序遍历按照节点上的键值,以升序访问BST上的所有节点。
先序遍历先访问根节点,然后以同样的方式访问左子树和右子树,
后序遍历先访问叶子节点,从左子树到右子树,再到根节点。

中序遍历使用递归的方式最容易实现
这里的inOrder是中序遍历的意思。
先访问左子树,再访问根节点,最后访问右子树,倘若不理解递归,就先看一个例子,

function factorial(number) {
    if (number == 1) {
        return number;
    } else {
        return number * factorial(number - 1);
    }
}
print(factorial(5));

画一幅图进行理解

5*factorial(4)
5*4*factorial(3)
5*4*3*factorial(2)
5*4*3*2*1
5*4*3*2
5*4*6
5*24
120

看了这个过程就很好理解了。

那中序遍历的代码如下

function inOrder(node) {
    if (!(node == null)) {
        inOrder(node.left);
        putStr(node.show()+"");
        inOrder(node.right);
    }
}

先序遍历定义如下

function preOrder (node) {
    if(!(node == null)) {
        putstr(node.show()+"");
        preOrder(node.left);
        preOrder(node.right);
    }
}

后序遍历

function postOrder(node) {
    if (!(node == null)) {
        postOrder(node.left);
        postOrder(node.right);
        putstr(node.show()+"");
    }
}

对BST通常有三种类型的查找

(1)查找给定值
(2)查找最小值
(3)查找最大值
查找最大值和 最小值非常简单,因为较小的值总是在左子节点上,在BST上查找最小值,只需要遍历左子树,直到找到最后一个节点
getMin()方法查找BST上的最小值,

function getMin() {
    var current = this.root;
    while(!(current.left == null) {
        current = current.left;
    }
    return  current.data;
}
function getMax() {
    var current = this.root;
    while(!(current.right == null){
        current = current.right;
    }
    return current.data;
}

查找给定值

function find(data) {
    var current = this.root;
    while(current != null) {
        if (current.data == data) {
           return current;
        }
        else if (data < current.data) {
            current = current.left;
        }
        else {
            current = current.right;
        }
    }
    return null;
}

从二叉查找树上删除节点

从BST中删除节点的第一步是判断当前节点是否包含待删除数据,如果包含,则删除该结点,如果不包含,则比较当前节点上的数据和待删除的数据。如果待删除的数据小于当前节点的数据,则移至当前节点的左子节点进行比较,如果删除的数据大于当前节点上的数据,则移至当前节点的右子节点继续比较。
如果待删除节点是叶子节点,那么只需要将从父节点指向他的链接指向null,
如果待删除节点只包含一个子节点,那么原本指向他的节点就得做些调整,使其执行他的子节点。

如果待删除节点包含两个子节点,正确的做法有两种:要么查找待删除节点左子树上的最大值,要么查找其右子树上的最小值。这里我们选择后一种方式。

我们需要一个查找子树最小值的方法,后面会用他找到的最小值创建一个临时节点,将临时节点上的值赋值到待删除节点,然后在删除临时节点。

function remove (data) {
    root = removeNode(this.root, data);
}
function removeNode(node, data) {
    if (node == null) {
        return null;
    }
    if (data == node.data) {
        //没有子节点的节点
        if(node.left == null && node.right == null) {
            return null;
        }
        //没有左子节点的节点
        if (node.left == null) {
            return node.right;
        }
        //没有右子节点的节点
        if (node.right == null) {
            return node.left;
        }
        //有两个子节点的节点
        var tempNode = getSmallest(node.right);
        node.data = tempNode.data;
        node.right = removeNode(node.right, tempNode.data);
        return node;
    }
    else if(data < node.data) {
        node.left = removeNode(node.left, data);
        return node;
    }
    else {
        node.right = removeNode(node.right, data);
        return node;
    }
    else {
        node.right = removeNode(node.right, data);
        return node;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值