東方算程譚

Oriental Code Talk ── επιστημηが与太をこく、弾幕とは無縁のシロモノ。

目次

Blog 利用状況

ニュース

著作とお薦めの品々は

著作とお薦めの品々は
東方熱帯林へ。

別館: 茶ネタなら
恵比寿亭茗茶楼

あわせて読みたい

わんくま

  1. 東京勉強会#2
    C++/CLI カクテル・レシピ
  2. 東京勉強会#3
    template vs. generics
  3. 大阪勉強会#6
    C++むかしばなし
  4. 東京勉強会#7
    C++むかしばなし
  5. 東京勉強会#8
    STL/CLRによるGeneric Programming
  6. TechEd 2007 @YOKOHAMA
    C++・C++/CLI・C# 適材適所
  7. 東京勉強会#14
    Making of BOF
  8. 東京勉強会#15
    状態遷移
  9. 名古屋勉強会#2
    WinUnit - お気楽お手軽UnitTest

CodeZine

  1. Cで実現する「ぷちオブジェクト指向」
  2. CUnitによるテスト駆動開発
  3. SQLiteで組み込みDB体験(2007年版)
  4. C++/CLIによるCライブラリの.NET化
  5. C# 1.1からC# 3.0まで~言語仕様の進化
  6. BoostでC++0xのライブラリ「TR1」を先取りしよう (1)
  7. BoostでC++0xのライブラリ「TR1」を先取りしよう (2)
  8. BoostでC++0xのライブラリ「TR1」を先取りしよう (3)
  9. BoostでC++0xのライブラリ「TR1」を先取りしよう (4)
  10. BoostでC++0xのライブラリ「TR1」を先取りしよう (5)
  11. C/C++に対応した、もうひとつのUnitTestFramework ─ WinUnit
  12. SQLiteで"おこづかいちょう"
  13. STL/CLRツアーガイド
  14. マージ・ソート : 巨大データのソート法
  15. ヒープソートのアルゴリズム
  16. C++0xの新機能「ラムダ式」を次期Visual Studioでいち早く試す
  17. .NETでマンデルブロ集合を描く
  18. .NETでマンデルブロ集合を描く(後日談)
  19. C++/CLI : とある文字列の相互変換(コンバージョン)
  20. インテルTBBによる選択ソートの高速化
  21. インテルTBB3.0 によるパイプライン処理
  22. Visual C++ 2010に追加されたSTLアルゴリズム
  23. Visual C++ 2010に追加されたSTLコンテナ「forward_list」
  24. shared_ptrによるObserverパターンの実装

@IT

  1. Vista時代のVisual C++の流儀(前編)Vista到来。既存C/C++資産の.NET化を始めよう!
  2. Vista時代のVisual C++の流儀(中編)MFCから.NETへの実践的移行計画
  3. Vista時代のVisual C++の流儀(後編) STL/CLRによるDocument/Viewアーキテクチャ
  4. C++開発者のための単体テスト入門 第1回 C++開発者の皆さん。テスト、ちゃんとしていますか?
  5. C++開発者のための単体テスト入門 第2回 C++アプリケーションの効率的なテスト手法(CppUnit編)
  6. C++開発者のための単体テスト入門 第3回 C++アプリケーションの効率的なテスト手法(NUnit編)

AWARDS


Microsoft MVP
for Visual Developer - Visual C++


Wankuma MVP
for いぢわる C++


Nyantora MVP
for こくまろ中国茶

Xbox

Links

記事カテゴリ

書庫

日記カテゴリ

データ構造なめんな

ネタ元 → 例外に依存するロジックは駄目ですよ

ほほぉ、なかなかに興味深い実験でございます。

 「このケースのように、事前に対象データの絞り込みは言語で
  行うほうが良いケースもあります。」

SQLわからんちんの僕には胸のすく思い

もちっと速くなるかもしんないなーってんでちょいと実験です。


using System;
using System.Collections.Generic;
using System.Diagnostics;

class Program {

  static long AddUnique<T>(IEnumerable<T> src, ICollection<T> dst) {
    Stopwatch watch = Stopwatch.StartNew();
    foreach ( T item in src ) {
      if ( !dst.Contains(item) ) { // 重複なければ
        dst.Add(item); // 追加
      }
    }
    watch.Stop();
    return watch.ElapsedMilliseconds;
  }

  public static void Main() {
    int N = 100000; // 要素数
    int M = 10000; // 値の上限
    // 元ネタ生成
    int[] src = new int[N];
    var r = new Random();
    for ( int i = 0; i < N; ++i )src[i] = r.Next(M);
    // 3つのCollectionで比べてみよう
    Console.WriteLine("LinkedList : {0}[ms]",AddUnique(src, new LinkedList<int>()));
    Console.WriteLine("List       : {0}[ms]",AddUnique(src, new List<int>()));
    Console.WriteLine("HashSet    : {0}[ms]",AddUnique(src, new HashSet<int>()));
  }
}

実行結果:
LinkedList : 4729[ms]
List       : 3503[ms]
HashSet    : 17[ms]

Hashすげー

投稿日時 : 2009年12月6日 1:13

コメントを追加

# それ LINQ で 2009/12/06 9:30 NyaRuRu

Linq to Object の Distinct が,AddUnique に比べて十分早いので,
Console.WriteLine("LinkedList : {0}[ms]",AddUnique(src.Distinct(), new LinkedList<int>()));
Console.WriteLine("List : {0}[ms]",AddUnique(src.Distinct(), new List<int>()));
Console.WriteLine("HashSet : {0}[ms]",AddUnique(src.Distinct(), new HashSet<int>()));

とするだけでもかなり高速化します.

そもそも,今回の例だと
var dest = src.Distinct();
だけで事足りて,所要時間も HashSet 版より 1 桁小さいです.
ご参考までに.

# re: データ構造なめんな 2009/12/06 10:18 επιστημη

へー、Distinctすげー。
どんな実装になってんだろ。
結局は上記AddUniqueと同様のことやるしかないと思うんだけど...

# re: データ構造なめんな 2009/12/06 13:07 NyaRuRu

あーすみません.

>そもそも,今回の例だと
>var dest = src.Distinct();
>だけで事足りて,所要時間も HashSet 版より 1 桁小さいです.

の速度計測の部分を間違っていて,ToList() or ToArray() を行わずに測ったものになっていました.
Distinct 版が速く見えたのは,単に Distinct が Lazy に実装されているだけです.
ToList() で評価して,HashSet 版より若干遅いか同程度でした.

# re: データ構造なめんな 2009/12/06 13:46 NyaRuRu

もう一点,

> Console.WriteLine("HashSet : {0}[ms]",AddUnique(src.Distinct(), new HashSet<int>()));

で速くなるってのも間違ってましたね.すんません.

あと,HashSet 版の結果ぐらいの短時間になると,初回実行時のオーバーヘッドが無視できないようですね.
Console.WriteLine("HashSet : {0}[ms]",AddUnique(src, new HashSet<int>()));
Console.WriteLine("HashSet : {0}[ms]",AddUnique(src, new HashSet<int>()));
という感じで二回実行すると差がだいぶ見えてしまいます.

# re: データ構造なめんな 2009/12/06 16:32 επιστημη

納得しましたありがとです。
Hashよりひとケタ速いてどないな実装や!? て不思議に思うてましたです。

# re: データ構造なめんな 2009/12/06 22:07 NyaRuRu

蛇足ですみませんが,

>Hashよりひとケタ速いてどないな実装や!? て不思議に思うてましたです。

一桁ってことはないですが,N = 100000, M = 10000 ぐらいのオーダーだと、
static long AddUnique<T>(IEnumerable<T> src, ICollection<T> dst)

static long AddUnique<T>(T[] src, ICollection<T> dst)
に変えるだけで Hash 版の速度は 2 割ぐらい変わります.
(配列に対する foreach は最適化されるため)

また,上に書いたように初回実行と2回目の実行で 50% ぐらい所要時間が違います.
この辺りのオーバーヘッドを除外して,アルゴリズムの違いを議論するためには,N = 100000, M = 10000 はすこし小さすぎるかもしれませんね.

# re: データ構造なめんな 2009/12/06 22:50 ognac

Hashも奥が深いですね。いってみれば、メモリ内索引テーブルですものね。
List.Contains (配列.Contains)だと、順次Checkなので、データ量が増えると不利かぁ。

# [C#][Other]人のソースコードは読むもんだと感じた 2009/12/07 11:00 かずきのBlog

[C#][Other]人のソースコードは読むもんだと感じた

# HashSetのコスト 2010/02/01 0:04 Ognacの雑感

HashSetのコスト

# HashSetのコスト 2010/02/01 0:05 Ognacの雑感

HashSetのコスト

タイトル  
名前  
URL
コメント