二、哈希查找
1.定义:哈希也称为散列,哈希查找的好处在于不用经过一系列的比较后才能确定位置。通过一个哈希函数可以快速定位存储位置,得到查找结果。
2.哈希冲突:不同关键字的多为数据元素映射到同一个存储位置,就导致哈希冲突。我们不可能使无限量的数据存储到有限的存储空间中,所以哈希冲突时不可避免的。
3.设计哈函数:直接定址法、除留余数法、平方取中法、折叠法。
4.避免哈希冲突的办法:线性开放寻址法、拉链法。这里采用拉链法来完成哈希查找。
myHashTable.cs
Code
using System;
namespace search{
public class myHashTable
{
public OneLinkNode[] table; //哈希基表数组
public int size; //哈希基表的数组容量
public myHashTable(int n) //构造函数,分配哈希基表的存储单元
{
size = n;
table=new OneLinkNode[size];
for(int i=0;i<size;i++)
{
table[i]=new OneLinkNode();
}
}
public int hash(int k) //哈希函数,除留余数法
{
return k%size;
}
public void insert(int k) //哈希表中插入k值
{
OneLinkNode q;
int i=hash(k);
//Console.Write(table[i].data);
if(table[i].data==0) //该位置上没有数据元素
table[i].data=k; //k值存入哈希基表
else //产生冲突时
{
q=new OneLinkNode(k); //k值节点插入哈希链表
q.next=table[i].next; //q节点作为哈希链表的首节点
table[i].next=q; //哈希链表的头指针存入哈希基表
}
}
public OneLinkNode hashSearch(int k)
{
int i=hash(k);
// Console.Write(i);
if(table[i].data == 0)
return null;
else
if(k==table[i].data) //k在哈希基表中
return table[i]; //返回节点地址
else //k在哈希链表中
{
OneLink link = new OneLink(10);
link.head=table[i].next;
//link.output();
OneLinkNode p = new OneLinkNode();
p=link.Search(k); //哈希链表中查找k
//Console.Write(p.data);
link.head = null; //设置链表为空
return p; //返回在哈希链表中查找k的结果
}
}
public bool remove(int k)
{
return false;
}
public void output(myHashTable ht)
{
for(int i=0;i<ht.size;i++)
{
Console.Write("table["+i+"]= "+ht.table[i].data+" ");
OneLink link = new OneLink(size);
link.head=ht.table[i].next;
link.output();
link.head=null;
}
}
public static void Main()
{
myHashTable mht = new myHashTable(10);
int[] key = {9,4,12,3,1,14,74,6,16,96};
for(int i=0;i<10;i++)
{
Console.Write(key[i]+" ");
mht.insert(key[i]);
}
Console.WriteLine();
mht.output(mht);
Console.WriteLine();
int k = 96;
OneLinkNode find = mht.hashSearch(k);
Console.WriteLine("find: "+k);
if(find!=null)
Console.WriteLine(find.data);
else
Console.WriteLine("null");
}
}
}
因为用到了单链表,之前又没写,所以只好自己动手再写两个:
OneLinkNode.cs
Code
using System;
namespace search
{
public class OneLinkNode
{
public int data=0;
public OneLinkNode next;
public OneLinkNode(int k,OneLinkNode nextNode)
{
data = k;
next = null;
}
public OneLinkNode(int k)
{
data = k;
next = null;
}
public OneLinkNode()
{
data = 0;
next = null;
}
/*
public void output()
{
next = new OneLinkNode();
next.data=10;
Console.Write(next.data);
}
public static void Main()
{
OneLinkNode olk = new OneLinkNode();
olk.output();
}
*/
}
}
OneLink.cs
Code
using System;
using search;
namespace search{
public class OneLink
{
public OneLinkNode head;
public OneLink(int n)
{
int i= 1;
head = null;
OneLinkNode rear,q;
head=new OneLinkNode(i++);
rear=head;
while(i<=n)
{
q=new OneLinkNode(i++);
rear.next=q;
rear=q;
}
}
public bool isEmapty()
{
return head==null;
}
public bool isFull()
{
return false;
}
public int length()
{
int i=0;
OneLinkNode p=head;
while(p!=null)
{
i++;
p=p.next;
}
return i;
}
public OneLinkNode index(int i)
{
if(i<=0) return null;
int j=0;
OneLinkNode p=head;
while(p!=null && j<i)
{
j++;
p=p.next;
}
return p;
}
public int get(int i)
{
OneLinkNode p=index(i);
if(p!=null)
return p.data;
else
return -32768;
}
public bool set(int i,int k)
{
OneLinkNode p=index(i);
if(p!=null)
{
p.data=k;
return true;
}
else
return false;
}
public OneLinkNode Search(int k)
{
OneLinkNode p = head;
while(p!=null)
{
if(p.data==k)
return p;
else
p=p.next;
}
return p;
}
public void output(OneLinkNode p)
{
while(p!=null)
{
Console.Write(p.data+" ");
p=p.next;
}
Console.WriteLine();
}
public void output()
{
output(head);
}
}
}
这里有几个好玩的东西,一个是C#中用来替代指针方法的问题比较突出;还一个是关于访问权限的问题,gray告诉我:“记住私有是指对类型私有,不是对对象私有”,虽然有点模糊,但起码有点明白了。以前因为访问性的问题,我把所有的成员访问权限设置为公有,太懒写属性访问器了。