study/Java

Map, Stack, Queue

으녕오리 2025. 4. 14. 01:03

1. 컬렉션 프레임워크 - Map 소개

 

Map은

  • 키-값 쌍을 저장하는 자료 구조
  • 순서 보장 X, 키는 중복 X, 값은 중복 O
  • 키를 통해 값을 빠르게 검색 가능
  • 자바는 HashMap, TreeMap, LinkedHashMap 등 다양한 Map 구현체를 제공한다.
    이 중 HashMap을 가장 많이 사용한다.

 

Map 인터페이스의 주요 메서드

메서드 설명
put(K key, V value) 키와 값을 저장. 같은 키가 있으면 값을 덮어씀.
putIfAbsent(K key, V value) 키가 없을 때만 값을 저장. 기존 값이 있으면 무시.
get(Object key) 해당 키에 연결된 값을 반환.
getOrDefault(Object key, V defaultValue) 키가 없으면 기본값을 반환.
remove(Object key) 해당 키와 값을 제거.
containsKey(Object key) 키 존재 여부 확인.
containsValue(Object value) 값 존재 여부 확인.
keySet() 모든 키를 Set으로 반환. 반복 처리에 유용.
entrySet() 키-값 쌍을 Set<Map.Entry<K,V>>로 반환. 전체 순회에 자주 사용.
isEmpty() 맵이 비어 있는지 확인.

 

Entry

Entry는 키-값의 쌍으로 이루어진 간단한 객체이다.

 

키 목록 조회 Set<String> keySet = studentMap.keySet()

Map의 key는 중복 허용 X

∴ Map의 모든 key 목록을 조회하는 keySet()을 호출 -> 중복을 허용하지 않는 자료 구조인 Set을 반환

 

값 목록 조회 Collection<Integer> values = studentMap.values()

Map의 값 목록은 중복 O, 순서 보장 X 이므로 Set과 List로 반환 X

∴ Collection으로 반환한다.

 

putIfAbsent()

Map의 같은 키에 다른 값을 저장하면, 기존 값을 교체한다.

putIfAbsent() -> 키에 값이 없는 경우에만 데이터가 저장된다.

 

2. 컬렉션 프레임워크 - Map 구현체

 

Map은 인터페이스이므로 직접 인스터스 생성은 불가하고, Map 인터페이스를 구현한 여러 클래스를 통해 사용할 수 있다.

ex) HashMap, TreeMapLinkedHashMap

 

Set vs Map

  • Set 과 Map 은 거의 같다. 단지 옆에 Value의 유무 차이일 뿐이다.
  • 실제로 자바 HashSet  구현은 대부분 HashMap 구현을 가져다 사용한다.
  • Map 에서 Value 비워두면 Set 으로 사용할 있다.
  • HashMap, LinkedHashMap, TreeMap의 특징은 각각 Set에서 학습한 내용과 거의 같다.
  • Set과 비교해서 Map은
    • Key를 사용하여 해시 코드를 생성한다.
    • Entry를 사용해서 Key, Value를 묶어서 저장한다.
  • 주의! Map의 Key로 사용되는 객체는 hashCode(), equals()를 반드시 구현해야 한다.
  • 실무에서는 Map이 필요한 경우, HashMap을 많이 사용한다.
    그리고 순서 유지, 정렬의 필요에 따라서 LinkedHashMap, TreeMap을 선택한다.

    • 이렇게 해시를사용해서 키와 값을 저장하는 자료 구조를 일반적으로 해시 테이블이라 한다.
    • HashSet  해시 테이블의 주요 원리를 사용하지만,
      - 저장 방식 대신 키만 저장하는 특수한 형태의해시 테이블이라고 생각하면 된다.

 

코드로 확인해보는 HashMap, LinkedHashMap, TreeMap  특징

더보기
import java.util.*;
public class JavaMapMain {
    public static void main(String[] args) {
        run(new HashMap<>());
        run(new LinkedHashMap<>());
        run(new TreeMap<>());
    }
    private static void run(Map<String, Integer> map) {
        System.out.println("map = " + map.getClass());
        map.put("C", 10);
        map.put("B", 20);
        map.put("A", 30);
        map.put("1", 40);
        map.put("2", 50);
        Set<String> keySet = map.keySet();
        Iterator<String> iterator = keySet.iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            System.out.print(key + "=" + map.get(key) + " ");
        }
        System.out.println();
    }
}

 

실행 결과

map = class java.util.HashMap
A=30 1=40 B=20 2=50 C=10

map = class java.util.LinkedHashMap
C=10 B=20 A=30 1=40 2=50

map = class java.util.TreeMap
1=40 2=50 A=30 B=20 C=10
  • HashMap : 순서 보장 X
  • LinkedHashMap : 키를 기준으로 입력한 순서 보장 O
  • TreeMap : 값을 기준으로 정렬

 

3. 스택 자료 구조

스택 구조 (후입 선출, LIFO, Last In First Out)

  • 1(넣기) -> 2(넣기) -> 3(넣기) -> 3(빼기) -> 2(빼기) -> 1(빼기) (나중에 입력한 값이 먼저 나온다.)
  • push 스택에 값을 넣는 것, pop 스택에서 값을 꺼내는 것
더보기
import java.util.Stack;
//Stack은 사용하면 안됨 -> Deque를 대신 사용
public class StackMain {
    public static void main(String[] args) {
        Stack<Integer> stack = new Stack<>();
        stack.push(1);
        stack.push(2);
        stack.push(3);
        System.out.println(stack);
// 다음 꺼낼 요소 확인(꺼내지 않고 단순 조회만)
        System.out.println("stack.peek() = " + stack.peek());
// 스택 요소 뽑기
        System.out.println("stack.pop() = " + stack.pop());
        System.out.println("stack.pop() = " + stack.pop());
        System.out.println("stack.pop() = " + stack.pop());
        System.out.println(stack);
    }
}

 

실행 결과

[1, 2, 3]
stack.peek() = 3
stack.pop() = 3
stack.pop() = 2
stack.pop() = 1
[]

주의! Stack 클래스는 사용 X -> Deque를 사용하는 것이 좋다.

 

4. 큐 자료 구조

큐 구조(선입 선출, FIFO, First In First Out)

  • 1(넣기) -> 2(넣기) -> 3(넣기) -> 1(빼기) -> 2(빼기) -> 3(빼기) (먼저 입력한 값이 먼저 나온다.)
  • offer 큐에 값을 넣는 것, poll 큐에서 값을 꺼내는 것

 

컬렉션 프레임워크 Queue

  • Queue 인터페이스는 List, Set 과 같이 Collection 의 자식이다.
  • Queue 대표적인 구현체는 ArrayDeque, LinkedList 있다.
  • LinkedList Deque List 인터페이스를 모두 구현한다.
더보기
import java.util.ArrayDeque;
import java.util.LinkedList;
import java.util.Queue;
public class QueueMain {
    public static void main(String[] args) {
        Queue<Integer> queue = new ArrayDeque<>();
//Queue<Integer> queue = new LinkedList<>();
//데이터 추가
        queue.offer(1);
        queue.offer(2);
        queue.offer(3);
        System.out.println(queue);
//다음 꺼낼 데이터 확인(꺼내지 않고 단순 조회만)
        System.out.println("queue.peek() = " + queue.peek());
//데이터 꺼내기
        System.out.println("poll = " + queue.poll());
        System.out.println("poll = " + queue.poll());
        System.out.println("poll = " + queue.poll());
        System.out.println(queue);
    }
}

 

실행 결과

[1, 2, 3]
queue.peek() = 1
poll = 1
poll = 2
poll = 3
[]

 

5. Deque 자료 구조

Deque

  • 양쪽 끝에서 요소를 추가하거나 제거할 수 있다.
  • Deque 일반적인 (Queue) 스택(Stack) 기능을 모두 포함하고 있다.

 

  • offerFirst() : 앞에 추가한다.
  • offerLast() : 뒤에 추가한다.
  • pollFirst() : 앞에서 꺼낸다.
  • pollLast() : 뒤에서 꺼낸다.
더보기
import java.util.ArrayDeque;
import java.util.Deque;
public class DequeMain {
    public static void main(String[] args) {
        Deque<Integer> deque = new ArrayDeque<>();
//Deque<Integer> deque = new LinkedList<>();
// 데이터 추가
        deque.offerFirst(1);
        System.out.println(deque);
        deque.offerFirst(2);
        System.out.println(deque);
        deque.offerLast(3);
        System.out.println(deque);
        deque.offerLast(4);
        System.out.println(deque);
// 다음 꺼낼 데이터 확인(꺼내지 않고 단순 조회만)
        System.out.println("deque.peekFirst() = " + deque.peekFirst());
        System.out.println("deque.peekLast() = " + deque.peekLast());
// 데이터 꺼내기
        System.out.println("pollFirst = " + deque.pollFirst());
        System.out.println("pollFirst = " + deque.pollFirst());
        System.out.println("pollLast = " + deque.pollLast());
        System.out.println("pollLast = " + deque.pollLast());
        System.out.println(deque);
    }
}

 

실행 결과

[1]
[2, 1]
[2, 1, 3]
[2, 1, 3, 4]
deque.peekFirst() = 2
deque.peekLast() = 4
pollFirst = 2
pollFirst = 1
pollLast = 4
pollLast = 3
[]

Deque 구현체와 성능 테스트

Deque 대표적인 구현체는 ArrayDeque, LinkedList  있다. 중에 ArrayDeque  모든 면에서 르다.

 

6. Deque Stack, Queue

Deque 양쪽으로 데이터를 입력하고 출력할 있으므로, 스택과 큐의 역할을 모두 수행할 있다.

Deque Stack  Queue 로 사용하기 위한 메서드 이름까지 제공한다.

 

Deque - Stack

Stack 자료 구조가 필요하면, Deque에 ArrayDeque 구현체를 사용한다.

더보기
import java.util.ArrayDeque;
import java.util.Deque;
public class DequeStackMain {
    public static void main(String[] args) {
        Deque<Integer> deque = new ArrayDeque<>();
//Deque<Integer> deque = new LinkedList<>();
// 데이터 추가
        deque.push(1);
        deque.push(2);
        deque.push(3);
        System.out.println(deque);
// 다음 꺼낼 데이터 확인(꺼내지 않고 단순 조회만)
        System.out.println("deque.peek() = " + deque.peek());
// 데이터 꺼내기
        System.out.println("pop = " + deque.pop());
        System.out.println("pop = " + deque.pop());
        System.out.println("pop = " + deque.pop());
        System.out.println(deque);
    }
}

 

실행 결과

[3, 2, 1]
deque.peek() = 3
pop = 3
pop = 2
pop = 1
[]

 

Deque - Queue

Deque 인터페이스는 Queue 인터페이스의 자식이기 때문에,
단순히 Queue  기능만 필요하면 Queue 인터페이스를 사용하고, 많은 기능이 필요하다면 Deque 인터페이스를 사용하면 된다.

구현체로는 성능이 빠른 ArrayDeque 사용한다.

더보기
import java.util.ArrayDeque;
import java.util.Deque;
public class DequeQueueMain {
    public static void main(String[] args) {
        Deque<Integer> deque = new ArrayDeque<>();
//Deque<Integer> deque = new LinkedList<>();
//데이터 추가
        deque.offer(1);
        deque.offer(2);
        deque.offer(3);
        System.out.println(deque);
//다음 꺼낼 데이터 확인(꺼내지 않고 단순 조회만)
        System.out.println("deque.peek() = " + deque.peek());
//데이터 꺼내기
        System.out.println("poll = " + deque.poll());
        System.out.println("poll = " + deque.poll());
        System.out.println("poll = " + deque.poll());
        System.out.println(deque);
    }
}

 

실행 결과

[1, 2, 3]
deque.peek() = 1
poll = 1
poll = 2
poll = 3
[]