Programing

Java에서 정렬 된 배열 목록

lottogame 2020. 9. 25. 08:14
반응형

Java에서 정렬 된 배열 목록


이에 대한 빠른 답변을 찾을 수 없어서 당황 스럽습니다. 본질적으로 java.util.List인터페이스 를 구현 하지만 멤버를 정렬 된 순서로 저장 하는 Java의 데이터 구조를 찾고 있습니다. 노멀 ArrayList을 사용 Collections.sort()하여 사용할 수 있다는 것을 알고 있지만 가끔 내 목록에서 회원을 추가하고 자주 검색하는 시나리오가 있으며 경우에 따라 회원을 검색 할 때마다 정렬 할 필요가 없습니다. 새로운 것이 추가되었습니다. 누구든지 JDK 또는 타사 라이브러리에 존재하는 그런 것을 가리킬 수 있습니까?

편집 : 데이터 구조는 중복을 보존해야합니다.

ANSWER 's SUMMARY :이 모든 것이 매우 흥미롭고 많은 것을 배웠습니다. 특히 Aioobe는 위의 요구 사항 (주로 중복을 지원하는 정렬 된 java.util.List 구현)을 달성하기 위해 인내심을 가지고 언급 할 가치가 있습니다. 나는 그의 대답을 내가 요청한 것에 대해 가장 정확한 것으로 받아 들였고, 내가 요청한 것이 정확히 내가 필요로하는 것이 아니더라도 내가 찾고있는 것의 의미를 자극한다고 생각했다.

내가 요청한 문제는 List 인터페이스 자체와 인터페이스의 선택적 메서드 개념에 있습니다. javadoc을 인용하려면 :

이 인터페이스의 사용자는 목록에서 각 요소가 삽입되는 위치를 정확하게 제어 할 수 있습니다.

정렬 된 목록에 삽입하면 삽입 지점을 정확하게 제어 할 수 없습니다. 그런 다음 몇 가지 방법을 어떻게 처리할지 생각해야합니다. 가지고 add예를 들면 :

public boolean add (Object o)

 Appends the specified element to the end of this list (optional operation).

이제 1) 계약을 깨고 정렬 된 버전의 add를 구현하는 불편한 상황에 처하게되었습니다. 2) add목록 끝에 요소를 추가하고 정렬 된 순서를 깨뜨리는 것 3) add던지면서 (선택 사항으로 ) 나가기 UnsupportedOperationException및 정렬 된 순서로 항목을 추가하는 다른 방법을 구현.

옵션 3이 아마도 최고 일 수 있지만 사용할 수없는 add 메서드와 인터페이스에없는 또 다른 sortedAdd 메서드가있는 것은 좋지 않습니다.

기타 관련 솔루션 (특정 순서 없음) :

  • 내가 요청한 것보다 내가 필요한 것에 가장 가까운 java.util.PriorityQueue . 대기열은 제 경우에 객체 모음의 가장 정확한 정의는 아니지만 기능적으로 필요한 모든 것을 수행합니다.
  • net.sourceforge.nite.util.SortedList . 그러나이 구현은 add(Object obj)메서드 에서 정렬을 구현하여 List 인터페이스의 계약을 깨뜨리고 add(int index, Object obj). 일반적인 합의에 따르면 throw new UnsupportedOperationException()이 시나리오에서는 더 나은 선택이 될 수 있습니다.
  • Guava의 TreeMultiSet 중복을 지원하는 집합 구현
  • ca.odell.glazedlists.SortedList 이 클래스는 javadoc에주의 사항이 있습니다.Warning: This class breaks the contract required by List

최소한의 솔루션

여기에 "최소한"해결책이 있습니다.

class SortedArrayList<T> extends ArrayList<T> {

    @SuppressWarnings("unchecked")
    public void insertSorted(T value) {
        add(value);
        Comparable<T> cmp = (Comparable<T>) value;
        for (int i = size()-1; i > 0 && cmp.compareTo(get(i-1)) < 0; i--)
            Collections.swap(this, i, i-1);
    }
}

삽입은 선형 시간으로 실행되지만 어쨌든 ArrayList를 사용하여 얻을 수있는 것입니다 (삽입 된 요소의 오른쪽에있는 모든 요소는 한 방향 또는 다른 방향으로 이동해야합니다).

비교할 수없는 것을 삽입하면 ClassCastException이 발생합니다. (이것은 PriorityQueue또한 취한 접근 방식입니다 : 자연 순서에 의존하는 우선 순위 큐는 또한 비교할 수없는 객체의 삽입을 허용하지 않습니다 (그렇게하면 ClassCastException이 발생할 수 있습니다). )

재정의 List.add

정렬 된 방식으로 요소를 삽입 하는 재정의 List.add(또는 List.addAll그 문제) 는 인터페이스 사양을 직접 위반 하는 것 입니다. 수있는 일은이 메서드를 재정 의하여 UnsupportedOperationException.

문서에서 List.add:

boolean add(E e)
    이 목록의 끝에 지정된 요소를 추가합니다 (선택적 작업).

add두 버전, addAll및의 두 버전 모두에 동일한 추론이 적용됩니다 set. (모두 목록 인터페이스에 따른 선택적 작업입니다.)


일부 테스트

SortedArrayList<String> test = new SortedArrayList<String>();

test.insertSorted("ddd");    System.out.println(test);
test.insertSorted("aaa");    System.out.println(test);
test.insertSorted("ccc");    System.out.println(test);
test.insertSorted("bbb");    System.out.println(test);
test.insertSorted("eee");    System.out.println(test);

....인쇄물:

[ddd]
[aaa, ddd]
[aaa, ccc, ddd]
[aaa, bbb, ccc, ddd]
[aaa, bbb, ccc, ddd, eee]

사용 java.util.PriorityQueue.


SortedList 살펴보기

이 클래스는 정렬 된 목록을 구현합니다. 두 개체를 비교하고 그에 따라 개체를 정렬 할 수있는 비교기로 구성됩니다. 목록에 개체를 추가하면 올바른 위치에 삽입됩니다. 비교기에 따라 동일한 개체는이 목록에 추가 된 순서대로 목록에 포함됩니다. 비교기가 비교할 수있는 개체 만 추가합니다.


목록에 이미 비교기에 따라 동일한 개체가 포함되어있는 경우 새 개체가 이러한 다른 개체 바로 뒤에 삽입됩니다.


Guava의 TreeMultiSet을 사용해 볼 수 있습니다 .

 Multiset<Integer> ms=TreeMultiset.create(Arrays.asList(1,2,3,1,1,-1,2,4,5,100));
 System.out.println(ms);

목록은 일반적으로 항목이 추가되는 순서를 유지합니다. 확실히 목록이 필요합니까 , 아니면 정렬 된 세트 (예 TreeSet<E>:)가 괜찮습니까? 기본적으로 중복을 보존해야합니까?


Aioobe의 접근 방식은 갈 길입니다. 그래도 그의 솔루션에 대해 다음 개선을 제안하고 싶습니다.

class SortedList<T> extends ArrayList<T> {

    public void insertSorted(T value) {
        int insertPoint = insertPoint(value);
        add(insertPoint, value);
    }

    /**
     * @return The insert point for a new value. If the value is found the insert point can be any
     * of the possible positions that keeps the collection sorted (.33 or 3.3 or 33.).
     */
    private int insertPoint(T key) {
        int low = 0;
        int high = size() - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            Comparable<? super T> midVal = (Comparable<T>) get(mid);
            int cmp = midVal.compareTo(key);

            if (cmp < 0)
                low = mid + 1;
            else if (cmp > 0)
                high = mid - 1;
            else {
                return mid; // key found
            }
        }

        return low;  // key not found
    }
}

aioobe의 솔루션은 큰 목록을 사용할 때 매우 느려집니다. 목록이 정렬되어 있다는 사실을 사용하면 이진 검색을 사용하여 새 값에 대한 삽입 지점을 찾을 수 있습니다.

나는 또한 상속보다 컴포지션을 사용합니다.

SortedList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable

It might be a bit too heavyweight for you, but GlazedLists has a SortedList that is perfect to use as the model of a table or JList


You could subclass ArrayList, and call Collections.sort(this) after any element is added - you would need to override two versions of add, and two of addAll, to do this.

Performance would not be as good as a smarter implementation which inserted elements in the right place, but it would do the job. If addition to the list is rare, the cost amortised over all operations on the list should be low.


I think the choice between SortedSets/Lists and 'normal' sortable collections depends, whether you need sorting only for presentation purposes or at almost every point during runtime. Using a sorted collection may be much more expensive because the sorting is done everytime you insert an element.

If you can't opt for a collection in the JDK, you can take a look at the Apache Commons Collections


Since the currently proposed implementations which do implement a sorted list by breaking the Collection API, have an own implementation of a tree or something similar, I was curios how an implementation based on the TreeMap would perform. (Especialy since the TreeSet does base on TreeMap, too)

If someone is interested in that, too, he or she can feel free to look into it:

TreeList

Its part of the core library, you can add it via Maven dependency of course. (Apache License)

Currently the implementation seems to compare quite well on the same level than the guava SortedMultiSet and to the TreeList of the Apache Commons library.

But I would be happy if more than only me would test the implementation to be sure I did not miss something important.

Best regards!


I had the same problem. So I took the source code of java.util.TreeMap and wrote IndexedTreeMap. It implements my own IndexedNavigableMap:

public interface IndexedNavigableMap<K, V> extends NavigableMap<K, V> {
   K exactKey(int index);
   Entry<K, V> exactEntry(int index);
   int keyIndex(K k);
}

The implementation is based on updating node weights in the red-black tree when it is changed. Weight is the number of child nodes beneath a given node, plus one - self. For example when a tree is rotated to the left:

    private void rotateLeft(Entry<K, V> p) {
    if (p != null) {
        Entry<K, V> r = p.right;

        int delta = getWeight(r.left) - getWeight(p.right);
        p.right = r.left;
        p.updateWeight(delta);

        if (r.left != null) {
            r.left.parent = p;
        }

        r.parent = p.parent;


        if (p.parent == null) {
            root = r;
        } else if (p.parent.left == p) {
            delta = getWeight(r) - getWeight(p.parent.left);
            p.parent.left = r;
            p.parent.updateWeight(delta);
        } else {
            delta = getWeight(r) - getWeight(p.parent.right);
            p.parent.right = r;
            p.parent.updateWeight(delta);
        }

        delta = getWeight(p) - getWeight(r.left);
        r.left = p;
        r.updateWeight(delta);

        p.parent = r;
    }
  }

updateWeight simply updates weights up to the root:

   void updateWeight(int delta) {
        weight += delta;
        Entry<K, V> p = parent;
        while (p != null) {
            p.weight += delta;
            p = p.parent;
        }
    }

And when we need to find the element by index here is the implementation that uses weights:

public K exactKey(int index) {
    if (index < 0 || index > size() - 1) {
        throw new ArrayIndexOutOfBoundsException();
    }
    return getExactKey(root, index);
}

private K getExactKey(Entry<K, V> e, int index) {
    if (e.left == null && index == 0) {
        return e.key;
    }
    if (e.left == null && e.right == null) {
        return e.key;
    }
    if (e.left != null && e.left.weight > index) {
        return getExactKey(e.left, index);
    }
    if (e.left != null && e.left.weight == index) {
        return e.key;
    }
    return getExactKey(e.right, index - (e.left == null ? 0 : e.left.weight) - 1);
}

Also comes in very handy finding the index of a key:

    public int keyIndex(K key) {
    if (key == null) {
        throw new NullPointerException();
    }
    Entry<K, V> e = getEntry(key);
    if (e == null) {
        throw new NullPointerException();
    }
    if (e == root) {
        return getWeight(e) - getWeight(e.right) - 1;//index to return
    }
    int index = 0;
    int cmp;
    index += getWeight(e.left);

    Entry<K, V> p = e.parent;
    // split comparator and comparable paths
    Comparator<? super K> cpr = comparator;
    if (cpr != null) {
        while (p != null) {
            cmp = cpr.compare(key, p.key);
            if (cmp > 0) {
                index += getWeight(p.left) + 1;
            }
            p = p.parent;
        }
    } else {
        Comparable<? super K> k = (Comparable<? super K>) key;
        while (p != null) {
            if (k.compareTo(p.key) > 0) {
                index += getWeight(p.left) + 1;
            }
            p = p.parent;
        }
    }
    return index;
}

You can find the result of this work at http://code.google.com/p/indexed-tree-map/

TreeSet/TreeMap (as well as their indexed counterparts from the indexed-tree-map project) do not allow duplicate keys , you can use 1 key for an array of values. If you need a SortedSet with duplicates use TreeMap with values as arrays. I would do that.

참고URL : https://stackoverflow.com/questions/4031572/sorted-array-list-in-java

반응형