2016-04-30 15 views
-1

非常に大きなハッシュテーブル(100万以上のエントリを持つ)で動作するリハッシュ関数を作成しようとしていますが、現在の方法は非常に効率が悪いです。ここに私の構造は、ここで構造体配列をコピーするときにMemcpyがsegfaultを引き起こす

typedef struct { 
    int id, count, correct, valid; 
    char* word; 
} Entry; 

typedef struct { 
    Entry* arr; 
    int size, numValid; 
} Hash; 

が、それは(のmemcpyを使用していない、非常にゆっくりと)今働く方法です以下のとおりです。

void rehash(Hash* hash) { 
    Entry* tempArr; 
    int i; 

    tempArr = calloc(hash->size, sizeof(Entry)); 
    for(i = 0; i < hash->size; i++) { 
     if(hash->arr[i].count) { 
     tempArr[i].count = hash->arr[i].count; 
     tempArr[i].correct = hash->arr[i].valid; 
     tempArr[i].word = malloc(strlen(hash->arr[i].word) + 1); 
     strcpy(tempArr[i].word,hash->arr[i].word); 
     tempLen++; 
     } 
     memcpy(&tempArr[i],&hash->arr[i],sizeof(Entry)); 
     tempArr[i] = hash->arr[i]; 
    } 

    removeAllEntries(hash); 
    resize(hash); 


    for(i = 0; i < (hash->size/2); i++) { 
     if(tempArr[i].count > 0) { 
     addEntry(hash,tempArr[i].word,tempArr[i].count); 
     /*printf("Added %s with count %d\n",tempArr[i].word,tempArr[i].count);*/ 
     free(tempArr[i].word); 
     } 
    } 
    free(tempArr); 
} 

私はのmemcpyを使用することを好むだろうが、私は生活のためにすることはできません私はそれが正しく動作するようになる。

void rehash(Hash* hash) { 
    Entry* tempArr; 
    int i; 

    tempArr = calloc(hash->size, sizeof(Entry)); 

    fprintf(stderr,"size: %d\n",hash->size * sizeof(Entry)); 
    memcpy((tempArr),(hash->arr),hash->size * sizeof(Entry)); 

    removeAllEntries(hash); 
    resize(hash); 

    for(i = 0; i < (hash->size/2); i++) { 
    if(tempArr[i].count > 0) { 
     addEntry(hash,tempArr[i].word,tempArr[i].count); 
     /*printf("Added %s with count %d\n",tempArr[i].word,tempArr[i].count);*/ 
     free(tempArr[i].word); 
    } 
    } 
    free(tempArr); 
} 

私はそれが簡単に、1行の修正だと確信していますが、私:ここで私は(これは動作しないコードである、と私はで助けを探しています)しようとしてんですよ私はそれを見ることができません。

void addEntry(Hash* hash, char* tag, int count) { 
    int value = CHV(hash->size, tag), flag = 1, iter = 0; 
    int possIndex = findEntry(hash, tag); 
    /*fprintf(stderr,"AddEntry...\n");*/ 


    if(possIndex >= 0) { 
     (hash->arr[possIndex].count)++; 
     return; 
    } 



    if((hash->size - hash->numValid) < ((double)hash->size/10)) 
    { 
     rehash(hash); 
    } 
    while(flag) { 
     iter++; 
     if(!(hash->arr[value].valid)) { 
     hash->arr[value].word = calloc(strlen(tag) + 1, sizeof(char)); 
     strcpy(hash->arr[value].word, tag); 
     wordsAlloced++; 
     hash->arr[value].valid = 1; 
     hash->arr[value].correct = 1; 
     hash->arr[value].count = count; 
     flag = 0; 
     } 
     else { 
     value++; 
     if(value == hash->size) { 
      value = 0; 
     } 
     } 
    } 
    hash->numValid++; 
} 
+1

'Entry'と' Hash'の宣言を知っておくと便利でしょう –

+1

どのスニペットに問題がありますか?どちらを使用していますか?あなたの質問にはどのようなものがありますか? – alk

+1

あなたは 'Entry'の定義を見せたいと思っています。 – alk

答えて

1

memcpyは問題ありません。問題はすべて無料です。エントリはremoveAllEntries(hash);で、tempArr[i].wordfreefree(tempArr[i].word);になります。コピーされたポインタなのでです。 addEntry(hash,tempArr[i].word,tempArr[i].count);tempArr[i].wordを使用しても無効です。それはすでにfree 'です。


1つの解決策は、reallocの使用を提案しています。

目的のサイズを変更するために焼き直しません

void resize(Hash* hash) { 
    Entry* tempArr; 

    if((tempArr = realloc(hash->arr, 2 * hash->size * sizeof(Entry)))==NULL){ 
     fprintf(stderr,"failed realloc in resize.\n"); 
     return ; 
    } 
    hash->size *= 2; 
    hash->arr = tempArr; 
    //TOTALALLOC += (hash->size * sizeof(Entry)); 
} 

void resize(Hash* hash) { 
    free(hash->arr); 
    hash->size *= 2; 
    hash->arr = calloc(hash->size, sizeof(Entry)); 
    //TOTALALLOC += (hash->size * sizeof(Entry)); 
} 

を交換してください。


別の解決策

再ハッシュは、何らかの理由で必要な場合。 numValidが有効な登録番号を表している場合は、次の

void rehash(Hash* hash) { 
    Entry* tempArr; 
    int i; 

    tempArr = malloc(hash->size * sizeof(Entry));//Initialization isn't required because it is replaced by memcpy. 

    //fprintf(stderr,"size: %d\n",hash->size * sizeof(Entry)); 
    memcpy(tempArr,hash->arr, hash->size * sizeof(Entry)); 
    //To replicate word 
    for(i = 0; i < hash->size; i++) { 
     if(hash->arr[i].count) { 
      tempArr[i].word = malloc(strlen(hash->arr[i].word) + 1); 
      strcpy(tempArr[i].word, hash->arr[i].word); 
     } 
    } 
    removeAllEntries(hash); 
    resize(hash); 

    for(i = 0; i < (hash->size/2); i++) { 
     if(tempArr[i].count > 0) { 
      addEntry(hash,tempArr[i].word, tempArr[i].count); 
      /*printf("Added %s with count %d\n",tempArr[i].word,tempArr[i].count);*/ 
      free(tempArr[i].word); 
     } 
    } 
    free(tempArr); 
} 

に変更するには、私はそれだけでwordcountを保存するのに十分であると思います。

+0

それはうまく動作し、間違いなく少し速いようです。問題は、大きなハッシュサイズで再ハッシングを行うにはまだ時間がかかりますが、1回の再ハッシュは後で5分かかることです。どうすればこれを制限できますか? –

+0

@EvanCooperこの部分で改善しようとすると、再び 'word'と' count'(Untested)だけを処理するかどうかと思います。私はいくつかの時間は避けられないと思う何が必要なのは、大量のデータを再ハッシュすることです。 – BLUEPIXY

関連する問題