diff --git a/zh/6.md b/zh/6.md new file mode 100644 index 0000000000000000000000000000000000000000..4b7c74e11b131fecb496a7c7f1f18caae6f68bc4 --- /dev/null +++ b/zh/6.md @@ -0,0 +1,141 @@ +# 第六章 搜索树 + +> 译者:[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;} +``` + +因为我写这个的特殊方式,当我在树中插入同一个值的多个副本时,它们总是在所有现有副本的右边。我将在删除操作中保留此属性。 + + + + + + + +