For a comsci project I have been assigned recently, we have to implement our own version of the STL Map using a Linked List. In our operator[] overload function though we cannot figure out how to access and return the "int&".
This is what we have tried doing so far:
int& LLMap::operator[](string key){
//return this->myMap.searchforNodeAddress(key)->getPairValue();
return this->myMap.searchforNodeAddress(key)->getPairValueAddress();
}
And here are the implementations of the functions being called:
PairNode* PairLinkedList::searchforNodeAddress(string desiredKey){
PairNode* currNode = this->getPairHead();
while (currNode != NULL){
if (currNode->getPairKey() == desiredKey){
return currNode;
}
else{
currNode = currNode->getNext();
}
}
}
And
int PairNode::getPairValue(){
return this->value;
}
int* PairNode::getPairValueAddress(){
return &(this->value);
}
We have been trying to figure this out for quite some time now and are completely stumped, any pointers in the right direction or any assistance at all would be greatly appreciated. Thank you
You can either dereference the address...
return *myMap.searchforNodeAddress(key)->getPairValueAddress();
...or change getPairValue()...
int& PairNode::getPairValue() // now returns int&
Separately, the STL map (lowercase "m") is confined to history - you probably mean the C++ Standard Library std::map, and you can't strictly "implement" either with a linked list: they're necessarily balanced binary trees, given the Standard's performance guarantees. You can implement something with a std::map-like interface - minus those performance characteristics - over a linked list....
Also, prefer to pass string parameters that won't be modified inside a function using const std::string&: it avoids allocating extra memory and copying the text over, only to release it after the function exits.
Related
This code is for finding the intersection and union of two sorted lists. The sorted list in inherited from a list class with all the basic functions. The main question is what is the return type of the function.
Is it a pointer to a list or the list itself? How would i display the contents of that "pointer".
template <typename Object>
class sorted_list : public List<Object>{
friend sorted_list<Object>*& slUnion( const sorted_list<Object>& list1, const sorted_list<Object> & list2){
auto i=list1.begin();
auto j=list2.begin();
sorted_list<Object> un;
static sorted_list<Object>* newlist=&un;
while(i!=list1.end() && j!=list2.end()){
if(*i<*j){
un.push_back(*i);
i++;
}
else if(*i>*j){
un.push_back(*j);
j++;
}
else{ //if equal
un.push_back(*i);
i++; j++;
}
}
while(i!=list1.end())
un.push_back(*i++);
while(j!=list2.end())
un.push_back(*j++);
return newlist;
}
};
When the program runs, the "un" in main points to NULL.
int main(){
sorted_list<int> l1;
int i=1;
while(i<10){
l1.push_back(i++);
}
sorted_list<int>l2;
int j=1;
while(j<10){
l2.push_back(j);
j+=2;
}
sorted_list<int> *un = slUnion(l1,l2);
}
You should typically return by value, i.e. sorted_list<Object>. Newer versions of cpp guarantee you that they will not actually make a copy.
What you are doing right now is wrong, because it has undefined behavior. You are using un, which is on the function stack, and return a pointer to it. By the time the function returns un has gone out of scope and the memory location can have been reused. Just completely remove the newlist pointer and return un instead.
You also seem to be confused about classes, methods and functions. As it is, your method does not have to be inside a class, or, since it does not seem to use class state, it can be static, if inside a class. It also does not seem like it would have to be a friend. If you wanted to write this as a member-function, it would look sth like this:
sorted_list<Object>& unionWith(const sorted_list<Object>& rhs) {
// merge this and rhs w deduplication into temp, then swap temp with this
...
return *this;
}
I think what is likely your problem, is that you don't assign &un to newlist, but that you initialize newlist with &un. Initialization is only performed once for a function-static variable, so future iterations of your method just skip that line and the pointer points to where the original version of un was. Try putting the assignment on a different line. That should fix your immediate issue, but the solution with the static pointer is still really bad, because the pointer is shared by all instances.
I have to implement a two way ordered list at a specific way, and I got stuck. I have a Bag class that has an Element class inside it. Now the problem is when I want to place an item inside the bag.
An element has a key (its value), a pointer to the smaller element (_down), and one to the larger (_up). When I put a new element inside the bag the code is the following (names translated so it's easier to understand)
void Bag::put(int e) {
if(_item_count==0){
Element *element = new Element(e, nullptr, nullptr);
_bot = element;
_top = element;
}else{
Element *p = _bot;
while(e > p->key()){
p = p->up();
}
Element *element = new Element(e, p, p->down());
p->down() = element;
}
}
So the problem is that p->down() is not assignable. I guess I should return the pointer by reference, but I don't know how to do that.
down() function
Bag::Element *Bag::Element::down() {
return _down;
}
I tried putting & at great many places, but I just can't figure out how to make it all work.
Here's the full code if needed, but it's variables are mostly Hungarian, I'll provide translation if needed.
Header on the left, cpp on the right
This will return a non-const lvalue reference to pointer which is good to be assigned to:
Bag::Element *&Bag::Element::down() {
return _down;
}
And perhaps you should also provide a const overload:
Bag::Element * const &Bag::Element::down() const {
return _down;
}
Of course you should update your class declaration accordingly.
And also you may consider using a struct for such simple classes like Element while making pointer fields public (which is the default access control for structs. Typically you won't get bashed for doing this in C/C++, unlike in Java where people tend to insist on using private fields and getter/setters even for super simple classes. (I'm not saying this good or bad, just a sort of convention.)
Just assign the pointer directly:
p->_down = element;
Note that you are only modifying the "down" pointer of the next element. You also need to modify the "up" pointer of the previous element.
Note also that your new element may be the first or the last element in the list, you should handle these cases specially. Once you do that, you may discover that special handling of the empty list is unnecessary.
I am having a huge issue with my recursive function in my binary search tree. My project is due in a few hours and I cannot for the life of me get ahold of my instructor.
My function seems to only be traversing the left most branch of my tree.
Assignment Operator:
template<typename Type>
BST<Type>& BST<Type>::operator=(const BST& that)
{
if(this != &that)
{
this->clear();
Node *c = that.root;
preORet(c);
}
return *this;
}
Recursive Function Called:
template<typename Type>
void BST<Type>::preORet(Node *c)
{
this->insert(c->data);
if(c->left != nullptr)
preORet(c->left);
else if(c->right != nullptr)
preORet(c->right);
}
As an aside, I understand that a lot of this may look like seriously bastardized code, but this is how my instructor expects it to look.
Thank you in advance.
Your problem is right here:
if(c->left != nullptr)
preORet(c->left);
else if(c->right != nullptr)
preORet(c->right);
You don't want an else if. You want to traverse the right sub-tree regardless of whether the left sub-tree was a nullptr.
In addition to taking out the else in your preORet() function, as the others have pointed out, it's also worth noting that you will get a segmentation fault (error code 11) if you happen to pass in a null pointer through your parameter Node *c.
Here is a solution:
template<typename Type>
void BST<Type>::preORet(Node *c)
{
if (c != nullptr)
{
this->insert(c->data);
preORet(c->left);
preORet(c->right);
}
}
This way, every pointer get's checked to see if it is null before being used, including the left and right pointers. If it is null, it'll just fall through, out of scope.
Get rid of the else in preORet().
Get rid of that else.
As your design looks, at first glance, to be easily move or swap able, I would use the copy-swap idiom to generate a reasonably efficient, easy to write operator=.
But that is just me.
this is my first time using the list STL and i'm not sure if what i'm trying to do is possible.
I have class_B which holds a list of class_A, I need a function in class_B that takes an ID, searches the list for an instance with the same ID, and gets a pointer form the list to the instance in that list:
bool class_B::get_pointer(int ID,class_A* pointer2A){
list<class_A>::iterator i;
for(i=class_A.begin();i!=class_A.end();i++){
if((*i).get_id()==ID) {
\\pointer2A=(i);<---------------this is what I'm trying to do
return true;
}
}
pointer2A=NULL;
return false;
}
how do I perform this, is it possible to convert from iterator to instance ?
EDIT:
I'm using this function in a multi-threaded program and I can't return an iterator to the calling function since another thread might delete an element of the list.
Now that I have a pointer to my element(and lets say it's locked so it can't be deleted), and a different thread removed another element and performed a sort on the list, what will happen to the pointer I'm holding ? (I don't know how the list rearranges the elements, is done by copying the elements using a copy c'tor, or by another mean?).
Useless answer was the most helpful in my case (BIG thanks), and yes I should use a reference to the pointer since I'm planing to change it.
You should write this:
pointer2A= &*i;
Here *i returns the object whose address you can get by prepending & as : &*i.
Note that i is not same as &*i. See this topic for more general discussion:
Difference between &(*similarObject) and similarObject? Are they not same?
Anyway, I would suggest you to read the pointer itself as:
class_A* class_B::get_pointer(int ID)
{
//I assume the name of the list is objA, not class_A
for(list<class_A>::iterator i=objA.begin();i!=objA.end();i++)
{
if( i->get_id()==ID)
{
return &*i;
}
}
return NULL; //or nullptr in C++11
}
Or, in C++11, you can use std::find_if as:
auto it = std::find_if(objA.begin(),
objA.end(),
[&](class_A const &a){ return a->get_id() == ID;});
classA *ptr = NULL;
if ( it != objA.end())
ptr = &*it; //get the pointer from iterator
Make sure get_id is a const member function.
if(i->get_id()==ID) {
pointer2A=&*i;
return true;
}
iterators are designed to have similar semantics to pointers, so for example you can write i->get_id() just as if you had a pointer to A.
Similarly, *i yields a reference A&, and &*i converts that back into a pointer - it looks a bit clunky (it would be an identity operation if i were really a pointer), but it's idiomatic.
Note that this won't do what you presumably want anyway - the caller's class_A* pointer2A is passed by value, so only get_pointer's copy of the pointer is modified, and the caller won't see that value. Try this:
bool class_B::get_pointer(int ID, class_A *& pointer2A)
{
list<class_A>::iterator i;
for(i=class_A.begin();i!=class_A.end();i++) {
if(i->get_id()==ID) {
pointer2A=&*i;
return true;
}
}
pointer2A=NULL;
return false;
}
Now pointer2A is passed by reference, so the caller's copy gets modified inside your function.
BTW, you can read the parameter declaration class_A * & pointer2A right-to-left, as "pointer2A is a reference to a pointer to class_A".
If you have an iterator, you can get a raw pointer by simply dereferencing the iterator (which gives you a reference), and then taking the address of that (which gives you a pointer). So, in your case:
pointer2A = &*i;
This might seem like an odd, clumsy way to get a pointer, and it is. But you normally don't care about pointers when you are using the collections & iterators from the Std Lib. Iterators are the glue that hold the "STL" together. That's what you should be dealing with, by and large, rather than raw pointers.
The loop you've written above certainly gets the job done that you wish to accomplish, but there are better* ways to accomplish the same goal. (Better is a subjective term.) In particular, the <algorithm> library provides both std::find and std::find_if which do just what they say they do. They find something in a collection. find will find something that is equal to what you're looking for. find_if will find something that matches some criteria that you specify. The latter is the appropriate algorithm to use here, and there are two main ways to use it.
The first, more "traditional" approach is to use a functor:
struct match_id : public std::unary_function<bool, class_A>
{
match_id(int ID) : id_(id) {};
bool operator()(const class_A* rhs) const
{
if( id_ == rhs->get_id() )
return true;
else
return true;
};
/* ... */
list<class_A>::iterator it = std::find_if(objA.begin(), objA.end(), match_id(ID));
This approach works in C++03 or C++11. Some people don't like it because it is rather verbose. I like it, on the other hand, because the actual buisness logic (the find_if call) is quite succinct and more expressive than an explicit loop.
In C++11, you can use a lambda in place of the functor:
unsigned ID = 42;
std::find_if( objA.begin(), objB.end(), [&ID](const class_A& rhs) -> bool { return rhs.get_id() == ID; } };
There's a tradeoff here. On the pro side, you don't have to write 10 or so lines of code for the functor, but on the con side, the lambda syntax is funky and takes a bit of getting used to.
The code below deletes the symbol associated with the stock object just fine. Its just bad object oriented design.
The way that i am searching for each stock symbol is by using a != or == test for NULL.
bool hashmap::remove(char const * const symbol, stock &s,
int& symbolHash, int& hashIndex, int& usedIndex)
{
if ( isAdded == 0 ) return false;
if ( hashTable[isRemoved].symbol == symbol ) return true;
else
{
symbolHash = this->hashStr( symbol );
hashIndex = symbolHash % maxSize;
usedIndex = hashIndex;
}
for ( int integer = 0; integer < maxSize; integer++ )
{
if ( hashTable[usedIndex].symbol != NULL &&
strcmp( hashTable[usedIndex].symbol, symbol ) == 0 )
{
isAdded--;
isRemoved = hashIndex;
s = &hashTable[usedIndex];
delete hashTable[usedIndex].symbol;
hashTable[usedIndex].symbol = NULL;
return true;
}
++usedIndex %= maxSize; // wrap around if needed
}
return false;
}
Im wondering now, if i delete in a such a way that:
hashTable[usedIndex].symbol = hashTable[NULL].symbol
Thereby, changing the way I logically test for an empty or found stock symbol. Is their a way to remove my stock symbol without having to redo the aspect of finding and searching?
Is this the correct way to remove in object oriented design?
First of all, "object oriented design" is very ambiguous.
Is isAdded a member variable? It isn't clear that it is and creates another dependency on this function that isn't obvious when looking at the signature. Same thing goes for isRemoved.
Generally, a function that takes 5 arguments is getting close to showing that there is too much dependencies on this function (nevermind the invisible dependencies in isAdded, isRemoved, and hashTable).
I'm not sure what type hashTable is, but you should never have to call delete in 2009. You can use auto_ptr, shared_ptr, unique_ptr (in C++0x). These will take care of freeing your resource when it is not needed anymore. If you are using an STL container, then don't use auto_ptr though.
If you would like to use a hashtable in C++, you really should consider using a hash_map. That will be a much better implementation than 99.9999% of us can accomplish.
When using a hash_map, you can call void erase(iterator first, iterator last) to erase/delete an element.
How is an insert collision handled? Most standard solutions—such as a linear search for an open slot, or generating a new hash—make deleting an element problematic. If deletions are common, consider using a list structure instead.