算法导论 第11章 散列表

11.1 直接寻址表

如果某应用要用到一个动态集合,其中每个元素都是全域U={0,1….,m}中的一个关键字
为表示动态集合,使用数组。称为直接寻址表,记为T[m],其中每个位置称为一个槽slot,对应于全域中的一个关键字
槽k指向集合中一个关键字为k的元素。如果该集合中没有关键字为k的元素,则T[k]=NIL;

程序实现思路:

  • 可以用静态数组实现,因为数组的下标等于关键字,所以可以用数组存放对应的元素。有几个缺点:首先难以确定NULL,由于数组元素的类型是确定的,所以如何用某个数来表示NULL,表示数组中没有此元素,是一个问题。如果具体问题中,用不上其某个元素,可以使用该元素作为数组的NULL。
  • 用指针数组实现,该方法普适程度高,数组中的元素都是指针,指向结构体,该结构体有两个参量,一个是关键字key,一个是卫星数据satellite。如果没有该关键字,则可以为指针赋值NULL,较容易实现。

下面给出指针数组的C语言实现

```
#include<stdio.h>
typedef  int  Elemtype ;        //定义结构体中存储的元素类型   注:若要改变其元素类型,在print_hash()函数中对应的printf函数也要改变define MAX 100            //定义全集大小
typedef struct hash                 //定义结构体
{int key;                        //关键字Elemtype satellite;              //元素类型
}Hash;                                //结构体名称为Hash//查找一个给定关键字为key的元素
Elemtype Direct_address_search(Hash* a[],int key)
{if(a[key]==NULL)                                               //判断关键字是否在{printf("the key element is not in list\n");exit(0);}return a[key]->satellite;                                       //返回该关键字对应的数据
}   //插入一个元素
void Direct_address_insert(Hash* a[],Hash* x)
{a[x->key]=x;
}//删除一个元素
void Direct_address_delete(Hash* a[],Hash* x)
{a[x->key]=NULL;
}//打印直接寻址表
void print_hash(Hash* a[])
{   int i=0;while(i<MAX){if(a[i]!=NULL){printf("%d %d\n",a[i]->key,a[i]->satellite);}i++; }
}//测试函数
int main()
{Hash* data[MAX];int i;int x;//创建直接寻址表,并初始化为空for(i=0;i<MAX;i++)
{data[i]=(Hash*)malloc(sizeof(Hash));//   printf("%d\t",data[i]);data[i]=NULL;//   printf("%d\n",data[i]);}//给出元素(5,100),(2,200),(0,300)进行测试Hash* a=(Hash*)malloc(sizeof(Hash));a->key=5;a->satellite=100;Hash* b=(Hash*)malloc(sizeof(Hash));b->key=2;b->satellite=200;Hash* c=(Hash*)malloc(sizeof(Hash));c->key=0;c->satellite=300;Direct_address_insert(data,a);Direct_address_insert(data,b);Direct_address_insert(data,c);x=Direct_address_search(data,5);Direct_address_delete(data,a);print_hash(data);//释放内存for(i=0;i<MAX;i++)free(data[i]);free(a);free(b);free(c);return 0;
}
```

练习11.1-1

查找S中最大的数,需要遍历整个表,所以复杂度为O(n)
下面给出其代码:

```
Elemtype direct_address_Maxsearch(Hash* t[],int m)
{int i;Elemtype max;for(i=0;i<m;i++){if(a[i]!=NULL){ max=a[i]->satellite;break;}}if(i==m){printf("no element in the hast table\n");exit(0);}for(;i<m;i++){if(a[i]!=NULL&&a[i]->satellite>max)max=a[i]->satellite;}return max;
}
```

习题11.1-2 实现位向量

分析:题目中说用位向量来表示一个包含不同元素的动态集合,并且不需要卫星数据,所以就是给定一个集合,判断整型关键字是否在里面,位向量是0和1的数组。为了节省空间,用一个整型的32位来存储32个数,从0-31,并且该数应该是连续的。不连续的存储需要特定的hash函数来映射。对于给定总数大小n,如果要存储其n个数,用位向量来存储只需(n/32+1)个整型量,主要的操作是插入一个数,删除一个数,搜索一个数。
具体代码如下:

```
#include<stdio.h>
#include<stdlib.h>
#define BIT_INT 32
//定义该结构体
typedef struct bit_vector
{unsigned int* table;int size;
} Bitvector;
//初始化
Bitvector* bit_create(int size)
{Bitvector* bit=(Bitvector*)malloc(sizeof(Bitvector));bit->size=size/BIT_INT+1;bit->table=(unsigned int*)calloc(sizeof(int),bit->size);return bit;
}
//插入key
void Bit_insert(Bitvector* bit,int key)
{bit->table[key/BIT_INT]|=(1<<(key%BIT_INT));
}
//删除操作
void Bit_delete(Bitvector* bit,int key)
{bit->table[key/BIT_INT]&=~(1<<(key%BIT_INT));
}//返回值为1说明存在,为0说明不存在
int Bit_search(Bitvector* bit,int key)
{return (bit->table[key/BIT_INT]&(1<<(key%BIT_INT)))!=0;
}//打印元素值
void print_bit(Bitvector* bit)
{int i;int size=bit->size*BIT_INT;for(i=0;i<size;i++)if(Bit_search(bit,i)==1)printf("%d\n",i);printf("\n");
}
//释放内存
void Bit_destory(Bitvector* bit)
{free(bit->table);free(bit);
}int main()
{Bitvector* bit=bit_create(1024);int i,x;Bit_insert(bit,15);Bit_insert(bit,250);Bit_insert(bit,900);print_bit(bit);Bit_delete(bit,250);print_bit(bit);printf("------------------\n");x=Bit_search(bit,2);printf("sousuo :  %d\n",x);x=Bit_search(bit,900);printf("sousuo: %d\n",x);Bit_destory(bit);return 0;
}
```

参考来源:

习题11.1-3

分析:该题目可以用链表来解决。对于有相同key值的数,在该key值处用链表链接。

习题11.1-4

想法:
由于大数组太大,不能初始化,我们也就等于不知道到底哪里有真正的数据,于是乎数据不能存储在大数组中,因为你根本不知道到底哪里才是数据。
这里方式是:将数据存储到栈上,栈上的增删查都可以实现O(1),然后在大数组上,对应key的位置的元素,存放栈上对应的下标,这样根据key到大数组中找到栈的下标,然后根据栈的下标又可以找到那个key值对应的数据元素了。
然后,还需要解决如何判断数据是否有效的问题,这个也很简单,经过上面的查找过程,不难发现,如果该数据是有效的,需要满足以下几个条件:
1. key值对应到大数组中位置的值,必须位于[0,栈的栈顶位置]之间,否则肯定不是数据
2. 满足第1条之后,我们到栈上对应的位置,找到那个元素数据,它的key值要反过来等于我们原始的key值,否则表示这个数据也是不存在的.
参考来源
代码如下:

 ```
#include<stdio.h>
#define MAX 100
#define large_number 10000
int Hash[large_number];struct
{int Stack[MAX];int top;
} stack;void init(stack* s)
{s->top=-1;
}
//search the element k
int  search(int* hash,stack* s,int value)
{int num=hash[value];if(num>0&&num<=s->top&&s.Stack[num]==value)return num;return 0;
}void insert(int* hash,stack* s,int x)
{if(search(hash,s,x)!=0){printf("already exist\n");return ;}s->top++;s.Stack[s->top]=value;hash[value]=s->top;
}void delete(int* hash,stack* s,int value)
{int num=search(hash,s,value);if(num){int val=s->Stack[s->top];s->Stack[num]=val;s->top--;hash[val]=num;printf("delete successfully\n");}elseprintf("delete failed\n");
}
```

算法导论 直接寻址表相关推荐

  1. 假设一动态集合S用一个长度为m的直接寻址表T来表示。请给出一个查找S中最大元素的过程。(算法导论第十一章11.1-1)

    假设一动态集合S用一个长度为m的直接寻址表T来表示.请给出一个查找S中最大元素的过程.你所给的过程在最坏情况下的运行时间是多少. (算法导论第十一章11.1-1) #include "Key ...

  2. MIT算法导论公开课第七讲哈希表

    哈希表又称散列表,其定义是根据一个哈希函数将集合S中的关键字映射到一个表中,这个表就称为哈希表,而这种方法就称为Hashing.从作用上来讲,构建哈希表的目的是把搜索的时间复杂度降低到O(1),考虑到 ...

  3. 【算法导论33】跳跃表(Skip list)原理与java实现

    Skip list是一个用于有序元素序列快速搜索的数据结构,由美国计算机科学家William Pugh发明于1989年.它的效率和红黑树以及 AVL 树不相上下,但实现起来比较容易.作者William ...

  4. 算法设计与分析——散列表/哈希表(Hash Table):直接寻址表

    分类目录:<算法设计与分析>总目录 相关文章: ·散列表/哈希表(Hash Table)(一):基础知识 ·散列表/哈希表(Hash Table)(二):直接寻址表 ·散列表/哈希表(Ha ...

  5. 【MIT算法导论】哈希表、全域哈希

    哈希表及哈希算法 一. 直接寻址 1. 应用条件 当关键字的全域比较小时(也即:候选的关键字的数目较少),直接寻址法才是行之有效的. p.s. 借用下图,即U(全域)很小,那么需要存储的部分K(实际需 ...

  6. 算法导论程序24--直接寻址表(Python)

    当关键字的全域U比较小时,直接寻址是一种简单而有效的技术. 假设某应用要用到一个动态集合,其中每个元素都是取自全域U={0,1,...   ,m-1}中的一个关键字,这里m不是一个很大的数.另外,假设 ...

  7. 《算法导论》学习分享——11. 散列表(哈希表)

    11. 散列表(哈希表) 文章目录 11. 散列表(哈希表) 直接寻址表 散列表 链接法散列分析 散列函数 除法散列 乘法散列 全域散列 开放寻址法 线性探查 双重探查 开放寻址法分析 完全散列 涉及 ...

  8. 散列表(算法导论笔记)

    散列表 直接寻址表 一个数组T[0..m-1]中的每个位置分别对应全域U中的一个关键字,槽k指向集合中一个关键字为k的元素,如果该集合中没有关键字为k的元素,则T[k] = NIL 全域U={0,1, ...

  9. 基本数据结构(算法导论)与python

    Stack, Queue Stack是后进先出, LIFO, 队列为先进先出, FIFO 在python中两者, 都可以简单的用list实现, 进, 用append() 出, Stack用pop(), ...

最新文章

  1. 3.实现串口功能及消息邮箱
  2. gantt markdown
  3. Python学习(四)
  4. Thymeleaf提取公共页面(从实例入手,以inspinia模板为例)
  5. IOS 打包证书签名 shell脚本
  6. oracle 查看用户状态,Oracle数据库查看用户状态
  7. 哪些原因会导致rs485转换器信号受干扰?
  8. 文件系统ext3的文件大小限制
  9. 消息(5)——WSE增强的web服务套件,MTOM附件
  10. 单片机基础学-按键篇
  11. 计算机网络的服务资源管理器,MCSA学习指南-配置文件服务器资源管理器-文件服务器...
  12. 内向的人和陌生人聊天,如何做到有话可说
  13. 安全算法-对称加密与非对称加密
  14. 浅谈老妈的QQ号被盗之后
  15. 学会这几招,能找到90%以上的资源
  16. 钉钉 服务器 消息推送,【20210727 更新】 全能推送PushBot(原钉钉推送)支持企业微信,PushPlus,Bark...
  17. 【MM小贴士】SAP采购订单创建参考采购申请的强控
  18. 总结一些常见的国际标准化组织
  19. Spring整合Quartz集群部署
  20. 网络骗子的特征。大家一定要转载。

热门文章

  1. 修改windows的主机映射文件(hosts文件)
  2. 前端HTML点击图片放大效果展示
  3. [转]中国将建口径8米巨型太阳望远镜
  4. 【Delphi】中使用消息Messages(七)Android 系统消息
  5. 织梦dedecms橙色响应式月嫂保姆家政服务公司网站模板
  6. MySQL连接查询技术总结
  7. 计算机专业jsp项目,可练手
  8. C语言入门 九九乘法表
  9. Java代码审计——WebGoat CSRF (上)
  10. SQL Server 代理 显示异常,未开启