Gabung GallopSearch: O (log (n) * log (i)) daripada O (n)
Saya pergi ke depan dan menerapkan saran greybeard di komentar. Terutama karena saya memerlukan versi misi kritis yang sangat efisien dari kode ini.
- Kode menggunakan gallopSearch yang O (log (i)) di mana i adalah jarak dari indeks saat ini indeks yang relevan ada.
- Kode menggunakan binarySearch untuk setelah pencarian gallop telah mengidentifikasi rentang yang tepat. Karena gallop membatasi ini pada rentang yang lebih kecil, binarySearch yang dihasilkan juga O (log (i))
- Gallop dan penggabungan dilakukan mundur. Tampaknya ini bukan misi kritis, tetapi memungkinkan penggabungan array. Jika salah satu array Anda memiliki cukup ruang untuk menyimpan nilai hasil, Anda bisa menggunakannya sebagai array penggabungan dan array hasil. Anda harus menentukan rentang yang valid dalam array dalam kasus seperti itu.
- Dalam hal itu tidak memerlukan alokasi memori (penghematan besar dalam operasi kritis). Itu hanya memastikan itu tidak dan tidak bisa menimpa nilai-nilai yang tidak diproses (yang hanya dapat dilakukan mundur). Bahkan, Anda menggunakan array yang sama untuk input dan hasilnya. Itu tidak akan menderita efek buruk.
- Saya secara konsisten menggunakan Integer.compare () sehingga ini bisa dimatikan untuk keperluan lain.
- Ada kemungkinan saya mungkin telah melakukan kesalahan sedikit dan tidak memanfaatkan informasi yang sebelumnya telah saya buktikan. Seperti pencarian biner ke dalam rentang dua nilai, yang satu nilai sudah diperiksa. Mungkin juga ada cara yang lebih baik untuk menyatakan loop utama, nilai c membalik tidak akan diperlukan jika mereka digabungkan menjadi dua operasi secara berurutan. Karena Anda tahu Anda akan melakukan satu maka yang lain setiap kali. Ada ruang untuk memoles.
Ini harus menjadi cara paling efisien untuk melakukan ini, dengan kompleksitas waktu O (log (n) * log (i)) daripada O (n). Dan kompleksitas waktu kasus terburuk O (n). Jika array Anda kasar dan memiliki nilai string yang panjang, ini akan membuat cara lain untuk melakukannya lebih kecil, jika tidak maka hanya akan lebih baik daripada mereka.
Ini memiliki dua nilai baca di ujung array gabungan dan nilai tulis dalam array hasil. Setelah mengetahui nilai akhir mana yang kurang, ia melakukan pencarian gallop ke dalam array itu. 1, 2, 4, 8, 16, 32, dll. Ketika menemukan rentang di mana nilai baca array lain lebih besar. Ini biner mencari ke dalam rentang itu (memotong kisaran menjadi dua, mencari setengah yang benar, ulangi sampai nilai tunggal). Kemudian array akan menyalin nilai-nilai tersebut ke posisi penulisan. Perlu diingat bahwa salinan tersebut, secara tidak sengaja, dipindahkan sedemikian rupa sehingga tidak dapat menimpa nilai yang sama dari array pembacaan (yang berarti array penulisan dan array baca dapat sama). Itu kemudian melakukan operasi yang sama untuk array lain yang sekarang dikenal kurang dari nilai baca baru array lainnya.
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;
}
Ini harus menjadi cara paling efisien untuk melakukannya.
Beberapa jawaban memiliki kemampuan menghapus duplikat. Itu akan membutuhkan algoritma O (n) karena Anda harus benar-benar membandingkan setiap item. Jadi inilah yang berdiri sendiri untuk itu, untuk diterapkan setelah fakta. Anda tidak dapat berpacu melalui beberapa entri secara keseluruhan jika Anda perlu melihat semuanya, meskipun Anda bisa berpacu melalui duplikat, jika Anda memiliki banyak entri.
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;
}
Pembaruan: Jawaban sebelumnya, bukan kode yang mengerikan tetapi jelas lebih rendah daripada yang di atas.
Hyper-optimasi yang tidak perlu. Itu tidak hanya memanggil arraycopy untuk bit akhir, tetapi juga untuk awal. Memproses setiap pengantar non-tumpang tindih dalam O (log (n)) oleh binarySearch ke dalam data. O (log (n) + n) adalah O (n) dan dalam beberapa kasus efeknya akan sangat jelas terutama hal-hal seperti di mana tidak ada tumpang tindih antara array yang menggabungkan sama sekali.
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;
}