字符串哈希表的一个实现

http://hi.baidu.com/%C2%F8%CD%B7%CA%C7%B0%FC%D7%D3/blog/item/e14e59d6105c552307088b92.html

 

 

怎么快速查找我要的资料呢

Description
招生考试,初试结束后,校方会贴出一张大榜单,上面是通过初试获得复试资格的考生名单。考生和家长一大早都来看榜,但是一面墙那么大的名单,要看很久才能看完。怎么能快一些呢?一般来说,名单按姓氏笔画或拼音字母排序,是一张有序表,这就让我们想到了基于有序表的二分查找算法 binarysearch, 而我们学计算机的知道还有一种叫做 哈希 的方法 hash。

这个问题就是要求 Acmer 实现在名单中快速查找某一姓名的算法。



Input
输入数据分为名单和询问两部分。

首先是名单部分,第一行是一个正整数 n (n<=500000), 表示名单中的人数。下面 n 行, 每一行有一个由大写字母A-Z和小写字母a-z组成的字符串,代表名单中的姓名。

然后是询问部分,第一行是一个正整数 m (m<=10000), 表示询问的次数。下面 m 行, 每一行有一个由大写字母A-Z和小写字母a-z组成的字符串,代表要查询的姓名。


输入中的每个字符串长度不超过10。


Output
对于每一次查询,如果要查询的字符串出现在名单中输出 "YES", 否则输出 "NO"。(注意不要加引号)
每一次查询占一行。


Sample Input

5
abc
edfg
x
a
Mike
3
Mike
bc
EDFG


Sample Output

YES
NO
NO



Hint
二分查找,hash 只是作为提示,并不要求一定要用它们来解题。

如果使用 map, set 等等, 很有可能超时,对于 Java 也是如此。

建议使用 scanf(), printf(), 有助于提高效率,对于 Java 任选输入方式。

注意,区分大小写,而且可能有相同的名字。

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

    上面是BOJ的1003题,最简单的方法是调用C下库函数 qsort 和 bsearch (stdlib.h),即首先对所有字符串快速排序,然后二分查找。提交后,Memory:6616K   Time:831MS。这么写很逆天。

    但既然题目点到了hash,对咱种初学者来说最好还是动动手实现下比较好。下面就贴出用哈希表解决这道题的代码:

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>

#define HashTableSize 650000

typedef struct Node HashNode;

struct Node {
            char * str;
            HashNode * next;
      };

//ELF Hash Function
unsigned int ELFHash(const char * str)
{
      unsigned int hash = 0;
      unsigned int x = 0;

      while (*str) {
                  hash = (hash << 4) + (*str++);

                  if ((x = hash & 0xF0000000L ) != 0) {
                              hash ^= ( x >> 24);
                              hash &= ~x;
                        }
            }

      return hash&0x7FFFFFFF;
}

void HashInsert(char * str, HashNode ** HashTable)
{
      int key;
      HashNode * tempA, * tempB;
      key = ELFHash(str) % HashTableSize;

      if (HashTable[key] == NULL) {
                  HashTable[key] = (HashNode *)malloc(sizeof(HashNode));
                  HashTable[key]->str = str;
                  HashTable[key]->next = NULL;
                  return;
            }

      tempA = HashTable[key];

      while (tempA != NULL) {
                  if (!strcmp(tempA->str, str)) return;

                  tempB = tempA;

                  tempA = tempA->next;
            }

      tempA = (HashNode *)malloc(sizeof(HashNode));

      tempA->str = str;
      tempA->next = NULL;
      tempB->next = tempA;

      return;

}

HashNode*  HashSearch(const char * str, HashNode ** HashTable)
{
      int key = ELFHash(str) % HashTableSize;
      HashNode * temp;

      if (HashTable == NULL || HashTable[key] == NULL) return NULL;

      temp = HashTable[key];

      while (temp != NULL) {
                  if (!strcmp(temp->str, str)) return temp;

                  temp = temp->next;
            }

      return NULL;

}

int  HashDelete(char * str, HashNode ** HashTable)
{
      HashNode * tempA, *tempB = NULL;
      int key = ELFHash(str) % HashTableSize;

      if (HashTable == NULL) return 0;

      tempA = HashTable[key];

      if (strcmp(tempA->str, str) == 0) {
                  HashTable[key] = tempA->next;
                  free(tempA);
                  return 1;
            }

      tempB = tempA->next;

      while (tempB->next) {
                  if (strcmp(tempB->str, str) == 0) {
                              tempA->next = tempB->next;
                              free(tempB);
                              return 1;
                        }

                  tempA = tempA->next;

            }

      return 0;
}

void HashDestory(HashNode *** HashTable)
{
      int i;
      HashNode * temp;

      for (i = 0;i < HashTableSize;i++) {
                  while ((*HashTable)[i] != NULL) {
                              temp = (*HashTable)[i];
                              (*HashTable)[i] = (*HashTable)[i]->next;
                              free(temp);
                        }
            }

      free(*HashTable);

      *HashTable = NULL;
}

HashNode ** HashInit(int size)
{
      HashNode ** HashTable = (HashNode **)calloc(size, sizeof(HashNode *));
      return HashTable;
}

void HashDisplay(HashNode ** HashTable)
{
      int i;
      HashNode * temp;

      if (HashTable) {
                  for (i = 0;i < HashTableSize;i++) {
                              printf("%d: ", i);
                              temp = HashTable[i];

                              while (temp) {
                                          printf("%s", temp->str);

                                          if (temp = temp->next) printf("-->");
                                    }

                              printf("/n");
                        }
            }

}

void main()
{
      char str[500000][11];
      char cmp[11];
      HashNode ** HashTable = NULL;
      int m, n, i;

      HashTable = HashInit(HashTableSize);
      scanf("%d", &n);

      for (i = 0;i < n;i++) {
                  scanf("%s", str[i]);
                  HashInsert(str[i], HashTable);
            }

      scanf("%d", &m);

      for (i = 0;i < m;i++) {
                  scanf("%s", cmp);

                  if (HashSearch(cmp, HashTable))
                        printf("YES/n");
                  else
                        printf("NO/n");
            }

      HashDestory(&HashTable);

}
提交后:Memory:9612K     Time:375MS
采用的是链地址法处理冲突,散列函数为ELFHash。
Hash表属于空间换时间的一种方法,明显可以看到时间减少了一半多。不过上面的程序空间上应该还可以再优化。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值