목차
- 기준에 따라 데이터를 정렬
- [실전 문제] 위에서 아래로
- [실전 문제] 성적이 낮은 순서로 학생 출력하기
- [실전 문제] 두 배열의 원소 교체
기준에 따라 데이터를 정렬
- 정렬(Sorting)
- 데이터를 특정한 기준에 따라서 순서대로 나열
- 이진 탐색(Binary Search)에서 사용
- 선택 정렬, 삽입 정렬, 퀵 정렬, 계수 정렬
- 리스트를 뒤집는 연산 시간 복잡도 : O(N)
- 선택 정렬(Selection Sort)
- 매번 가장 작은 것을 선택하는 알고리즘
- 가장 작은 데이터를 선택해 맨 앞에 있는 데이터와 바꾸고, 그 다음 작은 데이터를 선택해 앞에서 두 번째 데이터와 바꾸는 과정을 반복하면 전체 데이터 정렬이 이루어진다.
- 시간 복잡도 : O(N^2)
- N-1번 만큼 가장 작은 수를 찾아서 맨 앞으로 보내야 한다.
- N X (N+1) / 2 = (N^2 + N) / 2 = O(N^2)
- 데이터가 늘어날 경우의 정렬 수행 시간(파이썬 기준)
- 삽입 정렬(Insertion Sort)
- 특정한 데이터를 적절한 위치에 삽입
- 그 앞의 데이터들은 이미 정렬되어 있다고 가정한다.
- 첫 번째 데이터는 그 자체로 정렬되어 있다고 생각하기 때문에 두 번째 데이터부터 시작한다.
- 시간 복잡도 O(N^2)
- 현재 리스트의 데이터가 거의 정렬되어 있는 상태일 경우 매우 빠르게 동작한다.
- 퀵 정렬(Quick Sort)
- 가장 많이 사용되는 알고리즘
- 기준을 설정한 다음 큰 수와 작은 수를 교환한 후에 리스트를 반으로 나누는 방식으로 동작한다.
- 피벗(Pivot)이 사용되고, 다양한 분할 방법이 있다.
- 호어 분할(Hoare Partition) : 가장 대표적인 분할 방식. 리스트에서 첫 번째 데이터를 피벗으로 정한다.
- 왼쪽에서부터 피벗보다 큰 데이터를 찾고, 오른쪽에서부터 피벗보다 작은 데이터를 찾는다.
- 큰 데이터와 작은 데이터의 위치를 서로 교환해준다.
- 왼쪽과 오른쪽에서 찾는 값이 엇갈린 경우 작은 데이터와 피벗의 위치를 서로 변경해준다.
- 분할 = 파티션(Divide = Partition) : 피벗의 왼쪽에는 피벗보다 작은 데이터가 위치하고, 피벗의 오른쪽에는 피벗보다 큰 데이터가 위치하도록 하는 작업
- 파티션이 완료된 상태에서 왼쪽 배열을 정렬 오른쪽 배열을 정렬
- (퀵 정렬 종료 조건) 현재 리스트의 데이터 개수가 1개인 경우, 이미 정렬이 되어 있다고 간주하여 분할이 불가능하다.
- 시간 복잡도 평균 : O(NlogN), 최악의 경우 : O(N^2)
- 무작위 데이터는 빠르게 동작할 확률이 높지만, 왼쪽 데이터를 피벗으로 삼을 때 이미 데이터가 정렬되어 있는 경우라면 매우 느리게 동작한다.
- 데이터 유형을 파악하기 어렵다면 퀵 정렬을 사용하는 것이 유리하다.
- 계수 정렬(Count Sort)
- 특정한 조건이 부합할 때만 사용할 수 있지만 매우 빠른 정렬 알고리즘
- 데이터 개수 N, 최대 값 K
- 최악의 경우에도 수행 시간 O(N + K) 보장
- (제한 조건) 데이터의 크기 범위가 제한되어 정수 형태로 표현할 수 있을 때만 사용 가능 -> 리스트(배열)을 선언해야 되기 때문
- 0이상 100이하인 성적 데이터 정렬에 효과적이다.
- 모든 범위를 담을 수 있는 배열을 생성하고, 모든 데이터를 0으로 초기화한다.
- 데이터를 하나씩 확인하며 데이터 값과 동일한 인덱스의 데이터를 1씩 증가시켜준다.
JAVA 정렬 라이브러리
- Arrays.sort()
- 듀얼 피봇 퀵 정렬 사용
- 시간 복잡도
- 평균 O(Nlog(N)
- 최악의 경우 O(N^2)
- Collection.sort()
- Timesort 사용
- 삽입 정렬과 합병 정렬을 결합하여 만든 정렬
- 시간 복잡도
- 평균 O(Nlog(N))
- 최악의 경우 O(Nlog(N))
- 최선의 경우 O(N)
- 삽입 정렬을 사용하는데 O(N^2)이 나오는 이유
- 삽입 정렬은 인접한 메모리와 비교를 반복하기 때문에 참조 지역성의 원리를 만족하고 있다.
- 작은 n 에 대하여 삽입 정렬이 빠른 속도를 보여준다.
- (아이디어) 전체를 작은 덩어리로 잘라 각각의 덩어리를 삽입 정렬을 사용하여 병합하면 좀 더 빨라질 것이다.
- 참고 글
- https://d2.naver.com/helloworld/0315536
- Timesort 사용
실전 문제 (1)
- 위에서 아래로
- 문제 요약
- 하나의 수열을 내림차순으로 정렬하는 프로그램
- 문제 해설
- 수의 개수가 500개 이하로 매우 적기 때문에, 모든 수는 1~100,000개이다. 어떠한 정렬 알고리즘이어도 상관 없기 때문에 가독성을 위해 기본 정렬 라이브러리를 사용한다.
실전 문제 (2)
- 성적이 낮은 순서로 학생 출력하기
- 문제 요약
- N 명의 학생
- 학생의 정보 - 이름, 성적
- 성적이 낮은 순서대로 학생 이름을 출력하는 프로그램
- 문제 해설
- 학생의 정보가 최대 100,000개이므로, 최악의 경우 O(NlogN)을 보장하는 알고리즘 혹은 O(N)을 보장하는 계수 정렬 사용
실전 문제 (3)
- 두 배열의 원소 교체
- 문제 요약
- 두 개의 배열 A, B은 N개의 원소로 구성
- 배열의 원소는 모두 자연수
- 최대 K번 바꿔치기 연산 수행 : 배열 A의 원소와 배열 B의 원소 하나를 골라서 서로 바꾸는 것
- 배열 A의 모든 원소 합의 최대값을 출력하는 프로그램
- 문제 해설
- 매번 배열 A에서 가장 작은 원소를 고르고, 배열 B에서 가장 큰 원소와 교체한다.
- 배열 A의 원소를 오름차순 정렬 후, 배열 B 원소를 내림차순 정렬한다.
- 그리고 두 배열의 원소를 가장 첫 번째 인덱스부터 비교해나간다.
- 단, 배열 A에서 가장 작은 원소 < 배열 B에서 가장 큰 원소 일 경우에만 수행
'CS > 자료구조&알고리즘' 카테고리의 다른 글
[알고리즘] JAVA 자료구조 HashSet, HashMap, TreeSet, TreeMap (0) | 2022.06.27 |
---|---|
[이것이 코딩테스트다] 2-7장 이진 탐색 (0) | 2022.01.28 |
[이것이 코딩테스트다] 2-5장 DFS/BFS (0) | 2022.01.26 |
[이것이 코딩테스트다] 2-4장 구현 (0) | 2022.01.17 |
[이것이 코딩테스트다] 2-3장 그리디 (0) | 2022.01.17 |