算法导论18.3 Exercises 答案

18.3-1

如下是整棵树的初始状态:

graph TD
    A[E L P T X];B[A C];C[J K];D[N O];
    E[Q R S];F[U V];G[Y Z];
    A---B;A---C;A---D;A---E;
    A---F;A---G;
  • C
graph TD
    A[L P T X];B[A E J K];D[N O];
    E[Q R S];F[U V];G[Y Z];
    A---B;A---D;A---E;
    A---F;A---G;
  • C
graph TD
    A[L P T X];B[A E J K];D[N O];
    E[Q R S];F[U V];G[Y Z];
    A---B;A---D;A---E;
    A---F;A---G;
  • P
graph TD
    A[L Q T X];B[A E J K];D[N O];
    E[R S];F[U V];G[Y Z];
    A---B;A---D;A---E;
    A---F;A---G;
  • V
graph TD
    A[L Q X];B[A E J K];D[N O];
    E[R S T U];G[Y Z];
    A---B;A---D;A---E;
    A---G;

18.3-2

首先写出两个子程序:B-TREE-PREDECESSOR-INTERNAL-NODEB-TREE-SUCCESSOR-INTERNAL-NODE,用于求解某个内部节点\(x\)的第\(i\)个键\(x.key_i\)的前驱和后继。

1
2
3
4
5
6
7
8
9
10
11
12
13
B-TREE-PREDECESSOR-INTERNAL-NODE(z, i)
x = z.c_{i}
while not x.leaf
DISK-READ(x.c_{x.n + 1})
x = x.c_{x.n + 1}
return x.key_{x.n}

B-TREE-SUCCESSOR-INTERNAL-NODE(z, i)
x = z.c_{i + 1}
while not x.leaf
DISK-READ(x.c[1])
x = x.c_{1}
return x.key_{1}

那么我们接下来可以按照每个步骤写出B-TREE-DELETE的过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// 节点x的第i个键和它的两个子节点x.c_{i},x.c_{i + 1}合并(需要保证这两个子节点的键数都为t-1)。
B-TREE-PUSHDOWN(T, x, i)
y = x.c_{i}
z = x.c_{i + 1}
// 将z合并到y,并插入k
y.key_{t} = k
for j = 1 to t - 1
y.key_{t + j} = z.key_{j}
for j = 1 to t
y.c_{t + j} = z.c_{j}
// 从x中删去z和k。
for j = i + 1 to x.n
x.key_{j - 1} = x.key_{j}
for j = i + 2 to x.n + 1
x.c_{j - 1} = x.c_{j}
x.n = x.n - 1
if x.n > 0
DISK-WRITE(x)
else
// 如果x被删光了,那么y成为新的根节点。
T.root = y
DISK-WRITE(y)

B-TREE-DELETE(T, k)
x = T.root
if x == T.nil
error "not find key: " k
DISK-READ(x)
while not x.leaf
i = 1
while i <= x.n and x.key_{i} < k
i = i + 1
if i <= x.n and x.key_{i} == k
//进入Case 2
//Case 2a
DISK-READ(x.c_{i})
y = x.c_{i}
if y.n >= t
k' = B-TREE-PREDECESSOR-INTERNAL-NODE(x, i)
x.key_{i} = k'
DISK-WRITE(x)
k = k'
x = y
else
//Case 2b
DISK-READ(x.c_{i + 1})
z = x.c_{i + 1}
if z.n >= t
k' = B-TREE-SUCCESSOR-INTERNAL-NODE(x, i)
x.key_{i} = k'
DISK-WRITE(x)
k = k'
x = z
//Case 2c
else
B-TREE-PUSHDOWN(T, x, i)
else
//进入Case 3,此时x.c_{i}为k所在子树。
DISK-READ(x.c_{i})
y = x.c_{i}
if y.n == t - 1
if i > 1
l = x.c_{i - 1}
DISK-READ(l)
if i <= x.n
r = x.c_{i + 1}
DISK-READ(r)
// Case 3a
if i > 1 and l.n >= t
k' = l.key_{l.n}
t' = l.c_{l.n + 1}
l.n = l.n - 1
for j = y.n downto 1
y.key_{j + 1} = y.key_{j}
for j = y.n + 1 downto 1
y.c_{j + 1} = y.c_{j}
y.key_{1} = k'
y.c_{1} = t'
y.n = y.n + 1
DISK-READ(x)
DISK-READ(l)
DISK-READ(y)
else if i <= x.n and r.n >= t
k' = r.key_{1}
t' = r.c_{1}
for j = 2 to r.n
r.key_{j - 1} = r.key_{j}
for j = 2 to r.n + 1
r.c_{j - 1} = r.c_{j}
r.n = r.n - 1
y.key_{y.n + 1} = x.key_{i}
y.c_{y.n + 2} = t'
x.key_{i} = k'
y.n = y.n + 1
DISK-READ(x)
DISK-READ(r)
DISK-READ(y)
// Case 3b
else
if i == x.n + 1
i = i - 1
B-TREE-PUSHDOWN(T, x, i)
else
x = y
//目前x是某个叶子叶子节点,即Case 1,并且保证了x.n >= t。
i = -1
for j = 1 to x.n
if x.key_{j} == k
i = j
if i == -1
error "not find key: " k
else
for j = i + 1 to x.n
x.key_{j - 1} = x.key_{j}
x.n = x.n - 1
DISK-WRITE(x)