가장 작은 데이터를 선택해 맨 앞에 있는 데이터와 바꾸고, 그 다음 작은 데이터를 선택해 앞에서 두 번째 데이터와 바꾸는 과정을 반복하는 방법
주어진 리스트 중에 최솟값을 찾는다.
그 값을 맨 앞에 위치한 값과 교체한다(패스(pass)).
맨 처음 위치를 뺀 나머지 리스트를 같은 방법으로 교체한다.
voidselection_sort(int list[],int n){int i, j, least,tmp;for(i=0;i<n-1;i++){ least = i;for(j=i+1;j<n;j++){if(list[j]<list[least]){ least = j; }SWAP(list[i],list[j],tmp); } }}
voidmerge(int array[],int left,int mid,int right){int i, j, k, m; i = left; j = mid +1; k = left; //결과 배열의 인덱스int tempArray[MAX];//left부터 mid 까지의 블록과 mid+1부터 right까지의 블록을 서로 비교하는 부분while (i <= mid && j <= right) {if (array[i] < array[j]){ //left index 값이 right index 값보다 작으면 left index 값을 결과 result에 복사 tempArray[k] = array[i]; i++; }else{ //아니라면 right index 값을 결과 result에 복사 tempArray[k] = array[j]; j++; } k++; }// left 블록의 값은 다 처리되었는데 right 블록의 index가 아직 남아있을 경우// right index를 순차적으로 결과 result에 복사if (i > mid){for (m = j; m <= right; m++){ tempArray[k] = array[m]; k++; } } else { // left 블록의 index가 아직 남아있을 경우 left index를 순차적으로 결과 result에 복사for (m = i; m <= mid; m++){ tempArray[k] = array[m]; k++; } }for(m = left; m <= right; m++){ array[m] = tempArray[m]; }}voidmerge_sort(int array[],int left,int right){int mid;// 분할이 다 되지 않았을 경우 if 문 실행if(left < right){ mid = (left + right)/2;merge_sort(array, left, mid); //왼쪽 블록 분할merge_sort(array, mid+1, right); //오른쪽 블록 분할merge(array, left, mid, right); //분할된 블록 병합 }}
복잡도 : O(n*log(n))
기수정렬(Radix Sort)
기수 정렬은 정수의 자리수를 기준으로 낮은 자리수부터 비교해 정렬하는 알고리즘입니다.
예를 들어 3자리 수라면 1의자리, 10의자리 , 100의 자리 숫자를 순서대로 비교해서 정렬하는 방법입니다.
#include<algorithm>boolcompare(int a,int b){// 오름차순 // return a<b;// 내림차순return a>b;}boolcomparep(POINT a,POINT b){if(a.x ==b.x ) returna.y <b.y;elsereturna.x <b.x;}//처음부터 n-1번째까지 원소를 compare함수의 정의대로 정렬//퀵정렬 기반으로 정렬한다.//std::sort(정렬할 자료의 시작 주소, 정렬할 자료의 마지막 주소,[비교함수 주소])std::sort(S,S+n,compare);
defquick_sort(array):iflen(array)<=1:return pivot = array[0] temp = array[1:] left = [i for i in temp if i < pivot] right = [i for i in temp if i > pivot]returnquick_sort(left)+ [pivot] +quick_sort(right)
시간 복잡도
평균적 : O(nlog(n))
최악의 경우 : O(N^2)
데이터 수
N^2(선택정렬, 삽입 정렬)
NlogN(퀵 정렬)
1,000
약 1,000,000
약 10,000
1,000,000
약 1,000,000,000,000
약 20,000,000
다만 퀵정렬은 평균적으로 시간복잡도가 O(NlogN)이지만 최악의 경우(이미 정렬되어 있는 경우) O(N^2)인 것을 주의해야한다.
모든 데이터가 양의 정수인 상황을 가정해볼 것이다. 데이터의 개수가 N, 데이터 중 최대값이 K일 때, 계수 정렬은 최악의 경우에도 수행시간 O(N+K)를 보장한다.
계수 정렬은 데이터의 크기 범위가 제한되어 정수 형태로 표현할 수 있을 때만 사용할 수 있다. 만약 데이터의 값이 무한한 범위를 가질 수 있는 실수형 데이터가 주어지는 경우에는 계수 정렬은 사용하기 어렵다. 일반적으로 가장 큰 데이터와 가장 작은 데이터의 차이가 1,000,000을 넘지 않을 때 효과적으로 사용할 수 있다.
계수 정렬은 위와 모든 범위를 담을 수 있는 크기의 리스트를 선언해야하기 때문에, 크기에 제한이 있다.
defcount_sort(array): count = [0] * (max(array)+1)for i in array: count[i]+=1for j inrange(len(count)):for x inrange(count[j]):print(j, end=' ')
시간 복잡도 : O(N+K), 최대값 크기 K, 데이터수 N
파이썬 3.7 정렬 알고리즘 비교
데이터 수(N)
선택 정렬
퀵 정렬
기본 정렬 라이브러리
100
0.0123
0.00156
0.00000753
1000
0.354
0.00343
0.0000365
10000
15.475
0.0312
0.000248
선택 정렬은 기본 정렬 라이브러리를 포함해 다른 알고리즘과 비교했을 때 매우 비효율 적이지만, 특정한 리스트에서 가장 작은 데이터를 찾을때는 유용하게 사용된다.
sorted()
파이썬 기본 정렬 라이브러리에서 제공하는 sorted()는 퀵정렬 과 동작 방식이 비슷한 병합 정렬을 기반(병합 정렬 + 삽입정렬)으로 만들어졌다. 병합 정렬은 퀵정렬보다 일반적으로 느리지만, 최악의 경우에도 O(NlogN) 시간 복잡도를 보장한다.