10장 정렬(Sorting)
단순 정렬 알고리즘
- 버블 정렬(Bubble Sort) : O(n2)
- 선택 정렬(Selection Sort) : O(n2)
- 삽입 정렬(Insertion Sort) : O(n2)
복잡하지만 효율적인 정렬 알고리즘
- 힙 정렬(Heap Sort) : O(nlog2n)
- 병합 정렬(Merge Sort) : O(nlog2n)
- 퀵 정렬(Quick Sort) : O(nlog2n)
- 기수 정렬(Radix Sort) : O(ln) -> O(n)
예상문제 : {13, 212, 14, 7141, 10987, 6, 15}
- 버블 정렬 2회전한 후의 결과는?
- 선택 정렬 3회전한 후의 결과는?
- 삽입 정렬 4회전한 후의 결과는?
- 힙 정렬을 위해 최소힙(Min Heap)을 구성한 후 2개 삭제 후의 힙을 그리시오.
- 병합정렬 과정을 단계별로 그리시오.
- 퀵정렬 과정을 단계별로 그리시오.
- 버킷 5개를 가지고 기수 정렬(LSD) 과정을 단계별로 그리시오.
- 버킷을 5개 가지고 하려면 5진수로 변경해서 풀어야 함(현재 수준으로는 어려움)
- 이번 퀴즈는 버킷 10개 중 0,1,2,3,4번만 가지고 풀 수 있는 문제로 출제했음
소스 코드
- 버블 정렬(Bubble Sort) : S010_BubbleSort.c
1234567891011121314151617181920212223242526272829#include <stdio.h>void BubbleSort(int arr[], int n){int i, j;int temp;for(i=0; i<n-1; i++){for(j=0; j<(n-i)-1; j++){if(arr[j] > arr[j+1]){temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;}}}}int main(void){int arr[4] = {3, 2, 4, 1};int i;BubbleSort(arr, sizeof(arr)/sizeof(int));for(i=0; i<4; i++)printf("%d ", arr[i]);printf("\n");return 0;} - 선택 정렬(Selection Sort) : S010_SelectionSort.c
123456789101112131415161718192021222324252627282930313233#include <stdio.h>void SelSort(int arr[], int n){int i, j;int maxIdx;int temp;for(i=0; i<n-1; i++){maxIdx = i; // 정렬 순서상 가장 앞서는 데이터의 indexfor(j=i+1; j<n; j++){ // 최소값 탐색if(arr[j] < arr[maxIdx])maxIdx = j;}/* 교환 */temp = arr[i];arr[i] = arr[maxIdx];arr[maxIdx] = temp;}}int main(void){int arr[4] = {3, 4, 2, 1};int i;SelSort(arr, sizeof(arr)/sizeof(int));for(i=0; i<4; i++)printf("%d ", arr[i]);printf("\n");return 0;} - 삽입 정렬(Insertion Sort) : S010_InsertionSort.c
1234567891011121314151617181920212223242526272829303132#include <stdio.h>void InserSort(int arr[], int n){int i, j;int insData;for(i=1; i<n; i++){insData = arr[i]; // 정렬 대상을 insData에 저장for(j=i-1; j>=0 ; j--){if(arr[j] > insData)arr[j+1] = arr[j]; // 비교 대상 한 칸 뒤로 밀기elsebreak; // 삽입 위치 찾았으니 탈출!}arr[j+1] = insData; // 찾은 위치에 정렬 대상 삽입!}}int main(void){int arr[5] = {5, 3, 2, 4, 1};int i;InserSort(arr, sizeof(arr)/sizeof(int));for(i=0; i<5; i++)printf("%d ", arr[i]);printf("\n");return 0;} - 힙 정렬(Heap Sort) : S010_HeapSort.c
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115#include <stdio.h>#define TRUE 1#define FALSE 0#define HEAP_LEN 100int numOfData;int heap[HEAP_LEN];void HeapInit(){numOfData = 0;}int HIsEmpty(){if(numOfData == 0)return TRUE;elsereturn FALSE;}int GetParentIDX(int idx) {return idx/2;}int GetLChildIDX(int idx){return idx*2;}int GetRChildIDX(int idx){return GetLChildIDX(idx)+1;}int GetHiPriChildIDX(int idx){if(GetLChildIDX(idx) > numOfData){ // 자식 노드가 없다면return 0;}else if(GetLChildIDX(idx) == numOfData){ // 왼쪽 자식 노드가 마지막 노드라면return GetLChildIDX(idx);}else{ // 왼쪽 자식 노드와 오른쪽 자식 노드의 우선순위를 비교if(heap[GetLChildIDX(idx)] > heap[GetRChildIDX(idx)])return GetRChildIDX(idx);elsereturn GetLChildIDX(idx);}}void HInsert(int pr){//root노드의 idx = 1int idx = numOfData + 1;int nelem = pr;while(idx != 1){if(pr < (heap[GetParentIDX(idx)])){heap[idx] = heap[GetParentIDX(idx)];idx = GetParentIDX(idx);}else{break;}}heap[idx] = nelem;numOfData += 1;}char HDelete(){char retData = heap[1]; // 삭제할 데이터 임시 저장int lastElem = heap[numOfData];int parentIdx = 1; // 루트 노드의 Indexint childIdx;while(childIdx = GetHiPriChildIDX(parentIdx)){if(lastElem <= heap[childIdx])break;heap[parentIdx] = heap[childIdx];parentIdx = childIdx;}heap[parentIdx] = lastElem;numOfData -= 1;return retData;}void HeapSort(int arr[], int n){int i;HeapInit();// 정렬 대상을 가지고 힙을 구성한다.for(i=0; i<n; i++)HInsert(arr[i]);// 순서대로 하나씩 꺼내서 정렬을 완성한다.for(i=0; i<n; i++)arr[i] = HDelete();}int main(void){int arr[8] = {3, 4, 2, 1, 7, 6, 9,5};int i;HeapSort(arr, sizeof(arr)/sizeof(int));for(i=0; i<sizeof(arr)/sizeof(int); i++)printf("%d ", arr[i]);printf("\n");return 0;} - 병합 정렬(Merge Sort) : S010_MergeSort.c
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364#include <stdio.h>#include <stdlib.h>void MergeTwoArea(int arr[], int left, int mid, int right){int fIdx = left;int rIdx = mid+1;int i;int * sortArr = (int*)malloc(sizeof(int)*(right+1));int sIdx = left;while(fIdx<=mid && rIdx<=right){if(arr[fIdx] <= arr[rIdx])sortArr[sIdx] = arr[fIdx++];elsesortArr[sIdx] = arr[rIdx++];sIdx++;}if(fIdx > mid){for(i=rIdx; i<=right; i++, sIdx++)sortArr[sIdx] = arr[i];}else{for(i=fIdx; i<=mid; i++, sIdx++)sortArr[sIdx] = arr[i];}for(i=left; i<=right; i++)arr[i] = sortArr[i];free(sortArr);}void MergeSort(int arr[], int left, int right){int mid;if(left < right){// 중간 지점을 계산한다.mid = (left+right) / 2;// 둘로 나눠서 각각을 정렬한다.MergeSort(arr, left, mid);MergeSort(arr, mid+1, right);// 정렬된 두 배열을 병합한다.MergeTwoArea(arr, left, mid, right);}}int main(void){int arr[7] = {3, 2, 4, 1, 7, 6, 5};int i;// 배열 arr의 전체 영역 정렬MergeSort(arr, 0, sizeof(arr)/sizeof(int)-1);for(i=0; i<7; i++)printf("%d ", arr[i]);printf("\n");return 0;} - 퀵 정렬(Quick Sort) : S010_QuickSort.c
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051#include <stdio.h>void Swap(int arr[], int idx1, int idx2){int temp = arr[idx1];arr[idx1] = arr[idx2];arr[idx2] = temp;}int Partition(int arr[], int left, int right){int pivot = arr[left]; // 피벗의 위치는 가장 왼쪽!int low = left+1;int high = right;while(low <= high){ // 교차되지 않을 때까지 반복while(pivot > arr[low])low++;while(pivot < arr[high])high--;if(low <= high) // 교차되지 않은 상태라면 Swap 실행Swap(arr, low, high); // low와 high가 가리키는 대상 교환}Swap(arr, left, high); // 피벗과 high가 가리키는 대상 교환return high; // 옮겨진 피벗의 위치 정보 반환}void QuickSort(int arr[], int left, int right){if(left <= right){int pivot = Partition(arr, left, right); // 둘로 나눠서QuickSort(arr, left, pivot-1); // 왼쪽 영역을 정렬QuickSort(arr, pivot+1, right); // 오른쪽 영역을 정렬}}int main(void){int arr[7] = {3, 2, 4, 1, 7, 6, 5};// int arr[3] = {3, 3, 3};int len = sizeof(arr) / sizeof(int);int i;QuickSort(arr, 0, sizeof(arr)/sizeof(int)-1);for(i=0; i<len; i++)printf("%d ", arr[i]);printf("\n");return 0;} - 기수 정렬(Radix Sort) : S010_RadixSort.c, LSD 기준
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129#include <stdio.h>#include <stdlib.h>#define BUCKET_NUM 10typedef struct _node{int data;struct _node * next;} Node;Node *front[BUCKET_NUM];Node *rear[BUCKET_NUM];////// queue의 기본함수 enqueue(), dequeue(), +알파함수 peek()void enqueue(int buck_no, int data){Node *newNode = (Node *)malloc(sizeof(Node));newNode->data = data;newNode->next = NULL;if(front[buck_no] == NULL){front[buck_no] = newNode;rear[buck_no] = newNode;}else{rear[buck_no]->next = newNode;rear[buck_no] = newNode;}}int dequeue(int buck_no){int data = -1;if(front[buck_no] == NULL){printf("Empty\n");}else{Node *cur = front[buck_no];data = cur->data;front[buck_no] = cur->next;free(cur);}return data;}int peek(int buck_no){if(front[buck_no] == NULL){printf("Empty\n");return -1;}else{return front[buck_no]->data;}}////////// stack 추가 함수void initQueue(int buck_no){front[buck_no] = NULL;rear[buck_no] = NULL;}int isEmpty(int buck_no){if(front[buck_no] == NULL){return 1; //true}else{return 0; //false}}void Free(){int i;Node *cur;for(i=0; i<BUCKET_NUM; i++){while(front[i] != NULL) {cur = front[i];front[i] = front[i]->next;free(cur);}}}///////// 메인 함수void RadixSort(int arr[], int num, int maxLen){ // maxLen은 가장 긴 데이터의 길이int bi;int pos;int di;int divfac = 1;int radix;// 총 10개의 버킷 초기화for(bi=0; bi<BUCKET_NUM; bi++)initQueue(bi);// 가장 긴 데이터의 길이만큼 반복for(pos=0; pos<maxLen; pos++){ // 정렬 대상의 수만큼 반복for(di=0; di<num; di++){// N번째 자리의 숫자 추출radix = (arr[di] / divfac) % 10;// 추출한 숫자를 근거로 데이터 버킷에 저장enqueue(radix, arr[di]);}// 버킷 수만큼 반복for(bi=0, di=0; bi<BUCKET_NUM; bi++){// 버킷에 저장된 것 순서대로 다 꺼내서 다시 arr에 저장while(!isEmpty(bi))arr[di++] = dequeue(bi);}// N번째 자리의 숫자 추출을 위한 피제수의 증가divfac *= 10;}}int main(void){int arr[7] = {13, 212, 14, 7141, 10987, 6, 15};int len = sizeof(arr) / sizeof(int);int i;RadixSort(arr, len, 5);for(i=0; i<len; i++)printf("%d ", arr[i]);printf("\n");return 0;}