I come from Python/Java land and I'm trying to tinker with making my own hashmap now in c++.
When I try to check to compare the locations of positions in the hash table to NULL (lines 6 and 11), I get the error:
invalid operands to binary expression ('value_type' (aka 'HashEntry') and 'long')"
I'm hoping someone can steer me in the direction of what I'm doing wrong and how I can fix it.
void CustomHash::insert(HashEntry entry) {
int k = entry.getKey();
int i = 0;
int hashVal = hash_One(k);
int temp = hashVal;
while (i < size && hashArray[temp] != NULL) {
i++;
temp = (hashVal + i*hash_Two(k)) % size;
}
if (hashArray[temp] == NULL) {
hashArray[temp] = entry;
}
else {
cout << "Failure" << endl;
}
}
Edit 1: hashArray declaration
CustomHash::CustomHash(int m) {
this->size = m;
this->hashArray = vector<HashEntry>();
}
Given,
hashArray is a vector<HashEntry> Object
hashArray[temp] evaluates to a HashEntry. You cannot compare a HashEntry with NULL.
Use a different strategy to check whether hasArray has any items whose key is equal to temp. I suggest using std::count_if.
while (i < size && std::count_if(hashArray.begin(), hashArray.end(),
[=temp](HashEntry const& e)
{ return (temp == e.getKey());}) > 0 )
{
i++;
temp = (hashVal + i*hash_Two(k)) % size;
}
A better solution, as suggested by #cdhowie, is to use std::any_of.
while (i < size && std::any_of(hashArray.begin(), hashArray.end(),
[=temp](HashEntry const& e)
{ return (temp == e.getKey());}) )
{
i++;
temp = (hashVal + i*hash_Two(k)) % size;
}
Related
I am writing code for Leetcode problem 38. Count and Say. It doesn't pass the cases, so I add some cout to debug. Please tell me is there a normal way to debug nested for loop, where should I add the cout expression. I don't want to know how to modify the code to pass the cases.
Here is my code:
class Solution {
public:
string countAndSay(int n) {
string cur("1");
while (--n) {
string tmp = cur;
string next;
for (int i = 0; i < tmp.size();) {
cout << "i:" << i << endl;
int count = 1;
for (int j = i + 1; j < tmp.size(); j++) {
if (tmp[j] != tmp[0]) {
break;
}
count++;
}
cout << "count:" << count << endl;
next += std::to_string(count) + tmp[0];
cout << "cur:" << cur << endl;
i += count;
}
cur = next;
cout << n << cur << endl;
}
return cur;
}
};
You're gonna have to use a debugger for that, and step by step go through your algorithm to find the bugs. It's hard to debug someone else's algorithm.
This'll pass through:
#include <string>
struct Solution {
static const std::string countAndSay(int n) {
if (not n) {
return "";
}
std::string res = "1";
while (--n) {
std::string curr = "";
for (int index = 0; index < res.size(); index++) {
int count = 1;
while ((index + 1 < res.size()) and (res[index] == res[index + 1])) {
count++;
index++;
}
curr += std::to_string(count) + res[index];
}
res = curr;
}
return res;
}
};
Java Solutions
class Solution {
public String countAndSay(int n) {
if (n == 1)
return "1";
String prev = countAndSay(n - 1);
StringBuilder str = new StringBuilder();
int i = 0;
while (i < prev.length()) {
char curr = prev.charAt(i);
int j = 0;
while (i + j < prev.length() && prev.charAt(i + j) == curr)
j++;
str.append(j);
str.append(curr);
i += j;
}
return str.toString();
}
}
Here is one of LeetCode's solutions using regex:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class Solution {
public String countAndSay(int n) {
String currSeq = "1";
// Pattern to match the repetitive digits
String regexPattern = "(.)\\1*";
Pattern pattern = Pattern.compile(regexPattern);
for (int i = 1; i < n; ++i) {
Matcher m = pattern.matcher(currSeq);
StringBuffer nextSeq = new StringBuffer();
// each group contains identical and adjacent digits
while (m.find()) {
nextSeq.append(m.group().length() + String.valueOf(m.group().charAt(0)));
}
// prepare for the next iteration
currSeq = nextSeq.toString();
}
return currSeq;
}
}
and here's another LeetCode's solution also using Sliding Window:
class Solution {
public String countAndSay(int n) {
LinkedList<Integer> prevSeq = new LinkedList<Integer>();
prevSeq.add(1);
// Using -1 as the delimiter
prevSeq.add(-1);
List<Integer> finalSeq = this.nextSequence(n, prevSeq);
StringBuffer seqStr = new StringBuffer();
for (Integer digit : finalSeq) {
seqStr.append(String.valueOf(digit));
}
return seqStr.toString();
}
protected LinkedList<Integer> nextSequence(int n, LinkedList<Integer> prevSeq) {
if (n <= 1) {
// remove the delimiter before return
prevSeq.pollLast();
return prevSeq;
}
LinkedList<Integer> nextSeq = new LinkedList<Integer>();
Integer prevDigit = null;
Integer digitCnt = 0;
for (Integer digit : prevSeq) {
if (prevDigit == null) {
prevDigit = digit;
digitCnt += 1;
} else if (digit == prevDigit) {
// in the middle of the sub-sequence
digitCnt += 1;
} else {
// end of a sub-sequence
nextSeq.add(digitCnt);
nextSeq.add(prevDigit);
// reset for the next sub-sequence
prevDigit = digit;
digitCnt = 1;
}
}
// add the delimiter for the next recursion
nextSeq.add(-1);
return this.nextSequence(n - 1, nextSeq);
}
}
References
For additional details, you can see the Discussion Board. There are plenty of accepted solutions with a variety of languages and explanations, efficient algorithms, as well as asymptotic time/space complexity analysis1, 2 in there.
So I am working on Huffman coding for a project. However, my code just doesn't work. When i ran it on visual studio, it didn't give me an error. What I was trying to do is to read a file and put all of them into a string. And get the frequency for each character in that string. But I think when the file got a little bit large, it seems like my code is running in a infinite loop. Can anyone explain anything to me? By the way, I had a sorted function that I used to sort a vector of node* by their frequency.
ifstream infile;
infile.open(filename);
string q;
string line;
while (getline(infile, line))
{
q += line;
}
char y;
int count = 0;
int check = 0;
for (int i = 0; i < q.size(); i++) //if the string gets big, it seems to become an infinite loop in here
{
y = q[i];
for (int x = i - 1; x > 0; x--) //make sure not counting the same char
{
if (y == q[x])
{
check++;
}
}
if (check == 0)
{
for (int i = 0; i < q.size(); i++)
{
if (q[i] == y)
{
count++;
}
}
node*x = new node;
x->char1 = y; //my node have char
x->freq = count; //my node has frequency
list1.push_back(x);
}
count = 0;
check = 0;
}
sort(list1.begin(), list1.end(), sorter); //sort them from small to big
while (list1.size() > 1)
{
node*left = list1[0];
node*right = list1[1];
list1.erase(list1.begin(), list1.begin() + 2);
double sum = left->freq + right->freq;
node* x = new node;
x->freq = sum;
x->left = left;
x->right = right;
list1.push_back(x);
sort(list1.begin(), list1.end(), sorter);
}
list1.clear();
return true;
The following is my sort function
static struct {
bool operator()(NodeInterface* a, NodeInterface* b) {
if (a->getFrequency() == b->getFrequency()) {//if the frequencies are even,
if (b->getCharacter() == '\0') return false;
if (a->getCharacter() != '\0') {
return (int)a->getCharacter() < (int)b->getCharacter();
}
return false;
}
return a->getFrequency() < b->getFrequency();
}
} sorter;
I see two major problems.
You have a for loop inside a for loop both initializing and using int i
Change the variable name of the inner loop.
for (int i = 0; i < q.size(); i++) //if the string gets big, it seems to become an infinite loop in here
.
.
if (check == 0)
{
for (int i = 0; i < q.size(); i++) //Change this to int j for example
{
.
.
And the Sorter struct. I would rewrite it as this.
static struct {
bool operator()(NodeInterface* a, NodeInterface* b) {
if (a->getFrequency() == b->getFrequency()) {//if the frequencies are even,
if (b->getCharacter() == '\0') return false;
if (a->getCharacter() == '\0') return true;
return (int)a->getCharacter() < (int)b->getCharacter();
}
return a->getFrequency() < b->getFrequency();
}
} sorter;
A few suggestions for your for loop:
for (int i = 0; i < q.size(); i++) //if the string gets big, it seems to become an infinite loop in here
{
y = q[i];
//You can avoid this entire loop by using a structure like map
for (int x = i - 1; x > 0; x--) //make sure not counting the same char
{
if (y == q[x])
{
check++;
//break; //if you use a loop, break it once you find the character.
}
}
if (check == 0)
{
for (int j = 0; j < q.size(); j++)//Renamed variable + you can start this loop from j = i as you know there is no occurrence of y before that.
{
if (q[i] == y)
{
count++;
}
}
node*x = new node;
x->char1 = y; //my node have char
x->freq = count; //my node has frequency
list1.push_back(x);
}
count = 0;
check = 0;
}
I have the following for each loop which compares several guids with each other.
stringc flanking_id = *flanking_it;
if (abzug) {
if (AppFrame::isValidPointer(&flanking_id)) {
if (AppFrame::isValidPointer(&abzug->guid)) {
if (flanking_id.size() > 0 && abzug->guid.size() > 0) {
if (flanking_id.size() >= abzug->guid.size()) {
if (flanking_id.equalsn(abzug->guid, abzug->guid.size())) {
return bauteil;
}
}
}
}
}
}
abzug-guid is an core::stringw which is an Irrlicht-Engine datatype.
isValidPointer calls a method which is containing the following two lines
BOOL result = somePointer != 0 && somePointer != NULL && somePointer != nullptr && somePointer != nil;
return result;
So it shouldn't be possible, that one of my guids is broken. But Xcode says there is a possible null pointer dereference in this line.
if (flanking_id.equalsn(abzug->guid, abzug->guid.size())) {
This is the warning...
Array access (via field 'array') results in a null pointer dereference (within a call to 'equalsn')
How to solve this hint?
EDIT: equalsn() from irrString.h by Irrlicht-Engine
bool equalsn(const string<T,TAlloc>& other, u32 n) const
{
u32 i;
for(i=0; i < n && array[i] && other[i]; ++i)
if (array[i] != other[i])
return false;
// if one (or both) of the strings was smaller then they
// are only equal if they have the same length
return (i == n) || (used == other.used);
}
Example on Ideone.com
int * p1 = 0;
int p2 = *p1;
cout << "&p2 != 0: " << (&p2 != 0) << endl;
cout << "*p1 = 1 : " << flush;
*p1 = 1;
cout << "ok" << endl;
Output:
Runtime error time: 0 memory: 3096 signal:11
&p2 != 0: 1
*p1 = 1 :
So, the check for valid pointer after the last one was dereferenced is useless. It should be
if (abzug) {
if (AppFrame::isValidPointer(flanking_it)) {
stringc flanking_id = *flanking_it;
//...
Concerning warning, I'm not sure what Xcode dislikes, but I suspect this lines
for(i=0; i < n && array[i] && other[i]; ++i) // line 1
if (array[i] != other[i]) // line 2
There is should be check in line 1 that index i is less then size of array. In case of n greater than source string length there will be error.
BTW, instead of 7 enclosed if-statements you can use
if (!abzug ||
!AppFrame::isValidPointer(&flanking_id) ||
!AppFrame::isValidPointer(&abzug->guid) ||
... {
return ...;
}
if (flanking_id.equalsn(abzug->guid, abzug->guid.size())) {
return bauteil;
}
Or if a return statement can not be used then
do {
if (!abzug ||
!AppFrame::isValidPointer(&flanking_id) ||
!AppFrame::isValidPointer(&abzug->guid) ||
... {
break;
}
if (flanking_id.equalsn(abzug->guid, abzug->guid.size())) {
return bauteil;
}
} while (0);
I am still learning C++, so please if this is a duplicate point me to correct topic as I couldn't find any good and useful explanation.
I try to create a function in my ascending_ordered_array class which will insert elements into "empty" array sorting them in the same time.
Below is my code so far, but unfortunately it doesn't work 100% correctly as it adds two largest numbers as a last for positions in array.
void ascOrderedArray::push(Datatype p_item, Datatype* p_array, int p_size)
{
int i, j = 0;
int temp, num;
if (p_array[j] < 0)
p_array[j] = p_item;
for (i = 0; i < (p_size - 1); i++)
{
num = p_size;
for (j = (p_size - 1); j >= i; j--)
{
if (p_array[num]> p_array[j])
num = j;
}
temp = p_array[num];
p_array[num] = p_item;
p_array[i] = temp;
}
}
Here is part of main which call function above trying place random numbers into it
for (i = 0; i < size; i++)
{
num = (i + 1)* (rand() % 100);
arr.push(num, arr, size);
}
any hints what I am missing out?
This is code I wrote and its work as long as it is no resize neccessary
void ascOrderedArray::push(Datatype p_item)
{
//check if array is big enough and resize it if necessary
if (m_numElements >= m_size)
resize();
//checking if array contains some elements and if not set its first to pased item
if (m_numElements == 0)
{
m_array[0] = p_item;
m_numElements++;
return;
}
else
{
int i = m_numElements;
while (i >= 0 && i <= m_numElements)
{
//shifting array elements
m_array[i] = m_array[i - 1];
if (p_item > m_array[i - 1])
{
m_array[i] = p_item;
break;
}
--i;
}
m_numElements++;
}
}
For the following structure of a trie.
struct Trie {
bool eow; //when a Trie field isWord = true, hence there is a word
char letter;
Trie *letters[27];
};
I'm trying to create a function for an auto completion program, that basically prints out words in a trie given a specific string prefix
Here is what i have:
int wordcheck( TrieNode &node )
{
if (node.isWord == 1) // you have found your word, so return true
{
return 1;
}
for (int i = 0; i < 26; i++)
{
if (node.letters[i] != NULL && wordcheck(*(node.letters[i])))
{
return 1;
}
}
return 0;
}
string find (TrieNode &node, const string &word, string acc)
{
if (word.length() == 0)
{
string x = "";
if (node.isWord == 1){
x = " ";
int check = 1;
for(int i = 0; i < 26; i++)
{
if (node.letters[i] != NULL && wordcheck(*(node.letters[i])))
{
x = x + acc; check = 0; break;
}
}
if(check == 1)
{ return x; }
}
for (int i = 0; i < 26; i++){
if (node.letters[i] != NULL && wordcheck(*(node.letters[i])))
{
char let = (char)(i + (int)'a');
if (x[x.length() - 1 ] == ' ')
{
x = x + acc;
}
x = x + node.letters[i]->letter
+ find(*(node.letters[i]), word, acc + node.letters[i]->letter);
}
}
return x;
}
else if (node.letters[word[0] - 'a'] == NULL)
{ return ""; }
else {
return word[0] + find(*(node.letters[ word[0] - 'a']),
word.substr(1, word.length()-1),
acc + word[0]);
}
}
it seems to work other than the fact it if i give it a long prefix it will print words shorter than the prefix. I used accumulative recursion, and im sure there is a more efficient way of doing this. My question is if anyone could make it so that i return the right strings, or guide me through a easier algorithm if possible?
I'm trying to create a function for an auto completion program, that basically prints out words in a trie given a specific string prefix
I am not going to analyse your program - for me it is too complicated, e.g. I don't get any idea what wordcheck is supposed to do? Why is it not bool but int? Do you really need to check that your sub-trie has any word, do you really have non empty Trie without words in it?
For first - to print all words which begin with the given prefix - you need to go to the node where all these words begin:
TrieNode* TreeNode::get(std::string word)
{
TreeNode* retVal = this;
for (size_t i = 0; i < word.length(); ++i) {
if (Words[i] < 'a' || words[i] > 'z')
throw std::runtime_error("Wrong word");
if (retVal->letters[word[i] - 'a'] != NULL)
retVal = retVal->letters[word[i] - 'a'];
else
return nullptr;
}
return retVal;
}
You need the function which prints all the words from the given node:
void TreeNode::printAll(std::ostream& os, std::string prefix)
{
if (isWord)
os << prefix << "\n";
for (size_t i = 0; i < 26; ++i) {
if (retVal->letters[i] != NULL)
// this recursive call can be replaced with iterative solution with stack
letters[i]->print(os, prefix + char('a' + i));
}
}
And combining these functions - gives you what you want:
void TreeNode::printBeginWith(std::ostream& os, std::string prefix)
{
TreeNode* node = get(prefix);
if (node)
node->printAll(os, prefix);
}