01 /****************************/ 02 /* 線形探索 */ 03 /* coded by Y.Suganuma */ 04 /****************************/ 05 #include <stdio.h> 06 #include <stdlib.h> 07 #include <time.h> 08 #include "MT.h" 09 10 int main() 11 { 12 // 初期設定 13 int s[100000], n = 0; 14 int *data = new int [5000000]; 15 init_genrand((unsigned)time(NULL)); 16 // データの設定 17 clock_t tm1 = clock(); 18 for (int i1 = 0; i1 < 5000000; i1++) { 19 data[i1] = genrand_int31(); 20 if (i1%50 == 0 && n < 100000) { 21 s[n] = data[i1]; 22 n++; 23 } 24 } 25 clock_t tm2 = clock(); 26 printf("保存: %d ms\n", (int)(tm2-tm1)); 27 // データの探索 28 for (int i1 = 0; i1 < n; i1++) { 29 int sw = 0; 30 for (int i2 = 0; i2 < 5000000; i2++) { 31 if (data[i2] == s[i1]) { 32 sw = 1; 33 break; 34 } 35 } 36 if (sw == 0) { 37 printf("***error*** データが見つからない!\n"); 38 exit(1); 39 } 40 } 41 clock_t tm3 = clock(); 42 printf("探索: %d ms\n", (int)(tm3-tm2)); 43 44 return 0; 45 }
保存: 46 ms 探索: 182098 ms
001 /****************************/ 002 /* 二分探索 */ 003 /* coded by Y.Suganuma */ 004 /****************************/ 005 #include <stdio.h> 006 #include <stdlib.h> 007 #include <time.h> 008 #include <algorithm> 009 #include "MT.h" 010 011 using namespace std; 012 013 /*************************/ 014 /* データの比較(昇順) */ 015 /* bsearch 用 */ 016 /*************************/ 017 int compare_n(const void *arg1, const void *arg2) 018 { 019 int *a1 = (int *)arg1; 020 int *a2 = (int *)arg2; 021 return *a1 - *a2; 022 } 023 024 /**************************************/ 025 /* 二分探索( Binary Search ) */ 026 /* key : 探索するキーデータ */ 027 /* data : データ */ 028 /* n : データ数 */ 029 /* return : 1 : 見つかった */ 030 /* 0 : 見つからなかった */ 031 /**************************************/ 032 bool search(int key, int *data, int n) 033 { 034 int sw = 0, left = 0, right = n-1, center; 035 036 if (data[right] > data[left]) { 037 while (left < right) { 038 center = (left + right) / 2; 039 if (data[center] < key) 040 left = (center < n-1) ? center + 1 : center; 041 else 042 right = center; 043 } 044 } 045 else { 046 while (left < right) { 047 center = (left + right) / 2; 048 if (data[center] > key) 049 left = (center < n-1) ? center + 1 : center; 050 else 051 right = center; 052 } 053 } 054 055 if (data[left] == key) 056 sw = 1; 057 058 return sw; 059 } 060 061 #define N 5000000 062 063 int main() 064 { 065 // 初期設定 066 int s[100000], n = 0; 067 int *data = new int [N]; 068 init_genrand((unsigned)time(NULL)); 069 // データの設定 070 clock_t tm1 = clock(); 071 for (int i1 = 0; i1 < N; i1++) { 072 data[i1] = genrand_int31(); 073 if (i1%50 == 0 && n < 100000) { 074 s[n] = data[i1]; 075 n++; 076 } 077 } 078 clock_t tm2 = clock(); 079 printf("保存: %d ms\n", (int)(tm2-tm1)); 080 // データのソート 081 sort(data, data+N); 082 clock_t tm3 = clock(); 083 printf("sort: %d ms\n", (int)(tm3-tm2)); 084 // データの探索 085 for (int i1 = 0; i1 < n; i1++) { 086 int sw = search(s[i1], data, N); 087 if (sw == 0) { 088 printf("***error*** データが見つからない!\n"); 089 exit(1); 090 } 091 } 092 clock_t tm4 = clock(); 093 printf(" 探索: %d ms\n", (int)(tm4-tm3)); 094 // データの探索(標準関数 bsearch の利用) 095 for (int i1 = 0; i1 < n; i1++) { 096 int *sw = (int *)bsearch(&s[i1], data, N, sizeof(int), compare_n); 097 if (sw == NULL) { 098 printf("***error*** データが見つからない!\n"); 099 exit(1); 100 } 101 } 102 clock_t tm5 = clock(); 103 printf(" 探索(bsearch): %d ms\n", (int)(tm5-tm4)); 104 // データの探索(C++ 標準ライブラリ binary_search の利用) 105 for (int i1 = 0; i1 < n; i1++) { 106 bool sw = binary_search(data, data+N, s[i1]); 107 if (!sw) { 108 printf("***error*** データが見つからない!\n"); 109 exit(1); 110 } 111 } 112 clock_t tm6 = clock(); 113 printf(" 探索(binary_search): %d ms\n", (int)(tm6-tm5)); 114 115 return 0; 116 }
保存: 30 ms sort: 402 ms 探索: 40 ms 探索(bsearch): 49 ms 探索(binary_search): 39 ms
001 /****************************/ 002 /* ハッシュ法( Hash ) */ 003 /* coded by Y.Suganuma */ 004 /****************************/ 005 #include <stdio.h> 006 #include <stdlib.h> 007 #include <string.h> 008 #include <string> 009 #include <set> 010 #include <unordered_set> 011 #include <time.h> 012 #include "MT.h" 013 014 using namespace std; 015 016 int hit = 0; 017 018 /***********************************/ 019 /* クラス Hash(ハッシュテーブル) */ 020 /***********************************/ 021 class Hash { 022 int size; // ハッシュテーブルの大きさ 023 set <string> *table; // 衝突リスト 024 025 /*******************/ 026 /* ハッシュ関数 */ 027 /* s : 文字列 */ 028 /*******************/ 029 int hash(char *s) 030 { 031 unsigned int hash = 0; 032 int len = strlen(s); 033 for (int i1 = 0; i1 < len; i1++ ) { 034 hash = (hash << 4) + s[i1]; // 左に4ビットシフトし文字を加える 035 unsigned int g = hash & 0xf0000000; // ビット毎のAND 036 if (g != 0) { 037 hash ^= g >> 24; // 排他的論理和 038 hash ^= g; 039 } 040 } 041 042 return hash % size; 043 } 044 045 public: 046 047 /******************/ 048 /* コンストラクタ */ 049 /******************/ 050 Hash(int sz) 051 { 052 size = sz; 053 table = new set <string> [size]; 054 } 055 056 /***************************************/ 057 /* データの追加 */ 058 /* str : データ(文字列) */ 059 /* return : =1 : 追加 */ 060 /* =0 : 同じデータが存在 */ 061 /***************************************/ 062 int add(char *str) 063 { 064 int k = hash(str); 065 if (!(table[k].empty())) 066 hit++; 067 pair<set<string>::iterator, bool> p = table[k].insert((string)str); 068 return p.second; 069 } 070 071 /***********************************/ 072 /* データの探索 */ 073 /* str : データ(文字列) */ 074 /* return : =1 : 見つかった */ 075 /* =0 : 見つからない */ 076 /***********************************/ 077 int search(char *str) 078 { 079 int sw = 0; 080 int k = hash(str); 081 set<string>::iterator it = table[k].find((string)str); 082 if (it != table[k].end()) 083 sw = 1; 084 return sw; 085 } 086 }; 087 088 int main() 089 { 090 // 初期設定 091 int n = 0; 092 char s[100000][11]; 093 Hash H(10000000); 094 init_genrand((unsigned)time(NULL)); 095 // データの設定 096 printf("Hash\n"); 097 clock_t tm1 = clock(); 098 for (int i1 = 0; i1 < 5000000; i1++) { 099 int k = genrand_int31(); 100 char st[11]; 101 gcvt((double)k, 11, st); 102 st[strlen(st)-1] = '\0'; // 最後のピリオドが除かれる 103 int sw = H.add(st); 104 if (sw > 0) { 105 if (i1%50 == 0 && n < 100000) { 106 strcpy(s[n], st); 107 n++; 108 } 109 } 110 else 111 i1--; 112 } 113 clock_t tm2 = clock(); 114 printf(" 保存: %d ms, 衝突回数: %d\n", (int)(tm2-tm1), hit); 115 // データの探索 116 for (int i1 = 0; i1 < n; i1++) { 117 int sw = H.search(s[i1]); 118 if (sw == 0) { 119 printf("***error*** データが見つからない!\n"); 120 exit(1); 121 } 122 } 123 clock_t tm3 = clock(); 124 printf(" 探索: %d ms\n", (int)(tm3-tm2)); 125 // データの設定(string, unordered_set) 126 n = 0; 127 string* str = new string [100000]; 128 printf("unordered_set(string)\n"); 129 unordered_set<string> us; 130 for (int i1 = 0; i1 < 5000000; i1++) { 131 int k = genrand_int31(); 132 char st[11]; 133 gcvt((double)k, 11, st); 134 st[strlen(st)-1] = '\0'; // 最後のピリオドが除かれる 135 string sts(st); 136 pair<unordered_set<string>::iterator, bool> sw = us.insert(sts); 137 if (sw.second) { 138 if (i1%50 == 0 && n < 100000) { 139 str[n] = sts; 140 n++; 141 } 142 } 143 else 144 i1--; 145 } 146 clock_t tm4 = clock(); 147 printf(" 保存(string, unordered_set): %d ms\n", (int)(tm4-tm3)); 148 // データの探索(string, unordered_set) 149 for (int i1 = 0; i1 < n; i1++) { 150 unordered_set<string>::iterator it = us.find(str[i1]); 151 if (it == us.end()) { 152 printf("***error*** データが見つからない!\n"); 153 exit(1); 154 } 155 } 156 clock_t tm5 = clock(); 157 printf(" 探索(string, unordered_set): %d ms\n", (int)(tm5-tm4)); 158 // データの設定(int, unordered_set) 159 n = 0; 160 int kk[100000]; 161 printf("unordered_set(int)\n"); 162 unordered_set<int> usi; 163 for (int i1 = 0; i1 < 5000000; i1++) { 164 int k = genrand_int31(); 165 pair<unordered_set<int>::iterator, bool> sw = usi.insert(k); 166 if (sw.second) { 167 if (i1%50 == 0 && n < 100000) { 168 kk[n] = k; 169 n++; 170 } 171 } 172 else 173 i1--; 174 } 175 clock_t tm6 = clock(); 176 printf(" 保存(int, unordered_set): %d ms\n", (int)(tm6-tm5)); 177 // データの探索(int, unordered_set) 178 for (int i1 = 0; i1 < n; i1++) { 179 unordered_set<int>::iterator it = usi.find(kk[i1]); 180 if (it == usi.end()) { 181 printf("***error*** データが見つからない!\n"); 182 exit(1); 183 } 184 } 185 clock_t tm7 = clock(); 186 printf(" 探索(int, unordered_set): %d ms\n", (int)(tm7-tm6)); 187 188 return 0; 189 }
Hash 保存: 8034 ms, 衝突回数: 1642507 探索: 35 ms unordered_set(string) 保存(string, unordered_set): 9292 ms 探索(string, unordered_set): 29 ms unordered_set(int) 保存(int, unordered_set): 2256 ms 探索(int, unordered_set): 7 ms
a | b | c |
---|---|---|
3 | 0 | 2 |
001 /****************************/ 002 /* 文字列探索 */ 003 /* coded by Y.Suganuma */ 004 /****************************/ 005 #include <stdio.h> 006 #include <string.h> 007 #include <time.h> 008 #include "MT.h" 009 010 #define N 1000201 011 #define N1 5000 012 #define N2 200 013 014 /****************************************************/ 015 /* 単純な探索 */ 016 /* text : テキスト */ 017 /* ptn : 探索パターン */ 018 /* return : 発見位置のポインタ(失敗したらNULL) */ 019 /****************************************************/ 020 char *search_s(char *text, char *ptn) 021 { 022 char *s = NULL; 023 int len = (int)(strlen(text) - strlen(ptn)); 024 for (int i1 = 0; i1 < len; i1++) { 025 int k = i1; 026 int sw = 1; 027 for (int i2 = 0; i2 < (int)strlen(ptn); i2++) { 028 if (ptn[i2] != text[k]) { 029 sw = 0; 030 break; 031 } 032 else 033 k++; 034 } 035 if (sw > 0) { 036 s = &text[i1]; 037 break; 038 } 039 } 040 return s; 041 } 042 043 /****************************************************/ 044 /* BM 法 */ 045 /* text : テキスト */ 046 /* ptn : 探索パターン */ 047 /* return : 発見位置のポインタ(失敗したらNULL) */ 048 /****************************************************/ 049 char *search_BM(char *text, char *ptn) 050 { 051 int len_t = (int)strlen(text); 052 int len_p = (int)strlen(ptn); 053 // ずらし幅テーブル 054 int step[255]; 055 for (int i1 = 0; i1 < 255; i1++) 056 step[i1] = -1; 057 for (int i1 = len_p-1; i1 >= 0; i1--) { 058 if (step[(int)ptn[i1]] < 0) 059 step[(int)ptn[i1]] = len_p - 1 - i1; 060 } 061 // 実行 062 char *s = NULL; 063 int k = len_p - 1; 064 while (k < len_t) { 065 int k1 = k; 066 int k2 = len_p - 1; 067 int sw = 1; 068 while (k2 >= 0) { 069 if (ptn[k2] != text[k1]) { 070 if (step[(int)text[k1]] < 0) // text[k1] がパターンに含まれない 071 k += len_p; 072 else { // text[k1] がパターンに含まれる 073 int k3 = step[(int)text[k1]]; 074 int k4 = len_p - k2; 075 if (k3 > k4) 076 k = k1 + k3; 077 else 078 k = k1 + k4; 079 } 080 sw = 0; 081 break; 082 } 083 else { 084 k1--; 085 k2--; 086 } 087 } 088 if (sw > 0) { 089 s = &text[k-len_p+1]; 090 break; 091 } 092 } 093 return s; 094 } 095 096 /****************/ 097 /* main program */ 098 /****************/ 099 int main() 100 { 101 clock_t tm1 = clock(); 102 char **pattern = new char *[N1]; 103 for (int i1 = 0; i1 < N1; i1++) 104 pattern[i1] = new char[N2+1]; 105 char *text = new char[N+1]; 106 107 init_genrand((unsigned)time(NULL)); 108 // テキストと探索データの生成 109 int n = 0; 110 for (int i1 = 0; i1 < N; i1++) { 111 text[i1] = (char)(65 + 58 * genrand_real3()); 112 if (n < N1 && i1 >= 2*N2 && (i1 % N2) == 0) { 113 int k = i1 - N2 - N2 / 2 - 1; 114 for (int i2 = 0; i2 < N2; i2++) { 115 pattern[n][i2] = text[k]; 116 k++; 117 } 118 pattern[n][N2] = '\0'; 119 if (n % 2 > 0) // 存在しないデータの作成 120 pattern[n][N2/2] = '('; 121 n++; 122 } 123 } 124 text[N] = '\0'; 125 clock_t tm2 = clock(); 126 printf("***初期設定終了: %d ms***\n", (int)(tm2-tm1)); 127 // 検索 128 printf("テキスト文字数 %d 探索パターン数 %d 探索パターン文字数 %d\n", N, n, N2); 129 // 標準関数 strstr 130 printf("標準関数 strstr\n"); 131 tm1 = clock(); 132 int hit = 0; 133 for (int i1 = 0; i1 < n; i1++) { 134 char *str = strstr(text, pattern[i1]); 135 if (str == NULL) 136 hit++; 137 } 138 tm2 = clock(); 139 printf(" 探索時間: %d ms 見つからなかったパターン数: %d\n", (int)(tm2-tm1), hit); 140 // 単純な方法 141 printf("単純な方法\n"); 142 tm1 = clock(); 143 hit = 0; 144 for (int i1 = 0; i1 < n; i1++) { 145 char *str = search_s(text, pattern[i1]); 146 if (str == NULL) 147 hit++; 148 } 149 tm2 = clock(); 150 printf(" 探索時間: %d ms 見つからなかったパターン数: %d\n", (int)(tm2-tm1), hit); 151 // BM 法 152 printf("BM 法\n"); 153 tm1 = clock(); 154 hit = 0; 155 for (int i1 = 0; i1 < n; i1++) { 156 char *str = search_BM(text, pattern[i1]); 157 if (str == NULL) 158 hit++; 159 } 160 tm2 = clock(); 161 printf(" 探索時間: %d ms 見つからなかったパターン数: %d\n", (int)(tm2-tm1), hit); 162 163 return 0; 164 }
***初期設定終了: 24 ms*** テキスト文字数 1000201 探索パターン数 5000 探索パターン文字数 200 標準関数 strstr 探索時間: 3062 ms 見つからなかったパターン数: 2500 単純な方法 探索時間: 231324 ms 見つからなかったパターン数: 2500 BM 法 探索時間: 1374 ms 見つからなかったパターン数: 2500
C++ の string を使用した場合
01 /****************************/ 02 /* 文字列探索(C++のstring) */ 03 /* coded by Y.Suganuma */ 04 /****************************/ 05 #include <time.h> 06 #include <iostream> 07 #include <string> 08 #include "MT.h" 09 10 #define N 1000201 11 #define N1 5000 12 #define N2 200 13 14 using namespace std; 15 16 /****************/ 17 /* main program */ 18 /****************/ 19 int main() 20 { 21 clock_t tm1 = clock(); 22 string pattern[N1]; 23 string text = ""; 24 25 init_genrand((unsigned)time(NULL)); 26 // テキストと探索データの生成 27 int n = 0; 28 for (int i1 = 0; i1 < N; i1++) { 29 text += (char)(65 + 58 * genrand_real3()); 30 if (n < N1 && i1 >= 2*N2 && (i1 % N2) == 0) { 31 int k = i1 - N2 - N2 / 2 - 1; 32 pattern[n] = text.substr(k, N2); 33 if (n % 2 > 0) // 存在しないデータの作成 34 pattern[n][N2/2] = '('; 35 n++; 36 } 37 } 38 clock_t tm2 = clock(); 39 printf("***初期設定終了: %d ms***\n", (int)(tm2-tm1)); 40 // 検索( C++ string の find ) 41 printf("テキスト文字数 %d 探索パターン数 %d 探索パターン文字数 %d\n", N, n, N2); 42 printf("C++ string の find\n"); 43 tm1 = clock(); 44 int hit = 0; 45 for (int i1 = 0; i1 < n; i1++) { 46 int k = text.find(pattern[i1]); 47 if (k < 0) 48 hit++; 49 } 50 tm2 = clock(); 51 printf(" 探索時間: %d ms 見つからなかったパターン数: %d\n", (int)(tm2-tm1), hit); 52 53 return 0; 54 }
***初期設定終了: 62 ms*** テキスト文字数 1000201 探索パターン数 5000 探索パターン文字数 200 C++ string の find 探索時間: 71004 ms 見つからなかったパターン数: 2500
講義内容目次 | 菅沼ホーム | 前ページ | 次ページ |