Kapan lebih baik menggunakan Daftar vs LinkedList ?
c#
.net
vb.net
data-structures
linked-list
Jonathan Allen
sumber
sumber
Jawaban:
Edit
Jawaban asli ...
Saya menemukan hasil yang menarik:
Daftar tertaut (3,9 detik)
Daftar (2,4 detik)
Bahkan jika Anda hanya mengakses data pada dasarnya itu jauh lebih lambat !! Saya katakan tidak pernah menggunakan LinkedList.
Berikut adalah perbandingan lain yang melakukan banyak sisipan (kami berencana untuk memasukkan item di tengah daftar)
Daftar Tertaut (51 detik)
Daftar (7,26 detik)
Daftar Tertaut memiliki referensi lokasi tempat memasukkan (0,04 detik)
Jadi hanya jika Anda berencana untuk memasukkan beberapa item dan Anda juga di suatu tempat memiliki referensi di mana Anda berencana untuk memasukkan item kemudian gunakan daftar tertaut. Hanya karena Anda harus memasukkan banyak item, itu tidak membuatnya lebih cepat karena mencari lokasi di mana Anda ingin memasukkannya membutuhkan waktu.
sumber
list.AddLast(a);
dalam dua contoh LinkedList terakhir? Saya bisa melakukannya sekali sebelum loop, sepertilist.AddLast(new Temp(1,1,1,1));
di sebelah LinkedList terakhir, tapi sepertinya (bagi saya) seperti Anda menambahkan dua kali lebih banyak objek Temp di loop sendiri. (Dan ketika saya mengecek diri saya dengan aplikasi tes , tentu saja, dua kali lebih banyak di LinkedList.)I say never use a linkedList.
cacat karena posting Anda nanti mengungkapkan. Anda mungkin ingin mengeditnya. 2) Apa waktu Anda? Instansiasi, penambahan, dan pencacahan sekaligus dalam satu langkah? Kebanyakan, instantiasi dan enumerasi bukan hal yang dikhawatirkan oleh ppl, itu adalah langkah satu kali. Khususnya waktu memasukkan dan penambahan akan memberikan ide yang lebih baik. 3) Yang terpenting, Anda menambahkan lebih dari yang dibutuhkan ke daftar tertaut. Ini perbandingan yang salah. Menyebarkan gagasan yang salah tentang tertaut.Dalam kebanyakan kasus,
List<T>
ini lebih bermanfaat.LinkedList<T>
akan memiliki biaya lebih sedikit ketika menambahkan / menghapus item di tengah daftar, sedangkanList<T>
hanya dapat menambahkan / menghapus dengan murah di akhir daftar.LinkedList<T>
hanya itu yang paling efisien jika Anda mengakses data berurutan (baik maju atau mundur) - akses acak relatif mahal karena harus berjalan di rantai setiap kali (karenanya mengapa tidak memiliki pengindeks). Namun, karena aList<T>
pada dasarnya hanyalah sebuah array (dengan pembungkus) akses acak baik-baik saja.List<T>
juga menawarkan banyak metode dukungan -Find
,ToArray
, dll; Namun, ini juga tersedia untukLinkedList<T>
dengan .NET 3.5 / C # 3.0 melalui metode ekstensi - sehingga kurang dari faktor.sumber
List<T>
danT[]
akan gagal karena terlalu chunky (semua satu slab),LinkedList<T>
akan meratap karena terlalu granular (slab per elemen).Memikirkan daftar tertaut sebagai daftar bisa sedikit menyesatkan. Ini lebih seperti sebuah rantai. Bahkan, dalam. NET,
LinkedList<T>
bahkan tidak diimplementasikanIList<T>
. Tidak ada konsep indeks yang nyata dalam daftar tertaut, meskipun tampaknya ada. Tentu saja tidak ada metode yang disediakan di kelas menerima indeks.Daftar tertaut dapat ditautkan secara tunggal, atau ditautkan secara ganda. Ini mengacu pada apakah setiap elemen dalam rantai hanya memiliki tautan ke yang berikutnya (ditautkan sendiri) atau ke kedua elemen sebelumnya / berikutnya (ditautkan dua kali).
LinkedList<T>
terkait dua kali lipat.Secara internal,
List<T>
didukung oleh sebuah array. Ini memberikan representasi yang sangat kompak dalam memori. Sebaliknya,LinkedList<T>
melibatkan memori tambahan untuk menyimpan tautan dua arah antara elemen yang berurutan. Jadi jejak memori aLinkedList<T>
umumnya akan lebih besar daripada untukList<T>
(dengan peringatan yangList<T>
dapat memiliki elemen array internal yang tidak digunakan untuk meningkatkan kinerja selama operasi penambahan.)Mereka memiliki karakteristik kinerja yang berbeda juga:
Menambahkan
LinkedList<T>.AddLast(item)
waktu yang konstanList<T>.Add(item)
waktu konstan diamortisasi, kasus terburuk linierTergantung
LinkedList<T>.AddFirst(item)
waktu yang konstanList<T>.Insert(0, item)
waktu linierInsersi
LinkedList<T>.AddBefore(node, item)
waktu yang konstanLinkedList<T>.AddAfter(node, item)
waktu yang konstanList<T>.Insert(index, item)
waktu linierPemindahan
LinkedList<T>.Remove(item)
waktu linierLinkedList<T>.Remove(node)
waktu yang konstanList<T>.Remove(item)
waktu linierList<T>.RemoveAt(index)
waktu linierMenghitung
LinkedList<T>.Count
waktu yang konstanList<T>.Count
waktu yang konstanMengandung
LinkedList<T>.Contains(item)
waktu linierList<T>.Contains(item)
waktu linierBersih
LinkedList<T>.Clear()
waktu linierList<T>.Clear()
waktu linierSeperti yang Anda lihat, mereka kebanyakan setara. Dalam praktiknya, API dari
LinkedList<T>
lebih rumit untuk digunakan, dan rincian kebutuhan internalnya mencurahkan ke dalam kode Anda.Namun, jika Anda perlu melakukan banyak penyisipan / pemindahan dari dalam daftar, ia menawarkan waktu yang konstan.
List<T>
menawarkan waktu linier, karena item tambahan dalam daftar harus dikocok setelah penyisipan / penghapusan.sumber
Daftar tertaut menyediakan penyisipan atau penghapusan anggota daftar yang sangat cepat. Setiap anggota dalam daftar tertaut berisi pointer ke anggota berikutnya dalam daftar sehingga untuk memasukkan anggota pada posisi i:
Kerugian dari daftar tertaut adalah akses acak tidak dimungkinkan. Mengakses anggota memerlukan melintasi daftar sampai anggota yang diinginkan ditemukan.
sumber
Jawaban saya sebelumnya tidak cukup akurat. Benar-benar mengerikan: D Tetapi sekarang saya dapat memposting jawaban yang jauh lebih berguna dan benar.
Saya melakukan beberapa tes tambahan. Anda dapat menemukan sumbernya dengan tautan berikut dan periksa kembali di lingkungan Anda sendiri: https://github.com/ukushu/DataStructuresTestsAndOther.git
Hasil singkat:
Array perlu digunakan:
Daftar harus digunakan:
LinkedList perlu menggunakan:
Keterangan lebih lanjut:
Menarik untuk diketahui:
LinkedList<T>
secara internal bukan Daftar di .NET. Itu bahkan tidak diimplementasikanIList<T>
. Dan itu sebabnya ada indeks dan metode yang tidak ada terkait dengan indeks.LinkedList<T>
adalah koleksi berbasis simpul-pointer. Dalam. NET itu dalam implementasi terkait dua kali lipat. Ini berarti bahwa elemen sebelum / berikutnya memiliki tautan ke elemen saat ini. Dan data terfragmentasi - objek daftar yang berbeda dapat ditemukan di berbagai tempat RAM. Juga akan ada lebih banyak memori yang digunakanLinkedList<T>
daripada untukList<T>
atau Array.List<T>
di .Net adalah alternatif Java dariArrayList<T>
. Ini berarti bahwa ini adalah pembungkus array. Jadi itu dialokasikan dalam memori sebagai satu blok data yang berdekatan. Jika ukuran data yang dialokasikan melebihi 85000 byte, itu akan dipindahkan ke Tumpukan Objek Besar. Tergantung pada ukuran, ini dapat menyebabkan tumpukan tumpukan (bentuk kebocoran memori ringan). Tetapi dalam waktu yang sama jika ukuran <85000 byte - ini memberikan representasi yang sangat ringkas dan akses cepat dalam memori.Blok bersebelahan tunggal lebih disukai untuk kinerja akses acak dan konsumsi memori tetapi untuk koleksi yang perlu mengubah ukuran secara teratur struktur seperti Array umumnya perlu disalin ke lokasi baru sedangkan daftar tertaut hanya perlu mengelola memori untuk yang baru dimasukkan / menghapus node.
sumber
Perbedaan antara Daftar dan LinkedList terletak pada implementasi yang mendasarinya. Daftar adalah koleksi berbasis array (ArrayList). LinkedList adalah koleksi berbasis simpul-pointer (LinkedListNode). Pada penggunaan level API, keduanya hampir sama karena keduanya mengimplementasikan set antarmuka yang sama seperti ICollection, IEnumerable, dll.
Perbedaan utama muncul ketika masalah kinerja. Misalnya, jika Anda menerapkan daftar yang memiliki operasi "INSERT" berat, LinkedList mengungguli Daftar. Karena LinkedList dapat melakukannya dalam waktu O (1), tetapi Daftar mungkin perlu memperluas ukuran array yang mendasarinya. Untuk informasi lebih lanjut / detail Anda mungkin ingin membaca tentang perbedaan algoritmik antara LinkedList dan struktur data array. http://en.wikipedia.org/wiki/Linked_list dan Array
Semoga bantuan ini,
sumber
Add
selalu di akhir array yang ada.List
"cukup baik" dalam hal itu, bahkan jika bukan O (1). Masalah serius terjadi jika Anda membutuhkan banyakAdd
yang tidak pada akhirnya. Marc menunjukkan bahwa kebutuhan untuk memindahkan data yang ada setiap kali Anda memasukkan (bukan hanya ketika ukuran diperlukan) adalah biaya kinerja yang lebih besarList
.Keuntungan utama daftar yang ditautkan daripada array adalah bahwa tautan tersebut memberi kami kemampuan untuk mengatur ulang item secara efisien. Sedgewick, hlm. 91
sumber
Keadaan umum untuk menggunakan LinkedList adalah seperti ini:
Misalkan Anda ingin menghapus banyak string tertentu dari daftar string dengan ukuran besar, katakanlah 100.000. String yang akan dihapus dapat dicari di HashSet dic, dan daftar string diyakini mengandung antara 30.000 hingga 60.000 string yang harus dihapus.
Lalu apa jenis Daftar terbaik untuk menyimpan 100.000 Strings? Jawabannya adalah LinkedList. Jika mereka disimpan dalam ArrayList, maka iterasi di atasnya dan menghapus Strings yang cocok akan membutuhkan milyaran operasi, sementara itu hanya membutuhkan sekitar 100.000 operasi dengan menggunakan iterator dan metode remove ().
sumber
RemoveAll
untuk menghapus item dariList
tanpa memindahkan banyak item di sekitar, atau gunakanWhere
dari LINQ untuk membuat daftar kedua. MenggunakanLinkedList
sini namun akhirnya memakan dramatis memori lebih dari jenis lain dari koleksi dan hilangnya berarti memori lokalitas bahwa hal itu akan terasa lebih lambat untuk iterate, sehingga cukup sedikit lebih buruk daripadaList
.RemoveAll
setara di Jawa.RemoveAll
tidak tersedia untukList
, Anda bisa melakukan algoritma "pemadatan", yang akan terlihat seperti loop Tom, tetapi dengan dua indeks dan kebutuhan untuk memindahkan item agar disimpan satu per satu di array internal daftar. Efisiensi adalah O (n), sama dengan algoritma Tom untukLinkedList
. Di kedua versi, waktu untuk menghitung kunci HashSet untuk string mendominasi. Ini bukan contoh yang baik kapan harus digunakanLinkedList
.Ketika Anda membutuhkan akses indeks bawaan, pengurutan (dan setelah pencarian biner ini), dan metode "ToArray ()", Anda harus menggunakan Daftar.
sumber
Pada dasarnya,
List<>
dalam. NET adalah pembungkus array . ALinkedList<>
adalah daftar tertaut . Jadi pertanyaannya adalah, apa perbedaan antara array dan daftar yang ditautkan, dan kapan seharusnya sebuah array digunakan daripada daftar yang ditautkan. Mungkin dua faktor terpenting dalam keputusan Anda yang akan digunakan adalah:sumber
Ini diadaptasi dari jawaban yang diterima Tono Nam yang mengoreksi beberapa pengukuran yang salah di dalamnya.
Ujian:
Dan kodenya:
Anda dapat melihat hasilnya sesuai dengan kinerja teoritis yang telah didokumentasikan orang lain di sini. Cukup jelas -
LinkedList<T>
mendapatkan waktu besar jika dimasukkan. Saya belum menguji penghapusan dari bagian tengah daftar, tetapi hasilnya harus sama. Tentu sajaList<T>
memiliki area lain di mana ia berkinerja lebih baik seperti O (1) akses acak.sumber
Gunakan
LinkedList<>
kapanToken Stream
,.Untuk yang lainnya, lebih baik digunakan
List<>
.sumber
LinkedListNode<T>
objek dalam kode Anda. Jika Anda bisa melakukannya, maka itu jauh lebih baik daripada menggunakanList<T>
, terutama untuk daftar yang sangat panjang di mana memasukkan / menghilangkan sering.node.Value
kapan pun Anda menginginkan elemen aslinya). Jadi Anda menulis ulang algoritma untuk bekerja dengan node, bukan nilai mentah.Saya setuju dengan sebagian besar poin di atas. Dan saya juga setuju bahwa Daftar terlihat seperti pilihan yang lebih jelas dalam sebagian besar kasus.
Tapi, saya hanya ingin menambahkan bahwa ada banyak contoh di mana LinkedList adalah pilihan yang jauh lebih baik daripada Daftar untuk efisiensi yang lebih baik.
Semoga seseorang akan menemukan komentar ini bermanfaat.
sumber
Begitu banyak jawaban rata-rata di sini ...
Beberapa implementasi daftar tertaut menggunakan blok yang mendasari node yang dialokasikan sebelumnya. Jika mereka tidak melakukan ini daripada waktu konstan / waktu linier kurang relevan karena kinerja memori akan buruk dan kinerja cache lebih buruk.
Gunakan daftar tertaut saat
1) Anda menginginkan keamanan utas. Anda dapat membangun algo yang lebih aman. Biaya penguncian akan mendominasi daftar gaya bersamaan.
2) Jika Anda memiliki struktur seperti antrian besar dan ingin menghapus atau menambahkan di mana saja tetapi akhirnya sepanjang waktu. > Daftar 100K ada tetapi tidak umum.
sumber
Saya mengajukan pertanyaan serupa terkait dengan kinerja koleksi LinkedList , dan menemukan penerapan Cque karya Steven Cleary dari Deque adalah solusinya. Berbeda dengan koleksi Antrian, Deque memungkinkan barang bergerak on / off depan dan belakang. Ini mirip dengan daftar tertaut, tetapi dengan peningkatan kinerja.
sumber
Deque
adalah "mirip dengan linked list, tetapi dengan peningkatan kinerja" . Harap masukkan pernyataan itu:Deque
lebih baik daripadaLinkedList
, untuk kode spesifik Anda . Mengikuti tautan Anda, saya melihat bahwa dua hari kemudian Anda mengetahui dari Ivan Stoev bahwa ini bukan inefisiensi dari LinkedList, tetapi inefisiensi dalam kode Anda. (Dan bahkan jika itu merupakan inefisiensi dari LinkedList, itu tidak akan membenarkan pernyataan umum bahwa Deque lebih efisien; hanya dalam kasus-kasus tertentu.)