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これにより、出力が出力された dump 関数の特定の呼び出しがわかります。この関数は、基本的な検証も実行できます。たとえば、指定されたポインターが null でないことを確認し (ただし、それは出力されます)、ポインターが null でない場合にのみ構造の内容を明確に調べる必要があります。この関数は、ハッシュ テーブルが作成された直後に呼び出すことができ、各挿入操作の後に再度呼び出すことができます。これにより、コードが期待どおりに機能していることを確認できます。

関数をコード内に保持します。定期的にコンパイルされていることを確認し(古くならないように)、ハッシュテーブルで問題が発生した場合はいつでも使用してください。


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
于 2012-08-31T02:45:07.270 に答える