插入排序链接列表Java

时间:2014-03-15 23:24:12

标签: java sorting insertion-sort

我试图为LinkedList编写一个Insertion排序,我有一个工作方法,但速度非常慢。一个多小时的时间来添加和排序50,000个元素。

public void insert(Custom c) 
{
    int i = 0;
    for (i = 0; i < list.size(); i++)
    {
        if(list.get(i).compareTo(c) > 0  )
        {
            list.add(i,c);
            return;
        }
    }
    list.add(c);    
}

我知道我可以使用Collections.Sort但是对于这个赋值我需要编写自己的LinkedList。我并没有要求提供完整的解决方案。

4 个答案:

答案 0 :(得分:1)

首先,List上的插入排序会变慢(O(N^2))......无论你怎么做。但您似乎已将其实施为O(N^3)

这是你的代码...将被称为N次,以添加每个列表元素。

public void insert(Entry e) 
{
    int i = 0;
    for (i = 0; i < list.size(); i++)       // HERE #1
    {
        if(list.get(i).compareTo(e) > 0  )  // HERE #2
        {
            list.add(i,e);                  // HERE #3
            return;
        }
    }
    list.add(e);                            // HERE #4   
}

在“HERE#1”,我们迭代直到 M次,其中M是当前(部分)列表长度;即O(M)。这是插入排序中固有的。但是,根据您实施size()方法的方式,可以将迭代转换为O(M^2)操作序列。 (LinkedList.size()方法只返回size变量的值。这里没问题。但如果size()计算了元素...)

在“HERE#2”,我们有一个获取和比较。比较(compareTo(...))很便宜,但链接列表上的get(i)操作涉及从头开始遍历列表。这是O(M)操作。由于您通过get(i)来电进行了O(M)insert次通话,因此调用O(M^2)和排序O(N^3)

在“HERE#3”,add(i,e)重复上一次get(i)电话的列表遍历。但这并不是那么糟糕,因为每add(i,e)次呼叫只执行insert次呼叫。因此总体复杂性不受影响。

在“此处#4”,add()操作可以是O(1)O(M),具体取决于其实施方式。 (对于LinkedList.add(),它是O(1),因为列表数据结构保留了对列表最后一个节点的引用。)无论哪种方式,总体复杂性都不会受到影响。

简而言之:

  • #2的代码肯定会使其成为O(N^3)种。

  • #1的代码也可以O(N^3) ...但不能使用标准LinkedList类。


那该怎么办?

  • 一种方法是重新编码insert操作,以便它直接使用nextprev字段等遍历列表。不应该调用任何“更高级别”列表操作:size,get(i),add(e)或add(i,e)。

    但是,如果您通过扩展或包装LinkedList来实现此功能,则不能选择此选项。那些领域是私人的。

  • 如果要扩展或包装LinkedList,则解决方案是使用listIterator()方法为您提供ListIterator,并将其用于有效遍历。 add上的ListIterator操作为O(1)

  • 如果(假设)您正在寻找对(大)LinkedList进行排序的最快方法,那么解决方案就是使用Collections.sort。在幕后,该方法将列表内容复制到一个数组,对数组进行O(NlogN)排序,并从排序后的数组中重建列表。

答案 1 :(得分:0)

根据this回复,由于性能更佳,您应使用ListIterator.add()代替List.add

答案 2 :(得分:0)

如何使用更快的排序算法?

以下是QuickSort。它比大型数据集的正常排序更快。 QuickSort的平均情况为O(nlogn),而插入的平均情况为O(n ^ 2)。不是很大的区别吗?

示例实施

QuickSort类

import java.util.*;

public class QuickSort{


    public static void swap(int A[] , int x, int y){

        int temp = A[x];
        A[x] = A[y];
        A[y] = temp;

    }



    public static int[] QSort(int A[],int L, int U){
        Random randomGenerator = new Random();

        if ( L >= U){
            return A;
        }

        if (L < U) {
            /*                                                                                                                                                                                                                                                                
              Partion the array around the pivot, which is eventually placed                                                                                                                                                                                                  
              in the correct location "p"                                                                                                                                                                                                                                     

            */

            int randomInt = L + randomGenerator.nextInt(U-L);
            swap(A,L,randomInt);
            int T = A[L];
            int p = L;

            for(int i= L+1; i<= U; i++){
                if (T > A[i]){
                    p = p+1;
                    swap(A,p,i);

                }


            }



        /* Recursively call the QSort(int u, int l) function, this deals with                                                                                                                                                                                                 
           the upper pointer first then the lower.                                                                                                                                                                                                                            
        */
            swap(A,L,p);
            QSort(A,p+1,U);
            QSort(A,L, p-1);

        }
        return A;

    }
}

Sample Main

import java.util.*;

public class Main{
    public static void main(String [] args){

        int[] intArray =  {1,3,2,4,56,0,4,2,4,7,80,120,99,9,10,67,101,123,12,-1,-8};

        System.out.printf("Original Array was:\n%s\n\n",Arrays.toString(intArray));

        System.out.printf("Size of Array is: %d\n\n",intArray.length);

        QuickSort.QSort(intArray, 0, intArray.length - 1);
        int num = Integer.parseInt(args[0]);
        System.out.println("The sorted array is:");
        System.out.println(Arrays.toString(intArray));

    }
}

上面的示例将对Int数组进行排序,但您可以轻松编辑它以对任何对象进行排序(例如,在您的情况下为Entry)。我会让你自己解决这个问题。

祝你好运

答案 3 :(得分:0)

list.add(e)list.get(e)每次调用时都会占用o(n)。旅行时,你应该避免使用它们。

相反,如果您必须编写自己的链接列表,则应该跟踪您正在旅行的元素。通过替换操作i ++并通过elem = elem.nextelem = elem.getnext()得到(i),(可能还有别的,取决于你如何实现你的链表)。然后通过执行以下操作添加元素:

elem.next.parent = e;
e.next = elem.next;
elem.next = e;
e.parent = elem; 

这里我的示例适用于双向链表,elem表示您当前正在比较要添加的对象的链表中的元素。