zoukankan      html  css  js  c++  java
  • JavaScript树(二) 二叉树搜索

    TypeScript方式实现源码

      1 // 二叉树与二叉树搜索
      2 class Node {
      3     key;
      4     left;
      5     right;
      6     constructor(key) {
      7         this.key = key;
      8         this.left = null;
      9         this.right = null;
     10     }
     11 }
     12 class BinarySearchTree {
     13     root = null;
     14     public insert(key) {
     15         let newNode = new Node(key);
     16 
     17         if (this.root === null) {
     18             this.root = newNode;
     19         } else {
     20             this.insertNode(this.root, newNode);
     21         }
     22     }
     23     private insertNode(node, newNode) {
     24         if (newNode.key < node.key) {
     25             if (node.left === null) {
     26                 node.left = newNode;
     27             } else {
     28                 this.insertNode(node.left, newNode);
     29             }
     30         } else {
     31             if (node.right === null) {
     32                 node.right = newNode;
     33             } else {
     34                 this.insertNode(node.right, newNode);
     35             }
     36         }
     37     }
     38     public search(key) {
     39         return this.searchNode(this.root, key);
     40     }
     41     private searchNode(node, key) {
     42         if (node === null) {
     43             return false;
     44         }
     45         if (key < node.key) {
     46             return this.searchNode(node.left, key);
     47         } else if (key > node.key) {
     48             return this.searchNode(node.right, key);
     49         } else {
     50             return true;
     51         }
     52     }
     53     /**
     54      * 中序遍历
     55      */
     56     public inOrderTraverse(callback) {
     57         this.inOrderTraverseNode(this.root, callback);
     58     }
     59     private inOrderTraverseNode(node, callback) {
     60         if (node !== null) {
     61             this.inOrderTraverseNode(node.left, callback);
     62             callback(node.key);
     63             this.inOrderTraverseNode(node.right, callback);
     64         }
     65     }
     66     /**
     67      * 先序遍历
     68      */
     69     public preOrderTraverse(callback) {
     70         this.preOrderTraverseNode(this.root, callback)
     71     }
     72     private preOrderTraverseNode(node, callback) {
     73         if (node !== null) {
     74             callback(node.key);
     75             this.preOrderTraverseNode(node.left, callback);
     76             this.preOrderTraverseNode(node.right, callback);
     77         }
     78     }
     79     /**
     80      * 后序遍历
     81      */
     82     public postOrderTraverse(callback) {
     83         this.postOrderTranverseNode(this.root, callback)
     84     }
     85     private postOrderTranverseNode(node, callback) {
     86         if (node !== null) {
     87             this.postOrderTranverseNode(node.left, callback);
     88             this.postOrderTranverseNode(node.right, callback);
     89             callback(node.key);
     90         }
     91     }
     92     public min() {
     93 
     94     }
     95     private minNode(node) {
     96         if (node) {
     97             while (node && node.left !== null) {
     98                 node = node.left;
     99             }
    100             return node.key;
    101         }
    102         return null;
    103     }
    104     public max(node) {
    105         if (node) {
    106             while (node && node.right !== null) {
    107                 node = node.right;
    108             }
    109             return node.key;
    110         }
    111         return null;
    112     }
    113     public remove(key) {
    114         this.root = this.removeNode(this.root, key);
    115     }
    116     private removeNode(node, key) {
    117         if (node === null) {
    118             return null;
    119         }
    120         if (key < node.key) {
    121             node.left = this.removeNode(node.left, key);
    122             return node;
    123         } else if (key > node.key) {
    124             node.right = this.removeNode(node.right, key);
    125             return node;
    126         } else { // 建等于node.key
    127             // 第一种情况——一个叶节点
    128             if (node.left === null && node.right === null) {
    129                 node = null;
    130                 return node;
    131             }
    132 
    133             // 第二种情况——一个只有一个子节点的节点
    134             if (node.left === null) {
    135                 node = node.right;
    136                 return node;
    137             } else if (node.right === null) {
    138                 node = node.left;
    139                 return node;
    140             }
    141 
    142             // 第三种情况——一个只有两个子节点的节点
    143             let aux = findMinNode(node.right);
    144             node.key = aux.key;
    145             node.right = this.removeNode(node.right, aux.key);
    146             return node;
    147         }
    148     }
    149 }
    150 function printNode(value) {
    151     console.log(value);
    152 }
    153 let tree = new BinarySearchTree();
    154 tree.insert(11);
    155 tree.insert(7);
    156 tree.insert(15);
    157 tree.insert(5);
    158 tree.insert(3);
    159 tree.insert(9);
    160 tree.insert(8);
    161 tree.insert(10);
    162 
    163 tree.insert(13);
    164 tree.insert(12);
    165 tree.insert(14);
    166 tree.insert(20);
    167 tree.insert(18);
    168 tree.insert(25);
    169 tree.insert(6);
    170 
    171 // tree.inOrderTraverse(printNode);
    172 // tree.preOrderTraverse(printNode);
    173 tree.postOrderTraverse(printNode);
    174 
    175 console.log(tree.search(1) ? 'Key 1 found.' : 'Key 1 not found.');
    176 console.log(tree.search(8) ? 'Key 8 found.' : 'Key 8 not found.');
    二叉树 BinarySearchTree

    二叉树和二叉搜索树 

      二叉树中的节点最多只能有两个子节点:一个是左侧子节点,另一个是右侧子节点。这些定
    义有助于我们写出更高效的向/从树中插入、查找和删除节点的算法。二叉树在计算机科学中的
    应用非常广泛。
      二叉搜索树(BST)是二叉树的一种,但是它只允许你在左侧节点存储(比父节点)小的值,
    在右侧节点存储(比父节点)大(或者等于)的值。上一节的图中就展现了一棵二叉搜索树。
    二叉搜索树将是我们在本章中要研究的数据结构。

      下图展现了二叉搜索树数据结构的组织方式:

      

      和链表一样,将通过指针来表示节点之间的关系(术语称其为边) 。在双向链表中,每个节
    点包含两个指针,一个指向下一个节点,另一个指向上一个节点。对于树,使用同样的方式(也
    使用两个指针) 。但是,一个指向左侧子节点,另一个指向右侧子节点。因此,将声明一个Node
    类来表示树中的每个节点(行{1}) 。值得注意的一个小细节是,不同于在之前的章节中将节点
    本身称作节点或项,我们将会称其为键。键是树相关的术语中对节点的称呼。
      我们将会遵循和LinkedList类中相同的模式(第5章) ,这表示也将声明一个变量以控制此
    数据结构的第一个节点。在树中,它不再是头节点,而是根元素(行{2}) 。
      然后,我们需要实现一些方法。下面是将要在树类中实现的方法。
       insert(key):向树中插入一个新的键。
       search(key):在树中查找一个键,如果节点存在,则返回true;如果不存在,则返回false。 
       inOrderTraverse:通过中序遍历方式遍历所有节点。
       preOrderTraverse:通过先序遍历方式遍历所有节点。

       min:返回树中最小的值/键。
       max:返回树中最大的值/键。
       remove(key):从树中移除某个键。
      我们将在后面的小节中实现每个方法。 

     向树中插入一个键 

      要向树中插入一个新的节点(或项) ,要经历三个步骤。
      第一步是创建用来表示新节点的Node类实例(行{1}) 。只需要向构造函数传递我们想用来
    插入树的节点值,它的左指针和右指针的值会由构造函数自动设置为null。
      第二步要验证这个插入操作是否为一种特殊情况。 这个特殊情况就是我们要插入的节点是树
    的第一个节点(行{2}) 。如果是,就将根节点指向新节点。
      第三步是将节点加在非根节点的其他位置。

    树的遍历 

      遍历一棵树是指访问树的每个节点并对它们进行某种操作的过程。但是我们应该怎么去做
    呢?应该从树的顶端还是底端开始呢?从左开始还是从右开始呢?访问树的所有节点有三种方
    式:中序、先序和后序。 

    中序遍历 

      中序遍历是一种以上行顺序访问BST所有节点的遍历方式, 也就是以从最小到最大的顺序访
    问所有节点。中序遍历的一种应用就是对树进行排序操作。

    this.inOrderTraverse = function(callback){ 
        inOrderTraverseNode(root, callback); //{1} 
    }; 

      inOrderTraverse方法接收一个回调函数作为参数。回调函数用来定义我们对遍历到的每
    个节点进行的操作(这也叫作访问者模式,要了解更多关于访问者模式的信息,请参考http://en.
    wikipedia.org/wiki/Visitor_pattern) 。由于我们在BST中最常实现的算法是递归,这里使用了一个
    私有的辅助函数,来接收一个节点和对应的回调函数作为参数(行{1}) 。

    var inOrderTraverseNode = function (node, callback) { 
        if (node !== null) { //{2} 
            inOrderTraverseNode(node.left, callback);  //{3} 
            callback(node.key);                        //{4} 
            inOrderTraverseNode(node.right, callback); //{5} 
        } 
    }; 

      要通过中序遍历的方法遍历一棵树,首先要检查以参数形式传入的节点是否为null(这就
    是停止递归继续执行的判断条件——行{2}——递归算法的基本条件) 。
      然后,递归调用相同的函数来访问左侧子节点(行{3}) 。接着对这个节点进行一些操作
    (callback) ,然后再访问右侧子节点(行{5}) 。
      我们试着在之前展示的树上执行下面的方法:

    function printNode(value){ //{6} 
        console.log(value); 
    } 
    tree.inOrderTraverse(printNode); //{7} 

      但首先,需要创建一个回调函数(行{6}) 。我们要做的,是在浏览器的控制台上输出节点
    的值。然后,调用inOrderTraverse方法并将回调函数作为参数传入(行{7}) 。当执行上面的

      代码后,下面的结果将会在控制台上输出(每个数字将会输出在不同的行) :
      3 5 6 7 8 9 10 11 12 13 14 15 18 20 25
      下面的图描绘了inOrderTraverse方法的访问路径:

  • 相关阅读:
    干掉idea视图黄色警告
    idea插件 Background Image Plus 随机更换背景图片
    es的rest风格的api文档
    使用postman对elasticsearch接口调用
    es插件安装
    emoji表情等特殊字符处理和存储的两个方案
    java8两个字段进行排序问题
    java 必应壁纸批量下载
    elasticsearch学习(1)
    RocketMq报错 Java HotSpot(TM) Server VM warning:
  • 原文地址:https://www.cnblogs.com/menu/p/6984842.html
Copyright © 2011-2022 走看看