Dizi ve bağlantılı listeye karşı


201

Neden birisi bir dizi üzerinde bağlantılı bir liste kullanmak isteyesin ki?

Bağlantılı bir listeyi kodlamak, şüphesiz, bir dizi kullanmaktan biraz daha fazla iştir ve kişi ek çabayı neyin haklı çıkaracağını merak edebilir.

Bağlantılı bir listede yeni öğelerin eklenmesi önemsiz olduğunu düşünüyorum ama bir dizi büyük bir angarya. Bir veri kümesini bir dizide depolamaya karşı depolamak için bağlantılı listeyi kullanmanın başka avantajları var mı?

Bu soru bu sorunun bir kopyası değildir, çünkü diğer soru özellikle belirli bir Java sınıfı hakkında sorurken bu soru genel veri yapıları ile ilgilidir.


1
Related - Ne zaman LinkedList <> over ArrayList <> kullanılır? - Java, ancak diziler (ArrayList) ve bağlantılı listeler muhtemelen her dilde aynı performansa sahiptir.
Bernhard Barker


1
@rootTraveller Aslında bu soru bu sorunun bir kopyası olacaktı çünkü sorum ilk önce gönderildi.
Onorio Catenacci

Yanıtlar:


146
  • Farklı boyutlardaki verileri bağlantılı bir listede saklamak daha kolaydır. Bir dizi, her öğenin tam olarak aynı boyutta olduğunu varsayar.
  • Bahsettiğiniz gibi, bağlantılı bir listenin organik olarak büyümesi daha kolaydır. Bir dizinin boyutunun önceden bilinmesi veya büyümesi gerektiğinde yeniden oluşturulması gerekir.
  • Bağlantılı bir listenin karıştırılması, neyin neye işaret ettiğini değiştirme meselesidir. Bir dizi karıştırmak daha karmaşıktır ve / veya daha fazla bellek gerektirir.
  • Yinelemelerinizin tümü "foreach" bağlamında gerçekleştiği sürece yinelemede hiçbir performansı kaybetmezsiniz.

20
Farklı boyutlardaki eşyalar nasıl farklı muamele görür? Bağlantılı liste, bir sonraki alana sahip sabit bir yapı kullanır (sabit boyut gerektirir) veya araçtaki verilere bir işaretçi depolar (değişken boyut OK). Her iki yaklaşım da bir vektör ile aynı derecede kolaydır. Karıştırma için de aynı şey geçerli.
Brian

33
Bir dizi karıştırma daha az karmaşık olduğunu söyleyebilirim .
Hugh Allen

24
Bu cevap yanlış ve yanıltıcı. (bir dizinin büyüklüğünü bilmeniz gerektiğinde hariç)
Robert Paulson

36
Bağlantılı bir listeyi yinelemek, veri konumu nedeniyle daha yavaş olmaz mı?
Firas Assaad

7
@Rick, vektörler genellikle boyutlarının her artışında yeni alan tahsis etmelerine gerek kalmayacak şekilde ihtiyaç duydukları alanı aşırı konumlandırır. Sonuç, vektörlerin tipik olarak çok daha az bellek yoğun olması, bağlantılı listelerden daha fazla olmamasıdır.
Winston Ewert

179

Başka bir iyi neden, bağlantılı listelerin verimli çok iş parçacıklı uygulamalara kendilerini iyi vermesidir. Bunun nedeni, değişikliklerin yerel olma eğilimindedir - veri yapısının yerelleştirilmiş bir bölümüne ekleme ve çıkarma için yalnızca bir veya iki işaretçiyi etkiler. Böylece, aynı bağlantılı listede çalışan birçok iş parçacığına sahip olabilirsiniz. Dahası, CAS tipi işlemleri kullanarak kilitsiz versiyonlar oluşturmak ve ağır kilitlerden tamamen kaçınmak mümkündür.

Bağlantılı bir listeyle, yineleyiciler değişiklikler yapılırken listeden de geçiş yapabilirler. Değişikliklerin çarpışmadığı iyimser durumda, yineleyiciler çekişmeden devam edebilir.

Bir dizide, dizinin boyutunu değiştiren herhangi bir değişikliğin dizinin büyük bir bölümünü kilitlemeyi gerektirmesi muhtemeldir ve aslında, tüm dizi boyunca küresel bir kilit olmadan yapılması nadirdir, bu nedenle değişiklikler dünya işlerini durdurur.


9
Alex - bu benim başıma hiç gelmeyecek ilginç bir konu. Çok iyi bir cevap. Eđer yapabilseydim seni iki kez vurabilirdim. :-)
Onorio Catenacci

5
Bununla nereye gidebileceğiniz hakkında iyi bir fikir edinmek için atlama listelerine (özellikle Java 6'da ConcurrentSkipListMap) göz atın. CSLM, mükemmel performansa sahip sıralı, eşzamanlı bir haritadır. Senkronize bir TreeMap'ten çok daha iyi. tech.puredanger.com/2007/10/03/skip-lists
Alex Miller

… Bunun dışında ConcurrentSkipListMapveya ConcurrentSkipListMaplistede olmayanlar, adlarında bir yerde “Liste” olsa bile. Her ikisi de sıralanacak ve benzersiz anahtarlar gerektirir. Bir örneğe ihtiyacınız varsa List, yani rastgele öğelere yinelenen öğelere izin veren veri yapısına ihtiyacınız varsa , bu uygun değildir ve LinkedListeşzamanlı olarak güncellenebilir bir şey gibi bir veri yapısı oluşturmak için büyük çaba sarf etmeniz gerekir . Sadece eşzamanlı bir kuyruğa veya deque'ye ihtiyacınız varsa, evet, mevcut örnekler bile var, ama eşzamanlı List… Bunun mümkün olduğuna ikna olmadım.
Holger

128

Wikipedia'nın farklılıklar hakkında çok iyi bir bölümü var.

Bağlantılı listelerin dizilere göre birçok avantajı vardır. Öğeler bağlantılı listelere süresiz olarak eklenebilirken, bir dizi sonunda doldurulacak veya yeniden boyutlandırılması gerekecek, bu da bellek parçalanırsa bile mümkün olmayan pahalı bir işlemdir. Benzer şekilde, birçok öğenin çıkarıldığı bir dizi atık olarak boşalabilir veya daha küçük yapılması gerekebilir.

Öte yandan, diziler rastgele erişime izin verirken, bağlantılı listeler yalnızca öğelere sıralı erişime izin verir. Tek bağlantılı listeler aslında sadece tek bir yönde gezilebilir. Bu, bağlantılı listeleri yığın öğesi gibi bir öğeyi dizinine göre hızlı bir şekilde aramanın yararlı olduğu uygulamalar için uygun değildir. Dizilerdeki sıralı erişim, başvuru ve veri önbelleklerinin konumu nedeniyle birçok makinedeki bağlantılı listelere göre daha hızlıdır. Bağlantılı listeler önbellekten neredeyse hiçbir fayda sağlamaz.

Bağlantılı listelerin bir diğer dezavantajı, referanslar için gereken fazladan depolama alanıdır; bu da onları genellikle karakterler veya boole değerleri gibi küçük veri öğelerinin listeleri için kullanışsız hale getirir. Ayrıca yavaş olabilir ve her yeni eleman için ayrı ayrı bellek ayırmak için saf bir ayırıcı ile, genellikle bellek havuzları kullanılarak çözülen bir sorun olabilir.

http://en.wikipedia.org/wiki/Linked_list


4
Bu mükemmel bir cevap. Her ikisinin de avantaj ve dezavantajlarını kısa ve öz bir şekilde tanımlar.
Rick

teşekkür ederim)) ölü basit ama ben wiki görmedim)
Timur Fayzrakhmanov

58

Bir tane daha ekleyeceğim - listeler tamamen işlevsel veri yapıları gibi davranabilir .

Örneğin, aynı uç bölümü paylaşan tamamen farklı listeleriniz olabilir

a = (1 2 3 4, ....)
b = (4 3 2 1 1 2 3 4 ...)
c = (3 4 ...)

yani:

b = 4 -> 3 -> 2 -> 1 -> a
c = a.next.next  

ile gösterilen verileri ve aiçine kopyalamak zorunda kalmadan .bc

Bunların sabit değişkenleri kullanın fonksiyonel dilde kadar popüler olmasının nedeni budur - prependve tailoperasyonlar orijinal veri kopyalamak zorunda kalmadan özgürce ortaya çıkabilir - Eğer değişmez olarak veri tedavi ederken çok önemli özellikler.


4
Daha önce hiç bulamayacağım bir başka ilginç nokta da var. Teşekkür ederim.
Onorio Catenacci

Bunu python'da nasıl yapabilirim?
22'de aşırı değişim

29

Listenin ortasına yerleştirmenin daha kolay olmasının yanı sıra, bağlantılı listenin ortasından silmek bir diziden çok daha kolaydır.

Ama açıkçası, hiçbir zaman bağlantılı bir liste kullanmadım. Ne zaman hızlı ekleme ve silme gerektiğinde, hızlı aramaya da ihtiyacım vardı, bu yüzden bir HashSet'e ya da sözlüğe gittim.


2
Çok doğru, ekleme ve silme çoğu zaman arandıktan sonra gelir, bu nedenle zaman karmaşıklıklarının toplamını da dikkate almanız gerekir.
MA Hossain Tonu

28

İki bağlantılı listeyi (özellikle iki bağlantılı listeyi) birleştirmek, iki diziyi birleştirmekten çok daha hızlıdır (birleştirmenin yıkıcı olduğu varsayılarak). Birincisi O (1), ikincisi O (n) alır.

EDIT: Açıklığa kavuşturmak için, burada birleştirme sıralaması değil, sırasız anlamda "birleştirme" demek istedim. Belki "birleştirmek" daha iyi bir kelime olurdu.


2
Yalnızca bir listeyi diğerine ekliyorsanız. Aslında iki sıralı listeyi birleştiriyorsanız, O (1) 'den daha fazla bir günlük alacaktır.
Herms

3
@Herms, ancak herhangi bir ek bellek ayırmadan iki sıralı bağlantılı listeyi birleştirebilirsiniz, sadece her iki listeyi de gezer ve işaretçileri uygun şekilde ayarlar. İki diziyi birleştirmek normalde en az bir ekstra dizi alır.
Paul Tomblin

1
Evet, listeleri birleştirmek bellekte daha verimlidir, ancak bu benim yorum yaptığım şey değildi. Bağlantılı listelerin birleştirilmesinin O (1) olduğunu söylemek, durumu netleştirmeden çok yanıltıcıdır.
Herms

@Herms listelerini birleştirmek, herhangi bir mantıklı veri modeli altında dizileri birleştirmekten daha fazla bellek verimli değildir.
Alexei Averchenko

2
Alexei Averchenko: İki listeyi birleştirmek, hatta iki sıralı listeyi birleştirmek, O (1) hafızasıyla yerinde yapılabilir. İki diziyi birleştirmek, diziler zaten bellekte bitişik olmadıkça mutlaka O (n) belleği alır. Amaçladığınız nokta, n öğenin bir listesinin ve n öğelerin bir dizisinin hem O (n) hafızasını aldığı, hem de bağlantılı listeler için katsayının daha yüksek olduğu fikridir.
rampion

17

ArrayList için ve LinkedList'e karşı yaygın olarak görülmemiş bir argüman, LinkedLists hata ayıklama sırasında rahatsız olmasıdır . Bakım geliştiricileri tarafından programı anlamak için harcanan zaman, örneğin hataları, artışları ve IMHO'yu bazen performans uygulamalarındaki nanosaniyeleri veya kurumsal uygulamalardaki bellek tüketimindeki baytları haklı çıkarmaz. Bazen (elbette, uygulamaların türüne bağlıdır), birkaç bayt harcamak daha iyidir, ancak daha sürdürülebilir veya anlaşılması daha kolay bir uygulamaya sahip olmak daha iyidir.

Örneğin, bir Java ortamında ve Eclipse hata ayıklayıcısını kullanarak bir ArrayList'in hata ayıklaması, anlaşılması çok kolay bir yapı ortaya koyacaktır:

arrayList   ArrayList<String>
  elementData   Object[]
    [0] Object  "Foo"
    [1] Object  "Foo"
    [2] Object  "Foo"
    [3] Object  "Foo"
    [4] Object  "Foo"
    ...

Öte yandan, LinkedList'in içeriğini izlemek ve belirli nesneleri bulmak, LinkedList iç bileşenlerini filtrelemek için gereken bilişsel yükten bahsetmemek için, Ağacı Genişlet tıklatma kabusu haline gelir:

linkedList  LinkedList<String>
    header  LinkedList$Entry<E>
        element E
        next    LinkedList$Entry<E>
            element E   "Foo"
            next    LinkedList$Entry<E>
                element E   "Foo"
                next    LinkedList$Entry<E>
                    element E   "Foo"
                    next    LinkedList$Entry<E>
                    previous    LinkedList$Entry<E>
                    ...
                previous    LinkedList$Entry<E>
            previous    LinkedList$Entry<E>
        previous    LinkedList$Entry<E>

17

Her şeyden önce, C ++ bağlantılı listelerde çalışmak bir diziden çok daha fazla sorun olmamalıdır. Sen kullanabilirsiniz std :: liste veya boost işaretçi listesi bağlantılı listeler için. Bağlantılı listeler ve dizilerle ilgili önemli sorunlar, işaretçiler için gereken fazladan alan ve korkunç rasgele erişimdir. Bağlantılı bir liste kullanmanız gerekiyorsa

  • verilere rastgele erişime ihtiyacınız yok
  • özellikle listenin ortasında öğeler ekleyecek / sileceksiniz

14

Benim için böyle,

  1. Giriş

    • Bağlantılı Listeler , öğelere yalnızca sıralı erişime izin verir. Dolayısıyla algoritmik karmaşıklıklar O (n) 'nin sırasıdır.
    • Diziler elemanlarına rastgele erişime izin verir ve bu nedenle karmaşıklık O (1) düzenidir.
  2. Depolama

    • Bağlantılı listeler referanslar için ek bir depolama alanı gerektirir. Bu onları karakter veya boole değerleri gibi küçük veri öğelerinin listeleri için kullanışsız hale getirir.
    • Diziler , bir sonraki veri öğesine işaret etmek için fazladan depolama alanına ihtiyaç duymaz. Her öğeye dizinler aracılığıyla erişilebilir.
  3. Boyut

    • Bağlı listelerin boyutu doğası gereği dinamiktir.
    • Büyüklüğü dizisi beyanı ile sınırlandırılmıştır.
  4. Ekleme / Silme

    • Öğeler bağlantılı listelere süresiz olarak eklenebilir ve silinebilir .
    • Değerlerin Ekleme / Silme diziler çok pahalıdır. Bellek yeniden tahsisi gerektirir.

2 numara 2 ve 2 numara 3 var :)
Hengameh

Boş bir dizi bildirebilir ve ardından gerektiği gibi veri eklemeye devam edebiliriz. Hala sabit bir boyutu nasıl yapar?
HebleV

11

İki şey:

Bağlantılı bir listeyi kodlamak şüphesiz bir dizi kullanmaktan biraz daha fazla iştir ve ek çabayı neyin haklı çıkaracağını merak etti.

C ++ kullanırken asla bağlantılı listeyi kodlamayın. Sadece STL'yi kullanın. Uygulamanın ne kadar zor olduğu, bir veri yapısını diğerinin üzerine seçmek için asla bir neden olmamalı çünkü çoğu zaten orada uygulanmaktadır.

Bir dizi ve bağlantılı bir liste arasındaki gerçek farklara gelince, benim için en önemli şey yapıyı nasıl kullanmayı planladığınızdır. C ++ 'da yeniden boyutlandırılabilir bir dizi için kullanılan terim olduğundan vektör terimini kullanacağım.

Bağlantılı bir listeye indeksleme yavaştır, çünkü belirli bir dizine ulaşmak için listeden geçmeniz gerekirken, bir vektör bellekte bitişiktir ve işaretçi matematiğini kullanarak oraya gidebilirsiniz.

Bağlantılı listenin sonuna veya başına eklemek kolaydır, çünkü bir vektörde içeriği yeniden boyutlandırmak ve kopyalamak zorunda kalabileceğiniz tek bir bağlantıyı güncellemeniz gerekir.

Bir öğeyi listeden kaldırmak kolaydır, çünkü bir çift bağlantıyı koparmanız ve sonra tekrar birleştirmeniz yeterlidir. Bir öğeyi vektörden kaldırmak, siparişe önem veriyorsanız, daha hızlı veya daha yavaş olabilir. Kaldırmak istediğiniz öğenin üzerine son öğeyi takas etmek daha hızlı olurken, her şeyi aşağı kaydırdıktan sonra değiştirmek daha yavaştır ancak siparişi korur.


Yukarıda birisine söylediğim gibi, soruyu bana sorulduğu şekilde anlatmaya çalışıyordum. Hiç C ++ bir dizi (veya bir rulo-kendi-bağlantılı listesi) kullanmak olmaz - Ben her ikisi de STL sürümlerini kullanmak istiyorum.
Onorio Catenacci

10

Eric Lippert son zamanlarda dizilerin konservatif olarak kullanılmasının nedenlerinden biri hakkında bir yazı yayınladı.


2
Kuşkusuz iyi bir gönderi, ancak dizi tartışmasına karşı bağlantılı bir listede ilgili değil.
Robert Paulson

2
Liste uygulamasından bağımsız olarak, dizilerin dezavantajlarını ve Listelerin avantajlarını tartıştığından Eric'in makalesinin büyük bir kısmının alakalı olduğunu öneririm.
Bevan

8

Hızlı ekleme ve kaldırma gerçekten bağlantılı listeler için en iyi argümanlardır. Yapınız dinamik olarak büyürse ve herhangi bir öğeye (dinamik yığınlar ve kuyruklar gibi) sabit zamanlı erişim gerekli değilse, bağlantılı listeler iyi bir seçimdir.


7

İşte hızlı bir tane: Öğelerin kaldırılması daha hızlı.


7

Bağlantılı liste özellikle koleksiyon sürekli büyüdüğünde ve küçüldüğünde yararlıdır. Örneğin, bir dizi kullanarak bir Kuyruk (sonuna kadar ekleyin, önden kaldırın) uygulamaya çalıştığınızı hayal etmek zordur - tüm zamanınızı bir şeyler aşağı kaydırmak için harcıyorsunuz. Öte yandan, bağlantılı bir listeyle önemsizdir.


4
Hâlâ hızlı / verimli olan çok fazla iş olmadan dizi tabanlı bir kuyruğunuz olabilir. Sadece hangi indeksin "kafa" hangisinin "kuyruk" olduğunu takip etmek zorundasınız. Sabit boyutlu bir sıraya (örneğin bir çekirdekte klavye arabelleği) ihtiyacınız varsa bu oldukça iyi çalışır.
Herms

3
En sevdiğiniz algoritma başvurusunda aramak istiyorsanız "dairesel tampon" olarak adlandırılır.
Steve Jessop

7

Listenin ortasına ekleme ve kaldırma dışında, bağlantılı listeleri daha çok seviyorum çünkü dinamik olarak büyüyebilir ve küçülebilirler.


6
Vektörler (= temel olarak diziler) de bunu yapabilir ve referans konumlar nedeniyle genellikle amortismana tabi tutulmuş maliyetler listelerin maliyetinden daha düşüktür.
Konrad Rudolph

7

Artık hiç kimse kendi bağlantılı listesini kodlamıyor. Aptalca olurdu. Bağlantılı bir listeyi kullanmanın daha fazla kod alması önermesi yanlıştır.

Bu günlerde, bağlantılı bir liste oluşturmak öğrenciler için sadece bir alıştırmadır, böylece kavramı anlayabilirler. Bunun yerine, herkes önceden oluşturulmuş bir liste kullanır. C ++ 'da, sorumuzdaki açıklamaya dayanarak, bu muhtemelen bir stl vektörü ( #include <vector>) anlamına gelir .

Bu nedenle, bir dizi ile bir dizi arasındaki bağlantıyı seçmek tamamen uygulamanızın ihtiyaçlarına göre her yapının farklı özelliklerini tartmakla ilgilidir. Ek programlama yükünün aşılmasının karar üzerinde sıfır etkisi olmalıdır.


2
Er..umm .. std :: vector, bağlantılı bir liste değil, bir dizidir. Standart bağlantılı liste std :: list şeklindedir.
James Curran

1
evet, ama bence o op dinamik bir dizi değiştirme için istediğini daha yakın vektör.
Joel Coehoorn

@Joel, soruyu C ++ öğrenmeye çalışan bu adam bana söylediği gibi anlatmaya çalışıyordum. Ben de kendi bağlantılı listemi kodlamakla uğraşmazdım ama bana böyle sordu. :-)
Onorio Catenacci

Özel derleyicilerin bulunduğu bellek kısıtlı ortamlarda (mikro denetleyiciler), dilin tamamı (örn., C ++ içindeki kaplar) uygulanmaz. Bu yüzden, kendi bağlantılı listenizi kodlamanız gerekebilir. nongnu.org/avr-libc/user-manual/FAQ.html#faq_cplusplus
Minh Tran

6

Bu gerçekten bir verimlilik meselesidir, bağlantılı bir listeye elemanları eklemek, kaldırmak veya taşımak için (sadece değiştirmediğiniz yerde) ek yük minimumdur, yani işlemin kendisi O (1), bir dizi için O (n) ayetidir. Bir veri listesinde yoğun bir şekilde çalışıyorsanız, bu önemli bir fark yaratabilir. Veri türlerinizi, bunlar üzerinde nasıl çalışacağınıza bağlı olarak seçtiniz ve kullandığınız algoritma için en verimli olanı seçtiniz.


6

Diziler, tam öğe sayısının nerede bilindiği ve dizine göre aramanın mantıklı olduğu yerlerde anlamlıdır. Örneğin, video çıkışımın kesin durumunu sıkıştırma olmadan belirli bir anda saklamak istersem, muhtemelen [1024] [768] boyutunda bir dizi kullanırdım. Bu bana tam olarak ihtiyacım olanı sağlayacak ve bir liste belirli bir pikselin değerini elde etmek için çok, çok daha yavaş olacaktır. Bir dizinin mantıklı olmadığı yerlerde, verilerle etkili bir şekilde ilgilenmek için genellikle bir listeden daha iyi veri türleri vardır.


6

Arrays Vs Bağlantılı Listesi:

  1. Dizi belleği ayırma bazen parçalanmış bellek nedeniyle başarısız olur.
  2. Dizilerde önbellekleme daha iyidir, çünkü tüm öğelere bitişik bellek alanı ayrılmıştır.
  3. Kodlama Dizilerden daha karmaşıktır.
  4. Dizilerden farklı olarak Bağlantılı Liste'de boyut kısıtlaması yok
  5. Bağlantılı Listeye ekleme / Silme daha hızlıdır ve Dizilerde erişim daha hızlıdır.
  6. Bağlantılı Liste çoklu iş parçacığı açısından daha iyi.

-1: Bunların hepsinin sadece numaralandırılması değil doğrulanması gerekir.
John Saunders

Her nokta yukarıdaki cevaplarda zaten açıklanmıştır. Bir geç gelen numaralandırma olmaktan başka seçeneğim yoktu. BTW, Hangisine açıklanmak istersiniz?
AKS

Zaten açıklanmışlarsa, neden cevap veriyorsunuz?
John Saunders

2
Böylece tartışmanın özet bir görünümünü verecektir. Ve bu tür cevapları seviyorum, böylece aynı açıklamayı tekrar tekrar okumak zorunda kalmam. Bunu benimle aynı düşünme tarzına sahip insanlar için yaptım. Farklı ppl farklı stilleri var. Herşey aynı.
AKS

3

diziler doğada statik olduğundan, bellek ayırma gibi tüm işlemler yalnızca derleme sırasında gerçekleşir. Yani işlemci çalışma zamanında daha az çaba harcamalıdır.


3

Öğeleri ekleyerek ve kaldırarak da değiştirmek istediğiniz sıralı bir kümeniz olduğunu varsayalım. Ayrıca, daha sonra önceki veya sonraki öğeyi alabileceğiniz şekilde bir öğeye referans tutma yeteneğine sahip olmanız gerekir. Örneğin, bir kitaptaki yapılacaklar listesi veya paragraflar kümesi.

Öncelikle, kümenin dışındaki nesnelere referansları tutmak istiyorsanız, büyük olasılıkla nesneleri kendileri depolamak yerine dizide işaretçiler depolayacağınızı unutmayın. Aksi takdirde diziye ekleyemezsiniz - nesneler diziye katıştırılırsa, eklemeler sırasında hareket ederler ve onlara işaretçiler geçersiz olur. Aynı şey dizi indeksleri için de geçerlidir.

İlk probleminiz, sizin de belirttiğiniz gibi, ekleme bağlantılı liste O (1) içine ekleme yapılmasına izin verir, ancak bir dizi genellikle O (n) gerektirir. Bu problem kısmen aşılabilir - hem okuma hem de yazma işleminin en kötü ihtimalle logaritmik olduğu dizi benzeri sıradan erişim arabirimi veren bir veri yapısı oluşturmak mümkündür.

İkinci ve daha ciddi probleminiz, bir sonraki elemanı bulmak için verilen elemanın O (n) olmasıdır. Küme değiştirilmediyse, öğenin dizinini işaretçi yerine referans olarak tutabilir ve böylece find-next'i O (1) işlemi haline getirebilirsiniz, ancak elinizde olduğu gibi nesnenin kendisine bir işaretçi ve hiçbir şekilde "dizinin" tamamını taramak dışında dizideki geçerli dizinini belirlemek için. Bu, diziler için çözülemez bir sorundur - eklemeleri optimize edebilseniz bile, sonraki bulma türünü optimize etmek için yapabileceğiniz hiçbir şey yoktur.


Lütfen bunu ayrıntılı bir şekilde açıklar mısınız?
Hengameh

1
Wikipedia'da Dinamik Dizi / Vriants bölümünde bazı şeyler var. Aklımda olan şey tam olarak değil ... Sayfaları olan ancak anahtarsız b + ağaç benzeri bir yapı düşünün, bunun yerine her ara sayfa alt sayfaların her birinde kaç öğe olduğunu hatırlarken, yaprak sayfaları küçük bir dizideki öğeleri. Bir yaprak sayfasına bir öğe eklerken, yer açmak için sayfanın yaklaşık yarısını hareket ettirmeniz, ardından yukarı çıkıp tüm ata sayfalarındaki öğe sayısını güncellemeniz gerekir. Bir
#N öğesini ararken

3

Bir dizide O (1) zamanında herhangi bir öğeye erişme ayrıcalığına sahip olursunuz. Bu yüzden İkili arama Hızlı sıralama, vb gibi işlemler için uygundur. Öte yandan bağlantılı liste O (1) zamanında olduğu gibi ekleme silme için uygundur. Her ikisinin de avantajları ve dezavantajları vardır ve birini uygulamak istediğiniz şeye göre diğerini tercih etmektir.

- Daha büyük bir soru, her ikisinin de bir melezine sahip olabilir miyiz. Liste olarak python ve perl'in uyguladığı gibi bir şey.


3

Bağlantılı liste

Yerleştirme söz konusu olduğunda daha çok tercih edilir! Temel olarak, işaretçi ile ilgilenmesi

1 -> 3 -> 4

Ekle (2)

1 ........ 3 ...... 4
..... 2

En sonunda

1 -> 2 -> 3 -> 4

3'te 2 noktadan bir ok ve 2'de 1 noktadan ok

Basit!

Ama Diziden

| 1 | 3 | 4 |

Ekle (2) | 1 | 3 | | 4 | | 1 | | 3 | 4 | | 1 | 2 | 3 | 4 |

Herkes farkı görselleştirebilir! Sadece 4 endeks için 3 adım gerçekleştiriyoruz

Dizi uzunluğu bir milyon ise? Dizi verimli mi? Cevap hayır! :)

Aynı şey silinmek için de geçerli! Bağlantılı Listede yalnızca işaretçiyi kullanabilir ve öğeyi geçersiz kılabilir ve sonraki nesneyi sınıflandırabiliriz! Ancak dizi için shiftLeft () gerçekleştirmemiz gerekir

Umarım yardımcı olur! :)


3

Bağlantılı Liste, diziden daha fazla bir ek yüktür, ayrıca tüm bu noktaların kabul edildiği ek bellek depolama alanı gerektirir. Ama dizinin yapamayacağı birkaç şey var. Birçok durumda 10 ^ 9 uzunluğunda bir dizi istediğinizi varsayalım, çünkü bir sürekli bellek konumu elde etmek zorundasınız. Bağlantılı liste burada bir kurtarıcı olabilir.

Varsayalım, birden çok şeyi veriyle birlikte depolamak istediğinizi varsa, bunlar bağlantılı listede kolayca genişletilebilir.

STL kapları genellikle sahne arkasında bağlantılı liste uygulamasına sahiptir.


3

1- Bağlantılı liste dinamik bir veri yapısıdır, böylece bellek ayırarak ve yeniden yerleştirerek çalışma zamanında büyüyebilir ve küçülebilir. Dolayısıyla, bağlantılı listenin başlangıç ​​boyutunun verilmesine gerek yoktur. Düğümlerin yerleştirilmesi ve silinmesi gerçekten daha kolaydır.

2- Bağlantılı listenin boyutu, çalışma zamanında artabilir veya azalabilir, böylece bellek kaybı olmaz. Dizi durumunda, 10 boyutlu bir dizi bildirir ve sadece 6 elementi saklarsak, 4 elementin boşa harcanması gibi, çok fazla bellek kaybı olur. Bağlantılı listede böyle bir sorun yoktur, çünkü bellek sadece gerektiğinde tahsis edilir.

3- Yığın ve kuyruklar gibi veri yapıları bağlantılı liste kullanılarak kolayca uygulanabilir.


1 ve 2, dizi dinamik olarak tahsis edilerek çözülür. 3. Yığın dizisi gibi kolayca uygulanabilir. Kuyruklar biraz daha karmaşık, ama çok zor değil - dairesel bir tampon yapabilirsiniz.
Hedede

2

Bağlantılı listeyi kullanmanın tek nedeni, öğeyi eklemenin kolay olmasıdır (ayrıca kaldırmak).

Dezavantaj, işaretçilerin çok yer kaplaması olabilir.

Ve bu kodlama daha zordur: Genellikle kod bağlantılı listeye (veya sadece bir kez) ihtiyacınız yoktur, bunlar STL'ye dahil edilir ve hala yapmak zorundaysanız çok karmaşık değildir.


2
İşaretçiler çok yer kaplıyor mu? Pek sayılmaz. Bağlantılı bir boole listesi saklıyorsanız, işaretçilerin çok fazla yer kapladığından emin olun. Ancak karmaşık nesneleri (genellikle durumdur) saklıyorsanız, işaretçiler muhtemelen ihmal edilebilir olacaktır.
Herms

gülümsemeyi unuttum :) Ama 'olamaz' değil 'demişti.
user15453

1

Ayrıca bağlantı listesinin dizilerden daha iyi olduğunu düşünüyorum. çünkü bağlantı listesinde geçiş yapıyoruz ancak dizilerde değil


1

Dilinize bağlı olarak, bu dezavantajların ve avantajların bazıları dikkate alınabilir:

C Programlama Dili : Bağlantılı bir liste kullanırken (tipik olarak yapı işaretçileri aracılığıyla), bellek sızdırmadığından emin olunmalıdır. Daha önce de belirtildiği gibi, bağlantılı listelerin karıştırılması kolaydır, çünkü tek yapmanız gereken işaretçileri değiştirmek, ancak her şeyi serbest bırakmayı hatırlayacak mıyız?

Java : Java'nın otomatik bir çöp toplama özelliği vardır, bu nedenle sızan bellek bir sorun olmaz, ancak üst düzey programcıdan gizlenen, bağlantılı bir listenin ne olduğuna dair uygulama ayrıntılarıdır. Bir düğümü listenin ortasından kaldırmak gibi yöntemler, bir prosedür için dilin bazı kullanıcılarının beklediğinden daha karmaşıktır.


1

Neden bir dizi üzerinden bağlantılı bir liste? Bazılarının söylediği gibi, daha yüksek ekleme ve silme hızı.

Ama belki ikisinin de sınırları ile yaşamak ve ikisinden de en iyisini elde etmek zorunda değiliz, aynı zamanda ... ha?

Dizi silme işlemlerinde, bir satırın silindiğini göstermek için 'Silindi' baytını kullanabilirsiniz, böylece diziyi yeniden düzenlemek artık gerekli değildir. Ekleme yükünü veya hızla değişen verileri kolaylaştırmak için bunun için bağlantılı bir liste kullanın. Onlara atıfta bulunurken, önce mantığınızdan önce birini sonra diğerini aramasını isteyin. Böylece, bunları birlikte kullanmak size her ikisinin de en iyisini verir.

Gerçekten büyük bir diziniz varsa, daha küçük olan en son kullanılan öğelerin bulunduğu 20, 50, 100 öğelerini tuttuğu başka, daha küçük bir dizi veya bağlantılı liste ile birleştirebilirsiniz. Gerekli olan daha kısa bağlantılı listede veya dizide değilse, büyük diziye gidersiniz. Orada bulunursa, daha sonra 'en son kullanılan şeylerin yeniden kullanılmaya en çok benzediği' varsayımıyla daha küçük bağlantılı listeye / diziye ekleyebilirsiniz (ve evet, muhtemelen en az kullanılan öğeyi listeden çarpma). Bu, birçok durumda doğrudur ve bir .ASP güvenlik izinleri kontrol modülünde, kolaylık, zarafet ve etkileyici bir hızla ele almak zorunda kaldım bir sorunu çözdü.


1

Birçoğunuz bağlantılı listenin vs vs ana adv./dis'e dokunduğunuz halde, karşılaştırmaların çoğu birinin diğerinden daha iyi / kötü olduğu şeklindedir. dizide rastgele erişim yapabilirsiniz ancak bağlantılı listede ve diğerlerinde mümkün değildir. Ancak bu, bağlantı listelerinin ve dizinin benzer bir uygulamada uygulanacağını varsayar. Bununla birlikte, bağlantı listesinin belirli bir uygulama dağıtımında dizi veya tersi yönde nasıl tercih edileceği doğru bir yanıt olmalıdır. Bir sözlük uygulaması uygulamak istediğinizi varsayalım, ne kullanırsınız? Dizi: mmm bu ikili arama ve diğer arama algo ile kolay erişim sağlar .. ama bağlantı listesi nasıl daha iyi olabileceğini düşünelim .. Sözlük "Blob" aramak istiyorum. A-> B-> C-> D ----> bir bağlantı listesine sahip olmak anlamlı olur mu?

A -> B -> C -> ...Z
|    |    |
|    |    [Cat, Cave]
|    [Banana, Blob]
[Adam, Apple]

Şimdi yukarıdaki yaklaşım daha mı iyi ya da düz bir dizi mi [Adem, Elma, Muz, Damla, Kedi, Mağara]? Dizi ile bile mümkün olabilir mi? Bu nedenle, bağlantı listesinin en büyük avantajı, yalnızca bir sonraki öğeye değil aynı zamanda başka bir bağlantı listesine / dizi / yığın / veya başka bir bellek konumuna işaret eden bir öğeye sahip olabilmenizdir. Dizi, depolayacağı elemanın blok boyutuna dilimlenmiş tek bir düz bitişik bellektir. diğer şekilde. Benzer şekilde bir USB sürücü yaptığınızı varsayalım. Şimdi dosyaların herhangi bir dizi veya bağlantı listesi olarak kaydedilmesini ister misiniz? Sanırım neye işaret ettiğimi anladın :)

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.