C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: 指定値を越える最初の要素を高速に検索したい


(過去ログ 122 を表示中)

[トピック内 5 記事 (1 - 5 表示)]  << 0 >>

■72975 / inTopicNo.1)  指定値を越える最初の要素を高速に検索したい
  
□投稿者/ キム (15回)-(2014/08/06(Wed) 16:49:40)

分類:[C#] 

お世話になります。

昇順ソート済みの配列で指定値を越える最初の要素のインデックスを高速に取得したいと思っています。
C#のバージョンは2010、.NET Framework は4 Client Profileです。

具体的には下記のような動作をさせたいです。

    double[] ar1 = { 0.0, 0.0, 1.0, 2.0, 2.0, 2.0, 4.0, 4.0, 4.0, 4.0 };
    double[] ar2 = { 0.0, 0.0, 1.0, 2.0, 3.0, 3.0, 4.0, 4.0, 4.0, 4.0 };
    double[] ar3 = { 0.0, 0.0, 1.0, 2.0, 3.0, 3.0,  };

    int index1 = Array.FindIndex(ar1, x => x > 3);  // 6が返る
    int index2 = Array.FindIndex(ar2, x => x > 3);  // 6が返る
    int index3 = Array.FindIndex(ar3, x => x > 3);  // -1が返る(見つからなかった)

御覧のようにArray.FindIndexで実現できることですが、計算量がO(n)になってしまいます。
与えられる配列の要素数は最大で3000ほどあります。
そこで、少しでも高速化するためにバイナリサーチを行いたいと考えています。

Array.BinarySearchで一致する要素が見つからなかった場合の仕様は下記の通りです。
・value より大きい値がある場合は、最初の大きい要素のインデックスのビットごとの補数
・value より大きい値が無い場合は、配列の要素数のビットごとの補数

このことを利用して、下記の実装を行いました。

まず、値が等しい場合に小さいと偽るIComparer<T>を実装しました。

    // 値が等しい場合に小さいと偽るIComparer実装
    public class GreaterCompare : IComparer<double>
    {
        public int Compare(double x, double y)
        {
            return (x <= y) ? -1 : 1;
        }
    }

そして、それを使って検索するメソッドを実装しました。

    // 指定値より大きい最初の要素のインデックスを返す(バイナリサーチ版)
    int FindGreater(double[] array, double value)
    {
        int index = ~Array.BinarySearch(array, value, new GreaterCompare());
        return (index < array.Length) ? index : -1; 
    }

GreaterCompareが値が等しい場合に小さいと偽るので、一致する値は絶対に見つかりません。
その結果、最初の大きい要素のインデックス(大きい値がない場合は要素数)のビットごとの補数が返ってきます。

これを加工して戻り値としています。

一通り試しましたが正常に動作しているようです。
が、もっと良い方法があるような気がしています。

これよりスマートで速い方法はありますでしょうか?
少しでも速くしたいのです。
#性能評価はまだ先ですが、クライアントからこの部分は出来るだけ速くという注文があるのです。

ヒントだけでもご教示いただけたら嬉しいです。
よろしくお願い致します。

引用返信 編集キー/
■72979 / inTopicNo.2)  Re[1]: 指定値を越える最初の要素を高速に検索したい
□投稿者/ shu (607回)-(2014/08/06(Wed) 17:40:18)
No72975 (キム さん) に返信
配列に入る値の範囲がそれほど大きくなければ
indexと配列を用意して
index[i] = 整数iがある最小のインデックス
のように値を設定する処理を対象配列ソート時に実行するのはどうでしょう?
引用返信 編集キー/
■72984 / inTopicNo.3)  Re[2]: 指定値を越える最初の要素を高速に検索したい
□投稿者/ キム (16回)-(2014/08/06(Wed) 20:07:50)
No72979 (shu さん) に返信

お返事ありがとうございます。

値の整数部分をハッシュ値とするハッシュテーブルを作るということですね。

いくつかサンプルデータをいただいているのですが、[0,1)の範囲に集中して分布しているものや、
一様に広範囲に分布しているものがあります。
なので、値の整数部分というわけには行きませんが、うまくハッシュ関数が定義できれば高速化できるかもしれません。

配列の生成とソートは呼び出し側が行っていますが、私の処理以外にも検索が必要な部分は多いと思いますので、
呼び出し側でハッシュテーブルを作って処理全体で活用すれば生成コストを引いても十分おつりが来るかもしれませんね。

パフォーマンス改善が必要になった場合の対策案の1つとしてクライアントにもお話してみます。

引用返信 編集キー/
■73118 / inTopicNo.4)  Re[3]: 指定値を越える最初の要素を高速に検索したい
□投稿者/ キム (17回)-(2014/08/20(Wed) 22:10:24)
No72984 (キム さん) に返信

結論が遅くなってごめんなさい。
結局、呼び出し側でハッシュテーブルを作るのが難しいということで、
最初に提示したバイナリサーチを用いた方法でいくことになりました。

今回は採用できませんでしたが、ハッシュテーブルについて勉強できて良かったです。
ありがとうございます。

引用返信 編集キー/
■73119 / inTopicNo.5)  Re[4]: 指定値を越える最初の要素を高速に検索したい
□投稿者/ キム (18回)-(2014/08/20(Wed) 22:13:58)
ごめんなさい、解決済みを付け忘れました。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -