GallopSearch 병합 : O (n) 대신 O (log (n) * log (i) )
나는 의견에 회색 수염 제안을 이행했습니다. 주로이 코드의 매우 효율적인 미션 크리티컬 버전이 필요했기 때문입니다.
- 이 코드는 O (log (i)) 인 gallopSearch를 사용합니다. 여기서 i는 현재 색인에서 관련 색인이 존재하는 거리입니다.
- 이 코드는 갤럽 검색에서 적절한 범위를 식별 한 후 이진 검색을 사용합니다. 갤럽이이를 더 작은 범위로 제한했기 때문에 결과 binarySearch도 O (log (i))입니다.
- 갤럽 및 병합은 거꾸로 수행됩니다. 이것은 미션 크리티컬 한 것처럼 보이지 않지만 배열을 병합 할 수 있습니다. 배열 중 하나에 결과 값을 저장할 공간이 충분하면 병합 배열 및 결과 배열 로 간단히 사용할 수 있습니다 . 이 경우 배열 내에 유효한 범위를 지정해야합니다.
- 이 경우 메모리 할당이 필요하지 않습니다 (중요한 작업에서 크게 절약). 단순히 처리되지 않은 값을 덮어 쓸 수 없으며 덮어 쓸 수 없습니다 (뒤로 만 가능). 실제로 입력과 결과 모두에 동일한 배열을 사용합니다. 아무런 영향을 미치지 않습니다.
- 나는 Integer.compare ()를 일관되게 사용하여 다른 목적으로 전환 할 수있었습니다.
- 내가 약간 증명했을 수도 있고 내가 이전에 입증 한 정보를 활용하지 못할 수도 있습니다. 하나의 값이 이미 확인 된 두 값의 범위로 이진 검색과 같은. 메인 루프를 명시하는 더 좋은 방법이있을 수도 있습니다. 뒤집기 c 값이 순서대로 두 개의 연산으로 결합되면 필요하지 않습니다. 당신은 당신이 매번 다른 하나를 할 것을 알고 있기 때문에. 광택을 내야 할 여지가 있습니다.
이것은 O (n)이 아니라 O (log (n) * log (i))의 시간 복잡성과 함께 가장 효율적인 방법이어야합니다 . 그리고 최악의 경우 시간 복잡도 O (n). 배열이 울퉁불퉁하고 값이 긴 문자열을 사용하면 다른 방법으로 난장이 발생하지 않습니다. 그렇지 않으면 배열보다 낫습니다.
병합 배열의 끝에는 두 개의 읽기 값과 결과 배열 내의 쓰기 값이 있습니다. 어떤 값이 더 작은 지 알아 낸 후에는 해당 배열로 갤럽 검색을 수행합니다. 1, 2, 4, 8, 16, 32 등. 다른 배열의 읽기 값이 더 큰 범위를 찾으면. 이진은 해당 범위로 검색합니다 (범위를 반으로 자르고 올바른 반을 검색하며 단일 값까지 반복). 그런 다음 해당 값을 쓰기 위치에 복사합니다. 사본은 필연적으로 하나의 판독 배열에서 동일한 값을 덮어 쓸 수 없도록 이동합니다 (이는 기록 배열과 판독 배열이 동일 할 수 있음). 그런 다음 다른 어레이에 대해 동일한 작업을 수행하여 다른 어레이의 새로운 읽기 값보다 작은 것으로 알려져 있습니다.
static public int gallopSearch(int current, int[] array, int v) {
int d = 1;
int seek = current - d;
int prevIteration = seek;
while (seek > 0) {
if (Integer.compare(array[seek], v) <= 0) {
break;
}
prevIteration = seek;
d <<= 1;
seek = current - d;
if (seek < 0) {
seek = 0;
}
}
if (prevIteration != seek) {
seek = binarySearch(array, seek, prevIteration, v);
seek = seek >= 0 ? seek : ~seek;
}
return seek;
}
static public int binarySearch(int[] list, int fromIndex, int toIndex, int v) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
int midVal = list[mid];
int cmp = Integer.compare(midVal, v);
if (cmp < 0) {
low = mid + 1;
} else if (cmp > 0) {
high = mid - 1;
} else {
return mid;// key found
}
}
return -(low + 1);// key not found.
}
static public int[] sortedArrayMerge(int[] a, int[] b) {
return sortedArrayMerge(null, a, a.length, b, b.length);
}
static public int[] sortedArrayMerge(int[] results, int[] a, int aRead, int b[], int bRead) {
int write = aRead + bRead, length, gallopPos;
if ((results == null) || (results.length < write)) {
results = new int[write];
}
if (aRead > 0 && bRead > 0) {
int c = Integer.compare(a[aRead - 1], b[bRead - 1]);
while (aRead > 0 && bRead > 0) {
switch (c) {
default:
gallopPos = gallopSearch(aRead, a, b[bRead-1]);
length = (aRead - gallopPos);
write -= length;
aRead = gallopPos;
System.arraycopy(a, gallopPos--, results, write, length);
c = -1;
break;
case -1:
gallopPos = gallopSearch(bRead, b, a[aRead-1]);
length = (bRead - gallopPos);
write -= length;
bRead = gallopPos;
System.arraycopy(b, gallopPos--, results, write, length);
c = 1;
break;
}
}
}
if (bRead > 0) {
if (b != results) {
System.arraycopy(b, 0, results, 0, bRead);
}
} else if (aRead > 0) {
if (a != results) {
System.arraycopy(a, 0, results, 0, aRead);
}
}
return results;
}
가장 효율적인 방법입니다.
일부 답변에는 중복 제거 기능이있었습니다. 각 항목을 실제로 비교해야하므로 O (n) 알고리즘이 필요합니다. 사실 여기에 적용 할 독립형이 있습니다. 중복 된 항목이 많을 경우 중복 항목을 통해 갤럽 할 수 있지만 모든 항목을 확인해야하는 경우 여러 항목을 끝까지 질주 할 수 없습니다.
static public int removeDuplicates(int[] list, int size) {
int write = 1;
for (int read = 1; read < size; read++) {
if (list[read] == list[read - 1]) {
continue;
}
list[write++] = list[read];
}
return write;
}
업데이트 : 이전 답변, 끔찍한 코드는 아니지만 위의 것보다 분명히 열등합니다.
또 다른 불필요한 하이퍼 최적화. 종료 비트뿐만 아니라 시작 비트에 대해서도 arraycopy를 호출합니다. binarySearch를 사용하여 O (log (n))의 소개 비 중첩을 데이터로 처리합니다. O (log (n) + n)은 O (n)이며 어떤 경우에는 병합 배열간에 겹치지 않는 부분과 같은 효과가 특히 두드러집니다.
private static int binarySearch(int[] array, int low, int high, int v) {
high = high - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
int midVal = array[mid];
if (midVal > v)
low = mid + 1;
else if (midVal < v)
high = mid - 1;
else
return mid; // key found
}
return low;//traditionally, -(low + 1); // key not found.
}
private static int[] sortedArrayMerge(int a[], int b[]) {
int result[] = new int[a.length + b.length];
int k, i = 0, j = 0;
if (a[0] > b[0]) {
k = i = binarySearch(b, 0, b.length, a[0]);
System.arraycopy(b, 0, result, 0, i);
} else {
k = j = binarySearch(a, 0, a.length, b[0]);
System.arraycopy(a, 0, result, 0, j);
}
while (i < a.length && j < b.length) {
result[k++] = (a[i] < b[j]) ? a[i++] : b[j++];
}
if (j < b.length) {
System.arraycopy(b, j, result, k, (b.length - j));
} else {
System.arraycopy(a, i, result, k, (a.length - i));
}
return result;
}