Hợp nhất GallopSearch: O (log (n) * log (i)) thay vì O (n)
Tôi đã đi trước và thực hiện đề nghị greybeard trong các ý kiến. Chủ yếu là vì tôi cần một phiên bản nhiệm vụ quan trọng của mã này.
- Mã này sử dụng một gallopSearch là O (log (i)) trong đó i là khoảng cách từ chỉ mục hiện tại mà chỉ mục có liên quan tồn tại.
- Mã sử dụng nhị phân Tìm kiếm sau khi tìm kiếm phi nước đại đã xác định phạm vi, phạm vi thích hợp. Vì phi nước đại giới hạn ở phạm vi nhỏ hơn, kết quả nhị phân Tìm kiếm cũng là O (log (i))
- Việc phi nước đại và hợp nhất được thực hiện ngược. Điều này dường như không phải là nhiệm vụ quan trọng nhưng nó cho phép hợp nhất các mảng. Nếu một trong các mảng của bạn có đủ chỗ để lưu trữ các giá trị kết quả, bạn chỉ cần sử dụng nó làm mảng hợp nhất và mảng kết quả. Bạn phải chỉ định phạm vi hợp lệ trong mảng trong trường hợp đó.
- Nó không yêu cầu phân bổ bộ nhớ trong trường hợp đó (tiết kiệm lớn trong các hoạt động quan trọng). Nó chỉ đơn giản là đảm bảo rằng nó không và không thể ghi đè lên bất kỳ giá trị chưa được xử lý nào (chỉ có thể được thực hiện ngược). Trong thực tế, bạn sử dụng cùng một mảng cho cả hai đầu vào và kết quả. Nó sẽ không bị ảnh hưởng xấu.
- Tôi luôn sử dụng Integer.compare () để có thể tắt các mục đích này.
- Có một số cơ hội tôi có thể đã bị lừa một chút và không sử dụng thông tin mà tôi đã chứng minh trước đây. Chẳng hạn như tìm kiếm nhị phân vào một phạm vi gồm hai giá trị, trong đó một giá trị đã được kiểm tra. Cũng có thể có một cách tốt hơn để nêu vòng lặp chính, giá trị lật c sẽ không cần thiết nếu chúng được kết hợp thành hai thao tác theo trình tự. Vì bạn biết bạn sẽ làm cái này rồi cái kia mọi lúc. Có chỗ để đánh bóng.
Đây phải là cách hiệu quả nhất để làm điều này, với độ phức tạp thời gian của O (log (n) * log (i)) thay vì O (n). Và độ phức tạp thời gian trường hợp xấu nhất của O (n). Nếu các mảng của bạn bị vón cục và có các chuỗi giá trị dài với nhau, điều này sẽ lùn đi bất kỳ cách nào khác để làm điều đó, nếu không nó sẽ tốt hơn chúng.
Nó có hai giá trị đọc ở cuối mảng hợp nhất và giá trị ghi trong mảng kết quả. Sau khi tìm ra giá trị cuối nào ít hơn, nó thực hiện tìm kiếm phi nước đại vào mảng đó. 1, 2, 4, 8, 16, 32, v.v. Khi nó tìm thấy phạm vi mà giá trị đọc của mảng khác lớn hơn. Nó tìm kiếm nhị phân vào phạm vi đó (cắt phạm vi một nửa, tìm kiếm một nửa chính xác, lặp lại cho đến khi một giá trị duy nhất). Sau đó, nó sao chép các giá trị đó vào vị trí ghi. Hãy nhớ rằng bản sao, do cần thiết, đã di chuyển sao cho nó không thể ghi đè lên cùng các giá trị từ mảng đọc (có nghĩa là mảng ghi và mảng đọc có thể giống nhau). Sau đó, nó thực hiện thao tác tương tự cho mảng khác mà hiện được biết là nhỏ hơn giá trị đọc mới của mảng khác.
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;
}
Đây phải là cách hiệu quả nhất để làm điều đó.
Một số câu trả lời có khả năng loại bỏ trùng lặp. Điều đó sẽ yêu cầu thuật toán O (n) vì bạn thực sự phải so sánh từng mục. Vì vậy, đây là một độc lập cho điều đó, sẽ được áp dụng sau thực tế. Bạn không thể phi nước đại qua nhiều mục trong suốt quá trình nếu bạn cần xem tất cả chúng, mặc dù bạn có thể phi nước đại qua các bản sao, nếu bạn có rất nhiều mục.
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;
}
Cập nhật: Câu trả lời trước, mã không kinh khủng nhưng rõ ràng kém hơn những điều trên.
Một tối ưu hóa không cần thiết khác. Nó không chỉ gọi bản sao cho các bit cuối, mà còn cho đầu. Xử lý bất kỳ giới thiệu không trùng lặp trong O (log (n)) bằng nhị phân Tìm kiếm vào dữ liệu. O (log (n) + n) là O (n) và trong một số trường hợp, hiệu ứng sẽ được phát âm khá rõ, đặc biệt là những thứ như không có sự chồng chéo giữa các mảng hợp nhất.
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;
}