簡體   English   中英

在 Java 中使用 LinkedList 選擇排序

[英]Selection sort with LinkedList in Java

我想在 Java 中使用 LinkedList 實現選擇排序。

我知道如何用 ArrayList 做到這一點,請不要評論我應該改用它。 我有興趣展示鏈表與 arrays 相比的優點(快速插入和刪除)和缺點。

我知道如何在 C 中執行此操作,在那里我有指針並可以訪問列表的節點結構。 但在 Java 中,我發現最接近的是 ListIterator。

這是我編譯和工作的代碼:

class Pile {
    private final List< Card > cards;

    public void sortWithSelectionSortUsingLinkedList( final Comparator< Card > comparator ) {
        final List< Card > list = new LinkedList< Card >( cards );
        cards.clear();
        
        for( final ListIterator< Card > it = list.listIterator(); it.hasNext(); ) {
            final int currentIndex = it.nextIndex();
            final Card currentCard = it.next();
            int indexToMoveToCurrent = currentIndex;
            Card cardToMoveToCurrent = currentCard;
            for( final ListIterator< Card > jt = list.listIterator( it.nextIndex() ); jt.hasNext(); ) { // Problem A
                int indexPossiblyLower = jt.nextIndex();
                Card cardPossiblyLower = jt.next();
                if( comparator.compare( cardPossiblyLower, cardToMoveToCurrent ) < 0 ) {
                    cardToMoveToCurrent = cardPossiblyLower;
                    indexToMoveToCurrent = indexPossiblyLower;
                }
            }
            it.set( cardToMoveToCurrent );
            list.set( indexToMoveToCurrent, currentCard ); // Problem B
            // The below swapping code causes ConcurrentModificationException // Problem C
            // it.previous();
            // it.add( list.remove( indexToMoveToCurrent ) );
        }
        
        cards.addAll( list );
    }
}

我的問題如下:

A) 要從 1 迭代到外部迭代器 (it) 的 position 之外,我必須調用帶有索引的 listIterator。 我懷疑此方法從列表的開頭走到給定的 position。這很浪費,因為我們之前已經有一個元素的迭代器。 我怎樣才能有效地從給定的迭代器迭代到列表的末尾?

B) 要交換元素,我必須使用 list.set 和索引,這會導致與 A) 相同的低效率。

C) 我計划通過修改列表節點來交換元素,而不僅僅是它們的值。 據我了解,我當前的代碼指向下圖的中間部分,而我想到達底部: 鏈表修改

在當前的算法中,這可能沒有什么區別,但我想檢查其他排序算法,而這個 LinkedList 並不像我預期的那樣工作。

一對一的交換與刪除元素並將其插入到另一個元素之前不同。 示例:abcdefgh 是原始的,交換 b 和 f 導致 afcdebgh,而在 b 之前刪除和插入 f 將導致 afbcdegh。 我認為 LinkedLists 可以有效地執行后者。 如果我只能像 Arrays 那樣使用它們,那么為什么 LinkedLists 存在呢?

我有興趣展示鏈表與 arrays 相比的優點(快速插入和刪除)和缺點。

恭喜你,你已經成功地展示了 java 的特定 LinkedLists 實現的缺點,它們很爛,不要使用它們 - 它們的性能比 big-O 符號所建議的更差(現代 CPU 架構和鏈表只是彼此不喜歡),如果不向后彎腰並使用ListIterator ,實際上不可能嘗試利用這些優勢。 但是,ListIterator 的 API 不足以執行交換元素之類的操作,因為您不能直接訪問跟蹤器節點(包含上一個、下一個和值字段的節點)。

那為什么 LinkedLists 存在呢?

它們可能一開始就不應該存在。 “他們為什么這樣做?” 無異於問:“核心 java 開發團隊在 90 年代某處思考什么,當這些東西被寫出來的時候?”

我們可以猜測。

  • 感覺寫的合乎邏輯。 有些事情在你非常仔細地思考之前是非常有道理的,然后它就沒有了。 有人根本沒有真正考慮清楚。
  • LinkedList 作為一個概念是眾所周知的,每個關於列表以及如何實現它們的基礎信息學章節都將它們與數組樣式列表相提並論。
  • arraylist 增長的“成本”被攤銷——通常它的成本為 0,但有時后備數組是“滿的”,而 ArrayList impl 需要制作一個全新的數組,將所有元素復制過來。 因此,攤銷 - 便宜,但它會“爆發”。 相對而言, arraylist.add()調用經常需要花費大量時間。 如今,這完全無關緊要了; 如果您想編寫一個永遠不會突然變慢的應用程序,那么 JVM 不是您想要的(垃圾收集暫停、操作系統暫停等),因此“好處”是無關緊要的。 但它在 90 年代編寫時(被認為是)相關的方式。 人們肯定會期待一個 impl 並為其提交功能請求,即使核心團隊確實意識到實際使用它們可能很少是一個好主意。
  • Java 絕對不會刪除它們 - 一旦引入,它們就會保留,除非有非常令人信服的理由不這樣做。 向后兼容性很好。
  • LinkedList 早於 ArrayDeque 和大多數其他集合類(LinkedList 是最初添加的。它不在 java 1.0 中(只有 Vector 和 Hashtable 是),但它在 1.1 中,它引入了層次結構(Collection,List,Set,Map,HashMap , ArrayList, 和 LinkedList). 有一次它提供了前端快速插入和末尾快速插入而沒有困難(即無需首先緩慢地將 ListIterator 導航到插入點),這是當時其他類型所沒有的屬性.今天,無論你有什么問題需要一個集合,LinkedList 都不太可能是正確的,但在那時,它更有可能。
  • LinkedList 極其糟糕的性能特征,顯然不是大 O 符號意義上的,而是實用意義上的 - 這些跟蹤器對象如何導致大量緩存頁面未命中,因此即使它們在算法上應該很快,但它們卻慢得離譜 - 遠遠不夠,遠不是當時的一個因素。 在 90 年代,緩存未命中的代價是幾個周期,許多處理器一開始就沒有。 今天的成本是巨大的——一千個周期。
  • 最重要的是,誰知道呢。 有人決定寫它。 並不意味着你應該使用它。

暫無
暫無

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

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