2011-12-08 16 views
3

私は高水準言語のプログラミング経験があり、数週間前に(学術的理由で)プレーンCでコーディングを開始しました。私はmap<char,myStruct*>のようなデータ構造を実装したいと思います。プレーンCの単一文字からポインターへのマッピングの実装

これで十分ではない場合:可能なすべてのSINGLE charのどこかで定義した構造体へのポインタへの「マッピング」が必要です。 2 charが同じstructを指し示すことができないようにする方法があれば(地図上に新しい要素を挿入するときはcharをチェックせずに)、それはきちんとしていますが、それは厳密には必要ではありません。また、マップからペアリングを削除し、同じキーであるが異なるポインターでペアリングを再挿入できるようにする必要があります。

私はこれを考えて、すべての可能な文字の長さをポインタ配列として作成し、配列インデックスとしてcharを使用して対応するポインタを格納することができたと考えました。これはうまくいくかもしれませんが、私のアプリケーションで2つの文字だけを使用すると、そのアドレスに多くのスペースを割り当てるのは非効率的です。

まだ、私は他の解決策は考えられませんでした(私はC初心者だと考えていますが、驚くことではありません)。私は、たとえあいまいであっても、正しい方向への提案には感謝します。

+0

私はあなたがGlibライブラリを調べることをお勧めします - それはハッシュとあらゆる種類のものを含みます。あなたはそれらからいくつかのアイデアを "盗む"ことができます。 「テンプレート」が醜い場合は、厳密な型だけのマップを実装したい場合はそれほど難しくありません。純粋なCの "テンプレート"または "ジェネリックス"の背後にある一般的な考え方は、コンテナにstructの "sizeof"を伝えてそれを使用することです。 #defineマクロを使用して、アクセスする際に特定のタイプにマテリアルをキャストします。実際の構造体メモリは、char配列として格納されます。 – Matej

+0

基本的な考え方は、構造体を操作する関数を使用することです。構造体は、キーのサイズ、格納されたデータのサイズ、ハッシュ関数へのポインタ(設定可能にしたい場合)など、マップが表すマップについての特定のことを知る必要があります。これに関連したStandford semiからのいくつかのyoutubeビデオを見て、私がそれらを見つけることができるかどうかを見て覚えています。 – Corbin

+0

あなたが望むものはハッシュテーブルと呼ばれます。そして私の推測では、あなたのキーは文字列なので、charではなくchar *(普通のvoid * array [256];で実装できる)であろうということです。 – wildplasser

答えて

3

、最も簡単な方法は、単に文字データ型の最大値に等しい静的なサイズの配列を行うことです。

64と仮定すると
#include <limits.h> 
void * mapping[1u << CHAR_BIT]; 

8ビットのポインタと8ビットのcharの場合、これはマップ全体の8 * 256 = 2,048バイトのメモリを占有します(あなたが格納している "ユーザーデータ"は除く)。 64ビットシステム上で動作するプログラムでは、2 KBのメモリが簡単です。この実装の容易さとスピードは、無駄なメモリのバランスをよく取る必要があります。

配列の "物理的な"サイズを制限したい場合に最も簡単なことは、1文字をハッシュすることですが、次にハッシュの衝突を扱う必要があります。

struct ValueChain 
{ 
    struct ValueChain *next; 
    void *value; 
    char key; 
} 

#define MAP_SIZE 127 /* This should be prime. */ 
struct ValueChain* mapping[MAP_SIZE]; 

は、ここでは、ポインタ配列のサイズを半分にしましたが、各値のコストが増加している:

あなたのような何かを行うことができます。また、衝突した値を挿入するときに動的な割り当てが必要になります。

さらにコンパクトにすることができます。

#define MAP_SIZE 31 
struct ValueChain mapping[MAP_SIZE]; 

ここで、アレイ内の各値は、完全ValueChain「リストヘッダ」ではなく一方にだけポインタです。 64ビットマシンでは、mapping配列の場合はおそらく約558バイトが使用されますが、衝突を検出するまで動的割り当てを行う必要はありません。

これらのハッシュは、ちょうどconst char key = myChar % MAP_SIZE;に近似することができます。

+0

ありがとう、これは私が探していたものです。 – MHaaZ

0

あなたのキーは文字列であると仮定します。

まあ...自分で実装する必要がない場合は、don'tとしてください。

理論的にはそれほど難しいことではありません。

キーと値とオプションのリンクリストへのポインタを含む配列を作成します。

ハッシュマップにアクセスすると、ハッシュされたキーのモジュロをとります。これは、配列内の位置です。次に、ハッシュされていないキーと格納されたキーを比較して、衝突を検出する必要があります。彼らがあなたと一致すれば、それを見つけました。そうでない場合は、リンクされたリストをループし、一致するまでキーを比較する必要があります。

明らかにこれは簡単な実装であり、メモリを節約してパフォーマンスを改善するためにはるかに多くのことが可能です。 (コメンターが示唆されているようにして)あなたが言うのと同じように

+0

私の鍵は文字列ではありません。これは単一の文字であり、単純なものをハッシュする必要はありません(これを反映するためにタイトルを編集しました)。 – MHaaZ

0
struct myStruct array[1u << CHAR_BIT]; 

#define uchar_to_mystruct_ptr(c) (c >=0 && c < (1u << CHAR_BIT) ? &array[c] : NULL) 
+0

しかし、これは非常に大きい場合でも、存在する可能性がある各スタウトのスペースを予約することを意味します。私は組み込みシステムのために働いているので、マッピングに実際に挿入されている(char、pointer)ペアリングのためにメモリを使いたいだけです。 – MHaaZ

+0

あなたは*非常に少数のエントリー(例えば10..20)を持っていますか? {名前、値}のペアを持つテーブルを使用して、線形検索(またはバイナリ検索)を使用するだけです。 – wildplasser

+0

私はわずか10エントリーだけでなく、カップル数万を持っているかもしれません。私はメモリをできるだけきれいに保ち、未使用のスペースを避ける必要があります。 – MHaaZ

関連する問題