【问题标题】:Does a linkedList takes longer to be sorted?对linkedList 进行排序是否需要更长的时间?
【发布时间】:2021-03-16 23:06:12
【问题描述】:

突然想到一个问题,由于linkedList的get(index)方法的时间复杂度不是O(1),而是O(N),那么,会不会影响排序的时间复杂度呢?例如下面的代码(冒泡排序):

public static void bubbleSort(int arr[])
{
    int n = arr.length;
    for (int i = 0; i < n-1; i++)
        for (int j = 0; j < n-i-1; j++)
            if (arr[j] > arr[j+1]) {
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
            }
}

当我执行冒泡排序时,我需要获取元素。在任何排序算法中,您都需要获取元素,所以......当我执行冒泡排序时,平均时间复杂度是否为 O(n*log(n)*n)?如果是的话,当我使用Collections.sort(linkedList)时,平均时间复杂度也是O(n*log(n)*n)吗?

【问题讨论】:

  • 我记得,Java List 实现有一个支持数组。因此,get 操作始终保证为 O(1)。此外,您可以使用 HashMaps 实现类似的东西来存储列表中的节点索引。
  • Collections.sort 使用 QuickSort 或 TimSort 的改编版本,具体取决于列表大小。对于这些算法,复杂度为 O(log(n)) 或 O(n log(n))
  • @Harsh ArrayList 有这个属性,LinkedList 没有。不,Java 列表操作上的 get() 操作根本不能保证为 O(1)。
  • @rzwitserloot 感谢您的信息。我不知道这一点。

标签: java sorting linked-list


【解决方案1】:

对于“何时执行冒泡排序”,这取决于您如何实现冒泡排序。特别是冒泡排序可以采用 O(n^2) - 不比平常差 - 使用链表,因为它总是处理彼此相邻的元素。不过,如您所描述的,一个简单的实现将采用 O(n^3)。

来自Collections.sort的Javadoc:

这个实现将指定的列表转储到一个数组中,对数组进行排序,然后遍历列表,从数组中的相应位置重置每个元素。这避免了由于尝试对链表进行就地排序而导致的 n2 log(n) 性能。

【讨论】:

    【解决方案2】:

    这是List.sort (Java 13) 的实现

     default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }
    

    如您所见,无论您要对哪种列表实现进行排序,性能都几乎相同。

    现在,如果我们看看toArray 是如何实现的,我们会看到以下内容:

    链表

    public Object[] toArray() {
        Object[] result = new Object[size];
        int i = 0;
        for (Node<E> x = first; x != null; x = x.next)
            result[i++] = x.item;
        return result;
    }
    

    数组列表

    public Object[] toArray() {
        return Arrays.copyOf(elementData, size);
    }
    

    所以,如果你想对 LinkedList 进行排序,它会比 ArrayList 慢一点,但不会慢很多。

    【讨论】:

      【解决方案3】:

      当我执行冒泡排序时,平均时间复杂度是否为 O(n*log(n)*n)?

      您在那里是在误解下运作的。冒泡排序是O(n^2)。这不是一种高效的排序算法。

      LinkedList 大多没用;它会胜过arraylist的情况实际上是不存在的(你认为O(1)插入任何地方都是有用的,但除非你有一个listIterator,否则你实际上并没有得到它,并且在性能方面的缺点是很大的比算法复杂性所暗示的更糟糕,因为它与片上缓存的交互方式(即:非常非常糟糕)。

      正如 Octavian 的回答已经强调的那样,对所有列表进行排序的默认实现(并且 LinkedList 不会费心改变这种行为,但它可以)只是将完整的副本复制到具有 O(1) 访问权限的东西中,在那里排序,然后将其全部复制回去。从算法上讲,这意味着它只是添加了O(n) 因素,这是无关紧要的(毕竟至少排序为O(n log n)

      请记住,算法复杂性只会告诉您在您为其提供相对于其他大输入足够大的输入时其性能的行为。一个O(n^2) 算法可以比另一个快一千倍。

      像这样对 LinkedList 进行排序......不是很好。比 ArrayList 慢得多,即使不是 O(n)

      【讨论】:

        猜你喜欢
        • 2015-06-01
        • 2019-05-23
        • 1970-01-01
        • 2022-01-20
        • 2012-09-20
        • 2012-03-23
        • 2022-01-25
        • 2018-11-30
        相关资源
        最近更新 更多