【发布时间】:2016-06-10 14:59:45
【问题描述】:
我正在努力提高我的算法知识,并尝试从 Skiena 的算法设计手册中解决以下问题:
4-26 考虑使用比较对包含 n 个 0 和 1 的序列进行排序的问题。对于两个值 x 和 y 的每次比较,算法会了解 x y 中的哪一个。
(a) 给出一个算法,在最坏的情况下进行 n-1 次比较。证明您的算法是最优的。
(b) 给出一个算法,在平均情况下进行 2n/3 次比较排序(假设 n 个输入中的每一个都是 0 或 1 的概率相等)。证明你的算法是最优的。
这是我对 (a) 的解决方案:
void sort(int arr[], int length) {
int last_zero = -1;
for (int i = 1; i < length; i++) {
if (arr[i] < arr[i-1]) {
int tmp = arr[i];
arr[i] = arr[++last_zero];
arr[last_zero] = tmp;
} else if (arr[i] > arr[i-1]) {
last_zero = i-1;
}
}
return;
}
有没有更好的方法来做到这一点?
我不确定如何处理 (b) 部分。有一个类似的问题here,但我不明白那里的解释。
编辑:显然这被认为过于模糊,所以让我根据回复进行跟进。
我正在跟进@amit 的回复。这部分我不太明白:
(使得 i_k != i_h for k!= h、i_k != i_h for k!= h 和 i_k != j_h 对于所有 k,h)。
无论如何,我想我大致理解您提出的解决 (b) 部分的想法。然而,当我尝试为它编写代码时,我发现它很难完成。这是我到目前为止所拥有的,根据我的测试,它成功地对所有 (0,1) 和 (1,0) 对进行排序,并将相等的对推到数组的末尾,所以我最终得到 {all zeros, allones , 相等对}。我正在尝试实际移动数组元素,而不是计算 0 和 1 的数量。我被困在如何从我目前所拥有的着手:
int compare(int a, int b);
void shift_right(int arr[], int start, int end);
int prob_4_26_b(int arr[], int length) {
int last_zero = -1;
int last_one = -1;
for (int i = 0; i < length; i += 2) {
int tmp = compare(arr[i], arr[i+1]);
int cur_zero, cur_one;
if (tmp == 0) {
continue;
}
cur_zero = i;
cur_one = i + 1;
/* We have a 0 and a 1 */
/* If this is the first zero we have put it at index 0
and shift everything from index 0 to cur_zero-1 right by 1.
last_zero = 0 and if there are ones last_one++ */
if (last_zero == -1) {
int start = 0;
int end = cur_zero - 1;
shift_right(arr, start, end);
arr[0]=0;
last_zero = 0;
if (last_one != -1) {
last_one++;
}
}
/* If this is not the first zero we have then put it at
last_zero+1 and shift everything from last_zero+1 to cur_zero-1
right by 1. last_zero++ and if we have ones last_one++. */
else {
int start = last_zero + 1;
int end = cur_zero - 1;
shift_right(arr, start, end);
arr[last_zero+1] = 0;
last_zero++;
if (last_one != -1) {
last_one++;
}
}
/* If this is the first one we have put it after the last_zero.
Shift everything from last_zero+1 to cur_one-1 right by 1.
last_one = last_zero+1. */
if (last_one == -1) {
int start = last_zero + 1;
int end = cur_one-1;
shift_right(arr, start, end);
arr[last_zero+1] = 1;
last_one = last_zero + 1;
}
/* If this is not the first one we have put it at last_one+1
and shift everything from last_one+1 to cur_one-1 right by 1.
last_one++ */
else {
int start = last_one + 1;
int end = cur_one - 1;
shift_right(arr, start, end);
arr[last_one+1] = 1;
last_one++;
}
}
return 0;
}
void shift_right(int arr[], int start, int end) {
for (int i = end; i >=start; i--) {
arr[i+1] = arr[i];
}
}
int compare(int a, int b) {
if (a < b)
return -1;
else if (a > b)
return 1;
else
return 0;
}
【问题讨论】: