0

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

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

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

4

1 回答 1

0

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

  1. return 1;在以前的 NULL 条目中插入新条目后,您不包括在内。
  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;
}

测试.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
于 2012-08-31T02:45:07.270 回答