问题描述
您如何描述以下代码的运行时分析?这是基数排序的第二步(第一步是创建计数器)。
const reAssignArraySlots = (arr,counter) => {
let i = 0;
let j = 0;
while(i<arr.length) {
let k = 0;
let num = counter[i] || 0;
while(k<num) {
arr[j] = i;
k+=1;
j+=1;
}
i+=1;
j+=1;
}
return arr;
};
我相信无论如何都是 O(n),但想检查一下这种直觉。示例:
A) 所有元素都相同。计数器将是 { '2': 3 }。带有 i 的 while 循环将处理 1x,带有 k 的 while 循环将处理 3x,并且每次插入都是 O(1)。我将 3 个插入加起来使 O(3) 即 O(n)
B) 所有元素都是唯一的。计数器将是 { '2': 1,'1': 1,'3': 1 }。 while 循环将处理 i 3 倍。每次插入都是 O(1),加起来就是 O(3),也就是 O(n)。
C) 非唯一的、非顺序的元素。 {'4':1,'1':1,'3':2}。这里我不确定。对于每次插入,我们都会有 O(1),但是我们会对 i = 2 进行额外检查,这不在此处。不确定这是否会使我们达到 O(4)。最终,如果我们有足够稀疏的东西,这可以得到 O(n^2)。
代码的其余部分:
const getCounter = (arr) => {
const counter = {};
let min,max;
arr.forEach((item) => {
if(counter[item] !== undefined) {
counter[item] += 1;
} else {
counter[item] = 1;
}
});
return counter;
};
export const countSort = (arr) => {
const counter = getCounter(arr);
return reAssignArraySlots(arr,counter);
};
解决方法
我看到 2 个嵌套循环,所以我倾向于说它不比 O(n^2) 慢。
-
i
在外循环中递增 -
k
在内循环中递增(并在循环前设置为零) -
j
在两个循环中都递增
k
对于每个循环可能不同,但可以说它有一个平均值 ave_k
在循环结束时,在我看来 j
将始终等于 i * ave_k
。
最大的问题是k
(或ave_k
)的大小是多少?
- 它与
i
成正比吗?那么你有 O(n^2)。 - 它与
ln(i)
成正比吗?那么你有 O(n ln(n) )。 - 它是恒定的,独立于
i
吗?那么你有 O(n)。 - 它通常是
i
的平方吗?那么你有 O(n^2) - 它通常是
i
的平方根吗?那么你有 O(n sqrt(n) )