二叉树与二叉查找树

来源:互联网 发布:java获取系统当前时间 编辑:程序博客网 时间:2024/06/07 12:28

一、树的相关术语

  • 树是一种非线性的数据结构,以分层的形式存储数据
  • 树由一组以边连接的节点组成,如下:

这里写图片描述

  • 树的层数被定义为树的深度

二、二叉树

  • 二叉树是一种特殊的树,规定每个节点的子节点不能超过两个
  • 通过将子节点的个数设置为2,可以高效地在树中插入、删除、查找数据
  • 二叉查找树是一种特殊的二叉树,相对较小的值保存在左节点上,较大的值保存在右节点上,这一特性使得查找的效率很高

这里写图片描述
三、二叉查找树的实现

1、 二叉查找树由节点组成,或者说树都是由节点组成,因此,我们要定义的第一个对象就是Node:

function Node(data){    this.data = data;   //存储键值    this.left = left;   //指向左孩子的指针    this.right = right; //指向右孩子的指针    this.show = show;   //显示保存在节点中的数据}function show(){    return this.data;}

2、创建一个类,用来表示二叉查找树(BST)。类中只包含一个数据成员:root(一个用来表示二叉查找树的根节点的Node对象),初始化为null,从而创建一个空节点。

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

3、设计一个insert()方法,用来向树中加入新节点

  • 创建一个Node对象,将数据传入该对象中保存
  • 检查BST是否有根节点,如果没有,是一颗新树,该节点为树的根节点
  • 如果该元素不是树的根节点,则要遍历BST,找到适合插入节点的位置,实现算法:
    • 设根节点为当前节点
    • 如果待插入节点中保存的数据小于当前节点,则设新的当前节点为原节点的左节点,否则,执行第四步
    • 如果当前节点为null,则插入节点,否则,继续循环第二步
    • 如果待插入节点中保存的数据大于当前节点,则设新的当前节点为原节点的右节点
    • 如果当前节点为null,则插入节点,否则,继续循环第四步
function BST() {    this.root = null;    this.insert = insert;}function insert(data) {    var node = new Node(data,null,null);    if(this.root == null) {        this.root = node;    } else {        var currentNode = this.root;        var parent;        while(true) {            parent = currentNode;            if(data < currentNode.data) {                currentNode = currentNode.left;                if(currentNode == null) {                    parent.left = node;                    break;                }            } else {                currentNode = currentNode.right;                if(currentNode == null) {                    parent.left = node;                    break;                }            }        }    }}

4、二叉查找树的遍历

  • 遍历有三种方式
    (1)中序遍历:按照节点上的键值,以升序访问BST上的所有节点

这里写图片描述

function inOrder(node){    if( node != null){        inOrder(node.left);        console.log(node.show()+' ');        inOrder(node.right)    }}

(2) 先序遍历:先访问根节点,然后以同样的方式访问左子树和右子树
这里写图片描述

function preOrder(node){    if(node != null){        console.log(node.show());        preOrder(node.left);        preOrder(node.right)    }}

(3) 后序遍历:先访问叶子节点,从左子树到右子树再到根节点
这里写图片描述

function postOrder(node){    if(node != null){        postOrder(node.left);        postOrder(node.right);        console.log(node.show());    }}
  • 测试程序
var nums = new BST();nums.insert(23);nums.insert(45);nums.insert(16);nums.insert(37);nums.insert(3);nums.insert(99);nums.insert(22);console.log("inOrder:")inOrder(nums.root); //3 16  22  23  37  45  99console.log("preOrder")preOrder(nums.root); //23 16  3  22  45  37  99console.log("postOrder")postOrder(nums.root); //3  22  16  37  99  45  23

四、在二叉查找树上进行查找
1、查找最小值和最大值

  • 查找最小值:因为较小的值总是在左节点上,因此,在BST上要找到最小值,只需要遍历左子树,直到最后一个节点
function getMin(){    var node = this.root;    var parent;    while(node != null){        parent = node;        node = node.left;    }    return parent.data;}
  • 查找最大值:因为较大的值总是在右节点上,因此,在BST上要找到最大值,只需要遍历右子树,直到最后一个节点
function getMax(){    var node = this.root;    var parent;    while(node != null){        parent = node;        node = node.right;    }    return parent.data;}
  • 使用上面的测试数据进行测试
console.log(nums.getMax());     //99console.log(nums.getMin());     //3

2、查找给定值

  • 在BST上要查找给定值,需要比较该值和当前节点上的值的大小。
  • 通过比较,确定给定值不在当前节点时,该向左还是向右遍历。
function find(data){    var node = this.root;    while(node != null){        if(node.data == data){            return node;        }else if(node.data > data){            node = node.left;        }else{            node = node.right;        }    }    return null;}
  • 找到返回保存该值的节点,没有找到返回null
  • 继续使用上面的测试数据进行测试
console.log(nums.find("23"));console.log(nums.find("100"));

这里写图片描述

五、在二叉查找树上删除节点

  • 判断当前节点是否包含待删除的数据,如果包含,删除该节点
  • 如果不包含,比较当前节点的数据和待删除的数据,如果待删除数据小于当前节点,则移至当前节点的左子节点继续比较;如果待删除数据大于当前节点,则移至当前节点的右子节点继续比较;
  • 删除之后要保证仍然是个二叉树
    • 如果待删除节点是叶子节点,则将从父节点指向它的链接指向null
    • 如果待删除节点只包含一个子节点,则从父节点指向它的链接指向它的子节点
    • 如果待删除数据有两个子节点
      • 查找待删除节点左子树上的最大值
      • 查找待删除节点右子树上的最小值
        eg - 给出如下二叉查找树:
        这里写图片描述
        • 删除节点3之后,你可以返回:
          这里写图片描述
        • 或者:
          这里写图片描述
function removeNode(node) {    var root =  remove(this.root,node);    return root;}function remove(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 = getMin(node.right);        node.data = tempNode;        node.right = remove(node.right,tempNode);        return node;    }else if(data < node.data){        node.left = remove(node.left,data);        return node;    }else{        node.right = remove(node.right,data);        return node;    }}
原创粉丝点击