web-dev-qa-db-ja.com

ソートされたリンクリストへの挿入Java

以下のコードで、intのソート済みLinkedListに新しい整数を挿入していますが、次の値へのポインターを持つ単一のリンクリストと次および前の値へのポインタ。 Nodesを使用して以下のケースを実装しようとしましたが、Javaがこのインポートorg.w3c.dom.Node(ドキュメントオブジェクトモデル)をインポートしているため、スタックしました。

挿入ケース

  1. 空の配列に挿入
  2. 挿入する値がすべてより少ない場合は、最初に挿入します。
  3. 挿入する値が何よりも大きい場合は、最後に挿入してください。
  4. 値がLLの特定の値よりも小さいか大きい場合、中間になる可能性があります。

    import Java.util.*;
    
    public class MainLinkedList {
    public static void main(String[] args) {
    LinkedList<Integer> llist = new LinkedList<Integer>();
    
    llist.add(10);
    llist.add(30);
    llist.add(50);
    llist.add(60);
    llist.add(90);
    llist.add(1000);
    System.out.println("Old LinkedList " + llist);
    
    //WHat if you want to insert 70 in a sorted LinkedList
    LinkedList<Integer> newllist = insertSortedLL(llist, 70);
    System.out.println("New LinkedList " + newllist);
    }
    
    public static LinkedList<Integer> insertSortedLL(LinkedList<Integer> llist, int value){
    
        llist.add(value);
        Collections.sort(llist);
        return llist;
    
    }
    

    }

8
cloudviz

これは完全にあなたの目的に役立つかもしれません:

このコードを使用してください:

_import Java.util.*;

public class MainLinkedList {
    private static LinkedList<Integer> llist;

    public static void main(String[] args) {
        llist = new LinkedList<Integer>();

        addValue(60);
        addValue(30);
        addValue(10);
        addValue(-5);
        addValue(1000);
        addValue(50);
        addValue(60);
        addValue(90);
        addValue(1000);
        addValue(0);
        addValue(100);
        addValue(-1000);
        System.out.println("Linked List is: " + llist);

    }

    private static void addValue(int val) {

        if (llist.size() == 0) {
            llist.add(val);
        } else if (llist.get(0) > val) {
            llist.add(0, val);
        } else if (llist.get(llist.size() - 1) < val) {
            llist.add(llist.size(), val);
        } else {
            int i = 0;
            while (llist.get(i) < val) {
                i++;
            }
            llist.add(i, val);
        }

    }

}
_

この1つのメソッドは、Collections.sort(list)を使用せずに、リストへの挿入をソートされた方法で管理します

6
Master

ListIteratorを使用する場合、getを実行するための複雑さはO(1)になります。

public class OrderedList<T extends Comparable<T>> extends LinkedList<T> {

    private static final long serialVersionUID = 1L;


    public boolean orderedAdd(T element) {      
        ListIterator<T> itr = listIterator();
        while(true) {
            if (itr.hasNext() == false) {
                itr.add(element);
                return(true);
            }

            T elementInList = itr.next();
            if (elementInList.compareTo(element) > 0) {
                itr.previous();
                itr.add(element);
                System.out.println("Adding");
                return(true);
            }
        }
    }
}
19
Amruth

@Atrakeur

「新しい要素を追加するたびにすべてのリストをソートするのは効率的ではありません」

それは事実ですが、リストを常にソートされた状態にする必要がある場合、それが実際に唯一のオプションです。

「最善の方法は、要素を必要な場所(正しい位置)に直接挿入することです。これを行うには、すべての位置をループして、この番号が属する場所を見つけることができます。」

これはまさにサンプルコードが行うことです。

「または、Collections.binarySearchを使用して、この高度に最適化された検索アルゴリズムでこの作業を実行します

バイナリ検索は効率的ですが、ランダムアクセスリストに対してのみです。したがって、リンクリストの代わりに配列リストを使用することもできますが、リストが大きくなるにつれてメモリコピーを処理する必要があります。また、リストの容量が実際の要素数よりも多い場合(かなり一般的です)、必要以上のメモリを消費することになります。

したがって、どのデータ構造/アプローチを取るかは、ストレージとアクセスの要件に大きく依存します。

[編集]実際、サンプルコードには1つの問題があります。ループすると、リストの複数のスキャンが発生します。

int i = 0;
while (llist.get(i) < val) {
    i++;
}
llist.add(i, val);

Get(i)の呼び出しは、リストを1回走査してi番目の位置に到達します。次に、add(i、val)への呼び出しはそれを再び横断します。したがって、これは非常に遅くなります。

より良いアプローチは、ListIteratorを使用してリストをトラバースし、挿入を実行することです。このインターフェイスは、現在の位置に要素を挿入するために使用できるadd()メソッドを定義します。

1
Greg Brown

com.google.common.collect.TreeMultiset をご覧ください。

これは事実上、同じ値の複数のインスタンスを許可するソートされたセットです。

それは、あなたがやろうとしていることに対する素晴らしい妥協です。挿入はArrayListよりも安価ですが、それでもバイナリ/ツリー検索の検索のメリットは得られます。

1
DanJ

ログ(N)時間の複雑さで簡単に実行できます。すべての値を反復処理する必要はありません。バイナリ検索を使用して、ソートされたリンクリストに値を追加できます。その関数の上限の位置に値を追加するだけです。コードを確認してください。

    public static int ubound(LinkedList<Integer> ln, int x) {
        int l = 0;
        int h = ln.size();
        while (l < h) {
            int mid = (l + h) / 2;
            if (ln.get(mid) <= x) l = mid + 1;
            else h = mid;
        }
        return l;
    }

    public void solve() 
    {
        LinkedList<Integer> ln = new LinkedList<>();
        ln.add(4);
        ln.add(6);
        ln.add(ubound(ln, 5), 5);
        out.println(ln);

    }

出力:[4、5、6]

あなたはバイナリ検索についてもっと学ぶことができます: https://www.topcoder.com/community/data-science/data-science-tutorials/binary-search/

0
NIKUNJ KHOKHAR

順序の基準を理解して、データを挿入する場所を見つける必要があります。

簡単な方法は、挿入位置をブルートフォース検索することです(リストを通過する、バイナリ検索...)。

データの性質がわかっている場合の別の方法は、挿入位置を見積もり、チェックの数を減らすことです。たとえば、「Zorro」を挿入し、リストがアルファベット順に並んでいる場合は、リストの後ろから開始するか、または文字がどこにあるかを推定します(おそらく最後に向かって)。これがどこから来てどのように分布しているかがわかっている場合、これは数に対しても機能します。これは補間検索と呼ばれます: http://en.wikipedia.org/wiki/Interpolation_search

バッチ挿入についても検討してください。大量のデータをすばやく挿入する場合は、一度に多くの挿入を行い、その後は1回だけソートすることを検討してください。

0

リンクされたリストは、SortedListのより良い実装ではありません

また、新しい要素を追加するたびにすべてのリストを並べ替えるのは効率的ではありません。最善の方法は、要素を必要な場所(正しい位置)に直接挿入することです。このため、すべての位置をループして、この番号が属する場所を見つけて挿入するか、Collections.binarySearchを使用して、この高度に最適化された検索アルゴリズムでこのジョブを実行できます。

BinarySearchは、オブジェクトがリストにある場合はオブジェクトのインデックスを返します(必要に応じて、ここで重複を確認できます)、または(-(挿入ポイント)-1)オブジェクトがまだリストにない場合(および挿入ポイントは順序を維持するためにオブジェクトを配置する必要があるインデックス)

0
Atrakeur