ความแตกต่างระหว่าง SortedList และ SortedDictionary คืออะไร


261

มีความแตกต่างในทางปฏิบัติจริงระหว่าง a SortedList<TKey,TValue>และ a SortedDictionary<TKey,TValue>หรือไม่? มีสถานการณ์ใดบ้างที่คุณจะใช้อย่างใดอย่างหนึ่งโดยเฉพาะ



13
ฉันสับสน ทำไม SortedList จะมีพารามิเตอร์ประเภทสองSortedList<TKey,TValue>มากกว่าหนึ่งSortedList<T>? ทำไมมันไม่ใช้IList<T>?
พันเอก Panic

3
@ColonelPanic เนื่องจาก SortedList ที่ใช้งานได้คือแผนที่ไม่ใช่คอลเล็กชันเชิงเส้น อย่าปล่อยให้ชื่อหลอกคุณ เช่นเดียวกับพจนานุกรมคุณส่งผ่านคีย์คุณจะได้ค่ากลับมา ในขณะที่ไม่ได้เรียงลำดับของพจนานุกรม SortedList จะเรียงตามลำดับเรียงตามธรรมชาติ
nawfal

คำตอบ:


294

ใช่ - คุณสมบัติด้านประสิทธิภาพแตกต่างกันอย่างมีนัยสำคัญ มันอาจจะเป็นการดีกว่าถ้าจะเรียกพวกเขาSortedListและSortedTreeสะท้อนให้เห็นถึงการดำเนินการอย่างใกล้ชิดยิ่งขึ้น

ดูเอกสาร MSDN สำหรับแต่ละรายการ ( SortedList, SortedDictionary) เพื่อดูรายละเอียดของประสิทธิภาพสำหรับการทำงานที่แตกต่างกันในไซต์ที่ต่างกัน นี่เป็นบทสรุปที่ดี (จากSortedDictionaryเอกสาร):

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>

( SortedListจริง ๆ แล้วรักษาอาร์เรย์ที่เรียงลำดับแทนที่จะใช้ทรีมันยังคงใช้การค้นหาแบบไบนารีเพื่อค้นหาองค์ประกอบ)


ขอบคุณมากสำหรับทุกคนสำหรับพอยน์เตอร์ ฉันเดาว่าฉันขี้เกียจเกินไปกับ RTFM ... ง่ายกว่าที่จะถามคนดีๆใน SO ... ;) ฉันโหวตให้คุณทั้งคู่ตอบคำถาม จอนได้รับเครดิตตอบเมื่อถูกเรียก :)
Shaul Behr

2
ฉันคิดว่านิยาม SortedList ควรได้รับการแก้ไขเนื่องจากฉันไม่เชื่อว่าเป็นแผนภูมิการค้นหาแบบไบนารี ...
nchaud

1
ฉันดูการใช้ตัวสะท้อนแสงและพบว่ามันไม่ได้ใช้แผนภูมิการค้นหาแบบไบนารี
Daniel Imms

. ผมคิดว่า SortedDictionary เป็น AVL ต้นไม้หรือสีแดง Blacktree (ค่าใช้จ่ายในการดำเนินงานทั้งหมด O (logn) และ SortedList เป็นไบนารีการค้นหา (มีค่าใช้จ่าย O (n) เวลาในกรณีที่เลวร้ายที่สุด) L
ghoster

105

นี่คือมุมมองแบบตารางถ้ามันช่วย ...

จากมุมมองของประสิทธิภาพ :

+------------------+---------+----------+--------+----------+----------+---------+
| Collection       | Indexed | Keyed    | Value  | Addition |  Removal | Memory  |
|                  | lookup  | lookup   | lookup |          |          |         |
+------------------+---------+----------+--------+----------+----------+---------+
| SortedList       | O(1)    | O(log n) | O(n)   | O(n)*    | O(n)     | Lesser  |
| SortedDictionary | n/a     | O(log n) | O(n)   | O(log n) | O(log n) | Greater |
+------------------+---------+----------+--------+----------+----------+---------+

* Insertion is O(1) for data that are already in sort order, so that each 
  element is added to the end of the list (assuming no resize is required).

จากมุมมองการใช้งาน :

+------------+---------------+----------+------------+------------+------------------+
| Underlying | Lookup        | Ordering | Contiguous | Data       | Exposes Key &    |
| structure  | strategy      |          | storage    | access     | Value collection |
+------------+---------------+----------+------------+------------+------------------+
| 2 arrays   | Binary search | Sorted   | Yes        | Key, Index | Yes              |
| BST        | Binary search | Sorted   | No         | Key        | Yes              |
+------------+---------------+----------+------------+------------+------------------+

ในการแปลความหมายคร่าวๆหากคุณต้องการประสิทธิภาพแบบดิบSortedDictionaryอาจเป็นทางเลือกที่ดีกว่า หากคุณต้องการค่าใช้จ่ายหน่วยความจำที่น้อยกว่าและการดึงดัชนีที่SortedListเหมาะควรดีกว่า ดูคำถามนี้สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเวลาที่จะใช้

คุณสามารถอ่านเพิ่มเติมได้ที่นี่ , ที่นี่ , ที่นี่ , ที่นี่และที่นี่


โปรดทราบว่าหากคุณต้องการผลงานที่ดีและใช้หน่วยความจำที่ค่อนข้างต่ำและดึงการจัดทำดัชนีพิจารณาBDictionary<Key,Value>ใน LoycCoreSortedDictionaryแทน
Qwertie

1
ใช่ดูที่ส่วนล่างของบทความนี้ โดยBDictionaryทั่วไปแล้วจะช้ากว่าSortedDictionaryยกเว้นขนาดที่ใหญ่มาก แต่จะเร็วกว่าSortedListหากมีมากกว่า 700 รายการ การใช้หน่วยความจำควรสูงกว่าSortedList(ต่ำกว่าSortedDictionary) เพียงเล็กน้อยเท่านั้นเนื่องจากการใช้อาร์เรย์ในใบไม้ของต้นไม้
Qwertie

22

ฉันถอดรหัสตัวสะท้อนแสงแบบเปิดเพื่อดูสิ่งนี้เนื่องจากดูเหมือนจะสับสนSortedListเล็กน้อย ในความเป็นจริงไม่ได้เป็นต้นไม้ค้นหาแบบทวิภาค, มันเป็นความเรียง (โดยกุญแจ) อาร์เรย์ของคู่ค่าคีย์ นอกจากนี้ยังมีTKey[] keysตัวแปรที่เรียงลำดับซิงค์กับคู่คีย์ - ค่าและใช้ในการค้นหาแบบไบนารี

นี่คือที่มาบางส่วน (กำหนดเป้าหมาย. NET 4.5) เพื่อสำรองการอ้างสิทธิ์ของฉัน

สมาชิกส่วนตัว

// Fields
private const int _defaultCapacity = 4;
private int _size;
[NonSerialized]
private object _syncRoot;
private IComparer<TKey> comparer;
private static TKey[] emptyKeys;
private static TValue[] emptyValues;
private KeyList<TKey, TValue> keyList;
private TKey[] keys;
private const int MaxArrayLength = 0x7fefffff;
private ValueList<TKey, TValue> valueList;
private TValue[] values;
private int version;

SortedList.ctor (IDictionary, IComparer)

public SortedList(IDictionary<TKey, TValue> dictionary, IComparer<TKey> comparer) : this((dictionary != null) ? dictionary.Count : 0, comparer)
{
    if (dictionary == null)
    {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.dictionary);
    }
    dictionary.Keys.CopyTo(this.keys, 0);
    dictionary.Values.CopyTo(this.values, 0);
    Array.Sort<TKey, TValue>(this.keys, this.values, comparer);
    this._size = dictionary.Count;
}

SortedList.Add (TKey, TValue): void

public void Add(TKey key, TValue value)
{
    if (key == null)
    {
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
    }
    int num = Array.BinarySearch<TKey>(this.keys, 0, this._size, key, this.comparer);
    if (num >= 0)
    {
        ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
    }
    this.Insert(~num, key, value);
}

SortedList.RemoveAt (int): void

public void RemoveAt(int index)
{
    if ((index < 0) || (index >= this._size))
    {
        ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.index, ExceptionResource.ArgumentOutOfRange_Index);
    }
    this._size--;
    if (index < this._size)
    {
        Array.Copy(this.keys, index + 1, this.keys, index, this._size - index);
        Array.Copy(this.values, index + 1, this.values, index, this._size - index);
    }
    this.keys[this._size] = default(TKey);
    this.values[this._size] = default(TValue);
    this.version++;
}

13

ตรวจสอบหน้า MSDN สำหรับ SortedList :

จากข้อสังเกต:

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

  • SortedList<(Of <(TKey, TValue>)>)SortedDictionary<(Of <(TKey, TValue>)>)ใช้หน่วยความจำน้อยกว่า
  • SortedDictionary<(Of <(TKey, TValue>)>)มีการแทรกได้เร็วขึ้นและการกำจัดการดำเนินงานสำหรับข้อมูลที่ไม่ได้เรียงลำดับ, O(log n)ตรงข้ามกับการสำหรับO(n)SortedList<(Of <(TKey, TValue>)>)

  • ถ้ารายการที่มีประชากรทั้งหมดในครั้งเดียวจากข้อมูลที่เรียงลำดับจะเร็วกว่าSortedList<(Of <(TKey, TValue>)>)SortedDictionary<(Of <(TKey, TValue>)>)


9
ข้อความที่ยกมานั้นไม่ถูกต้อง (และถูกอัพเดตบน MSDN): SortedList ไม่ใช่ "แผนผังการค้นหาแบบไบนารี" แต่เป็น "อาร์เรย์ของคู่คีย์ / ค่า"
Eldritch Conundrum

12

นี่เป็นภาพที่แสดงให้เห็นว่าการแสดงเปรียบเทียบกันอย่างไร


คุณนำข้อมูลนั้นมาจากที่ใด จากรูปแบบนี้เราจะเห็นว่า Dictinary ดีกว่าในทุกทางดังนั้นจึงไม่มีเหตุผลที่คนอื่นจะมีอยู่จริง
alex kostin

9

พอมีการพูดในหัวข้อแล้ว แต่เพื่อให้ง่ายนี่คือสิ่งที่ฉันทำ

พจนานุกรมที่จัดเรียงควรใช้เมื่อ -

  • ต้องมีการแทรกและลบเพิ่มเติม
  • ข้อมูลในการยกเลิกการสั่งซื้อ
  • การเข้าถึงคีย์นั้นเพียงพอและไม่จำเป็นต้องเข้าถึงดัชนี
  • หน่วยความจำไม่ใช่คอขวด

ในอีกด้านหนึ่งรายการที่เรียงลำดับควรใช้เมื่อ -

  • ต้องมีการค้นหาและแทรกเพิ่มและลบน้อยกว่า
  • ข้อมูลถูกเรียงลำดับแล้ว (ถ้าไม่ใช่ทั้งหมดส่วนใหญ่)
  • ต้องมีการเข้าถึงดัชนี
  • หน่วยความจำคือค่าใช้จ่าย

หวังว่านี่จะช่วยได้ !!


1

การเข้าถึงดัชนี (กล่าวถึงที่นี่) เป็นความแตกต่างในทางปฏิบัติ หากคุณต้องการเข้าถึงตัวตายตัวแทนหรือผู้บุกเบิกคุณต้องใช้ SortedList SortedDictionary ไม่สามารถทำเช่นนั้นได้ดังนั้นคุณจึงถูก จำกัด ด้วยวิธีการใช้การเรียงลำดับ (ลำดับแรก / ก่อน)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.