簡體   English   中英

插入排序LinkedList Java

[英]Insertion Sort LinkedList Java

我正在嘗試為LinkedList寫一個插入排序,我有一個有效的方法,但是它的運行速度非常慢。 一個多小時即可添加和排序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。 我不要求僅提供一些提示的完整解決方案。

首先,對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)操作。 並且由於您使每個insert調用的get(i)調用O(M)次,因此使調用O(M^2)和排序O(N^3)

在“ HERE#3”處, add(i,e)重復前一個get(i)調用的列表遍歷。 但這還不錯,因為每個insert調用只執行一次add(i,e)調用。 因此,總體復雜度不受影響。

在“ HERE#4”處,取決於實現方式, add()操作可以為O(1)O(M) (對於LinkedList.add()它為O(1)因為列表數據結構保留對列表最后一個節點的引用。)兩種方式都不會影響總體復雜性。

簡而言之:

  • #2處的代碼肯定使它成為O(N^3)排序。

  • #1處的代碼也可以將其設置為O(N^3) ...,但不能使用標准LinkedList類。


那么該怎么辦?

  • 一種方法是重新編碼insert操作,以便它直接使用nextprev字段等遍歷列表。 不應調用任何“高級”列表操作:大小,get(i),add(e)或add(i,e)。

    但是,如果要通過擴展或包裝LinkedList來實現此目的,則不是一種選擇。 這些字段是私有的。

  • 如果要擴展或包裝LinkedList ,則解決方案是使用listIterator()方法為您提供ListIterator ,並將其用於有效的遍歷。 ListIteratoradd操作為O(1)

  • 如果(假設)您正在尋找對(大型) LinkedList進行排序的最快方法,那么解決方案是使用Collections.sort O(NlogN) ,該方法將列表內容復制到數組,對數組進行O(NlogN)排序,然后從排序后的數組中重建列表。

根據響應,由於性能更好,因此應使用ListIterator.add()而不是List.add

使用更快的排序算法呢?

這就是所謂的QuickSort 對於大型數據集,其速度比普通排序更快。 QuickSort具有O(nlogn)的平均情況,而插入僅具有O(n ^ 2)的平均情況。 是不是很大的不同?

實施范例

快速排序類

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;

    }
}

樣本主

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)。 病會讓你自己弄清楚。

祝好運

list.add(e)list.get(e) )每次調用都將占用o(n)。 您在旅行列表時應避免使用它們。

相反,如果您必須編寫自己的鏈接列表,則應跟蹤所旅行的元素。 通過將操作i ++和get(i)替換為elem = elem.nextelem = elem.getnext() ,(可能還取決於您實現鏈接列表的方式)。 然后通過執行以下操作添加一個元素:

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

在這里,我的示例適用於雙向鏈表,而elem表示當前正在比較要添加的對象的鏈表中的元素。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM