[java] Java에서 정렬 된 배열 목록

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

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

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

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

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

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

public boolean add (Object o)

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

이제 계약을 파기하고 추가 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);


답변

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


답변

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


답변

너무 무거울 수 있지만 GlazedLists 에는 테이블 또는 JList의 모델로 사용하기에 완벽한 SortedList 가 있습니다.