GallopSearch Merge: O (n) yerine O (log (n) * log (i) )
Devam ettim ve yorumlarda greybeard öneri uyguladım. Çoğunlukla bu kodun son derece verimli bir görev kritik sürümüne ihtiyacım olduğu için.
- Kod, i, ilgili dizinin var olduğu geçerli dizinden uzaklık olduğu O (log (i)) olan bir gallopSearch kullanır.
- Kod, dörtnala araması uygun aralık tanımladıktan sonra için bir binarySearch kullanır. Dörtnala bunu daha küçük bir aralıkla sınırladığından, sonuçta ortaya çıkan ikili arama da O (log (i))
- Dörtnala ve birleştirme geriye doğru gerçekleştirilir. Bu görev açısından kritik görünmüyor ancak dizilerin yerinde birleştirilmesine izin veriyor. Dizilerinizden birinde sonuç değerlerini depolamak için yeterli alan varsa, bunu birleştirme dizisi ve sonuç dizisi olarak kullanabilirsiniz. Böyle bir durumda dizi içindeki geçerli aralığı belirtmelisiniz.
- Bu durumda bellek tahsisi gerektirmez (kritik işlemlerde büyük tasarruflar). Sadece işlenmemiş değerlerin üzerine yazılmadığından ve bunların üzerine yazamayacağından emin olur (yalnızca geriye doğru yapılabilir). Aslında, hem girişler hem de sonuçlar için aynı diziyi kullanırsınız. Hiçbir kötü etkisi olmayacaktır.
- Sürekli olarak Integer.compare () kullandım, bu yüzden bu başka amaçlar için kapatılabilir.
- Daha önce kanıtlamış olduğum bilgileri kullanmamam ve kullanmamam için bir şans var. Bir değerin önceden kontrol edildiği iki değer aralığına ikili arama gibi. Ana döngüyü belirtmenin daha iyi bir yolu da olabilir, sırayla iki işlem halinde birleştirildiyse, çevirme c değerine ihtiyaç duyulmaz. Bildiğiniz için her seferinde birini sonra diğerini yapacaksınız. Biraz cila için yer var.
Bunu yapmanın en etkili yolu, O (n) yerine O (log (n) * log (i)) 'nin zaman karmaşıklığıdır . Ve O (n) 'nin en kötü zaman karmaşıklığı. Dizileriniz beceriksizse ve birlikte uzun değer dizilerine sahipse, bunu yapmak için başka bir yol cüce olur, aksi takdirde onlardan daha iyi olur.
Birleştirme dizisinin uçlarında iki okuma değeri ve sonuç dizisi içindeki yazma değeri vardır. Hangisinin son değerin daha az olduğunu bulduktan sonra, bu dizide dörtnala arama yapar. 1, 2, 4, 8, 16, 32 vb. Diğer dizinin okuma değerinin daha büyük olduğu aralığı bulduğunda. Bu aralığa ikili aramalar yapar (aralığı yarıya indirir, doğru yarıyı arar, tek bir değere kadar tekrar eder). Sonra dizi bu değerleri yazma konumuna kopyalar. Kopyanın zorunlu olarak, her iki okuma dizisinden de aynı değerlerin üzerine yazamayacağı şekilde taşındığını unutmayın (yazma dizisi ve okuma dizisi aynı olabilir). Daha sonra, diğer dizinin yeni okuma değerinden daha az olduğu bilinen diğer dizi için aynı işlemi gerçekleştirir.
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;
}
Bunu yapmanın en etkili yolu bu olmalı.
Bazı cevaplar yinelenen kaldırma özelliğine sahipti. Her öğeyi gerçekten karşılaştırmanız gerektiğinden bu bir O (n) algoritması gerektirir. İşte işte bundan sonra uygulanacak tek başına. Hepsine bakmanız gerekiyorsa, birden fazla giriş boyunca dörtnala gidemezsiniz, ancak çoğunuz varsa kopyaları dörtnala yapabilirsiniz.
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;
}
Güncelleme: Önceki cevap, korkunç kod değil, yukarıdakilerden açıkça daha düşük.
Başka bir gereksiz hiper optimizasyon. Sadece son bitler için değil, aynı zamanda başlangıç için de dizikopi çağırır. O (log (n)) 'de herhangi bir tanıtıcı olmayan çakışma işlemini bir binarySearch ile veriye işleyerek. O (log (n) + n), O (n) 'dir ve bazı durumlarda, özellikle birleştirme dizileri arasında hiç çakışma olmayan yerler gibi etkiler oldukça belirgin olacaktır.
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;
}