7.1.散列函数

散列是一种常见的存储数据的技术,按照这种方式可以非常迅速地插入和取回数据。散列所采用的数据结构被称为是散列表。尽管散列表提供了快速地插入、删除、以及取回数据的操作,但是诸如查找最大值或最小值这样的查找操作,散列表却无法执行地非常快。对于这类操作,其他数据结构会更适合.

 

7.2.选择散列函数

选择数组大小的时候,一个重要的原则就是要选择素数。

10007是素数,而且他没有大到会使用大量的内存来降低程序的内存。

下面例子中,散列函数SimpleHash利用霍纳(Horner)法则来计算(关于37的)多项式函数。

static void Main()
{
string[] names = new string[10007];
string name; string[] somenames = new string[]
{ "David", "Jennifer", "Donnie","Mayo",
"Raymond","Bernica","Mike", "Clayton","Beata","Michael"}; int hashVal; for (int i = 0; i < 10; i++)
{
name = somenames[i];
hashVal = SimpleHash(name, names);
names[hashVal] = name;
}
ShowDistrib(names); Console.Read();
} public static int SimpleHash(string s, string[]arr)
{
int tot = 0;
char[] cname;
cname = s.ToCharArray();
for (int i = 0; i < cname.GetUpperBound(0); i++)
{
tot += 37 * tot + (int)cname[i];
}
tot = tot % arr.GetUpperBound(0);
if (tot < 0)
{ tot += arr.GetUpperBound(0); }
return (int)tot;
} static void ShowDistrib(string[] arr)
{
for (int i = 0; i < arr.GetUpperBound(0); i++)
{
if (arr[i] != null)
{ Console.WriteLine(i+" "+arr[i]); }
}
}

 

7.3.查找散列表中数据

在散列表中查找数据,需要计算键的散列值,然后访问数组中的对应元素。这样的查找方式很明显要比逐个查找要效率的多。

 

7.4.解决冲突

7.4.1.桶式散列法

,是一种存储在散列表元素内的简单数据结构 ,它可以存储多个数据项。大多数实现中,这种数据结构就是一个数组,例如ArrayList类。

桶式散列法,最终要的事情,就是保持所用数组的数量尽可能地少。

插入一个数据项

用散列函数来确认用哪个数组(散列键)来存储数据项,然后查看此数据项是否已经在数组内。如果存在,就不做。如果不存在,就将数据项添加进这个数组。

移出一个数据项

用散列函数来确认用哪个数组(散列键)来移出数据项,然后查看此数据项是否已经在数组内。如果存在,就移出数据项。如果不存在,就不做。

7.4.2.开放定址法

开放定址函数会在散列表数组内寻找空单元来防止数据项。

两种不同的开放定址策略

线性探查

采用线性函数来确认试图插入的数组单元。顺次尝试单元直到找到一个空单元为止。

会出现的问题是数组内相邻单元中的数据元素会趋近成聚类,从而使得后续空单元的探查时间变得更长且效率更低。

平方探查

平方函数来确认要尝试哪个单元。

平方探查法的有趣属性是在散列表空余单元少于一半的情况下总能保证找到空的单元。

7.4.3.双重散列法

两个条件:散列函数不应该曾经计算到0,;表的大小必须是素数

 

7.5.5 Hashtable 类

可以实例化具有初始容量的散列表,或者使用默认容量。当然还可以同时指定初始容量和初始负载系数。

            Hashtable symbols = new Hashtable();
Hashtable symbols = new Hashtable(50);
HashTable symbols = new Hashtable(25, 3.0F);

 

7.5.1.从散列表中分别取回关键字和数值

Hashtable 类有两个非常有用的方法用来从散列表中取回关键字和数值:即 Keys 和 Values。这些方法创建了一个 Enumerator 对象,它允许使用 For Each 循环或者其他一些技术来检查关键字和数值。

Hashtable symbols = new Hashtable(25);
symbols.Add("salary", 100000);
symbols.Add("name", "David Durr");
symbols.Add("age", 45);
symbols.Add("dept", "Information Technology");
symbols["sex"] = "Male";
Console.WriteLine("The keys are: ");
foreach (Object key in symbols.Keys)
Console.WriteLine(key);
Console.WriteLine();
Console.WriteLine("The values are: ");
foreach (Object value in symbols.Values)
Console.WriteLine(value);

 

7.5.2.Hashtable 类的应用程序:计算机术语表

散列表的常见应用之一就是构造术语表或术语词典。本小节会举例说明使用散列表的一种方法就是为了这样一个应用—即计算机术语表。

程序首先从一个文本文件中读入一系列术语和定义。这个过程是在子程序 BuildGlossary 中编码实现的。文本文件的结构是:单词,定义,用逗号在单词及其定义之间进行分隔。这个术语表中的每一个单词都是单独一个词,但是术语表也可以很容易地替换处理短语。这就是用逗号而不用空格作分隔符的原因。此外,这种结构允许使用单词作为关键字,这是构造这个散列表的正确方法。

另一个子程序 DisplayWords 把单词显示在一个列表框内,所以用户可以选取一个单词来获得它的定义。既然单词就是关键字,所以能使用Keys 方法从散列表中正好返回单词。然后,用户就可以看到有定义的单词了。

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms; namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private Hashtable glossary = new Hashtable(); private void Form1_Load(object sender, EventArgs e)
{
BuildGlossary(glossary);
DisplayWords(glossary);
} private void BuildGlossary(Hashtable g)
{
StreamReader inFile;
string line;
string[] words;
inFile = File.OpenText(@"c:\111.txt");
char[] delimiter = new char[] { ',' };
while (inFile.Peek() != -1)
{
line = inFile.ReadLine();
words = line.Split(delimiter);
g.Add(words[0], words[1]);
}
inFile.Close();
}
private void DisplayWords(Hashtable g)
{
Object[] words = new Object[100];
g.Keys.CopyTo(words, 0);
for (int i = 0; i <= words.GetUpperBound(0); i++)
if (!(words[i] == null))
lstWords.Items.Add((words[i]));
} private void lstWords_SelectedIndexChanged(object sender, EventArgs e)
{
Object word;
word = lstWords.SelectedItem;
txtDefinition.Text = glossary[word].ToString();
}
}
}

数据结构和算法 – 7.散列和 Hashtable 类的更多相关文章

  1. JavaScript--数据结构与算法之散列

    散列:实现散列表的数据后可以快速地实现插入或者删除.但是对于实现查找操作则效率非常的低.散列表的底层是数组实现的,长度是预先设定,可以随时根据需求增加.所有的元素根据和该元素对应的键,保存在特定的位置 ...

  2. 数据结构与算法分析java——散列

    1. 散列的概念 散列方法的主要思想是根据结点的关键码值来确定其存储地址:以关键码值K为自变量,通过一定的函数关系h(K)(称为散列函数),计算出对应的函数值来,把这个值解释为结点的存储地址,将结点存 ...

  3. 非对称算法,散列(Hash)以及证书的那些事

    转载请注明出处 http://blog.csdn.net/pony_maggie/article/details/35389657 作者:小马 这几个概念在金融电子支付领域用得比較多,我忽然认为把它们 ...

  4. 散列之HashTable学习

    1,什么是散列? 举个例子,在日常生活中,你将日常用品都放在固定的位置,当你下次需要该东西时,直接去该地方取它.这个过程就相当于散列查找. 若将它们随意杂乱无章地存放,当需要某件东西时,只能一个地方一 ...

  5. 哈希表(散列)HashTable实现

    近期刷Leetcode发现凡是找字符串中反复字符或者数组中找反复数据的时候就不知道从何下手了. 所以决定学习一下哈希表解题.哈希表的原理主要是解决分类问题,hash表是介于链表和二叉树之间的一种中间结 ...

  6. 数据结构和算法 – 6.构建字典: DictionaryBase 类和 SortedList 类

      6.1.DictionaryBase 类的基础方法和属性 大家可以把字典数据结构看成是一种计算机化的词典.要查找的词就是关键字,而词的定义就是值. DictionaryBase 类是一种用作专有字 ...

  7. 数据结构和算法 – 番外篇.时间测试类Timing

    public class Timing { //startingTime--用来存储正在测试的代码的开始时间. TimeSpan startingTime; //duration--用来存储正在测试的 ...

  8. Java 散列集笔记

    散列表 散列表(hash table)为每个对象计算一个整数,称为散列码(hash code). 若需要自定义类,就要负责实现这个类的hashCode方法.注意自己实现的hashCode方法应该与eq ...

  9. 数据结构和算法(Golang实现)(26)查找算法-哈希表

    哈希表:散列查找 一.线性查找 我们要通过一个键key来查找相应的值value.有一种最简单的方式,就是将键值对存放在链表里,然后遍历链表来查找是否存在key,存在则更新键对应的值,不存在则将键值对链 ...

随机推荐

  1. MetadataType来帮助entity framework自动生成的代码进行标注

    真的是,用的时候就四处google,还是记在这里容易找 [MetadataType(typeof(Person.Metadata))] public partial class Person { pr ...

  2. 下一代GNU/Linux显示服务Wayland 1.12正式发布

    导读 最近,Bryce Harrington很高兴地宣布了“面向GNU/Linux操作系统的Wayland 1.12.0显示服务已正式发布”的消息.与它一同到来的,还有Weston 1.12.0合成器 ...

  3. PyCharm 入手第一记

    因为我是忠实的Linux用户,所以一下操作是在Linux下的完成,除了下载,因为Linux的下载着实有点让人捉急. PyCharm 下载地址: http://www.jetbrains.com/pyc ...

  4. BZOJ 3364: [Usaco2004 Feb]Distance Queries 距离咨询

    Description 一棵树,询问两点间距离. Sol 倍增. 方向没用. 没有然后了. Code /************************************************ ...

  5. backbone & django csrf_token的问题

    由于这个加入了token的验证,因此在backbone调用Model/Collection的save时会失败,错误403.(这里不讨论劫持重发的问题) 解决方案是:修改xmlHttpRequest的h ...

  6. webrtc开源项目音频重采样“不友好接口”的几点总结

    WebRTC(Web Real Time Communication)并不是Google原来自己的技术,在2010年,Google以大约6820万美元收购了VoIP软件 开发商Global IP So ...

  7. C# 毕业证书打印《六》

    整理思路,从新出发. 加载模版 public void loadtemplate(Label lable) { string p_tempateFile = @"fomate.xml&quo ...

  8. fstream的使用方法介绍

    转载自:  fstream的使用方法介绍 - saga's blog - C++博客 http://www.cppblog.com/saga/archive/2007/06/19/26652.html ...

  9. NGUI实现Sprite裁切成圆形或者椭圆形(不完美)

    先上效果 有个问题就是,UISprie用的Atlas的公用的材质,无法从当前要绘制的片段shader上获得uv百分比,所以当有其他的Sprite使用相同的Atlas时显示就有问题 其实Mesh是可以接 ...

  10. ThinkPHP增加数据库字段后插入数据为空的解决办法

    今天用ThinkPHP做了一个简单的商品发布系统,数据库本来只有四个字段id,name,url,image.id是主键,name是商品名称,url是商品链接,image是商品图片,做的差不多了,发现还 ...