JavaScript 树 非顺序结构是散列表

94 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情

我们将要学习另一种非顺序数据结构一-树,它对于存储需要快速查找的数据非常有用。 本章内容包括:

  • 树的相关术语
  • 创建树数据结构
  • 树的遍历
  • 添加和移除节点
  • AVL树

树数据结构

树是一种分层数据的抽象模型。现实生活中最常见的树的例子是家谱,或是公司的组织架松图,如下图所示:

image.png

树的相关术语

一个树结构包含一系列存在父子关系的节点。每个节点都有一个父节点(除了顶部的第一个节点 )以及零个或多个子节点:

image.png 位于树顶部的节点叫作根节点(11)。 它没有父节点。树中的每个元素都叫作节点,节点分h内部节点和外部节点。至公有个子节点的节点称为内部节点(75、作南20提为成)。没有子元素的节点称为外部节点或叶节点 (3、6、8、10、12、14、18和25是叶节点) 子树 一个节点可以有祖先和后代。一个节点 ( 除了根节点) 的祖先包括父节点、祖父节点、曾祖《节点等。一个节点的后代包括子节点、孙子节点、曾孙节点等。例如,节点5的祖先有节点1和节点11,后代有节点3和节点6。 有关树的另一个术语是子树。子树由节点和它的后代构成。例如,节点13、12和14构成了上图中树的一棵子树。 节点的一个属性是深度,节点的深度取决于它的祖先节点的数量。比如,节点3有3个祖先节点(5、7和11),它的深度为3。 树的高度取决于所有节点深度的最大值。一棵树也可以被分解成层级。根节点在第0层,它的子节点在第1层,以此类推。上图中的树的高度为3(最大高度已在图中表示第3层)。 现在我们知道了与树相关的一些最重要的概念,下面来学习更多有关树的知识。

二叉树和二叉搜索树

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

创建 BinarysearchTree类

让我们开始创建自己的BinarysearchTree类。首先,声明它的结构:

function BinarySearchTree() {
    var Node = function(key)( //(1)
        this.key = key;this.left = null;this.right = null;
    };
    var root = nu1l;//(2)
}

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

image.png 和链表一样,将通过指针来表示节点之间的关系(术语称其为边)。在双向链表中,每个节点包含两个指针,一个指向下一个节点,另一个指向上一个节点。对于树,使用同样的方式(也使用两个指针)。但是,一个指向左侧子节点,另一个指向右侧子节点。因此,将声明一个Node类来表示树中的每个节点(行(1))。值得注意的一个小细节是,不同于在之前的章节中将节点本身称作节点或项,我们将会称其为键。键是树相关的术语中对节点的称呼。

我们将会遵循和LinkedLit类中相同的模式(第S章,这表示将声明一个变量以控制此数据结构的第一个节点。在树中,它不再是头节点,而是根元素(行(2))。

然后,我们需要实现一些方法。下面是将要在树类中实现的方法。

  • insert(key):向树中插人一个新的键。
  • search(key): 在树中查找一个键,如果节点存在,则返回true; 如果不存在,则返回
  • falseo
  • inOrderTraverse: 通过中序遍历方式遍历所有节点。
  • preOrderTraverse: 通过先序遍历方式遍历所有节点。
  • postOrderTraverse: 通过后序遍历方式遍历所有节点
  • min:返回树中最小的值/键。
  • max:返回树中最大的值/键。
  • remove(key):从树中移除某个键

我们将在后面的小节中实现每个方法。

向树中插入一个键

实现的方法会比前几章实现的方法稍微复杂一些。我们将会在方法中使用很多递归。

下面的代码是用来向树插人一个新键的算法的第一部分:

this.insert = function(key)[
    var newNode = new Node(key); //(1)
    if (root === null){} //[2)
        root = newNode;
    } else {
        insertNode(root,newNode); //(3)
    }
}