เมื่อมันจะดีกว่าที่จะใช้รายการเอสLinkedList ?
เมื่อมันจะดีกว่าที่จะใช้รายการเอสLinkedList ?
คำตอบ:
โปรดอ่านความคิดเห็นต่อคำตอบนี้ ผู้คนอ้างว่าฉันไม่ได้ทำการทดสอบที่เหมาะสม ฉันเห็นด้วยว่าสิ่งนี้ไม่ควรเป็นคำตอบที่ยอมรับได้ ขณะที่ฉันเรียนรู้ฉันได้ทำการทดสอบและรู้สึกอยากแบ่งปัน
ฉันพบผลลัพธ์ที่น่าสนใจ:
// Temporary class to show the example
class Temp
{
public decimal A, B, C, D;
public Temp(decimal a, decimal b, decimal c, decimal d)
{
A = a; B = b; C = c; D = d;
}
}
LinkedList<Temp> list = new LinkedList<Temp>();
for (var i = 0; i < 12345678; i++)
{
var a = new Temp(i, i, i, i);
list.AddLast(a);
}
decimal sum = 0;
foreach (var item in list)
sum += item.A;
List<Temp> list = new List<Temp>(); // 2.4 seconds
for (var i = 0; i < 12345678; i++)
{
var a = new Temp(i, i, i, i);
list.Add(a);
}
decimal sum = 0;
foreach (var item in list)
sum += item.A;
แม้ว่าคุณจะเข้าถึงข้อมูลเป็นหลักมันช้ากว่ามาก !! ฉันบอกว่าไม่เคยใช้รายการที่ลิงก์
ต่อไปนี้เป็นการเปรียบเทียบการทำงานของเม็ดมีดจำนวนมาก (เราวางแผนที่จะแทรกรายการที่ตรงกลางของรายการ)
LinkedList<Temp> list = new LinkedList<Temp>();
for (var i = 0; i < 123456; i++)
{
var a = new Temp(i, i, i, i);
list.AddLast(a);
var curNode = list.First;
for (var k = 0; k < i/2; k++) // In order to insert a node at the middle of the list we need to find it
curNode = curNode.Next;
list.AddAfter(curNode, a); // Insert it after
}
decimal sum = 0;
foreach (var item in list)
sum += item.A;
List<Temp> list = new List<Temp>();
for (var i = 0; i < 123456; i++)
{
var a = new Temp(i, i, i, i);
list.Insert(i / 2, a);
}
decimal sum = 0;
foreach (var item in list)
sum += item.A;
list.AddLast(new Temp(1,1,1,1));
var referenceNode = list.First;
for (var i = 0; i < 123456; i++)
{
var a = new Temp(i, i, i, i);
list.AddLast(a);
list.AddBefore(referenceNode, a);
}
decimal sum = 0;
foreach (var item in list)
sum += item.A;
ดังนั้นหากคุณวางแผนที่จะแทรกหลายรายการและคุณยังมีที่อ้างอิงที่คุณวางแผนแทรกรายการจากนั้นใช้รายการที่เชื่อมโยง เพียงเพราะคุณต้องแทรกรายการจำนวนมากมันไม่ได้ทำให้เร็วขึ้นเพราะการค้นหาตำแหน่งที่คุณต้องการแทรกต้องใช้เวลา
list.AddLast(a);
ในสองตัวอย่าง LinkedList ล่าสุด ฉันจะทำมันก่อนที่จะวนรอบเช่นเดียวกับlist.AddLast(new Temp(1,1,1,1));
ในถัดจาก LinkedList ที่ผ่านมา แต่ดูเหมือน (กับฉัน) เช่นคุณกำลังเพิ่มสองวัตถุ Temp มากในลูปตัวเอง (และเมื่อฉันตรวจสอบตัวเองอีกครั้งด้วยแอปทดสอบแน่นอนว่ามีมากเป็นสองเท่าในรายการที่
I say never use a linkedList.
มีข้อบกพร่องตามที่คุณโพสต์ในภายหลังเผยให้เห็น คุณอาจต้องการแก้ไข 2) คุณจับเวลาอะไร การเริ่มต้นการเพิ่มและการนับรวมเข้าด้วยกันในขั้นตอนเดียว ส่วนใหญ่การสร้างอินสแตนซ์และการแจงนับไม่ใช่สิ่งที่ ppl กังวลเกี่ยวกับสิ่งเหล่านี้เป็นขั้นตอนเดียว กำหนดเวลาการแทรกและส่วนเพิ่มเติมโดยเฉพาะจะให้แนวคิดที่ดีกว่า 3) ที่สำคัญที่สุดคือคุณกำลังเพิ่มมากกว่าที่จำเป็นในรายการที่เชื่อมโยง นี่เป็นการเปรียบเทียบที่ผิด เผยแพร่แนวคิดที่ผิดเกี่ยวกับลิสต์ที่ลิงก์
ในกรณีส่วนใหญ่List<T>
มีประโยชน์มากกว่า LinkedList<T>
จะมีค่าใช้จ่ายน้อยลงเมื่อเพิ่ม / ลบรายการที่อยู่ตรงกลางของรายการในขณะที่List<T>
สามารถเพิ่ม / ลบรายการที่ถูกที่สุดในตอนท้ายของรายการเท่านั้น
LinkedList<T>
จะมีประสิทธิภาพที่สุดก็ต่อเมื่อคุณกำลังเข้าถึงข้อมูลตามลำดับ (ไปข้างหน้าหรือข้างหลัง) - การเข้าถึงแบบสุ่มค่อนข้างแพงเนื่องจากจะต้องเดินผ่านสายโซ่ในแต่ละครั้ง (เหตุใดจึงไม่มีดัชนี) อย่างไรก็ตามเนื่องจาก a List<T>
เป็นหลักเพียงแค่การเข้าถึงแบบสุ่ม (ด้วย wrapper) เป็นเรื่องปกติ
List<T>
นอกจากนี้ยังมีจำนวนมากวิธีการสนับสนุน - Find
, ToArray
ฯลฯ ; อย่างไรก็ตามสิ่งเหล่านี้สามารถใช้ได้LinkedList<T>
กับ. NET 3.5 / C # 3.0 ผ่านวิธีการขยาย - ดังนั้นจึงมีปัจจัยน้อยกว่า
List<T>
และT[]
จะล้มเหลวในการเป็นก้อน (แผ่นเดียวทั้งหมด) LinkedList<T>
จะครวญครางเพราะละเอียดเกินไป (แผ่นต่อองค์ประกอบ)
การคิดถึงรายการที่เชื่อมโยงเป็นรายการอาจทำให้เข้าใจผิดเล็กน้อย มันเหมือนโซ่มากกว่า ในความเป็นจริงใน. NET LinkedList<T>
ไม่ได้ใช้IList<T>
ไม่ได้ดำเนินการไม่มีแนวคิดที่แท้จริงของดัชนีในรายการที่เชื่อมโยงแม้ว่ามันอาจดูเหมือนว่ามี แน่นอนว่าไม่มีวิธีการใด ๆ ในชั้นเรียนที่ยอมรับดัชนี
รายการที่เชื่อมโยงอาจถูกลิงค์โดยลำพังหรือเชื่อมโยงซ้ำ สิ่งนี้หมายถึงว่าแต่ละองค์ประกอบในกลุ่มนี้มีลิงก์ไปยังองค์ประกอบถัดไปเท่านั้น (เชื่อมโยงโดยลำพัง) หรือทั้งสององค์ประกอบก่อนหน้า / ถัดไป (ลิงก์สองเท่า) LinkedList<T>
มีการเชื่อมโยงทวีคูณ
ภายในList<T>
ได้รับการสนับสนุนโดยอาเรย์ นี่เป็นการนำเสนอที่มีขนาดกะทัดรัดมากในหน่วยความจำ ตรงกันข้ามLinkedList<T>
เกี่ยวข้องกับหน่วยความจำเพิ่มเติมเพื่อจัดเก็บลิงค์แบบสองทิศทางระหว่างองค์ประกอบต่อเนื่อง ดังนั้นLinkedList<T>
โดยทั่วไปรอยความทรงจำของ a จะใหญ่กว่าList<T>
(ด้วยข้อแม้ที่List<T>
สามารถมีองค์ประกอบอาร์เรย์ภายในที่ไม่ได้ใช้เพื่อปรับปรุงประสิทธิภาพในระหว่างการดำเนินการต่อท้าย)
พวกมันมีคุณสมบัติด้านประสิทธิภาพที่แตกต่างเช่นกัน:
LinkedList<T>.AddLast(item)
เวลาคงที่List<T>.Add(item)
เวลาคงที่ตัดจำหน่ายกรณีเชิงเส้นที่เลวร้ายที่สุดLinkedList<T>.AddFirst(item)
เวลาคงที่List<T>.Insert(0, item)
เวลาเชิงเส้นLinkedList<T>.AddBefore(node, item)
เวลาคงที่LinkedList<T>.AddAfter(node, item)
เวลาคงที่List<T>.Insert(index, item)
เวลาเชิงเส้นLinkedList<T>.Remove(item)
เวลาเชิงเส้นLinkedList<T>.Remove(node)
เวลาคงที่List<T>.Remove(item)
เวลาเชิงเส้นList<T>.RemoveAt(index)
เวลาเชิงเส้นLinkedList<T>.Count
เวลาคงที่List<T>.Count
เวลาคงที่LinkedList<T>.Contains(item)
เวลาเชิงเส้นList<T>.Contains(item)
เวลาเชิงเส้นLinkedList<T>.Clear()
เวลาเชิงเส้นList<T>.Clear()
เวลาเชิงเส้นอย่างที่คุณเห็นพวกมันส่วนใหญ่จะเทียบเท่ากัน ในทางปฏิบัติ API ของLinkedList<T>
นั้นยุ่งยากกว่าการใช้งานและรายละเอียดของความต้องการภายในรั่วไหลออกมาเป็นรหัสของคุณ
อย่างไรก็ตามหากคุณต้องการแทรก / ลบหลายรายการจากภายในรายการจะมีเวลาคงที่ List<T>
เสนอเวลาเชิงเส้นเนื่องจากรายการพิเศษในรายการจะต้องถูกสับหลังจากการแทรก / กำจัด
รายการที่เชื่อมโยงให้การแทรกหรือลบรายการสมาชิกอย่างรวดเร็ว สมาชิกแต่ละคนในรายการที่เชื่อมโยงประกอบด้วยตัวชี้ไปยังสมาชิกถัดไปในรายการเพื่อแทรกสมาชิกที่ตำแหน่ง i:
ข้อเสียของรายการที่เชื่อมโยงคือการเข้าถึงแบบสุ่มไม่สามารถทำได้ การเข้าถึงสมาชิกต้องผ่านรายการจนกว่าจะพบสมาชิกที่ต้องการ
คำตอบก่อนหน้าของฉันไม่ถูกต้องเพียงพอ มันน่ากลัวจริงๆ: D แต่ตอนนี้ฉันสามารถโพสต์คำตอบที่มีประโยชน์และถูกต้องได้มากขึ้น
ฉันทำการทดสอบเพิ่มเติม คุณสามารถค้นหาแหล่งที่มาได้จากลิงค์ต่อไปนี้และตรวจสอบอีกครั้งในสภาพแวดล้อมของคุณด้วยตัวคุณเอง: https://github.com/ukushu/DataStructuresTestsAndOther.git
ผลสรุป:
อาร์เรย์ต้องใช้:
รายการจำเป็นต้องใช้:
LinkedList ต้องใช้:
รายละเอียดเพิ่มเติม:
LinkedList<T>
ภายในไม่ใช่รายการใน. NET IList<T>
ก็จะยิ่งไม่ใช้ และนั่นเป็นสาเหตุที่มีดัชนีขาดและวิธีการที่เกี่ยวข้องกับดัชนี
LinkedList<T>
คือการรวบรวมตามโหนด ใน. NET มันมีการเชื่อมโยงการใช้งานทวีคูณ ซึ่งหมายความว่าองค์ประกอบก่อนหน้า / ถัดไปมีลิงก์ไปยังองค์ประกอบปัจจุบัน และข้อมูลมีการแยกส่วน - วัตถุรายการที่แตกต่างสามารถอยู่ในตำแหน่งที่แตกต่างกันของ RAM นอกจากนี้จะมีหน่วยความจำมากกว่าที่ใช้LinkedList<T>
สำหรับList<T>
หรืออาร์เรย์
List<T>
ในสุทธิเป็นทางเลือกของ Java ArrayList<T>
ของ นี่หมายความว่านี่คืออาร์คเกอร์แรปเปอร์ ดังนั้นมันจึงถูกจัดสรรในหน่วยความจำให้เป็นหนึ่งบล็อกข้อมูลที่ต่อเนื่องกัน หากขนาดข้อมูลที่จัดสรรเกิน 85,000 ไบต์จะถูกย้ายไปที่ Large Object Heap ขึ้นอยู่กับขนาดสิ่งนี้สามารถนำไปสู่การแตกแฟรกเมนต์ของฮีป (แบบหน่วยความจำรั่วเล็กน้อย) แต่ในเวลาเดียวกันถ้าขนาด <85000 ไบต์ - นี่เป็นการนำเสนอขนาดกะทัดรัดและการเข้าถึงที่รวดเร็วในหน่วยความจำ
Single block ที่ต่อเนื่องกันเป็นที่ต้องการสำหรับการเข้าถึงแบบสุ่มและการใช้หน่วยความจำ แต่สำหรับคอลเลกชันที่ต้องเปลี่ยนขนาดเป็นประจำโครงสร้างเช่น Array โดยทั่วไปจะต้องคัดลอกไปยังตำแหน่งใหม่ในขณะที่รายการที่เชื่อมโยงจะต้องจัดการหน่วยความจำ / ลบโหนด
ความแตกต่างระหว่างรายการและรายการที่เชื่อมโยงอยู่ในการนำไปปฏิบัติ List คือการรวบรวมตามอาเรย์ (ArrayList) LinkedList เป็นคอลเล็กชันที่ใช้ตัวชี้โหนด (LinkedListNode) ในการใช้ระดับ API ทั้งคู่มีความเหมือนกันมากเนื่องจากทั้งคู่ใช้อินเทอร์เฟซชุดเดียวกันเช่น ICollection, IEnumerable เป็นต้น
ความแตกต่างที่สำคัญเกิดขึ้นเมื่อประสิทธิภาพมีความสำคัญ ตัวอย่างเช่นหากคุณกำลังใช้งานรายการที่มีการดำเนินการ "INSERT" จำนวนมาก LinkedList จะมีประสิทธิภาพสูงกว่ารายการ เนื่องจาก LinkedList สามารถทำได้ในเวลา O (1) แต่ List อาจต้องขยายขนาดของอาเรย์พื้นฐาน สำหรับข้อมูลเพิ่มเติม / รายละเอียดคุณอาจต้องการอ่านความแตกต่างของอัลกอริทึมระหว่าง LinkedList และโครงสร้างข้อมูลอาร์เรย์ http://en.wikipedia.org/wiki/Linked_list and Array
หวังว่าจะช่วยได้
Add
อยู่ในตอนท้ายของอาร์เรย์ที่มีอยู่เสมอ List
เป็น "ดีพอ" ที่ถึงแม้ว่าจะไม่ใช่ O (1) ปัญหาร้ายแรงเกิดขึ้นถ้าคุณต้องการหลายคนAdd
ที่ยังไม่จบ Marc ชี้ให้เห็นว่าความต้องการย้ายข้อมูลที่มีอยู่ทุกครั้งที่คุณแทรก (ไม่ใช่เพียงเมื่อจำเป็นต้องปรับขนาด) เป็นต้นทุนประสิทธิภาพที่สำคัญList
กว่า
ข้อได้เปรียบหลักของรายการที่ถูกเชื่อมโยงผ่านอาร์เรย์คือการเชื่อมโยงช่วยให้เราสามารถจัดเรียงรายการได้อย่างมีประสิทธิภาพ เซดจ์วิคพี 91
สถานการณ์ทั่วไปในการใช้ LinkedList เป็นดังนี้:
สมมติว่าคุณต้องการลบสตริงจำนวนมากออกจากรายการสตริงที่มีขนาดใหญ่ให้พูด 100,000 สตริงที่จะลบสามารถค้นหาได้ใน HashSet dic และเชื่อว่ารายการของสตริงนั้นมีอยู่ระหว่าง 30,000 ถึง 60,000 สตริงที่จะลบ
รายการประเภทที่ดีที่สุดสำหรับการจัดเก็บ 100,000 สายคืออะไร คำตอบคือ LinkedList หากพวกมันถูกเก็บไว้ใน ArrayList ให้ทำการวนซ้ำและกำจัด Strings ที่จับคู่กันซึ่งต้องใช้เวลาถึงหลายพันล้านการดำเนินการในขณะที่ใช้เพียง 100,000 การดำเนินการโดยใช้ iterator และ remove ()
LinkedList<String> strings = readStrings();
HashSet<String> dic = readDic();
Iterator<String> iterator = strings.iterator();
while (iterator.hasNext()){
String string = iterator.next();
if (dic.contains(string))
iterator.remove();
}
RemoveAll
เพื่อลบรายการออกจาก a List
โดยไม่ต้องย้ายรายการจำนวนมากหรือใช้Where
จาก LINQ เพื่อสร้างรายการที่สอง การใช้LinkedList
ที่นี่ แต่จบลงด้วยการบริโภคอย่างมากหน่วยความจำมากกว่าชนิดอื่น ๆ List
ของคอลเลกชันและการสูญเสียของหน่วยความจำท้องถิ่นหมายถึงว่ามันจะเห็นได้ชัดช้าย้ำทำให้มันค่อนข้างเลวร้ายยิ่งกว่า
RemoveAll
Java ที่เทียบเท่าหรือไม่
RemoveAll
ไม่มีให้ใช้List
คุณสามารถใช้อัลกอริทึม "การบดอัด" ซึ่งมีลักษณะคล้ายกับลูปของทอม แต่มีดัชนีสองตัวและต้องการย้ายไอเท็มเพื่อที่จะเก็บทีละรายการในอาร์เรย์ภายในของรายการ ประสิทธิภาพเป็น O (n) LinkedList
เช่นเดียวกับอัลกอริทึมสำหรับทอม ในทั้งสองเวอร์ชันเวลาในการคำนวณคีย์ HashSet สำหรับสตริงจะมีผล นี่ไม่ใช่ตัวอย่างที่ดีว่าควรใช้เมื่อLinkedList
ใด
เมื่อคุณต้องการการเข้าถึงการจัดทำดัชนีในตัวการเรียงลำดับ (และหลังจากการค้นหาแบบไบนารีนี้) และ "ToArray ()" วิธีการคุณควรใช้รายการ
โดยพื้นฐานแล้ว a List<>
ใน. NET คือ wrapper ทับอาเรย์ เป็นรายการที่เชื่อมโยงLinkedList<>
ดังนั้นคำถามที่เกิดขึ้นคือความแตกต่างระหว่างอาเรย์และรายการที่เชื่อมโยงคืออะไรและเมื่อใดควรใช้อาเรย์แทนที่จะเป็นรายการที่เชื่อมโยงกัน อาจเป็นสองปัจจัยที่สำคัญที่สุดในการตัดสินใจที่จะใช้ของคุณ:
สิ่งนี้ดัดแปลงมาจากTono Namคำตอบที่ยอมรับของแก้ไขการวัดที่ผิดเล็กน้อย
การทดสอบ:
static void Main()
{
LinkedListPerformance.AddFirst_List(); // 12028 ms
LinkedListPerformance.AddFirst_LinkedList(); // 33 ms
LinkedListPerformance.AddLast_List(); // 33 ms
LinkedListPerformance.AddLast_LinkedList(); // 32 ms
LinkedListPerformance.Enumerate_List(); // 1.08 ms
LinkedListPerformance.Enumerate_LinkedList(); // 3.4 ms
//I tried below as fun exercise - not very meaningful, see code
//sort of equivalent to insertion when having the reference to middle node
LinkedListPerformance.AddMiddle_List(); // 5724 ms
LinkedListPerformance.AddMiddle_LinkedList1(); // 36 ms
LinkedListPerformance.AddMiddle_LinkedList2(); // 32 ms
LinkedListPerformance.AddMiddle_LinkedList3(); // 454 ms
Environment.Exit(-1);
}
และรหัส:
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace stackoverflow
{
static class LinkedListPerformance
{
class Temp
{
public decimal A, B, C, D;
public Temp(decimal a, decimal b, decimal c, decimal d)
{
A = a; B = b; C = c; D = d;
}
}
static readonly int start = 0;
static readonly int end = 123456;
static readonly IEnumerable<Temp> query = Enumerable.Range(start, end - start).Select(temp);
static Temp temp(int i)
{
return new Temp(i, i, i, i);
}
static void StopAndPrint(this Stopwatch watch)
{
watch.Stop();
Console.WriteLine(watch.Elapsed.TotalMilliseconds);
}
public static void AddFirst_List()
{
var list = new List<Temp>();
var watch = Stopwatch.StartNew();
for (var i = start; i < end; i++)
list.Insert(0, temp(i));
watch.StopAndPrint();
}
public static void AddFirst_LinkedList()
{
var list = new LinkedList<Temp>();
var watch = Stopwatch.StartNew();
for (int i = start; i < end; i++)
list.AddFirst(temp(i));
watch.StopAndPrint();
}
public static void AddLast_List()
{
var list = new List<Temp>();
var watch = Stopwatch.StartNew();
for (var i = start; i < end; i++)
list.Add(temp(i));
watch.StopAndPrint();
}
public static void AddLast_LinkedList()
{
var list = new LinkedList<Temp>();
var watch = Stopwatch.StartNew();
for (int i = start; i < end; i++)
list.AddLast(temp(i));
watch.StopAndPrint();
}
public static void Enumerate_List()
{
var list = new List<Temp>(query);
var watch = Stopwatch.StartNew();
foreach (var item in list)
{
}
watch.StopAndPrint();
}
public static void Enumerate_LinkedList()
{
var list = new LinkedList<Temp>(query);
var watch = Stopwatch.StartNew();
foreach (var item in list)
{
}
watch.StopAndPrint();
}
//for the fun of it, I tried to time inserting to the middle of
//linked list - this is by no means a realistic scenario! or may be
//these make sense if you assume you have the reference to middle node
//insertion to the middle of list
public static void AddMiddle_List()
{
var list = new List<Temp>();
var watch = Stopwatch.StartNew();
for (var i = start; i < end; i++)
list.Insert(list.Count / 2, temp(i));
watch.StopAndPrint();
}
//insertion in linked list in such a fashion that
//it has the same effect as inserting into the middle of list
public static void AddMiddle_LinkedList1()
{
var list = new LinkedList<Temp>();
var watch = Stopwatch.StartNew();
LinkedListNode<Temp> evenNode = null, oddNode = null;
for (int i = start; i < end; i++)
{
if (list.Count == 0)
oddNode = evenNode = list.AddLast(temp(i));
else
if (list.Count % 2 == 1)
oddNode = list.AddBefore(evenNode, temp(i));
else
evenNode = list.AddAfter(oddNode, temp(i));
}
watch.StopAndPrint();
}
//another hacky way
public static void AddMiddle_LinkedList2()
{
var list = new LinkedList<Temp>();
var watch = Stopwatch.StartNew();
for (var i = start + 1; i < end; i += 2)
list.AddLast(temp(i));
for (int i = end - 2; i >= 0; i -= 2)
list.AddLast(temp(i));
watch.StopAndPrint();
}
//OP's original more sensible approach, but I tried to filter out
//the intermediate iteration cost in finding the middle node.
public static void AddMiddle_LinkedList3()
{
var list = new LinkedList<Temp>();
var watch = Stopwatch.StartNew();
for (var i = start; i < end; i++)
{
if (list.Count == 0)
list.AddLast(temp(i));
else
{
watch.Stop();
var curNode = list.First;
for (var j = 0; j < list.Count / 2; j++)
curNode = curNode.Next;
watch.Start();
list.AddBefore(curNode, temp(i));
}
}
watch.StopAndPrint();
}
}
}
คุณสามารถดูผลลัพธ์ที่เป็นไปตามประสิทธิภาพทางทฤษฎีที่คนอื่นมีเอกสารไว้ที่นี่ ค่อนข้างชัดเจน - LinkedList<T>
ได้รับเวลามากในกรณีที่มีการแทรก ฉันไม่ได้ทดสอบเพื่อลบออกจากรายการกลาง แต่ผลลัพธ์ควรจะเหมือนกัน แน่นอนว่าList<T>
มีพื้นที่อื่น ๆ ที่มันทำงานได้ดีกว่าเช่นการเข้าถึงแบบสุ่ม O (1)
ใช้LinkedList<>
เมื่อ
Token Stream
.List<>
สำหรับทุกอย่างอื่นจะดีกว่าการใช้งาน
LinkedListNode<T>
วัตถุในรหัสของคุณ หากคุณสามารถทำสิ่งนั้นได้ดีกว่าการใช้List<T>
โดยเฉพาะอย่างยิ่งสำหรับรายการที่ยาวมากซึ่งมีการแทรก / ลบบ่อยครั้ง
node.Value
เมื่อใดก็ตามที่คุณต้องการองค์ประกอบดั้งเดิม) ดังนั้นคุณเขียนอัลกอริธึมใหม่เพื่อทำงานกับโหนดไม่ใช่ค่าดิบ
ฉันเห็นด้วยกับประเด็นส่วนใหญ่ที่กล่าวข้างต้น และฉันก็เห็นด้วยว่ารายการดูเหมือนจะเป็นตัวเลือกที่ชัดเจนกว่าในกรณีส่วนใหญ่
แต่ฉันแค่ต้องการเพิ่มว่ามีหลายตัวอย่างที่ LinkedList เป็นตัวเลือกที่ดีกว่า List เพื่อประสิทธิภาพที่ดีกว่า
หวังว่าบางคนจะเห็นความคิดเห็นเหล่านี้มีประโยชน์
คำตอบโดยเฉลี่ยมากมายที่นี่ ...
การประยุกต์ใช้รายการที่เชื่อมโยงบางรายการใช้บล็อกพื้นฐานของโหนดที่จัดสรรไว้ล่วงหน้า หากพวกเขาไม่ทำเช่นนี้มากกว่าเวลาคงที่ / เวลาเชิงเส้นมีความเกี่ยวข้องน้อยลงเนื่องจากประสิทธิภาพของหน่วยความจำจะไม่ดีและประสิทธิภาพแคชยิ่งแย่ลง
ใช้รายการที่ลิงก์เมื่อ
1) คุณต้องการความปลอดภัยของเธรด คุณสามารถสร้าง algos safe thread ได้ดีขึ้น ค่าใช้จ่ายในการล็อคจะครอบงำรายการสไตล์ที่เกิดขึ้นพร้อมกัน
2) หากคุณมีคิวขนาดใหญ่เช่นโครงสร้างและต้องการลบหรือเพิ่มที่ใดก็ได้ แต่จบลงตลอดเวลา > 100K รายการมีอยู่จริง แต่ไม่ใช่ว่าเป็นเรื่องปกติ
ฉันถามคำถามที่คล้ายกันที่เกี่ยวข้องกับประสิทธิภาพของการรวบรวม LinkedListและค้นพบการใช้ C # ของ Steven Cleary ใน Dequeเป็นวิธีแก้ปัญหา ซึ่งแตกต่างจากคอลเลกชันคิว Deque ช่วยให้การย้ายรายการเปิด / ปิดด้านหน้าและด้านหลัง มันคล้ายกับรายการที่เชื่อมโยง แต่มีการปรับปรุงประสิทธิภาพ
Deque
เป็น"คล้ายกับรายการที่เชื่อมโยง แต่มีประสิทธิภาพการทำงานที่ดีขึ้น" โปรดมีสิทธิ์คำว่า: Deque
คือประสิทธิภาพที่ดีกว่าLinkedList
, รหัสเฉพาะของคุณ ตามลิงค์ของคุณฉันเห็นว่าอีกสองวันต่อมาคุณเรียนรู้จาก Ivan Stoev ว่านี่ไม่ใช่การเชื่อมโยงที่ไม่มีประสิทธิภาพ แต่เป็นความไร้ประสิทธิภาพในรหัสของคุณ (และถึงแม้ว่ามันจะไม่มีประสิทธิภาพของ LinkedList ที่จะไม่ปรับงบทั่วไปว่า Deque มีประสิทธิภาพมากขึ้นเฉพาะในบางกรณีเท่านั้น)