Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
OpenDocCN
cs61b-textbook-zh
提交
90ee1afd
C
cs61b-textbook-zh
项目概览
OpenDocCN
/
cs61b-textbook-zh
通知
3
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
C
cs61b-textbook-zh
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
90ee1afd
编写于
5月 05, 2019
作者:
Y
YYF
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Create 6.md
上级
fb5a0009
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
141 addition
and
0 deletion
+141
-0
zh/6.md
zh/6.md
+141
-0
未找到文件。
zh/6.md
0 → 100644
浏览文件 @
90ee1afd
# 第六章 搜索树
> 译者:[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中,我们用符号
\l
eq表述全序关系,全序关系具有以下属性:
* 完备性: 对于任何 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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录