【问题标题】:How to insert values into linked list members on an hashtable如何将值插入哈希表上的链表成员
【发布时间】:2019-09-30 14:18:21
【问题描述】:

我有一个联系人结构插入到哈希表中的链表中。我不知道我是否正确定义了所有结构。 我基本上想在给定命令“a”时通过输入添加联系人(命令如下:姓名邮件电话)。 如果联系人已存在,我将无法添加该联系人。

我尝试使用链表创建哈希表的必要结构,但我只是不明白如何使用它。所以这个函数对我理解这个概念很有帮助。

这是我尝试过的结构

#define NOME_SIZE 1023
#define MAIL_SIZE 511
#define TELEFONE_SIZE 63
#define HASH_SIZE 1000

typedef struct contacts{
    char name[NOME_SIZE];
    char mail[MAIL_SIZE];
    char phone[TELEFONE_SIZE];
    struct contacts *next;
}HashList;


typedef struct hash_bucket{
    HashList *head, *tail; 
    int n_elements; 
}HashBucket;

HashBucket hashtable[HASH_SIZE]; 

如果我能成功添加联系人,我不希望有任何输出。 如果它已经存在,它应该返回一个错误,说明联系人已经存在

【问题讨论】:

  • 哈希表的目标是从键进行快速访问,即使是对无法达到目标的键进行排序的链表。或者hash_bucket 代表“同义词”列表?在那种情况下,哈希表在哪里?
  • @bruno 我认为在这种情况下,每个哈希表条目都有自己的链表来解决哈希冲突。
  • @IanAbbott 是的,这就是我想要的
  • 所以你有一个函数计算哈希然后你做%HASH_SIZE,在这种情况下我建议你使用HASH_SIZE的素数,这样可以得到更好的结果
  • @bruno 是的

标签: c linked-list hashtable


【解决方案1】:

来自您的代码和我的评论的建议。我删除了n_elements,因为对我来说它没用。我让 tail 但不确定它是否有用,因为您的列表只有一个 next 和一个 previous。我为 name, phonemail 设置了数组,但我认为最好使用 char *

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

#define NOME_SIZE 1023
#define MAIL_SIZE 511
#define TELEFONE_SIZE 63
#define HASH_SIZE 1000

typedef struct contacts{
    char name[NOME_SIZE];
    char mail[MAIL_SIZE];
    char phone[TELEFONE_SIZE];
    struct contacts *next;
}HashList;


typedef struct hash_bucket{
    HashList *head, *tail; 
    /* int n_elements; * I removed that field, it is useless */
}HashBucket;

HashBucket hashtable[HASH_SIZE]; 

// from https://stackoverflow.com/a/7666577/2458991
size_t hash(char * str)
{
  size_t hash = 5381;
  unsigned char c;

  while ((c = (unsigned char) *str++) != 0)
    hash = ((hash << 5) + hash) + c; /* hash * 33 + c */

  return hash;
}

HashList * createElt(char * n, char * m, char * p)
{
  HashList * e = malloc(sizeof(HashList));

  strncpy(e->name, n, NOME_SIZE - 1);
  e->name[NOME_SIZE - 1] = 0;

  strncpy(e->mail, m, MAIL_SIZE - 1);
  e->name[MAIL_SIZE - 1] = 0;

  strncpy(e->phone, p, TELEFONE_SIZE - 1);
  e->name[TELEFONE_SIZE - 1] = 0;

  e->next = NULL;

  return e;
}

// add or replace an element, the key is the name
// return 0 if the entry is added, else a non null value if the entry is (probably) modified
int insertElt(char * n, char * m, char * p)
{
  // suppose list sort on the name
  HashBucket * hb = &hashtable[hash(n) % HASH_SIZE];
  HashList ** hl = &hb->head;

  for (;;) {
    if (*hl == NULL) {
      /* last (and may be first) element */
      *hl = createElt(n, m, p);
      hb->tail = *hl;
      return 0;
    }

    int cmp = strcmp((*hl)->name, n);

    if (cmp == 0) {
      /* replace */
      strncpy((*hl)->mail, m, MAIL_SIZE - 1);
      (*hl)->name[MAIL_SIZE - 1] = 0;

      strncpy((*hl)->phone, p, TELEFONE_SIZE - 1);
      (*hl)->name[TELEFONE_SIZE - 1] = 0;

      return 1;
    }

    if (cmp > 0) {
      /* insert before */
      HashList * e = createElt(n, m, p);

      e->next = *hl;
      *hl = e;

      return 0;
    }

    hl = &(*hl)->next;
  }
}

void pr()
{
  for (size_t i = 0; i != HASH_SIZE; ++i)
    for (HashList * hl = hashtable[i].head; hl != NULL; hl = hl->next)
      printf("%s %s %s\n", hl->name, hl->mail, hl->phone);
}

int main()
{
  printf("%d\n", insertElt("n1", "m1", "p1"));
  printf("%d\n", insertElt("n2", "m2", "p2"));
  pr();
  printf("%d\n", insertElt("n1", "mm1", "pp1"));
  pr();

  return 0;
}

编译和执行:

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra -Wall hm.c
pi@raspberrypi:/tmp $ ./a.out
0
0
n1 m1 p1
n2 m2 p2
1
n1 mm1 pp1
n2 m2 p2

【讨论】:

  • 我应该在终端上发出命令'a name mail phone'。例如:'a bruno bruno@gmail.com 987654322' 所以我插入变量的函数应该是无效的,我应该使用 fgets() 或 scanf() 取决于什么是最有帮助的。主函数只应该这样说:'int main(){ char command;列表=空; while(1){ 命令 = getchar(); switch(command){ case'a': insertElt();休息;
  • @MiguelRibeiro 坦率地说,您可以修改代码来做到这一点,不是吗?这是微不足道的
  • 这非常有帮助!我只是在解释我应该有的东西。非常感谢
  • @MiguelRibeiro 好的,编码愉快
猜你喜欢
  • 2015-06-10
  • 2015-04-11
  • 2015-06-25
  • 2017-03-28
  • 2020-08-25
  • 1970-01-01
  • 1970-01-01
  • 2013-11-15
相关资源
最近更新 更多