Recursively traverse dictionary trie to count total words - c++

I've built a trie from a linked list. Each node contains a char and an array of 27 nodes (letters of the alphabet + an extra spot for $ to represent the end of a word).
I tried writing a recursive method to count the number of words but it is returning 1. I'm not sure how to fix it or exactly what is wrong.
int recursiveCount(Node* temp, int count)
{
if (temp->value == '$')
{
count++;
}
for (int i = 0; i < 27; i++)
{
if (temp->array[i] != NULL)
{
return recursiveCount(temp->arr[i],count);
}
}
return count;
}

You pass count by value which means that it goes out of scope when the recursion unravels and only the one "furthest" out gets returned and since that i s the first count to be incremented it is just 1. Pass by reference instead int recursiveCount(Node* temp, int& temp);

As already noted in the other answers, your issue is that you're having different count variables, one for each recursive call. Incrementing one won't change the others. Instead of passing a (non const) reference you can also go for a more functional programming approach and return the count from your function. Of course you then need to sum up the returned counts of all recursive calls you made:
unsigned recursiveCount(Node const * node) /* you don't change the node, so make
it const. Why a pointer btw? A
reference would do fine! */
{
unsigned count = 0; /* You aren't expecting a negative number of
words, are you? So use unsigned. */
if (node->value == '$')
{
count++;
}
for (int i = 0; i < 27; i++)
{
if (node->array[i] != NULL) /* "array"!? change that to a meaningful
name ... "children" is bad, but not as
bad as "array" ... */
{
count += recursiveCount(node->array[i]); /* "arr" was a typo I
suppose */
}
}
return count; /* consistent indentation, please! */
}

You have marked this as C++, so I'm puzzled why the method is not part of Node. See encapsulation.
The significant error in your recursion code is not adding every '$'s found in each subsequent node. In particular, your code returns the count of only one invocation of the for loop, all others are discarded.
for (int i = 0; i < 27; i++)
{
if (temp->array[i] != NULL)
{
return recursiveCount(temp->arr[i],count);
// This only returns one value,
// and ignores all the other 26 possible values
// these should sum together
}
}
Consider making the method part of the node. Note how retVal accumulates every '$' found.
int Node::recursiveCount()
{
int retVal = 0; // accumulation
if (value == '$')
{
retVal += 1; // 1 word found here
}
// keep searching here, there might still be words with prefix
for (size_t i = 0; i < 27; i++)
{
if (nullptr != nxt[i])
{
retVal += (nxt[i]->recursiveCount());
// ^^ accumulate any other words found
}
}
return (retVal); // return full count
}

Related

My array is gettting an error because it's being defined as a singular integer

The point of this program is to output whether a series of digits (the number of digits undefined) is sorted or not (largest to smallest or smallest to largest).
I have defined my array in my function parameter, and I am trying to use a for loop to store the user's input, as long as it is above 0, in said array.
However, I am getting the error argument of type int is incompatible with parameter of type int*.
The exact error is the argument of type int is incompatible with parameter of type int*.
It is referring to line 22 and 23, these two;
isSorted(list[2000]); and
bool is = isSorted(list[2000]);.
I know this means my for loop is assigning a single value to my variable repeatedly from reading similar questions however I can not figure out how to fix this.
#include <iostream>
using namespace std;
bool isSorted(int list[]);
int main()
{
int i;
int list[2000];
int k = 0;
for (i = 0; i < 2000; i++)
{
int j;
while (j > 0)
{
cin >> j;
list[i] = j;
}
}
isSorted(list[2000]);
bool is = isSorted(list[2000]);
if (is == true)
cout << "sorted";
else
cout << "unsorted";
return 0;
}
bool isSorted(int list[])
{
int i = 0;
for (i = 0; i < 2000; i++)
{
if (list[i] > list[i + 1] || list[i] < list[i - 1])
{
return false;
}
else
return true;
}
}
I removed unused variable k.
Made 2000 parameterized (and set to 5 for testing).
In isSorted you are not allowed to return
true in the else as if your first element test would end in else you would return true immediately not testing other elements. But those later elements can be unsorted as well.
In isSorted you are not allowed to run the loop as for(i = 0; i < 2000; i++), because you add inside the for loop 1 to i and end up querying for i == 1999 list[2000], which is element number 2001 and not inside your array. This is correct instead: for (i = 0; i < 1999; i++). You also do not need to check into both directions.
You cannot call isSorted(list[2000]) as this would call is sorted with an int and not an int array as parameter.
You write int j without initializing it and then query while j > 0 before you cin << j. This is undefined behaviour, while most likely j will be zero, there is no guarantee. But most likely you never enter the while loop and never do cin
I renamed the isSorted as you just check in your example for ascending order. If you want to check for descending order you are welcome to train your programming skills and implementing this yourself.
Here is the code with the fixes:
#include <iostream>
using namespace std;
bool isSortedInAscendingOrder(int list[]);
const int size = 5; // Set this to 2000 again if you want
int main()
{
int i;
int list[size];
for (i = 0; i < size; i++)
{
int j = 0;
while(j <= 0)
{
cin >> j;
if(j <= 0)
cout << "rejected as equal or smaller zero" << endl;
}
list[i] = j;
}
if (isSortedInAscendingOrder(list))
cout << "sorted" << endl;
else
cout << "unsorted" << endl;
return 0;
}
bool isSortedInAscendingOrder(int list[])
{
for (int i = 0; i < size -1; i++)
{
if (list[i] > list[i + 1])
{
return false;
}
}
return true;
}
This is a definition of an array of 2000 integers.
int list[2000];
This is reading the 2000th entry in that array and undefined, because the highest legal index to access is 1999. Remember that the first legal index is 0.
list[2000]
So yes, from point of view of the compiler, the following only gives a single integer on top of being undefined behaviour (i.e. "evil").
isSorted(list[2000]);
You probably should change to this, in order to fix the immediate problem - and get quite close to what you probably want. It names the whole array as parameter. It will decay to a pointer to int (among other things loosing the information of size, but you hardcoded that inside the function; better change that by the way).
isSorted(list);
Delete the ignored first occurence (the one alone on a line), keep the second (the one assigning to a bool variable).
On the other hand, the logic of a your sorting check is flawed, it will often access outside the array, for indexes 0 and 1999. I.e. at the start and end of your loop. You need to loop over slightly less than the whole array and only use one of the two conditions.
I.e. do
for (i = 1; i < 2000; i++)
{
if (list[i] < list[i - 1])
/* ... */
The logic for checking ascending or descending sorting would have to be more complex. The question is not asking to fix that logic, so I stick with fixing the issues according to the original version (which did not mention two-way-sorting).
You actually did not ask about fixing the logic for that. But here is a hint:
Either use two loops, which you can break from as soon as you find a conflict, but do not return from the fuction immediatly.
Or use one loop and keep a flag of whether ascending or descending order has been broken. Then return true if either flag is still clear (or both, in case of all identical values) or return false if both are set.

Explanation for "Unreachable code" within c++ function

The goal is to write a function that searches an array for a value.
If the array contains the value, return the index where the key is located.If the array does not contain the value, return a -1
I have a c++ function that returns the index of an array variable. I need explanation on why my part of my code ( ie the 'i++' in the for loop expression) is tagged 'unreachable' by my IDE
I have tried debugging the code line by line to see if i can decipher why the i++ is unreachable. I am unable to identify why. However, I suspect it might have to do with my 'return' statement
int main()
{
const int size = 4;
int array[] = { 345, 75896, 2, 543 };
int searchKey = 543;
std::cout << "Found at: " << search(array, size, searchKey);
return 0;
}
int search(int* array, int size, int searchkey)
{
while (1) {
std::cout << "Enter an Integer to search. Hit -1 to quit.\n";
scanf("%d", &searchkey);
if (searchkey == -1) {
break;
}
for (int i = 0; i < size; i++) {
if (array[i] == searchkey) {
return 1;
}
else {
return -1;
}
}
}
}
I expect the function to return the index of the array if a searchKey exists in the array, but it always ends up returning '-1'
The for loop is not quite right. The function returns in the first iteration of the loop regardless of the value of the first item in the array. If the first item matches the search key, the function returns 1. If not, it returns -1. It never touches the second item in the array.
You need to remove the else part. Return -1 only after the loop ends.
for(int i=0; i<size; i++){
if(array[i] == searchkey){
// Key was found. Return the index.
return i;
}
}
// Key was not found.
return -1;
Your logic in code decide to return 1 or -1 in the very first time in for loop, so it never touch the i++.
You should only return -1 when loop ended (when search done)
for(int i=0; i<size; i++){
if(array[i] == searchkey){
// return the INDEX of array when found immediately
return i;
}
}
return -1;

Recursive palindrome checking without using vectors, size or additional parameters

The question is simple - palindrome checking. The restrictions complicate it quite a bit:
Not allowed to use any string functions, or even the string header file (strlen()is out).
Not allowed to use vectors or iterators.
No additional parameters can be passed to the function (this means that solutions which use indexes for start and end cannot be used). This also means that size of the array cannot be passed.
Solution should be recursive.
This is the best I could come up with:
bool checkPalindrome(char input[]) {
static int count = 0, i = 0, done = 0;
while(!done){
if(input[i]!='\0'){
// length of string is stored in count
count++;
i++;
}
}
done = 1; i = 0;
if(count>0){
// check characters from start and end
if(input[i]==input[count-1]){
count = count - 2;
return checkPalindrome(input+1);
}
else
return false;
}
else{
return true;
}
}
But this doesn't work on the online IDE where I'm supposed to submit this. It just throws up a "Time Limit Exceeded" error. Could someone point me towards the right direction?
In the first loop, where you check the length of the string, is an infinite loop.
Done is always set to 0 and never change.
In fact, this flag is not required, you can modify the loop as follows:
while (input[i] != '\0') {
count++;
i++;
}
If you do want to keep the 'done' flag, you just need to set it to 1 if the if clause condition is false:
while (!done) {
if (input[i] != '\0') {
count++;
i++;
}
else
{
done = 1;
}
}

Why does skips the "if stack not empty" conditional, when the stack still has elements?

I'm trying to make a program to solve the eight queens problem, however it keeps reaching the last return, when it should not, and tried putting it on an else, but then it never reached it, even if i initially give it an empty stack.
Also for whatever reasons the first time i call the top() function, it return a different element than the last i added, but if i call it again it return the correct element.
So i would like to know where the problem is?
bool search(stack<nodo>& board, int n) {
nodo queen;
queen=board.top();
queen=board.top();
if (queen.y == n)
return true;
bool valid;
if (!board.empty()) {
queen.y += 1;
for(int i; i<=n; i++) {
queen.x = i;
valid = isvalid(queen,board);
if (valid) {
board.push(queen);
search(board,n);
}
}
board.pop();
}
return false;
}
use while not if
while(!board.empty()) {
queen.y += 1;
for(int i; i<=n; i++){
queen.x = i;
valid = isvalid(queen,board);
if (valid) {
board.push(queen);
search(board,n);
}
}
board.pop();
}
if means check for one time only , but while mean do the samething till board.empty() == true.

C++ Sorting a struct vector alphabetically

I've got a task that I'm stuck on. I need to create a program that reads an input file, stores each word into a vector along with how many times that word was read (hence the struct). Those values then need to print out in alphabetical order.
I've come up with something that I think is along the right lines:
struct WordInfo {
string text;
int count;
} uwords, temp;
string word;
int count = 0; //ignore this. For a different part of the task
vector<WordInfo> uwords;
while (cin >> word) {
bool flag = false;
count += 1;
for (int i = 0; i < uwords.size(); i++) {
if (uwords[i].text == word) {
flag = true;
uwords[i].count += 1;
}
}
if (flag == false) {
if (count == 1) { //stores first word into vector
uwords.push_back(WordInfo());
uwords[0].count = 1;
uwords[0].text = word;
} else {
for (int i = 0; i < uwords.size(); i++) {
if (word < uwords[i].text) {
uwords.push_back(WordInfo());
WordInfo temp = {word, 1};
uwords.insert(uwords.begin() + i, temp);
}
}
}
}
}
Now the problem I'm having, is that when I run the program it appears to get stuck in an infinite loop and I can't see why. Although I've done enough testing to realise it's probably in that last if statement, but my attempts to fix it were no good. Any help is appreciated. Cheers.
EDIT: I forgot to mention, we must use vector class and we're limited in what we can use, and sort is not an option :(
if (word < uwords[i].text) {
uwords.push_back(WordInfo());
WordInfo temp = {word, 1};
uwords.insert(uwords.begin() + i, temp);
}
Take a good look at this piece of code:
First, it will actually insert 2 words into your list; one time an "empty" one with push_back, and one time with insert. And it will do that whenever the current word is smaller than the one at the position i.
And as soon as it has inserted, there's 2 new elements to walk over; one actually being at the current position of i, so in the next iteration, we will again compare the same word - so your loop gets stuck because index i increases by 1 each iteration, but the increase of i only steps over the just inserted element!
For a quick solution, you want to (1) search for the position where the word before is "smaller" than the current one, but the next one is bigger. Something like
if (uwords[i-1].text < word && word < uwords[i].text) {
(2) and you want to get rid of the push_back call.
Furthermore, (3) you can break the loop after the if condition was true - you have already inserted then, no need to iterate further. And (4), with a bit of condition tweaking, the count == 1 can actually be merged into the loop. Modified code part (will replace your whole if (code == false) block - warning, not tested yet):
if (!flag) {
for (int i = 0; i <= uwords.size(); ++i) {
if ((i == 0 || uwords[i-1].text < word) &&
(i == uwords.size() || word < uwords[i].text)) {
WordInfo temp = {word, 1};
uwords.insert(uwords.begin() + i, temp);
break;
}
}
}
You should not push your words nin vector, but in map
std::map<std::string,int>
Since map has comparable keys iterator over map, automaticaly returns sorted range that can be later pushed in vector if needed.