Hashtable搜索,命令提示奇怪的错误

时间:2012-08-31 02:06:37

标签: c hashtable

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

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

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

1 个答案:

答案 0 :(得分:0)

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

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

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


  4. 建议:

    如果您有一个相对复杂的数据结构,例如哈希表,则值得创建(和调试)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