GallopSearch合并:O(log(n)* log(i))而不是O(n)
我继续在评论中实施了灰胡子建议。主要是因为我需要此代码的高效关键任务版本。
- 该代码使用gallopSearch,它是O(log(i)),其中i是与当前索引相关的索引所在的距离。
- 疾驰搜索确定正确的范围后,代码将使用binarySearch进行搜索。由于疾驰将其限制在较小的范围内,因此生成的binarySearch也为O(log(i))
- 疾驰和合并是向后执行的。这似乎不是关键任务,但它允许就地合并阵列。如果您的一个数组有足够的空间来存储结果值,则可以简单地将其用作合并数组,然后结果数组。在这种情况下,必须在数组内指定有效范围。
- 在那种情况下,它不需要内存分配(在关键操作中节省了很多钱)。它只是确保它不会并且不会覆盖任何未处理的值(只能向后执行)。实际上,您对输入和结果使用相同的数组。它不会受到任何不良影响。
- 我一直使用Integer.compare(),因此可以出于其他目的将其切换出来。
- 我可能有一些机会被误用了,并且没有利用以前证明的信息。例如,对两个值的范围进行二进制搜索,已经检查了一个值。还有一种更好的方式来声明主循环,如果将它们依次组合为两个操作,则不需要翻转c值。既然您知道您每次都会做一个,那么另一个。还有一些地方可以擦亮。
这应该是最有效的方法,时间复杂度为O(log(n)* log(i))而不是O(n)。最坏的情况是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;
}