LinkedList: Push using dummy nodes - c++

So, I am implementing a LinkedList using dummy nodes to represent the front and the back of the list that remain empty (or _head and _tail) respectively.
I'm attempting to create a push function that inserts an element to the front of the linked list, yet for some reason I keep getting an error.
Here's the code
void push(const T& x)
{
if (count == 0)
{
_head->_next = _tail;
}
// Creates a new node with the user input data.
Node* current = new Node;
current->_data = x;
current->_next = _head->_next;
_head->_next = current;
count++;
}
Count is a instance variable that is used to keep track of the size of the list, and is defaulted to 0. And _data is the data value assigned to the current node.
For some reason, the compiler is stating that head->_next points to null, thus it can't assign the value to current. But I figured this issue would be handled by adding the if statement in the beginning.
Any suggestions?
Thanks in advance!

Related

Creating a second singly-linked list in reverse order of another list

I need to create a function that takes a normal singly-linked list and creates another list in reverse order of the first list, the first element in the new list will be the last element in the original list and so on.
My function for some reason only ever returns the same number over and over for the entirety of the new list. Therefore, if the last number in my original list is e.g. '50', the new list will be made up entirely of '50's.
This is my code, what am I doing wrong? If anyone wants me to post the whole program for more clarity or context give me a shout.
void invert() {
node *list1=top,*newlist,*temp,*prev;
while (list1->next!=NULL) {
list1=list1->next;
}
newlist=new node;
newlist->num=list1->num;
newlist->next=NULL;
if (top2==NULL) {
top2=newlist;
}
else {
for (temp=top2;temp!=NULL;temp=temp->next) {
prev=temp;
}
prev->next=newlist;
}
list1->next=NULL;
}
Your code cannot be correct as it creates only a single new node and then modifies the next link in existing nodes. From your requirements, you have to create a new list which means cloning all nodes and linking them in the reverse order.
Following the suggestion of #user4581301, I came up with the following:
node* invert(node* list)
{
node* inverted = NULL;
// run through original in order
for (node* p = list; p != NULL; p = p->next)
{
// clone the node
node* newNode = new node();
newNode->num = p->num;
// and link it so that the predecessor in the original list
// (which has been processed in the previous iteration) is
// linked as next node
newNode->next = inverted;
inverted = newNode;
}
return inverted;
}

How can I delete a node in my linked list in C++?

I've pasted my work so far here:
http://codepad.org/WhJuujRm
The concepts of linked lists boggle my mind, so I thought I'd practice. I know how to add nodes, and edit nodes, but I don't know how to remove nodes in my particular scenario.
My Pseudo Code:
previous == now - 1;
if(stdid == now->getID());
previous->setNext(now->getNext);
delete now;
return;
How could I implement this?
The mind-tease in deleting an element from a linked list is updating the pointer that brought you to the element in the first place. In your list case, that could be top (and/or possibly bottom), it could be some node's next. As you walk through the list hunting with a cur pointer, keep a prev pointer which you advance one step behind as you enumerate. Assuming you find the victim node (if you don't, there's nothing to do, woot!), prev will be in one of two states:
It will be NULL, in which case top is the pointer that refers to your victim node and top must be updated, or...
It will be some pointer to a node, in which case that node's next member needs to be updated to the reflect the victim node's next member value.
In both cases bottom may need updating as well. In the first case bottom will need to change if the list only had one node and you're deleting it. i.e. you will have an empty list when finished. Easy enough to tell, since top will be NULL after to detach cur and set top equal to cur->next. Even easier for you, since you're keeping a size member in your list container; if it was 1, you know both head and bottom
In the second case, the last node may be the victim node. In that case bottom has to be updated to reflect the new end of the list (which is coincidentally in prev, and may be NULL if, once again, the list had only a single element. How do you tell if the victim was the last node in the list? If it's next member is NULL, it has to be the last node, and bottom must be updated.
So something like this, a delete function based on ID search
void deleteStudent(int id)
{
student *cur = top, *prev = nullptr;
while (cur && cur->getID() != id)
{
prev = cur;
cur = cur->getNext();
}
// found a node?
if (cur)
{
student *pNext = cur->getNext();
// set new next pointer for prev, or new top
if (prev)
prev->setNext(pNext);
else
top = pNext;
// update bottom if needed
if (!pNext)
bottom = prev;
delete cur;
--scnt;
}
}
Other delete options and criteria I leave to you.
Best of luck.
This should work, but I have not tested it.
There is a special case, when the first node is deleted. previous is set to NULL for the first iteration, and the top has to be adjusted in this case.
I didn't use bottom, because it's not the way I would do it. If you use bottom, there is a second special case, when you delete the last student. I would mark the end of the list with a next pointer set to NULL, because this eliminates this special case.
bool deleteStudent(int id)
{
student* now = top;
student* prev = NULL;
while(now != NULL) {
student* next = now->getNext();
if(id == now->getID()) {
delete now;
if(prev) prev->setNext(next);
else top = next;
return true;
}
prev = now;
now = next;
}
return false;
}
I did not use your notation but I think you can get the point.
prev = NULL;
current = top;
while (current != NULL && !isfound(current)){
prev = current;
current = current->next;
}
// current point to the element you want to delete (if not NULL)
if(current != NULL) {
if(previous != NULL) {
previous->next = current->next;
}
else {
top = current->next;
}
delete current;
}

Return a pointer to a sorted list; linked list in C++

i want this function sortPair to take 2 Node pointers and return a pointer to a list of the 2 elements sorted alphabetically. The code below is what I have so far. If someone could let me know where I went wrong, that would be great.
struct Node{
string val;
Node* next;
};
Node* sortPair (Node* p1, Node* p2){
//Assert that neither pointer is null
assert(p1!=NULL);
assert(p2!=NULL);
Node* head=NULL;
Node* current=NULL;
Node* last = NULL;
current = new Node();
if(p1-> val >p2-> val) //If p1->val comes before p2->val in the alphabet
{
current->val = p1->val;
head = current;
last = current;
current = new Node();
current -> val = p2->val;
last = current;
last ->next = NULL;
}
else
{
current->val = p2->val;
head = current;
last = current;
current = new Node();
current -> val = p1->val;
last = current;
last ->next = NULL;
}
return head;
}
A linked list is just a series of nodes that are linked by each element having a pointer to the next one.
From your code, it seems like you do not want to make a list of the two nodes, but rather insert a node into a list that already exists.
If all you want to do is to make a linked list of the two nodes that are there, then set the one with the lower or higher value, depending on how you sort them, to point at the other one. For example, if you are sorting from smallest to biggest, set the smallest node's next pointer to point to the bigger one and return the pointer of the smallest one.
If you want to add one of the nodes into a list of nodes, then you must loop through the list until you find one that is larger or smaller than the node you want to insert. I recommend using a while loop.
If you want to merge two lists, then you must make a new loop that inserts each element of one list into the other list.
There is no need to make a new node for any of this, just use the ones you have and change the next pointers.
Hope this helps.

Nodes in binary tree are null

void MultiMap::insert(string key, unsigned int value)
{
if(head == nullptr)
head = new Node(key, value);
else
{
Node* tempNode = head;
while(tempNode != nullptr)
{
if(key <= tempNode->m_key)
tempNode = tempNode->m_left;
else if(key > tempNode->m_key)
tempNode = tempNode->m_right;
}
/*line 1*/tempNode = new Node(key, value);
//*line 2*/head->m_left = new Node(key, value);
}
}
For an assignment, I have to make a binary tree class, "MultiMap" with nodes that contain a string and an int.
The above is code to insert a new node into the tree. The nodes are sorted by their strings. If the string of the node I am trying to insert is > the current node, the program should try to insert it on the right branch of the tree, and if it is <=, the program should try to insert it on the left branch of the tree.
I tested it by trying to insert two nodes: (Joe, 5) and (Bill, 1) in that order, so if the program works properly, "bill" should be on the left branch of "joe".
Line 2 is commented out.
If I use line 1, the program compiles and "inserts" the second node, but when I try to look for it with other code, it only finds a nullptr. If I replace line 1 with line 2, the program works as expected.
"tempNode" is what I'm using to trace through the tree to find the appropriate place to insert a new node. "head" is a pointer to the first node in the tree. "m_left" and "m_right" are pointers to nodes, representing the left and right branches of a node, respectively.
I don't know why the two lines don't do the same thing even though at that point, it seems like tempNode and head->m_left are pointing to the same location in memory: the left branch of the first node.
Pointers are variables that hold addresses. There is nothing magic about them. Line 1 does this:
tempNode = new Node(key, value);
This doesn't insert anything into your tree. In fact, it just leaks memory.
What tempNode pointed to prior to this statement is irrelevant. More importantly, how tempNode held that prior value is already lost because you're already descended down the tree one level. Two pointers holding the same address just means the address is reachable with two pointers. Assigning a new address to a pointer has no effect on the previously addressed entity (if there was any).
Your task should be finding the pointer that should be filled in with the address of a newly allocated object. You found it (sort of). Unfortunately you also lost it as soon as you walked into it with your step "down" the tree for the final null-detection. As soon as this:
while (tempNode != nullptr)
becomes false and breaks, you're already one node too far. There are a number of ways to handle this. Some people like using a "parent" pointer, but that just means you have to special-case an empty map condition. Consider this instead:
void MultiMap::insert(string key, unsigned int value)
{
// pp will always point to the pointer we're testing
// i.e. a pointer to pointer.
Node **pp = &head;
while (*pp) // while whatever pp points to is a non-null-pointer
{
if (key < (*pp)->m_key)
pp = &(*pp)->m_left; // put address of left-pointer into pp
else if ((*pp)->m_key < key)
pp = &(*pp)->m_right; // put address of right pointer into pp
else break; // strict weak order match
}
if (*pp)
{
// found matching key. NOTE: unclear if you wanted to just update or not
}
else
{
// allocate new node.
*pp = new Node(key,value);
}
}
And you'll notice other than initializing our pointer-to-pointer with the address of the head node pointer, head is never referenced again.
Finally, notice there is no special-case head-node test. If the map is empty and the head pointer is NULL, this will automatically create a new node and make it the root.
What is going on here:
Node* tempNode = head;
while(tempNode != nullptr)
{
if(key <= tempNode->m_key)
tempNode = tempNode->m_left;
else if(key > tempNode->m_key)
tempNode = tempNode->m_right;
}
OK, now tempNode == nullptr, and it does not point to any node of the tree. As it is the variable on the stack, the next line:
/*line 1*/tempNode = new Node(key, value);
just initializes this local pointer and does not affect the tree itself. (Really here will be a memory leak.)
In your second line you initialize the node in the tree:
head->m_left = new Node(key, value);
But only for head->m_left.
So you can write:
if (key <= tempNode->m_key) {
if (tempNode->m_left == nullptr) {
tempNode->m_left = new Node(key, value);
break; // traverse tree loop
} else {
tempNode = tempNode->m_left;
}
}

Linked List containing a Linked List gives heap corruption error: Why?

Long story short: I made a Template Double-Linked List, and putting lists inside of other lists causes issues. This question has been solved.
I'm testing Double-Linked-Lists as templates, and I'm running into an issue where placing a linked list inside of another linked list gives the following error:
(Microsoft Visual Studio 2010 Express)
Windows has triggered a breakpoint in linkListTesting.exe. This may
be due to a corruption of the heap, which indicates a bug in
linkListTesting.exe or any of the DLLs it has loaded. This may also be
due to the user pressing F12 while linkListTesting.exe has focus. The
output window may have more diagnostic information.
Searching for this particular error yielded results along the lines of, "make sure you don't use uninitialized variables," -in this scenario, when I tell a list to push_back / push_front, etc, it should initialize the list for me.
(Not pressing F12, so that scenario's out.)
Here's my main cpp->
#include "vcLLMK2.h"
int main(int argc, char *argv[])
{
vcList<vcList<int>> a;
vcList<int> b;
b.push_back(1);
a.push_back(b);
//ERROR HAPPENS HERE APPARENTLY
return 0;
}
Pushing back (or front, tried that too) a new entry (in this case, '1') into 'b' works great. No crashes, no silliness. Pushing 'b' into 'a' causes the application to spit out the aforementioned error, trigger a breakpoint, and die.
I've recently started playing around with SDL, and intend on using a list as a container for 16 layers, which are basically lists of sprites/tiles/etc to render. The mode of thought is that the program will iterate through each entry in the layer-containing list, then render each object in the contained layer before moving on to the next.
"Why not just use std::list?"
-Because that's cheating.
Although it's pretty likely that those who answer in this thread will be able to point out each of the glaring flaws in my list's structure and implementation that I'm blissfully unaware of, what I'm most concerned about is what-in-particular is causing this peculiar error and how to remedy it. That said, my question for you folks is what is wrong with the linked-list setup that I've built that causes the above cpp to error at runtime?
The Linked List structure below is the culmination of reading the following pages:
http://www.codeproject.com/Articles/26631/Using-C-templates-for-functions-and-operators
http://www.cprogramming.com/tutorial/lesson15.html
http://geekswithblogs.net/MarkPearl/archive/2010/02/20/linked-lists-in-c.aspx
Turning it into a template is mostly the result of creative interpretation of this page: http://www.cplusplus.com/doc/tutorial/templates/
Here's my Link-List template class, with lots of comments->
#pragma once
#ifndef vcLLMK2_H_INCLUDED
#define vcLLMK2_H_INCLUDED
#define NULL 0
//THIS IS ALL OUR NODE SHOULD EVER NEED
template <class T>
struct vcListNode
{
public:
T data;
vcListNode<T> *next;
vcListNode<T> *prev;
};
template <class T>
struct vcList
{
public:
vcListNode<T> *root;//the list's "start"
vcListNode<T> *end;//the list's "end"
vcListNode<T> *cur;//used to bounce around amongst entries
int size();//returns number of non-null entries
int count;//because keeping track of these is easier than iterating through every time
void setAt(T,int);//sets data in a node
void push_front(T);//inserts a new node at the beginning of the list
void push_back(T);//same thing but back of list
void removeAt(int);//kills a node at an arbitrary spot in the list
void clear();//deletes all of the nodes in the list
T getAt(int);//returns data from a node in the list
vcList<T>& operator = (const vcList<T>&);//used for setting list a's contents to list b
//EDIT COPYCONSTRUCTOR
vcList<T>(const vcList<T>&);//copyconstructor
vcList();// : root(NULL),end(root),cur(NULL),count(0){};
~vcList();
};
//constructor - sets everything to null and count to zero on init
template <class T>
vcList<T>::vcList()
{
root=NULL;
cur=NULL;
end=NULL;
count=0;
}
//destructor - deletes all nodes
template <class T>
vcList<T>::~vcList()
{
clear();
}
//deletes all nodes from root to end
template <class T>
void vcList<T>::clear()
{
if(root==NULL)//assume list has nothing in it, abort
return;
//set current targeted entry to root
cur = root;
//as long as we have somewhere to go...
while(cur->next!=NULL)
{
//go there
cur=cur->next;
//and destroy where we were
delete cur->prev;
}
//then destroy ourselves because nihilism is good for memory
delete cur;
}
//used to set the contents of a list equal to those of another
template <class T>
vcList<T>& vcList<T>::operator= (const vcList<T> &fays)
{
//for starters, clear ourselves of any unwanted garbagedata
clear();
//check the import list's root entry
cur = fays.root;
//if the list containing the values we are importing is empty, we're done, move along
if(cur==NULL)
return *this;
//otherwise, make a new node - it's our new root
vcListNode<T> *newEntry = new vcListNode<T>;
newEntry->data = fays.root->data;
newEntry->prev = NULL;
newEntry->next = NULL;
//set root/end to the new entry
root = newEntry;
end = newEntry;
//update our count
count=1;
//fire through the import-list's entries
//cur starts at root
while(cur->next!=NULL)//(count<fays.count)
{
//move to next entry
cur=cur->next;
//add it to our list, push_back should update the location of 'end' for us
push_back(cur->data);
}
//we should be done here, so go ahead and return everything
return *this;
}
//this is mostly for convenience
template <class T>
int vcList<T>::size()
{
return count;
}
//adds a new entry to the front of our linked list
template <class T>
void vcList<T>::push_front(T info)
{
//eat some memory
vcListNode<T> *newEntry;
newEntry = new vcListNode<T>;
//set our memory and all that neat stuff
newEntry->data = info;
newEntry->next = root;
newEntry->prev = NULL;
//if our linked list is not empty
if(root!=NULL)
//set root's previous link to point at our new entry
root->prev = newEntry;
//if our linked list does not have an assigned end yet
if(end==NULL)
//assume it's empty and set end to our entry
end=newEntry;
//update the position of our root in the list, the beginning now begins at the beginning again
root = newEntry;
//and since we added something to the list, we should probably update our count of things in the list
count++;
}
//this finds an element in the pointer-chain and sets its information
template <class T>
void vcList<T>::setAt(T info,int index)
{
//set our target to the root
cur=root;
//run through the list's entries until we're where we're supposed to be
while(index>0)
{
cur=cur->next;
index--;
}
//set the data in the cell/node/whatever to our input
cur->data=info;
}
//returns the data contained in a node at a position in the list
template <class T>
T vcList<T>::getAt(int meBro)
{
//set target to root
cur=root;
//progress through the list
while(meBro>0)
{
cur=cur->next;
meBro--;
}
//dig the data out of the entry and return it
return cur->data;
}
//adds an element-containing node to the end of the list-chain
template <class T>
void vcList<T>::push_back(T info)
{
//if our list already has entries, end shouldn't be null
if(end!=NULL)
//so just target our end slot
cur=end;
//if our list is empty, however
else
//target the root instead
cur=root;
//create our new node, put stuff in it, etc
vcListNode<T> *newEntry;
newEntry = new vcListNode<T>;
newEntry->data = info;
//we're adding to the END of the list so make next null
newEntry->next = NULL;
//if cur is NOT null, then theoretically we're pointed at the end of the list
if(cur!=NULL)
//set our new entry's previous pointer to the end
newEntry->prev = cur;
//cur IS null, which means the list is empty
else
//set our entry's previous pointer to be null, duh
newEntry->prev = NULL;
//if the end of our list exists
if(end!=NULL)
{
//set the next entry in the list to point at our new entry
end->next = newEntry;
//then set end to target the new entry
end=newEntry;
}
//and if our list does not have an end yet for some reason (read as: it's empty)
else
{
//set the root to our new entry
root = newEntry;
//set the end to our new entry as well, since there's only one entry in the list
end = newEntry;
}
//update count of number of objects in list
count++;
}
//this deletes/removes/destroys/obliterates a node at a location in the list
template <class T>
void vcList<T>::removeAt(int index)
{
//for starters - is what we're trying to kill even here?
if(index>=count)
//NOPE GET OUT
return;
//later on it might speed things up to check whether the distance from end or root is shorter
//for now, just start at the beginning
//target the root
cur=root;
//move through the list to the specified entry
while(index>0)
{
index--;
cur=cur->next;
}
//if the previous entry exists
if(cur->prev!=NULL)
//point its next at the entry after this one
cur->prev->next=cur->next;
//if the previous entry is NULL, it means we're at the root
//so tell root to scoot forward one entry
//if there's a forward to scoot to
else if(cur->next != NULL)
root = cur->next;
//if the next entry exists
if(cur->next!=NULL)
//set the next entry's previous pointer to point at the entry before the targeted one
cur->next->prev=cur->prev;
//if the next entry does not exist, we must be at the end of the list
//so tell the end of the list to scoot back one slot
//if there's a back-one-slot to go to
else if(cur->prev!=NULL)
end = cur->prev;
//remove the entry at the targeted location
delete cur;
//decrement our count
count--;
}
//EDIT -> Copy Constructor
//copy constructor, similar as suggested to the operator=
template <class T>
vcList<T>::vcList(const vcList<T>& fays)
{
//might not be completely necessary, but we're not hurting anything by making sure
clear();
//check the import list's root entry
cur = fays.root;
//if the list containing the values we are importing is empty, we're done, move along
if(cur==NULL)
return;//just return, constructors don't get return types
//otherwise, make a new node - it's our new root
vcListNode<T> *newEntry = new vcListNode<T>;
newEntry->data = fays.root->data;
newEntry->prev = NULL;
newEntry->next = NULL;
//set root/end to the new entry
root = newEntry;
end = newEntry;
//update our count
count=1;
//fire through the import-list's entries
//cur starts at root
while(cur->next!=NULL)//(count<fays.count)
{
//move to next entry
cur=cur->next;
//add it to our list, push_back should update the location of 'end' for us
push_back(cur->data);
}
//we should be done here, so go ahead and return everything
//return *this;
}
#endif
I think you should take a look in one of the most important concepts in C++, that is pass by reference. The push_back method as an argument named info, that is a copy of the object you are using to call the method. Since you didn't explicit told the compiler how to create an copy of the vsList object, it's going to create a default copy contructor but it's not going to work as intended.
So the problem on your code really happens when the destructor of the object that is stored in the object "a" is called. Since it has no valid pointers, it's going to crash. You can solve your problems in two ways, changing the push_back (and all other methods) to receive T by "const reference" instead of by value or implementing a copy constructor.