编译处理时,涉及变量及属性的管理 :插入(新变量的定义),查找(变量的引用)。
顺序查找 O(N) 二分查找 O(logN) 二叉树查找O(H) 平衡二叉树 O(logN)
如何快速查找?
查找的本质:已知对象找位置
有序的安排对象-》 全序:顺序查找 半序:二叉树
直接算出位置-》 散列查找
散列查找:1.计算位置。2.解决冲突。
一、计算位置 构造散列函数。 要求:计算简单;地址分布均匀。
数字关键词:1 直接定值。2 除留余数 h(key)= key mod p,p<tablesize且p为素数。3 数字分析法。 4 折叠法。 5平方取中法。
字符关键字:1 ASII码加和法 2 前3个字符移位法。3 移位法。
二、处理冲突
1. 开放地址法。(换个位置)
2.链地址法。(同一位置的冲突对象放在一起)
开放地址法
一旦发生冲突,就按照某种规则起找另一空地址。
若 发生了第i次冲突,试探性的将地址加di
线性探测:di=i 容易产生聚集现象
平方探测:di=+-i*i 有空间,但跳来跳去不一定能找到。 有定理显示,如果散列表长度是某个4k+3形式的素数时,平方探测就可以探查到整个散列空间。
双散列:di=i*h2(key) 对任意key,h2(key)!=0 h2(key )=p-(key mod p)
再散列:把散列表扩大,散列表扩大时,需要重新计算。
代码
散列表的创建:
1 #define MAXTABLESIZE 100000 /* 允许开辟的最大散列表长度 */ 2 typedef int Index; 3 typedef Index Position; 4 typedef enum { Legitimate, Empty, Deleted}EntryType; 5 6 typedef struct HashEntry cell;// 散列表单元定义 7 struct HashEntry 8 { 9 ElementType Data; //散列表单元中的数据 10 EntryType Info; // 散列表单元的信息 11 }; 12 typedef struct Tb1Node *HashTable;//散列表定义 13 struct Tb1Node 14 { 15 int TableSize; //散列表大小 16 cell *cells; //散列表数组,数组是散列表单元的集合 17 }; 18 int NextPrime(int X) 19 { 20 int i,P; 21 P = (X%2==0) ? X+1:X+2; //PC从x下一个数奇数开始 22 while(P< MAXTABLESIZE) // 23 { 24 for(i=(int) (sqrt(X));i<2;i--)//依次判断从根号x到2中是否有可以整除的 25 if(P%i==0) break; //说明不是素数,跳出for, 26 if(i==2)break; //判断是不是全都除了一遍,如果全都除了一遍,都不整除,说明是素数,跳出while 27 else P=P+2; //说明不是素数,继续从下一个奇数p+2继续查找。 28 } 29 return P; 30 } 31 HashTable HashTableCreate(int TableSize) 32 { 33 int i; 34 HashTable h; 35 h =(HashTable)malloc(sizeof( HashTable)); //申请散列表空间 36 h->TableSize=NextPrime(TableSize);//散列表的大小是比给定的tablesize大的素数 37 h->cells = (cell*)malloc(h->TableSize* sizeof( cell));//散列表中散列单元的 的数组申请空间 38 for(i=0;i<h->TableSize;i++) //将散列表中的数组中的信息赋值 39 h->cells[i].Info=Empty; 40 return h; 41 }
错误分析:
1.一定要检查函数的返回值!!!!不要漏掉29行
平方探测法:
1 Position Find(ElementType key,HashTable h) 2 { 3 Position NewPositon ,CurrentPosition; 4 int Count=0; 5 NewPositon=CurrentPosition=Hash(key,h->TableSize); 6 while(h->cells[NewPositon].Info!=Empty&&h->cells[NewPositon].Data!=key) 7 //当新位置的散列单元不是空而且散列单元数据不等于key 寻找下一位置 8 { 9 if(++Count%2)//判断计数器是奇数,di+i平方 10 { 11 NewPositon =CurrentPosition +(Count+1)*(Count+1)/4; 12 while(NewPositon>=h->TableSize)//新位置不能大于TableSize 13 NewPositon=NewPositon%h->TableSize; 14 } 15 else//判断计数器是偶数,di-i平方 16 { 17 NewPositon =CurrentPosition -Count*Count/4; 18 while(NewPositon<0)//新位置不能小于于TableSize 19 NewPositon=NewPositon+h->TableSize; 20 } 21 22 } 23 return NewPositon; 24 } 25 bool Insert(HashTable h,ElementType key) 26 { 27 Position p; 28 p=Find(key,h); 29 if(h->cells[p].Info!=Legitimate) 30 { 31 h->cells[p].Info=Legitimate; 32 h->cells[p].Data=key; 33 return true; 34 } 35 else 36 { 37 printf("键值已经存在 "); 38 return false; 39 } 40 41 }