7

我正在学习合并排序,并在合并步骤中使用哨兵作为无穷大。

这是 Cormen 书中的算法。为什么我们在第 8 步和第 9 步中使用无穷大???

MERGE(A, p, q, r)

1 n1 ← q − p + 1

2 n2 ← r − q

3 create arrays L[1 . . n1 + 1] and R[1 . . n2 + 1]

4 for i ← 1 to n1

5 do L[i ] ← A[ p + i − 1]

6 for j ← 1 to n2

7 do R[ j ] ← A[q + j ]

8 L[n1 + 1] ← ∞

9 R[n2 + 1] ← ∞

10 i ← 1

11 j ← 1

12 for k ← p to r

13 do if L[i ] ≤ R[ j ]

14 then A[k] ← L[i ]

15 i ← i + 1

16 else A[k] ← R[ j ]

17 j ← j + 1
4

3 回答 3

10

哨兵是一个虚拟值,用于区分应该存在的值(例如用户输入)和控制值(需要特别处理的值)。一个简单的例子是使用 null 到 null 来标记列表的结尾。

在这种特定情况下,使用无穷大简化了当列表的两半重新合并在一起时的比较逻辑(例如,当合并任何与无穷大相比的东西会更少时,因此简化了合并结束的处理)。

于 2011-11-01T16:24:28.920 回答
4

哨兵值只是一个没有有效值的值。

如果我的域仅限于非零正数,则零可以是哨兵。

如果我的域仅限于正数,否则我会使用无符号整数,我可以使用有符号整数和负数作为标记。(当然,我为此失去了 unsigned 范围的上半部分。)

如果我使用指针指向一个值,则空指针可以是哨兵。

如果我使用的是 c 字符串,它是一个指针(或衰减为指针的数组),我可以使用空指针,或者在某些情况下,指向(char) 0(“空字符串”)作为哨兵.

哨兵只是一个值,你的有效输入永远不能接受。由于它不会被误认为是有效值,因此您的代码在看到标记值时可以执行“一些特殊的事情”,而不是对有效值执行的正常处理。

于 2011-11-01T16:27:39.080 回答
2

在这种情况下,在每个递归步骤中将无穷大(大于任何数字)添加到每个子数组的末尾,将避免合并两个子数组时在以下情况下的额外比较

  • 当第一个数组结束并且第二个数组剩余时
  • 或者当第二个数组结束并且第一个数组剩余时

在这两种情况下都不需要编写额外的逻辑来检查数组是否结束,如果结束则编写一些额外的代码。

于 2013-12-03T14:46:00.560 回答