Bir geçişte bağlantılı listenin orta öğesini nasıl bulabilirim?


12

Veri yapıları ve algoritmalardan en çok sorulan sorulardan biri, çoğunlukla telefon görüşmesi üzerine sorulmuştur.


5
Bu konuda sunulan cevaplar görüşmecinin beklediği şeyse, bu soru teknik yeteneği test etmez, ancak adayın bir avukat gibi kaçınabileceğini.
G. Bach

2
Bu korkunç bir röportaj sorusudur, çünkü belirsiz, belirsiz, sübjektif olan " geçiş " terimine eleştirel bir şekilde bağlıdır . Bu soruya hemen hemen tüm iyi cevaplar, tanımı etkili bir şekilde göz ardı edebilmeniz için kötüye kullanılmasını içerir.
RBarryYoung

2
Burada soru çok tartışılıyor. Bu, bir açıdan iyi bir röportaj sorusu olduğu anlamına gelir: düşünmeye başlar.
Hendrik Ocak

3
Bu yüzden "tüm elemanları bir vektöre okuyup, daha sonra elemanın pozisyon büyüklüğüne () / 2" de erişmesini istiyorum
Cort Ammon

1
@HendrikJan Aslında, tamamen korkunç bir röportaj sorusu olduğunu düşünüyorum. Birincisi, verimli tartışmadan ziyade “tek seferde” tam olarak ne anlama geldiğine dair tartışmalara yol açması muhtemeldir. İkincisi, bir aday "doğru" yanıtı bulabilir ve sonra "tek geçişte" kriterini ihlal ettiğini düşündükleri için reddedebilir. Üçüncüsü, iyi bilinen bir soru olduğu için, "Popüler röportaj sorularını biliyor musunuz?" "Bu işe uygun musunuz?" Bunlardan herhangi biri bunu bir soru olarak batırmak için yeterli olmalıdır; üçü de aynı anda bir felaket.
David Richerby

Yanıtlar:


24

Hile yaparak ve aynı anda iki geçiş yaparak paralel olarak. Ancak işe alım yapanların bunu beğenip beğenmeyeceğini bilmiyorum.

Tek bir bağlantılı listede, güzel bir numara ile yapılabilir. İki işaretçi liste üzerinde hareket eder, biri çift hızlıdır. Hızlı olan sona ulaştığında, diğeri yarı yoldadır.


1
Evet, bunun tek bir geçiş olup olmadığı belli değil. Bu noktada soru belirsiz.
David Richerby

2
Bu arada, bu, her biri bir saat yanan iki mumun olduğu bulmaca ile ilgilidir ve 45 dakikayı ölçmeniz istenir.
Hendrik Ocak

2
Bu, listeyi yinelemekten, öğeleri saymaktan ve ikinci kez yarım yol noktasına yinelemekten gerçekten farklı mıdır? Farklı olan tek şey ekstra yarıyı tekrarladığınız zamandır. @RBarryYoung'un diğer benzer cevaptan bahsettiği gibi, gerçekten tek bir geçiş değil, bir buçuk geçiş.

2
Liste uzunsa, her iki işaretçiyi de "paralel" olarak taşımak, ikinci kez tekrardan daha az önbellek kaybına neden olur.
zwol

2
Bu, döngü tespiti için kaplumbağa ve tavşan algoritması ile aynı prensibi kullanır .
Joshua Taylor

7

İki kez bağlı bir liste değilse, sadece bir liste sayabilir ve kullanabilirsiniz, ancak bu en kötü durumda belleğinizi iki katına çıkarmayı gerektirir ve liste bellekte saklamak için çok büyükse işe yaramaz.

Basit, neredeyse aptalca bir çözüm, her iki düğümde orta düğümü arttırmaktır

function middle(start) {
    var middle = start
    var nextnode = start
    var do_increment = false;
    while (nextnode.next != null) {
        if (do_increment) {
             middle = middle.next;
        }
        do_increment = !do_increment;
        nextnode = nextnode.next;
    }
    return middle;
}

İkinci seçeneğiniz doğru cevap (tabii ki IMHO).
Matthew Crumley

1
Aslında bağlantılı listenin üzerinden 1 1/2 geçiş yapıyor.
RBarryYoung

6

Hendrik'in cevabının detaylandırılması

İki kat bağlantılı bir listeyse, her iki uçtan yineleme yapın

function middle(start, end) {
  do_advance_start = false;
  while(start !== end && start && end) {
     if (do_advance_start) {
        start = start.next
     }
     else {
        end = end.prev
     }
     do_advance_start = !do_advance_start
  }
  return (start === end) ? start : null;
}

verilmiş [1, 2, 3] => 2

1, 3
1, 2
2, 2

verilmiş [1, 2] => 1

1, 2
1, 1

verilmiş [1] => 1

verilmiş [] => null


Bu nasıl verimli? Ayrıca n / 2 değil, n kez yineliyorsunuz.
Karan Khanna

3

Bağlantılı listenin düğümlerini gösterebilen bir işaretçi ve listedeki düğüm sayısını tutan bir tamsayı değişkeni ile bir yapı oluşturun.

struct LL{
    struct node *ptr;
    int         count;
}start;

start.ptrstart.count=1
start.count

start.count


-2

Dizinin her öğesinin, baştan başlayarak listeden her bir düğüme çapraz sırada işaretçi olduğu dinamik bir dizi oluşturun. Ziyaret ettiğiniz kaç düğümü izleyen (her yeni bir düğüme her gittiğinizde artan) 1 olarak başlatılan bir tamsayı oluşturun. Sonuna geldiğinizde, listenin ne kadar büyük olduğunu bilirsiniz ve her bir düğüme sıralı bir işaretçi diziniz olur. Son olarak, listenin boyutunu 2'ye bölün (ve 0 tabanlı indeksleme için 1 çıkarın) ve dizinin o dizininde tutulan işaretçiyi getirin; listenin boyutu garip ise, hangi öğeyi döndüreceğinizi seçebilirsiniz (yine de ilkini döndüreceğim).

İşte (dinamik bir dizi fikri biraz sakat olsa bile) noktayı alan bazı Java kodu. C / C ++ sağlamak istiyorum ama bu alanda çok paslı.

public Node getMiddleNode(List<Node> nodes){

    int size = 1;
    //add code to dynamically increase size if at capacity after adding
    Node[] pointers = new Node[10];

    for (int i = 0; i < nodes.size(); i++){
        //remember to dynamically allocate more space if needed
        pointers[i] = nodes.get(i);
        size++;
    }

    return pointers[(size - 1)/2];

}

-3

Özyineleme birden fazla geçiş olarak kabul edilir mi?

Referansla bir tamsayı sayısı geçirerek listeyi sonuna kadar gezdirin. Daha sonra başvurmak üzere her düzeyde bu değerin yerel bir kopyasını oluşturun ve sonraki çağrıya giden ref sayımını artırın.

Son düğümde sayımı ikiye bölün ve sonucu kesin (yalnızca iki öğe olduğunda ilk düğümün "orta" olmasını istiyorsanız) veya yuvarlayın (ikinci düğümün olmasını istiyorsanız) orta"). Sıfır veya tek tabanlı bir dizini uygun şekilde kullanın.

Çözülüyorsa, ref sayısını yerel kopyayla (düğümün numarası olan) eşleştirin. Eşitse, bu düğümü döndürün; yoksa özyinelemeli çağrıdan döndürülen düğümü döndürür.
.

Bunu yapmanın başka yolları da var; bazıları daha az hantal olabilir (Birisi bir dizi içine okumak ve orta - kudos belirlemek için dizi uzunluğu kullanın dedi gördüm düşündüm). Ama açıkçası, iyi bir cevap yok, çünkü bu aptalca bir röportaj sorusu. Hala bağlantılı listeleri kullanan bir numara ( destekleyici görüş ); İkincisi, orta düğümü bulmak, gerçek hayat senaryolarında değeri olmayan keyfi, akademik bir alıştırmadır; Üç, orta düğümü gerçekten bilmem gerekirse, bağlantılı listem bir düğüm sayısını ortaya çıkaracaktır. Bu özelliği korumak, orta düğümü her istediğimde tüm listeyi dolaşarak zaman harcamaktan daha kolaydır. Ve son olarak, dört, her görüşmeci farklı cevapları beğenecek veya reddedecektir - bir görüşmecinin düşündüğü şey kaygan, diğeri gülünç diyecektir.

Röportaj sorularını neredeyse her zaman daha fazla soru ile cevaplıyorum. Eğer böyle bir soru alırsam (asla sahip değilim), soruyorum (1) Bu bağlantılı listede ne saklıyorsunuz ve gerçekten bir ihtiyaç varsa orta düğüme verimli bir şekilde erişmek için daha uygun bir yapı var mı? ; (2) Kısıtlarım nelerdir? Bellek bir sorun değilse (örneğin dizi yanıtı) daha hızlı yapabilirim, ancak görüşmeci hafızayı toplamanın israf olduğunu düşünürse, öleceğim. (3) Hangi dilde geliştireceğim? Bildiğim hemen hemen her modern dilde, listenin geçişini gereksiz kılan bağlantılı listelerle başa çıkmak için yerleşik sınıflar var - neden dilin geliştiricileri tarafından verimlilik için ayarlanmış bir şeyi yeniden icat ettiniz?


6
Kimin neyi düşürdüğünü bilmiyorsunuz, bu yüzden bir kişinin her şeyi düşürdüğü sonucuna göre doğru olabilir veya olmayabilir, ancak kesinlikle sizin için mevcut gerçeklere dayanamaz. Ama cevabınızı küçümsüyorum çünkü kod yığınlarını değil açıklamaları arıyoruz.
David Richerby

Bir varsayım olabilir, ancak bir an ve 30 saniyeden daha kısa bir süre sonra her yazının tam olarak -1'i varsa, mantıksız değil. 5 veya 6 farklı insan olsa bile, bunlardan biri neden bir yorum bırakmadı. Ama en azından bir sebep belirttiğiniz için teşekkür ederim. Neden garip bir açıklamanın koddan daha iyi olduğunu anlamıyorum - evet, bir telefon görüşmesi için, ama OP'ye regürjitasyon için hazır bir cevap vermiyorum, ona bunu yapmanın bir yolunu gösteriyorum. IE Ben bir yazı downvoting düşünüyorum çünkü kod uncalled, ama en azından neden yaptığını söylediğin için teşekkür ederim.
James K

Adil nokta - Oyların zamanlamasını bilmeniz bana gelmemişti (sayfanın gerçekleşirken yüklenmesini sağlamak, sanırım, bizim gibi sıradan kullanıcıların bunu öğrenebilmesinin tek yolu). Gerçek koddan neden kaçınmaya çalıştığımızla ilgili birkaç meta yayınımız var: (1) (2) .
David Richerby

Meta bağlantılar için teşekkürler. SSS'yi okudum, ama orada hiçbir şey görmedim - böyle bir şey fark edeceğim, büyük olasılıkla beklediğim bir şey değil. Ama ölümünden sonra tekrar kontrol ettiğimde hiçbir şey bulamadım. Hala bakmýţ olabilirim, ama baktým. Meta yazılardaki mantık mantıklıdır; cevap için teşekkürler.
James K

-5

2 işaretçi kullanarak. Her yinelemede bir, her ikinci yinelemede bir artırın. 1. işaretçi bağlı listenin sonunu gösterdiğinde 2. işaretçi bağlı listenin orta modunu gösterecektir.


Bu Hendrick'in cevabını tekrarlıyor . Söyleyecek yeni bir şeyiniz yoksa lütfen cevap vermeyin.
David Richerby
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.