C++ Programming/알고리즘

[알고리즘] Quick Sort

2023. 1. 13. 18:46
목차
  1. 🐥 Quick Sort
  2. 💻 구현(C++)
  3. ⏱ 시간복잡도
  4. 💻 최악의 경우
  5. 📃 정리

🐥 Quick Sort

Quick Sort는 거의 모든 정렬 알고리즘보다 빠른 특징을 가지고 있기 때문에 라이브러리에서의 정렬은 대부분 Quick Sort를 바탕으로 만들어져있다.
Quick Sort는 매번 Pivot이라는 원소를 하나 선택하고 Pivot을 제자리로 보내는 작업을 반복한다. Pivot을 제자리로 보낸다는 말의 의미는 Pivot의 왼쪽에는 Pivot보다 작은 원소들을, Pivot의 오른쪽에는 Pivot보다 큰 원소들을 위치시킨다는 것이다.


가장 왼쪽에 있는 원소인 5를 Pivot으로 잡는다면 Pivot의 제자리는 위와 같다. Pivot을 기준으로 왼쪽은 Pivot보다 작은 원소들이, 오른쪽은 Pivot보다 큰 원소들이 있는 것을 볼 수 있다.



자세한 동작과정을 살펴보면 다음과 같다. Pivot을 제외한 양쪽 끝에 포인터를 두고 적절하게 스왑을 해주면 된다. 왼쪽 포인터 l, 오른쪽 포인터 r을 둔다.
l은 Pivot보다 큰 값이 나올 때까지 오른쪽으로 이동하고 r은 Pivot보다 작은 값이 나올 때까지 왼쪽으로 이동한다. 


초기 상태




l이동 후




r이동 후




l과 r의 이동이 멈췄고 l이 r보다 작거나 같다면 두 원소를 스왑한다.




l 이동 후




r 이동 후




l과 r의 이동이 멈췄고 l이 r보다 크기 때문에 r에 위치한 원소와 Pivot의 자리를 바꾼다. 이로써 Pivot의 제자리를 찾을 수 있다.



💻 구현(C++)

 

2751번: 수 정렬하기 2

첫째 줄에 수의 개수 N(1 ≤ N ≤ 1,000,000)이 주어진다. 둘째 줄부터 N개의 줄에는 수가 주어진다. 이 수는 절댓값이 1,000,000보다 작거나 같은 정수이다. 수는 중복되지 않는다.

www.acmicpc.net

위 문제를 해결하면서 Quick Sort를 구현해보자.
#include <iostream>
#define MAX 1000005
using namespace std;

int N;
int arr[MAX];

void quick_sort(int st, int en) {
	if (en <= st + 1) return;	// base condition

	int pivot = arr[st];	// 피벗
	int l = st + 1;			// 왼쪽 포인터
	int r = en - 1;			// 오른쪽 포인터

	while (true) {
		while (l <= r && arr[l] <= pivot) l++;
		while (l <= r && arr[r] >= pivot) r--;
		
		if (l > r) break;

		swap(arr[l], arr[r]);
	}

	swap(arr[st], arr[r]);
	quick_sort(st, r);
	quick_sort(r + 1, en);
}

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	cin >> N;
	for (int i = 0; i < N; i++) {
		cin >> arr[i];
	}

	quick_sort(0, N);

	for (int i = 0; i < N; i++) {
		cout << arr[i] << '\n';
	}

	return 0;
}

 

⏱ 시간복잡도

Quick Sort의 과정과 시간복잡도를 알아보자. 

 


Pivot을 제자리로 보내는 시간복잡도는 리스트의 크기에 비례한다. 즉 각 단계마다 O(N)이 필요하다.
Pivot이 매번 정가운데 위치해서 리스트를 둘로 쪼갠다면 단계는 logN이 될 것이다.
이 경우 Quick Sort의 전체 시간 복잡도는 O(NlogN)이 된다.



💻 최악의 경우

굉장히 좋아보이는 Quick Sort에는 치명적인 단점이 있다. 다음의 예시를 보자.


1 2 3 4 5 6 7 8 을 Quick Sort를 이용하여 정렬하면 매번 선택되는 Pivot은 가장 왼쪽에 위치할 것이고 이 때문에 단계는 logN이 아닌 N번의 단계가 된다.

 


따라서 이때의 시간복잡도는 O(N²)이 된다.



앞에서 대부분의 라이브러리의 정렬 알고리즘은 Quick Sort로 구현되어 있다고 했다. 그런데 최악의 경우에 O(N²)인 Quick Sort를 사용하는게 이해가 안될 수도 있지만 내부적으로 다양한 처리를 한다.
예를 들면 Pivot을 랜덤하게 고르거나, Pivot의 후보를 정하고 후보의 중앙값을 Pivot으로 정하기도 한다. 최악의 경우에도 O(NlongN)을 보장하기 위해서 일정 깊이 이상 들어가면 Quick Sort 대신 Heap Sort로 정렬한다.



📃 정리

  • Quick Sort의 평균 시간복잡도는 O(NlogN)
  • Quick Sort의 최악의 시간복잡도는 O(N²)
  • Quick Sort는 In-Place(추가적인 공간이 필요하지 않음) Sort
  • cache hit rate가 높음



참고
[1] https://www.youtube.com/watch?v=59fZkZO0Bo4&t=68s
[2] https://blog.encrypted.gg/955

  1. 🐥 Quick Sort
  2. 💻 구현(C++)
  3. ⏱ 시간복잡도
  4. 💻 최악의 경우
  5. 📃 정리
'C++ Programming/알고리즘' 카테고리의 다른 글
  • [알고리즘] Counting Sort
  • [알고리즘] Merge Sort
  • [알고리즘] 크루스칼(Kruskal) 알고리즘
  • [알고리즘] 0-1 BFS
Krrong
Krrong
노는게 제일 좋아Krrong 님의 블로그입니다.
Krrong
노는게 제일 좋아
Krrong
전체
오늘
어제
  • 분류 전체보기 (302)
    • Android (2)
    • 우아한테크코스 (46)
      • Level 5 ~ (3)
      • Level 4 (8)
      • Level 3 | Project (8)
      • Level 2 (12)
      • Level 1 | Mission (4)
      • Level 1 | 정리 (5)
      • 프리코스 (6)
    • 스터디 (1)
      • 기술면접 질문 정리 (1)
      • Kotlin in Action (0)
    • AI⦁딥러닝 (5)
    • Jetson Xavier (9)
    • Computer Vision (6)
      • GoProCam (2)
      • OpenCV (4)
    • (구)Android (36)
      • 이론 (4)
      • Java (20)
      • Kotlin (12)
    • C++ Programming (161)
      • 백준 (146)
      • 알고리즘 (13)
      • STL 사용법 (2)
    • Git (5)
    • Spring (5)
    • 활동 (3)
    • 기타 (3)
    • 🇩🇪 (13)
      • 일상 (13)
    • ✈️ 여행 (3)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • 글쓰기
  • 티스토리홈

공지사항

인기 글

태그

  • 알고리즘
  • 퀵소트
  • 정렬알고리즘

최근 댓글

최근 글

hELLO · Designed By 정상우.
Krrong
[알고리즘] Quick Sort
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.