定义

1、一棵二叉树:

  • 或者为空;
  • 或者包含三部分——一个值、一个左分支和一个右分支,并且这两个分支也都是二叉树。

2、一颗二叉搜索树是满足下面条件的二叉树:

  • 所有左分支的值都小于本节点的值;
  • 本节点的值小于所有右分支的值。

3、二叉搜索树的定义要求它的值必须能比较大小。为了强调这种区别,特称二叉搜索树的值为键,把节点存储的其他数据信息称为值。

数据组织

二叉搜索树的节点:

function Node(data,left,right) {
    //属性
    this.data = data;
    this.left = left;
    this.right = right;
    //方法
    this.show = show;
}
function show(){
    return this.data;
}

插入

算法描述:
用下述算法向一棵二叉搜索树中插入一个键k,

  • 如果树为空,创建一个叶子结点,令该节点的 key = k ;
  • 如果 k 小于根节点的 key ,将它插入到左子树中;
  • 如果 k 大于根节点的 key ,将它插入到右子树中。

算法描述函数:
insert(T,k)=node(ϕ,k,ϕ),node(insert(Tl,k),k,Tr),node(Tl,k,insert(Tr,k)),T=ϕk<k
其中,当T不为空时, Tl,Trk 分别是它的左右子树和key。函数node以给定的左子树、key和右子树为参数创建一个新节点。

实现:

function BST() { //初始化二叉搜索找树
    //属性
    this.root = null;
    //方法
    this.insert = insert;  //插入函数
    this.inorder = inorder; //中序遍历函数
}

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) {
                current = current.left;
                if (current == null) {
                    parent.left = n;
                    break;
                }
            } else {
                current = current.right;
                if (current == null) {
                    parent.right = n;
                    break;
                }
            }
        }
    }
}

遍历

1、有三种遍历 BST 的方式: 中序遍历、 前序遍历和后序遍历。
2、中序遍历的算法描述:

  • 如果树为空,则返回;
  • 否则,先中序遍历左子树,然后访问根节点,最后再中序遍历右子树。

算法描述函数:
如果二叉树非空,令 TlTrk 分别代表左右子树和key,可以定义下面的抽象map函数:
map(f,T)={ϕ,node(Tl,h,Tr),T=ϕ
其中, Tl=map(f,Tl)Tr=map(f,Tr)k=f(k)
实现:

//中序遍历
function inorder(node){
    if(node != null){
        inorder(node.left);
        console.log(node.show());
        inorder(node.right);
    }
}

//前序遍历
function perOrder(node){
    if(node != null){
        console.log(node.show());
        perOrder(node.left);
        perOrder(node.right);
    }
}

//后续遍历
function postorder(node){
    if(node != null){
        postorder(node.left);
        postorder(node.right);
        console.log(node.show());
    }
}

4、通过中序遍历得到一个排序方法:
先把一个无序列表转化为一棵二叉搜索树,然后再用中序遍历把树转换回列表。

var array = [23,45,16,37,3,99,22];
var nums = new BST();
for(var i in array){
    nums.insert(array[i]);
}
console.log("Inorder traversal: ");
inorder(nums.root); 

// Inorder traversal: 3 16 22 23 37 45 99

搜索

BST 通常有下列三种类型的查找:

  • 查找给定元素(lookup)
  • 查找最大或最小元素
  • 查找给定元素的上一个(predecessor)或下一个元素(successor)

lookup

算法描述:
我们可以按照下面描述的方法在树中查找一个key:

  • 如果树为空,查找失败
  • 如果根节点的key等于待查找的值,查找成功,返回根节点作为结果;
  • 如果待查找的值小于根节点的key,继续在左子树中递归查找;
  • 如果待查找的值大于根节点的key,继续在右子树中递归查找。

算法描述函数:
lookup(T,x)=ϕ,T,lookup(Tl,x),lookup(Tr,x),T=ϕk=xx<k

算法时间复杂度:
如果二叉树很平衡,绝大多数节点都有非空的左右分支,对于n个元素的二叉树,搜素算法的性能为 O(lgn) 。如果二叉树很不平衡,最坏情况下,查找的时间会退化到 O(n) 。若记树的高度为 h ,则算法的性能可以统一成 O(h) 的形式。

实现:

/* * findup:在BST中查找一个元素 * 如果找到给定值, 该方法返回保存该值的节点; 如果没找到, 该方法返回 null。 */
 function findup(data){ //递归实现
    var current = this.root;
     while(current!=null){
         console.log(current)
         if(current.data == data){
             return current;
         } else if(data<current.data){
             current = current.left;
         } else if(data > current.data){
             current = current.right;
         }
     }
     return null;
 }

function findup(data){ //迭代实现
     var current = this.root;
     while(current!=null && current.data!=data){
         if(data < current.data ){
             current = current.left;
         } else {
             current = current.right;
         }
     }
     return current;
 }

最小元素和最大元素

算法描述:
在BST中,较小的元素总是位于左侧分支,而较大的元素总是位于右侧分支。为了获取较小元素,可以不断向左侧前进,知道左侧分支为空。同样的,可以通过向右侧前进来获取最大元素。
算法描述函数:
min(T)={k,min(Tl),Tl=ϕ
max(T)={k,max(Tr),Tr=ϕ
算法时间复杂度:
两个函数的性能都是 O(h) ,其中 h 是树的高度。当二叉树比较平衡时, minmax 的性能都是 O(lgn) ,最坏情况下,性能退化为 O(n)
实现:

/* * getMin():取得BST最小值 */
function getMin() {
    var current = this.root;
    while (current.left != null) {
        current = current.left;
    }
    return current.data;
}

/* - getMax():取得BST最小值 */
 function getMax() {
    var current = this.root;
    while (current.right!= null) {
        current = current.right;
    }
    return current.data;
 }

前驱和后继

后继(Succ):给定元素 x ,它的后继元素 y 是满足 y>x 的最小值。
有两种情况:

  • 如果 x 所在的节点有一个非空的右子树,则右子树中的最小值就是答案。
  • 如果 x 没有非空的右子树,则需要向上回溯,找到最近的一个祖先,使得该祖先的左侧孩子,也为 x 的祖先。

实现:

/* * Succ:后继函数 * param: x——给定元素 * return:返回给顶元素在BST中的后继 */
function Succ(x){
  if(x.right!=null){
        //getMin(node) 获取以node节点为根节点的BST的最小值
        return this.getMin(x.right);
    } else{
        //Node节点有一个parent属性来保存父节点
        var parent = x.parent;
        while(parent!=null&&x ==parent.right){
            x = parent;
            parent = parent.parent;
        }
        return parent;
    }
}
/* * Pred:前驱函数 * param: x——给定元素 * return:返回给顶元素在BST中的前驱 */
function Pred(x){
    if(x.left!=null){
        //getMax(node) 获取以node节点为根节点的BST的最大值
        return this.getMax(x.left);
    } else{
        var parent = x.parent;
        while(parent!=null&&x ==parent.left){
            x = parent;
            parent = parent.parent;
        }
        return parent;
    }
}

删除

算法描述:
从二叉搜索树中删除节点 x 的方法如下:

  • 如果 x 没有子节点,或者只有一个孩子,直接将 x “切下”;
  • 如果 x 有两个孩子,我们用其右子树中的最小值替换 x ,然后将右子树中的这一最小值“切掉”。

因为右子树中的最小值节点不可能有两个非空的孩子,因此将上面第二种情况简化为第一种情况,因而可以直接将最小值节点“切掉”。

算法描述函数:
delete(T,x)=ϕnode(delete(Tl,x),k,Tr)node(Tl,k,delete(Tr,x))TrTlnode(Tl,y,delete(TR,y)):T=ϕ:x<k:x>k:x=kTl=ϕ:x=kTr=ϕ:x=kT@H_896_3270@l,Tr
其中, TlTrk 分别是当 T 非空时的左右子树和key:
Tl=left(T)Tr=right(T)k=key(T)y=min(Tr)

实现:

/* * removeData:删除数据 * param: * node——要删除数据的节点 * data——要删除的数据 * return: * 已删除data数据的树根节点 */
function removeData(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.data;
        node.right = removeData(node.right,tempNode.data);
        return node;
    }else if(data < node.data){
        node.left = removeData(node.left,data);
        return node;
    }else{
        node.right = removeData(node.right,data);
        return node;
    }

}
/* * remove() 方法:简单地接受待删除数据 */
function remove(data){
   this.root = removeData(this.root,data);
}

//test
var nums = new BST();
var arr = [4,8,1,2,10,9,14]; for(var i in arr){ nums.insert(arr[i]); } nums.remove(4); console.log(nums.root);

【数据结构】二叉搜索树BST的更多相关文章

  1. 利用Node实现HTML5离线存储的方法

    这篇文章主要介绍了利用Node实现HTML5离线存储的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  2. ios – 使用带有NodeJs HTTPS的certificates.cer

    我为IOS推送通知生成了一个.cer文件,我希望将它与NodeJSHTTPS模块一起使用.我发现HTTPS模块的唯一例子是使用.pem和.sfx文件,而不是.cer:有解决方案吗解决方法.cer文件可以使用两种不同的格式进行编码:PEM和DER.如果您的文件使用PEM格式编码,您可以像使用任何其他.pem文件一样使用它(有关详细信息,请参见Node.jsdocumentation):如果您的文件使

  3. 如何在XCode IDE中构建NodeJS?

    如何在XCodeIDE中将NodeJS构建为项目?NodeJS构建指令说它应该用以下内容构建:但是我希望在XCodeIDE中构建.我真正想要做的是在我的应用程序中嵌入NodeJS,所以我想如果我可以在XCode中构建NodeJS,那么我可以调整它以在我建立和运行NodeJS后添加我的应用程序.我想通过让V8在XCode中编译来取得一些进展,现在我正在尝试将NodeJS添加到V8项目中.解决方法在节点存储库根目录中运行./configure–xcode,您将获得所需的node.xcodeproj文件.

  4. 深入云存储系统Swift核心组件:Ring实现原理剖析

    它的目的是用于托管Rackspace的CloudFilesservice,原始项目代号是swift,所以沿用至今。Ring是Swift中最重要的组件,用于记录存储对象与物理位置间映射关系。先来看一下Swift文档中关于Ring的描述:Ring用来确定数据驻留在集群中的位置。有单独对应于Account数据库、container数据库和单个object的ring。Ring使用zone的概念来保证数据的隔离。每个partition的replica都确保放在了不同的zone中。本文逐步深入探讨了Swift如何通过

  5. swift篇第一期:简单的数据结构

    首先我们可以去使用Playground来编码,并且会实时的显示对应的编码信息,这样我们就不用每次都去运行程序来显示输出的东西了哦,也方便了我们对某些语句的验证,这个是比较赞的var与let前者为可变修饰符,后者为不可变从字面意思我们就可以很好的区分了常用的类型呢,跟其他语言基本相同啦,主要有几种:1.int类型2.Float,Double类型3.String类型4.Boolean类型当我们去声明一

  6. Swift 集合数据结构性能分析

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  7. Swift中的集合类数据结构

    在那种情况下,你将会需要一种基本的集合类数据结构。继续学习,你将会比较成熟的Cocoa数据结构与对应的纯Swift结构的性能。常见iOS数据结构iOS中三种最常用的数据结构是arrays,dictionaries和sets。除了在Swift和Objective-C中旧的Foundation框架中的数据结构,现在又有了新的仅支持Swift版本的数据结构与语言紧密结合在一起。Swift数组是同质的,意味着每一个Swift数组都只包含一种类型的对象。

  8. 11.Swift 中的类和结构体

    举例来说,以下情境中适合使用结构体:1.几何形状的大小,封装一个width属性和height属性,两者均为Double类型。这次就讲到这里,下次我们继续

  9. 如何通过Swift Package Manager 来构建一个简单的开发环境

    为了解决这个问题,我们需要在Package.swift中,添加必要的依赖关系:这样,我们就创建了一个叫做Application的target,它依赖我们之前创建的BSTmodule。

  10. a place you can learn algorithms and data structures(算法和数据结构) in swift

    https://github.com/raywenderlich/swift-algorithm-club

随机推荐

  1. 【数据结构】单调栈

    显然,每个发射站发来的能量有可能被0或1或2个其他发射站所接受,特别是为了安全,每个发射站接收到的能量总和是我们很关心的问题。由于数据很多,现只需要你帮忙计算出接收最多能量的发射站接收的能量是多少。输入输出格式输入格式:第1行:一个整数N;第2到N+1行:第i+1行有两个整数Hi和Vi,表示第i个人发射站的高度和发射的能量值。输入输出样例输入样例:34235610输出样例:7题解中有讲解代码实现

  2. BZOJ 1798 [Ahoi2009] Seq 维护序列seq [线段树+多重标记下传]【数据结构】

    有长为N的数列,不妨设为a1,a2,…Input第一行两个整数N和P。第二行含有N个非负整数,从左到右依次为a1,aN,。表示把所有满足t≤i≤g的ai改为ai×c。操作2:“2tgc”。同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。Output对每个操作3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。SampleInput7431234567512553242379313347SampleOutput2358HINT初始时数列为。对第5次操作,和为29+34+15+16=

  3. 陈越《数据结构》第一讲 基本概念

    陈越《数据结构》第一讲基本概念1什么是数据结构1.1引子例子:如何在书架上摆放图书?数据结构是:1.数据对象在计算机中的组织方式;2.数据对象必定与一系列加在其上的操作相关联;3.完成这些操作所用的方法就是算法。抽象数据类型数据类型-数据对象集;-数据集合相关联的操作集。抽象-与存放数据的机器无关;-与数据存储的物理结构无关;-与实现操作的算法和编程语言均无关。

  4. 陈越《数据结构》第二章 线性结构

    表中元素个数称为线性表的长度;线性表没有元素时,称为空表;表起始位置称表头,表结束位置称表尾。插入和删除操作只能在链栈的栈顶进行。

  5. 【数据结构】

    非线性结构:线性结构的元素之间具有线性关系,非线性结构中的元素之间不再是序列的关系,他们呈现的是更复杂的层次关系,即一个数据元素有且仅有一个直接前驱,但可有另个或者多个直接后继,显然比序列关系复杂常见非线性结构:树,图散列表PHP中的hashtable就是哈希表就是由数组和链表组成,一个长度为16的数组中,每个元素存储的是一个链表的头结点。

  6. 【数据结构】【C++STL】FIFO队列&amp;优先队列

    首先都需要打头文件queueFIFO队列是先进先出的就好像排队一样STL定义FIFO队列优先队列的话是有优先级存在的STL定义优先队列定义方式都是大根堆FIFO队列和优先队列都有一些操作COYG

  7. 【数据结构】 堆

    自底向上://增加/减少已有节点值Heap_Increase_Key//向堆插入新的节点HeapInsert自顶向下://替换堆顶后,维持堆函数KeepHeap//弹出堆顶函数Pop

  8. 【数据结构】链表

    线性表的顺序存储结构有存储密度高及能够随机存取等优点,但存在以下不足:线性表的链式存储(单链表)的实现单向循环链表的实现

  9. 伸展树(SPLAY)个人总结+模板 [平衡树]【数据结构】【模板】

    前言最近3个月内,无论是现场赛还线上赛中SPLAY出现的概率大的惊人啊啊啊!!!然而不会的我就GG了,同时发现大家都会SPLAY,,,,然后就学习了一波。——————————————————————————-附上整体代码-md贴上来太卡了,去题解里看吧维护序列的维护一堆数的

  10. BZOJ 1895 &amp; POJ 3580 supermemo [SPLAY]【数据结构】

    Ay}Ttimes.Forexample,performing“REVOLVE242”on{1,5}INSERTxP:insertPafterAx.Forexample,performing“INSERT24”on{1,5}DELETEx:deleteAx.Forexample,performing“DELETE2”on{1,5}MINxy:querytheparticipantwhatistheminimumnumberinsub-sequence{Ax…Ay}.Forexample,thecorrec

返回
顶部