SortedList <>, SortedDictionary <> และพจนานุกรม <>


104

ฉันพบSortedList<TKey, TValue> SortedDictionary<TKey, TValue>และDictionary<TKey, TValue>ใช้อินเทอร์เฟซเดียวกัน

  1. เมื่อไหร่ที่เราควรเลือกSortedListและทำSortedDictionaryซ้ำDictionary?
  2. อะไรคือความแตกต่างระหว่างSortedListและSortedDictionaryในแง่ของการใช้งาน?

คำตอบ:


102
  1. เมื่อทำซ้ำองค์ประกอบในสององค์ประกอบใดองค์ประกอบหนึ่งองค์ประกอบจะถูกจัดเรียง Dictionary<T,V>ไม่ให้มี

  2. MSDNกล่าวถึงความแตกต่างระหว่างSortedList<T,V>และSortedDictionary<T,V>:

คลาสทั่วไป SortedDictionary (TKey, TValue) เป็นต้นไม้ค้นหาแบบไบนารีที่มีการดึงข้อมูล O (log n) โดยที่ n คือจำนวนองค์ประกอบในพจนานุกรม ในแง่นี้จะคล้ายกับคลาสทั่วไปของ SortedList (TKey, TValue) ทั้งสองคลาสมีโมเดลอ็อบเจ็กต์ที่คล้ายกันและทั้งสองมีการดึงข้อมูล O (log n) โดยที่ทั้งสองคลาสแตกต่างกันคือการใช้หน่วยความจำและความเร็วในการแทรกและลบ:

SortedList (TKey, TValue) ใช้หน่วยความจำน้อยกว่า SortedDictionary (TKey, TValue)

SortedDictionary (TKey, TValue) มีการแทรกและการลบที่เร็วกว่าสำหรับข้อมูลที่ไม่ได้เรียงลำดับ: O (log n) เมื่อเทียบกับ O (n) สำหรับ SortedList (TKey, TValue)

หากมีการเติมรายการทั้งหมดในครั้งเดียวจากข้อมูลที่เรียงลำดับ SortedList (TKey, TValue) จะเร็วกว่า SortedDictionary (TKey, TValue)


21
ความแตกต่างในทางปฏิบัติอีกประการหนึ่งคือSortedListคุณสามารถดึงข้อมูลด้วยดัชนี (ซึ่งตรงข้ามกับการดึงด้วยคีย์) และในตัวSortedDictionaryคุณไม่สามารถ
Andrew Savinykh

67

ป้อนคำอธิบายภาพที่นี่

ฉันจะพูดถึงความแตกต่างระหว่างพจนานุกรม

ภาพด้านบนแสดงให้เห็นว่าDictionary<K,V>ทุกกรณีเท่ากันหรือเร็วกว่าSortedอนาล็อก แต่หากต้องการลำดับขององค์ประกอบเช่นเพื่อพิมพ์Sortedจะมีการเลือกอย่างใดอย่างหนึ่ง

Src: http://people.cs.aau.dk/~normark/oop-csharp/html/notes/collections-note-time-complexity-dictionaries.html


2
ภาพรวมที่ยอดเยี่ยม แม้ว่าจะไม่อยู่ในคำถามเดิม แต่ควรสังเกตว่าหากคุณเลือกระหว่างImmutableเวอร์ชันของพจนานุกรมเหล่านี้Sortedเวอร์ชันนั้นมักจะเร็วกว่าคู่ที่ไม่เรียงลำดับประมาณ 40-50% (ยังคงO(log(n))แต่เร็วกว่าอย่างเห็นได้ชัดต่อ op) . การกำหนดเวลาอาจแตกต่างกันไปขึ้นอยู่กับว่าอินพุตเรียงลำดับอย่างไร ดูstackoverflow.com/a/30638592/111575
Abel

22

ในการสรุปผลการทดสอบประสิทธิภาพ - SortedList เทียบกับ SortedDictionary เทียบกับพจนานุกรมเทียบกับ Hashtableผลลัพธ์จากดีที่สุดไปหาแย่ที่สุดสำหรับสถานการณ์ต่างๆ:

การใช้ความจำ:

SortedList<T,T>
Hashtable
SortedDictionary<T,T>
Dictionary<T,T>

แทรก:

Dictionary<T,T>
Hashtable
SortedDictionary<T,T>
SortedList<T,T>

ปฏิบัติการค้นหา:

Hashtable
Dictionary<T,T>
SortedList<T,T>
SortedDictionary<T,T>

foreach loop การดำเนินงาน

SortedList<T,T>
Dictionary<T,T>
Hashtable
SortedDictionary<T,T>

1
เมื่อตรวจสอบผลการทดสอบเหล่านี้เราสามารถตั้งคำถามเกี่ยวกับraison d'etreของ SortedDictionary
beawolf

1
หากCollectionความต้องการของคุณเป็นเช่นsortedนั้นคุณสามารถลืมHashtableและDictionary: หากคุณเติมคอลเลคชันของคุณในช็อตเดียว -> ไปที่ SortedList แต่ถ้าคุณคาดหวังไว้คุณมักจะต้อง.Addและ.Removeรายการ -> ไปสำหรับ SortedDictionary
อาม่า

บางทีอาจจำเป็นต้องชี้แจงว่าsortedหมายถึงอะไร: เมื่อคุณดำเนินการFor Each MyItem in Collectionแทนที่จะดำเนินการตามลำดับที่คุณ.Addแก้ไขรายการเดิม a sorted Collectionจะประมวลผลตามลำดับตามเกณฑ์ของKeyค่า (กำหนดไว้ในข้อIComparer) ตัวอย่างเช่นหากคีย์ของคุณเป็นสตริงคอลเลคชันของคุณจะถูกประมวลผลตามลำดับตัวอักษรของคีย์ของคุณโดยค่าเริ่มต้น แต่คุณสามารถกำหนดกฎการจัดเรียงแบบกำหนดเองได้ตลอดเวลา
อาม่า

10

ฉันเห็นว่าคำตอบที่เสนอนั้นมุ่งเน้นไปที่ประสิทธิภาพ บทความด้านล่างนี้ไม่ได้ให้ข้อมูลใหม่เกี่ยวกับประสิทธิภาพ แต่จะอธิบายถึงกลไกพื้นฐาน โปรดทราบว่ามันไม่ได้มุ่งเน้นไปที่สามCollectionประเภทที่กล่าวถึงในคำถาม แต่จะกล่าวถึงประเภททั้งหมดของSystem.Collections.Genericเนมสเปซ

http://geekswithblogs.net/BlackRabbitCoder/archive/2011/06/16/c.net-fundamentals-choosing-the-right-collection-class.aspx

สารสกัด:

พจนานุกรม <>

พจนานุกรมน่าจะเป็นคลาสคอนเทนเนอร์ที่ใช้ร่วมกันมากที่สุด พจนานุกรมเป็นชั้นที่เร็วที่สุดสำหรับการค้นหาเชื่อมโยง / แทรก / ลบเพราะมันใช้ตารางแฮชภายใต้ครอบคลุม เนื่องจากมีการแฮชคีย์ประเภทคีย์ควรใช้ GetHashCode () และ Equals () อย่างถูกต้องอย่างเหมาะสมหรือคุณควรให้ IEqualityComparer ภายนอกกับพจนานุกรมเกี่ยวกับโครงสร้าง เวลาแทรก / ลบ / ค้นหาของรายการในพจนานุกรมคือเวลาคงที่แบบตัดจำหน่าย - O (1) - ซึ่งหมายความว่าไม่ว่าพจนานุกรมจะใหญ่แค่ไหนก็ตามเวลาที่ใช้ในการค้นหาบางสิ่งก็ยังคงค่อนข้างคงที่ สิ่งนี้เป็นที่ต้องการอย่างมากสำหรับการค้นหาความเร็วสูง ข้อเสียเพียงอย่างเดียวคือพจนานุกรมโดยธรรมชาติของการใช้ตารางแฮชนั้นไม่มีการเรียงลำดับดังนั้นคุณจะไม่สามารถตัดผ่านรายการในพจนานุกรมในการสั่งซื้อ

เรียงลำดับ

SortedDictionary คล้ายกับ Dictionary ในการใช้งาน แต่แตกต่างกันมากในการนำไปใช้งาน SortedDictionary ใช้ต้นไม้ไบนารีภายใต้ครอบคลุมในการรักษารายการในการสั่งซื้อโดยกุญแจสำคัญ อันเป็นผลมาจากการเรียงลำดับประเภทที่ใช้สำหรับคีย์จะต้องใช้ IComparable อย่างถูกต้องเพื่อให้เรียงลำดับคีย์ได้อย่างถูกต้อง พจนานุกรมที่เรียงลำดับจะใช้เวลาในการค้นหาเล็กน้อยเพื่อความสามารถในการรักษารายการตามลำดับดังนั้นเวลาแทรก / ลบ / ค้นหาในพจนานุกรมที่เรียงลำดับจึงเป็นลอการิทึม - O (log n) โดยทั่วไปเมื่อใช้เวลาลอการิทึมคุณสามารถเพิ่มขนาดของคอลเล็กชันได้เป็นสองเท่าและจะต้องทำการเปรียบเทียบเพิ่มเติมเพียงครั้งเดียวเพื่อค้นหารายการ ใช้ SortedDictionary เมื่อคุณต้องการค้นหาอย่างรวดเร็ว แต่ยังต้องการให้สามารถรักษาคอลเลกชันตามลำดับด้วยคีย์

SortedList <>

SortedList คือคลาสคอนเทนเนอร์ที่เชื่อมโยงแบบเรียงลำดับอื่น ๆ ในคอนเทนเนอร์ทั่วไป อีกครั้งหนึ่งที่ SortedList เช่น SortedDictionary, ใช้กุญแจสำคัญในการจัดเรียงคู่คีย์ค่า ไม่เหมือนกับ SortedDictionary อย่างไรก็ตามรายการใน SortedList จะถูกจัดเก็บเป็นอาร์เรย์ของรายการที่เรียงลำดับ. ซึ่งหมายความว่าการแทรกและการลบเป็นแบบเชิงเส้น - O (n) - เนื่องจากการลบหรือเพิ่มรายการอาจเกี่ยวข้องกับการเลื่อนรายการทั้งหมดขึ้นหรือลงในรายการ อย่างไรก็ตามเวลาในการค้นหาคือ O (log n) เนื่องจาก SortedList สามารถใช้การค้นหาแบบไบนารีเพื่อค้นหารายการใด ๆ ในรายการโดยใช้คีย์ แล้วทำไมคุณถึงอยากทำเช่นนี้? คำตอบก็คือถ้าคุณจะโหลด SortedList ขึ้นหน้าการแทรกจะช้าลง แต่เนื่องจากการจัดทำดัชนีอาร์เรย์เร็วกว่าการติดตามลิงก์วัตถุการค้นหาจึงเร็วกว่า SortedDictionary เล็กน้อย อีกครั้งฉันจะใช้สิ่งนี้ในสถานการณ์ที่คุณต้องการการค้นหาอย่างรวดเร็วและต้องการรักษาคอลเล็กชันตามลำดับของคีย์และในกรณีที่การแทรกและการลบหายาก


สรุปเบื้องต้นของขั้นตอนพื้นฐาน

คำติชมยินดีเป็นอย่างยิ่งเพราะฉันแน่ใจว่าฉันทำทุกอย่างไม่ถูกต้อง

  • nอาร์เรย์ทั้งหมดมีขนาด
  • อาร์เรย์ที่ไม่เรียงลำดับ = .Add / .Remove คือ O (1) แต่. รายการ (i) คือ O (n)
  • เรียงลำดับ array = .Add / .Remove คือ O (n) แต่. Item (i) คือ O (log n)

พจนานุกรม

หน่วยความจำ

KeyArray(n) -> non-sorted array<pointer>
ItemArray(n) -> non-sorted array<pointer>
HashArray(n) -> sorted array<hashvalue>

เพิ่ม

  1. เพิ่มHashArray(n) = Key.GetHash# O (1)
  2. เพิ่มKeyArray(n) = PointerToKey# O (1)
  3. เพิ่มItemArray(n) = PointerToItem# O (1)

ลบ

  1. For i = 0 to nค้นหาiโดยที่HashArray(i) = Key.GetHash # O (log n) (อาร์เรย์ที่เรียงลำดับ)
  2. ลบHashArray(i)# O (n) (อาร์เรย์ที่เรียงลำดับ)
  3. ลบKeyArray(i)# O (1)
  4. ลบItemArray(i)# O (1)

รับไอเทม

  1. For i = 0 to nค้นหาiโดยที่HashArray(i) = Key.GetHash# O (log n) (อาร์เรย์ที่เรียงลำดับ)
  2. กลับ ItemArray(i)

วนซ้ำ

  1. For i = 0 to n, กลับ ItemArray(i)

เรียงลำดับ

หน่วยความจำ

KeyArray(n) = non-sorted array<pointer>
ItemArray(n) = non-sorted array<pointer>
OrderArray(n) = sorted array<pointer>

เพิ่ม

  1. เพิ่มKeyArray(n) = PointerToKey# O (1)
  2. เพิ่มItemArray(n) = PointerToItem# O (1)
  3. For i = 0 to nค้นหาiที่KeyArray(i-1) < Key < KeyArray(i)(โดยใช้ICompare) # O (n)
  4. เพิ่มOrderArray(i) = n# O (n) (อาร์เรย์ที่เรียงลำดับ)

ลบ

  1. For i = 0 to nหาiที่KeyArray(i).GetHash = Key.GetHash# O (n)
  2. ลบKeyArray(SortArray(i))# O (n)
  3. ลบItemArray(SortArray(i))# O (n)
  4. ลบOrderArray(i)# O (n) (อาร์เรย์ที่เรียงลำดับ)

รับไอเทม

  1. For i = 0 to nหาiที่KeyArray(i).GetHash = Key.GetHash# O (n)
  2. กลับ ItemArray(i)

วนซ้ำ

  1. For i = 0 to n, กลับ ItemArray(OrderArray(i))

SortedList

หน่วยความจำ

KeyArray(n) = sorted array<pointer>
ItemArray(n) = sorted array<pointer>

เพิ่ม

  1. For i = 0 to nค้นหาiที่KeyArray(i-1) < Key < KeyArray(i)(ใช้ICompare) # O (บันทึก n)
  2. เพิ่มKeyArray(i) = PointerToKey# O (n)
  3. เพิ่มItemArray(i) = PointerToItem# O (n)

ลบ

  1. For i = 0 to nหาiที่KeyArray(i).GetHash = Key.GetHash# O (log n)
  2. ลบKeyArray(i)# O (n)
  3. ลบItemArray(i)# O (n)

รับไอเทม

  1. For i = 0 to nหาiที่KeyArray(i).GetHash = Key.GetHash# O (log n)
  2. กลับ ItemArray(i)

วนซ้ำ

  1. For i = 0 to n, กลับ ItemArray(i)

9
  1. เมื่อคุณต้องการให้คอลเลกชันเรียงตามคีย์เมื่อคุณทำซ้ำ หากคุณไม่ต้องการจัดเรียงข้อมูลของคุณคุณควรใช้เพียงพจนานุกรมก็จะมีประสิทธิภาพที่ดีขึ้น

  2. SortedList และ SortedDictionary สวยมากทำสิ่งเดียวกัน แต่จะมีการดำเนินการที่แตกต่างกันจึงมีจุดแข็งที่แตกต่างกันและจุดอ่อนอธิบายที่นี่


0

พยายามกำหนดคะแนนประสิทธิภาพให้กับแต่ละกรณีที่นำเสนอโดย @Lev ฉันใช้ค่าต่อไปนี้:

  • O (1) = 3
  • O (บันทึก n) = 2
  • O (n) = 1
  • O (1) หรือ O (n) = 2
  • O (log n) หรือ O (n) = 1.5

ผลลัพธ์คือ (สูงกว่า = ดีกว่า):

Dictionary:       12.0 
SortedDictionary:  9.0 
SortedList:        6.5

แน่นอนว่าการใช้งานทุกกรณีจะให้น้ำหนักกับการดำเนินการบางอย่างมากกว่า


1
ตามกฎทั่วไปน้ำหนักของ O (log n) จะเป็น log (n) / log (2) (+1 ในแต่ละครั้ง n doubles) ในขณะที่น้ำหนักของ O (n) จะเป็น n ดังนั้นการถ่วงน้ำหนักของคุณจะถูกต้องสำหรับขนาดไม่เกิน 4 สิ่งที่เกินมาจะเห็นอัตราส่วน 2: 1 ของคุณเพิ่มขึ้นอย่างรวดเร็ว ตัวอย่างเช่นถ้า n = 100 คุณควรมี O (log n) = 15 ตามความคิดที่คล้ายคลึงกัน O (1) ของคุณจะมีน้ำหนัก 100 สรุป: O (n) แพ้การต่อสู้ค่อนข้างเร็ว หากไม่เป็นเช่นนั้นแสดงว่าอาร์เรย์ของคุณมีขนาดเล็กและประสิทธิภาพก็ไม่น่ากังวล
อาม่า
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.