Bağlantılı liste ne zaman dizi / dizi listesi üzerinde kullanılır?


176

Çok sayıda liste ve diziler kullanıyorum, ancak dizi listesinin bağlantılı listeden daha kolay olmasa bile kolayca kullanılamadığı bir senaryoya rastlamamıştım. Birisinin bana bağlantılı listenin ne zaman daha iyi olduğuna dair bazı örnekler verebileceğini umuyordum.


Java'da, ArrayList ve LinkedList yapıcıdan farklı olarak tam olarak aynı kodu kullanır. "Dizi listeniz ... bağlantılı listeden daha kolay veya daha kolay kullanılır" anlamsız. Lütfen bir ArrayList'in LinkedList'ten "daha kolay" olduğuna dair bir örnek verin.
S.Lott



3
S.Lott Bu doğru değil. Java ArrayList, bazı yardımcı işlevler eklenmiş bir Array'ın etrafındaki bir paketleyicidir. Bağlantılı bir liste, tabii ki bağlantılı bir listedir. developer.classpath.org/doc/java/util/ArrayList-source.html
kingfrito_5005

Yanıtlar:


261

Bağlantılı listeler şu durumlarda dizilere göre tercih edilir:

  1. listeden sabit zamanlı eklemelere / silmelere ihtiyacınız vardır (örneğin, zaman tahmininin kesinlikle kritik olduğu gerçek zamanlı hesaplamada)

  2. listede kaç öğe olacağını bilmiyorsunuz. Dizilerle, dizi çok büyürse belleği yeniden bildirmeniz ve kopyalamanız gerekebilir

  3. herhangi bir öğeye rastgele erişime ihtiyacınız yok

  4. listenin ortasına öğe ekleyebilirsiniz (öncelik sırası gibi)

Diziler şu durumlarda tercih edilir:

  1. öğelere dizinlenmiş / rastgele erişime ihtiyacınız var

  2. dizi için doğru miktarda bellek ayırabilmeniz için dizideki öğelerin sayısını önceden bilirsiniz

  3. sırayla tüm öğeler arasında yineleme yaparken hıza ihtiyacınız vardır. Her öğeye erişmek için dizideki işaretçi matematiğini kullanabilirsiniz; buna karşılık, bağlantılı listedeki her öğenin işaretçisine dayalı olarak düğüme bakmanız gerekir; bu da performans isabetlerine neden olabilecek sayfa hatalarına neden olabilir.

  4. hafıza bir sorundur. Doldurulmuş diziler, bağlantılı listelerden daha az bellek kaplar. Dizideki her öğe yalnızca veridir. Her bağlantılı liste düğümü, verilerin yanı sıra bağlantılı listedeki diğer öğelere bir (veya daha fazla) işaretçi gerektirir.

Dizi Listeleri (.Net'tekiler gibi) size dizilerin avantajlarını sağlar, ancak liste boyutu hakkında çok fazla endişelenmenize gerek kalmadan kaynakları sizin için dinamik olarak ayırır ve herhangi bir dizinde öğeleri herhangi bir çaba sarf etmeden veya silmeden silebilirsiniz. öğeleri karıştırma. Performans açısından, diziciler ham dizilerden daha yavaştır.


7
İyi bir başlangıç, ancak bu önemli şeyleri dışarıda bırakır: listeler yapı paylaşımını destekler, diziler daha yoğundur ve daha iyi bir konuma sahiptir.
Darius Bacon

1
Pratik olarak, diziciler ve diziler arasındaki performans farkı göz ardı edilebilir. Bu, karşılaştırılabilir bir karşılaştırma yaptığınızı varsayar ve örneğin, önceden boyutu bildiğinizde, diziliciye bunu anlatırsınız.
svick

40
LinkedList ne zamandan beri O (1) ekler / siler ( sabit zaman ekler / siler derken demek istediğim budur )? LinkedList'in ortasına bir şeyler eklemek her zaman O (n)
Pacerier

28
Eklenen konumda (yineleyici aracılığıyla) zaten bulunduysanız LinkedLists O (1) ekler var. Yine de her zaman değil.
Adam

4
Öncelik kuyrukları için bağlantılı listelerin kullanılması çok aptalca bir fikirdir. Dinamik dizi destekli yığınlar, O (lg n) amortisman eklenmesine ve en kötü durumda logaritmik delete-min'e izin verir ve en hızlı pratik öncelikli kuyruk yapıları arasındadır.
Fred Foo

54

Diziler O (1) rasgele erişime sahiptir, ancak öğelere öğe eklemek veya öğeden öğe kaldırmak gerçekten pahalıdır.

Bağlantılı listeler, herhangi bir yere öğe eklemek veya kaldırmak ve yinelemek için gerçekten ucuzdur, ancak rastgele erişim O (n) 'dir.


3
Bağlantılı listenin her iki ucundan öğe eklemek / kaldırmak gibi, bir dizinin sonundaki öğeleri kaldırmak da değişkendir . Ortada ... ikisi için de fazla değil.
Joey

1
@ Joey, Bağlantılı Liste O (n) sonunda ekleme / silme değil mi? Sondan bir önceki bağlantıya yerleştirilmediyseniz, son öğeyi bulmak için yine de O (n) adımına ihtiyacınız olacak, değil mi?
Alex Moore-Niemi

@ AlexMoore-Niemi: Tek bağlantılı bir liste için evet. Ancak birçoğunun ileri ve geri bağlantıları vardır ve böylece her iki ucu da işaret eder.
Joey

2
İki kez bağlantılı listelere sahip olmak,
LL'niz

"Bağlantılı listeler herhangi bir yere öğe eklemek veya kaldırmak ve yinelemek gerçekten ucuz" tamamen doğru değil. Bağlantılı listenin ortasında bulunan bir öğeyi kaldırmak istersem, listeden bu öğeye ulaşana kadar baştan tekrarlamam gerekir. O (n / 2) zamanı, burada n = listedeki öğe sayısı. Cevabınızdan, sabit zamanı O (1) dizide olduğu gibi önerdiğiniz gibi geliyor. Bağlantılı listenin baş / kök düğümünü eklemek / kaldırmak için sabit bir zamandır.
Yawar Murtaza

22
Algorithm           ArrayList   LinkedList
seek front            O(1)         O(1)
seek back             O(1)         O(1)
seek to index         O(1)         O(N)
insert at front       O(N)         O(1)
insert at back        O(1)         O(1)
insert after an item  O(N)         O(1)

ArrayLists, bir kez okundu-çok veya ekler için iyidir, ancak önden veya ortadan ekleme / çıkarma konusunda kötüdür.


14

Diğer cevaplara eklemek için, dizi listesi uygulamalarının çoğu listenin sonunda ekstra kapasite ayırır, böylece listenin sonuna O (1) zamanda yeni öğeler eklenebilir. Bir dizi listesinin kapasitesi aşıldığında, dahili olarak yeni, daha büyük bir dizi ayrılır ve tüm eski öğeler kopyalanır. Genellikle, yeni dizi eskisinin iki katı büyüklüğündedir. Bu , ortalama olarak , bir dizi listesinin sonuna yeni öğeler eklemenin, bu uygulamalarda O (1) işlemi olduğu anlamına gelir. Bu nedenle, önceden öğe sayısını bilmeseniz bile, bir dizi listesi, öğeleri eklemek için bağlantılı bir listeden daha hızlı olabilir, sonunda onları eklediğiniz sürece. Açıkçası, bir dizi listesindeki rastgele konumlara yeni öğeler eklemek hala bir O (n) işlemidir.

Bir dizi listesindeki öğelere erişim, bağlantılar sıralı olsa bile bağlantılı listeden daha hızlıdır. Bunun nedeni dizi öğelerinin bitişik bellekte depolanması ve kolayca önbelleğe alınabilmesidir. Bağlantılı liste düğümleri potansiyel olarak birçok farklı sayfaya dağıtılabilir.

Yalnızca rastgele konumlara öğe ekleyeceğinizi veya sileceğinizi biliyorsanız, bağlantılı bir liste kullanmanızı öneririm. Dizi listeleri hemen hemen her şey için daha hızlı olacaktır.


1
Ayrıca, dinamik diziler kullanarak bağlantılı listeler de (Özet Veri Türü anlamında) uygulayabilirsiniz. Bu şekilde, listenin başında amortismana tabi sabit zaman ekleme ve silmelere sahipken bilgisayar önbelleğinden ve ayrıca ekleme işleminin ardından öğenin dizinine sahip olduğunuzda, listenin ortasındaki itfa edilmiş sabit zaman ekleme ve silmelere sahip olabilirsiniz. yapılacak veya silinecek öğenin dizini (vardiya / vardiya gerekmez). Bunun için iyi bir referans CLRS 10.3'tür .
Domenico De Felice

7

Listenin avantajı, ortadaki öğeleri eklemeniz gerekiyorsa ve diziyi yeniden boyutlandırmaya ve bir şeyleri değiştirmeye başlamak istemiyorsanız görünür.

Bu doğru değil çünkü doğru. Bunun gibi birkaç çok özel durumum vardı, ama çok fazla değil.


Diziyi değiştirmek ve diziyi yeniden boyutlandırmak, ortada ters çevirmeler yaptığınızda gerçekte olan şeydir. Eğer sadece amortisman sınırına ulaşmazsanız, yeniden boyutlandırmadan kaydırmaya ihtiyacınız olacaktır.
9'da güvenli güvenlik

3

Her şey yineleme yaparken ne tür bir işlem yaptığınıza bağlıdır, tüm veri yapıları zaman ve bellek arasında değiş tokuş yapar ve ihtiyaçlarımıza bağlı olarak doğru DS'yi seçmeliyiz. Bu yüzden LinkedList'in diziden daha hızlı ve tersi olduğu bazı durumlar vardır. Veri yapıları üzerindeki üç temel işlemi düşünün.

  • Aranıyor

Dizi, dizin tabanlı veri yapısı olduğundan, array.get (index), directory, dizin DS'si değilken O (1) zaman alacaktır; bu nedenle, dizin <= n, n, bağlantılı listenin boyutudur, Böylece elemanlar rastgele erişime sahip olduğunda dizi bağlantılı liste daha hızlıdır.

S. Peki bunun arkasındaki güzellik nedir?

Diziler bitişik bellek blokları olduğundan, ilk erişim üzerine büyük parçalar önbelleğe yüklenir, bu da dizi lokasyonundaki öğelere eriştiğimiz sürece dizinin kalan elemanlarına erişmeyi nispeten hızlı hale getirir. özlüyorsa, Önbellek konumu önbellekteki işlemleri ifade eder ve bu nedenle bellekte olduğundan çok daha hızlı yürütülür, Temelde Dizide sıralı eleman erişiminin önbellekte olma olasılığını en üst düzeye çıkarırız. Bağlantılı listelerin bitişik bellek bloklarında olması gerekmemekle birlikte, listede sıralı olarak görünen öğelerin aslında bellekte birbirinin yanında düzenlendiği garantisi yoktur;

  • sokma

Bu, LinkedList'te kolay ve hızlıdır, çünkü ekleme, LinkedList'te (Java'da) diziye kıyasla O (1) işlemidir, dizi dolu olduğunda durumu düşünün, dizi dolduğunda içeriğin yeni diziye kopyalanması gerekir. öğeyi en kötü durumda ArrayList of O (n) içine alırken, dizinin sonuna dışında herhangi bir yere eklerseniz ArrayList'in dizinini güncellemesi gerekir, bağlantılı listenin yeniden boyutlandırılması gerekmiyorsa, sadece işaretçiler güncelleme.

  • silme

LinkedList'de eklemeler gibi çalışır ve diziden daha iyidir.


2

Bunlar Koleksiyon'un en yaygın kullanılan uygulamalarıdır.

ArrayList:

  • genellikle sonuna ekle / sil O (1) en kötü durum O (n)

  • ortadaki ekle / sil O (n)

  • herhangi bir pozisyonu al O (1)

Bağlantılı liste:

  • herhangi bir konuma yerleştirin / silin O (1) (öğeye referansınız olup olmadığını not edin)

  • ortadaki geri alma O (n)

  • ilk veya son elemanı O (1) al

Vektör: kullanma. ArrayList'e benzer, ancak tüm yöntemler senkronize edilmiş eski bir uygulamadır. Çok iş parçacıklı bir ortamda paylaşılan bir liste için doğru yaklaşım değildir.

HashMap

O ile anahtarla ekleme / silme / alma (1)

O'da TreeSet ekleme / silme / içerir (log N)

HashSet O içinde ekleme / kaldırma / içerir / boyut (1)


1

Gerçekte, bellek yerinin gerçek işlemede büyük bir performans etkisi vardır.

Rasgele erişime karşı "büyük veri" işlemede artan disk akışı kullanımı, uygulamanızın bunun etrafında yapılandırılmasının performansı daha büyük ölçekte nasıl önemli ölçüde artırabileceğini gösterir.

Bir diziye sıralı olarak erişmenin herhangi bir yolu varsa, bu en iyi performanstır. Bunun bir amaç olarak tasarlanması en azından performans önemliyse dikkate alınmalıdır.


0

Hmm, Arraylist aşağıdaki gibi durumlarda kullanılabilir sanırım:

  1. kaç elementin mevcut olacağından emin değilsiniz
  2. ancak dizin oluşturma yoluyla tüm öğelere rastgele erişmeniz gerekir

Örneğin, bir kişi listesindeki (boyutu sizin tarafınızdan bilinmeyen) tüm öğeleri içe aktarmanız ve bunlara erişmeniz gerekir


0

Radix Sort için diziler ve polinom işlemleri için bağlantılı listeyi kullanın.


0

1) Yukarıda açıklandığı gibi, takma ve çıkarma işlemleri LinkedList'te ArrayList (O (n)) ile karşılaştırıldığında iyi performans (O (1)) verir. Bu nedenle, uygulamada sık sık ekleme ve silme gereksinimi varsa LinkedList en iyi seçimdir.

2) Arama (alma yöntemi) işlemleri Arraylist'te (O (1)) hızlıdır ancak LinkedList'te (O (n)) hızlı değildir, bu nedenle daha az ekleme ve kaldırma işlemi ve daha fazla arama işlemi gereksinimi varsa, ArrayList en iyi seçiminiz olacaktır.


0

Temel fark, listenin en üstüne bir şeyler sık ​​sık eklemeniz veya kaldırmanız gerekmesidir.

Bir dizi ile, listenin üst kısmından bir şey kaldırırsanız, karmaşıklık o (n) olur, çünkü dizi öğelerinin tüm indeksleri değişmelidir.

Bağlantılı bir listeyle, o (1) 'dir, çünkü yalnızca düğümü oluşturmanız, başlığı yeniden atamanız ve bir sonraki başlık olarak bir sonraki referansa atamanız gerekir.

Listenin sonuna sık sık eklenirken veya kaldırılırken, karmaşıklıklar o (1) olacağı için diziler tercih edilir, ancak yeniden endeksleme gerekmez, ancak bağlantılı bir liste için o (n) olacaktır, çünkü kafadan gitmeniz gerekir son düğüme kadar.

Bağlantılı listede ve dizilerde arama yapmanın o (log n) olacağını düşünüyorum çünkü muhtemelen ikili bir arama kullanacaksınız.


0

Bazı kıyaslama yaptım ve liste sınıfının rastgele ekleme için aslında LinkedList'ten daha hızlı olduğunu gördüm:

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            int count = 20000;
            Random rand = new Random(12345);

            Stopwatch watch = Stopwatch.StartNew();
            LinkedList<int> ll = new LinkedList<int>();
            ll.AddLast(0);
            for (int i = 1; i < count; i++)
            {
                ll.AddBefore(ll.Find(rand.Next(i)),i);

            }
            Console.WriteLine("LinkedList/Random Add: {0}ms", watch.ElapsedMilliseconds);

            watch = Stopwatch.StartNew();
            List<int> list = new List<int>();
            list.Add(0);
            for (int i = 1; i < count; i++)
            {
                list.Insert(list.IndexOf(rand.Next(i)), i);

            }
            Console.WriteLine("List/Random Add: {0}ms", watch.ElapsedMilliseconds);

            Console.ReadLine();
        }
    }
}

Bağlantılı liste için 900 ms ve liste sınıfı için 100 ms sürer.

Sonraki tamsayı numaralarının listesini oluşturur. Her yeni tamsayı, listede zaten bulunan rastgele bir sayıdan sonra eklenir. Belki de List sınıfı bir diziden daha iyi bir şey kullanır.


Liste bir arayüz değil, bir sınıftır
borgmater

0

Diziler açık arayla en yaygın kullanılan veri yapılarıdır. Bununla birlikte, bağlantılı listeler, dizilerin en azından söylemek gerekirse beceriksiz veya pahalı olduğu kendi benzersiz yollarında yararlıdır.

Bağlı listeler, boyutlarının değişebileceği durumlarda yığınları ve kuyrukları uygulamak için kullanışlıdır. Bağlantılı listedeki her bir düğüm, düğümlerin çoğunu bozmadan itilebilir veya patlatılabilir. Aynı şey ortada bir yerde düğümlerin eklenmesi / silinmesi için de geçerlidir. Bununla birlikte, dizilerde, tüm elemanların kaydırılması gerekir, bu da yürütme süresi açısından pahalı bir iştir.

İkili ağaçlar ve ikili arama ağaçları, karma tablolar ve denemeler veri yapılarından bazılarıdır; burada - en azından C'de - bunları oluşturmak için temel bir bileşen olarak bağlantılı listelere ihtiyacınız vardır.

Bununla birlikte, indeksiyle herhangi bir keyfi öğeyi çağırabileceği durumlarda bağlantılı listelerden kaçınılmalıdır.


0

Bu noktalar kullanılarak soruya basit bir cevap verilebilir:

  1. Diziler, benzer türde veri öğelerinin toplanması gerektiğinde kullanılmalıdır. Oysa bağlantılı liste, düğüm olarak bilinen karışık tip veri bağlantılı elemanların bir koleksiyonudur.

  2. Dizide O (1) zamanında herhangi bir eleman ziyaret edilebilir. Bununla birlikte, bağlantılı listede O (n) zaman alan bağlı listenin tamamını baştan başlayarak gerekli düğüme geçirmemiz gerekir.

  3. Diziler için, başlangıçta belirli bir boyutun bildirilmesi gerekir. Ancak bağlantılı listelerin boyutu dinamiktir.

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.