【问题标题】:Hashtable searching, and command prompt weird error哈希表搜索和命令提示奇怪的错误
【发布时间】:2012-08-31 02:06:37
【问题描述】:

我正在尝试搜索哈希表,但遇到了一些问题。我的代码可以编译,但它有问题。我不太确定是什么。当我在命令提示符下运行它并将文件传递给程序时。我在搜索时遇到了一些问题

0 不真诚

struct htablerec {
   char **key;
   int *frequencies;
   int num_keys;
   int capacity;
};

static unsigned int htable_word_to_int(char *word) {
   unsigned int result = 0;
   while (*word != '\0') {
      result = (*word++ + 31 * result);
   }
   return result;
}

int htable_insert(htable h, char *str) {
   int i;
   /*convert string to integer*/
   unsigned int index = htable_word_to_int(str);
   /*calculate index to insert into hash table*/
   int remainder = index%h->capacity;
   /*once calculated position in the hash table, 3 possibilities occur*/
   /*no string in this positon, copy string to that position,
     increment number of keys, return 1*/
   if (h->key[remainder] == NULL) {
      char *key = emalloc(strlen(str) + 1);
      strcpy(key, str);
      h->key[remainder] = key;
      h->frequencies[remainder] = 1;
      h->num_keys++;
      return 1;
}

   /*the exact same string is at the position,
     increment frequency at that position,
     return frequency*/
   if (strcmp(str, h->key[remainder]) == 0) {
      h->frequencies[remainder]++;
      return h->frequencies[remainder];
   }/*a string is at that position, but it isnt the rightone,
      keep moving along the array until you find either an open
      space or the string you are looking for*/
   if (h->key[remainder] != NULL && strcmp(str, h->key[remainder]) != 0) {

      /*you may need to wrap back around to the beginning of the table,
        so each time you add,to the position you should also mod
        by the table capacity.*/
      for (i = 0; i < h->capacity; i++) {
         /*no string in this positon, copy string to that position,
           increment number of keys*/
         if (h->key[remainder] == NULL) {
            char *key = emalloc(strlen(str) + 1);
            strcpy(key, str);
            h->key[remainder] = key;
            h->frequencies[remainder] = 1;
            h->num_keys++;
         }
         /*if you find the string you were looking for,
           increment the frequency at the position
           and return the frequency*/
         if (strcmp(str, h->key[remainder]) == 0) {
            h->frequencies[remainder]++;
            return h->frequencies[remainder];
         }
         if (h->key[remainder] != NULL && h->capacity ==  i) {
            i = 0;
         }
      }   
   }
   /*if you have kept looking for an open space but there isnt one,
     the hash table must fu*/
   return 0;
   }

int htable_search(htable h, char *str) {
/*create an initialise, a value to hold the number of collisions we have when looking for our key*/
   int collisions = 0;
   unsigned int index = htable_word_to_int(str);
   /*calculate the position at which we should start looking for our key*/
   int remainder = index%h->capacity;

   /*while there is an item at that position, but it isn't the key, and we haven't yet checked the entire hash table*/
   while (h->key[remainder] != NULL && strcmp(str, h->key[remainder]) != 0 && h->key[remainder] != h->key[h->capacity]) {
   /*increment our position to look for the next cell*/
      h->key[remainder]++;
      /*increment the number of collisions we've had so far*/
      collisions++;
   }
   /*if our number of collisions == the hashtable capacity*/
   if(collisions == h->capacity) {
   /*then out hashtable was full, did not contain our key, so we should return 0*/
      return 0;
   }
   else {
   /*else return the frequency at our final position*/
      return h->frequencies[h->capacity];
   } 
}

#include <stdio.h>
#include <stdlib.h>
#include "mylib.h"
#include "htable.h"

int main(void) {
   htable h = htable_new(113);
   char word[256];
   char op;

   /*We must have a space before the %c*/
   while(2 == scanf(" %c %255s", &op, word)) {
   if ('+' ==  op) {
   htable_insert(h, word);
   }
   else if ('?' == op) {
   printf("%d %s\n", htable_search(h, word), word);
   }
   }

   htable_free(h);

   return EXIT_SUCCESS;
   }

我已经包含了上面的 mylib.c。

+ sociable
+ galleries
+ Russia
+ screamer
+ thickness
+ combed
+ escorted
+ revocable
+ digressed
+ Malawi
+ infringing
+ onslaught
+ files
+ kidded
+ unsound
+ tied
+ Ottawa
+ puzzles
+ build
+ necrosis
+ admire
+ cupful
+ brokers
+ segregation
+ Capet
+ Georges
+ bran
+ binders
+ zebras
+ contented
+ keypad
+ snowily
+ replaced
+ dominating
+ outright
+ Latinizers
+ invalidity
+ wakes
+ diversification
+ Riemannian
+ leadings
+ rhythmically
+ gentler
+ swarthy
+ disconnects
+ factoring
+ sequences
+ tiring
+ attendances
+ unloaded
? insincere
? constants
? unordered
? Toland
? butterfly
? suburban
? overtone
? Hauser
? numbers
? disadvantageous
? saintly
? Dutton
? homomorphic
? corporation
? climaxes
? dietitian
? manifestly
? greyest
? challenge
? tentacle
? Bernice
? bottle
? involve
? resisted
? wholesale
? trustworthiness
? Poole
? fourfold
? relentlessly
? fittingly
? doctorates
? cowlick
? Missoula
? curtsy
? calmness
? reallocate
? bossed
? scarce
? catheters
? regained
? autographing
? unobservable
? apprise
? lancer
? chicken
? crunches
? scrambled
? reared
? pealing
? violate
? sociable
? galleries
? Russia
? screamer
? thickness
? combed
? escorted
? revocable
? digressed
? Malawi
? infringing
? onslaught
? files
? kidded
? unsound
? tied
? Ottawa
? puzzles
? build
? necrosis
? admire
? cupful
? brokers
? segregation
? Capet
? Georges
? bran
? binders
? zebras
? contented
? keypad
? snowily
? replaced
? dominating
? outright
? Latinizers
? invalidity
? wakes
? diversification
? Riemannian
? leadings
? rhythmically
? gentler
? swarthy
? disconnects
? factoring
? sequences
? tiring
? attendances
? unloaded

这是我传入的文件的内容。我的插入方法有效,但如果需要,我也可以包含它。

【问题讨论】:

  • 由于您没有向我们展示任何打印任何内容的代码,也没有向我们展示函数htable_word_to_int(),并且由于我们不知道您的数据文件中有什么,因此我们不知所措可能出了什么问题。请制作一个SSCCE — 一个简短、独立、完整(编译)的示例。
  • 这不是错误...这是此调用的输出:printf("%d %s\n", htable_search(h, word), word);
  • 我看了之后才意识到,但是当我在命令行中运行程序时它确实会崩溃,因为它会打印出 0 insirere
  • @courtney 您正在从unsigned int 转换为signed int 以计算remainder。验证值是否正常。
  • @courtney 还要检查以确保 h-&gt;key[remainder]++; 是进行线性探测的正确方法。

标签: c hashtable


【解决方案1】:

您的一些问题在htable_insert() 内的for 循环中:

  1. 在以前的 NULL 条目中插入新条目后,您不包括 return 1;
  2. 您的环绕代码修改了错误的变量 (i)。我认为应该是:

    if (remainder >= h->capacity - 1)
        remainder = 0;
    else
        remainder++;
    
  3. 您在搜索代码中也遇到了大致相同的问题。


建议:

如果您有一个相对复杂的数据结构,例如哈希表,则值得创建(和调试)void dump_htable(FILE *fp, const char *tag, const htable h) 形式的函数。该函数会将结构内容的诊断转储打印到给定文件(通常为stdout,但有时为stderr 或日志文件),在信息前加上tag,以便您可以分辨出哪个特定调用输出来自的转储函数。该函数还可以进行基本的验证——例如,它应该确保给它的指针不为空(尽管无论如何它都会打印出来),并且显然应该只在指针不为空时检查结构的内容。您可以在创建哈希表后立即调用此函数,并在每次插入操作后再次调用此函数。这将允许您检查代码是否按预期工作。

将函数保留在代码中;确保它是例行编译的(因此它不会过时)并在遇到哈希表问题时使用它。


SSCCE — 工作代码

htable.h

#ifndef HTABLE_H_INCLUDED
#define HTABLE_H_INCLUDED

struct htablerec {
   char **key;
   int *frequencies;
   int num_keys;
   int capacity;
};

typedef struct htablerec *htable;

extern int htable_insert(htable h, char *str);
extern htable htable_new(unsigned size);
extern int htable_search(htable h, char *str);
extern void htable_free(htable h);

#endif /* HTABLE_H_INCLUDED */

htable.c

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

static void *emalloc(size_t size)
{
    void *space = malloc(size);
    if (space == 0)
    {
        fprintf(stderr, "Failed to allocate %zu bytes of memory\n", size);
        exit(EXIT_FAILURE);
    }
    return space;
}

static unsigned int htable_word_to_int(const char *word)
{
    unsigned int result = 0;
    while (*word != '\0')
    {
        result = (*word++ + 31 * result);
    }
    return result;
}

htable htable_new(unsigned size)
{
    htable h = emalloc(sizeof(*h));
    size_t nbytes = size * sizeof(*h->key);
    h->key = emalloc(nbytes);
    memset(h->key, '\0', nbytes);
    h->frequencies = emalloc(size * sizeof(*h->frequencies));
    h->capacity = size;
    h->num_keys = 0;
    return h;
}

void htable_free(htable h)
{
    if (h != 0)
    {
        free(h->frequencies);
        free(h->key);
        free(h);
    }
}

int htable_insert(htable h, char *str)
{
    int i;
    unsigned int index = htable_word_to_int(str);
    int remainder = index % h->capacity;

    for (i = 0; i < h->capacity; i++)
    {
        /* 1. No string at this position */
        if (h->key[remainder] == NULL)
        {
            char *key = emalloc(strlen(str) + 1);
            strcpy(key, str);
            h->key[remainder] = key;
            h->frequencies[remainder] = 1;
            h->num_keys++;
            return 1;
        }
        /* 2. the same string is already there */
        if (strcmp(str, h->key[remainder]) == 0)
        {
            h->frequencies[remainder]++;
            return h->frequencies[remainder];
        }
        /* 3. Keep searching */
        if (remainder >= h->capacity - 1)
            remainder = 0;
        else
            remainder++;
    }
    /* No match and no empty spaces left - hash table is full */
    return 0;
}

int htable_search(htable h, char *str)
{
    unsigned int index = htable_word_to_int(str);
    int remainder = index % h->capacity;

    for (int i = 0; i < h->capacity; i++)
    {
        if (h->key[remainder] == NULL)
            return -1;  /* Definitively not present */
        if (strcmp(str, h->key[remainder]) == 0)
            return remainder;   /* Definitively present */
        if (remainder >= h->capacity - 1)
            remainder = 0;
        else
            remainder++;
    }
    /* Table's full and key not found */
    return -1;
}

test.htable.c

#include "htable.h"
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>

static void dump_htable(FILE *fp, const char *tag, const htable h)
{
    fprintf(fp, "HASHTABLE: %s (0x%" PRIXPTR "\n", tag, (uintptr_t)h);
    if (h != 0)
    {
        fprintf(fp, "Capacity: %d; Number of keys: %d\n", h->capacity, h->num_keys);
        fprintf(fp, "Keys: 0x%" PRIXPTR "; Freq: 0x%" PRIXPTR "\n",
                (uintptr_t)h->key, (uintptr_t)h->frequencies);
        assert(h->key != 0 && h->frequencies != 0);
        if (h->num_keys > 0)
        {
            for (int i = 0; i < h->capacity; i++)
            {
                if (h->frequencies[i] != 0)
                {
                    assert(h->key[i] != 0);
                    fprintf(fp, "%3d: %2d  %s\n", i, h->frequencies[i], h->key[i]);
                }
            }
        }
    }
    fflush(fp);
}

int main(void)
{
    htable h = htable_new(113);
    char word[256];
    char op;

    /*We must have a space before the %c*/
    while(2 == scanf(" %c %255s", &op, word))
    {
        if ('+' ==  op)
        {
            if (htable_insert(h, word) <= 0)
                printf("Error: failed to insert %s\n", word);
            else
                dump_htable(stdout, word, h);
        }
        else if ('?' == op)
            printf("%d %s\n", htable_search(h, word), word);
        else
            printf("Bogus: %c %s\n", op, word);
    }

    htable_free(h);

    return EXIT_SUCCESS;
}

样本输出

哈希表的最后转储 - 用于检查 - 和结果。

HASHTABLE: unloaded (0x10F100910
Capacity: 113; Number of keys: 50
Keys: 0x10F100930; Freq: 0x10F100CC0
  2:  1  wakes
  7:  1  necrosis
  8:  1  galleries
  9:  1  Russia
 10:  1  Georges
 11:  1  outright
 13:  1  brokers
 16:  1  factoring
 17:  1  keypad
 18:  1  Latinizers
 19:  1  rhythmically
 20:  1  binders
 27:  1  sociable
 30:  1  Riemannian
 33:  1  gentler
 38:  1  segregation
 39:  1  invalidity
 43:  1  snowily
 47:  1  cupful
 48:  1  zebras
 49:  1  Capet
 50:  1  dominating
 51:  1  unloaded
 52:  1  unsound
 53:  1  revocable
 54:  1  tied
 58:  1  combed
 59:  1  leadings
 60:  1  bran
 61:  1  contented
 62:  1  sequences
 64:  1  replaced
 69:  1  escorted
 70:  1  infringing
 71:  1  onslaught
 72:  1  tiring
 75:  1  screamer
 80:  1  admire
 84:  1  build
 87:  1  Ottawa
 92:  1  Malawi
 93:  1  kidded
 94:  1  files
 95:  1  disconnects
 96:  1  puzzles
 97:  1  attendances
103:  1  diversification
104:  1  digressed
111:  1  swarthy
112:  1  thickness
-1 insincere
-1 constants
-1 unordered
-1 Toland
-1 butterfly
-1 suburban
-1 overtone
-1 Hauser
-1 numbers
-1 disadvantageous
-1 saintly
-1 Dutton
-1 homomorphic
-1 corporation
-1 climaxes
-1 dietitian
-1 manifestly
-1 greyest
-1 challenge
-1 tentacle
-1 Bernice
-1 bottle
-1 involve
-1 resisted
-1 wholesale
-1 trustworthiness
-1 Poole
-1 fourfold
-1 relentlessly
-1 fittingly
-1 doctorates
-1 cowlick
-1 Missoula
-1 curtsy
-1 calmness
-1 reallocate
-1 bossed
-1 scarce
-1 catheters
-1 regained
-1 autographing
-1 unobservable
-1 apprise
-1 lancer
-1 chicken
-1 crunches
-1 scrambled
-1 reared
-1 pealing
-1 violate
27 sociable
8 galleries
9 Russia
75 screamer
112 thickness
58 combed
69 escorted
53 revocable
104 digressed
92 Malawi
70 infringing
71 onslaught
94 files
93 kidded
52 unsound
54 tied
87 Ottawa
96 puzzles
84 build
7 necrosis
80 admire
47 cupful
13 brokers
38 segregation
49 Capet
10 Georges
60 bran
20 binders
48 zebras
61 contented
17 keypad
43 snowily
64 replaced
50 dominating
11 outright
18 Latinizers
39 invalidity
2 wakes
103 diversification
30 Riemannian
59 leadings
19 rhythmically
33 gentler
111 swarthy
95 disconnects
16 factoring
62 sequences
72 tiring
97 attendances
51 unloaded

【讨论】:

  • 哦,我认为当我将代码放入文件时,代码有点混乱,} 和 return 1 都在那里,但谢谢,我会看看。
  • 好的 - 如果问题中的内容与您正在编译的内容不完全一样,那么我们就很难找出问题所在。但是,如果您修复代码,我可能会删除此答案。创建dump_htable() 函数的建议仍然有效;这是我为调试您的代码而创建的,也是我使用自己的数据结构所做的。
猜你喜欢
  • 2012-10-02
  • 2018-02-18
  • 2013-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-30
  • 1970-01-01
  • 2014-04-07
相关资源
最近更新 更多