Sparta/TIL

24.03.18 TIL - 정렬 for Javascript

jskim4695 2024. 3. 19. 10:16

이번 프로젝트에서 정렬을 하게 될 일이 생겼는데, 이번 기회에 정렬에 대한 알고리즘을 공부하고 정리하는 시간을 가졌다.

컴퓨터 자료구조에는 많은 정렬이 있지만 간단하게 3개만 정리해보겠다.

 

1. 선택정렬

  • 매 단계에서 가장 작은 원소를 선택해서 앞으로 보내는 정렬
  • 앞으로 보낸 원소는 더이상 위치가 변경되지 않는다.
  • 시간 복잡도 O(N^2)로 비효율적
  • 동작방식
    • 각 단계에서 가장 작은 원소 선택
    • 현재까지 처리되지 않은 원소들 중 가장 앞의 원소와 위치를 교체한다.
// 선택 정렬 함수
function selectionSort(arr) {
	for (let i = 0; i < arr.length; i++) {
    	let minIndex = i;
        for (let j = i; j < arr.length; j++) {
        	if (arr[minIndex] > arr[j] {
            min Index = j
            }
        }
		// 스와프(swap)
        let temp = arr[i]
        arr[i] = arr[minIndex]
        arr[mindex] = temp
    }
}

 

2. 버블정렬

  • 단순히 인접한 두 원소를 확인하여, 정렬이 안 되어 있다면 위치를 서로 변경
  • 서로 인접한 두 원소를 비교하는 형태가 거품과 같다 하여서 붙힌 이름
  • 시간 복잡도 O( N ^2)로 비효율적인 정렬 알고리즘
  • 동작방식
    • 각 단계에서는 인접한 두 개의 원소를 비교하여, 필요시 위치를 변경
    • 한번의 단계가 수행되면 가장 큰 원소가 맨 뒤로 이동
    • 그 다음 단계에서는 맨 뒤로 이동한 데이터는 정렬에서 제외
// 버블 정렬 함수
function bubbleSort(arr) {
	for (let i = arr.length - 1; i > 0; i--) {
    	for (let j = 0; j < i; j++) {
    		if (arr[j] < arr[j + 1]) {
            	let temp = arr[j];
                arr[j] = arr[j + 1]
                arr[j + 1] = temp
            }
		}    
    }
}

 

3. 삽입정렬

  •  각 숫자를 적절한 위치에 삽입
  • O(N^2)의 시간복잡도로 비효율적
  • 동작방식
    • 각 단계에서 현재 원소가 삽입될 위치를 찾는다.
    • 적절한 위치에 도달할 때까지 반복적으로 왼쪽으로 이동한다.
function insertionSort(arr) {
  for (let i = 1; i < arr.length; i++) {
    for (let j = i; j > 0; j--) {
      // 인덱스 j부터 1까지 1씩 감소하며 반복
      if (arr[j] < arr[j - 1]) {
        // 한 칸씩 왼쪽으로 이동
        // 스와프(swap)
        let temp = arr[j];
        arr[j] = arr[j - 1];
        arr[j - 1] = temp;
      } else {
        // 자기보다 작은 데이터를 만나면 그 위치에서 멈춤
        break;
      }
    }
  }
}

 

4. 병합 정렬

  • 정형적인 분할 정복 알고리즘. 큰 문제를 작은 문제로 분할하고 각각 해결하여 해결된 작은 문제를 이용하여 큰 문제 해결하는 방법
  • 일반적으로 재귀함수를 이용해 구현
  • 더이상 쪼갤수 없는 크기가 될 때까지 계속하여 분할한다.
  • 단점 : 재귀함수를 사용하니 호출횟수가 많아지고, 오버헤드로 이어질 수 있다.
  • 동작방식
    • 정렬할 배열(큰 문제)을 같은 크기의 부분배열(작은문제) 2개로 분할
    • 부분 배열을 정렬(작은 문제를 해결) : 첫째 원소부터 하나씩 확인하여 정렬, 총 원소 개수가 N개일 때, O(N)의 시간 복잡도
    • 조합: 정렬된 부분배열을 하나로 병합
  • 시간복잡도는 최악의 경우에도 O(NlogN)이 보장되므로 효율적
// 병합(merge) 수행 함수
function merge(arr, left, mid, right) {
  let i = left;
  let j = mid + 1;
  let k = left; // 결과 배열의 인덱스
  while (i <= mid && j <= right) {
    if (arr[i] <= arr[j]) sorted[k++] = arr[i++];
    else sorted[k++] = arr[j++];
  }
  // 왼쪽 배열에 대한 처리가 다 끝난 경우
  if (i > mid) {
    for (; j <= right; j++) sorted[k++] = arr[j];
  }
  // 오른쪽 배열에 대한 처리가 다 끝난 경우
  else {
    for (; i <= mid; i++) sorted[k++] = arr[i];
  }
  // 정렬된 배열 결과를 원본 배열에 반영하기
  for (let x = left; x <= right; x++) {
    arr[x] = sorted[x];
  }
}

// 병합 정렬(merge sort) 함수
function mergeSort(arr, left, right) {
  // 원소가 1개인 경우, 해당 배열은 정렬이 된 상태로 이해 가능
  if (left < right) {
    // 원소가 2개 이상이라면
    let mid = parseInt((left + right) / 2); // 2개의 부분 배열로 분할(divide)
    mergeSort(arr, left, mid); // 왼쪽 부분 배열 정렬 수행(conquer)
    mergeSort(arr, mid + 1, right); // 오른쪽 부분 배열 정렬 수행(conquer)
    merge(arr, left, mid, right); // 정렬된 2개의 배열을 하나로 병합(combine)
  }
}

 

 

출처 : https://yoonsoo-space.tistory.com/120

 

JavaScript 정렬(sorting) 알고리즘

1. 선택 정렬 매 단계에서 가장 작은 원소를 선택해서 앞으로 보내는 정렬 방법 앞으로 보내진 원소는 더 이상 위치가 변경되지 않는다. 시간 복잡도 O(N^2)로 비효율적인 정렬 알고리즘 중 하나

yoonsoo-space.tistory.com