searching for a key in a bst - c++

the compiler is telling me that the assertion failed even though I have atleast 2 items in the array of linked nodes. How do I fix this bool contains function? And yes, I have tried multiple ways but I still get the same error.
Keep in mind that there are 2 items in different indexes of the array. But its not shown below.
This is the contain function:
bool Map::contains(string key){
bool idk = false;
if(elementsStoredCount != 0){
int idk = hashFunc(key); //the hashFunc computes using modulo
if(array[found] != nullptr){
idk = false;
}
else{
found = true;
}
}
return found;
}
when I test in my main.cpp, the second line fails for some reason.
assert(as.contains("1")==true);

Based on some of the other comments and reading the code, i would think that your problem is that your int hashFunc(string key) function is returning an incorrect index outside of the range of array[].
Have you debugged/tested taht the hashFunc() function to ensure the correct data? If correctly implemented and still you are facing a bug, then i'd next look at your table data/insertion functions.

Related

intersection function gets stuck after output

void intersectionLists(LinkedList argList) {
bool common = false;
ListNode* thisCurrentPointer{headPointer};
ListNode* argCurrentPointer;
cout <<"common elements between both lists are:\n";
while(thisCurrentPointer != nullptr) {
argCurrentPointer = argList.getHeadReference();
while(argCurrentPointer != nullptr){
if(thisCurrentPointer->data == argCurrentPointer->data) {
cout <<thisCurrentPointer->data;
common = true;
break;
}
argCurrentPointer = argCurrentPointer->nextPointer;
}
thisCurrentPointer = thisCurrentPointer->nextPointer;
}
if(!common) {
cout <<"none\n";
}
thisCurrentPointer = nullptr;
argCurrentPointer = nullptr;
delete thisCurrentPointer;
delete argCurrentPointer;
}
Hello everyone,
Iwas making this function for intersection in the linkedList class, which has the parameter of another linkedList object, one utility function i am using on line 9 is getHeadReference(), which simply returns the address stored in the headPointer (i am using this function in order to get argCurrentPointer to point at the head of the list that came in the parameter).
Anyway.. the function gives perfectly fine output of whatever two linked lists are but the control get "stuck" right after its execution, the control freezes, and a huge garbage value is returned, i really hope i am being clear.
I have dry run the code i can not seem to find the problem. Even in main when i call another function after the execution of "intersectionLists" function, the called function gets executed properly without any delay but the control can't seem to exit main after all the work is done, when i don't call this intersection code, no hang or delay whatsoever is observed, please help. Thank you.
I think this is because you detele thisCurrentPointer and argCurrentPointer after setting them to null. It is not necessary to do any deletion after as you are not duplicating your nodes.

C++ Statement can be simplified

Apologies for the lame question. I am using Intellij Clion Student licensed version for my C++ curriculum. As a part of implementing an UnsortedList class, we had to write a method isInTheList to see if an element is present in the array. The class implementation goes as
bool UnsortedList::isInTheList(float item) {
for (int i = 0; i < length; i++) {
if (data[i] == item) {
return true;
}
return false;
}
}
However, the ide shows a coloured mark at data[i] == item with a popup saying
Statement can be simplified less... (Ctrl+F1)
This inspection finds the part of the code that can be simplified, e.g. constant conditions, identical if branches, pointless boolean expressions, etc.
For a previous method to check if the list if empty, I used the following simplified form instead of if-else statement.
bool UnsortedList::isEmpty() {
return (length == 0);
}
However, with iteration involved now, I cannot come up with a simplified statement in the former. Any help is much appreciated. Thank you.
Fix
Your return false should be moved outside off the for loop.
Because you accidentally put it inside the for loop, this iteration never execute for the second time.
So your IDE thinks the for loop is pointless, and suggests you to simplify it to:
return data[0] == item;
This obviously isn't what you want. So really this is just a one-line shift to make it right.
Why not use STL?
inline bool UnsortedList::isInTheList(float item) {
return std::find(data, data+length, item) != data+length;
}
std::find returns an iterator pointing to the element if it's found, or an iterator equal to one-past-last item (i.e. exactly the second argument passed) if nothing is found. You can use a simple equality check to decide if one is found.
You are actually returning after one iteration in your loop. That's the remark of your compiler.
Your code could be simplified by easy write this:
bool UnsortedList::isInTheList(float item) {
if (length != 0) {
return data[0] == item;
}
}
Note, that this is still undefined behavior (UB). You do not have a return in all of your execution paths.
If your list is empty, you never enter the loop, which results in an UB, because there is no return statement, but the function has to return a bool.
I think, your intention was, to write something like this.
bool UnsortedList::isInTheList(float item) {
for (int i = 0; i < length; i++) {
if (data[i] == item) {
return true;
}
}
return false;
}
Move the return false; out of your for loop and you will be fine (still there are better ways to implement this, but that's another topic).

VS2013 C++: Map - Unhandled Exception, Out of Range

I'm trying to create a function that keeps track of recently used addresses, using a vector of maps for each index. Each time the address (used as the map key) is found, it would update the key member variable value. If its not a mapped value in the table, it will add it. That way I can keep track of older vs. newer addresses. Initially I tried to code it in the following manner:
int key = 0;
void update(uint32_t address, int index, vector<map<uint32_t, int> >& table)
{
auto search = table.at(index).find(address);
if(it != table.at(index).end())
{
table[index][address] = ++key;
}
else
{
table.at(index).insert(make_pair(address, ++key));
}
}
However, every time I go to test my function, VS2013 always throws an unhandled exception error informing me that the Unhandled exception was thrown because std::out_of_range when it gets to the auto search line. I figured the error was thrown because the map starts off initially empty, and there are no maps available for it to search through for any addresses. So then I modified it to determine first if the table is empty, if so insert the first pair, otherwise if its not, search the table for the address value, and update the key:
int key = 0;
void update(uint32_t address, int index, vector<map<uint32_t, int> >& table)
{
if(table.at(index).empty())
{
table.at(index).insert(make_pair(address, key));
}
else
{
auto search = table.at(index).find(address);
if(it != table.at(index).end())
{
table[index][address] = ++key;
}
else
{
table.at(index).insert(make_pair(address, ++key));
}
}
}
But then the same exception occurs at the if(table.at(index).empty()) line. Then I scaled it down, just to see if I could just simply capture and store any maps at all:
int key = 0;
void update(uint32_t address, int index, vector<map<uint32_t, int> >& table)
{
table.at(index).insert(make_pair(address, ++key));
}
And that generates the same unhandled exception also at table.at(index).insert(make_pair(address, ++key)).
Not only that but I've tried determining if the table.at(index) == NULL or nullptr or 0. Looked for alternative means of adding the map pairs to the vector, instead of using insert. Unfortunately, the options I was looking at don't exist for map (i.e. assign or push_back). I also looked into implementing a try-catch statement, but wasn't exactly sure on how to code it, especially with the "throw" keyword.
I have no idea what could be causing this issue. Does anyone have any suggestions on what could be the problem? Or what I'm doing wrong? Maybe my program doesn't like my vector of maps possibly?
Thank you!

Trouble erasing items through list while iterating

Okay, I have a STL list of references I am iterating through. This function has three equivalent parts. The function takes a wstring as a parameter, and runs the appropriate if statement. I have reduced the code to one if statement to try and get it working.
So, I check to see what has been passed in as an argument. I then check to see if the ClassItem is a certain type of animal. If it is, I check if it is hungry, and erase it from the list. I am just trying to avoid seg faults right now, and cannot seem to do it.
list<ClassItem *>::iterator i = Items.begin();
while(i != Items.end())
{
if(!AnimalType.compare(L"tiger"))
{
if((*i)->IsAnimalType(L"tiger"))
{
if((*i)->IsHungry())
{
i = Items.erase(i);
}
}
else
{
++i;
}
}
// I have tried removing this
else
{
i++;
}
}
I was under the impression that the current iterator is invalidated when I call erase. So, if I erase an element, I return the next valid iterator. Where am I going wrong?
EDIT: Thank you for all the quick help. The problem has been fixed. I have made use phresnel's solution and it worked wonderfully.
You are better off by using std::list::remove_if with a suitable predicate. This avoids the manual loop entirely, reducing scope for errors, and helping to either remove or at least you localise the source of the problem, since you can rely on this idiom being correct as long as your predicate is.
bool badAnimal(ClassItem * item)
{
// return true if animal is to be removed
}
Items.remove_if(badAnimal);
I see no potential for a segfault here. Anyways:
There are (IMHO) two possible problems:
if(!AnimalType.compare(L"tiger"))
This looks fishy. What is AnimalType? Do you really expect the value of if(!AnimalType.compare(L"tiger")) to change during iteration, if AnimalType itself does not?
In any case, it looks like a read, therefore shouldn't write. It looks constant, therefore shouldn't change.
Then:
if((*i)->IsAnimalType(L"tiger"))
{
if((*i)->IsHungry())
{
i = Items.erase(i);
}
// NO ITERATION IN CASE OF NOT HUNGRY.
// ONCE TRAPPED HERE, YOU HAVE AN INFINITE LOOP,
// EXCEPT AnimalType.compare(L"tiger") DOES SOMETHING
// NON-SANE.
}
else
{
++i;
}
this should better be:
if((*i)->IsAnimalType(L"tiger") && (*i)->IsHungry())
{
i = Items.erase(i);
}
else
{
++i;
}
However, even better would be to use the standard algorithms for element removal.
you may want to add
continue;
after your erasion.

Strange seg fault with function pointer returning a value

While learning C#, I found it fun to reimplement things like List or LinkedList just to understand how it works and potential problems you may have while implementing it.
While learning C++, since I have some experience in C#, I decided to challenge myself and attempt to implement more advanced code than what the end of chapter activities ask. So, I ended up trying to implement a non generic list in C++ to try it out, but ended up receiving a very weird seg fault.
A small disclaimer on the code, while trying to fix it I ended up refactoring it and removing stuff (none of it changed the error, though) so a function or two has no use but after a few hours trying to understand the problem, I don't want to remove or change anything and accidently fix the problem. Anyway, here's the code.
class List {
private:
int *ListData;
size_t ListSize;
size_t Pos;
std::stack<size_t> NullList;
size_t InternalNull();
inline size_t PosOnly();
void Check();
size_t (List::*NextNumber)();
public:
List(bool InternalNullHandle);
List(size_t DefaultSize, bool InternalNullHandle);
~List();
void Add(const int SalesRef);
int GetCopy(size_t Pos);
int Get();
};
List::List(bool InternalNullHandle) {
NextNumber = (InternalNullHandle) ? &List::InternalNull : &List::PosOnly;
ListSize = 32;
ListData = new int[32];
Pos = 0;
}
List::List(size_t DefaultSize, bool InternalNullHandle) {
NextNumber = (InternalNullHandle) ? &List::InternalNull : &List::PosOnly;
ListSize = DefaultSize;
ListData = new int[DefaultSize];
Pos = 0;
}
List::~List() {
delete[] ListData;
}
void List::Check() {
if (Pos >= ListSize) {
size_t OldSize = ListSize;
ListSize*=2;
int *Buffer = new int[ListSize];
memcpy(Buffer, ListData, sizeof(int)*OldSize);
if (ListData != NULL) {
delete[] ListData; //POINT OF INTEREST ONE
ListData = NULL;
}
else {
std::cerr<<"ListData is null."<<std::endl;
}
ListData = Buffer;
}
}
size_t List::InternalNull() {
if (NullList.size() != 0) {
size_t ToReturn = NullList.top();
NullList.pop();
return ToReturn;
}
return PosOnly();
}
inline size_t List::PosOnly() {
size_t Old = Pos;
++Pos;
Check();
return Old;
}
inline void List::Add(const int SalesRef) {
//size_t Value = (this->*NextNumber) ();
//ListData[Value] = SalesRef;
//if the above code is utilised instead, everything works fine
ListData[ (this->*NextNumber) () ] = SalesRef; //POINT OF INTEREST TWO
}
inline int List::GetCopy(size_t Pos) {
return ListData[Pos];
}
I normally don't post, but google extensively. I ended up installing and running valgrind, which gave read and write errors at Point of Interest One when Point of Interest Two was used. However, when Point of Interest Two was commented out and the commented lines were used, no problems were given.
The problem only arises after 128 iterations, meaning it doubles to 64 and 128 correctly as well as deleted the arrays correctly.
Also, as a note, the code ran perfectly fine on Windows compiled with g++.
I tried to reproduce the error using a separate class, but it worked perfectly fine.
Again, I know I should use the standard containers (and I will) but I like to understand everything and the fact that I can't figure this out is extremely annoying. Coupled with the fact that I can't even reproduce it and had to copy this incomplete and badly designed code just makes it worse. Thanks for the help in advance!
Minor edit, if it's really hard to read I'll add comments and try to clean the code up without breaking (well, fixing, rather) it. The OSes it was tested on was Windows 7 with mingw (which worked) and Debian with g++ (which only worked with the commented lines uncommented).
The problem with the statement
ListData[ (this->*NextNumber) () ] = SalesRef; //POINT OF INTEREST TWO
is that there's no sequence point between fetching the value of the field ListData and calling the member function pointed at by NextNumber. So the compiler is perfectly happy doing that load before the function call and then doing the indexing off of it after the call. However, that call may result in reallocating ListData, so the pointer it got from before the call is now dangling (it points at the just deleted array) and bad things happen.
With the commented out code, you force the function call to occur before the fetch of ListData, so that fetch will always get the right value after the resize reallocation.