• ベストアンサー

高速検索アルゴリズムとデータの追加・削除

現在高速検索のアルゴリズムを考えておりますが、 そこにデータの追加・削除が絡むと、 どのようにデータをまとめればいいのでしょうか? 例えば ------------ ------------ ------------- |data1|DATA1| |data2|DATA2| |data3|DATA3| ・・・ ------------ ------------ ------------- と要素を2つ持ったデータが複数存在した場合、 dataの昇順リスト ---------------------------- |Index|各データの先頭アドレス| ---------------------------- |・ |・ |・ DATAの昇順リスト ---------------------------- |Index|各データの先頭アドレス| ---------------------------- |・ |・ |・ というそれぞれのリストを持たせれば、 dataで検索したい場合、DATAで検索したい場合、 各リストのIndex値を用いて2分探索すれば高速だと考えました。 しかしデータの追加・削除があればそれぞれのリストを その度にソートし直さなければなりません。 もちろん追加・削除の度にデータ1つ分ずつずらしてやればいいだけですが、 基本的に使わない領域は解放したいですから、データ数の上限値が決まってない以上は 領域も確保されているとは限らないですから安易にデータをずらすことも出来ません。 データのずらしかたもどうでしょう? リストに加えるor削除する箇所からその時の最大値までをコピーして データ1つ分のサイズをずらして貼り付けるといった動作は、 連続した処理や排他的処理を考えると好ましくないのでしょうか? もし根本的に高速検索と追加・削除の相性が良い手法があればご教授願います。

質問者が選んだベストアンサー

  • ベストアンサー
  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.1

Baranced-Tree (平衡木)を使えば良いのではないでしょうか? 平衡木 - Security Akademeia http://akademeia.info/index.php?%CA%BF%B9%D5%CC%DA

uya_15
質問者

お礼

なるほど参考になりました。 構造が分かりやすくて、有効だと感じました。

その他の回答 (7)

  • don_go
  • ベストアンサー率31% (336/1059)
回答No.8

>現在高速検索のアルゴリズムを考えておりますが、 何と比べて「高速」なアルゴリズムを考えておられる のでしょうか? 目標をはっきりさせておかないと、既存の物より遅い のか速いのかさえ判別できないと思いますが? #高速検索にアセンブラを使用するという方法も一応 #ありますが....

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.7

蛇足ですけど^^ uya_15 さんは何度か質問を投げていらっしゃいますが、仕事としてプログラミングされているのなら、一度、アルゴリズム・データ構造の良書で勉強なさるのが、結局、早道で今後のためにもなるように思います^^ わたしは、古いテキストしか知りませんが、 ・A.V.エイホ 他 著、大野義夫 訳『データ構造とアルゴリズム』培風館 ・石畑清 著『アルゴリズムとデータ構造 (岩波講座 ソフトウェア科学)』岩波書店 などはいかがでしょう。A.V.エイホの『アルゴリズムの設計と解析』などもいいですが多少難しいですし、D.E.クヌースの『The Art of Computer Programming』はさらに難しいので、わたしはお薦めしません^^

uya_15
質問者

お礼

いくつかの高速検索のためのアルゴリズムには目を通しまして、 ただしっかり勉強だけを出来る時間の余裕もなかったので、しっかり理解できたのは2分木探索くらいでした。 またこのアルゴリズムはこういう時に最適だ!というところまで読みきれなかったので、 調べながらその傍らで質問させてもらいました。

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.6

すみません。参考にあげた URL では、<クローズドハッシュ>と呼んでいます^^; >『オープンハッシュ表(呼び方はいろいろ錯綜してるようですが)で持ってもいいと思います。』

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.5

あと、「基本的に使わない領域は解放したいですから…」とありますが、ちなみに、標準的な Unix 系のOSの malloc・free・realloc を使った実装は、free しても、システム自体に不要なメモリを返すわけではなく(プロセス自体の大きさは減少しない)、malloc・realloc で不要メモリの再利用ができるようにしているだけだと思います。brk・sbrk などを使えば、システムにメモリを返す(プロセス自体の大きさが減少する)ことができると思いますが、そうするとたぶん、malloc・free・realloc (これらが内部で sbrk を使っていると思うので)は使えなくなるのでやめたほうがいいと思います。windows は知りませんけど^^;

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.4

ご参考: 0. レコードを配列の要素として持つ必要がない。 1. レコードの記憶管理は別にする。 2. key、KEY 毎に一意にレコードが決まる。 3. key、KEY 毎に、ソート順に表示できたほうがいい。 とすると、以下のサンプルコードのようなやり方もあると思います。 1 で記憶管理も一緒にするとすれば insert・erase で new・delete するとか、2 でレコードが複数ある可能性があれば multimap にするとか、3 でソート順に表示しなくてもいい(ほとんど表示処理しないなら表示の際にソートして表示もいいですが)ならハッシュ表で実装してもいいですし。。まぁいろいろあると思いますけど^^ また、ソートされている必要がなく、レコードを配列要素として持つ必要がある(ただし、管理のためのメンバをレコードに追加できる場合)のなら、オープンハッシュ表(呼び方はいろいろ錯綜してるようですが)で持ってもいいと思います。 http://www-ui.is.s.u-tokyo.ac.jp/~takeo/course/2002/algorithm/note4.pdf ただ、すべて、主記憶に格納できる場合の話で、レコード・レコード数が巨大で外部記憶に格納しないとならない場合はまた別の方法によるのがいいと思います^^ ===(key==data、KEY==DATA なら map でなくて set でいい) #include <iostream> #include <string> #include <map> #include <utility> struct Record { std::string key; double data; int KEY; std::string DATA; }; std::map<std::string, Record *> map1; std::map<int, Record *> map2; Record *find(const std::string &k) { std::map<std::string, Record *>::iterator i = map1.find(k); if (i == map1.end()) return 0; return i->second; } Record *find(int k) { std::map<int, Record *>::iterator i = map2.find(k); if (i == map2.end()) return 0; return i->second; } bool insert(Record *r) { if (find(r->key) || find(r->KEY)) return false; map1.insert(std::make_pair(r->key, r)); map2.insert(std::make_pair(r->KEY, r)); return true; } template<typename T> bool erase(const T &k) { Record *r = find(k); if (!r) return false; map1.erase(r->key); map2.erase(r->KEY); return true; } void print(const Record *r) { std::cout << r->key << '\t' << r->data << '\t' << r->KEY << '\t' << r->DATA << '\n'; } void print1() { std::map<std::string, Record *>::iterator i = map1.begin(); while (i != map1.end()) { print(i->second); ++i; } std::cout << '\n'; } void print2() { std::map<int, Record *>::iterator i = map2.begin(); while (i != map2.end()) { print(i->second); ++i; } std::cout << '\n'; } #include <iostream> int main() { Record recs[] = { { "yamada", 0.0, 0, "taro" }, { "tanaka", 1.0, 1, "jiro" }, { "sato", 2.0, 2, "saburo" }, { "fujita", 3.0, 3, "taira" }, { "suzuki", 4.0, 4, "muneo" }, }; std::size_t nrec = sizeof recs / sizeof recs[0]; for (int i = 0; i < nrec; ++i) insert(recs + i); print1(); erase("fujita"); erase(1); print2(); } === % ./a.out fujita 3 3 taira sato 2 2 saburo suzuki 4 4 muneo tanaka 1 1 jiro yamada 0 0 taro yamada 0 0 taro sato 2 2 saburo suzuki 4 4 muneo

  • mikaemi
  • ベストアンサー率50% (33/65)
回答No.3

ソートしている目的が単に検索のためだけであれば、検索項目毎のハッシュ表を持つのもいいと思いますよ。ほかの用途に必要なのでソートされている必要があるのなら、検索項目毎にバランス木にするのがいいんじゃないでしょうか。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

普通は平衡木かなと思いますが場合によってはハッシュもあり? 平衡木といっても 2色木とか 2-3木とか 2-3-4木とかあって, プログラミングの難易度が違うので注意してください. 2-3木は組みやすい方かな. 2色木は図がないと苦労しそうな気がします.

uya_15
質問者

お礼

平衡木にもいろいろあるんですね。 時間のある時にでも、それぞれの長所を調べてみたいです。

関連するQ&A

  • リストの高速検索アルゴリズム

    1. Aを使用→Aを登録→(A=1) 2. Bを使用→Bを登録→(B=1,A=2) 3. Cを使用→Cを登録→(C=1,B=2,A=3) 4. Dを使用→Dを登録→(D=1,C=2,B=3,A=4) 5. Bを使用→順序のみ更新→(B=1,D=2,C=3,A=4) 6. 一番古いのを削除 →Aを削除→(B=1,D=2,C=3) 上記のような1000個のデータ(A,B…)を使用したら、使用履歴に登録していくプログラムを作るとして 高速に検索するには、どうすればよろしいでしょうか。 検索したいのは以下の2つです。 ・一番古いデータの検索(削除するため) ・データが登録有無の検索 汎用的な手法があればその名称をお教え願えないでしょうか。ちなみに二分木はちょっと違うような気がしました。

  • 検索アルゴリズム

     今、高速な検索アルゴリズムを探しています。  下記の条件のときに使えるアルゴリズムが何かないか、ご存知の方おしえてください。   1.データの順番は基本的にバラバラ   2.トゥリーやインデックスは検索の直前に作る  よろしくお願いします。

  • データ構造とアルゴリズム

    学校の課題なのですが、試験の得点順(降順)に学生番号と得点を表示することができるシステムを行っています。 仕様は下記の通りです。 外部仕様 1.試験の得点順(降順)に学生番号と得点を表示 2.機能メニュー(1:追加、2:削除、3:表示、1~3以外:終了)で操作できる 3.機能メニューの1:追加を選択すると、キーボードから学生番号と得点を入力することができる 4.機能メニューの2:削除を選択すると、キーボードから入力した学生番号のデータを削除することができる。 5.機能メニューの3:表示を選択すると、入力されているデータが、得点順に表示される 内部仕様 1. 使用言語はC言語とする 2. ダミーノードを使わない順方向リスト構造とする 3. リストのノードは構造体を使用する 4. リストのノードが常に得点の降順で並ぶように追加する 5. 入力データ型は、機能メニューを選択するための数字と得点は整数型、学生番号は文字列型とする 6. 先頭のノードのポインタを格納する変数名はheadとする 7. 全体の処理の流れは図1のとおりとし、【テンプレート・プログラム】の必要箇所に必要な機能を追加して完成させるものとする。テンプレート・プログラムで使用されている変数名は、そのまま使用すること。 8. 機能メニューは、関数名:menu()で表示する。menu()の仮引数は無し、戻り値は、キーボードから入力されたメニュー番号(整数)とする。 9. 機能メニューの1:追加では、関数名:insert()において先頭ノードから最後尾ノードに向けて順にキーボードから入力した得点と大小関係を比較し、得点の降順で並ぶように挿入位置を決めるためのアルゴリズムを考えて、新たなノードをリストに挿入する。関数名:insert()、仮引数:無し、戻り値:無し。なお、新しく追加するノードのポインタアドレスは変数pを使用する。追加する場所を探すために参照するノードのポインタアドレスは変数p2を使用する。 10. 機能メニューの2:削除では、関数名:del()においてキーボードから削除する学生番号を入力し、該当するノードを削除する。学生番号が見つからない場合は何もしない。関数名:del()、仮引数:無し、戻り値:無し。なお、文字列の比較には、strcmp()関数を使用する。 11. 機能メニューの3:表示では、関数名:disp()において先頭のノードから学生番号と得点を表示する。関数名:disp()、仮引数:無し、戻り値:無し。 この、追加機能のinsert、削除機能のdel、dispをどのように記述すればいいのかが分かりません。 分かる方宜しくお願いいたします。

  • データ構造とアルゴリズムの問題が分かりません。

    以下の問題で悩んでいます。 1 配列とリストでデータを末尾に追加する場合の時間計算量をO記法で表せ。 2 配列とリスト、それぞれの時間計算量以外の利点と欠点をなるべく多く挙げよ。 3 データ構造「スタック」、「キュー」を配列もしくはリストで実現した場合、それぞれの利点と欠点を挙げよ。 4 アルゴリズム「線形探索」、「二分探索」で特定のデータを検索するための時間計算量をO記法で表し、またその理由も記述せよ。 5 データを検索する操作のほうが多い場合と、データを追加する操作が多い場   合、 「線形探索」と「二分探索」どちらが有利か理由をつけて述べよ。 1は、挿入と削除はO記法で表せたのですが、追加が分かりませんでした。 2は配列の利点はランダムアクセス可能な点と任意のデータをすぐに扱える点の2点 リストの利点は扱うデータを自由に変えられる点の1点しか思いつかず、欠点はよく分かりませんでした。 3、4、5も理由をつけて説明しろと言われたら無理です。 テストに類題を出すと先生はおっしゃってたので、どうしてもすぐに回答が必要です。先生にも質問したのですが、テストに類題を出すから教えられない。自力で頑張れと言われ困っています。 どなたか御助力よろしくお願いいたします。

  • アルゴリズムのご相談2

    度々すいません。 また考え方の課題なんですけど、 各配列のDataの中に順不同なバラバラなデータが入っているときに、 その中から最も0に近いIndexでDataが空白になっている箇所を探すには、 どういった検索方法が高速なのでしょうか? この場合、頭から探すしかないのでしょうか? ---------------- | Index | Data ---------------- | 0 | 123 ---------------- | 1 | abc ---------------- | 2 | xyz ---------------- | 3 | ← ---------------- | 4 | 456 ---------------- | 5 | ---------------- | 6 | ABC ---------------- | 7 | XYZ ---------------- | 8 | 789 ---------------- | 9 | ijk ---------------- | … | …

  • LINE 友達削除した後に、また追加

    LINEでブロックリストから友達削除をしたあとに、またその相手を追加したい場合ID検索などがありますよね。 で、ID検索をして追加した場合、相手にはバレますか?「IDで追加されました」などの通知が相手に届くのでしょうか。 トーク履歴はないので、IDでばれないように追加したいです。

  • Excelグラフのデータの追加と削除について

    お世話になります。 商品名が項目軸で月が凡例のグラフを作成しています。 「データソースの選択」ダイアログボックスを使って1項目の系列要素ごと削除する(たとえば、パソコンという商品のデータのみ削除したい)場合、どのような方法がありますでしょうか?ダイアログボックスを使用しない方法でも良いのでお教え願います。 以下の条件でよろしくお願いいたします。  ・ グラフからは削除したいが元データ(表)は削除しない。  ・ コピーから形式を選択して貼り付けた追加データなので【行/列の切り替え】はできなくなっている。(追加データは大本の表とは別の場所(シートは同じ)につくったデータを使用)  ・ ダイアログボックスの系列欄にて系列の系列値を編集(追加データ分のみ削除)しようにもデータ量が多すぎて大変。  ・ 表データは行・列とも非表示はしたくない。

  • 表領域に追加したファイルの削除

    教えてください。 DB作成時にデフォルトで作成されていた「TEMP」と「CWMLITE」の表領域に誤ってデータファイルを追加してしまいました。 (TEMP02.dbf、CWMLITE02.dbfという風に) 追加したファイルを削除するには該当のデータファイルを オフラインにして実際にOS上からファイルを削除するという 手順で問題無いのでしょうか? それともOracle側でさらに処理が必要でしょうか?

  • Access フォームやレポートを作成したあとの追加

    たびたびお世話になります。 質問(1) Access2000で作成したフォームやレポートで、 後からクエリ上に情報を追加して、 その追加分を反映したい場合はどのようにすればよろしいのでしょうか。 単にテキストボックス等で反映されるだけのデータならよいのですが、 表示順を昇順に設定したので、その昇順どおりに レポートやフォームでも表示されてほしいのです。 レポートやフォームを設定する時に、表示を優先する設定があると思うのですが、 あとからそういったことは出来るのでしょうか。 前に詳しい人に聞いたときは、もう一度作ったほうが早いといわれました。 しかし、時間的な問題でそれが出来ないのです。 お知恵をいただけますと大変助かります。 質問(2)それから、複数人で入力しているのですが 排他的設定をしていないのにも関わらず 排他的になっているので開けませんといったようなエラーが出ることがあります。 デザイン画面を開こうとすると、そうなるのは分かるのですが、 入力でもそういうことがあるのでしょうか。 基本的なことばかりで申し訳ありません。 宜しくお願い致します。

  • C言語で、配列の要素を削除したい

    構造体からなる配列において、 データを追加/削除したいのですが、 どうしたらいいのでしょうか? 学校の課題なのですが、問題から読み取る限り リスト構造じゃなくて配列でつくるみたいなのです。。 追加データ数は限られてるので、数はだいじょうぶと 思うのですが、データを消したあと その消した部分をどうやってつめればいいですか?? また、数字を追加/削除した後に数字のならびを ソートして昇順にそろえなければいけないのですが、 バブルソート法では遅いでしょうか? (それしか習ってないのですが) 何かもっと早くできる方法があれば教えていただきたいです。 どうかよろしくお願いします!

専門家に質問してみよう