Collection
interface를 구현(implement)하는 클래스 또는 인터페이스다.Collection
은 모든 자료구조가 구현(implement)하는 인터페이스입니다. 아래 배우는 모든 자료구조에 해당하는 클래스, 인터페이스는 언제나 Collection
인터페이스를 구현하고 있다.
순서가 있는 나열된 데이터를 표현한다.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ListExample {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(5);
list.add(4);
list.add(11);
list.add(10);
System.out.println(list);
Collections.sort(list);
System.out.println(list);
System.out.println("size: " + list.size());
list.remove(4);
System.out.println(list);
int[] intArr = new int[3];
intArr[0] = 1;
intArr[1] = 5;
intArr[2] = 4;
int[] intArr2 = new int[5];
intArr2[0] = intArr[0];
intArr2[1] = intArr[1];
intArr2[2] = intArr[2];
intArr2[3] = 11;
intArr2[4] = 10;
for (int i = 1; i <= list.size(); i++) {
System.out.println(list.get(i));
}
for (int cur : list) {
System.out.println(cur);
}
}
}
list라는 변수는 실제로 Interface 타입으로 선언했기 때문에 interface에 있는 함수만 쓸 수 있다. 실제 로직은 ArrayList에 있는 로직으로 돌리겠지만.
Set은 순서를 유지하지 않는 데이터의 집합이며 데이터의 중복을 허용하지 않는다.
HashSet
은 Set 인터페이스를 구현한 대표적인 콜렉션이다. Set의 자료를 저장하고 조회할 때 HashTable을 이용해서 구현한다.import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class SetExample {
public static void main(String[] args) {
Set<Integer> integerSet = new HashSet<>();
integerSet.add(1);
integerSet.add(3);
integerSet.add(2);
integerSet.add(9);
integerSet.add(9);
System.out.println(integerSet);
Set<String> stringSet = new HashSet<>();
stringSet.add("LA");
stringSet.add("New York");
stringSet.add("LasVegas");
stringSet.add("San Francisco");
stringSet.add("Seoul");
System.out.println(stringSet);
stringSet.remove("Seoul");
System.out.println(stringSet);
System.out.println("exist LA?" + stringSet.contains("LA"));
List<String> removeTarget = new ArrayList<>();
removeTarget.add("LA");
removeTarget.add("New York");
stringSet.removeAll(removeTarget);
System.out.println(stringSet);
System.out.println("exist LA?" + stringSet.contains("LA"));
System.out.println("size: " + stringSet.size());
stringSet.clear();
System.out.println(stringSet);
}
}
Map은 키(key)와 값(value)을 하나의 데이터로 저장하는 특징을 가진다.
HashMap
은 Map 인터페이스를 구현한 대표적인 구현체다. HashTable로 구현되어있으며 데이터 검색에 O(1)의 시간복잡도로 조회할 수 있다.import java.util.HashMap;
import java.util.Map;
public class MapExample {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
map.put(1, "apple");
map.put(2, "berry");
map.put(3, "cherry");
map.put(100, "pineapple");
System.out.println(map);
Map<String, String> stringMap = new HashMap<>();
stringMap.put("first", "apple");
stringMap.put("second", "berry");
stringMap.putIfAbsent("second", "pineapple");
stringMap.putIfAbsent("third", "pineapple");
System.out.println(stringMap);
if (stringMap.containsKey("first")) {
System.out.println("exist!: " + stringMap.get("first"));
}
if (!stringMap.containsKey("noexist")) {
System.out.println("doesn't exist!");
}
for (String key : stringMap.keySet()) {
System.out.println(stringMap.get(key));
}
System.out.println(stringMap.values());
stringMap.remove("first");
System.out.println(stringMap);
stringMap.clear();
System.out.println("size: " + stringMap.size());
}
}
선언부분에 <> : 이 부분은 제네릭표시다.
Stack 은 마지막에 저장
한 데이터를 가장 먼저 꺼내는
자료구조다. 이것을 LIFO(Last In First Out) 라고 한다.
아래 그림을 보자. 먼저 삽입된 값인 17이 가장 아래로, 이후 삽입되는 값은 그 위에 쌓이기 시작한다. 이후, pop()을 통해 값을 반환할 때도 마지막에 삽입된 값인 45가 가장 먼저 반환된다.
이미지 출처 : https://coccagerman.medium.com/data-structures-stacks-7ec3c3247af1
웹브라우저의 앞페이지 이동 뒤페이지 이동 / 그릇 쌓기 등.
public class Main {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>();
stack.push(1);
stack.push(3);
stack.push(5);
stack.push(7);
System.out.println(stack); // Stack을 출력
System.out.println(stack.peek()); // Stack의 가장 상단 값을 출력(삭제는 하지 않는다.)
stack.pop(); // Stack의 가장 상단 값을 제거한다.
System.out.println(stack);
System.out.println(stack.size()); // Stack의 크기를 반환합.
System.out.println(stack.contains(1)); // Stack에 1이라는 값이 있으면 true를, 그렇지 않으면 false를 반환
System.out.println(stack.empty()); // STack이 비어있으면 true를, 그렇지 않으면 false를 반환
System.out.println(stack);
}
}
Queue 는 처음에 저장한 데이터를 가장 먼저 꺼내게 되는 FIFO(First In First Out)
구조로 되어있다.
아래 그림을 보자. 큐는 양 쪽 끝의 통로가 뚫려있다고 생각하면 된다. 가장 먼저 들어온 Data가 가장 먼저 반환된다.
큐
를 활용하는 방식은 우선순위 큐, 원형 우선순위 큐, 원형 큐 등 다양하게 존재한다.
이미지 출처 : https://www.programiz.com/java-programming/queue
public class QueueExample {
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<>();
queue.add(1);
queue.add(3);
queue.add(5);
System.out.println(queue);
System.out.println("first element : " + queue.peek());
System.out.println(queue.size());
System.out.println("first element : " + queue.poll());
System.out.println(queue.size());
System.out.println("first element : " + queue.peek());
queue.offer(2);
queue.offer(4);
queue.offer(8);
System.out.println(queue);
int lastSizeOfQueue = queue.size();
for(int i=0; i< lastSizeOfQueue; i++ ){
queue.poll();
}
System.out.println("is Empty : "+ queue.isEmpty());
}
}
실무에서는 단순히 Stack, Queue 클래스 대신에 ArrayDeque을 많이 사용한다. 기본 Stack, Queue의 기능을 모두 포함하면서도 성능이 더 좋다.
이미지 출처 : https://www.interviewbit.com/data-structure-interview-questions/
이미지 출처 : https://codegym.cc/groups/posts/java-deque
The name “Deque” means “Double Ended Queue”. “Deque” is pronounced like a "deck" of cards and you know what? It is somewhat similar to a real deck of cards: you may take a card from the bottom or the top of such a deck.
이미지 출처 : https://codegym.cc/groups/posts/java-deque
So you can enqueue and dequeue from both ends of a Java Deque, that means you can use a Deque as both queue and stack.
public class Main {
public static void main(String[] args) {
ArrayDeque<Integer> arrayDeque = new ArrayDeque<>(); // ArrayDeque를 이용한 선언(제네릭스 이용)
arrayDeque.addFirst(1);
arrayDeque.addFirst(2);
arrayDeque.addFirst(3);
arrayDeque.addFirst(4); // arrayDeque의 앞에 값을 삽입
System.out.println(arrayDeque);
arrayDeque.addLast(0); // arrayDeque의 끝에 값을 삽입
System.out.println(arrayDeque);
arrayDeque.offerFirst(10); // addFirst와 비슷하지만 큐의 크기 문제가 생길 때, offerFirst는 false를,
// addFrist는 exception을 반환합니다.
System.out.println(arrayDeque);
arrayDeque.offerLast(-1); // arrayDeque의 끝에 값을 삽입
System.out.println(arrayDeque);
System.out.println(arrayDeque.size()); // 7
System.out.println(arrayDeque.removeFirst()); // 첫번째 값을 제거하면서 그 값을 리턴
System.out.println(arrayDeque.removeLast()); // 마지막 값을 제거하면서 그 값을 리턴
System.out.println(arrayDeque);
System.out.println(arrayDeque.size()); // 5
System.out.println(arrayDeque.pollFirst()); // 첫번째 값을 반환 및 제거하면서 그 값을 리턴
System.out.println(arrayDeque);
System.out.println(arrayDeque.size()); // 4
System.out.println(arrayDeque.pollLast()); // 마지막 값을 반환 및 제거하면서 그 값을 리턴
System.out.println(arrayDeque);
System.out.println(arrayDeque.size()); // 3
System.out.println(arrayDeque.peekFirst()); // 첫번째 값을 반환, 제거하지 않음
System.out.println(arrayDeque.peekLast()); // 마지막 값을 반환, 제거하지 않음
System.out.println(arrayDeque.size()); // 3
}
}