🔌 SPARTA/Courses

배열과 컬렉션

eunjiom 2026. 1. 28. 20:57

🗒️ 플로우차트

1️⃣ 1차원 배열

1. 배열의 개념과 특징

 

1) 개념

  • 동일한 타입의 데이터를 연속된 공간에 저장하는 자료구조
  • 예) 숫자들을 차례대로 저장하는 상자

2) 특징

  • 인덱스로 위치가 정해져 있음
  • 고정된 크기
  • 연속된 메모리 공간: 데이터는 메모리에 연속적으로 저장

3) 배열 선언 및 각 요소 접근 예시

// 배열 선언과 초기화
int[] numbers = new int[5];  // 크기가 5인 정수 배열 생성
int[] scores = {90, 80, 85, 95, 88};  // 초기값과 함께 배열 생성

// 배열 요소 접근
numbers[0] = 10;  // 첫 번째 요소에 10 저장
int thirdScore = scores[2];  // 세 번째 요소 값 읽기

// for문을 이용한 배열 순회 (인덱스로 값 참조)
for(int i = 0; i < scores.length; i++) {
    System.out.println(scores[i]);
}

// for-each문을 이용한 배열 순회 (직접 값 참조)
for(int score : scores) {
    System.out.println(score);
}

 

2. 배열의 탐색 방법

 

1) 순차 탐색의 개념과 구현

  • 개념: 배열의 처음부터 끝까지 하니씩 요소를 확인하며 값을 찾는 검색 방법
  • 구현 코드
public class SequentialSearch {
    public static int sequentialSearch(int[] arr, int target) {
        // 1. 배열의 첫 번째 요소부터 시작
        // 1-1. 배열을 순차적으로 탐색하기 위한 반복문 시작
        for (int i = 0; i < arr.length; i++) {
            // 1-2. 현재 인덱스의 요소에 접근
            
            // 2. 찾고자 하는 값(target)과 현재 요소 비교
            // 2-1. target과 현재 요소가 일치하면, 현재 인덱스 반환
            if (arr[i] == target) {
                return i;
            }
            // 2-2. 일치하지 않으면, 다음 인덱스로 이동하여 1-2부터 반복
        }
        
        // 3. 배열 탐색 완료 후 결과 처리
        // 3-1. 배열 끝까지 탐색했는데 찾지 못한 경우 실패(-1) 반환
        return -1;
    }

    public static void main(String[] args) {
        // 테스트를 위한 예제 배열과 찾을 값 설정
        int[] arr = {4, 2, 7, 1, 9, 3};
        int target = 7;
        
        // 순차 탐색 수행 및 결과 출력
        int result = sequentialSearch(arr, target);
        if (result != -1) {
            System.out.println("찾은 위치: " + result);
        } else {
            System.out.println("값을 찾지 못했습니다.");
        }
    }
}
  • 시간 복잡도: O(N)

2) 이진 탐색의 개념과 구현

  • 개념: 정렬된 배열에서 효율적으로 원하는 값을 찾음 / 탐색 범위를 절반으로 줄여가며 검색(빠른 결과)
  • 조건: 정렬된 배열에서만 가용 가능 / 정렬되지 않은 배열은 정렬 후 사용
  • 시간 복잡도: 정렬된 배열 O(log N) / 정렬되지 않은 배열 O(N log n)
  • 구현 코드
public class Solution {
    private static int binarySearch(int[] arr, int target) {
        // 1. 탐색 범위의 시작점과 끝점 설정
        // 1-1. left는 배열의 첫 번째 인덱스로 설정
        int left = 0;
        // 1-2. right는 배열의 마지막 인덱스로 설정
        int right = arr.length - 1;

        // 2. 탐색 범위가 유효한 동안 반복
        while (left <= right) {
            // 2-1. 중간 위치 계산
            int mid = (left + right) / 2;

            // 3. 중간 값과 target 비교 후 처리
            // 3-1. 중간 값이 target과 같으면 해당 인덱스 반환
            if (arr[mid] == target) {
                return mid;
            }
            // 3-2. 중간 값이 target보다 크면 오른쪽 범위를 줄임
            else if (arr[mid] > target) {
                right = mid - 1;
            }
            // 3-3. 중간 값이 target보다 작으면 왼쪽 범위를 줄임
            else {
                left = mid + 1;
            }
        }

        // 4. 탐색 완료 후 결과 처리
        // 4-1. 찾지 못한 경우 실패(-1) 반환
        return -1;
    }

    public static void main(String[] args) {
        // 테스트를 위한 정렬된 예제 배열과 찾을 값 설정
        int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9}; //정렬된 배열이어야 함
        int target = 7;

        // 이진 탐색 수행 및 결과 출력
        int result = binarySearch(arr, target);
        if (result != -1) {
            System.out.println("찾은 위치: " + result);
        } else {
            System.out.println("값을 찾지 못했습니다.");
        }
    }
}

 

3) 투 포인터의 개념과 구현

  • 개념: 두 개의 포인터를 이용하여 배열 탐색
  • 연속된 구간의 합이나 특정 조건을 만족하는 부분을 찾을 때 사용
  • 시간 복잡도: O(N)
  • 두 수의 합이 특정 값이 되는 쌍 찾기
    : 합이 작으면 왼쪽 증가 / 크면 오른쪽 감소
  • 코드 구현
public class Solution {
   public static boolean findTwoSum(int[] arr, int target) {
       // 1. 포인터 초기화
       // 1-1. left 포인터는 배열의 첫 번째 인덱스로 설정
       int left = 0;
       // 1-2. right 포인터는 배열의 마지막 인덱스로 설정
       int right = arr.length - 1;
       
       // 2. 두 포인터가 교차하기 전까지 반복
       while (left < right) {
           // 2-1. 현재 두 포인터가 가리키는 값의 합 계산
           int sum = arr[left] + arr[right];
           
           // 2-2. 합과 목표값 비교
           // 3. 합과 목표값 비교 후 포인터 이동
           // 3-1. 합이 목표값과 같으면 true 반환 (쌍을 찾음)
           if (sum == target) {
               System.out.println("찾은 두 수: " + arr[left] + ", " + arr[right]);
               return true;
           } 
           // 3-2. 합이 목표값보다 작으면 left 포인터를 오른쪽으로 이동 (더 큰 값 필요)
           else if (sum < target) {
               left++;
           }
           // 3-3. 합이 목표값보다 크면 right 포인터를 왼쪽으로 이동 (더 작은 값 필요) 
           else {
               right--;
           }
       }
       
       // 4. 탐색 완료 후 결과 처리
       // 4-1. 목표값을 만드는 쌍을 찾지 못한 경우 false 반환
       return false;
   }

   public static void main(String[] args) {
       // 테스트를 위한 예제 배열과 목표 합 설정
       int[] arr = {4, 1, 8, 7, 3, 2};  // 정렬되지 않은 배열
       int target = 10;  // 찾고자 하는 합
       
       // 투 포인터 탐색 수행 및 결과 출력
       System.out.println("원본 배열: " + Arrays.toString(arr));
       System.out.println("목표 합: " + target);
       boolean result = findTwoSum(arr, target);
       System.out.println("합이 " + target + "이 되는 두 수가 " + 
           (result ? "존재합니다." : "존재하지 않습니다."));
   }
}

 

3. 정렬 알고리즘

 

1) 버블 정렬

  • 배열을 반복적으로 순회하며 인접한 두 요소를 비교하는 정렬
  • 배열을 앞에서부터 차례대로 두 개씩 비교 > 순서가 잘못된 경우 위치를 바꿔주는 과정
  • 시간 복잡도: O(N2제곱)
  • 장점: 이해하기 쉽고 구현하기 간단함 / 작은 데이터를 정렬할 때 좋음
    단점: 시간 복잡도가 큼 / 데이터가 많으면 시간이 오래 걸림
  • 구현 코드
public class BubbleSort {
    public static void bubbleSort(int[] arr) {
        int n = arr.length;
        
        // 1. 외부 반복문: 정렬 과정(패스)을 몇 번 반복할지를 결정
        // - 배열의 크기만큼 반복하며, 한 번 반복할 때마다 하나의 숫자가 최종 위치를 찾음
        for (int i = 0; i < n - 1; i++) {
            
            // 2. 내부 반복문: 실제 비교와 교환이 일어나는 과정
            // - 이웃한 두 숫자를 비교
            // - 범위가 점점 줄어듦 (n-i-1): 이미 정렬된 요소는 제외
            for (int j = 0; j < n - i - 1; j++) {
                // 3. 인접한 두 요소 비교 및 교환
                // - 왼쪽 숫자가 오른쪽 숫자보다 크면 두 숫자의 위치를 바꿈
                if (arr[j] > arr[j + 1]) {
                    // 이웃한 두 수 자리 교환
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
    }

    // 배열 출력을 위한 유틸리티 메서드
    public static void printArray(int[] arr) {
        for (int num : arr) {
            System.out.print(num + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        // 예시 배열 [5, 3, 8, 2]로 테스트
        int[] arr = {5, 3, 8, 2};
        
        System.out.println("정렬 전 배열:");
        printArray(arr);
        
        // 버블 정렬 수행
        bubbleSort(arr);
        
        System.out.println("정렬 후 배열:");
        printArray(arr);
    }
}

 

2) 계수 정렬

  • 숫자를 직접 비교하지 않고 숫자가 몇 번 나왔는지 세어서 정렬(개수만큼 나열)
  • 시간 복잡도: O(N+K) > N = 데이터 개수, K = 데이터 중 최댓값
  • 장점: 양의 정수 데이터의 정렬 속도가 매우 빠름 / 비교 연산이 없어 구현이 간단
    단점: 0 이상의 정수만 정렬 가능 / 데이터 범위만큼 추가 메모리 필요 / 최댓값이 매우 크면 비효율적
  • 구현 코드
public class CountingSort {
    public static void countingSort(int[] arr) {
        // 1. 최댓값 찾기 - O(N)
        int max = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
        }

        // 2. 카운팅 배열 생성 및 초기화
        int[] counts = new int[max + 1];

        // 3. 숫자 세기 - O(N)
        for (int num : arr) {
            counts[num]++;
        }

        // 4. 결과 배열 생성
        int index = 0;
        for (int i = 0; i <= max; i++) {
            while (counts[i] > 0) {
                arr[index] = i;
                index++;
                counts[i]--;
            }
        }
    }

    // 배열 출력을 위한 유틸리티 메서드
    public static void printArray(int[] arr) {
        for (int num : arr) {
            System.out.print(num + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        // 예시 배열 [4, 1, 3, 1, 2]로 테스트
        int[] arr = {4, 1, 3, 1, 2};

        System.out.println("정렬 전 배열:");
        printArray(arr);

        // 계수 정렬 수행
        countingSort(arr);

        System.out.println("정렬 후 배열:");
        printArray(arr);
    }
}

 

3) 안정 계수정렬

  • 안정 정렬: 동일한 값을 가진 요소들의 원래 순서를 유지하는 정렬 방식
  • 계수 정렬 > 안정 정렬 구현 = 누적 합 배열 사용
  • 시간 복잡도: O(N+K)
  • 구현 코드
public class StableCountingSort {
    public static int[] stableCountingSort(int[] arr) {
        // 1. 카운팅 배열 생성
        // 원본 배열의 최댓값 찾기
        int max = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
        }
        
        // 원본 배열의 최댓값 크기만큼의 카운팅 배열을 생성
        int[] counts = new int[max + 1];
        
        // 원본 배열을 순회하면서 각 숫자가 몇 번 등장했는지 카운팅 배열에 기록
        for (int num : arr) {
            counts[num]++;
        }
        
        // 2. 누적 합 배열 생성
        // 카운팅 배열과 같은 크기의 누적 합 배열을 생성
        int[] cumulative = new int[max + 1];
        
        // 카운팅 배열을 순회하면서 각 위치까지의 누적 합을 계산
        cumulative[0] = counts[0];
        for (int i = 1; i <= max; i++) {
            cumulative[i] = cumulative[i - 1] + counts[i];
        }
        
        // 3. 결과 배열 생성
        // 결과 배열을 원본 배열과 같은 크기로 생성
        int[] result = new int[arr.length];
        
        // 원본 배열을 뒤에서부터 순회
        for (int i = arr.length - 1; i >= 0; i--) {
            int num = arr[i];
            // 현재 숫자를 num이라 할 때, (cumulative[num] - 1)을 인덱스로 하여 결과 배열에 num을 저장
            result[cumulative[num] - 1] = num;
            // cumulative[num]의 값을 1 감소
            cumulative[num]--;
        }
        
        return result;
    }

    // 배열 출력을 위한 유틸리티 메서드
    public static void printArray(int[] arr) {
        for (int num : arr) {
            System.out.print(num + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        // 예시 배열 [4, 1, 3, 1, 2]로 테스트
        int[] arr = {4, 1, 3, 1, 2};
        
        System.out.println("정렬 전 배열:");
        printArray(arr);
        
        // 안정 계수 정렬 수행하고 결과 받기
        int[] sortedArr = stableCountingSort(arr);
        
        System.out.println("정렬 후 배열:");
        printArray(sortedArr);
    }
}

 

4) 정렬 알고리즘 비교

2️⃣ 2차원 배열

1. 개념과 특징

 

1) 개념

  • 표처럼 생긴 배열
  • 가로(행) + 세로(열)

2) 특징

  • 행과 열로 위치를 찾음
  • 크기가 정해져 있음: 만들 때 행 개수, 열 개수 정함
  • 메모리에 차례대로 저장
  • 예시)
// 2차원 배열 선언과 초기화
int[][] matrix = new int[3][4]; // 3행 4열의 2차원 배열 생성 

// 초기 값을 바로 넣어 3행 3열 배열 생성
int[][] scores = {
    {90, 85, 95},
    {75, 80, 85},
    {88, 92, 96}
};

// 2차원 배열 요소 접근하기
matrix[0][1] = 10;       // 1행 2열 위치에 10을 저장
int score = scores[1][2]; // scores[1][2]는 2행 3열 값, 즉 85

// 중첩 for문을 이용한 2차원 배열 순회
for (int i = 0; i < scores.length; i++) {
    for (int j = 0; j < scores[i].length; j++) {
        System.out.print(scores[i][j] + " ");
    }
    System.out.println(); // 각 행 출력 후 줄바꿈
}

// for-each문을 이용한 2차원 배열 순회
for (int[] row : scores) {    // scores 배열에서 한 행씩 꺼내기
    for (int value : row) {   // 해당 행에서 각 값 꺼내기
        System.out.print(value + " ");
    }
    System.out.println();
}

 

2. 행렬 순회 방법

 

1) 행 우선 순회

  • 가로로 보고 다음 줄로 내려가기
  • for(행)
      for(열)
  • 시간 복잡도: O(NxM) > N = 행의 개수, M = 열의 개수
  • 구현 코드
public class MatrixTraversal {
    public static void rowMajorOrder(int[][] arr) {
        int rows = arr.length;
        int cols = arr[0].length;
        
        // 1. 행 반복문(바깥쪽)과 열 반복문(안쪽) 설정
        // 1-1. 행 인덱스 i는 0부터 행의 크기-1까지 반복
        for (int i = 0; i < rows; i++) {
            // 1-2. 열 인덱스 j는 0부터 열의 크기-1까지 반복
            for (int j = 0; j < cols; j++) {
                // 2. 현재 위치(i,j)의 원소에 접근
                // 2-1. arr[i][j] 형태로 각 원소에 접근
                System.out.print(arr[i][j] + " ");
            }
            // 3. 다음 행으로 이동하여 반복
            // 3-1. 현재 행의 순회가 끝나면 다음 행으로 이동
            System.out.println();
        }
    }

    public static void main(String[] args) {
        int[][] matrix = {
            {1, 2, 3},
            {4, 5, 6},
            {7, 8, 9}
        };
        System.out.println("행 우선 순회 결과:");
        rowMajorOrder(matrix);
    }
}

 

2) 열 우선 순회

  • 세로로 위에서 아래로 보고 옆 열로 이동
  • for(열)
      for(행)
  • 시간 복잡도: O(NxM)
  • 구현 코드
public class MatrixTraversal {
    public static void columnMajorOrder(int[][] arr) {
        int rows = arr.length;
        int cols = arr[0].length;
        
        // 1. 열 반복문(바깥쪽)과 행 반복문(안쪽) 설정
        // 1-1. 열 인덱스 j는 0부터 열의 크기-1까지 반복
        for (int j = 0; j < cols; j++) {
            // 1-2. 행 인덱스 i는 0부터 행의 크기-1까지 반복
            for (int i = 0; i < rows; i++) {
                // 2. 현재 위치(i,j)의 원소에 접근
                // 2-1. arr[i][j] 형태로 각 원소에 접근
                // 2-2. 각 열을 위에서 아래로 순회
                System.out.print(arr[i][j] + " ");
            }
            // 3. 다음 열로 이동하여 반복
            // 3-1. 현재 열의 순회가 끝나면 다음 열로 이동
            System.out.println();
        }
    }

    public static void main(String[] args) {
        int[][] matrix = {
            {1, 2, 3},
            {4, 5, 6},
            {7, 8, 9}
        };
        System.out.println("열 우선 순회 결과:");
        columnMajorOrder(matrix);
    }
}

 

3) 지그재그 순회

  • 홀수 행은 ->, 짝수 행은 <-
  • if(행이 짝수) 정방향
    else 역방향
  • 시간 복잡도: O(NxM)
  • 구현 코드
public class MatrixTraversal {
    public static void zigzagOrder(int[][] arr) {
        int rows = arr.length;
        int cols = arr[0].length;
        
        // 1. 행 인덱스에 따른 순회 방향 결정
        for (int i = 0; i < rows; i++) {
            // 1-1. 행 인덱스(i)가 짝수인 경우: 왼쪽에서 오른쪽으로 순회
            if (i % 2 == 0) {
                // 2-1. 짝수 행: j를 0부터 열의 크기-1까지 증가
                for (int j = 0; j < cols; j++) {
                    System.out.print(arr[i][j] + " ");
                }
            }
            // 1-2. 행 인덱스(i)가 홀수인 경우: 오른쪽에서 왼쪽으로 순회
            else {
                // 2-2. 홀수 행: j를 열의 크기-1부터 0까지 감소
                for (int j = cols - 1; j >= 0; j--) {
                    System.out.print(arr[i][j] + " ");
                }
            }
            // 3. 다음 행으로 이동하여 반복
            // 3-1. 현재 행의 순회가 끝나면 다음 행으로 이동
            System.out.println();
        }
    }

    public static void main(String[] args) {
        int[][] matrix = {
            {1, 2, 3},
            {4, 5, 6},
            {7, 8, 9}
        };
        System.out.println("지그재그 순회 결과:");
        zigzagOrder(matrix);
    }
}

 

4) 델타 탐색

  • 현재 위치 기준으로 상하좌우나 대각선 등 특정 방향으로 인접한 요소를 탐색
  • 이동하고 싶은 방향 정하고 행(row), 열(col)이 어떻게 변하는지 수치로 표현
  • 배열로 만들어서 반복문 처리
// 상, 하, 좌, 우
int[] dy = {-1, 1, 0, 0};
int[] dx = {0, 0, -1, 1};

newRow = row + dy[i];
newCol = col + dx[i];

 

3. 행렬 변환

 

1) 전치 행렬

  • 행 <-> 열 바꾸기
  • 시간 복잡도: O(NxM)
  • 구현 코드
public static int[][] transpose(int[][] matrix) {
    int n = matrix.length;    // 행의 개수
    int m = matrix[0].length; // 열의 개수
    
    // 행과 열의 크기를 바꿔서 새로운 배열 생성
    int[][] result = new int[m][n];
    
    // 모든 원소를 순회하며 위치 변환
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            result[j][i] = matrix[i][j];
        }
    }
    return result;
}

 

2) 행렬의 회전(90도/180도/270도)

  • 자주 쓰는 공식
    • 90도: (i, j) → (j, N-1-i)
    • 180도: (i, j) → (N-1-i, M-1-j)
    • 270도: (i, j) → (M-1-j, i)
  • 90도씩 돌 때마다 i,j가 자리 바꿈 + 하나는 뒤집힘
  • 시간 복잡도: O(NxM)
  • 구현 코드
// 90도 회전 (직사각형 행렬)
public static int[][] rotate90(int[][] matrix) {
    int N = matrix.length;    // 행의 개수
    int M = matrix[0].length; // 열의 개수
    int[][] result = new int[M][N]; // 결과 배열의 크기가 바뀜
    
    for(int i = 0; i < N; i++) {
        for(int j = 0; j < M; j++) {
            result[j][N-1-i] = matrix[i][j];
        }
    }
    return result;
}

// 180도 회전 (직사각형 행렬)
public static int[][] rotate180(int[][] matrix) {
    int N = matrix.length;
    int M = matrix[0].length;
    int[][] result = new int[N][M]; // 원래 크기 유지
    
    for(int i = 0; i < N; i++) {
        for(int j = 0; j < M; j++) {
            result[N-1-i][M-1-j] = matrix[i][j];
        }
    }
    return result;
}

// 270도 회전 (직사각형 행렬)
public static int[][] rotate270(int[][] matrix) {
    int N = matrix.length;
    int M = matrix[0].length;
    int[][] result = new int[M][N]; // 결과 배열의 크기가 바뀜
    
    for(int i = 0; i < N; i++) {
        for(int j = 0; j < M; j++) {
            result[M-1-j][i] = matrix[i][j];
        }
    }
    return result;
}

 

3️⃣ 컬렉션 프레임워크(import를 불러와 사용하는 도구)

1. List 인터페이스

 

1) 개념

  • 순서를 유지하며 중복을 허용하는 요소들의 집합

2) 특징

  • 순서 유지: 삽입된 순서
  • 유연한 크기
  • 다양한 구현체: ArrayList(배열 기반), LinkedList(이중 연결 리스트 기반)

3) ArrayList vs LinkedList

  • ArrayList
    • 조회가 많을 때: 인덱스 바로 접근 > O(1)
    • 삽입/삭제가 주로 끝에서 일어날 때: add(), remove(last)
    • 데이터 변경은 적고 읽기가 많은 경우
    • 메모리 접근 속도가 바끔 / cpu 활용 효율적
  • LinkedList
    • 삽입/삭제가 앞이나 뒤에서 빈번할 때
    • 리스트 크기 예측하기 어려울 때

4) 배열과 ArrayList의 차이점

  • 배열
    • 크기가 고정된 데이터 집합을 처리할 때 적합
    • 데이터 구조가 단순하고 성능(접근 속도)이 중요한 경우 유리
    • 메모리 사용이 효율적이어야 하거나 기본 타입 데이터를 다룰 때
  • ArrayList
    • 동적으로 데이터 크기가 변할 가능성이 있을 때
    • 요소 추가/삭제가 빈번하고, 코드를 간단하고 가독성 있게 작성하고 싶을 때
    • 데이터 조작에 다양한 메서드가 필요할 때

5) Collections 주요 기능

  • 정렬
    • 자연 정렬 순서 또는 사용자 정의 기준
    • 주요 메서드: Collections.sort(List<T>) / Collections.sort(List<T>, Comparator<T>)
  • 최솟값, 최댓값 찾기(Min/Max)
    • 최솟값과 최댓값을 쉽게 찾을 수 있음
    • 주요 메서드: Collections.min(Collection<T>) / Collections.max(Collection<T>)
  • 빈도 계산
    • 요소가 얼마나 자주 등장했는지 확인
    • 메서드: Collections.frequency(Collection<T>, T)
  • 이진 탐색
    • 정렬된 리스트에서 빠르게 값을 찾는 문제(반드시 정렬 상태)
    • 메서드: Collections.binarySearch(List<T>, T key)
  • 요소 치환
    • 컬렉션 순서 뒤집음
    • 주요 메서드: Collections.reverse(List<T>)
  • 요소 회전
    • 요소를 지정된 거리만큼 이동
    • 주요 메서드: Collections.rotate(List<T>, int distance)

2. Map 인터페이스

 

1) Map 컬렉션 특징과 사용 목적

  • 키(Key)와 값(Value)을 하나의 쌍으로 묶어서 저장하는 자료구조
  • 특징

  • 사용 목적: 빠르게 찾고 싶을 때 / 연관된 데이터 묶을 때 / 중복 키를 막고 싶을 때
  • 활용 상황: ID와 객체 매핑 / 데이터 그룹화, 분류 / 빈도수 계산

2) HashMap 주요 메서드 및 활용

  • Map 인터페이스를 구현한 대표적인 클래스
  • 선언 및 주요 메서드
// 1. 선언
HashMap<String, Integer> map = new HashMap<>();

// 2. 데이터 추가 및 수정
map.put("A", 1);                     // 키가 "A"인 값에 1 저장
map.putIfAbsent("A", 10);            // "A"키가 없을 때만 10 저장
int value = map.getOrDefault("B", 0);// "B"키 조회, 없으면 기본값 0

// 3. 존재 여부 확인
if (map.containsKey("A")) { ... }    // "A"키 존재 여부 확인
if (map.containsValue(1)) { ... }    // 값 1 존재 여부 확인

// 4. 삭제
map.remove("A");                     // "A"키 삭제
map.clear();                         // 전체 삭제

// 5. 값 변경하기 (다양한 방법)
HashMap<String, Integer> scores = new HashMap<>();
scores.put("Kim", 80);

// 5-1. 일반적 방식
if (scores.containsKey("Kim")) {
    scores.put("Kim", scores.get("Kim") + 10);
}

// 5-2. compute 활용 (람다 사용)
scores.compute("Kim", (key, oldVal) -> oldVal + 10);

// 5-3. 키가 있을 때만 변경 (computeIfPresent)
scores.computeIfPresent("Kim", (key, oldVal) -> oldVal + 10);

// 6. 크기 확인
int size = map.size();
boolean isEmpty = map.isEmpty();
  • 순회 방법
HashMap<String, Integer> map = new HashMap<>();
map.put("사과", 1000);
map.put("바나나", 2000);
map.put("오렌지", 3000);

// 1. entrySet() 활용 - (키, 값) 쌍 직접 접근
for (Map.Entry<String, Integer> entry : map.entrySet()) {
    String key = entry.getKey();
    int val = entry.getValue();
    // 처리 로직
}

// 2. keySet() 활용 - 키만 필요할 때
for (String key : map.keySet()) {
    // 키를 이용한 값 조회 또는 처리
}

// 3. values() 활용 - 값만 필요할 때
for (int val : map.values()) {
    // 값만을 이용한 처리
}

 

3. Set 인터페이스

 

1) 개념

  • 중복되지 않는 요소들을 저장하는 자료구조

2) 사용 목적

  • 중복 제거: 대용량 데이터에서 같은 요소가 반복될 때, 효율적으로 중복을 제거할 수 있음
  • 유일성 보장: 비즈니스 로직상 고유해야 하는 값(예: 상품 코드, 회원 ID) 관리
  • 집합 연산 처리: 합집합, 교집합, 차집합과 같은 집합 연산을 쉽게 수행
  • 메모리 절약: 불필요한 중복데이터를 제거하여 메모리 사용량 감소

3) 활용 상황

  • 데이터 처리 측면
    • 로그 분석: 다양한 IP나 사용자 ID 중에서 유일한 값을 추출
  • 비즈니스 로직 측면
    • 회원 관리: 중복 불가능한 식별자(이메일, 전화번호) 관리

4) 주요 메서드

// 1. 선언
HashSet<String> set = new HashSet<>();

// 2. 데이터 추가 및 삭제
set.add("A");        // 요소 "A" 추가 (중복 요소는 추가되지 않음)
set.remove("A");     // "A" 삭제
set.clear();         // 모든 요소 삭제

// 3. 데이터 확인
boolean exists = set.contains("A");  // "A"가 존재하는지 확인
int size = set.size();               // Set의 크기 확인
boolean empty = set.isEmpty();       // 비었는지 확인

// 4. 집합 연산
Set<String> set1 = new HashSet<>();
Set<String> set2 = new HashSet<>();
// 합집합: set1에 set2의 요소 모두 추가
set1.addAll(set2);      
// 교집합: set1과 set2에 모두 있는 요소만 남김
set1.retainAll(set2);   
// 차집합: set1에서 set2의 요소 제거 (set1 - set2)
set1.removeAll(set2);

 

5) 순회 방법

HashSet<String> fruits = new HashSet<>();
fruits.add("사과");
fruits.add("바나나");
fruits.add("오렌지");

// for-each문 활용
for (String fruit : fruits) {
    System.out.println(fruit);
}
// 출력 결과 (순서는 무작위):
// 바나나
// 오렌지
// 사과

'🔌 SPARTA > Courses' 카테고리의 다른 글

Spring MVC / Data JPA  (0) 2026.01.30
Spring 시작하기  (1) 2026.01.29
완전 탐색과 그리디 알고리즘  (1) 2026.01.27
알고리즘 개념  (1) 2026.01.27
걷기반 4회차: 상속과 제네릭, enum  (1) 2026.01.23