您的位置:首页 > 其它

hash表之拉链法处理冲突

2014-08-16 17:01 363 查看

/*hash表之拉链法处理冲突:*/

方法一:(不推荐)

#define ARRLEN 17

#define NAMELEN 20

#define ADDRLEN 20

typedef struct _rec

{

    char name[NAMELEN];

    char addr[ADDRLEN];

    struct _rec *next;

} rec;

//hash函数,线性定址法和余数法结合。

//得到的地址为数组的下标。

//count为hash表长,即模。

int hash(char *name, int count)

{

    int hashcode = 0;

    int i;

    int len = strlen(name);

    for(i = 0; i < len; i++)

    {

        hashcode = hashcode * i + name[i];

    }

    return hashcode % count ;

}

/*

添加一个记录,如果这个位置已有元素,则在该元素后拉链,添加到链中。

数组中的每个元素的值为 结构体元素的指针。

并且数组中的每个元素存储的指针域为带有头节点的链表的头节点。

数组中的每个元素时不存储数据域的,因为头节点没有数据域。

所以数组名为结构体元素的二级指针。

*/

void hash_insert(rec **hashtable, int count, rec *record)

{

    int hashcode = hash(record->name, count);

    rec *tmp;

//hash地址没有被占用,直接填充。

    if(hashtable[hashcode] == NULL)

    {

        if( (hashtable[hashcode] = (rec *)malloc(sizeof(rec))) == NULL)

        {

            fprintf(stderr, "malloc error\n");

        }

        else

        {

            strcpy(hashtable[hashcode]->name, record->name);

            strcpy(hashtable[hashcode]->addr, record->addr);

            hashtable[hashcode]->next = NULL;

        }

    }

    else

    {//被占用了,则填充在后面的链的结尾处。

        tmp = hashtable[hashcode];

        while(tmp->next != NULL)

        {

            tmp = tmp->next;

        }//定位到链尾。

       

        if( (tmp->next = (rec *)malloc(sizeof(rec))) == NULL)

            fprintf(stderr, "malloc error\n");

        else

        {

            strcpy(tmp->next->name, record->name);

            strcpy(tmp->next->addr, record->addr);

            tmp->next->next = NULL;

        }

    }

}

/*

hash_search:

*/

int hash_search(rec **hashtable, int count, rec *record)

{

    int hashcode = hash(record->name, count);

    rec *tmp = hashtable[hashcode];

    while(tmp != NULL)

    {

        if(strcmp(tmp->name, record->name) == 0)

        {

            strcpy(record->addr, tmp->addr);

            return hashcode;

        }

        //else tmp=temp->next;

    }

    return -1;

}

/*

删除某个记录,

*/

void hash_delete(rec **hashtable, int count, char *name)

{

    int hashcode = hash(name, count);

       

    rec *tmp1, *tmp2;

    //没有该记录。

    if(hashtable[hashcode] == NULL)

        return;

        //在第一个位置就找到记录。

    else if(hashtable[hashcode] != NULL &&

        strcmp(hashtable[hashcode]->name, name) == 0)

    {

        free(hashtable[hashcode]);

        hashtable[hashcode] = NULL;

    }

    else

    {

        tmp1 = hashtable[hashcode];

        while(tmp1->next != NULL && strcmp(tmp1->next->name, name) != 0)

            tmp1 = tmp1->next;

        if(tmp1->next != NULL)

        {

            tmp2 = tmp1->next;

            tmp1->next = tmp2->next;

            free(tmp2);

        }

    }

}

   

int menu_select(void)

{

    char s[80];

    int c;

    do

    {

        printf("1. Enter a record\n");

        printf("2. Search a record\n");

        printf("3. Delete a record\n");

        printf("4. Quit\n");

        printf("Enter a choice:\n");

        fgets(s, 80, stdin);

        c = atoi(s);

    } while(c < 1 || c > 5);

    return c;

}

void rec_insert(rec **hashtable, int count)

{

    rec tmp;

    int len;

    printf("Enter the name:\n");

    fgets(tmp.name, NAMELEN, stdin);

    printf("Enter the addr:\n");

    fgets(tmp.addr, ADDRLEN, stdin);

    len = strlen(tmp.name);

    if(tmp.name[len -1] == '\n')

        tmp.name[len - 1] = '\0';

   

    len = strlen(tmp.addr);

    if(tmp.addr[len -1] == '\n')

        tmp.addr[len -1] = '\0';

    tmp.next = NULL;

    hash_insert(hashtable, count, &tmp);

}

void rec_search(rec **hashtable, int count)

{

    rec tmp;

    int len;

    int loc;

    printf("Enter the name:\n");

    fgets(tmp.name, NAMELEN, stdin);

   

    len = strlen(tmp.name);

    if(tmp.name[len -1] == '\n')

        tmp.name[len -1] = '\0';

    if( (loc = hash_search(hashtable, count, &tmp)) != -1)

    {

        printf("%s\n%s\n", tmp.name, tmp.addr);

    }

    else

        printf("can not found\n");

}

void rec_delete(rec **hashtable, int count)

{

    char s[NAMELEN];

    int len;

    printf("Enter the name:\n");

    fgets(s, NAMELEN, stdin);

    len = strlen(s);

    if(s[len -1] == '\n')

        s[len -1] = '\0';

   

    hash_delete(hashtable, count, s);

}

int main(void)

{

    rec *a[ARRLEN];

    int choice;

    memset(a, 0, sizeof(a));

    while(1)

    {

        choice = menu_select();

        switch(choice)

        {

        case 1:

            rec_insert(a, ARRLEN);

            break;

        case 2:

            rec_search(a, ARRLEN);

            break;

        case 3:

            rec_delete(a, ARRLEN);

            break;

        case 4:

            exit(0);

        }

    }

}

----------------------------

(二)步骤:

(1)构建一个链表的节点的结构体ListNode;包含两个字段一个字段是 关键字,一个是next;

那么使用ListNode*类型的变量,就可以保存一个带有头节点的链表了。

(2)构建一个HashTable的结构体;包含两个字段,一个是hashTable的大小,size,还有一个是

ListNode*的数组 ListNode**  lists,即 lists[i] 就是 hash值为i的链表,i为通过hash函数得到的 hash地址 。

(注意:HashTable数组中的每个元素存储的是链表的 头指针,并没有包含关键字的值, 关键字都是存储在链表的头指针后面的节点中 )

(3)构造hash函数,如 int Hash(KeyType key, int prime);

取余法,得到地址,返回。

(4)初始化HashTable,数组中每个元素为链表的头结点。

(5)int hashSearch(HashTable h , KeyType key);

可有key,根据hash函数,得到key所指的链表的头指针,然后依次遍历该链表,看是否可以查到。

(6) hashInsert(HashTabel  h ,KeyType key)

首先调用hashSearch函数,如果,没有查找到,则插入。

---------------------------

方法二:(推荐)

/*

*哈希表 拉链法

*/

#include<stdio.h>

#include<stdlib.h>

#define MinTableSize 10

typedef int ElemType;

typedef unsigned int Index;

typedef struct ListNode

{

 ElemType element;

 struct ListNode *next;

}*Position;

typedef Position List;

/*

类型说明:

ListNode类型:

List=Position=ListNode*;

HashTbl*=HashTable;

List* TheLists,所以TheList是ListNode**类型的;

*/

typedef struct HashTbl

{

 int TableSize;

  List *TheLists;

}*HashTable;

/*因为表长通常都是prime*/

//这个写的好像不对。

int NextPrime(int N)

{

 int i;

 if(N%2==0)

  N++;

 for(;;N+=2)

 {

  for(i=3;i*i<=N;i+=2)

   if(N%i==0)

    return 0;

  return N; 

 }

}

/*hash函数*/

Index Hash(ElemType Key,int TableSize)

{

 return Key%TableSize;

}

/*

初始化hash表。

hash表的数组名是ListNode**;

表中的每个元素为listNode*;

初始化时每个元素都是一个空链,所以每个元素的next为null;

*/

HashTable InitializeTable(int TableSize)

{

 HashTable H;

 int i;

 if(TableSize<MinTableSize)

 {

  printf("Table size too small!\n");

  return NULL;

 }

 

 /*Allocate table*/

 H=(HashTable)malloc(sizeof(struct HashTbl));

 if(NULL==H)

   printf("Out of space!!!\n");

 H->TableSize=NextPrime(TableSize);

 

 

 H->TheLists=(List *)malloc(sizeof(List)*H->TableSize);

 if(NULL==H->TheLists)

 {

   printf("Out of space!!!\n");

   free(H);

   return NULL;

 }

 

 for(i=0;i<H->TableSize;i++)

 {

  H->TheLists[i]=(Position)malloc(sizeof(struct ListNode));

  if(NULL==H->TheLists[i])

   printf("Out of space!!!\n");

  else

   H->TheLists[i]->next=NULL;

  H->TheLists[i]->element=0;//哈希表中所有元素的key初始化为0

 }

 return H;

}

/*hash查找*/

Position Find(ElemType Key,HashTable H)

{

 Position p;

 List L;

 L=H->TheLists[Hash(Key,H->TableSize)];

 p=L->next;

 while(p!=NULL&&p->element!=Key)

  p=p->next;

 return p;

}

/*

hash插入

hashTable中的每个元素存储的是带有头节点的链表的头节点。

头节点的数据域是没有数据的。

所以如果一个存储一个数据,数据存储的是在hashTable元素的next节点中。

*/

void Insert(ElemType Key,HashTable H)

{

 Position pos,newCell;

 List L;

 pos=Find(Key,H);

 if(NULL==pos)/*没有找到关键字key*/

 {

  newCell=(Position)malloc(sizeof(struct ListNode));

  if(NULL==newCell)

    printf("Out of space!!!"); 

  else

  {

   L=H->TheLists[Hash(Key,H->TableSize)];

   newCell->next=L->next;

   newCell->element=Key;/*头插法*/

   L->next=newCell;

  }

 }

}

/*

删除hash表。

*/

void DestroyTable(HashTable H)

{

 int i;

 for(i=0;i<H->TableSize;i++)

 {

  Position p=H->TheLists[i];

  Position temp;

  while(p!=NULL)

  {

   temp=p->next;

   free(p);

   p=temp;

  }

 }

 free(H->TheLists);

 free(H);

}

void printHash(HashTable H,int len)

{

 int i;

 for(i=0;i<len;i++)

 {

  Position p=H->TheLists[i];

  while(p)

  {

   printf("address=%d value=%d\n",i,p->element);

   p=p->next;

  } 

 }

}

int main()

{

 

 HashTable H;

 Position p=NULL;

 int array[]={19,14,23,01,68,20,84,27,55,11,10,79};

 int len=sizeof(array)/sizeof(array[0]);

 int i;

 ElemType k;

         

 H=InitializeTable(len);

 for(i=0;i<len;i++)

 {

  Insert(array[i],H); 

 }

 printHash(H,len);

 printf("\n\n");

 

 printf("please input the value which need find:");

 scanf("%d",&k);

 p=Find(k,H);

 if(p)

   printf("%d",p->element);

 else

   printf("cannot find the value!");

 printf("\n\n");

 

 printf("free the table\n");

 DestroyTable(H);

 printf("it's done!!!");

 printf("\n\n");

 return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  拉链法