본문 바로가기
Java

[Java] 기본 문법 정리 - 정렬, 스택 & 큐, 우선순위 큐, 해시맵, 해시셋

by clolee 2025. 3. 19.

8. 정렬 (Arrays.sort(), Collections.sort(), Comparator)

정렬은 코딩테스트에서 탐색, 최적화, 조합 문제에서 매우 자주 등장하는 개념.
자바에서는 기본적으로 Arrays.sort()(배열 정렬), Collections.sort()(리스트 정렬)과 같은 메서드를 제공함.


📍 1) 기본 정렬 (Arrays.sort())

  • Arrays.sort(배열)을 사용하면 오름차순(ASC) 정렬됨.
  • 내부적으로 Dual-Pivot QuickSort 알고리즘 사용 (평균 O(N logN))

배열 정렬 예제


  
import java.util.Arrays;
public class SortingExample {
public static void main(String[] args) {
int[] arr = {5, 3, 8, 1, 2};
Arrays.sort(arr); // 기본 오름차순 정렬
System.out.println(Arrays.toString(arr)); // [1, 2, 3, 5, 8]
}
}

📍 2) 리스트 정렬 (Collections.sort())

  • 리스트를 정렬할 때는 Collections.sort(리스트) 사용.

리스트 정렬 예제


  
import java.util.ArrayList;
import java.util.Collections;
public class ListSortingExample {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(5);
list.add(3);
list.add(8);
list.add(1);
list.add(2);
Collections.sort(list); // 오름차순 정렬
System.out.println(list); // [1, 2, 3, 5, 8]
}
}

📍 3) 내림차순 정렬 (Comparator.reverseOrder())

배열 내림차순 정렬


  
import java.util.Arrays;
import java.util.Collections;
public class DescendingSortExample {
public static void main(String[] args) {
Integer[] arr = {5, 3, 8, 1, 2};
Arrays.sort(arr, Collections.reverseOrder()); // 내림차순 정렬
System.out.println(Arrays.toString(arr)); // [8, 5, 3, 2, 1]
}
}

📌 Collections.reverseOrder()는 Integer[] 배열에서만 사용 가능
📌 int[] 배열에서는 사용 불가 → Integer[]로 변환해야 함!


📍 4) Comparator를 활용한 정렬 (커스텀 정렬)

  • Comparator를 사용하면 사용자 정의 정렬 기준을 적용할 수 있음.
  • 예를 들어, 객체 리스트를 정렬할 때 활용.

예제: 객체 리스트 정렬 (나이순 정렬)


  
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + " (" + age + "세)";
}
}
public class CustomSortExample {
public static void main(String[] args) {
ArrayList<Person> people = new ArrayList<>();
people.add(new Person("Alice", 25));
people.add(new Person("Bob", 20));
people.add(new Person("Charlie", 30));
Collections.sort(people, new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
return p1.age - p2.age; // 나이 기준 오름차순 정렬
}
});
System.out.println(people); // [Bob (20세), Alice (25세), Charlie (30세)]
}
}

📌 compare(a, b)에서
✔️ a - b → 오름차순
✔️ b - a → 내림차순


9. 스택과 큐 (Stack, Queue, Deque)

스택과 큐는 자료를 저장하고 꺼내는 방식이 다른 자료구조.

📍 1) Stack (LIFO: 후입선출)

  • push() → 데이터 추가
  • pop() → 마지막 데이터 제거 & 반환
  • peek() → 마지막 데이터 확인 (제거 X)
  • isEmpty() → 스택이 비었는지 확인

스택 사용 예


  
import java.util.Stack;
public class StackExample {
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>();
stack.push(10);
stack.push(20);
stack.push(30);
System.out.println(stack.pop()); // 30 (가장 나중에 들어온 값 제거)
System.out.println(stack.peek()); // 20 (제거 안 하고 보기만)
}
}

📍 2) Queue (FIFO: 선입선출)

  • offer() → 데이터 추가
  • poll() → 첫 번째 데이터 제거 & 반환
  • peek() → 첫 번째 데이터 확인 (제거 X)

큐 사용 예


  
import java.util.LinkedList;
import java.util.Queue;
public class QueueExample {
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<>();
queue.offer(10);
queue.offer(20);
queue.offer(30);
System.out.println(queue.poll()); // 10 (가장 먼저 들어온 값 제거)
System.out.println(queue.peek()); // 20 (제거 안 하고 보기만)
}
}

📍 3) Deque (양방향 큐)

  • Deque는 앞뒤로 추가/삭제가 가능한 자료구조
  • addFirst(), addLast() → 앞/뒤에 추가
  • removeFirst(), removeLast() → 앞/뒤에서 제거
  • peekFirst(), peekLast() → 앞/뒤 확인 (제거 X)

Deque 사용 예


  
import java.util.Deque;
import java.util.LinkedList;
public class DequeExample {
public static void main(String[] args) {
Deque<Integer> deque = new LinkedList<>();
deque.addFirst(10);
deque.addLast(20);
deque.addFirst(5);
System.out.println(deque.pollFirst()); // 5 (앞에서 제거)
System.out.println(deque.pollLast()); // 20 (뒤에서 제거)
}
}

10. 우선순위 큐 (PriorityQueue)

우선순위 큐는 가장 작은 값(기본값) 또는 가장 큰 값이 먼저 나오는 큐.

  • 기본값: 최소 힙 (작은 값이 먼저 나온다)
  • 내림차순 정렬: PriorityQueue<>(Collections.reverseOrder())

우선순위 큐 사용 예


  
import java.util.PriorityQueue;
public class PriorityQueueExample {
public static void main(String[] args) {
PriorityQueue<Integer> pq = new PriorityQueue<>(); // 최소 힙
pq.offer(30);
pq.offer(10);
pq.offer(20);
System.out.println(pq.poll()); // 10 (가장 작은 값 제거)
System.out.println(pq.poll()); // 20
}
}

📌 최대 힙(큰 값이 먼저 나오는 큐)


  
PriorityQueue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder());

11. 해시맵과 해시셋 (HashMap, HashSet)

해시맵(HashMap)과 해시셋(HashSet)은 해싱(Hashing) 기법을 활용한 자료구조.
둘 다 빠른 데이터 검색과 저장 (O(1) 평균 시간복잡도)이 장점.


📌 1) HashMap (키-값 저장, 중복 키 X)

특징

  • 키(Key)와 값(Value) 쌍으로 저장
  • 키는 중복 불가능, 값은 중복 가능
  • 빠른 데이터 검색 가능 (평균 O(1))

📍 (1) HashMap 기본 사용


  
import java.util.HashMap;
public class HashMapExample {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<>();
// 데이터 추가 (put)
map.put("apple", 3);
map.put("banana", 2);
map.put("cherry", 5);
// 값 조회 (get)
System.out.println("바나나 개수: " + map.get("banana")); // 2
// 키 존재 여부 확인 (containsKey)
System.out.println("apple이 있는가? " + map.containsKey("apple")); // true
// 키-값 삭제 (remove)
map.remove("apple");
// 크기 확인 (size)
System.out.println("맵 크기: " + map.size()); // 2
// 모든 키-값 출력 (for-each)
for (String key : map.keySet()) {
System.out.println(key + ": " + map.get(key));
}
}
}

📌 출력 결과


  
바나나 개수: 2
apple이 있는가? true
크기: 2
banana: 2
cherry: 5

📍 (2) HashMap 정렬 (TreeMap 이용)

HashMap은 키의 순서를 보장하지 않음,
TreeMap을 사용하면 키를 자동 정렬 가능 (오름차순 정렬)


  
import java.util.TreeMap;
public class TreeMapExample {
public static void main(String[] args) {
TreeMap<String, Integer> sortedMap = new TreeMap<>();
sortedMap.put("banana", 2);
sortedMap.put("apple", 3);
sortedMap.put("cherry", 5);
System.out.println(sortedMap); // {apple=3, banana=2, cherry=5}
}
}

📌 2) HashSet (중복 없는 집합, 순서 없음)

특징

  • 중복을 허용하지 않는 데이터 저장
  • 순서를 보장하지 않음
  • 빠른 데이터 검색 가능 (평균 O(1))

📍 (1) HashSet 기본 사용


  
import java.util.HashSet;
public class HashSetExample {
public static void main(String[] args) {
HashSet<Integer> set = new HashSet<>();
// 데이터 추가 (add)
set.add(10);
set.add(20);
set.add(10); // 중복 추가 (무시됨)
// 포함 여부 확인 (contains)
System.out.println("20이 있는가? " + set.contains(20)); // true
// 데이터 삭제 (remove)
set.remove(10);
// 크기 확인 (size)
System.out.println("집합 크기: " + set.size()); // 1
// 모든 요소 출력 (for-each)
for (int num : set) {
System.out.println(num);
}
}
}

📌 출력 결과


  
20 있는가? true
집합 크기: 1
20

📌 중복된 값은 자동 제거됨!


📍 (2) TreeSet (자동 정렬되는 집합)

  • HashSet은 순서를 보장하지 않음,
  • TreeSet은 자동 오름차순 정렬 지원

  
import java.util.TreeSet;
public class TreeSetExample {
public static void main(String[] args) {
TreeSet<Integer> sortedSet = new TreeSet<>();
sortedSet.add(30);
sortedSet.add(10);
sortedSet.add(20);
System.out.println(sortedSet); // [10, 20, 30]
}
}

📌 3) HashMap vs HashSet 비교

HashMap HashSet

저장 방식 키-값(Key-Value) 쌍 저장 값(Value)만 저장
중복 허용 키(Key)는 중복 불가능, 값(Value)은 중복 가능 중복 값 저장 불가
순서 보장 X (순서 없음) X (순서 없음)
정렬 지원 X (TreeMap 사용하면 가능) X (TreeSet 사용하면 가능)
탐색 속도 O(1) (해시 테이블 이용) O(1) (해시 테이블 이용)

🎯 정리

1️⃣ HashMap키-값 저장, 키 중복 불가, 빠른 탐색 가능
2️⃣ HashSet값 저장, 중복 허용 안 됨, 빠른 탐색 가능
3️⃣ TreeMap, TreeSet자동 정렬이 필요할 때 사용

📌 코딩 테스트에서 HashMap, HashSet은 빠른 탐색 & 중복 처리에서 유용하게 사용됨! 🚀

댓글