我已经获得了算法的基本代码,该算法选择未排序数组中的第k个最小元素(或者排序,我不确定)。通常情况下,我们会使用quickselect进行快速选择,但我们已经给出了另一个标记为“计数选择”的选择。作为函数名称。
" Counting select使用类似的方法来计算排序。列表中的项目用作计数数组的索引。然后,从数组的低值结束开始,累计项目计数,直到总数超过期望值。"
// return the kth smallest item
int countingSelect(int items[], int first, int last, int k) {
int counts[cap];
for (int c = 0; c < cap; c++) {
counts[c] = 0;
}
for (int i = first; i < last; i++) {
counts[items[i]] += 1;
}
int c = 0;
while (k >= 0) {
k -= counts[c++];
}
return c-1;
}
我很难将其分解为伪代码,因此我可以准确理解该函数的工作原理。通过我们给出的代码,我的第一个困惑是价值&#39; cap&#39;是,以及它的功能是什么。通常上限是多少?我还没有获得这些信息。
将算法分解为伪代码是理解它的一种好方法,我请求一些帮助来分解它并逐步完成代码。
提前谢谢你。
答案 0 :(得分:2)
我认为cap是列表中最大的数字(因此你可以分配足够的内存)。
计数是每个数字在列表中出现的数量的计数。例如,count [n]表示列表中n的数量。
第一个循环初始化计数值。
第二个循环通过并通过递增计数中的适当位置来调整计数。完成此循环后,count是列表中每个数字出现的数量的计数。例如,count [n]表示列表中n的数量。
最后一位经过并遍历列表,将count中前几个索引的元素相加,直到该数字大于k。那么之前的数字是我们超过k的地方,所以我们返回那个数字。
答案 1 :(得分:2)
如果你理解了计数排序,这应该很简单。如果没有,那么让我简单说一下计数排序的工作原理。
假设你有10个数字,在[0,15]范围内。由于您知道数据的边界,因此您可以检查输入,并标记您看到每个数字的次数。然后迭代计数并按顺序检索数字:
input numbers
counts[0..15] = 0
for i in numbers
++counts[numbers[i]]
for i in counts
counts[i] times
print i
让我们看一个例子:
numbers: 1 5 3 13 5 2 0 1 14 2
第一个循环创建计数:
(index) 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
counts: 1 2 2 1 0 2 0 0 0 0 0 0 0 1 1 0
第二个循环给你:
1 times 0
2 times 1
2 times 2
1 time 3
0 times 4
2 times 5
0 times 6
...
即:
0 1 1 2 2 3 5 5 13 14
你的算法基本相同,除了输出排序列表,它找到第k个最小项。
在上面的示例中,您可以看到:
0th smallest numbers is 0
1st and 2nd smallest numbers are 1
3rd and 4th smallest numbers are 2
5th smallest number is 3
6th and 7th smallest numbers are 5
...
如果你仔细观察,你会看到这种模式:
if k <= 0 => 0
else if k <= 2 => 1
else if k <= 4 => 2
else if k <= 5 => 3
else if k <= 7 => 5
else if k <= 8 => 13
else if k <= 9 => 14
然而,数字
0 2 4 5 7 8 9
实际上是counts
本身的运行总和!
那么,算法的底部是一个运行总和,除了检查总和何时大于k
。如果是这样,之前的号码就是你的答案。请注意,counts
的索引是数字本身。
int c = 0;
int sum = 0;
while (k >= sum) {
sum += counts[c++];
}
return c-1;
您的算法已尝试避开sum
变量,而是从k
本身中减去运行总和,这具有相同的效果。