我对计数排序算法有两个疑问:
复杂度如何O(n)
?算法中有5个for循环。每个for循环的复杂性应该是n吗?导致n^4
复杂性?我知道我错了,计算排序是线性的,但我想知道为什么我的推理是错误的。
如果计数排序算法是线性的,为什么它是O(n+K)
而不仅仅是O(n)
,如果添加K
,它就不再是线性的了吗?
这也是我所指的计数排序代码:
void countSort(char *str)
{
// The output character array that will have sorted str
char output[strlen(str)];
// Create a count array to store count of inidividul characters and
// initialize count array as 0
int count[RANGE + 1], i;
memset(count, 0, sizeof(count));
// Store count of each character
for(i = 0; str[i]; ++i)
++count[str[i]];
// Change count[i] so that count[i] now contains actual position of
// this character in output array
for (i = 1; i <= RANGE; ++i)
count[i] += count[i-1];
// Build the output character array
for (i = 0; str[i]; ++i)
{
output[count[str[i]]-1] = str[i];
--count[str[i]];
}
// Copy the output array to str, so that str now
// contains sorted characters
for (i = 0; str[i]; ++i)
str[i] = output[i];
}
答案 0 :(得分:2)
回答1:
有三个&#39; for&#39;每个都在O(n)
中工作的循环
因此整体复杂性为:
O(n)+O(n)+O(n) = O(n+n+n) = O(3n)
在3n
的情况下,3
是常量,可以忽略,因此复杂性会降低到O(n)
回答2:
算法不仅取决于数组的大小N
,还取决于其中收集的数字的范围K
。它需要一个更大的计数数组,因此需要迭代来对数组进行排序:
{1,10000000,3,2,0} // K=10000001
比它:
{1,4,5,2,3} // K=6
因此for循环使用代码的复杂性以这种方式计算:
for(i = 0; str[i]; ++i) // O(n)
for (i = 1; i <= RANGE; ++i) // O(k)
for (i = 0; str[i]; ++i) // O(n)
for (i = 0; str[i]; ++i) // O(n)
并且整体复杂性是O(n)+O(n)+O(n)+O(k) = O(n+k)
的复杂性,并确定了我对您的问题的答案:算法复杂性仍被视为线性。
答案 1 :(得分:1)
渐近复杂度在某种意义上表示作为输入大小函数的操作数。这很有用,因为它显示了随着输入大小的增加算法减慢了多少。常数不会影响减速,因此会被忽略。忽略我们得到的常数:
strlen(str)
执行strlen(str)
次操作(它检查整个字符串,直到找到'\0'
)
memset()
执行strlen(str)
次操作
第二个for
执行RANGE
次操作
其他三个for
中的每一个都执行strlen(str)
次操作
在您的示例中,strlen(str)
用n
表示,RANGE
用K
表示。所以整个函数执行O(5n + K) = O(n + K)
次操作。
n + K
仍然是一个线性函数,可以是两个变量(它是一个幂1的多项式)。
为了更深入地理解这一点,你需要阅读更多关于渐近复杂性(严格的数学理论)的内容。