开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情
我们将要学习另一种非顺序数据结构一-树,它对于存储需要快速查找的数据非常有用。 本章内容包括:
- 树的相关术语
- 创建树数据结构
- 树的遍历
- 添加和移除节点
- AVL树
树数据结构
树是一种分层数据的抽象模型。现实生活中最常见的树的例子是家谱,或是公司的组织架松图,如下图所示:
树的相关术语
一个树结构包含一系列存在父子关系的节点。每个节点都有一个父节点(除了顶部的第一个节点 )以及零个或多个子节点:
位于树顶部的节点叫作根节点(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)
}
下图展现了二叉搜索树数据结构的组织方式:
和链表一样,将通过指针来表示节点之间的关系(术语称其为边)。在双向链表中,每个节点包含两个指针,一个指向下一个节点,另一个指向上一个节点。对于树,使用同样的方式(也使用两个指针)。但是,一个指向左侧子节点,另一个指向右侧子节点。因此,将声明一个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)
}
}