주어진 자료에서 중복되지 않은 값이 주어질 때 그 데이터내에 특정 값이 존재하는지 검색하는 방법 중 이진탐색(Binary Search)은 자료를 정렬한후 분할정복방식으로 데이터를 2/1씩 나누면서 값이 존재하는지 확인하는 알고리즘을 사용했었다.
이진탐색이 데이터내 특정 값을 정확히 찾는 것이라면 lower bound와 upper bound 는 이진탐색 알고리즘에서 약간 변형된 것으로 중복된 자료가 있을때 유용하게 탐색할 수 있는 알고리즘으로
lower bound는 데이터내 특정 K값보다 같거나 큰값이 처음 나오는 위치를 리턴해주고 upper bound 는 K값보다 처음으로 큰 값이 나오는 위치를 리턴해주는 알고리즘이다.
△ [출처] http://bajamircea.github.io/coding/cpp/2018/08/09/lower-bound.html
위 그림에 보이듯이 중복된 값( 2, 3 값이 여러개 있다)이 있는 배열을 정렬한 상태에서 3의 값을 기준으로
lower_bound(3) 를 호출하면 3보다 같으면서 큰 값이 최초로 나타나는 index = 3을 리턴해주고
upper_bound(3) 3보다 큰 값이 젤 처음 나오는 index = 6을 리턴한다.
다음 예제를 보면 lower_bound 와 upper_bound 가 어떻게 다른지 좀 더 명확해 질 것이다.
△ [출처] http://bajamircea.github.io/coding/cpp/2018/08/09/lower-bound.html
lower_bound 와 upper_bound 는 stl 에서 내장된 메소드로 제공해주지만 자바에서는 제공해 주지 않기 때문에 필요하다면 직접 구현을 해야한다.
구현은 이진탐색(Binary Search)과 거의 비슷해서 어렵지 않으나 약간 다른 부분이 있어 그 부분만 주의 깊게 살펴보면 된다.
구현 전에 우선 이진검색 코드를 다시 상기하자
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public static int binarySearch(int[] list, int key) {
// 맨처음 low = 0, high는 배열의 끝이다.
int low = 0;
int high = list.length - 1;
while (low <= high) {
int mid = low + (high - low)/2; // mid 값을 계산.
if (key > list[mid]) // 키값이 더 크면 왼쪽을 버린다.
low = mid + 1;
else if (key < list[mid]) // 키값이 더 작으면 오른쪽을 버린다.
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found
}
Colored by Color Scripter
|
이진탐색과 다른점은 크기가 9인 int test1[] = {1,2,2,3,3,3,4,6,7} 이 주어질때 이진탐색은 정확히 같은 값이 있는곳을 찾는거지만 lower bound는 주어진 값보다 같거나 큰 값이 처음으로 나오는걸 리턴해야 하는데 만약 lower_bound(9) 면 주어진 배열크기 만큼 리턴되어야 하기 때문에 high = array.length -1 이 아니고 high = array.length로 지정 해야 한다.
그리고 탐색한 값이 주어진 값보다 크거나 같으면 바로 리턴하지 같거나 처음으로 나오는 값을 찾기위해 범위를 더 좁히면서 찾아간다.
예를들어 test1 에서 lower_bound(3) 을 호출하면
{1,2,2,3, 3 <- array[mid]는 여기를 가리킴.,3,4,6,7}
하지만 우리가 찾으려 하는 index 는 처음 mid = 4 가 아닌 mid=3 이어야 한다.
따라서 크거나 같은경우 high = mid 로 지정해서 범위를 좀더 좁혀 나가면서 찾아가는 것이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public static int lowerBound(int[] array, int value) {
int low = 0;
int high = array.length;
while (low < high) {
final int mid = low + (high - low)/2;
if (value <= array[mid]) {
high = mid;
} else {
low = mid + 1;
}
}
return low;
}
Colored by Color Scripter
|
그리고 탐색한 값이 주어진 값보다 크다면 바로 리턴하지 않고 최초로 큰 값이 있는 위치를 찾기 위해 high = mid 지정하여 범위를 더 좁히면서 찾아가면 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public static int upperBound(int[] array, int value) {
int low = 0;
int high = array.length;
while (low < high) {
final int mid = low + (high - low)/2;
if (value >= array[mid]) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
}
Colored by Color Scripter
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
public class Main {
public static void main(String[] args) {
int test1[] = {1,2,2,3,3,3,4,6,7};
}
}
Colored by Color Scripter
|
'알고리즘(Algorithm) > 검색 & 탐색(Searching)' 카테고리의 다른 글
부르트포스(Brute Force) (0) | 2019.07.04 |
---|---|
보간탐색(Interpolation Search) (2) | 2019.06.19 |
이진탐색(Binary Search) (0) | 2019.06.19 |
선형(순차) 탐색(Linear Search) (0) | 2019.06.19 |