算法导论 直接寻址表

算法导论 第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");
    }
    else
        printf("delete failed\n");
}
```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值