面试准备 - HashTable 的C#实现 开放地址法
Hashtable是很经常在面试中遇到的数据结构,因为他的O(1)操作时间和O(n)空间
之所以自己写一份是因为:
- 加深对于hashtable的理解
- 某些公司面试的时候需要coding.......
开放地址法 Xn=(Xn-1 +b ) % size
理论上b要和size是要精心选择的,不过我这边没有做特别的处理,101的默认size是从c#源代码中抄袭的。。。。
代码尽量简单一点是为了理解方便
hashtable快满的时候扩展一倍空间,数据和标志位还有key 这三个数组都要扩展
删除的时候不能直接删除元素,只能打一个标志(因为用了开放地方方法)
目前只支持string和int类型的key(按位131进制)
非线程安全- 因为这是范例代码
支持泛型
public class Hashtable<T>
{
public Hashtable()
{
this.dataArray = new T[this.m];
this.avaiableCapacity = this.m;
this.keyArray = new int[this.m];
for (int i = ; i < this.keyArray.Length; i++)
{
this.keyArray[i] = -;
}
this.flagArray = new bool[this.m];
}
private int m = ;
private int l = ;
private int avaiableCapacity;
private double factor = 0.35;
private T[] dataArray;
private int[] keyArray;
private bool[] flagArray;
public void Add(string s, T item)
{
if (string.IsNullOrEmpty(s))
{
throw new ArgumentNullException("s");
}
if ((double)this.avaiableCapacity / this.m < this.factor)
{
this.ExtendCapacity();
}
var code = HashtableHelper.GetStringHash(s);
this.AddItem(code, item, this.dataArray, code, this.keyArray, this.flagArray);
}
public T Get(string s)
{
if (string.IsNullOrEmpty(s))
{
throw new ArgumentNullException("s");
}
var code = HashtableHelper.GetStringHash(s);
return this.GetItem(code, this.dataArray, code, this.keyArray, this.flagArray);
}
private void ExtendCapacity()
{
this.m *= ;
this.avaiableCapacity += this.m;
T[] newItems = new T[this.m];
int[] newKeys = new int[this.m];
bool[] newFlags = new bool[this.m];
for (int i = ; i < newKeys.Length; i++)
{
newKeys[i] = -;
}
for (int i = ; i < this.dataArray.Length; i++)
{
if (this.keyArray[i] >= && !this.flagArray[i])
{
//var code = HashtableHelper.GetStringHash(s);
this.AddItem(
this.keyArray[i],
this.dataArray[i],
newItems,
this.keyArray[i],
newKeys,
this.flagArray);
}
}
this.dataArray = newItems;
this.keyArray = newKeys;
this.flagArray = newFlags;
// throw new NotImplementedException();
}
private int AddItem(int code, T item, T[] data, int hashCode, int[] keys, bool[] flags)
{
int address = code % this.m;
if (keys[address] < )
{
data[address] = item;
keys[address] = hashCode;
this.avaiableCapacity--;
return address;
}
else if (keys[address] == hashCode)
{
if (flags[address])
{
flags[address] = false;
data[address] = item;
return address;
}
throw new ArgumentException("duplicated key");
}
else
{
int nextAddress = address + this.l; //open addressing Xn=Xn-1 + b
return this.AddItem(nextAddress, item, data, hashCode, keys, flags);
}
}
private T GetItem(int code, T[] data, int hashCode, int[] keys, bool[] flags)
{
int address = code % this.m;
if (keys[address] < )
{
return default(T);
}
else if (keys[address] == hashCode)
{
if (flags[address])
{
return default(T);
}
return data[address];
}
else
{
int nextAddress = address + this.l; //open addressing Xn=Xn-1 + b
return this.GetItem(nextAddress, data, hashCode, keys, flags);
}
}
public void Delete(string s)
{
if (string.IsNullOrEmpty(s))
{
throw new ArgumentNullException("s");
}
var code = HashtableHelper.GetStringHash(s);
this.DeleteItem(code, this.dataArray, code, this.keyArray, this.flagArray);
}
private void DeleteItem(int code, T[] data, int hashCode, int[] keys, bool[] flags)
{
int address = code % this.m;
if (keys[address] < )
{
return;
//not exist
}
else if (keys[address] == hashCode)
{
if (!this.flagArray[address])
{
flags[address] = true;
this.avaiableCapacity++;
}
}
else
{
int nextAddress = address + this.l; //open addressing Xn=Xn-1 + b
this.DeleteItem(nextAddress, data, hashCode, keys, flags);
}
}
}
public class HashtableHelper
{
public static int GetStringHash(string s)
{
if (string.IsNullOrEmpty(s))
{
throw new ArgumentNullException("s");
}
var bytes = Encoding.ASCII.GetBytes(s);
int checksum = GetBytesHash(bytes, , bytes.Length);
return checksum;
}
public static int GetBytesHash(byte[] array, int ibStart, int cbSize)
{
if (array == null || array.Length == )
{
throw new ArgumentNullException("array");
}
int checksum = ;
for (int i = ibStart; i < (ibStart + cbSize); i++)
{
checksum = (checksum * ) + array[i];
}
return checksum;
}
public static int GetBytesHash(char[] array, int ibStart, int cbSize)
{
if (array == null || array.Length == )
{
throw new ArgumentNullException("array");
}
int checksum = ;
for (int i = ibStart; i < (ibStart + cbSize); i++)
{
checksum = (checksum * ) + array[i];
}
return checksum;
}
}
面试准备 - HashTable 的C#实现 开放地址法的更多相关文章
- Hash冲突的线性探测开放地址法
在实际应用中,无论如何构造哈希函数,冲突是无法完全避免的. 开放地址法 这个方法的基本思想是:当发生地址冲突时,按照某种方法继续探测哈希表中的其他存储单元,直到找到空位置为止.这个过程可用下式描述: ...
- Java解决Hash(散列)冲突的四种方法--开放地址法(线性探测,二次探测,伪随机探测)、链地址法、再哈希、建立公共溢出区
最近时间有点紧,暂时先放参考链接了,待有时间在总结一下: 查了好多,这几篇博客写的真心好,互有优缺点,大家一个一个看就会明白了: 参考 1. 先看这个明白拉链法(链地址法),这个带源码,很好看懂,只不 ...
- 开放地址法实现HashTable
前注:本文不是讲解Java类库的Hashtable实现原理,而是根据计算机哈希表原理自己实现的一个Hashtable. HashTable内部是用数组存放一个(Key-Value pair)键值对的引 ...
- 开放地址法散列表ADT
数据结构定义如下: typedef unsigned int Index; typedef Index Position; struct HashTbl; typedef struct HashTbl ...
- 链地址法实现HashMap
前注:本文介绍的HashMap并非Java类库的实现.而是根据哈希表知识的一个实现. 上文介绍了开放地址法实现HashTable,它的缺点是对hashCode映射为地址后如果出现重复地址,则会占用其他 ...
- C# Dictionary源码剖析---哈希处理冲突的方法有:开放定址法、再哈希法、链地址法、建立一个公共溢出区等
C# Dictionary源码剖析 参考:https://blog.csdn.net/exiaojiu/article/details/51252515 http://www.cnblogs.com/ ...
- java 解决Hash(散列)冲突的四种方法--开放定址法(线性探测,二次探测,伪随机探测)、链地址法、再哈希、建立公共溢出区
java 解决Hash(散列)冲突的四种方法--开放定址法(线性探测,二次探测,伪随机探测).链地址法.再哈希.建立公共溢出区 标签: hashmaphashmap冲突解决冲突的方法冲突 2016-0 ...
- 面试之Hashtable和ConcurrentHashMap
那么要如何保证HashMap的线程安全呢? 方法有很多,比如使用Hashtable或者Collections.synchronizedMap,但是这两位选手都有一个共同的问题:性能.因为不管是读还是写 ...
- java8中哪个类用到了开放地址解决冲突
hreadlocalmap使用开放定址法解决haah冲突,hashmap使用链地址法解决hash冲突
随机推荐
- .PRT extension and multiple NX versions
http://nxway.blogspot.ca/2007/10/prt-extension-and-multiple-nx-versions.html To open prt files with ...
- 网页播放器(jsp、js)
jsp对控件显示 <%@ page language="java" import="java.util.*" pageEncoding="UTF ...
- Jquery的multifile使用随记
1.多文件上传: 2.如上几个验证不重复,和限制上传数量的验证显示的是英文,改成中文文本时,如果不用国标解码,到时候提示框会出现乱码现象.所以一般需要中文显示的时候,我们应该这样做: 拿denied做 ...
- [翻译]Spring框架参考文档(V4.3.3)-第二章Spring框架介绍 2.1 2.2 翻译--2.3待继续
英文链接:http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/overview.ht ...
- 解剖SQLSERVER 完结篇 关于Internals Viewer源代码
解剖SQLSERVER 完结篇 关于Internals Viewer源代码 大家可能都用过Internals Viewer这个软件 <查看SQLSERVER内部数据页面的小插件Internals ...
- TableLayout表格布局详解
一.Tablelayout简介 Tablelayout类以行和列的形式对控件进行管理,每一行为一个TableRow对象,或一个View控件.当为TableRow对象时,可在TableRow下添加子控件 ...
- 淘宝上倒卖新浪微盘事件来龙去脉——谈谈巧用IMEI
这是一个老黄历的事件,曾记得淘宝上的卖家卖10元卖50g网络硬盘,并且卖的相当的火,一个月就卖了500个账号.由于我也是那个事件的亲身经历者之一,这里就看到了IMEI号在项目中防止作弊是何其的重要. ...
- 【转】MongoDB安全配置
[转自]http://drops.wooyun.org/%E8%BF%90%E7%BB%B4%E5%AE%89%E5%85%A8/2470 0x00 MongoDB权限介绍 1.MongoDB安装时不 ...
- Linux文件系统应用---系统数据备份和迁移(用户角度)
1 前言 首先承诺:对于从Windows系统迁移过来的用户,困扰大家的 “Linux系统下是否可以把系统文件和用户文件分开到C盘和D盘中” 的问题也可以得到完满解决. 之前的文章对Linux的文 ...
- 《你必须知道的.NET》读书笔记一:小OO有大智慧
此篇已收录至<你必须知道的.Net>读书笔记目录贴,点击访问该目录可以获取更多内容. 一.对象 (1)出生:系统首先会在内存中分配一定的存储空间,然后初始化其附加成员,调用构造函数执行初 ...