算法导论 直接寻址表

来源:互联网 发布:大数据的发展阶段 编辑:程序博客网 时间:2024/06/14 22:47

算法导论 第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;}//插入keyvoid 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 10000int 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");    }    else        printf("delete failed\n");}```
0 0
原创粉丝点击