链表与Hash检索实测

测试环境:

  Win7 SP1、8G内存、3.4GHz 4核

测试代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Diagnostics;

namespace FactoryMode
{
    public class TestObject
    {
        public string memberString { get; set; }
        public long memberBigInt { get; set; }
    }

    [Serializable]
    public class Program : MarshalByRefObject
    {
        static long TotalCount = 2000000;
        static long FisrtLv = 500000;
        static long SecondLv = 1000000;
        static long ThirdLv = 1500000;

        static void Main(string[] args)
        {
            //链表测试资源准备
            var ObjectList = new List<TestObject>();
            for (int i = 0; i < TotalCount; i++)
            {
                var newTestObject = new TestObject();
                newTestObject.memberString = i.ToString();
                newTestObject.memberBigInt = i;
                ObjectList.Add(newTestObject);
            }

            //查找1
            var stopWatch1 = Stopwatch.StartNew();
            var result1 = ObjectList.Find(p => p.memberBigInt == SecondLv);
            var lastElapsedTime1 = stopWatch1.ElapsedMilliseconds;
            Console.WriteLine("Condition 1: {0} ms.", lastElapsedTime1);
            Console.WriteLine("result1: {0}.", result1.memberString);

            //字典测试资源准备
            var ObjectDictionary = new Dictionary<string, TestObject>();
            for (int i = 0; i < TotalCount; i++)
            {
                var newTestObject = new TestObject();
                newTestObject.memberString = i.ToString();
                newTestObject.memberBigInt = i;
                ObjectDictionary.Add(newTestObject.memberString, newTestObject);
            }

            //查找2
            var stopWatch2 = Stopwatch.StartNew();
            var result2 = ObjectDictionary[Convert.ToString(ThirdLv)];
            var lastElapsedTime2 = stopWatch2.ElapsedMilliseconds;
            Console.WriteLine("Condition 2: {0} ms.", lastElapsedTime2);
            Console.WriteLine("result2: {0}.", result2.memberString);

            Console.Read();

        }
    }
}

测试结果:

  链表检索:每50w 12ms;

  Hash检索:0ms;

测试代码2:

            //写入1
            var stopWatch3 = Stopwatch.StartNew();
            for (int i = 0; i < FisrtLv; i++)
            {
                ObjectList[i].memberBigInt += 1;
            }
            var lastElapsedTime3 = stopWatch3.ElapsedMilliseconds;
            Console.WriteLine("Condition 3: {0} ms.", lastElapsedTime3);

            //写入2
            var stopWatch4 = Stopwatch.StartNew();
            for (int i = 0; i < FisrtLv; i++)
            {
                ObjectDictionary[Convert.ToString(i)].memberBigInt += 1;
            }
            var lastElapsedTime4 = stopWatch4.ElapsedMilliseconds;
            Console.WriteLine("Condition 4: {0} ms.", lastElapsedTime4);

测试结果2:

  链表写入:12ms;

  Hash写入:143ms;(根据散列函数得到了新的存储位置,数据转移开销)

技术参考:http://blog.sina.com.cn/s/blog_7880b6e30100xi94.html

注意点:

  虽然Hash具有O(1)的数据检索效率,但它空间开销却通常很大,是以空间换取时间,所以Hashtable适用于读取操作频繁,写入操作很少的操作类型。

引申思考:

  在实际的应用中,应避免将所有的常用、不常用的数据都放在同一个数据结构中,无论是使用自定义的内存结构或者是redis,都应该定时将过期数据放入二级缓存,为一级缓存瘦身。

  在游戏服务器应用中,一个服务器应将数据分为内存数据、冷备数据,登陆时将冷备数据加载至内存(登陆较慢可容忍),单服热数据容量一般不会超过5w级别,数据结构的性能可接受。

  在之前一个http短连接项目的应用中,每次协议都直接从redis读取数据,处理完毕之后写入redis,但是 redis 实际上没有冷数据,这样随着运行时间的推移,效率会越来越低。

时间: 2024-08-01 09:37:56

链表与Hash检索实测的相关文章

数组、链表、Hash(转)

在程序中,存放指定的数据最常用的数据结构有两种:数组和链表. 数组和链表的区别: 1.数组是将元素在内存中连续存放. 链表中的元素在内存中不是顺序存储的,而是通过存在元素中的指针联系到一起. 2.数组必须事先定义固定的长度,不能适应数据动态地增减的情况.当数据增加时,可能超出原先定义的元素个数:当数据减少时,造成内存浪费. 链表动态地进行存储分配,可以适应数据动态地增减的情况. 3.(静态)数组从栈中分配空间, 对于程序员方便快速,但是自由度小. 链表从堆中分配空间, 自由度大但是申请管理比较麻

HashMap解决hash冲突的方法

源码分析 HashMap 采用一种所谓的“Hash 算法”来决定每个元素的存储位置.当程序执行 map.put(String,Obect)方法 时,系统将调用String的 hashCode() 方法得到其 hashCode 值——每个 Java 对象都有 hashCode() 方法,都可通过该方法获得它的 hashCode 值.得到这个对象的 hashCode 值之后,系统会根据该 hashCode 值来决定该元素的存储位置.源码如下: public V put(K key, V value)

In-Memory:Hash Index

SQL Server 2016支持哈希查找,用户可以在内存优化表(Memory-Optimized Table)上创建Hash Index,使用Hash 查找算法,实现数据的极速查找.在使用上,Hash Index 和B-Tree索引的区别是:Hash Index 是无序查找,Index Key必须全部作为Filter,而B-Tree索引是有序查找,不需要Index Key都作为Filter,只需要前序字段存在即可:在存储结构上,Hash Index使用Hash Table实现,存在Hash 冲

HashMap之Hash碰撞冲突解决方案及未来改进

说明:参考网上的两篇文章做了简单的总结,以备后查(http://blogread.cn/it/article/7191?f=wb  ,http://it.deepinmind.com/%E6%80%A7%E8%83%BD/2014/04/24/hashmap-performance-in-java-8.html) 1.HashMap位置决定与存储 通过前面的源码分析可知,HashMap 采用一种所谓的“Hash 算法”来决定每个元素的存储位置.当程序执行put(String,Obect)方法 时

Hash的一点测试

哈希表的学习与测试 以前写的hash都是碰运气的hash,就是乘上质数取模的那种,这样不能保证不碰撞,所以今天先写上几个双hush和链表的hash,并比较一下他们的速度,测试的话用洛谷上的“字符串哈希”题目进行测试. Hash1:碰撞三个点 用时352ms /* 这个是只进行一次取质数的hash    第一次尝试    取key值127  mod值 10000000 */ Hash2:碰撞三个点 用时360ms /* 这个也是只进行一次取质数的           hush key值131   

大厂面试必问!HashMap 怎样解决hash冲突?

HashMap冲突解决方法比较考验一个开发者解决问题的能力. 下文给出HashMap冲突的解决方法以及原理分析,无论是在面试问答或者实际使用中,应该都会有所帮助. 在Java编程语言中,最基本的结构就是两种,一种是数组,一种是模拟指针(引用),所有的数据结构都可以用这两个基本结构构造,HashMap也一样. 当程序试图将多个 key-value 放入 HashMap 中时,以如下代码片段为例: HashMap<String,Object>m=newHashMap<String,Objec

Java容器的常见问题

记录Java容器中的常见概念和原理 参考: https://github.com/wangzhiwubigdata/God-Of-BigData#%E4%B8%89Java%E5%B9%B6%E5%8F%91%E5%AE%B9%E5%99%A8 https://blog.csdn.net/justloveyou_/article/details/78653929 基础容器 ArrayList(动态数组).LinkedList(带头结点的双向链表) ArrayList public class A

Java集合容器面试题

什么是集合 集合框架:用于存储数据的容器. 集合框架是为表示和操作集合而规定的一种统一的标准的体系结构. 任何集合框架都包含三大块内容:对外的接口.接口的实现和对集合运算的算法. 接口:表示集合的抽象数据类型.接口允许我们操作集合时不必关注具体实现,从而达到"多 态".在面向对象编程语言中,接口通常用来形成规范. 实现:集合接口的具体实现,是重用性很高的数据结构. 算法:在一个实现了某个集合框架中的接口的对象身上完成某种有用的计算的方法,例如查 找.排序等.这些算法通常是多态的,因为相

LRU 缓冲池 (不考虑多线程)

lru:(转)LRU算法的实现 什么是LRU算法? LRU是Least Recently Used的缩写,即最近最少使用页面置换算法,是为虚拟页式存储管理服务的.关于操作系统的内存管理,如何节省利用容量不大的内存为最多的进程提供资源,一直是研究的重要方向.而内存的虚拟存储管理,是现在最通用,最成功的方式——在内存有限的情况下,扩展一部分外存作为虚拟内存,真正的内存只存储当前运行时所用得到信息.这无疑极大地扩充了内存的功能,极大地提高了计算机的并发度.虚拟页式存储管理,则是将进程所需空间划分为多个