1. 자주 사용하는 자료구조 List, Map, Set 비교 요약 (Java Collection - 1 복습)
1) List: 요소의 순서가 중요하고, 중복을 허용해야 한다면 List
- 순서가 있는 데이터의 컬렉션이다.
- 중복된 요소를 포함할 수 있다.
- 인덱스를 사용하여 요소에 접근할 수 있다.
- 일반적으로 배열 형태로 구현된다.
- Java에서는 ArrayList, LinkedList 등이 List 인터페이스를 구현하는 클래스이다.
2) Map: 키-값 쌍을 저장하고, 키를 기반으로 값을 검색해야 한다면 Map
- 키-값(key-value) 쌍의 데이터를 저장하는 컬렉션이다.
- 순서가 정의되어 있지 않다.
- 키는 중복될 수 없지만, 값은 중복될 수 있다.
- 키를 사용하여 값을 검색하고, 변경할 수 있다.
- Java에서는 HashMap, LinkedHashMap, TreeMap 등이 Map 인터페이스를 구현하는 클래스이며, 일반적으로 HashMap 형태로 구현한다.
3) Set: 중복되지 않는 요소들의 집합을 다루고, 순서가 중요하지 않다면 Set
- 중복되지 않는 요소들의 컬렉션이다.
- 순서가 정의되어 있지 않다.
- 요소 간의 관계는 순서가 아닌 동등성(equality)에 의해 결정된다.
- 값을 검색하거나 변경하기 위해 인덱스를 사용할 수 없다.
- Java에서는 HashSet, LinkedHashSet, TreeSet 등이 Set 인터페이스를 구현하는 클래스이며, 일반적으로 HashSet 형태로 구현된다.
2. 자주 사용하는 데이터 구조 세부 파악 (ArrayList, HashMap, HashSet)
1) ArrayList
- ArrayList는 동적 배열로 구현되어 있으며, 크기를 동적으로 조정할 수 있다.
- 요소들을 인덱스를 통해 접근할 수 있고, 순서가 유지된다.
- 중복된 요소를 허용한다.
- 요소를 추가하거나 삭제하는 작업이 빈번한 경우에 적합하다.
ArrayList<String> list = new ArrayList<>();
list.add("사과");
list.add("바나나");
list.add("딸기");
// 리스트 전체 출력: 기존의 for-each 문 사용
for (String fruit : list) {
System.out.println(fruit);
}
// 람다식 적용
list.forEach(fruit -> System.out.println(fruit));
// 사과 개수 확인
long appleCount = list.stream().filter(fruit -> fruit.equals("사과")).count();
System.out.println("사과 개수: " + appleCount);
// 사과 존재 여부 확인
boolean isAppleExist = list.stream().anyMatch(fruit -> fruit.equals("사과"));
System.out.println("사과 존재 여부: " + isAppleExist);
2) HashMap
- HashMap은 키-값 쌍으로 데이터를 저장하는 해시 테이블 기반의 구조이다.
- 키는 중복되지 않으며, 값은 중복될 수 있다.
- 해시 함수를 사용하여 데이터에 접근하므로 매우 빠른 검색 속도를 제공한다.
- 데이터를 효율적으로 검색하고자 할 때 적합하다.
HashMap<String, Integer> map = new HashMap<>();
map.put("사과", 10);
map.put("바나나", 5);
map.put("딸기", 3);
// 리스트 전체 출력
map.forEach((fruit, quantity) -> System.out.println(fruit + ": " + quantity));
// 사과 개수 확인
int count = map.getOrDefault("사과", 0);
System.out.println("사과 개수: " + count);
// 사과 존재 여부 확인
boolean isAppleExist = map.containsKey("사과");
System.out.println("사과 존재 여부: " + isAppleExist);
3) HashSet
- HashSet은 중복된 요소를 허용하지 않는 데이터 구조이다.
- 해시 테이블을 사용하여 요소를 저장하므로 중복된 요소를 효율적으로 제거한다.
- 요소의 순서를 보장하지 않는다.
- 요소의 존재 여부를 빠르게 확인하고자 할 때 적합하다.
HashSet<String> set = new HashSet<>();
set.add("사과");
set.add("바나나");
set.add("딸기");
// 리스트 전체 출력
set.forEach(fruit -> System.out.println(fruit));
// 사과의 존재 여부 확인
boolean isAppleExist = set.contains("사과");
if (isAppleExist) {
System.out.println("사과가 존재합니다.");
}
// 사과 개수 확인
long appleCount = set.stream().filter(fruit -> fruit.equals("사과")).count();
System.out.println("사과 개수: " + appleCount);
3. 반복자 Iterator
1) 정의
반복자(Iterator)는 Java Collection Framework에서 컬렉션 내의 요소들을 순차적으로 탐색하는 데 사용되는 인터페이스이다. 반복자를 통해 컬렉션의 요소에 접근하고 수정할 수 있다.
2) 사용 방법
ArrayList<String> list = new ArrayList<>();
list.add("사과");
list.add("바나나");
list.add("딸기");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String fruit = iterator.next();
if(fruit.equals("바나나"){
iterator.remove();
}
System.out.println(fruit);
}
- Iterator 인터페이스는 java.util 패키지에 정의되어 있다.
- Iterator 객체는 컬렉션의 첫 번째 요소 앞에 위치하고, next() 메서드를 호출하여 요소를 차례로 반환한다.
- hasNext() 메서드는 다음 요소의 존재 여부를 확인하며, 요소가 있는 경우 true를 반환한다.
- remove() 메서드를 사용하여 현재 요소를 삭제할 수 있다.
3) 반복자를 사용한 데이터 참조 vs foreach문을 통한 데이터 직접 참조
Java Collection Framework의 데이터를 참조할 때 실제로는 반복자와 foreach 루프를 모두 사용할 수 있다.
대부분의 상황에서는 foreach 루프를 사용하여 직접 데이터를 참조하는 것이 더 편리하고 가독성이 좋다. foreach 루프는 반복자를 사용하는 코드보다 간결하며, 개발자가 직접 반복자를 다루는 부분을 신경쓰지 않아도 되기 때문이다.
종종 데이터를 삭제하거나 변경해야 하는 경우에는 반복자를 사용하는 것이 유용할 수 있다. 반복자는 컬렉션의 요소를 안전하게 삭제할 수 있도록 지원하며, 일부 컬렉션(ArrayList, LinkedList 등 순차적 데이터 구조)에서는 수정 작업에 반복자를 사용하는 것이 권장된다.
따라서 대부분의 경우에는 foreach 루프를 사용하여 데이터를 참조하고, 데이터를 삭제하거나 변경해야 하는 경우에는 반복자를 사용하는 것이 일반적이다.
4. 컬렉션을 이용한 정렬 및 찾기
1) 기초지식: Comparator<T> Interface
Comparator<T> 인터페이스Comparator<T>는 두 개의 객체를 비교하는 데 사용되는 인터페이스이다. Comparator<T>를 구현하여 사용자 지정 비교 로직을 구현하고, 이를 정렬 알고리즘 등에 전달하여 객체의 순서를 기준으로 작업을 수행할 수 있다. 즉, 정렬이나 정렬 기준을 지정하는 데 사용된다.
*Comparator<T> 인터페이스 원형
public interface Comparator<T> {
int compare(T o1, T o2);
// ...
}
compare 메서드는 두 개의 객체를 비교하여 순서를 결정한다. 이 메서드는 아래와 같은 반환 값의 의미를 갖는다.
- 음수 값: o1은 o2보다 작다.
- 0: o1과 o2는 같다.
- 양수 값: o1은 o2보다 크다.
2) 정렬(Sorting)
자바 프레임워크에서 제공하는 정렬 기능은 주로 Collections 클래스와 Arrays 클래스에서 찾을 수 있다.
(1) Collections 클래스
- Collections.sort(List<T> list)
- 이 메서드는 주어진 리스트를 기본적으로 오름차순으로 정렬한다.
- 리스트의 요소는 Comparable 인터페이스를 구현한 객체들이어야 한다. 이 인터페이스를 구현한 객체들은 자연적인 순서를 갖고 있어 정렬이 가능하다.
- 정렬은 리스트 내의 객체들을 변경하며, 반환값은 void이다.
- Collections.sort(List<T> list, Comparator<? super T> c)
- 이 메서드는 주어진 리스트를 주어진 Comparator를 사용하여 정렬한다.
- Comparator 객체 c는 T 타입의 객체들을 비교하는 로직을 담은 객체이다.
- Comparator를 통해 비교 로직을 커스터마이징할 수 있기 때문에 객체의 자연적인 순서와 다른 기준으로 정렬할 수 있다.
- 정렬은 리스트 내의 객체들을 변경하며, 반환값은 void이다.
(2) Arrays 클래스
- Arrays.sort(T[] arr)
- 이 메서드는 주어진 배열을 기본적으로 오름차순으로 정렬한다.
- 배열의 요소는 Comparable 인터페이스를 구현한 객체들이어야 한다.
- 정렬은 배열 내의 요소들을 변경한다.
- Arrays.sort(T[] arr, Comparator<? super T> c)
- 이 메서드는 주어진 배열을 주어진 Comparator를 사용하여 정렬한다.
- Comparator 객체 c는 T 타입의 객체들을 비교하는 로직을 담은 객체이다.
- 정렬은 배열 내의 요소들을 변경한다.
3) 찾기(Searching)
자바 프레임워크에서 제공하는 찾기 기능은 주로 Collections 클래스와 Arrays 클래스에서 찾을 수 있다.
(1) Collections 클래스
- Collections.binarySearch(List<? extends T> list, T key)
- 이 메서드는 주어진 리스트에서 이진 검색을 사용하여 특정 요소를 찾는다.
- 리스트는 이미 정렬되어 있어야 한다.
- T는 검색할 객체들의 타입이다.
- key는 찾고자 하는 요소이다.
- 반환값은 찾은 요소의 인덱스이다. 찾지 못한 경우에는 -(삽입 포인트 + 1)의 값을 반환한다.
- Collections.binarySearch(List<? extends T> list, T key, Comparator<? super T> c)
- 이 메서드는 주어진 리스트에서 이진 검색을 사용하여 특정 요소를 찾는다.
- 리스트는 이미 정렬되어 있어야 한다.
- T는 검색할 객체들의 타입이다.
- key는 찾고자 하는 요소이다.
- c는 T 타입의 객체들을 비교하는 로직을 담은 Comparator 객체이다.
- 반환값은 찾은 요소의 인덱스이다. 찾지 못한 경우에는 -(삽입 포인트 + 1)의 값을 반환한다.
(2) Arrays 클래스
- Arrays.binarySearch(T[] arr, T key)
- 이 메서드는 주어진 배열에서 이진 검색을 사용하여 특정 요소를 찾는다.
- 배열은 이미 정렬되어 있어야 한다.
- T는 검색할 객체들의 타입이다.
- key는 찾고자 하는 요소이다.
- 반환값은 찾은 요소의 인덱스이다. 찾지 못한 경우에는 -(삽입 포인트 + 1)의 값을 반환한다.
- Arrays.binarySearch(T[] arr, T key, Comparator<? super T> c)
- 이 메서드는 주어진 배열에서 이진 검색을 사용하여 특정 요소를 찾는다.
- 배열은 이미 정렬되어 있어야 합니다.
- T는 검색할 객체들의 타입입니다.
- key는 찾고자 하는 요소이다.
- c는 T 타입의 객체들을 비교하는 로직을 담은 Comparator 객체입니다.
- 반환값은 찾은 요소의 인덱스이다. 찾지 못한 경우에는 -(삽입 포인트 + 1)의 값을 반환한다.
4) sort(), binarySearch() 메소드 세부 분석
(1) sort() 메소드
public static <T> void sort(List<T> list, Comparator<? super T> c)
- Comparator<? super T> c에서 <? super T>는 T 타입이거나 T의 상위 타입을 나타낸다. 이것은 Comparator 객체 c가 T 타입 또는 T를 상속하거나 구현한 타입들과 비교할 수 있음을 의미한다. 따라서, sort 메서드는 T 타입의 객체들을 정렬하는 데 사용되며, Comparator 객체는 T 타입 또는 T의 상위 타입과 비교할 수 있는 로직을 담고 있어야 한다.
- 이 메서드는 주어진 리스트를 주어진 Comparator를 사용하여 정렬한다.
- Comparator를 통해 비교 로직을 커스터마이징할 수 있기 때문에 객체의 자연적인 순서와 다른 기준으로 정렬할 수 있다.
- 정렬은 리스트 내의 객체들을 변경하며, 반환값은 void이다.
(2) binarySearch() 메소드
public static <T> int binarySearch(List<? extends T> list, T key, Comparator<? super T> c)
- List<? extends T> list에서 <? extends T>는 T 타입 또는 T의 하위 타입들을 나타낸다. 이것은 list에 T 타입 또는 T를 상속한 타입의 객체들을 저장할 수 있음을 의미한다. T 타입 또는 T의 하위 타입들과 key를 비교하고자 할 때, Comparator 객체 c는 T 타입 또는 T의 상위 타입과 비교할 수 있는 로직을 담고 있어야 한다. 그리고, 반환값은 찾은 요소의 인덱스이며, list에 저장된 객체들은 T 타입 또는 T의 하위 타입들이어야 한다.
- list는 이미 정렬되어 있어야 하며, 해당 메서드는 주어진 리스트에서 이진 검색을 사용하여 특정 요소를 찾는다.
- Comparator 를 통해 객체들을 비교하는 방식을 커스터마이징할 수 있다.
- 반환값은 찾은 요소의 인덱스이다. 찾지 못한 경우에는 -(삽입 포인트 + 1)의 값을 반환한다. 삽입 포인트는 해당 요소를 삽입할 때 리스트의 정렬 순서를 유지할 수 있는 위치이다.
'자바(Java)' 카테고리의 다른 글
Java - 메소드 참조와 Optional 클래스 (0) | 2023.08.11 |
---|---|
Java - 람다식 (0) | 2023.08.11 |
Java Collection - 1 (0) | 2023.07.19 |
Java Generic (0) | 2023.07.03 |
Java 싱글톤 패턴(SingleTon Pattern) / 게터&세터(Getter & Setter) (0) | 2023.03.03 |