zoukankan      html  css  js  c++  java
  • 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的查找性能,不做其他用处

  • 相关阅读:
    python 的csr_python
    OpenBLAS学习一:源码架构解析&GEMM分析
    gcc警告选项汇总
    Welcome! This is the documentation for Python 3.6.8
    CentOS 7 查看和设置防火墙状态
    django中多个app放入同一文件apps
    安装mysqlclient, 链接mysql失败,提示“Library not loaded: @rpath/libmysqlclient.21.dylib”
    动手玩转Docker(二)
    动手玩转Docker(一)
    转载:微服务部署:蓝绿部署、滚动部署、灰度发布、金丝雀发布
  • 原文地址:https://www.cnblogs.com/binyao/p/3051438.html
Copyright © 2011-2022 走看看