hash表之拉链法处理冲突

来源:互联网 发布:csgo国服网络连接失败 编辑:程序博客网 时间:2024/05/24 01:46


/*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;
}



0 0
原创粉丝点击