• List和hashtable之查找效率


    假设这样的一个场景,有两个List<string>,分别是listA和listB,其中均有超过1w+的数据量,现在要求找出在B中但是不在A中的数据集合,

    于是我们写了以下代码

    View Code
    listB.ForEach(re =>
                 {
                     if (!listA.Contains(re))
                     {
                         //.......
                     }
                 });

    这样写的话,是能够达到我们的需求的,但是很不幸,时间也会消耗很多。

    我们看下List.Contains的源代码实现

    View Code
    [__DynamicallyInvokable]
     public bool Contains(T item)
     {
         if (item == null)
         {
             for (int j = 0; j < this._size; j++)
             {
                 if (this._items[j] == null)
                 {
                     return true;
                 }
             }
             return false;
         }
         EqualityComparer<T> comparer = EqualityComparer<T>.Default;
         for (int i = 0; i < this._size; i++)
         {
             if (comparer.Equals(this._items[i], item))
             {
                 return true;
             }
         }
         return false;
     }

    这是因为List.Contains 本质是通过循环查找出该条数据,每一次的调用都会重头循环,所以效率很低。显然,这是不可取的。

    于是,我们可以利用Hashtable的键值对改善这种情况。

    代码如下:

    View Code
    listA.ForEach(re =>
                 {
                     table.Add(re, re);
                 });
                 listB.ForEach(re =>
                     {
                         if (table.ContainsKey(re))
                         {
                             //......
                         }
                     });

    虽然,多了一个循环,但是总时间确实减少了很多。

    我们可以看下Hashtable.ContainsKey源代码:

    View Code
    public virtual bool ContainsKey(object key)
     {
         uint num;
         uint num2;
         Hashtable.bucket bucket;
         if (key == null)
         {
             throw new ArgumentNullException("key", Environment.GetResourceString("ArgumentNull_Key"));
         }
         Hashtable.bucket[] buckets = this.buckets;
         uint num3 = this.InitHash(key, buckets.Length, out num, out num2);
         int num4 = 0;
         int index = (int) (num % buckets.Length);
         do
         {
             bucket = buckets[index];
             if (bucket.key == null)
             {
                 return false;
             }
             if (((bucket.hash_coll & 0x7fffffff) == num3) && this.KeyEquals(bucket.key, key))
             {
                 return true;
             }
             index = (int) ((index + num2) % ((ulong) buckets.Length));
         }
         while ((bucket.hash_coll < 0) && (++num4 < buckets.Length));
         return false;
     }

    可见,哈希表的数据查找效率不是盖出来的。

    我们可以通过下面的代码验证:

    View Code
    static void Main(string[] args)
             {
                 List<string> listA = new List<string>();
                 List<string> listB = new List<string>();
                 for (int i = 0; i < 9999; i++)
                 {
                     listA.Add(i.ToString());
                     listB.Add((i + 1).ToString());
                 }
                 Stopwatch watch = new Stopwatch();
                 watch.Start();
                 listB.ForEach(re =>
                 {
                     if (!listA.Contains(re))
                     {
                         //.......
                     }
                 });
                 watch.Stop();
                 Console.WriteLine("List.Contains need {0}", watch.ElapsedTicks);
                 Hashtable table = new Hashtable();
                 watch.Restart();
                 listA.ForEach(re =>
                 {
                     table.Add(re, re);
                 });
                 listB.ForEach(re =>
                     {
                         if (table.ContainsKey(re))
                         {
                             //......
                         }
                     });
                 watch.Stop();
                 Console.WriteLine("Hashtable.Contains need {0}", watch.ElapsedTicks);
                 Console.ReadKey(true);
             }

    执行的结果如下:

    List.Contains need 1920001 Hashtable.Contains need 8493 可以看到,效率提升了很多,当数据量越大,效果越明显。

    注:本帖只是为了说明可以使用Hashtable改善List的查找性能,不做其他用处

  • 相关阅读:
    c#操作Excel时,抛出异常:“未在本地计算机上注册“Microsoft.ACE.OLEDB.12.0”提供程序”
    设计模式(二)(Factory method)工厂方法设计模式
    设计模式(一)Singlton
    oracle中merge的用法,以及各版本的区别 Create
    rowid去重(删除表的重复记录)
    Oracle 12C 新特性之 恢复表
    Oracle 12C 新特性之 sqlplus查看History命令
    Oracle 12C 新特性之 PDB热克隆(本地克隆、远端异机克隆)
    Oracle 12C 新特性之 db默认字符集AL32UTF8、PDB支持不同字符集
    Oracle 12C 新特性之表分区部分索引(Partial Indexes)
  • 原文地址:https://www.cnblogs.com/binyao/p/3051438.html
Copyright © 2020-2023  润新知