您的位置:首页 > 产品设计 > UI/UE

.NET源码中的SortedDictionary<TKey, TValue>和SortedList<TKey, TValue>

2014-07-01 11:05 483 查看
SortedDictionary<TKey, TValue>和SortedList<TKey, TValue>的功能相同,都用来存储按Key排序的键值对,且无重复。

而内部实现的差异却很大,SortedDictionary<TKey, TValue>的内部实现是红黑二叉搜索树,而SortedList<TKey, TValue>的内部是两个数组,分别存储Key和Value序列。

这就决定了:

SortedList<TKey, TValue>的内存占用的少,因为树上还要存储左右树和红标识。
但是插入的删除的话数组要比树慢。树是O(log2N),数组是O(N)。
而插入已排序的数据的话,数组要快。

SortedList<TKey, TValue>的内部数据结构定义如下:

可以看到两个数组用来存储keys和values。而数组的最大长度是2GB.
public class SortedList<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IEnumerable
  {
    private static TKey[] emptyKeys = new TKey[0];
    private static TValue[] emptyValues = new TValue[0];
    private TKey[] keys;
    private TValue[] values;
    private int _size;
    private int version;
    private IComparer<TKey> comparer;
    private SortedList<TKey, TValue>.KeyList keyList;
    private SortedList<TKey, TValue>.ValueList valueList;
    [NonSerialized]
    private object _syncRoot;
    private const int _defaultCapacity = 4;
    private const int MaxArrayLength = 2146435071;


而SortedDictionary<TKey, TValue>的内部数据结构定义如下:
内部其实是一个TreeSet的键值对泛型,而TreeSet则是继承于SortedSet红黑树。

public class SortedDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IEnumerable
  {
    [NonSerialized]
    private SortedDictionary<TKey, TValue>.KeyCollection keys;
    [NonSerialized]
    private SortedDictionary<TKey, TValue>.ValueCollection values;
    private TreeSet<KeyValuePair<TKey, TValue>> _set;


其中的KeyValuePair<TKey, TValue>的定义如下:
public struct KeyValuePair<TKey, TValue>
  {
    private TKey key;
    private TValue value;


然后对SortedDictionary<TKey, TValue>的增删改查就都是按照SortedSet<T>红黑树的操作了。

而SortedList<TKey, TValue>的增,查,删的实现分别如下:

增:先二分查找到要插入的位置,

public void Add(TKey key, TValue value)
    {
      if ((object) 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);
    }


然后插入:插入的时候要将目标位置之后的所有数据都向后移。。

private void Insert(int index, TKey key, TValue value)
    {
      if (this._size == this.keys.Length)
        this.EnsureCapacity(this._size + 1);
      if (index < this._size)
      {
        Array.Copy((Array) this.keys, index, (Array) this.keys, index + 1, this._size - index);
        Array.Copy((Array) this.values, index, (Array) this.values, index + 1, this._size - index);
      }
      this.keys[index] = key;
      this.values[index] = value;
      ++this._size;
      ++this.version;
    }


删:先通过Key的找到要删除的位置索引

public bool Remove(TKey key)
    {
      int index = this.IndexOfKey(key);
      if (index >= 0)
        this.RemoveAt(index);
      return index >= 0;
    }


找到索引的过程是这样的:还是二分查找。

public int IndexOfKey(TKey key)
    {
      if ((object) key == null)
        ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
      int num = Array.BinarySearch<TKey>(this.keys, 0, this._size, key, this.comparer);
      if (num < 0)
        return -1;
      else
        return num;
    }


而根据索引删除的过程如下:把索引之后所有数据前移,然后把最后一个位置赋值为default<T>。

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((Array) this.keys, index + 1, (Array) this.keys, index, this._size - index);
        Array.Copy((Array) this.values, index + 1, (Array) this.values, index, this._size - index);
      }
      this.keys[this._size] = default (TKey);
      this.values[this._size] = default (TValue);
      ++this.version;
    }


直接根据数组索引Key来get和set Value的实现如下:

public TValue this[TKey key]
    {
      get
      {
        int index = this.IndexOfKey(key);
        if (index >= 0)
          return this.values[index];
        ThrowHelper.ThrowKeyNotFoundException();
        return default (TValue);
      }
      set
      {
        if ((object) key == null)
          ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);
        int index = Array.BinarySearch<TKey>(this.keys, 0, this._size, key, this.comparer);
        if (index >= 0)
        {
          this.values[index] = value;
          ++this.version;
        }
        else
          this.Insert(~index, key, value);
      }
    }


以上。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐