提交 90ee1afd 编写于 作者: Y YYF

Create 6.md

上级 fb5a0009
# 第六章 搜索树
> 译者:[YYF](https://github.com/yongfengyan)
有关树的一个重要应用就是搜索。这项任务是确定数据结构中是否存在目标值,这些目标值表示一组数据,搜索结果可能返回与该值相关的一些辅助信息。在所有这些搜索中,我们都会执行多个步骤,直到我们找到了要查询的值,或者尝试了所有可能性。在每一步中,我们都会为下一步考虑从而消除其中的一些部分。在线性搜索(linear search)的情况下(见§1.3.1),我们在每个步骤中删除一个数据单元。在二分法搜索(binary search)的情况下(见第1.3.4节),在每个步骤中删除剩余数据的一半。
二分法搜索的问题是,待搜索项集不易更改;除非新添加数据项大于所有现有数据,否则添加新数据项需要移动原待搜索集的某些部分,以便为新项腾出合适的空间。最坏情况下,此操作的成本会随着集合的大小成比例地增加。这将转化为一个插入数据的问题,但是找到一组数据的中间值这一二分法的关键操作的花销将会变大。
对于树结构。假设我们有一组数据值,我们可以从每个数据值中提取一个键(key),并且键集可能是完全有序的,也就是说,我们总是可以说一个键小于、大于或等于另一个键。键值的意义完全取决于数据的种类,但表达方式应做好标注。我们可以通过让这些数据值作为二叉搜索树(BST)的标签来近似进行二分搜索,二叉搜索树具有如下性质:
BST性质:对于树的每个节点x,x的左子树中的所有节点的键都小于或等于x的键,x的右子树中的所有节点的键都大于或等于x的键。
图6.1a是典型BST的示例。在该示例中,标签是整数,键与标签相同,关于“小于”、“大于”和“等于”的表达为其通常的含义。
键不必是整数。通常,我们可以对key使用任何一种全序关系(total order)来把一组数据添加到BST中,我们用符号\leq表述全序关系,全序关系具有以下属性:
* 完备性: 对于任何 x 和 y 要么满足 x \leq y 要么满足 y \leq x 或者二者同时都满足
* 传递性: 如果 x \leq y 而且 y \leq z 那么 x \leq z
* 非对称性 如果 x \leq y 并且 y \leq x 那么 x = y
例如,键可以是整数,而且不仅可以是整数,可以有它们通常的含义。或者数据和键可以是字符串,其顺序是字典排序。或者,数据可以是(pairs)一对(A,B),键可以是对的第一项。字典排序就像是按定义的单词排序,而不考虑它们的含义。最后一个排序是一个例子,在这个例子中,人们可能期望在搜索树中有几个具有相同键的不同项。
从定义看起BST的一个重要特性是,通过BST可以按标签的升序访问其节点,这就产生了一种简单的排序算法,称为树排序“tree sort”。
```java
/** Permute the elements of A into non-decreasing order. Assumes
* the elements of A have an order on them. */
static void sort(SomeType[] A) {
int i;
BST T;
T = null;
for (i = 0; i < A.length; i += 1) {
insert A[i] into search tree T.
}
i = 0;
traverse T in inorder, where visiting a node, Q, means
A[i] = Q.label(); i += 1;
}
```
someType类型的数据,根据BST定义的要求,用来表示具有小于和等于运算性质的数据。
## 6.1 BST的应用
由于BST是二叉树,我们可以使用5.2节中的表示来给图6.2这个类。现在我将使用int类型作为标签,并假定标签与键相同。
由于在这个特殊的BST中一个标签可能对应多个实例,因此我必须仔细指定删除该标签或查找包含该标签的节点的含义。我在这里选择了包含标签的“最高”节点--最接近根的节点。
为什么这总是独一无二的?也就是说,为什么不能有两个包含标签的最高节点,同样接近于根节点?
这个特定的BST定义的一个问题特征是,数据结构相对来说是不受保护的。
正如insert上的注释所表明的那样,当t.label()为20时,可以通过向其中一个子元素中插入错误的内容来“破坏”bst(如bst.insert(t.left(),42)。
当我们把这种表示应用于6.2节的SortedSet中时,我们会避免此类错误引用。
```java
/** A binary search tree. */
class BST {
protected int label;
protected BST left, right;
/** A leaf node with given LABEL */
public BST(int label) {
this(label, null, null);
}
/** Fetch the label of this node. */
public int label();
/** Fetch the left (right) child of this. */
public BST left() ...public BST right() ...
/** The highest node in T that contains the
* label L, or null if there is none. */
public static BST find(BST T, int L) ...
/** True iff label L is in T. */
public static boolean isIn(BST T, int L){
return find (T, L) != null;
}
/** Insert the label L into T, returning the modified tree.
* The nodes of the original tree may be modified. If
* T is a subtree of a larger BST, T’, then insertion into
* T will render T’ invalid due to violation of the binary-
* search-tree property if L > T’.label() and T is in
* T’.left() or L < T’.label() and T is in T’.right().
*/
public static BST insert(BST T, int L) ...
/** Delete the instance of label L from T that is closest to
* to the root and return the modified tree. The nodes of
* the original tree may be modified. */
public static BST remove(BST T, int L) ...
/* This constructor is private to force all BST creation
* to be done by the insert method. */
private BST(int label, BST left, BST right) {
this.label = label; this.left = left; this.right = right;
}
}
```
6.2: A BST representation
### 6.1.1 搜索 BST
搜索BST与数组中进行二分搜索非常相似,树的根对应于数组的中间值。
```java
/** The highest node in T that contains the
* label L, or null if there is none. */
public static BST find(BST T, int L){
if (T == null || L == T.label)return T;
else if (L < T.label)
return find(T.left, L);
else return find(T.right, L);
}
```
### 6.1.2 插入 BST
正如之前所说,使用一棵树的好处是向它添加数据时花销相对较小,如下面的例行程序。
```java
/** Insert the label L into T, returning the modified tree.
* The nodes of the original tree may be modified.... */
static BST insert(BST T, int L){
if (T == null)
return new BST (L, null, null);
if (L < T.label)
T.left = insert(T.left, L);
else
T.right = insert(T.right, L);
return T;}
```
因为我写这个的特殊方式,当我在树中插入同一个值的多个副本时,它们总是在所有现有副本的右边。我将在删除操作中保留此属性。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册