같은 자료형의 데이터를 연속된 메모리 공간에 저장하는 선형 자료구조
배열의 생성(초기화)
int[] arr = new int[5];
선언과 동시에 값 지정
int[] array = {1, 2, 3, 4, 5};
시간 복잡도
cf) 배열과 연결 리스트의 차이


import java.util.Arrays;
public class BubbleSort {
public static void main(String[] args) {
int[] arr = { 1, 16, 2, 20, 97, 99 };
int N = arr.length;
// array의 길이를 저장
for (int i = N - 1; i > 0; i--) {
for (int j = 0; j < i; j++) {
// 오름차순 정렬
if (arr[j] > arr[j + 1]) {
int tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
}
}
System.out.println(Arrays.toString(arr));
}
}
}
import java.util.Arrays;
public class SelectionSort {
public static void main(String[] args) {
int[] arr = { 1, 16, 2, 20, 97, 99 };
int N = arr.length;
for (int i = 0; i < N - 1; i++) {
int minIdx = i;
for (int j = i + 1; j < N; j++) {
if (arr[minIdx] > arr[j]) {
minIdx = j;
}
}
// if(minIdx == i) continue;
int tmp = arr[i];
arr[i] = arr[minIdx];
arr[minIdx] = tmp;
}
System.out.println(Arrays.toString(arr));
}
}
안정 vs 불안정 정렬 차이 : 중복된 값이 있을 때, 입력된 순서가 정렬 후에도 유지되는 가?
버블 정렬 : 인접한 수만 바꾸고 값이 같으면 바꾸지 않고 지나감
선택 정렬 : 수에 따라 변경이 될 수 있음
ex) 2 (a), 2(b), 1 -> 1, 2 (b), 2 (a) : 맨 앞에 있는 2(A)와 1을 바꾸면서 순서 역전
각 항목이 몇 번 등장했는지(빈도)를 세서, 그 정보를 이용해 정렬 결과를 만든다.
→ 비교 기반 정렬이 아니라 카운트 기반 정렬이라 선형 시간에 가깝게 가능
특징
(1) 안정 정렬(Stable)로 구현 가능: 같은 값의 원래 순서 유지
(2) 정수(또는 정수로 매핑 가능한 값)에 대해서만 적용하기 쉬움
(값 자체를 인덱스로 쓰는 count 배열을 만들기 때문)
(3) 비 비교 정렬
조건 / 제약
(1) count[value] 형태로 쓰려면 값의 범위(최대값)를 알아야 한다.
(2) 값의 최대가 크면 count 배열이 커져서 공간 사용량이 증가한다.
시간 복잡도
O(n + k)
따라서, O(2n+k) = O(n+k)
(1) 데이터가 들어갈 수 있는 범위 확인
cf) 데이터 범위가 항상 0부터 시작한다는 보장은 없음
(2) 0~k (데이터 범위)까지의 배열 생성
(3) 데이터를 순회하면서 해당 인덱스의 값을 증가시킴
(4) 카운트 배열의 누적합을 구하여 정렬된 결과를 어느 위치에 배치해야하는 지 알 수 있음
(5) 원본 배열의 뒤에서부터 순회하며 원소를 배치

public static int[] countingSort(int[] arr) {
int N = arr.length;
// 1. 가장 큰 값 찾기
int K = -1;
for (int i = 0; i < N; i++) {
if (arr[i] > K) K = arr[i];
}
// 2. Counting 하기
// 등장 횟수를 저장할 count 배열 생성
int[] count = new int[K + 1];
// 각 숫자 등장 횟수 세기
for (int i = 0; i < N; i++) {
count[arr[i]]++;
}
// 3. 누적합 구하기
for (int i = 1; i < K + 1; i++) {
count[i] += count[i - 1]; // count[i] → i 이하의 숫자가 총 몇 개인지
}
// 4. 역방향으로 원본을 순회하면서 정렬 시작
int[] sortedArr = new int[N]; // 원본 배열과 동일한 크기의 배열
for (int i = N - 1; i >= 0; i--) // 뒤에서부터 순회
{
int num = arr[i]; // 현재 정렬 대상 값
int idx = count[num] - 1; // 누적합 정보로 실제 들어갈 인덱스 계산
sortedArr[idx] = num; // 계산된 위치에 값 저장
count[num]--; // 다음 동일 숫자가 앞에 올 수 있도록 위치 한 칸 전진
}
return sortedArr;
}
}
원소끼리 a < b 비교를 반복하는 대신, 자릿수(digit) 를 기준으로 여러 번 분류/정렬을 반복해 전체를 정렬하는 알고리즘
-> 보통 각 자릿수 정렬 단계에서 카운팅 정렬 같은 안정 정렬을 사용함
정렬 방식 (LSD 방식)
1의 자리 → 10의 자리 → 100의 자리 → … 순서로 정렬(Least Significant Digit)
특징
(1) 안정 정렬(Stable) 로 구현 가능(자릿수별 정렬이 안정적이면 전체도 안정적)
(2) 주로 0 이상의 정수 정렬에 많이 사용
(3) 정수뿐 아니라 자릿수 개념으로 표현 가능한 문자열에도 응용 가능
시간 복잡도
O(d × (n + k))
-> 카운팅 정렬 O(n+k)를 자릿수 d번 반복하는 것과 같음
-> d가 커질수록(자릿수 많을수록) 느려짐
제약/주의
(1) 자릿수가 늘면 비용 증가
(2) 음수 / 소수는 그대로 적용하기 어렵고, 처리하려면 추가 변환/전처리가 필요함
// 기수정렬(LSD방식)
public static void radixSort(int[] arr) {
// 최댓값 찾기(자릿수 계산)
int max = arr[0];
for (int v : arr) {
if (v > max) max = v;
}
// 1의 자리, 10의자리, 100의자리.... 정렬
// 가장 큰수의 자릿수까지만 정렬 ( ex 123 /1000 = 0 되어서 종료)
for (int exp = 1; max / exp > 0; exp *= 10) {
countingSort(arr, exp); } }
public static void countingSort(int[] arr, int exp) {
int n = arr.length;
int[] output = new int[n]; // 자릿수 정렬이 완료된 데이터 임시 보관
int[] count = new int[10]; // 자릿수별로 비교, 올 수 있는 숫자는 0-9
// 1. 개수 세기
for (int i = 0; i < n; i++) {
int digit = (arr[i] / exp) % 10; // 전체값이 아니라 특정 자릿수만 추출
count[digit]++; }
// 2. 누적합
for (int i = 1; i < 10; i++) {
count[i] += count[i - 1]; }
// 3. 역방향으로
for (int i = n - 1; i >= 0; i--) {
int digit = (arr[i] / exp) % 10; //자릿수 추출
output[count[digit] - 1] = arr[i]; //자릿수 기준 위치에 저장
count[digit]--; }
// 4. output arr에 덮기
// 새 배열에 반환하는 카운팅과 달리 다음 자릿수 정렬을 위해 원본 배열 업데이트
for (int i = 0; i < n; i++) {
arr[i] = output[i]; } } }
열심히 이 글을 읽으시고, 코딩체력이 높으신 분들은 당연하게
Arrays.sort() 쓰면 되는 거 아님?
이라는 생각을 하셨을 것이다.
cf) Arrays.sort()
java.util.Arrays의 sort()는 배열을 정렬하는 표준 메서드
Arrays.sort(int[] a); // 기본형(primitive) 배열
Arrays.sort(Integer[] a); // 객체 배열(Wrapper)
Arrays.sort(T[] a, Comparator<? super T> c); // 비교기(정렬 기준) 지정
Arrays.sort(a, from, to); // 부분 정렬
(1) 기본형 배열
Ex) int[], double[]
int[] a = {5, 2, 9, 1};
Arrays.sort(a);
(2) 객체 배열
Ex) Integer[], String[] etc
String[] s = {"b", "a", "a"};
Arrays.sort(s); // stable: 같은 "a"의 상대 순서 유지
대부분의 코테/실무 정렬은 Arrays.sort()로 충분..!
샤라웃 투 ㅅㅇ
땡스 투 ㅅㅎ