1. 검색(Searching)
- 키(key)를 이용하여 원하는 데이터를 찾는 것
- 배열 검색을 위한 알고리즘
1) 선형 검색 : 무작위로 늘어놓은 데이터 모임에서 검색을 수행
2) 이진 검색 : 일정한 규칙으로 늘어놓은 데이터 모임에서 아주 빠른 검색을 수행
3) 해시법 : 추가, 삭제가 자주 일어나는 데이터 모임에서 아주 빠른 검색을 수행
(1) 체인법 : 같은 해시 값의 데이터를 선형 리스트로 연결하는 방법
(2) 오픈 주소법 : 데이터를 위한 해시 값이 충돌할 때 재해시하는 방법
- 데이터 집합에 대한 검색뿐 아니라 데이터의 추가, 삭제 등 다른 작업까지 고려해야 함
- 용도, 목적, 실행 속도, 자료구조 등을 고려하여 알고리즘을 선택하기
2. 선형 검색(Linear search)
1) 선형 검색이란?
- 요소가 직선 모양으로 늘어선 배열에서 원하는 키 값을 갖는 요소를 만날 때까지 맨 앞에서부터 순서대로 요소를 검색하는 것
- 다음 조건 중 하나라도 성립하면 검색을 종료함
조건 1. 검색할 값을 발견하지 못하고 배열의 끝을 지나간 경우 -> 검색 실패
조건 2. 검색할 값과 같은 요소를 발견한 경우 -> 검색 성공
- 배열의 요솟수가 n개일 때 조건 1,2를 판단하는 횟수의 평균값은 n / 2
- 선형 검색은 배열에서 순서대로 검색하는 유일한 방법임
2) 보초법(sentinel method)
- 선형 검색에서 종료 조건을 검사하는 비용을 반(50%)으로 줄이는 방법
- 검색하고자 하는 키 값을 맨 끝 요소, 즉 보초(sentinel)에 저장
조건 1. 검색할 값을 발견하지 못하고 배열의 끝을 지나간 경우 -> 검색 실패
조건 2. 검색할 값과 같은 요소를 발견한 경우 -> 검색 성공
- 원하는 데이터가 존재하지 않아도 보초까지 검색하면 조건 2가 성립함
- 조건 1을 판단하지 않게 되면서 반복문에서 종료 판단 횟수를 2회에서 1회로 줄임 (50% 감소)
3. 이진 검색(binary search)
1) 이진 검색이란?
- 요소가 오름차순 또는 내림차순으로 정렬된 배열에서 검색하는 알고리즘
ex) 48을 이진 검색할 때
(1) 배열의 중앙에 위치한 요소인 a[3]부터 검색을 시작
(2) 31은 48보다 작으므로 검색 대상을 a[4]~a[6]으로 좁힘. 그 중 중앙에 위치한 요소인 a[5]부터 검색
(3) 53은 48보다 크므로 검색 대상을 a[4]로 좁힘. a[4]가 48이므로 검색 성공
2) 검색 범위 좁히는 법
pl : 맨 앞 인덱스
pr : 맨 끝 인덱스
pc : 중앙 인덱스
key : 찾을 값
a[] : 값이 있는 배열
(1) a[pc] < key
- a[pl]~a[pc]는 key보다 작은 것이 분명하므로 검색 대상에서 제외
- 검색 범위는 a[pc]보다 뒷쪽인 a[pc+1]~a[pr]
- pl = pc + 1로 업데이트
(2) a[pc] > key
- a[pc]~a[pr]은 key보다 큰 것이 분명하므로 검색 대상에서 제외
- 검색 범위는 a[pc]보다 앞쪽인 a[pl]~a[pc-1]
- pr = pc - 1로 업데이트
- 종료 조건
조건 1. a[pc]와 key가 일치하는 경우 -> 검색 성공
조건 2. 검색 범위가 더 이상 없는 경우 -> 검색 실패
- 검색을 반복할 때마다 검색 범위가 절반이 되므로 검색에 필요한 비교 횟수의 평균값은 log n
4. 선형 검색과 이진 검색의 복잡도
1) 복잡도(complextiy)
- 알고리즘의 성능을 객관적으로 평가하는 기준
(1) 시간 복잡도(time complexity) : 실행에 필요한 시간을 평가한 것
(2) 공간 복잡도(space complexity) : 기억 영역과 파일 공간이 얼마나 필요한가를 평가한 것
- O(f(n))과 O(g(n))의 복잡도를 계산하는 법
O(f(n)) + O(g(n)) = O(max(f(n), g(n)))
즉, 전체 복잡도는 차원이 가장 높은 복잡도를 의미함
2) 선형 검색의 시간 복잡도
static int seqSearch(int[] a, int n, int key) {
int i = 0; // O(1)
while(i < n) { // O(n/2)
if(a[i] == key) // O(n/2)
return i; // O(1)
i++; // O(n/2)
}
return -1; // O(1)
}
※ 컴퓨터에게 n/2와 n의 차이는 크지 않다?
- n의 값이 무한히 커진다고 가정했을 때, n/2와 n의 차이는 무의미해지기 때문에 컴퓨터는 n/2를 n으로 인식함
O(1) + O(n) + O(n) + O(1) + O(n) + O(1) = O(n)
선형 검색 알고리즘의 복잡도는 O(n)
3) 이진 검색의 시간 복잡도
static binSearch(int[] a, int n, int key) {
int pl = 0; // O(1)
int pr = n - 1; // O(1)
do {
int pc = (pl + pr) / 2; // O(log n)
if(a[pc] == key) // O(log n)
return pc; // O(1)
else if(a[pc] < key) // O(log n)
pl = pc + 1; // O(log n)
else
pr = pc - 1; // O(log n)
} while(pl <= pr); // O(log n)
return -1; // O(1)
}
O(1) + O(1) + O(log n) + O(log n) + O(1) + O(log n) + ... + O(1) = O(log n)
이진 검색 알고리즘의 복잡도는 O(log n)
5. Arrays.binarySearch에 의한 이진 검색
1) Arrays.binarySearch
- Array는 배열에서 이진 검색을 하는 메서드를 표준 라이브러리로 제공
- javas.util.Arrays 클래스의 binarySearch 메서드 제공
- 이진 검색 메서드를 직접 코딩할 필요가 없고, 모든 자료형 배열에서 검색이 가능함
- 오름차순으로 정렬된 배열 a를 가정하고 키 값이 key인 요소를 이진 검색함
- javas.util.Arrays의 binarySearch 메서드 (출처 : docs.oracle.com/javase/8/docs/api/)
static int | binarySearch(byte[] a, byte key)
Searches the specified array of bytes for the specified value using the binary search algorithm. |
static int | binarySearch(byte[] a, int fromIndex, int toIndex, byte key)
Searches a range of the specified array of bytes for the specified value using the binary search algorithm. |
static int | binarySearch(char[] a, char key)
Searches the specified array of chars for the specified value using the binary search algorithm. |
static int | binarySearch(char[] a, int fromIndex, int toIndex, char key)
Searches a range of the specified array of chars for the specified value using the binary search algorithm. |
static int | binarySearch(double[] a, double key)
Searches the specified array of doubles for the specified value using the binary search algorithm. |
static int | binarySearch(double[] a, int fromIndex, int toIndex, double key)
Searches a range of the specified array of doubles for the specified value using the binary search algorithm. |
static int | binarySearch(float[] a, float key)
Searches the specified array of floats for the specified value using the binary search algorithm. |
static int | binarySearch(float[] a, int fromIndex, int toIndex, float key)
Searches a range of the specified array of floats for the specified value using the binary search algorithm. |
static int | binarySearch(int[] a, int key)
Searches the specified array of ints for the specified value using the binary search algorithm. |
static int | binarySearch(int[] a, int fromIndex, int toIndex, int key)
Searches a range of the specified array of ints for the specified value using the binary search algorithm. |
static int | binarySearch(long[] a, int fromIndex, int toIndex, long key)
Searches a range of the specified array of longs for the specified value using the binary search algorithm. |
static int | binarySearch(long[] a, long key)
Searches the specified array of longs for the specified value using the binary search algorithm. |
static int | binarySearch(Object[] a, int fromIndex, int toIndex, Object key)
Searches a range of the specified array for the specified object using the binary search algorithm. |
static int | binarySearch(Object[] a, Object key)
Searches the specified array for the specified object using the binary search algorithm. |
static int | binarySearch(short[] a, int fromIndex, int toIndex, short key)
Searches a range of the specified array of shorts for the specified value using the binary search algorithm. |
static int | binarySearch(short[] a, short key)
Searches the specified array of shorts for the specified value using the binary search algorithm. |
static <T> int | binarySearch(T[] a, int fromIndex, int toIndex, T key, Comparator<? super T> c)
Searches a range of the specified array for the specified object using the binary search algorithm. |
static <T> int | binarySearch(T[] a, T key, Comparator<? super T> c)
Searches the specified array for the specified object using the binary search algorithm. |
(1) 검색에 성공한 경우
- key와 일치하는 요소의 인덱스를 반환
- 이 때, 맨 앞의 인덱스나 특정한 인덱스가 아닌 무작위의 인덱스 반환
(2) 검색에 실패한 경우
- 삽입 포인트를 x라고 할 때 -x-1을 반환
- 삽입 포인트 : 검색하기 위해 지정한 key보다 큰 요소 중 첫 번째 요소의 인덱스
2) 기본 자료형 배열에서 binarySearch 메서드 사용
int[] x = {15, 27, 39, 77, 92, 108, 121};
int key1 = 39;
int key2 = 103;
int idx1 = Arrays.binarySearch(x, key1); // idx1 = 2 (검색 성공시 인덱스 반환)
int idx2 = Arrays.binarySearch(x, key2); // idx2 = -6 (검색 실패시 -(삽입포인트)-1 반환, 즉 -5-1 = -6 반환)
- 배열 x는 오름차순으로 정렬되어 있어야 함
3) 객체의 배열에서 binarySearch 메서드 사용
(1) static int binarySearch(Object[] a, Object key)
- '자연 정렬'이라는 방법으로 요소의 대소 관계를 판별
- 정수 배열, 문자열 배열에서 검색할 때 적절
(2) static <T> int binarySearch(T[] a, T key, Comparator<? super T> c)
- '자연 순서'가 아닌 순서로 줄지어 있는 배열에서 검색하거나 '자연 순서'를 논리적으로 갖지 않는 클레스 배열에서 검색할 때 적절
- 배열의 요소가 어떤 순서로 줄지어 있는지, 각 요소의 대소 관계를 어떻게 판단할 것인지에 대해서 알려주어야 하며, 이것이 세 번째 매개변수 c임
- 즉, Comparator 인터페이스와 compare 메서드를 구현한 클래스를 먼저 작성한 뒤, 그 클래스의 인스턴스를 생성하여 c로 전달함
참고 - Do it! 자료구조와 함께 배우는 알고리즘 입문 : 자바 편 (저자 : 보요 시바타, 출판 : 이지스 퍼블리싱)
'공부 > 알고리즘' 카테고리의 다른 글
[알고리즘-04] 정렬(Sorting) - 퀵 정렬, 병합 정렬, 힙 정렬 (0) | 2021.05.22 |
---|---|
[알고리즘+] 최대공약수, 최소공배수 (0) | 2021.04.27 |
[알고리즘-04] 정렬(Sorting) - 버블 정렬, 단순 선택 정렬, 단순 삽입 정렬 (0) | 2021.04.22 |
[알고리즘-03] 재귀 알고리즘 (0) | 2021.04.20 |
[알고리즘-01] 알고리즘, 순서도 (0) | 2021.03.14 |