Trie find/add function not working properly - c++

I am trying to implement a search function for my trie tree data structure. I am confused on how to properly implement this, as I assume my logic seems correct right now...although I am still a beginner in this. If someone can take a look at my function, and suggest where to improve, that would be greatly appreciated. The main takes in large word files and then searches for words in it to test the function basically. Right now it returns false for a word that should be in the trie object.
example error message
Error: jean-pierre is not in the spellcheck and it should have been
search function:
//looks up the word in the SpellCheck object. If it is in the SpellCheck object,true is returned.
//You can assume that the word will be all lower case.
bool lookup(const string& word) const {
if (!root_) {
return false;
}
Node* curr = root_;
if (word[0] == '\0') {
return curr->isTerminal_ == true;
}
for (int i = 0; i < word.length(); i++)
{
int idx = curr->getIndex(word[i]);
if (idx < 0 || idx >= 26){
return false;
}
// Search top level for node that
// matches first character in key
if (curr->children_[idx] == nullptr) {
return false;
}
curr = curr->children_[idx];
}
return curr->isTerminal_ == true;
}
Node struct:
struct Node {
bool isTerminal_;
char ch_;
Node* children_[26];
Node(char c = '\0') {
isTerminal_ = false;
ch_ = c;
for (int i = 0; i < 26; i++) {
children_[i] = nullptr;
}
}
//given lower case alphabetic charachters ch, returns
//the associated index 'a' --> 0, 'b' --> 1...'z' --> 25
int getIndex(char ch) {
return ch - 'a';
}
};
Node* root_;

You have multiple bugs in your implementation.
Your addWord function isn't correct.
This one should be better:
void addWord(const string& newWord, int currChar, Node* rt)
{
//check if currChar index is still in newWord
if (currChar < newWord.length()) {
//find index of currChar
char currLetter = newWord[currChar];
int idx = rt->getIndex(currLetter);
//if no letter at that index create a new node
if (!rt->children_[idx])
//make a new node
rt->children_[idx] = new Node(currLetter);
//continue to add
addWord(newWord, currChar + 1, rt->children_[idx]);
}
else
rt->isTerminal_ = true; //last char
}
The other bug you totally missed: "jean-pierre" contains non a-z characters :) and your getIndex will fail for any char that's not within [a-z] range.
The other points:
do not hardcode values like 26, because if you need to update your
range from [a-z] code elsewhere will silently fail.
use assert to check input assumptions.
Something like this:
int getIndex(char ch)
{
assert(ch >= 'a' && ch <= 'z');
return ch == '-' ? 26 : ch - 'a';
}

Related

How to use enqueu, dequeue, push, and peek in a Palindrome?

I'm writing a program to see if a string is a palindrome. I'm having trouble with the implementing the queue.enqueue(nextCharacter), stack.push(nextCharacter), queueFront = queue.peekFront(), stackTop = stack.peek(), queue.dequeu(). I tried looking at examples online of implementations of peek(), deque, push, and enqueue. Could not find any that worked correctly. I have to follow this exact format of this program.
// Start of Pseudcode given:
isPalindrome(someString: string): boolean
{
// Create an empty queue and stack
aQueue = new empty queue
aStack = new empty stack
// Add each character of string to both queue and stack
length = length of someString
for (i= 1 throught length)
{
nextChar = ith character of someString
aQueue.enqueue(nextChar)
aStack.push(nextChar)
}
charactersAreEqual=true
// Compare queue characters with stack characters
while (aQueue is not empty and charactersAreEqual)
{
queueFront = aQueue.peekFront();
stackTop = aStack.peek()
if(queueFront equals stackTop)
{
aQueue.dequeue();
aStack.pop()
}
else {
charactersAreEqual = false
}
#include <string>
#include <queue>
#include <stack>
#include <iostream>
bool isPalindrome(std::string str) {
// Declare variables
int length;
char nextCharacter;
bool charactersEqual;
char queueFront;
char stackTop;
// Create an empty queue and stack
std::queue<char> queue;
std::stack<char> stack;
// Set lenth to length of string
length = str.length();
// Add each character of string to both queue and stack
for (int i = 0; i < length; i++) {
nextCharacter = str.at(i);
queue.enqueue(nextCharacter); // ??????
stack.push(nextCharacter); // ?????
}
// Set characters to true
charactersEqual = true;
// Compare queue characters with stack characters
while (!queue.empty() && charactersEqual) {
queueFront = queue.peekFront(); // ?????
stackTop = stack.peek(); // ?????
if (queueFront == stackTop) {
queue.dequeu(); // ?????
stack.pop();
}
else {
charactersEqual = false;
}
}
return charactersEqual; // return characters that are equal
}
For an ASCII string, you can:
bool result = std::equal(str.begin(), str.end(), str.rbegin(), str.rend());
If you are using Unicode then you should probably reverse the whole string then use the equality operator:
bool isPalindrome(std::u8string str)
{
// Less efficient
std::u8string rstr{str};
std::reverse(rstr.begin(), rstr.end());
return (str == str2);
}
For instance, is 'é' and 'e' the same letter? In Dutch, "één hond" and "een hond" are the same because the first means "one dog" and the second can mean either "one dog" or "a dog" depending on the context. Therefore, you need to be careful if you need internationalization.
Here's a snippet from a program I wrote a while ago that checks if a word is a palindrome. I know it's not what you're asking for, but I figured I'd put it out there.
bool isPalindrome(const string word)
{
for (int i = 0, j = word.length() - 1; i < j; i++, j--)
{
if (word[i] != word[j]) //If any comparison fails, return false
return false;
}
//If all the checks passed, return true
return true
}

Palindrome but with a scentence

So writing a palindrome with pointers and boolean. I have it working with a single word but then I began building it to work with a sentence. The problem is I am unsure how to keep the new modified sentence after making it lowercase and getting rid of the spaces for it to return whether it is or isn't a palindrome. It keeps returning the palindrome as false and when I went to check why I see that the program ignores the modification and kept the original string. I can't use "&" on the parameter as I tested it out. Any hints or takes on what I can do to keep the new modified string?
int main()
{
userInput();
return 0;
}
void userInput()
{
char str[90];
std::cout<<"Please enter a string to check if it is a palindrome: ";
std::cin.getline(str, 90);
modifyString(str);
}
void modifyString(char *string)
{
int count = 0;
for (int i=0; i<strlen(string); i++)
{
putchar(tolower(string[i]));
}
for (int i = 0; string[i]; i++)
{
if (string[i] != ' ')
{
string[count++] = string[i];
}
}
string[count] = '\0';
std::cout<<string<<std::endl;
results(string);
}
bool checkPalindrome(char *string)
{
char *begin;
char *end;
begin = string;
end = (string + strlen(string)-1);
while(begin != end)
{
if ((*begin) == (*end))
{
begin ++;
end--;
}
else
{
return false;
}
}
return true;
}
void results(char *string)
{
bool isItPalindrome;
isItPalindrome = checkPalindrome(string);
if( isItPalindrome == true)
{
std::cout<<"\nCongrats, the string is a palindrome!";
}
else
{
std::cout<<"\nThis string is not a palindrome.";
}
}
For starters this definition of main
int main()
{
userInput();
return 0;
}
does not make a sense. According to the function name main the function should perform the main task that is to output whether the entered sentence is a palindrome or not.
This for loop
for (int i=0; i<strlen(string); i++)
{
putchar(tolower(string[i]));
}
does nothing useful. It just outputs the string in the lower case.
This statement
end = (string + strlen(string)-1);
can invoke undefined behavior if an empty string was passed.
This while loop
while(begin != end)
{
if ((*begin) == (*end))
{
begin ++;
end--;
}
else
{
return false;
}
}
also can invoke undefined behavior for a string containing an even number ofo characters because after this if statement
if ((*begin) == (*end))
{
begin ++;
end--;
}
if the two adjacent characters are equal then begin after incrementing will be greater than end after its decrementing. And as a result the loop will continue its iteration.
In general the approach when the original string is changed is just a bad approach.
Your program has too many functions. It is enough to write one function that will determine whether the passed string is a palindrome or not.
Here is a demonstrative program.
#include <iostream>
#include <cstring>
#include <cctype>
bool checkPalindrome( const char *s )
{
const char *t = s + std::strlen( s );
do
{
while ( s != t && std::isspace( ( unsigned char )*s ) ) ++ s;
while ( s != t && std::isspace( ( unsigned char )*--t ) );
} while ( s != t &&
std::tolower( ( unsigned char )*s ) == tolower( ( unsigned char ) *t ) &&
++s != t );
return s == t;
}
int main()
{
const size_t N = 100;
char s[N] = "";
std::cout << "Please enter a string to check if it is a palindrome: ";
std::cin.getline( s, N );
std::cout << '\n';
if ( checkPalindrome( s ) )
{
std::cout << "Congrats, the string is a palindrome!\n";
}
else
{
std::cout << "This string is not a palindrome.\n";
}
return 0;
}
Its output might look like
Please enter a string to check if it is a palindrome: 1 23 456 6 54 321
Congrats, the string is a palindrome!
Okay, I solved it!
As one of the users on here brought up a point that my lowercase did not modify the string and only prints it out. I try my best to solve the problem and I think I found the solution and everything works perfectly fine. comment back to debug it if you like to see how it looks but what I did was create a for loop again for the lower case but made another pointer with it. here how it looks.
for (char *pt = string; *pt != '\0'; ++pt)
{
*pt = std::tolower(*pt);
++pt;
}
Now that definitely changes the string into a lower case and keeps it as a lower case.
so now the modified function looks like this and ready to take any sentence palindrome you give it. Example: A nUt fOr a jAr of tUNa. We make this all lowercase and take out space and boom palindrome and return true.
void modifyString(char *string)
{
int count = 0;
for (char *pt = string; *pt != '\0'; ++pt)
{
*pt = std::tolower(*pt);
++pt;
}
for (int i = 0; string[i]; i++)
{
if (string[i] != ' ')
{
string[count++] = string[i];
}
}
string[count] = '\0';
//take out the forward slash below to see how it looks after being modified
// std::cout<<std::endl<<string<<std::endl;
results(string);
}

Code checking the result of std::unordered_set::find won't compile

I am writing a program to determine whether all characters in a string are unique or not. I am trying to do this using an unordered_set. Here is my code:
#include <iostream>
#include <unordered_set>
#include <string>
using namespace std;
bool uniqueChars(string word) {
unordered_set<char> set;
for (int i = 0; i < word.length(); i++) {
auto character = set.find(word[i]);
// if word[i] is found in set then not all chars are unique
if (character == word[i]) {
return false;
}
//else add word[i] to set
else {
set.insert(word[i]);
}
}
return true;
}
int main() {
string word;
getline(cin, word);
bool result = uniqueChars(word);
return 0;
}
It is giving me this error:
|15|error: no match for 'operator==' (operand types are 'std::__detail::_Node_iterator' and 'char')|
I believe that means that character is not comparable to word[i], but I'm not sure.
How do I make this work?
Note that std::unordered_set::find returns an iterator, not the element. It can't be compared to the element directly.
You could check whether the element was found or not by comparing the iterator with std::unordered_set::end. e.g.
auto character = set.find(word[i]);
// if word[i] is found in set then not all chars are unique
if (character != set.end()) {
return false;
}
//else add word[i] to set
else {
set.insert(word[i]);
}
BTW: Better not to use set as the name of variable, which is the name of another STL container.
Take advantage of the return value of insert. It tells you whether a duplicate was found during insertion (in which case nothing is inserted).
bool uniqueChars(string word) {
unordered_set<char> set;
for ( char c : word ) {
if ( ! set.insert( c ).second ) {
return false; // set didn't insert c because of a duplicate.
}
}
return true; // No duplicates.
}
However, this isn't as efficient as it might look. unordered_set is a heap-based hash table and its implementation is fairly heavyweight. A lightweight bit-vector works well for classifying characters.
#include <bitset>
constexpr int char_values = numeric_limits< char >::max()
- numeric_limits< char >::min() + 1;
bool uniqueChars(string word) {
bitset< char_values > set;
for ( char c : word ) {
int value_index = c - numeric_limits< char >::min();
if ( set[ value_index ] ) {
return false;
} else {
set[ value_index ] = true;
}
}
return true; // No duplicates.
}
*character == word[i]
( This is the way to access the characters but it is not needed and it
should be guided by a check whether it points to the past to the last
element)
The *charcater is basically referencing the already inserted charcater.
if(character != set1.end() )
return false; // as we are sure that it is not unique character string
You have to dereference it. but in that case you also need to do the whether it return iterator pointing to `set::end``.
By the way there is a really a simple way to do what you are trying to do.
bool uniqueChars(string word) {
unordered_set<char> set1;
for (int i = 0; i < word.length(); i++)
auto character = set1.insert(word[i]);
return set1.size()==word.length();
}
"set" is a key word in c++

recursive call overflows

On a test data set the following code works, but when I change to a second test set with a similar size it overflows.
To change a string of tokens into an associated new string of tokens I use this vector lookup function
//looks for input string in vector and returns output, 'c' is check row, 'r' is return row
string vectorSearch(string &check, int &direction, int n, int c, int r, int level)
{
if ((direction == 1 && check.length() <= 1) || n == list.size()-1 ||(direction == 0 && check.length() > 1)) { //if reading and string is 1 char then pass over
if (direction == 1){ //convert '???' into '?'
string temp = "";
bool wildToken = false;
for (unsigned int i = 0; i < check.length(); i++) {
temp+='?';
if (check.compare(temp) == 0) { check = '?'; wildToken = false; } //done,'???" case, return '?' token
else if (check[i] == '?') wildToken = true; //not done searching
}
}
return check;
} else {
if (list[n][c] == check || list[n][c] == ('0'+check)) //add dummy '0'
return list[n][r];
else
return vectorSearch (check, direction, n+1, c, r, level);
}
}
After working fine for a dozen conversions the stack overflows
vectorSearch is called from this function
//this function takes an ontology and direction==1 (default) changes from string
//to single char or if direction==0 takes single char and converts to string representation
string Lexicon::convertOntology(string input, int level, int direction, string out, string temp)
{
if (input == "" && temp == "")
return out; //check for completed conversion
else {
if (direction == 0 || input[0] == '.' || input[0] == '-' || input == "" ) { //found deliniator or end
if (temp == "") temp = input[0]; //condition for reverse w/o deleniators
if (input != "") return convertOntology(input.substr(1), level+1, direction,
out+=vectorSearch(temp, direction, 0, direction, 1-direction, level));
else {
string empty = "";
return convertOntology(empty, level+1, direction, out+=vectorSearch(temp, direction, 0, direction, 1-direction, level));
}
} else
return convertOntology(input.substr(1), level, direction, out, temp+=input[0]); //increment and check
}
}
The call stack is a finite resource and can be exhausted like any other. The larger your function is (with respect to creation of local variables you create inside it) the larger the amount of space each call uses on the stack. It is something that is unavoidable with recursion unless you can restrict the number of recursive calls in some way.
You can only go so deep with recursion before running out of stack space. Luckily, any recursive function can be re-written to be iterative. I believe the below is a correct iterative implementation of your vectorSearch, I'll leave the latter one to you.
string vectorSearch(string &check, int &direction, int n, int c, int r, int level)
{
while(true)
{
if ((direction == 1 && check.length() <= 1) || n == list.size()-1 ||(direction == 0 && check.length() > 1)) { //if reading and string is 1 char then pass over
if (direction == 1){ //convert '???' into '?'
string temp = "";
bool wildToken = false;
for (unsigned int i = 0; i < check.length(); i++) {
temp+='?';
if (check.compare(temp) == 0) { check = '?'; wildToken = false; } //done,'???" case, return '?' token
else if (check[i] == '?') wildToken = true; //not done searching
}
}
return check;
} else if (list[n][c] == check || list[n][c] == ('0'+check)) {//add dummy '0'
return list[n][r];
}
n++;
}
}
thank you to the reviews and comments.
The functions are fine - this recursive function bundle requires that the string exists in the database it acts an, and the string checks prior to these incorrectly recognized a special condition and inserted a dummy char. There is the recursive function that precedes these two - I did not correctly see that I had written a bundle of three recursive functions - and that one was searching within parameters for a string longer than what exists in the database; apparently the parameters were wider than the stack. Checked into the parameters and one was not updated and was not controlling.
I fixed the special condition, the strings are now the same length and the search parameters are fixed.
the functions posted are not too complex.

How do I write a simple regular expression pattern matching function in C or C++?

This is a question in my paper test today, the function signature is
int is_match(char* pattern,char* string)
The pattern is limited to only ASCII chars and the quantification * and ?, so it is relatively simple. is_match should return 1 if matched, otherwise 0.
How do I do this?
Brian Kernighan provided a short article on A Regular Expression Matcher that Rob Pike wrote as a demonstration program for a book they were working on. The article is a very nice read explaining a bit about the code and regular expressions in general.
I have played with this code, making a few changes to experiment with some extensions such as to also return where in the string the pattern matches so that the substring matching the pattern can be copied from the original text.
From the article:
I suggested to Rob that we needed to find the smallest regular
expression package that would illustrate the basic ideas while still
recognizing a useful and non-trivial class of patterns. Ideally, the
code would fit on a single page.
Rob disappeared into his office, and at least as I remember it now,
appeared again in no more than an hour or two with the 30 lines of C
code that subsequently appeared in Chapter 9 of TPOP. That code
implements a regular expression matcher that handles these constructs:
c matches any literal character c
. matches any single character
^ matches the beginning of the input string
$ matches the end of the input string
* matches zero or more occurrences of the previous character
This is quite a useful class; in my own experience of using regular
expressions on a day-to-day basis, it easily accounts for 95 percent
of all instances. In many situations, solving the right problem is a
big step on the road to a beautiful program. Rob deserves great credit
for choosing so wisely, from among a wide set of options, a very small
yet important, well-defined and extensible set of features.
Rob's implementation itself is a superb example of beautiful code:
compact, elegant, efficient, and useful. It's one of the best examples
of recursion that I have ever seen, and it shows the power of C
pointers. Although at the time we were most interested in conveying
the important role of a good notation in making a program easier to
use and perhaps easier to write as well, the regular expression code
has also been an excellent way to illustrate algorithms, data
structures, testing, performance enhancement, and other important
topics.
The actual C source code from the article is very very nice.
/* match: search for regexp anywhere in text */
int match(char *regexp, char *text)
{
if (regexp[0] == '^')
return matchhere(regexp+1, text);
do { /* must look even if string is empty */
if (matchhere(regexp, text))
return 1;
} while (*text++ != '\0');
return 0;
}
/* matchhere: search for regexp at beginning of text */
int matchhere(char *regexp, char *text)
{
if (regexp[0] == '\0')
return 1;
if (regexp[1] == '*')
return matchstar(regexp[0], regexp+2, text);
if (regexp[0] == '$' && regexp[1] == '\0')
return *text == '\0';
if (*text!='\0' && (regexp[0]=='.' || regexp[0]==*text))
return matchhere(regexp+1, text+1);
return 0;
}
/* matchstar: search for c*regexp at beginning of text */
int matchstar(int c, char *regexp, char *text)
{
do { /* a * matches zero or more instances */
if (matchhere(regexp, text))
return 1;
} while (*text != '\0' && (*text++ == c || c == '.'));
return 0;
}
See This Question for a solution you can not submit. See this paper for a description of how to implement a more readable one.
Here is recursive extendable implementation. Tested for first order of pattern complexity.
#include <string.h>
#include <string>
#include <vector>
#include <iostream>
struct Match {
Match():_next(0) {}
virtual bool match(const char * pattern, const char * input) const {
return !std::strcmp(pattern, input);
}
bool next(const char * pattern, const char * input) const {
if (!_next) return false;
return _next->match(pattern, input);
}
const Match * _next;
};
class MatchSet: public Match {
typedef std::vector<Match *> Set;
Set toTry;
public:
virtual bool match(const char * pattern, const char * input) const {
for (Set::const_iterator i = toTry.begin(); i !=toTry.end(); ++i) {
if ((*i)->match(pattern, input)) return true;
}
return false;
}
void add(Match * m) {
toTry.push_back(m);
m->_next = this;
}
~MatchSet() {
for (Set::const_iterator i = toTry.begin(); i !=toTry.end(); ++i)
if ((*i)->_next==this) (*i)->_next = 0;
}
};
struct MatchQuestion: public Match {
virtual bool match(const char * pattern, const char * input) const {
if (pattern[0] != '?')
return false;
if (next(pattern+1, input))
return true;
if (next(pattern+1, input+1))
return true;
return false;
}
};
struct MatchEmpty: public Match {
virtual bool match(const char * pattern, const char * input) const {
if (pattern[0]==0 && input[0]==0)
return true;
return false;
}
};
struct MatchAsterisk: public Match {
virtual bool match(const char * pattern, const char * input) const {
if (pattern[0] != '*')
return false;
if (pattern[1] == 0) {
return true;
}
for (int i = 0; input[i] != 0; ++i) {
if (next(pattern+1, input+i))
return true;
}
return false;
}
};
struct MatchSymbol: public Match {
virtual bool match(const char * pattern, const char * input) const {
// TODO: consider cycle here to prevent unnecessary recursion
// Cycle should detect special characters and call next on them
// Current implementation abstracts from that
if (pattern[0] != input[0])
return false;
return next(pattern+1, input+1);
}
};
class DefaultMatch: public MatchSet {
MatchEmpty empty;
MatchQuestion question;
MatchAsterisk asterisk;
MatchSymbol symbol;
public:
DefaultMatch() {
add(&empty);
add(&question);
add(&asterisk);
add(&symbol);
}
void test(const char * p, const char * input) const {
testOneWay(p, input);
if (!std::strcmp(p, input)) return;
testOneWay(input, p);
}
bool testOneWay(const char * p, const char * input) const {
const char * eqStr = " == ";
bool rv = match(p, input);
if (!rv) eqStr = " != ";
std::cout << p << eqStr << input << std::endl;
return rv;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
using namespace std;
typedef vector<string> Strings;
Strings patterns;
patterns.push_back("*");
patterns.push_back("*hw");
patterns.push_back("h*w");
patterns.push_back("hw*");
patterns.push_back("?");
patterns.push_back("?ab");
patterns.push_back("a?b");
patterns.push_back("ab?");
patterns.push_back("c");
patterns.push_back("cab");
patterns.push_back("acb");
patterns.push_back("abc");
patterns.push_back("*this homework?");
patterns.push_back("Is this homework?");
patterns.push_back("This is homework!");
patterns.push_back("How is this homework?");
patterns.push_back("hw");
patterns.push_back("homework");
patterns.push_back("howork");
DefaultMatch d;
for (unsigned i = 0; i < patterns.size(); ++i)
for (unsigned j =i; j < patterns.size(); ++j)
d.test(patterns[i].c_str(), patterns[j].c_str());
return 0;
}
If something is unclear, ask.
Cheat. Use #include <boost/regex/regex.hpp>.
try to make a list of interesting test cases:
is_match("dummy","dummy") should
return true;
is_match("dumm?y","dummy") should
return true;
is_match("dum?y","dummy")
should return false;
is_match("dum*y","dummy") should
return true;
and so on ...
then see how to make the easier test pass, then the next one ...
Didn't test this, actually code it, or debug it, but this might get you a start...
for each character in the pattern
if pattern character after the current one is *
// enter * state
while current character from target == current pattern char, and not at end
get next character from target
skip a char from the pattern
else if pattern character after the current one is ?
// enter ? state
if current character from target == current pattern char
get next char from target
skip a char from the pattern
else
// enter character state
if current character from target == current pattern character
get next character from target
else
return false
return true
The full power of regular expressions and finite state machines are not needed to solve this problem. As an alternative there is a relatively simple dynamic programming solution.
Let match(i, j) be 1 if it is possible to match the the sub-string string[i..n-1] with the sub-pattern pattern[j, m - 1], where n and m are the lengths of string and pattern respectively. Otherwise let match(i, j) be 0.
The base cases are:
match(n, m) = 1, you can match an empty string with an empty pattern;
match(i, m) = 0, you can't match a non-empty string with an empty pattern;
The transition is divided into 3 cases depending on whether the current sub-pattern starts with a character followed by a '*', or a character followed by a '?' or just starts with a character with no special symbol after it.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int is_match(char* pattern, char* string)
{
int n = strlen(string);
int m = strlen(pattern);
int i, j;
int **match;
match = (int **) malloc((n + 1) * sizeof(int *));
for(i = 0; i <= n; i++) {
match[i] = (int *) malloc((m + 1) * sizeof(int));
}
for(i = n; i >= 0; i--) {
for(j = m; j >= 0; j--) {
if(i == n && j == m) {
match[i][j] = 1;
}
else if(i < n && j == m) {
match[i][j] = 0;
}
else {
match[i][j] = 0;
if(pattern[j + 1] == '*') {
if(match[i][j + 2]) match[i][j] = 1;
if(i < n && pattern[j] == string[i] && match[i + 1][j]) match[i][j] = 1;
}
else if(pattern[j + 1] == '?') {
if(match[i][j + 2]) match[i][j] = 1;
if(i < n && pattern[j] == string[i] && match[i + 1][j + 2]) match[i][j] = 1;
}
else if(i < n && pattern[j] == string[i] && match[i + 1][j + 1]) {
match[i][j] = 1;
}
}
}
}
int result = match[0][0];
for(i = 0; i <= n; i++) {
free(match[i]);
}
free(match);
return result;
}
int main(void)
{
printf("is_match(dummy, dummy) = %d\n", is_match("dummy","dummy"));
printf("is_match(dumm?y, dummy) = %d\n", is_match("dumm?y","dummy"));
printf("is_match(dum?y, dummy) = %d\n", is_match("dum?y","dummy"));
printf("is_match(dum*y, dummy) = %d\n", is_match("dum*y","dummy"));
system("pause");
return 0;
}
The time complexity of this approach is O(n * m). The memory complexity is also O(n * m) but with a simple modification can be reduced to O(m).
Simple recursive implementation. It's slow but easy to understand:
int is_match(char *pattern, char *string)
{
if (!pattern[0]) {
return !string[0];
} else if (pattern[1] == '?') {
return (pattern[0] == string[0] && is_match(pattern+2, string+1))
|| is_match(pattern+2, string);
} else if (pattern[1] == '*') {
size_t i;
for (i=0; string[i] == pattern[0]; i++)
if (is_match(pattern+2, string+i)) return 1;
return 0;
} else {
return pattern[0] == string[0] && is_match(pattern+1, string+1);
}
}
Hope I got it all right.
A C program to find the index,from where the sub-string in the main string is going to start.
enter code here
#include<stdio.h>
int mystrstr (const char *,const char *);
int mystrcmp(char *,char *);
int main()
{
char *s1,*s2;//enter the strings, s1 is main string and s2 is substring.
printf("Index is %d\n",mystrstr(s1,s2));
//print the index of the string if string is found
}
//search for the sub-string in the main string
int mystrstr (const char *ps1,const char *ps2)
{
int i=0,j=0,c=0,l,m;char *x,*y;
x=ps1;
y=ps2;
while(*ps1++)i++;
while(*ps2++)j++;
ps1=x;
ps2=y;
char z[j];
for(l=0;l<i-j;l++)
{
for(m=l;m<j+l;m++)
//store the sub-string of similar size from main string
z[c++]=ps1[m];
z[c]='\0'
c=0;
if(mystrcmp(z,ps2)==0)
break;
}
return l;
}
int mystrcmp(char *ps3,char *ps4) //compare two strings
{
int i=0;char *x,*y;
x=ps3;y=ps4;
while((*ps3!=0)&&(*ps3++==*ps4++))i++;
ps3=x;ps4=y;
if(ps3[i]==ps4[i])
return 0;
if(ps3[i]>ps4[i])
return +1;
else
return -1;
}