Bir milyar sayının medyanını hesaplayın


127

Bir milyar sayınız ve yüz bilgisayarınız varsa, bu sayıların medyanını bulmanın en iyi yolu nedir?

Sahip olduğum çözümlerden biri:

  • Seti bilgisayarlar arasında eşit olarak bölün.
  • Onları sıralayın.
  • Her set için medyanları bulun.
  • Setleri medyanlara göre sıralayın.
  • En düşükten en yüksek medyana bir seferde iki set birleştirin.

O m1 < m2 < m3 ...zaman önce birleştirirsek Set1ve Set2ortaya çıkan kümede medyandan Set12(birleştirilmiş) daha düşük olan tüm sayıları atabiliriz . Yani herhangi bir zamanda eşit büyüklükte kümelerimiz var. Bu arada, bu paralel bir şekilde yapılamaz. Herhangi bir fikir?


3
@John Boker: Aslında problem iki alt problemden oluşuyor: 1) listeyi sıralayın ve 2) 5'000'000'000 indeksli elemanı alın. Sayıların sıralandığına pek inanmıyorum.
Roman

3
@Roman: Sorunun tanımladığınız iki alt problemden oluşması gerekmez, örneğin hızlı seçim. Ancak quickselect, en azından önemsiz bir şekilde paralelleşmez. Ve elbette haklısınız, eğer sayılar önceden sıralanırsa bu oldukça anlamsız bir soru.
Steve Jessop

5
@fmsf: İngilizce konuşan hiçbir ülkenin İngilizcede uzun milyarları herhangi bir resmi amaç için kullandığını sanmıyorum . Örneğin burada, Birleşik Krallık'ta, onu 1974'te kullanmayı bıraktık . İngiliz dilinde "milyar" kelimesini bir milyon milyon anlamında kullanmanın, "gerçek bir milyar" değil, sapkın bir hile sorusu olduğunu düşünürdüm . Elbette Fransızca'da tamamen farklı bir konu olurdu, ama soru Fransızca değil.
Steve Jessop

5
Sıralamanıza gerek yok! en.wikipedia.org/wiki/…
glebm

2
1 milyar sayı yalnızca birkaç gigabayt veridir, bu görevi çözmek için birden fazla bilgisayara veya karmaşık algoritmalara ihtiyacınız yoktur. Fazla karmaşıklaştırma.
user626528

Yanıtlar:


54

Ah, beynim az önce devreye girdi, şimdi mantıklı bir önerim var. Bu bir röportaj olsaydı muhtemelen çok geç, ama boşver:

Makine 1, "kontrol makinesi" olarak adlandırılacaktır ve argüman uğruna, ya tüm verilerle başlar ve diğer 99 makineye eşit parseller halinde gönderir, ya da veriler, makineler arasında eşit olarak dağıtılmaya başlar ve verilerinin 1 / 99'unu diğerlerinin her birine gönderir. Bölmelerin eşit olması gerekmez, sadece yakın.

Her bir makine verilerini sıralar ve bunu, önce düşük değerleri bulmaya yardımcı olacak şekilde yapar. Örneğin, hızlı sıralama, her zaman önce bölümün alt kısmını [*] sıralar. Verilerini mümkün olan en kısa sürede artan sırayla kontrol makinesine geri yazar (sıralamaya devam etmek için asenkron IO kullanarak ve muhtemelen Nagle açıkken: biraz deney yapın).

Kontrol makinesi, gelen veriler üzerinde 99 yönlü bir birleştirme gerçekleştirir, ancak birleştirilmiş verileri atar, yalnızca gördüğü değerlerin sayısını tutar. Medyanı 1/2 milyarıncı ve 1/2 milyar artı birinci değerlerin ortalaması olarak hesaplar.

Bu, "sürüdeki en yavaş" probleminden muzdariptir. Algoritma, medyandan daha düşük her değer bir sıralama makinesi tarafından gönderilinceye kadar tamamlanamaz. Veri paketi içinde böyle bir değerin oldukça yüksek olması makul bir olasılıktır. Dolayısıyla, verilerin ilk bölümlenmesi tamamlandıktan sonra, tahmini çalışma süresi, verilerin 1 / 99'unu sıralayıp kontrol bilgisayarına geri gönderme süresi ile kontrolün verileri 1/2 okuma süresinin birleşimidir. . "Kombinasyon" maksimum ve bu zamanların toplamı arasında, muhtemelen maksimuma yakın bir yerdedir.

İçgüdülerim, bir ağ üzerinden veri göndermenin, sıralamaktan daha hızlı olması için (sadece medyanı seçmek şöyle dursun) oldukça hızlı bir ağ olması gerektiğidir. Ağın anlık olduğu varsayılabiliyorsa, örneğin verileri içeren RAM'e eşit erişime sahip 100 çekirdeğiniz varsa daha iyi bir olasılık olabilir.

Ağ G / Ç büyük olasılıkla bağlı olduğundan, en azından kontrol makinesine geri gelen veriler için oynayabileceğiniz bazı hileler olabilir. Örneğin, "1,2,3, .. 100" göndermek yerine, belki bir tasnif makinesi "101'den küçük 100 değer" anlamına gelen bir mesaj gönderebilir. Kontrol makinesi daha sonra, en üstteki değerlerin en azını bulduğu değiştirilmiş bir birleştirme gerçekleştirebilir ve ardından tüm ayırma makinelerine bunun ne olduğunu söyler, böylece (a) kontrol makinesine nasıl olduğunu söyleyebilirler. birçok değer bu değerin altında "sayılır" ve (b) sıralı verilerini bu noktadan göndermeye devam eder.

Daha genel olarak, muhtemelen kontrol makinesinin 99 sıralama makinesiyle oynayabileceği akıllıca bir meydan okuma-yanıt tahmin oyunu vardır.

Bu, daha basit olan ilk versiyonumdan kaçınılan, makineler arasında gidiş-dönüşleri içerir. Göreceli performanslarını nasıl körü körüne tahmin edeceğimi gerçekten bilmiyorum ve değiş tokuşlar karmaşık olduğu için, bunun gerçek bir sorun olduğunu varsayarak, kendimle ilgili düşüneceğim her şeyden çok daha iyi çözümler olduğunu hayal ediyorum.

[*] kullanılabilir yığın izni - O (N) fazladan alanınız yoksa, ilk olarak hangi parçanın yapılacağına dair seçiminiz kısıtlıdır. Ancak, yeterince fazladan alanınız varsa, seçiminizi yapabilirsiniz ve yeterli alanınız yoksa, en azından ilk birkaç bölüm için küçük bölümü yaparak bazı köşeleri kesmek için yaptığınız şeyi kullanabilirsiniz.


Lütfen beni düzeltin, eğer yanılıyorsam, yalnızca daha sonra atmak için geldiği için veriler üzerinde neden 99'lu birleştirme gerçekleştiriyorsunuz? Bunun yerine sayıları geldikçe tutmak yeterli mi?
sreeprasad

4
@SREEPRASADGOVINDANKUTTY: tekrarlanan adım, 99 adayın en küçük değerini atmak ve sayımı artırmaktır. Bu 99 yönlü birleştirme adımı olmadan gelen tüm değerlerin sayısını tutmanın hiçbir faydası yoktur. Bunları geldiklerinde karşılaştırmazsanız, attığınız değerin medyanın altında olduğunu bilemezsiniz.
Steve Jessop

Ancak, bu bölümlerden herhangi birinin sadece medyandan daha yüksek sayılar içermesi ve bu nedenle geri döndürdüğü daha düşük bölümlerin medyandan daha yüksek olması için küçük bir şans yok mu, ancak kontrol bunu bilmediğinden, onları, medyan ve başarısız ...?
Gullydwarf

@Gullydwarf: Çok yönlü bir birleştirme, elindeki 99 değerden yalnızca en küçük olanını atar ve bunların her biri diğer makinelerden birinden kalan en küçük değerdir. Bölümlerden biri medyandan tamamen büyükse, medyan geçene kadar bu 99 değerin en küçüğü olmayacaktır (bu noktada bitiriyoruz). Yani atılmayacak.
Steve Jessop

52
sort -g numbers | head -n 500000001 | tail -n 2 | dc -e "1 k ? ? + 2 / p"

2
LOL. Bu gerçekten işe yarıyor mu yoksa OOM katili tamamlanmadan önce onu bombalayacak mı? (herhangi bir makul bilgisayarda)
Isak Savo

5
Yapmak gerekir. sort, çekirdek dışı sıralamanın nasıl yapılacağını bilir, bu nedenle bellek tükenmez.
DrPizza

6
@Zagfai Çok uzun süreceğini sanmıyorum; bir milyar sayı, 32-bit girişler / kayan değerler için yalnızca 4 GB, 64-bit girişler / çiftler için 8GB'dir. İkisi de muazzam bir şekilde yorucu görünmüyor.
DrPizza

13
Intel i5-4200M @ 3.1 GHz (4 çekirdek) üzerinde denedim. timeTüm boru hattına uygulanan komuta göre , real=36m24s("duvar saati zamanı"), user=113m15s ("paralel zaman", tüm çekirdekler eklendi) aldı. En uzun komut, diğerlerinin çok ilerisinde, sortdört çekirdeğime% 100 oranında işlenmiş olsa bile oldu . RAM tüketimi çok kabul edilebilirdi.
Morgan Touverey Kağıt Oymacılığı

12
Sonra 100 bilgisayarda çalıştırın, böylece sonucun doğru olduğundan 100 kat daha fazla emin olabilirsiniz :)
dos

27

Burada aykırı olmaktan nefret ediyorum, ancak sıralamanın gerekli olduğuna inanmıyorum ve bence bir milyar / 100 sayıyı sıralamayı içeren herhangi bir algoritma yavaş olacak. Bir bilgisayarda bir algoritma düşünelim.

1) Milyardan rastgele 1000 değer seçin ve bunları sayıların dağılımı, özellikle de bir aralık hakkında fikir edinmek için kullanın.

2) Değerleri sıralamak yerine, az önce hesapladığınız dağıtıma göre bunları paketlere ayırın. Bölmelerin sayısı, bilgisayarın bunları verimli bir şekilde işleyebilmesi için seçilir, ancak aksi takdirde uygun olduğu kadar büyük olmalıdır. Bölüm aralıkları, her bir bölüme yaklaşık olarak eşit sayıda değer girecek şekilde olmalıdır (bu, algoritma için kritik değildir, ancak verimliliğe yardımcı olur. 100.000 kova uygun olabilir). Her bir gruptaki değerlerin sayısına dikkat edin. Bu bir O (n) sürecidir.

3) Medyanın hangi kova aralığında olduğunu bulun. Bu, her bir bölümdeki toplam sayıları inceleyerek yapılabilir.

4) Bu bölümdeki değerleri inceleyerek gerçek medyanı bulun. Yalnızca 10.000 sayıyı sıraladığınız için, burada isterseniz bir sıralama kullanabilirsiniz. Bu paketteki değerlerin sayısı büyükse, sıralama için yeterince küçük bir sayı elde edene kadar bu algoritmayı tekrar kullanabilirsiniz.

Bu yaklaşım, değerleri bilgisayarlar arasında bölerek önemsiz bir şekilde paralel hale gelir. Her bilgisayar, her bir gruptaki toplamları, 3. adımı gerçekleştiren bir 'kontrol' bilgisayarına bildirir. Adım 4 için her bilgisayar, ilgili gruptaki (sıralanan) değerleri kontrol bilgisayarına gönderir (bu algoritmaların her ikisini de paralel olarak yapabilirsiniz, ama muhtemelen buna değmez).

Toplam işlem O (n) 'dir, çünkü 3. ve 4. adımların her ikisi de önemsizdir, kova sayısı yeterince büyükse.


1
Sanırım bu medyan medyan ve hızlı seçim algoritmaları arasında bir şey. en.wikipedia.org/wiki/Selection_algorithm
Dimath

4. adımda, paketler yalnızca 10.000 içermeyebilir. Dağılımın ortaya doğru çarpık olması, örneğin verilerin% 80'ini içerebileceği, ki bu hala çok büyük olabilir.
justhalf

Bunu hesaba katmak için düzenlendi.
DJClayworth

4
Bu algoritmada performans O (n) değildir: çoğu sayının "medyan" kovasına düşmesini sağlayabilir ve her şeyi sıralamak kadar kötü performans gösterebilir.
Sklivvz

1
@WULF Mükemmel bir soru. Algoritmanın anahtarıdır ve 1. adım bunu ele alır. Bir dağılım oluşturmak için sayıların örneklenmesi bulduğum en iyisidir.
DJClayworth

12

Bir milyar, aslında modern bir bilgisayar için oldukça sıkıcı bir iştir. Burada 4 GB değerinde 4 baytlık tam sayılardan bahsediyoruz ... 4 GB ... bu bazı akıllı telefonların RAM'idir.

public class Median {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();

        int[] numbers = new int[1_000_000_000];

        System.out.println("created array after " +  (System.currentTimeMillis() - start) + " ms");

        Random rand = new Random();
        for (int i = 0; i < numbers.length; i++) {
            numbers[i] = rand.nextInt();
        }

        System.out.println("initialized array after " + (System.currentTimeMillis() - start) + " ms");

        Arrays.sort(numbers);

        System.out.println("sorted array after " + (System.currentTimeMillis() - start) + " ms");

        if (numbers.length % 2 == 1) {
            System.out.println("median = " + numbers[numbers.length / 2 - 1]);
        } else {
            int m1 = numbers[numbers.length / 2 - 1];
            int m2 = numbers[numbers.length / 2];
            double m = ((long) m1 + m2) / 2.0;
            System.out.println("median = " + new DecimalFormat("#.#").format(m));
        }
}

Makinemdeki çıktı:

created array after 518 ms
initialized array after 10177 ms
sorted array after 102936 ms
median = 19196

Yani bu, tek bir çekirdek kullanarak makinemde iki dakikadan daha kısa bir sürede (1:43 bunlardan 0:10 rasgele sayılar oluşturmak içindir) ve hatta tam bir sıralama yapıyor. Gerçekten hiçbir şey fantezi değil.

Bu kesinlikle daha büyük sayı kümeleri için ilginç bir görevdir. Burada bir noktaya değinmek istiyorum: Bir milyar fıstıktır. Şaşırtıcı derecede basit görevlere karmaşık çözümler sunmaya başlamadan önce iki kez düşünün;)



1
@vidstige Gerçekten okumadım, ama haklısın. cevabım kesinlikle daha uygulamalı olsa da, insanlar bunu biraz daha takdir ediyor gibi görünüyor;)
sfussenegger

Medyan olsa olmadığını, medyan olup (numbers[numbers.length / 2]+numbers[numbers.length / 2+1])/2olmadığını numbers.lengthbile ve olduğunu numbers[numbers.length / 2]yalnızca numbers.lengthgarip.
Sklivvz

@Sklivvz doğru, ancak medyanı hesaplamak için geçen süreyi farkedilebilir şekilde etkilememelidir.
vidstige

1
@Sklivvz tabii ki haklısın. Medyan hesaplamasını yeni güncelledim. Yine de cevabın geri kalanını değiştirmez.
sfussenegger

10

Tahmini ortalama ve 99. yüzdelik gibi sıra istatistiklerinin verimli gibi algoritmalar ile dağıtılabilir t-sindirimi ya da Q-sindirimi .

Her iki algoritmayı kullanarak her düğüm, yerel olarak depolanan değerlerin dağılımını temsil eden bir özet üretir. Özümler tek bir düğümde toplanır, birleştirilir (dağılımları etkin bir şekilde toplar) ve daha sonra medyan veya başka herhangi bir yüzdelik dilim aranabilir.

Bu yaklaşım tarafından kullanılan elasticsearch ve, muhtemelen, BigQuery (kantilleri fonksiyonunun açıklama ile gidiş).


5

Bu sayı kümesi için medyan

2, 3, 5, 7, 11, 13, 67, 71, 73, 79, 83, 89, 97

67.

Bu sayı kümesi için medyan

2, 3, 5, 7, 11, 13, 67, 71, 73, 79, 83, 89

40'tır.

Sorunun yaklaşık 1.000.000.000 tamsayı (x) olduğunu varsayarsak 0> = x <= 2.147.483.647 ve OP'nin aradığı (öğe (499.999.999) + öğe (500.000.000)) / 2 (sayılar sıralıysa). Ayrıca 100 bilgisayarın hepsinin eşit olduğunu varsayarsak.

dizüstü bilgisayarımı ve GigE'yi kullanarak ...

Bulduğum şey, dizüstü bilgisayarımın 10.000.000 Int32'yi 1.3 saniyede sıralayabildiğiydi. Yani kaba bir tahmin, bir milyar sayı sıralaması 100 x 1.3 saniye (2 dakika 10 saniye);)

Bir gigabit Ethernet üzerinde 40 MB'lık bir dosyanın tek yönlü bir dosya aktarımı tahmini .32 saniyedir. Bu, tüm bilgisayarlardan sıralanan sonuçların yaklaşık 32 saniye içinde geri döneceği anlamına gelir (bilgisayar 99, dosyayı başladıktan 30 saniye sonrasına kadar alamadı). Oradan en düşük 499,999,998 sayıyı atmak, sonraki 2'yi eklemek ve 2'ye bölmek uzun sürmemelidir.


3
Seçmen yorumu olumsuz mu? Nasıl daha iyisini yapabileceğimi anlamama yardımcı olur.
dbasnett

5
Ben aşağı seçen değilim, ancak bir milyar sayıyı sıralamak 10 milyonu sıralamaktan 100 kat daha uzun sürmez, çünkü bir listeyi sıralamak için en kötü durum karmaşıklığı O (n log n). Sıralama aynı zamanda hafızanız tükendiğinde ve diskte sıralamaya başlamanız gerektiğinde daha yavaş olan siparişlerdir.
Richard Poole

Bence doğru yoldasınız; Amaç bir kerede mümkün olan en hızlı cevapsa, birden fazla makinede sıralama yapmak iyi bir fikir olabilir. Ancak hedef en düşük ortalama süre ise, her makinenin kendi aramasını yapması daha mantıklıdır.
Charlie

Aynı faktöre sahip olduklarını varsayarsak (muhtemelen bellek sorunları nedeniyle yoklar) a*(1e7)log(1e7) = 1.3sec=> a = 1.6e-9sec => a*(1e9)log(1e9) ~ 167sec, yani tahmininiz o kadar da kapalı değildi.
bcorso

Tahminleriniz çok kaba. İlk olarak, bazı sıralama algoritmaları en kötü senaryoda (örneğin yaygın olarak kullanılan hızlı sıralama) o (n ^ 2) olarak gider. İkinci olarak, L2 önbelleğinizin boyutu ile ilgili bir test veri kümesi seçtiniz. Bu, sonuçları çarpıtır. Üçüncü olarak, siz (diğer birçok cevaplayıcı gibi) "sayı" nın "tam sayı" anlamına geldiğini varsayarsınız. Çok farklı performans özelliklerine sahip kayan nokta, çift veya ondalık anlamına gelebilir.
Sklivvz

5

Bu insanları şaşırtabilir, ancak sayılar 32 bit (veya daha küçük) içine sığacak kadar küçük tamsayılarsa - Sadece bir kova sıralaması yapın! Herhangi bir sayıda 32 bitlik giriş için yalnızca 16 GB ram gerekir ve O (n) ile çalışır, bu da makul n için herhangi bir dağıtılmış sistemden daha iyi performans göstermelidir, örneğin bir milyar.

Sıralanmış listeye sahip olduğunuzda, medyanı seçmek önemsizdir. Aslında, sıralı listeyi oluşturmanıza gerek yoktur, ancak bunu yalnızca paketlere bakarak yapmalısınız.

Aşağıda basit bir uygulama gösterilmektedir. Yalnızca 16 bitlik tam sayılar için çalışır, ancak 32 bit'e genişletme kolay olmalıdır.

#include <stdio.h>
#include <string.h>

int main()
{
    unsigned short buckets[65536];
    int input, n=0, count=0, i;

    // calculate buckets
    memset(buckets, 0, sizeof(buckets));
    while (scanf("%d", &input) != EOF)
    {
        buckets[input & 0xffff]++;
        n++;
    }

    // find median 
    while (count <= n/2)
    {
        count += buckets[i++];
    }

    printf("median: %d\n", i-1);

    return 0;
}

Bir milyar ( 109 ) sayı içeren bir metin dosyası kullanmak ve bunun timegibi çalıştırmak

time ./median < billion

makinemde 1m49.293s çalışma süresi verir. Çalışma süresinin çoğu muhtemelen disk IO'dur.


Bu gerçekten soruyu cevaplamaz ve varsayımlara dayanır. Örneğin, tam sayı olduklarını bile bilmiyorsunuz.
Sklivvz

Soruya ne şekilde cevap vermiyor? Ve evet, cevabım sayıların tam sayı olduğunu varsayıyor. Varsayımlarımı net bir şekilde ifade etmeye çalıştım.
vidstige

Tam sayıya sahip olmanın bir varsayım olduğunu belirtmiyorsunuz, ne de OP'nin sorduğu 100 bilgisayarı nasıl kullanacağınıza değinmiyorsunuz. Medyanı bir düğümde hesaplayabilirsiniz, ancak nedenini göstermedikçe bu "en iyi" çözüm değildir. Ayrıca, en.wikipedia.org/wiki/Radix_sort#Efficiency'ye göre basamak sayısı değişiyorsa, radix sıralaması o (n) değildir, bu durumda kesinlikle o (n log n)
Sklivvz

"Eğer tam sayılar 32 bitlik bir tamsayıya sığacak kadar küçükse" diyerek başlıyorum ... Radix sıralaması, gönderdiğiniz bağlantıda büyük açıklıkla açıklandığı gibi sabit bir kelime boyutu w için O (n) 'dir . Burada sabit bir kelime boyutunun 32 olduğunu varsayıyorum.
vidstige

1
Diğer 99 bilgisayarla ne yaptığınız bu yanıtla alakalı değildir. Bir piramit oluşturmak veya yakmak için onları üst üste koyabilirsiniz. Veya onları görmezden gelin.
vidstige

3

İşin garibi, bence yeterince bilgisayarınız varsa, O(n)medyan bulma algoritmalarını kullanmaktansa sıralama yapmanız daha iyidir . (Çekirdekleriniz çok, çok yavaş O(n)değilse, sadece bir tane kullanır ve sadece 1e9 sayıları için bir ortanca bulma algoritması kullanırdım; 1e12 varsa, bu daha az pratik olabilir.)

Her neyse, bu sorunu çözmek için log n çekirdeğimizden daha fazlasına sahip olduğumuzu ve güç tüketimini önemsemediğimizi, sadece cevabı hızlı aldığımızı varsayalım. Ayrıca, bunun belleğe önceden yüklenmiş tüm verilerin bulunduğu bir SMP makinesi olduğunu varsayalım. (Örneğin, Sun'ın 32 çekirdekli makineleri bu türdendir.)

Bir iş parçacığı listeyi körü körüne eşit büyüklükte parçalara böler ve diğer M iş parçacığına bunları sıralamasını söyler. Bu iplikler (n/M) log (n/M)zamanla bunu gayretle yapıyor . Daha sonra sadece medyanlarına değil, aynı zamanda 25. ve 75. yüzdelik dilimlerine de geri dönerler (biraz farklı sayılar seçerseniz en kötü durum daha iyidir). Artık 4 milyon veri aralığına sahipsiniz. Daha sonra bu aralıkları sıralayın ve bir sayı bulana kadar listede yukarı doğru çalışın, öyle ki, sayıdan daha küçük olan veya sayı içeren her aralığı atarsanız , verilerinizin yarısını atmış olursunuz. Bu medyan için alt sınırınız. Üst sınır için de aynısını yapın. Bu, M log Mzaman gibi bir şey alır ve tüm çekirdeklerin beklemesi gerekir, bu yüzden gerçekten israf olurM^2 log Mpotansiyel zaman. Artık tek iş parçacığınızı diğerlerine tüm verileri aralığın dışına atmalarını (her geçişte yaklaşık yarısını atmalısınız) ve tekrar etmelerini söyleyin - veriler zaten sıralandığı için bu önemsiz derecede hızlı bir işlemdir. log(n/M)Kalan verileri alıp O(n)üzerinde standart bir medyan bulucu kullanmak daha hızlı olmadan önce bunu defalarca tekrarlamanız gerekmez .

Yani toplam karmaşıklık buna benzer O((n/M) log (n/M) + M^2 log M log (n/M)). Bu nedenle, bu, O(n)bir çekirdekte medyan sıralamadan daha hızlıdır M >> log(n/M)ve M^3 log M < nbu, tanımladığınız senaryo için doğrudur.

Ne kadar verimsiz olduğu düşünüldüğünde , bunun gerçekten kötü bir fikir olduğunu düşünüyorum , ama daha hızlı.


o (n / M log (n / M)), kelimenin tam anlamıyla, o (n log n) 'dir, çünkü o (n / M log (n / M)) = 1 / M o (n (log n - log M) ) = o (n log n). Bunu o (n) ile gerçekten karşılaştıramazsınız, çünkü "o" temelde "büyük çok n için orantılı ve bazı belirtilmemiş sabitler" anlamına gelir. Bu sabitleri bilmediğiniz sürece karşılaştıramazsınız, ancak yeterince büyük N için sabitler baskın değildir. Daha düşük sayılar için tüm bahisler kapalıdır, o (1) kolayca o (n!) 'Den daha yavaş olabilir.
Sklivvz

@Sklivvz - nve Misteğe bağlı olarak ölçeklenebilen değişkenlerdir, dolayısıyla biri her ikisini de içerir. Özellikle şunu varsaymıştım M> log n, yani n log nbunun sadece değil n, umursuyorsanız, sizin de önemsemeniz gerektiği anlamına gelir M.
Rex Kerr

3

Bu, oylanan algoritmadan daha hızlı yapılabilir (n log n)

- Sıralama istatistikleri dağıtılmış seçim algoritması - O (n)
Sorunu, sıralanmamış bir dizide k'inci sayıyı bulmanın orijinal problemine basitleştirin.
- Sayma sıralama histogramı O (n)
Sayıların aralığı hakkında bazı özellikler varsaymalısınız - aralık belleğe sığabilir mi? - Harici birleştirme sıralaması - O (n log n) - yukarıda açıklanmıştır
Temel olarak ilk geçişteki sayıları sıralarsınız, ardından ikinci geçişte medyanı bulursunuz.
- Sayıların dağılımı hakkında bir şey biliniyorsa başka algoritmalar üretilebilir.

Daha fazla ayrıntı ve uygulama için bkz:
http://www.fusu.us/2013/07/median-in-large-set-across-1000-servers.html


2

Bir bilgisayar, sorunu çözmek için fazlasıyla yeterlidir.

Ama 100 bilgisayar olduğunu varsayalım. Yapmanız gereken tek karmaşık şey listeyi sıralamaktır. 100 parçaya bölün, her bilgisayara bir parça gönderin, orada sıralanmalarına izin verin ve bundan sonra parçaları birleştirin.

Sonra sıralı listenin ortasından numara alın (yani, 5000 000 000 dizin ile).


3
Her neyse şimdi benim temsilcim oldukça yuvarlak :)
Roman

Birleştirme en iyi ihtimalle O (n) 'dir ve tek bir çekirdekte medyanı O (n)' de bulabilirsiniz, bu nedenle bu, kazançsız çok fazla ekstra iş yaratıyor gibi görünüyor.
Rex Kerr

2

Verilerinize bağlıdır. En kötü durum senaryosu, eşit olarak dağıtılmış sayılardır.

Bu durumda, medyanı bu örnekte olduğu gibi O (N) zamanda bulabilirsiniz:

Sayılarınızın 2,7,5,10,1,6,4,4,6,10,4,7,1,8,4,9,9,3,4,3 (aralık 1-10) olduğunu varsayalım .

3 kova oluşturuyoruz: 1-3, 4-7, 8-10. Üst ve alt kısımların eşit boyutta olduğuna dikkat edin.

Kovaları sayılarla doldururuz, her birinde kaç tane düştüğünü sayarız, maksimum ve minimum

  • düşük (5): 2,1,1,3,3, min 1, max 3
  • orta (10): 7,5,6,4,4,6,4,7,4,4, min 4, maks 7
  • yüksek (5): 10, 10, 8, 9, 9, min 8, max 10

Ortalama orta kovaya düşer, gerisini göz ardı ederiz

3 kova oluşturuyoruz: 4, 5-6, 7. Düşük, 5 sayımla başlayacak ve en fazla 3 ve yüksek, en az 8 ve 5 sayı ile başlayacaktır.

Her sayı için alçak ve yüksek kovaya kaç kişinin düştüğünü, maksimum ve minimum sayıları sayıyoruz ve orta kovayı koruyoruz.

  • eski düşük (5)
  • düşük (5): 4, 4, 4, 4, 4, maks. 4
  • orta (3): 5,6,6
  • yüksek (2): 7, 7, min 7
  • eski yüksek (5)

Şimdi medyanı doğrudan hesaplayabiliriz: böyle bir durumumuz var

old low    low          middle  high  old high
x x x x x  4 4 4 4 4 4   5 6 6  7 7   x x x x x

yani medyan 4,5'tir.

Dağıtım hakkında biraz bilgi sahibi olduğunuzu varsayarsak, hızı optimize etmek için aralıkları nasıl tanımlayacağınıza ince ayar yapabilirsiniz. Her durumda, performans O (N) ile gitmelidir çünkü 1 + 1/3 + 1/9 ... = 1.5

Uç durumlar nedeniyle minimum ve maksimuma ihtiyacınız vardır (örneğin, medyan, eski düşük maksimum ile bir sonraki eleman arasındaki ortalama ise).

Tüm bu işlemler paralel hale getirilebilir, her bilgisayara verinin 1 / 100'ünü verebilir ve her bir düğümdeki 3 grubu hesaplayabilir, ardından sakladığınız paketi dağıtabilirsiniz. Bu yine ağı verimli kullanmanıza neden olur çünkü her sayı ortalama 1,5 kez geçer (yani O (N)). Düğümler arasında yalnızca minimum sayıları geçirirseniz bunu bile geçebilirsiniz (örneğin, düğüm 1'de 100 sayı varsa ve düğüm 2'de 150 sayı varsa, düğüm 2, düğüm 1'e 25 numara verebilir).

Dağıtım hakkında daha fazla bilginiz yoksa, burada O (N) 'den daha iyisini yapabileceğinizden şüpheliyim, çünkü elementleri en az bir kez saymanız gerekiyor.


1
Tüm sayılar eşit olduğunda gerçek daha kötü durum (algoritmanız için) değil mi? Eğer haklıysam, ortadaki kovalarınız dışında hiçbiri tüm öğelerle dolu olmayacak. Bu nedenle, aralığın ortasına kadar üssel olarak hızlı ilerleyerek her seferinde tüm öğeleri geçmeniz gerekecektir. O(n log n)Bu durumda bir olacağına inanıyorum . Mantıklı geliyor ? Bu arada fikrini beğendim
Dici

1
@Dici gerçekten değil: Öncelikle "hepsi aynı" senaryosunu kısayol yapabilirsiniz, çünkü min ve maks. Cevapta da söylediğim gibi, dağılımı bilmek, paketleme tercihlerinizi yönlendirebilir; ikinci olarak, o(n)+o(n/3)+o(n/9)+...hangisinin hareketsiz o(n)olup olmadığını yine de alacaktır o(n log n).
Sklivvz

Öte yandan, muhtemelen farklı bir en kötü durum senaryosu, U şeklinde bir dağılım var. Bunun hakkında biraz düşünmem, en kötü durumu resmileştirmem gerekiyor, ancak o(n)saf bölümlemeyle bu durumda olduğundan daha kötüsü olabilir .
Sklivvz

Mmm evet, minimum ve maksimum "hepsi aynı" vakanın
üstesinden

2

Daha kolay bir yöntem, ağırlıklı sayılara sahip olmaktır.

  • Büyük seti bilgisayarlar arasında böl
  • Her seti sıralayın
  • küçük kümeyi yineleyin ve tekrarlanan öğelere göre ağırlıkları hesaplayın
  • her 2 seti 1'e birleştirin (her biri zaten sıralanmıştır) ağırlıkları güncelleyin
  • sadece bir set elde edene kadar setleri birleştirmeye devam edin
  • OneBillion / 2'ye ulaşana kadar ağırlıkları biriktirerek bu seti tekrarlayın

1

10 ^ 9 sayısını her bilgisayara ~ 80MB olacak şekilde bölün. Her bilgisayar numaralarını sıralar. Daha sonra bilgisayar 1 kendi numaralarını bilgisayar 2, bilgisayar 3 ve 4, vb. İle birleştirir. Sonra bilgisayar 1 sayıların yarısını tekrar 2'ye, 3'ten 4'e vb. Yazar. Sonra 1 birleştirme, bilgisayarlardaki sayıları sıralar. 1,2,3,4, onları geri yazar. Ve bunun gibi. Bilgisayarlardaki RAM'in boyutuna bağlı olarak, her adımda tüm sayıları tek tek bilgisayarlara yazmamaktan kurtulabilirsiniz, sayıları bilgisayar 1'de birkaç adımda biriktirebilirsiniz, ancak matematik işlemlerini yaparsınız.

Oh, sonunda 500000000'ncü ve 500000001'inci değerlerin ortalamasını alın (ama orada yeterince 00 olduğunu kontrol edin, ben yok).

DÜZENLEME: @Roman - buna inanamıyorsanız bile doğru olsa da, önermenin doğruluğunu veya yanlışlığını açıklamamın bir anlamı yok. Söylemek istediğim şey, kaba kuvvetin bazen bir yarışta akıllıca geçtiğiydi. Uygulayabileceğime inandığım, işe yarayacak, çok çeşitli boyutlardaki giriş ve sayılara uyarlanabilen, bilgisayarların özelliklerine ve bilgisayarların özelliklerine göre ayarlanabilen bir algoritma tasarlamak yaklaşık 15 saniyemi aldı. ağ düzenlemeleri. Siz veya başka biri, daha karmaşık bir algoritma tasarlamak 15 dakika sürerse, çözümümü kodlamak ve çalıştırmaya başlamak için 14 dakika 45 saniye avantajım var.

Ama bunların hepsinin iddia olduğunu özgürce kabul ediyorum, hiçbir şeyi ölçmedim.


burada sadece tüm sayıları birleştiriyoruz. Bunu kullanarak daha iyi bir şekilde yapabilir miyiz: - "iki sıralı listenin medyanını oturum açma zamanında bulabiliriz. N, her listenin uzunluğudur."
anony

1
@anony - kendi sorunuzu yanıtlarken, çözümümün kodlanmasını, test edilmesini ve tamamlanmasını sağlayacağım. Daha iyi yollar olmasını bekliyorum, ancak bazen basit bir yolla paralellik kurmak, beni gerçekten zor problemlere karşı kafamı kaşıma özgür bırakıyor.
Yüksek Performans Mark

7 dakikada gerçekten yaptın mı? Doğru olsa bile buna inanamıyorum. Ben de benzer görevi yaptım (bu bir üniversite ödeviydi) ve tüm uzaktan kumandaları uygulamak ve test etmek yaklaşık 2 saat sürdü (java RMI kullandım).
Roman

Ne söylediğinizi anlıyorum, ancak aynı sebeple DrPizza'nın daha da hızlı bir çözümü var; bu, tek bir düğümdeki tüm verileri sıralamak ve diğer 99'u yok saymaktır. Hiçbirimiz verilerin ne kadar pahalı olduğunu bilmiyoruz. transfer düşünülmelidir, bu yüzden hepimiz belirsiz bir şekilde makul görünen bir uzlaşma seçiyoruz. Çözümünüz tüm verileri birden çok kez aktarıyor, bu yüzden bundan biraz şüpheleniyorum, ancak kesinlikle bir çözüm.
Steve Jessop

'belli belirsiz makul' - bu benim için yeterince iyi @ Steve! Özellikle belirsiz bir şekilde mantıksız bir soruya yanıt olarak.
Yüksek Performans Mark

1

Bu, düğümler arasında sıralanmamış veriler (örneğin günlük dosyalarından) kullanılarak aşağıdaki şekilde yapılabilir.

1 ana düğüm ve 99 alt düğüm vardır. Alt düğümlerin iki api çağrısı vardır:

  • istatistik (): min, max ve count döndürür
  • karşılaştır (median_guess): eşleşen değeri sayar, değerden küçük say ve değerden büyük say

Üst düğüm, tüm düğümlerin minimum ve maksimumunu not ederek tüm alt düğümlerde istatistik () çağırır.

İkili arama artık aşağıdaki şekilde yürütülebilir:

  1. Minimum ve maksimum yuvarlamayı ikiye bölün - bu medyan 'tahmin'tir
  2. Sayıdan büyük, sayıdan küçükten büyükse, minimum değeri tahmin olarak ayarlayın
  3. Sayıdan büyük, sayıdan küçükse, maksimumu tahmine ayarlayın.
  4. Minimum ve maksimum eşit olduğunda sayı tek biterse
  5. Sayım, maksimum <= minimum + tahmin.match_count olduğunda bile biterse Bu, sıralanmamış veriler (örneğin günlük dosyalarından) kullanılarak düğümlerde aşağıdaki şekilde yapılabilir.

1 ana düğüm ve 99 alt düğüm vardır. Alt düğümlerin iki api çağrısı vardır:

  • istatistik (): min, max ve count döndürür
  • karşılaştır (median_guess): eşleşen değeri sayar, değerden küçük say ve değerden büyük say

Üst düğüm, tüm düğümlerin minimum ve maksimumunu not ederek tüm alt düğümlerde istatistik () çağırır.

İkili arama artık aşağıdaki şekilde yürütülebilir:

  1. Minimum ve maksimum yuvarlamayı ikiye bölün - bu medyan 'tahmin'tir
  2. Sayıdan büyük, sayıdan küçükten büyükse, minimum değeri tahmin olarak ayarlayın
  3. Sayıdan büyük, sayıdan küçükse, maksimumu tahmine ayarlayın.
  4. Minimum ve maksimum eşit olduğunda sayı tek biterse
  5. Maksimum <= minimum + tahmin. Maç_sayısı olduğunda sayı bile biterse

İstatistikler () ve karşılaştırma () bir O (N / Mlogn / M) sıralaması ile önceden hesaplanabiliyorsa, ön hesaplama için O (N) bellek karmaşıklığına sahip bir O (N / M) ön hesaplaması hesaplama. Daha sonra sabit zamanda karşılaştırma () yapabilirsiniz, böylece her şey (ön hesaplama dahil) O (N / MlogN / M) + O (logN)

Bir hata yaptıysam bana haber ver!


evet sadece ikili arama yapardım. Her bilgisayarı birkaç kez arayarak ağ bant genişliğinden tasarruf eder. Ayrıca her makinede, zamandan tasarruf etmek için pivotun her iki tarafındaki numaraları değiştirdiği yerde bir "pivot" olabilir. (pivot, medyanın bir önceki tahmini olacaktır, bu nedenle bir dahaki sefere, yalnızca pivotun bir tarafındaki tüm sayıları gözden geçirmeniz gerekir)
robert king

0

Şuna ne dersiniz: - her düğüm 1 Milyar / 100 sayı alabilir. Her düğümde elemanlar sıralanabilir ve medyan bulunabilir. Medyanların medyanını bulun. Tüm düğümlerdeki medyan-medyandan daha küçük sayıların sayısını toplayarak medyan-medyan'ın yaptığı% x:% y dağılımını bulabiliriz. Şimdi tüm düğümlerden medyanların medyanından daha az olan öğeleri silmesini isteyin (örneğin% 30:% 70'lik bölünme).% 30 sayılar silinir. 1 Milyar'ın% 70'i 700 milyondur. Artık 3 milyondan az düğümü silen tüm düğümler, bu ekstra düğümleri ana bilgisayara geri gönderebilir. Ana bilgisayar, artık tüm düğümlerin neredeyse eşit sayıda düğüme (7 milyon) sahip olacağı şekilde yeniden dağıtılır. Artık sorun 700 milyon sayıya indirgendiğine göre .... tek bir bilgisayarda hesaplanabilecek daha küçük bir kümeye sahip olana kadar devam ediyor.


Temelde, sorun setini her zaman en az% 30 oranında azaltıyoruz ve bu sayede çok sayıda paralel hesaplama elde ediyoruz. Her düğüm 10 milyon ile başlar ve her yinelemede veri kümesini% 30 azaltır.
anony

İlk yinelemede 500 Milyonuncu sayıyı arıyoruz. İkinci yinelemede - eğer silinen sayıların sayısı 300 milyon ise, o zaman 200 milyonuncu sayı ararız ve böyle devam eder ...
anony

2
Bu doğru yoldaymış gibi görünüyor, ancak% 30 /% 70'lik payınız ile medyanı kazara atmaktan nasıl kaçınacağınızı çok açık bir şekilde açıklamıyorsunuz. Şu karşı örneği ele alalım: ilk% 29'unuzun tamamen sıfır olduğunu ve diğer tüm blokların 1000 kadar sayıldığını ve her blok kümesinin sondan bir fazla olduğunu varsayalım. 30. yüzdelik dilim medyan, verilerin% 29'unun tamamını ve verilerin% 61'inin yarısından biraz daha azını atacaktır, bu da verilerin% 29 +% 30'u =% 59'dur. Oops, az önce gerçek medyanı attık! Görünüşe göre bunu kastetmiyorsun, ya da en azından benim yorumladığımdan daha akıllıca kastediyorsun.
Rex Kerr

0

İlk önce tek bir makinede n sayının medyanını nasıl bulacağımızı bulalım: Temel olarak bölümleme stratejisi kullanıyorum.

Problem: seçim (n, n / 2): En küçük numaradan n / 2. sayıyı bulun.

Orta eleman k'yi ve veriyi 2 alt diziye bölmeyi seçersiniz. 1'inci tüm <k öğelerini içerir ve 2. tüm öğeleri> = k içerir.

sizeof (1. alt dizi)> = n / 2 ise, bu alt dizinin medyanı içerdiğini bilirsiniz. Ardından 2. alt diziyi atabilirsiniz. Bu problem seçimini çözün (sizeof 1st sub-array, n / 2) .

Aksi takdirde, bu 1. alt diziyi atın ve seçimi çözün (2. alt dizi, n / 2 - sizeof (1. alt dizi))

Yinelemeli olarak yapın.

zaman karmaşıklığı O (n) beklenen zamandır.

Şimdi birçok makinemiz varsa, her yinelemede, bölmek için bir dizi işlememiz gerekir, diziyi diff makinelerine dağıtırız. Her makine kendi dizi yığınını işler ve özetini merkez kontrol makinesine geri gönderir, yani 1. alt dizinin boyutu ve 2. alt dizinin boyutu. Göbek makineleri özetler toplar ve hangi alt dizinin (1. veya 2.) daha fazla işleneceğine ve 2. seçim parametresine karar verir ve her makineye geri gönderir. ve bunun gibi.

Bu algoritma, harita azaltma kullanılarak çok düzgün bir şekilde uygulanabilir.

Nasıl görünüyor?


0

Sanırım Steve Jessop'un cevabı en hızlı olacak.

Ağ veri aktarım boyutu darboğazsa, işte başka bir yaklaşım.

Divide the numbers into 100 computers (10 MB each). 
Loop until we have one element in each list     
    Find the meadian in each of them with quickselect which is O(N) and we are processing in parallel. The lists will be partitioned at the end wrt median.
    Send the medians to a central computer and find the median of medians. Then send the median back to each computer. 
    For each computer, if the overall median that we just computed is smaller than its median, continue in the lower part of the list (it is already partitioned), and if larger in the upper part.
When we have one number in each list, send them to the central computer and find and return the median.

Her biri 32 MB demek istiyorsun?
dici

Listenin alt kısmında devam etmekle neyi kastediyorsunuz?
Ruthvik Vaila

0

Bunu şöyle yapardım:

başlangıçta 100 kişinin tümü en yüksek ve en düşük sayıyı bulmak için çalışır; her bilgisayarın sorguladığı veritabanı / dosyanın kendi parçası vardır;

en yüksek ve en düşük sayılar bulunduğunda, bir bilgisayar verileri okur ve her sayıyı eşit olarak 99'un geri kalanına dağıtır; sayılar eşit aralıklarla dağıtılır; (biri -100 milyondan 0'a, diğeri - 0'dan 100 milyona kadar sürebilir, vb.);

Numaraları alırken, 99 bilgisayardan her biri bunları sıralar;

Sonra, medyanı bulmak kolaydır ... Her bilgisayarda kaç tane sayı olduğunu görün, hepsini toplayın (sayıların kendilerinin değil, kaç tane sayı olduğunun toplamı), 2'ye bölün; hangi bilgisayarın sayı olduğunu ve hangi dizinde olduğunu hesaplayın;

:) voilla

PS Burada çok fazla kafa karışıklığı var gibi görünüyor; ORTANCA - SIRALANMIŞ SAYILAR LİSTESİ ORTASINDAKİ SAYIDIR!



0

Sayılar farklı değilse ve sadece belirli bir aralığa aitse yani tekrarlanıyorsa, o zaman aklıma gelen basit bir çözüm sayıları 99 makineye eşit olarak dağıtmak ve bir makineyi usta olarak tutmaktır. Artık her makine verilen sayıları yineler ve her sayının sayısını bir hash setinde saklar. Sayı, belirli bir bilgisayara tahsis edilen sayılar kümesinde her tekrarlandığında, karma kümesindeki sayısını günceller.

Tüm makineler daha sonra hash setlerini ana makineye geri döndürür. Ana makine, bir hash setinde bulunan aynı anahtarın sayısını toplayarak, hash setlerini birleştirir. Örneğin, makine # 1'in karma kümesinde ("1", 7) girişi vardı ve makine # 2'nin karma kümesinde ("1", 9) giriş vardı, bu nedenle karma kümelerini tararken ana makine, ("1", 16) vb.

Karma kümeleri birleştirildikten sonra, anahtarları sıralayın ve şimdi sıralanan karma kümeden (n / 2). Öğeyi ve (n + 2/2). Öğeyi kolayca bulabilirsiniz.

Milyarlarca sayı farklıysa bu yöntem faydalı olmayacaktır.


0

Pekala, farklı tam sayıların sayısının (diyelim) 4 milyar olduğunu bildiğinizi varsayalım, o zaman bunları 64 bin kova halinde gruplayabilir ve kümedeki her makineden (100 bilgisayar) her bir kova için dağıtılmış bir sayı elde edebilirsiniz. Tüm bu sayıları birleştirin. Şimdi, medyana sahip olan kovayı bulun ve bu sefer sadece hedef kovanızda yer alacak 64k elemanlar için kovalar isteyin. Bu, "kümeniz" üzerinden O (1) (özellikle 2) sorgu gerektirir. : D


0

Benim kuruş değerim, zaten başkaları tarafından ortaya atılan her şeyden sonra:

Tek bir makinede medyanı bulmak O (N): https://en.wikipedia.org/wiki/Selection_algorithm .

100 makineye N numara göndermek de O (N) 'dir. Bu yüzden, 100 makineyi kullanmayı ilginç kılmak için, ya iletişim görece hızlı olmalı ya da N, N / 100 yapılabilirken tek bir makinenin üstesinden gelemeyecek kadar büyük ya da sadece matematiksel problemi düşünmeden düşünmek istiyoruz. veri iletişimi.

İşleri kısaltmak için, makul sınırlar içinde, verimlilik analizini etkilemeden sayıları gönderebileceğimiz / dağıtabileceğimizi varsayacağım.

Daha sonra, bir makinenin bazı genel işlemler için "ana" olarak atandığı aşağıdaki yaklaşımı düşünün. Bu nispeten hızlı olacaktır, dolayısıyla "ana makine" de her makinenin gerçekleştirdiği ortak görevlere katılır.

  1. Her makine sayıların N / 100'ünü alır, kendi medyanını hesaplar ve bu bilgiyi ana makineye gönderir.
  2. Ana makine, tüm farklı medyanların sıralı bir listesini derler ve bunu her makineye geri göndererek sıralı bir kova dizisi (her makinede aynıdır), her medyan değer için bir tane (tek değerli bir kova) ve aradaki her aralık için bir tane tanımlar. bitişik medyanlar. Elbette, en düşük medyanın altındaki ve en yüksek olanın üzerindeki değerler için alt uç ve üst uç kovalar da vardır.
  3. Her makine, her bir gruba kaç sayı düştüğünü hesaplar ve bu bilgiyi ana makineye geri iletir.
  4. Ana birim, medyanı hangi bölümün içerdiğini, kaç düşük değerin (toplamda) bu bölümün altına düştüğünü ve kaçının yukarıda olduğunu belirler.
  5. Seçili bölüm tek değerli bir bölümse (orta değerlerden biri) veya seçili bölüm yalnızca 1 (N tek) veya 2 (N çift) değer içeriyorsa, işimiz bitti. Aksi takdirde yukarıdaki adımları aşağıdaki (bariz) değişikliklerle tekrar ederiz:
  6. Ana makineden 100 makineye (yeniden) yalnızca seçilen bölümdeki sayılar ve dahası
  7. Medyanı (her makinede) değil, toplamdan kaç tane daha yüksek sayının atıldığını ve kaç tane daha düşük sayıyı hesaba kattığımız k-inci değerini hesaplayacağız. Kavramsal olarak her makinenin, atılan düşük / yüksek sayılardan kendi payı vardır ve atılan sayıları (kavramsal olarak) içeren (kavramsal olarak) kümedeki yeni medyanı hesaplarken bunu hesaba katar.

Zaman karmaşıklığı:

  1. Biraz düşünmek sizi her adımda analiz edilecek toplam değer sayısının en az iki faktör azaldığına ikna edecektir (2 oldukça hasta bir durum olur; önemli ölçüde daha iyi bir azalma bekleyebilirsiniz). Bundan elde ederiz:
  2. O (N) olan medyanı (veya k-inci değerini) bulmanın c * N zamanını aldığını varsayarsak, önfaktör c N ile çok fazla değişmez, böylece onu o an için sabit olarak alabiliriz, Nihai sonucumuzu en fazla 2 * c * N / 100 kez alacağız. Bu nedenle, 100 makine kullanmak bize 100/2 hızlandırma faktörü (en azından) verir.
  3. Başlangıçta belirtildiği gibi: Makineler arasındaki sayıların iletişimi için harcanan zaman, her şeyi tek bir makinede yapmayı daha çekici hale getirebilir. Ancak, dağıtılmış yaklaşıma gidersek, tüm adımlarda birlikte iletilecek toplam sayı sayısı 2 * N'yi (ilk kez N, ikinci kez <= N / 2, <= bunun yarısı) üçüncü ve benzeri).

-1
  1. 1 milyar sayıyı 100 makineye bölün. Her makinede 10 ^ 7 numara olacaktır.

  2. Bir makineye gelen her numara için, numarayı bir frekans haritasında, sayı -> sayımda saklayın. Ayrıca her makinede minimum sayıyı saklayın.

  3. Her makinedeki medyanı bulun: her makinedeki minimum sayıdan başlayarak, medyan indekse ulaşılana kadar sayıları toplayın. Her makinedeki medyan, yakl. 5 * 10 ^ 6 sayıdan küçük ve büyük.

  4. Tüm medyanların medyanını bulun, ki bu yaklaşık. 1 milyar sayının medyanı olan 50 * 10 ^ 7 sayı.

Şimdi 2. adımın bazı optimizasyonu: Bir frekans haritasında depolamak yerine, sayıları değişken bir bit dizisinde saklayın. Örneğin: Bir makinedeki minimum sayıdan başlayalım, bunlar frekans sayılarıdır:

[min number] - 8 count
[min+1 number] - 7 count
[min+2 number] - 5 count

Yukarıdakiler bit dizisinde şu şekilde saklanabilir:

[min number] - 10000000
[min+1 number] - 1000000
[min+2 number] - 10000

Her makine yalnızca 10 ^ 7 sayı işlediğinden, her makine için toplamda yaklaşık 10 ^ 7 bite mal olacağını unutmayın. 10 ^ 7 bit = 1,25 * 10 ^ 6 bayt, yani 1,25 MB

Dolayısıyla, yukarıdaki yaklaşımla her bir makinenin yerel medyanı hesaplamak için 1,25 MB alana ihtiyacı olacaktır. Ortanca medyan, bu 100 yerel medyan üzerinden hesaplanabilir, bu da medyan 1 milyar sayı ile sonuçlanır.


Ya sayılar yüzerse?
Sklivvz

-1

Yaklaşık Medyanı hesaplamak için bir yöntem öneririm. :) Bu bir milyar sayı rastgele bir sıradaysa, sanırım bir milyar sayının 1 / 100'ü veya 1 / 10'unu rastgele seçebilirim, 100 makine ile sıralayabilirim, sonra medyanını seçebilirim. Ya da milyarlarca sayıyı 100 parçaya ayıralım, her makine rastgele her parçanın 1 / 10'unu seçsin, medyanını hesaplasın. Bundan sonra 100 sayımız var ve 100 sayının medyanını daha kolay hesaplayabiliriz. Sadece bir öneri, matematiksel olarak doğru olup olmadığından emin değilim. Ama bence sonucu matematikte pek iyi olmayan bir yöneticiye gösterebilirsiniz.


Açıkça doğru değil ve görüşmecinizin asla kandırabileceğiniz aptal bir domuz olduğunu düşünmemenizi şiddetle tavsiye ederim
Dici

Haha tamam, cevabınızın yanlış olduğu gerçeğini değiştirmez. Kanıtlamak çok kolay
Dici

Tamam, istatistikle ilgili bir ders okuduktan sonra, bir milyar sayının 1 / 100'ünü hatta 1 / 1000'ini rasgele alıp ortancasını hesaplama fikrinin o kadar da kötü olmadığını düşünüyorum. Bu sadece yaklaşık bir hesaplama.
lazyboy

-3

Steve Jessop'un cevabı yanlış:

aşağıdaki dört grubu düşünün:

{2, 4, 6, 8, 10}

{21, 21, 24, 26, 28}

{12, 14, 30, 32, 34}

{16, 18, 36, 38, 40}

Medyan, ikinci grupta yer alan 21'dir.

Dört grubun medyanı 6, 24, 30, 36, Toplam medyan 27'dir.

Böylece ilk döngüden sonra dört grup şu hale gelecektir:

{6, 8, 10}

{24, 26, 28}

{12, 14, 30}

{16, 18, 36}

21 zaten yanlış bir şekilde atıldı.

Bu algoritma, yalnızca iki grup olduğunda durumu destekler.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.