1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
#include<iostream>
//#include <string_view>
#include <boost/utility/string_ref.hpp>
//or std::string_view, std::experimental::string_view
//note boost string_ref does have tiny differences with std::string_view,
//but I want to believe that it is mostly forward compatible with string_view.
typedef boost::string_ref sview;
//note that there is also std::chrono::high_resolution_clock, this is an afterthought after already writing this...
#ifdef _WIN32
#include <Windows.h>
typedef LARGE_INTEGER TIMER_U;
typedef double TIME_RESULT_U;
TIMER_U time()
{
LARGE_INTEGER counter;
::QueryPerformanceCounter(&counter);
return counter;
}
//in milliseconds
TIME_RESULT_U time_result(TIMER_U first, TIMER_U last)
{
LARGE_INTEGER frequency;
::QueryPerformanceFrequency(&frequency);
return TIME_RESULT_U((last.QuadPart - first.QuadPart) * 1000) / TIME_RESULT_U(frequency.QuadPart);
}
#else
#include <time.h>
typedef clock_t TIMER_U;
typedef double TIME_RESULT_U;
TIMER_U time(){return clock();}
//in milliseconds
TIME_RESULT_U time_result(TIMER_U first, TIMER_U last)
{
return (TIME_RESULT_U)(last - first) / TIME_RESULT_U(CLOCKS_PER_SEC/1000);
}
#endif
using namespace std;
//Simple (brute force/naive) match algorithm
bool has_substring(sview input_string, sview pattern){
int j=0;
int i=0;
int k = 0;
while(i<static_cast<int>(input_string.length()) && j<static_cast<int>(pattern.length())){
if(input_string[i] == pattern[j]){
i++;
j++;}
else{j=0; k++ ; i=k;}
}
if(j==static_cast<int>(pattern.length())){
return true;
}
return false;
}
//Function to compute temporary integer array for prefix/suffix matches
///note I could probably quickly replace the buffer with a std::array, but too late.
void temp_array(sview pattern, int* buffer, int buf_size){
int index = 0;
for(int i=1; i<buf_size;){
if(pattern[i] == pattern[index]){
buffer[i]= buffer[index]+1;
index++;
i++;
}
else{
if(index != 0){
index = buffer[index-1];}
else{buffer[i]=0;
i++;}
}
}
}
//Function to implement KMP Algorithm for pattern match
bool KMP_alg(sview input_string, sview pattern, int* buffer, int buf_size){
//vector<int> tmp_kmp =
temp_array(pattern, buffer, buf_size);
int i=0;
int j=0;
while(i < static_cast<int>(input_string.length()) && j < static_cast<int>(pattern.length())){
if(input_string[i] == pattern[j]){
i++;
j++;}
else{
if(j!=0){
j = buffer[j-1];}
else{
i++;}
}
}
if(j == static_cast<int>(pattern.length())){
//cout << "Match begins at char. " << i-pattern.length()+1 << " of input" << endl;
//cout << "Match ends at char. " << i << " of input" << endl;
return true;}
else {
//cout <<"No match found" << endl;
return false;}
}
int main(){
const char *input = "darnoc76elocbergdarnoc78darnoc77";
char pattern[] = "darnoc77";
TIMER_U t1 = time();
int buffer[sizeof(pattern)-1]; //sizeof is in bytes, luckily chars are only 1 byte.
int buf_size = sizeof(pattern)-1;
bool result = KMP_alg(input, pattern, buffer, buf_size);
TIMER_U t2 = time();
cout << "KMP algorithm took " << time_result(t1,t2) << " ms." << endl;
t1 = time();
bool check = has_substring(input, pattern);
t2 = time();
cout << "Naive algorithm took " << time_result(t1,t2) << " ms." << endl;
cout << result << endl;
cout << check << endl;
return 0;
}
|