Algorithm - Sorting

2025. 8. 13. 20:16·C++ 프로그래머스/Sort

정렬(Sorting)이란?

데이터를 어떤 기준에 따라 순서대로 재배치하는 알고리즘을 뜻한다

 

정렬의 종류에는 

버블 정렬(Bubble Sorting)

선택 정렬(Selection Sorting)

삽입 정렬(Insertion Sorting)

퀵 정렬(Quick Sorting)

병합 정렬(Merge Sorting)

등이 있다

 

버블 정렬(Bubble Sorting)

https://gmlwjd9405.github.io/2018/05/06/algorithm-bubble-sort.html

 

개념 : 배열의 인접한 두개의 아이템을 선택하고 비교해서

왼쪽의 아이템이 오른쪽 보다 클경우 

즉 arr[0] > arr[1] 일경우

배열의 들어있는 원소를 서로 Swap하여 바꾼다

이걸 끝까지 반복하여 배열 전체가 정렬되는것이 버블 정렬 이다

 

시간복잡도 : O(N^2)

N - 1번의 반복이 필요하기때문에 좋은 알고리즘은 아님

 

 

버블정렬의 예시

#include <iostream>
#include <vector>
using namespace std;

void solution(vector<int>&arr)
{
	for (int i = 0; i < arr.size(); i++)
	{
		for (int j = 0; j < arr.size() - 1; j++)
		{
			//배열의 왼쪽값보다 오른쪽값이 크다면스왑
			if (arr[j] > arr[j + 1])
			{
				//붙어있는 인덱스아이템 서로 스왑
				swap(arr[j], arr[j + 1]);
			}
		}
	}
}
int main()
{
	vector<int> arr = { 1, 3, 5, 2, 9 };
	solution(arr);
	for (int x : arr)
	{
		cout << x << " ";
	}
}

 

선택 정렬(Selection Sorting)

https://gmlwjd9405.github.io/2018/05/06/algorithm-selection-sort.html

 

개념 : 배열에서 가장 작은(혹은 가장 큰) 원소를 찾아서 배열의 앞쪽부터 차례대로 자리를 바꾸며 정렬

처음부터 끝가지 탐색해서 최솟값 혹은최대값을 찾고 그 값을 현재 위치의 값과 Swap

배열 끝까지 반복하면 선택정렬이 완성

 

선택 정렬의 시간복잡도 : O(N^2)

특징 : N번의 스왑을 하지는 않아 버블보다는 좋을수있고 구현이 쉽고 직관적이나

데이터가 많으면 너무 느려서 이것도 그렇게 효율적인 정렬은 아니다

 

 

선택 정렬의 예시

#include <iostream>
#include <vector>
using namespace std;

void solution(vector<int>& arr)
{
	for (int i = 0; i < arr.size(); i++)
	{
		//최솟값 초기화
		int minIndex = i;
		for (int j = i + 1; j < arr.size(); j++)
		{
			//현재 검사중인 원소가 지금까지 발견한최솟값 보다 작으면
			//더 작은값이 발견되었으니 최솟값 위치를 j로 업데이트 한다
			if (arr[j] < arr[minIndex])
			{
				minIndex = j;
			}
		}
		//최솟값이 현재 위치와 다르면 swap
		if (minIndex != i)
		{
			swap(arr[i], arr[minIndex]);
		}
	}
}
int main()
{
	vector<int> arr = { 1, 3, 7, 2, 9 };
	solution(arr);
	for (int x : arr)
	{
		cout << x << " ";
	}
}

 

 

 

삽입 정렬(Insertion Sorting)

https://gmlwjd9405.github.io/2018/05/06/algorithm-insertion-sort.html

 

 

개념 : 배열을 왼쪽부터 차례대로 검사하면서

현재 위치에 값을 왼쪽에 정렬된 부분에 알맞은 위치에 "삽입" 정렬방식

현재 원소를 왼쪽의 정렬된 부분과 비교해가며 적절한 자리로 밀어 넣는 방식

 

두번쨰 원소부터 시작을 하여 그 원소를 왼쪽의 정렬된 부분과 비교하며

정렬된 부분에서 더 큰원소들을 오른쪽으로 밀어내며 현재 원소를 올바른 위치에 삽입

 

삽입 정렬의 시간복잡도 : O(N^2)

최선의 경우 O(N)

거의 정렬된 배열에 매우 빠르고 안정 정렬이다

하지만 무작위 데이터에서는 느리다

 

삽입 정렬의 예시

#include <iostream>
#include <vector>
using namespace std;

void solution(vector<int>& arr)
{
	//배열의 두번쨰 원소부터 검사
	for (int i = 1; i < arr.size(); i++)
	{
		//삽입할 원소
		int key = arr[i];
		//key원소보다 더 왼쪽에 있는 인덱스
		int j = i - 1;

		//key보다 큰 원소들을 오른쪽으로 한칸 미루기
		while (j >= 0 && arr[j] > key)
		{
			//arr[j]는 현재 비교중인 왼쪽원소
			//arr[j + 1]은 그 원소의 오른쪽칸
			arr[j + 1] = arr[j];
			//원소를 오른쪽으로 밀기
			j--;
		}
		arr[j + 1] = key;
	}
}

 

퀵 정렬(Quick Sorting)

https://gmlwjd9405.github.io/2018/05/10/algorithm-quick-sort.html

 

 

퀵정렬 개념 : 분할 정복 개념 을 사용하는 아주 빠른 정렬알고리즘

작동박식 :

1. Pivot 기준점 하나를 선택한다 ( 배열의 첫번쨰 원소, 마지막원소, 중간값, 랜덤값 여러가지 선택 가능)

2. Pivot 기준으로 분할한다 ( Pivot보다 작은 값은 왼쪽, 큰값은 오른쪽)     작은값 << - Pivot - >> 큰값

3. 왼쪽과 오른쪽 각각을 재귀 호출로 다시 퀵 정렬

4. 분할이 불가능할때 정렬 완료

 

즉 분할 , 정복, 결합을 실행하면된다

 

  • 분할(Divide): 입력 배열에서 하나의 피벗(Pivot)을 선택하고, 피벗을 기준으로 왼쪽에는 피벗보다 작은 요소들, 오른쪽에는 피벗보다 큰 요소들로 나누어 2개의 부분 배열로 분할한다.
  • 정복(Conquer): 각 부분 배열이 충분히 작아질 때까지 같은 방법(분할 정복)을 재귀적으로 적용하여 정렬한다.
  • 결합(Combine): 정렬된 왼쪽 배열, 피벗, 정렬된 오른쪽 배열을 순서대로 합쳐 하나의 완전한 정렬 배열을 만든다.

 

 

 

ex) 배열 [ 5, 3, 2, 8, 7, 10, 11 ] 이 있을때 퀵 정렬방식을 사용하면

1. 첫번쨰 원소는 '5' /  Pivot = '5'

왼쪽은 pivot보다 작은 [ 3, 2 ]

오른쪽은 pivot보다 큰 [ 8, 7, 10, 11 ]

 

2. 왼쪽부분 [ 3 , 2 ]

왼쪽부분의 첫 번쨰 원소는 '3' / Pivot = '3'

왼쪽 [ 2 ] -> 원소1개(정렬완료)

오른쪽 = x  

 

3. 오른쪽부분 [ 8. 7. 10, 11]

오른쪽부분의 첫 번째 원소는 '8' / pivot = '8'

왼쪽은 pivot보다 작은 [ 7 ] -> 원소1개(정렬완료)

오른쪽은 pivot보다 큰 [ 10, 11]

 

4. 오른쪽의 오른쪽부분 [ 10, 11 ]

첫번째 원소 '10' / pivot = '10'

왼쪽 = 없음 

오른쪽 = [ 11 ] -> 원소1개(정렬완료)

 

더이상 분할할수 없을때 

최종 정렬 = 왼쪽 + Pivot + 오른쪽 

 

왼쪽 부분 합치는법

[ 3 , 2 ] 정렬 결과

[ 2 ] + 3 + [  ] = [ 2, 3 ]

왼쪽부분 정렬 결과 = [ 2, 3 ]

 

오른쪽 부분 합치는법[8, 7, 10, 11 ] 정렬 결과[ 7 ] + 8 + [ 10 , 11 ] = [ 7, 8, 10, 11 ]오른쪽부분 정렬 결과 = [ 7, 8, 10, 11 ]

 

배열 [ 5, 3, 2, 8, 7, 10, 11 ]의 pivot은 첫번째 원소인 '5'

[2, 3] + 5 + [7, 8, 10, 11]

[2, 3, 5, 7, 8, 10, 11] 이 결과값으로 도출된다

 

장점 : 속도가 매우 빠름

다른 정렬 알고리즘(삽입, 선택, 버블 정렬 등)은 평균적으로 O(N²)의 시간복잡도를 가지지만,

퀵 정렬은 평균적으로 O(N log N)의 시간복잡도를 가진다.

단점 : 정렬된 리스트에 대해서는 퀵정렬이 수행시간이 오히려 더 많이 걸림

 

퀵 정렬 예시 

#include <iostream>
#include <vector>
using namespace std;

void solution(vector<int>& arr)
{
	//내부 재귀 함수 정의하기
	auto quickSorting = [&](auto&& self, int left, int right) -> void
		{
			if (left >= right)
			{
				return;
			}
			//원소의 가장 첫번째 원소
			int pivot = arr[left];
			//피봇 기준으로 왼쪽과 오른쪽 탐색할 포인터 초기화
			int pivotLeft = left + 1;
			int pivotRight = right;

			//더이상 교환할 원소가 없을떄까지 반복
			while (pivotLeft <= pivotRight)
			{
				while (pivotLeft <= pivotRight && arr[pivotLeft] <= pivot)
				{
					pivotLeft++;
				}
				while (pivotRight >= pivotLeft && arr[pivotRight] >= pivot)
				{
					pivotRight--;
				}

				if (pivotLeft > pivotRight)
				{
					swap(arr[left], arr[pivotRight]);
				}
				else
				{
					swap(arr[pivotLeft], arr[pivotRight]);
				}
			}

			//왼쪽 재귀 호출
			self(self, left, pivotRight - 1);
			//오른쪽 재귀 호출
			self(self, pivotRight + 1, right);
		};
	//초기 호출
	quickSorting(quickSorting, 0, arr.size() - 1);
}
int main()
{
	vector<int> arr = { 5, 3, 2, 8, 7, 10, 11 };
	solution(arr);
	for (int x : arr)
	{
		cout << x << " ";
	}
	return 0;
}

 

 

 

병합 정렬(Merge Sorting)

 

병합 정렬 개념 :  분할 정복의 알고리즘중 하나의 정렬방식

배열을 반 으로 나눈뒤 크기가 1 이 될떄까지 계속 나눔

배열의 크기가 1이되면 정렬이됨

 

정렬된 두 배열을 하나로 합치면 배열 완성

 

ex ) [5, 3, 8, 6, 7]

중간 인덱스를 계산한다

중간 인덱스 = (시작인덱스  + 끝인덱스) / 2

result = ( 0 + 4 ) / 2 = 2 중간인덱스의 결과값은 2

2번 인덱스 즉 8이 중간값이 된다

 

1. 왼쪽

[ 5, 3, 8 ] -> [5, 3] + [8]

[5, 3] -> [5] + [3] -> [3, 5]

[3, 5] + [8] -> [3, 5, 8]

 

2.오른쪽 

[6, 7] -> 정렬됨

 

3. 결과값 = [3, 5, 8]   ,  [6, 7] 이 존재

첫번째 원소 3, 6 비교 3이 더 작음

첫번째 배열에 3 추가 [ 3 ]

 

두번째 원소 5와 6 비교 5가 더 작음

두번째 배열에 5 추가 [ 3, 5 ]

 

세번째 원소 8과 6 비교 6가 더 작음

세번째 배열에 6 추가 [ 3, 5, 6 ]

 

세번쨰 원소 8과 7 비교 7이 더 작음

네번째 배열에 6 추가 [ 3, 5, 6, 7]

 

남은원소 처리 8 추가

[3, 5, 6, 7, 8]

-------------- 만약 인덱스가 홀수 갯수 일경우 ------


개념 : 작게 나눈뒤 다시 합치면서 정렬

ex ) {5, 3, 8, 6}

 

1. 분할하기

ex ) [5, 3, 8, 6]

-> [5, 3], [8, 6]

 

2. 정복하기

[5,3] -> [3,5}

[8,6] -> [6,8]

 

3. 병합하기

[3, 5]  + [6 + 8]

[ 3, 5, 6, 8]

 

시간복잡도 : 항상 O(N LOG N)

장점 : 안정적, 빠름

단점 : 추가 메모리가 필요하다

시간복잡도 : 모든경우 전부 O( N LOG N )

이유 : 배열을 계속 반으로 나누고 나누는 정렬 방식이라서

 

장점 : 최선 최악 평균 모드 O (NLOGN]이라 안정적이고 큰 데이터인경우 적합하다

안정정렬이다

 

단점 : 추가 메모리가 필요하다, 작은 배열에는 비효율적이다

 

병합 정렬 예시

#include <iostream>
#include <vector>
using namespace std;

void mergeSort(vector<int>& arr, int left, int right) {
    if (left >= right) return;

    int mid = (left + right) / 2;
    mergeSort(arr, left, mid);       // 왼쪽 정렬
    mergeSort(arr, mid + 1, right);  // 오른쪽 정렬

    // 병합
    vector<int> temp;
    int i = left, j = mid + 1;
    while (i <= mid && j <= right) {
        if (arr[i] < arr[j])
        {
            temp.push_back(arr[i++]);
        }
        else
        {
            temp.push_back(arr[j++]);
        }
    }
    while (i <= mid)
    {
        temp.push_back(arr[i++]);
    }
    while (j <= right)
    {
        temp.push_back(arr[j++]);
    }

    for (int k = 0; k < temp.size(); ++k)
    {
        arr[left + k] = temp[k];
    }

}

void solution(vector<int>& arr) {
    mergeSort(arr, 0, arr.size() - 1);
}
int main()
{
	vector<int> arr = { 5, 3, 2, 8, 7, 10, 11 };
	solution(arr);
	for (int x : arr)
	{
		cout << x << " ";
	}
	return 0;
}

 

 

 

 

 

 

 

 

 

 

'C++ 프로그래머스 > Sort' 카테고리의 다른 글

프로그래머스(C++) - H-Index  (1) 2025.08.19
프로그래머스(C++) - 가장 큰 수  (0) 2025.08.18
프로그래머스(C++) - k번째 수  (0) 2025.08.18
프로그래머스(C++) - 명예의 전당(1)  (0) 2025.07.27
'C++ 프로그래머스/Sort' 카테고리의 다른 글
  • 프로그래머스(C++) - H-Index
  • 프로그래머스(C++) - 가장 큰 수
  • 프로그래머스(C++) - k번째 수
  • 프로그래머스(C++) - 명예의 전당(1)
lucodev
lucodev
커피와 노트북 그리고 개발
  • lucodev
    루코 개발테이블
    lucodev
  • 전체
    오늘
    어제
    • 분류 전체보기 (209) N
      • Unreal 프로젝트 다이어리 (106) N
        • 첫번째 프로젝트 (73)
        • 두번째 프로젝트 (33) N
      • Unreal 팁 (8)
      • Unreal 디버깅 (8)
      • C++ 프로그래머스 (52)
        • Stack,Queue (7)
        • Hash (4)
        • Heap (2)
        • Sort (5)
        • Exhaustive search (5)
        • Greedy (2)
        • BFS , DFS (7)
        • Graph (2)
        • Dynamic Programming (1)
        • C++ Math (2)
        • 기타 문제 (14)
      • C++ 백준 (4)
      • C++ 팁 (1)
      • 개인 코테 & 스타디 <비공개> (29)
        • 코드 개인보관함 (9)
        • 코딩테스트+@ (11)
        • 알고리즘 스타디 (6)
        • 알고리즘 스타디 과제 (3)
        • 비공개 (0)
  • 인기 글

  • 최근 글

  • 최근 댓글

  • 링크

  • 공지사항

  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 태그

    언리얼
    언리얼 프로그래스바
    언리얼 ui
    언리얼 인벤토리
    언리얼 상호작용
    언리얼 컷씬
    unreal 인벤토리
    언리얼 behaviortree
    언리얼 비헤이비어트리
    unreal inventory
    unreal 모션매칭
    언리얼 motionmatching
    언리얼 parkour
    unreal 파쿠르
    Unreal Parkour
    언리얼 모션매칭
    언리얼 behavior tree
    언리얼 파쿠르
    언리얼 시퀀스
    unreal 시퀀스
  • hELLO· Designed By정상우.v4.10.3
lucodev
Algorithm - Sorting
상단으로

티스토리툴바