计数选择算法

时间:2012-06-01 08:16:22

标签: algorithm select counting

我已经获得了算法的基本代码,该算法选择未排序数组中的第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;是,以及它的功能是什么。通常上限是多少?我还没有获得这些信息。

将算法分解为伪代码是理解它的一种好方法,我请求一些帮助来分解它并逐步完成代码。

提前谢谢你。

2 个答案:

答案 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本身中减去运行总和,这具有相同的效果。