The SortedSet Interface

Dev.Hammy·2024년 1월 17일

Java API

목록 보기
8/15

SortedSet은 요소를 오름차순(ascending)으로 유지하고 요소의 자연 순서(natural ordering)에 따라 정렬되거나 SortedSet 생성 시 제공된 Comparator에 따라 정렬되는 Set입니다. 일반적인 Set 작업 외에도 SortedSet 인터페이스는 다음에 대한 작업을 제공합니다.

  • Range view — SortedSet에 대한 임의의 범위 작업을 허용합니다.
  • Endpoint — SortedSet의 첫 번째 또는 마지막 요소를 반환합니다.
  • Comparator access — 세트를 정렬하는 데 사용되는 Comparator가 있는 경우 이를 반환합니다.
    SortedSet 인터페이스의 코드는 다음과 같습니다.
public interface SortedSet<E> extends Set<E> {

	// Range-view
    SortedSet<E> subSet(E fromElement, E toElement);
    SortedSet<E> headSet(E toElement);
    SortedSet<E> tailSet(E fromElement);
    
    // Endpoints
    E first();
    E last();
    
    // Comparator access
    Comparator<? super E> comparator();
 }

Set Operations

Set에서 상속받은 SortedSet의 연산은 두 가지 예외를 제외하고 정렬된 세트와 일반 세트에서 동일하게 동작합니다.

  • iterator 작업에서 반환된 Iterator는 정렬된 집합을 순서대로 순회(traverses)합니다.
  • toArray가 반환한 배열에는 정렬된 세트의 요소가 순서대로 포함되어 있습니다.

인터페이스가 이를 보장하지는 않지만 Java 플랫폼의 SortedSet 구현의 toString 메소드는 정렬된 세트의 모든 요소를 순서대로 포함하는 문자열을 반환합니다.

Standard Constructors (표준 생성자)

관례에 따라(By convention) 모든 범용 Collection 구현은 Collection을 취하는 표준 변환 생성자(standard conversion constructor)를 제공합니다. SortedSet 구현도 예외는 아닙니다. TreeSet에서 이 생성자는 요소를 자연스러운 순서(natural ordering)에 따라 정렬하는 인스턴스를 만듭니다. 이것은 아마도 실수였을 것입니다. 지정된 컬렉션이 SortedSet 인스턴스인지 여부를 동적(dynamically)으로 확인하고, 그렇다면 동일한 기준(comparator 또는 natural ordering)에 따라 새 TreeSet을 정렬하는 것이 더 나을 것입니다. TreeSet은 이전과 같은 접근 방식을 취했기 때문에 SortedSet을 사용하고 동일한 기준에 따라 정렬된 동일한 요소가 포함된 새 TreeSet을 반환하는 생성자도 제공합니다. 이 두 생성자 중 호출되는 생성자(및 정렬 기준이 유지되는지 여부)를 결정하는 것은 런타임 유형이 아니라 인수의 컴파일 타임 유형입니다.

SortedSet 구현은 또한 규칙에 따라 Comparator를 취하고 지정된 Comparator에 따라 정렬된 빈 집합을 반환하는 생성자를 제공합니다. 이 생성자에 null이 전달되면 자연 순서에 따라 요소를 정렬하는 집합이 반환됩니다.


글에서 언급된 "두 가지 예외"는 문맥에 따라 혼란스러울 수 있습니다. 여기서 "예외"라는 용어는 보통 "예외적인 상황"을 나타내지 않고, 특별한 경우나 예외적인 규칙을 의미하는 것이 아닙니다. 오히려 "특징"이나 "차이"를 의미하는 것으로 이해해야 합니다. 따라서 해당 문장에서 언급된 "두 가지 예외"는 특별한 상황을 나타내는 것이 아니라, "두 가지 특징" 또는 "두 가지 차이점"을 의미합니다.

다시 살펴보겠습니다:

  1. "iterator" 작업에서 반환된 Iterator는 정렬된 집합을 순서대로 순회합니다.

    • 이는 SortedSet이라는 이름에서 알 수 있듯이, 정렬된 순서를 유지하는 특징을 강조하고 있습니다. 일반적인 Set과는 달리 SortedSet에서 반복자(Iterator)를 통해 순회할 때는 정렬된 순서로 요소에 접근할 수 있습니다.
  2. toArray가 반환한 배열에는 정렬된 세트의 요소가 순서대로 포함되어 있습니다.

    • toArray 메서드를 사용하여 SortedSet의 요소를 배열로 변환할 때도 정렬된 순서를 유지합니다. 이는 정렬된 순서를 요구하는 상황에서 유용합니다.

그리고 "Standard Constructors (표준 생성자)" 부분에서는 SortedSet 구현 클래스 중 하나인 TreeSet이 제공하는 생성자에 대한 설명이 나와있습니다. 여기서 언급된 내용은 다음과 같습니다:

  • TreeSetSortedSet을 구현한 클래스 중 하나로, 요소를 자연 순서(natural ordering)에 따라 정렬하는 인스턴스를 만듭니다.
  • TreeSet의 생성자 중 일부는 지정된 Comparator에 따라 정렬된 빈 집합을 반환하거나, null이 전달되면 자연 순서에 따라 정렬하는 집합을 반환합니다.

이는 TreeSet이 정렬된 순서를 유지하며 동작하는데 있어서의 특징을 설명하고 있습니다.


Range-view Operations

range-view 작업은 List 인터페이스에서 제공하는 작업과 다소 유사하지만 한 가지 큰 차이점이 있습니다. sorted set의 range view는 backing sorted set이 직접 수정되는 경우에도 유효한 상태로 유지됩니다. 이는 sorted set의 range view endpoints이 List의 경우처럼 지원(backing) 컬렉션의 특정 요소가 아니라 요소 공간(space)의 절대 지점(absolute points)이기 때문에 가능합니다. sorted set의 range view는 실제로 요소 공간의 지정된 부분에 있는 set의 모든 부분을 보여주는 창(window)일 뿐입니다. range-view에 대한 변경 사항은 backing sorted set에 다시 기록되며 그 반대의 경우도 마찬가지입니다. 따라서 List의 range-views와 달리 sorted-set에 대한 range-view를 장기간 사용해도 괜찮습니다.

정렬된 세트는 세 가지 range view 작업을 제공합니다. 첫 번째 subSetsubList와 같은 두 개의 엔드포인트를 사용합니다. indices가 아닌 endpoint은 object이며 SetComparator 또는 해당 요소의 자연 순서( 집합이 자체적으로 정렬하는 데 사용하는 방식)를 사용하여 정렬된 집합의 요소와 비교 가능(comparable)해야 합니다. subList와 마찬가지로 range는 낮은 끝점(low endpoint)을 포함하지만 높은 끝점은 제외하여 절반만 열려 있습니다.

따라서 다음 코드 줄은 dictionary이라는 문자열 SortedSet에서 "doorbell"과 "pickle" 사이에("doorbell"을 포함하지만 "pickle"을 제외하고) 포함된 단어 수를 알려줍니다.

int count = dictionary.subSet("doorbell", "pickle").size();

같은 방식으로(in like manner) 다음 한 줄짜리 코드는 문자 f로 시작하는 모든 요소를 제거합니다.

dictionary.subSet("f", "g").clear();

비슷한 방법을 사용하여 각 문자로 시작하는 단어 수를 알려주는 표를 인쇄할 수 있습니다.

for (char ch = 'a'; ch <='z'; ) {
	String from = String.valueOf(ch++);
    String to = String.valueOf(ch);
    System.out.println(from + ": " + dictionary.subSet(from, to).size());
}

  • "f" : 큰 따옴표로 감싸진 문자열
  • 'f' : 작은 따옴표로 감싸진 단일 문자
  • String.valueOf(character) : String 클래스의 정적 메서드로서, 주어진 값을 문자열로 표현합니다
  • String from = String.valueOf(ch++); :현재 ch 값을 이용하여 문자열 from을 생성하고, 그 다음에 ch1 증가시킵니다. 따라서 from에는 현재 ch의 값이 문자열로 변환되어 들어가게 되고, ch 값은 다음 문자로 증가합니다.
  • String to = String.valueOf(ch);: to 문자열을 생성할 때 이미 ch 값이 증가했으므로, 현재 ch의 증가된 값이 문자열로 변환되어 to에 들어가게 됩니다.

열린 간격 대신 두 끝점을 모두 포함하는 닫힌 간격(closed interval)을 보려는 경우를 가정해 보겠습니다. 요소 유형이 요소 공간에서 주어진 값의 후속 항목 계산(calculation of the successor)을 허용하는 경우 lowEndpoint에서 후속 항목(highEndpoint)으로 subSet을 요청하기만 하면 됩니다. 완전히 명확하지는 않지만(not entirely obvious) String의 자연 순서에서 문자열 s의 후속 항목은 s + "\0"입니다. 즉, snull 문자가 추가됩니다.

따라서 다음 한 줄짜리 코드는 doorbell과 pickle을 포함하여 "doorbell"과 "pickle" 사이에 몇 개의 단어가 사전에 포함되어 있는지 알려줍니다.

count = dictionary.subSet("doorbell", "pickle\0").siae();

유사한 기술을 사용하여 끝점이 모두 포함되지 않은 열린 간격(open-interval)을 볼 수 있습니다. lowEndpoint에서 highEndpoint까지의 open-interval 뷰는 successor(lowEndpoint)에서 highEndpoint까지의 half-open 간격입니다. 다음을 사용하여 "doorbell"과 "pickle" 사이의 단어 수를 계산합니다(둘 다 제외).

count = dictionary.subSet("doorbell\0", "pickle").size();

SortedSet 인터페이스에는 두 가지 range-view 작업(headSettailSet)이 더 포함되어 있으며 둘 다 단일 Object 인수를 사용합니다. 전자는 지정된 객체를 포함하지 않는 backing SortedSet의 초기 부분에 대한 뷰를 반환합니다. 후자는 지정된 객체에서 시작하여 backing SortedSet의 끝까지 계속되는 backing SortedSet의 마지막 부분에 대한 뷰를 반환합니다. 따라서 다음 코드를 사용하면 사전을 두 개의 분리된 볼륨(a-m 및 n-z)으로 볼 수 있습니다.

SortedSet<String> volume1 = dictionary.headSet("n");
SortedSet<String> volume2 = dictionary.tailSet("n");

Endpoint Operations

SortedSet 인터페이스에는 정렬된 세트의 첫 번째 요소와 마지막 요소를 반환하는 작업이 포함되어 있습니다. 당연히 first 요소와 last 요소라고 합니다. 명백한 용도 외에도 lastSortedSet 인터페이스의 결함(deficiency)에 대한 해결 방법(workaround)을 허용합니다. SortedSet으로 하고 싶은 것 중 하나는 Set 내부로 가서 앞으로 또는 뒤로 반복(iterate)하는 것입니다. 내부에서 앞으로 나아가는 것은 충분히 쉽습니다. tailSet을 가져와서 반복하면 됩니다. 불행히도 뒤로 돌아가는 쉬운 방법은 없습니다.

다음 관용구는 요소 공간에서 지정된 객체 o보다 작은 첫 번째 요소를 얻습니다.

Object predecessor = ss.headSet(o).last();

이는 정렬된 집합 내부의 한 지점에서 한 요소를 뒤로 이동하는 좋은 방법입니다. 반복적으로 적용하여 뒤로 반복할 수도 있지만 이는 반환된 각 요소를 조회해야 하므로 매우 비효율적입니다.

Comparator Accessor

SortedSet 인터페이스에는 집합을 정렬하는 데 사용되는 Comparator를 반환하는 comparator라는 접근자 메서드가 포함되어 있습니다. 집합이 해당 요소의 자연 순서에 따라 정렬된 경우에는 null입니다. 이 방법은 정렬된 집합을 동일한 순서로 새 정렬된 집합에 복사할 수 있도록 제공됩니다. 이는 이전에 설명한 SortedSet 생성자에서 사용됩니다.

0개의 댓글