基数排序的赋值部分运行时

问题描述

您如何描述以下代码的运行时分析?这是基数排序的第二步(第一步是创建计数器)。

   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) 慢。

  1. i 在外循环中递增
  2. k 在内循环中递增(并在循环前设置为零)
  3. 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) )