C++ Linked list implementation crashing - c++

I am trying to implement a linked list for a data structures class and I am having some difficulty with the searching portion of the algorithm.
Below is the offending code, which I have tried to implement following the pseudo-code in the MIT introduction to algorithms text:
//
// Method searches and retrieves a specified node from the list
//
Node* List::getNode(unsigned position)
{
Node* current = m_listHead;
for(unsigned i = m_listSize-1; (current != 0) && (i != position); --i)
current = current->next;
return current;
}
The head at this point in the program is the 4th node, which contains the value of int 5. the problem appears to be in the body of the for-loop, where the pointer to the node object is assigned to the next node. But this is going beyond the head of the node, so it is essentially pointing at some random location in memory (this makes sense).
Shouldn't the algorithm be moving to the previous Node instead of the next Node in this case? Below is the pseudo-code:
LIST-SEARCH(L, k)
x <- head
while x != NIL and key != k
do x <- next[x]
return x
Also, here is the header file for my Linked list implementation. I haven't tried to implement it in Template form yet just to keep things simple:
#ifndef linkList_H
#define linkList_h
//
// Create an object to represent a Node in the linked list object
// (For now, the objects to be put in the list will be integers)
//
struct Node
{
// nodes of list will be integers
int number;
// pointer to the next node in the linked list
Node* next;
};
//
// Create an object to keep track of all parts in the list
//
class List
{
public:
// Contstructor intializes all member data
List() : m_listSize(0), m_listHead(0) {}
// methods to return size of list and list head
Node* getListHead() const { return m_listHead; }
unsigned getListSize() const { return m_listSize; }
// method for adding a new node to the linked list,
// retrieving and deleting a specified node in the list
void addNode(Node* newNode);
Node* getNode(unsigned position);
private:
// member data consists of an unsigned integer representing
// the list size and a pointer to a Node object representing head
Node* m_listHead;
unsigned m_listSize;
};
#endif
Implementation of addNode method:
//
// Method adds a new node to the linked list
//
void List::addNode(Node* newNode)
{
Node* theNode = new Node;
theNode = newNode;
theNode->next;
m_listHead = theNode;
++m_listSize;
}

Try this to construct the list:
void List::addNode(int number)
{
newNode = new Node;
newNode -> number = number;
newNode -> next = m_listHead ;
m_listHead = newNode;
++m_listSize;
}
It will add nodes to the head. Perhaps you may wish to store the pointer to the tail and insert the nodes there.

Unfortunately your code doesn't resemble the pseudo code you supply.
The pseudo-code is for searching a linked-list for a key, not a position.
The pseudo code reads as:
Assign head to (node) x.
while x isn't null and the key inside the current node (x) doesn't match k
assign x->next to x
return x
The returned value is either a pointer to the node that contains k or null
If you're trying to find the node at a given position your loop would be (note this is assuming you're going to use a zero-based index for accessing the list):
Assign head to (node) x
assign 0 to (int) pos
while x isn't null and pos not equal to given position
assign x->next to x
increment pos
return x
The result will either be a pointer to the node at the given position or null (if you hit the end of the list first)
Edit: Your code is very close to the latter if that's what you're trying to do ... can you see the difference?
Edit because I like homework where the OP asks the right questions :)
Node* List::getNodeContaining(int searchValue)
{
Node* current = m_listHead;
while (current != 0 && current->number != searchValue)
{
current = current->next;
}
return current;
}
Node* List::getNodeAtPos(int position)
{
Node* current = m_listHead;
int pos = 0;
while (current != 0 && pos != position)
{
current = current->next;
pos++;
}
return current;
}

You list is very different from what a normal list ADT looks like. Rather than returning nodes, which would require the client know about the list implementation, you return and accept the type you're making a list of.
In this case you're making a list of integers, sou you'd want
public:
void add(int num); //prepends an Item to the list
int get(int pos);
The implementations of both are simple. Add makes a new node, and links it in;
void List::add(int num)
{
Node *newNode = new Node;
newNode->number = num;
newNode->next = m_listHead;
m_listHead = newNode;
m_listSize++;
}
Then get is easy too:
int List::get(int pos)
{
if(pos>m_listSize)
;//throw an error somehow
Node *tmp = m_listHead;
while(pos-->0)
tmp=tmp->next;
return m->number
}

Related

Write a function takes in 2 parameters – the pointer head OR tail plus the direction to traverse for a linked list

Here is how I defined and initialized a linked list
struct listrec
{
struct listrec *prev;
float value;
struct listrec *next;
};
listrec *head, *tail;
int main() {
int number;
cin >> number;
float content = 2.0;
for (float i = 0; i < number; i++)
{
if (i == 0)
{
head = new listrec;
head->prev = nullptr;
head->value = 1.0;
head->next = nullptr;
tail = head;
}
else
{
auto *newNode = new listrec;
newNode->value = content++;
newNode->next = nullptr;
newNode->prev = tail;
tail->next = newNode;
tail = tail->next;
}
}
return 0;
}
This is how the linked list looks like
I need to " write a function that takes two input parameters - the pointer head OR tail plus a parameter of which direction to traverse - to traverse the linked list and return the number of elements in the list. "
I have no idea how to write a function like that…
I know, if I want to count the number of elements from the first node, then I can write a function like this:
float listSize(listrec* head)
{
int count = 0;
listrec* current = head; // Initialize current
while (current != NULL)
{
count++;
current = current->next;
}
return count;
}
Or, if I want to count the elements from the last element, then
float listSize2(listrec* tail)
{
int count = 1;
listrec* current = tail;
while (tail->prev != NULL)
{
count++;
tail = tail->prev;
}
return count;
}
But how can I combine these two? Any hints would be appreciated!
Here is the function, assuming a doubly linked list:
enum class Direction {FORWARD, REVERSE};
struct Node
{
Node * previous;
Node * next;
};
unsigned int Count(Node * p_begin, Direction traverse_dir)
{
unsigned int node_count = 0U;
while (p_begin != nullptr)
{
++node_count;
if (traverse_dir == FORWARD)
{
p_begin = p_begin->next;
}
else
{
p_begin = p_begin->previous;
}
}
return node_count;
}
Per the requirement, the function takes 2 parameters, a pointer to a head or tail node, and a direction and returns the quantity of nodes traversed.
The function starts at the pointer passed, then goes forward or reverse (depending on the direction parameter), and increments the node counter. The loop stops when a null pointer is encountered, which usually signals the beginning or end of a list.
Since only a node class is used, you can inherit from the Node to make various list types:
struct Integer_Node : public Node
{
int data;
};
The data field does not play a role in traversing the list, so it was removed from the fundamental node object.
You don't need to "combine" them. You need to call one or the other depending on the direction:
enum class Direction { Forward, Backwards };
int listSize(listrec* p, Direction dir)
{
if (dir == Direction::Forward)
return listSize(p);
else
return listSize2(p);
}
This is not a review site, that being said I cannot in good conscience leave this answer without some advice for your code:
in C++ you should use RAII. A consequence of that is that you should never use explicit calls to new / delete and you should not use owning raw pointers.
count is an integer, so returning float in your functions makes no sense. Floating point data has its problems, don't use it for integers.
better name your functions. listSize and listSize2 are terrible names. Your functions don't list, they just return the size. So a better name is getSize. Also differentiating between then by a number is another terrible idea. You can use getSize and getSizeReverse.
there is no need to pass pointers to your function. Passing by reference, or even by value in your case is preferred.
you need better OOP abstractions. listrec is a list record (aka a list node). On top of this you need a class that abstracts a list. This would contain a pointer to the head of the list and a pointer to the tail of the list.
you should create a function for insertion into the list (and one for each operation on the list) and not do it manually in main.

Why my head pointer is changing in linked list,even not passing it by reference?

I created a linked list, and made a function reverseList which takes a pointer to head and return pointer to last node.
Node* reverseList(Node *head)
{
Node* curr=head;
Node* prev=NULL;
Node* ahead;
while(curr!=NULL)
{
ahead=curr->next;
curr->next=prev;
prev=curr;
curr=ahead;
}
return prev;
}
But in main when I am doing this
int main()
{
int n;///no of elements in list
cin>>n;
Node* head=NULL;
head=createList(head,n);///creating list(it is working properly)
printList(head);
cout<<endl;
Node* temp=reverseList(head);///reversing list and storing address of list in
//new node
printList(temp);///printing reversed list properly
cout<<endl;
printList(head);///while printing this it is printing only one elements,
//which implies head pointer changes but I don't know
///how
}
My head pointer changes, and it is printing only one value. I had pass my head pointer in reverseList by value. I am providing image of output.
Comments explain fine already, trying to illustrate to make it a little clearer:
1 > 2 > 3 > 4 > NULL
^
head
Now you reverse the list, resulting in:
4 > 3 > 2 > 1 > NULL
^ ^
temp head
As you never changed head, it still points to the same node as it pointed to before the list reversal, but after reversing the list, this node is now the last one.
Side note: Forgetting to re-assign is quite a common error, so it is a good idea to encapsulate the linked list in a separate class:
class LinkedList
{
Node* _head;
public:
class Node; // just as you have already
void reverse() // now a member function
{
//reverse as you did before
// encapsulating the assignment: (!)
_head = newHead;
}
Node* head() { return _head; }
};
LinkedList l;
// ...
Node* tmp = l.head();
l.reverse();
// tmp variable points to tail...
// expecting tmp pointing to head is still an error,
// and there is no way to prevent it
// BUT the correct head can always be re-acquired:
head = l.head();
Edit in response to comment:
If you want to create a new list, you will have to copy the nodes:
Node* createReversedList(Node* head)
{
Node* cur = NULL;
while(head)
{
Node* tmp = new Node(*head);
// (provided you have an appropriate copy constructor)
tmp->next = cur;
cur = tmp;
head = head->next;
}
return cur;
}
Note the new name, reverse rather implies modifying the original list as you did.
To create a new Linked List, you need to create a new variable of Node, and perform operations on that variable.
So, the code would be something like:
Node* reverseList(Node *head)
{
Node* newRootPtr = new Node(); //Pointer to the new root. This will be returned to the calling function.
newRootPtr->next = NULL; //In the reversed list, the original head will be the last node.
Node* curr=head; //For iterations
while(curr->next!=NULL) //For every node, until the last node. Note that here, we need to stop at the last node, which will become the first node of the new List.
{
Node ahead=*(curr->next); //Create a new Node equal to the next node of the original list.
Node* aheadPtr = &ahead; //Pointer to the new node
aheadPtr->next = newRootPtr; //Point the new node to the previous node of the new list
newRootPtr = aheadPtr; //update root node
curr=curr->next;
}
return newRootPtr;
}

traversing a doubly-linked list and insert at its end (C++)

I have to face this problem: I have a doubly linked list and I have to make insertion at the tail. My list is made of Nodes such as
struct Node {
int val; // contains the value
Node * next; // pointer to the next element in the list
Node * prev; // pointer to the previous element in the list
};
and my class list declares only
private:
Node * first; // Pointer to the first (if any) element in the list
at first.
Now, I wrote such a method for inserting:
void List::insert(int n){
Node * tmp = new Node;
tmp->val = n;
tmp->next = 0;
if (!first) {
first = tmp;
}
else {
Node * p = new Node;
p = first;
while (p->next) {
p = p->next;
}
p->next = tmp;
tmp->prev = p;
}
};
and if I take several numbers from cin (say, 1 2 3 4), I call insert but I end up not having all the elements I wanted to store. I have only first and tmp, which contains the last number from the input (e.g. 4).
I struggle to figure out what's wrong - my first suggestion is variable scope.
Or is there anything wrong during the pointer setting?
OBS: I'd use a tail pointer of course, but the aim is traversing the list.
Any feedback is really appreciated.

c++ remove similar nodes linked list

For a homework assignment I need to remove all similar nodes that the number passed into. For example if I have on the list
3
5
5
4
the 5's will be removed from the linked list and I will end with
3
4
we are not allowed to use the std library for this class and here is the header file
namespace list_1
{
class list
{
public:
// CONSTRUCTOR
list( );
// postcondition: all nodes in the list are destroyed.
~list();
// MODIFICATION MEMBER FUNCTIONS
//postcondition: entry is added to the front of the list
void insert_front(const int& entry);
//postcondition: entry is added to the back of the list
void add_back(const int& entry);
// postcondition: all nodes with data == entry are removed from the list
void remove_all(const int& entry);
// postcondition: an iterator is created pointing to the head of the list
Iterator begin(void);
// CONSTANT MEMBER FUNCTIONS
// postcondition: the size of the list is returned
int size( ) const;
private:
Node* head;
};
}
I can understand how to remove the front, and the back of the list. But for some reason I can't wrap my head around going through the list and removing all of the number that is passed in. Anything helps! Thanks
edited to include Node.h
#pragma once
namespace list_1
{
struct Node
{
int data;
Node *next;
// Constructor
// Postcondition:
Node (int d);
};
}
There are two ways of doing this. The first is to iterate through the list and remove the nodes. This is tricky because to do that you have to keep a pointer to the previous node so you can change its next value.
The code for removing a node would look like this (assume current is the current node and prev is the previous node)
Node* next = current->next;
delete current;
prev->next = next;
Maintaining a reference to the previous node can be a bit tedious though, so here is another way to do it. In this method, you essentially create a new list but don't insert Nodes who's data is equal to entry.
The code might look a little like this
void list::remove_all(const int &entry)
{
Node* newHead = NULL;
Node* newTail = NULL;
Node* current = head;
// I'm assuming you end your list with NULL
while(current != NULL)
{
// save the next node in case we have to change current->next
Node* next = current->next;
if (current->data == entry)
{
delete current;
}
else
{
// if there is no head, the set this node as the head
if (newHead == NULL)
{
newHead = current;
newTail = current;
newTail->next = NULL; // this is why we saved next
}
else
{
// append current and update the tail
newTail->next = current;
newTail = current;
newTail->next = NULL; // also why we saved next
}
}
current = next; // move to the next node
}
head = newHead; // set head to the new head
}
Note: I didn't test this, I just typed it up off the top of my head. Make sure it works. =)
Hope this helps! ;)

Graph Representation using Linked-List

Im having some trouble trying to figure out how to get the pointers right when adding edges to a certain paired vertex.
Below is a short idea about how the linked list should look like after Vertexs and Nodes are done being Inputed.
How can i keep order on the neighborList as well? Should there be another condition if there is already a vertex edge in that current vertex?
Heres the Structured Class im trying to build:
class graph{
private:
typedef struct node{
char vertex;
node * nodeListPtr;
node * neighborPtr;
}* nodePtr;
nodePtr head;
nodePtr curr;
public:
graph();
~graph();
void AddNode(char AddData);
void AddEdge(char V, char E);
void printList();
};
graph::graph(){
head = NULL;
curr = NULL;
}
// Adds a node to a linked list
void graph::AddNode(char AddData){
nodePtr n = new node;
n->nodeListPtr = NULL;
n->vertex = AddData;
if(head != NULL){
curr = head;
while(curr->nodeListPtr != NULL){
curr = curr->nodeListPtr;
}
curr->nodeListPtr = n;
}
else{
head = n;
}
}
// takes 2 Parameters (V is pointing to E)
// I want to set it up where the neighborptr starts a double linked List basically
void graph::AddEdge(char V, char E){
// New Node with data
nodePtr n = new node;
n->neighborPtr = NULL;
n->vertex = E;
// go to the first node in the nodeList and go through till you reach the Vertex V
curr = head;
while(curr->vertex != V){
curr = curr->nodeListPtr;
}
//Once the Vertex V is found in the linked list add the node to the neighborPtr.
curr->neighborPtr = n;
}
One problem you currently have is that each node can only have one "edge" node. In your illustration, nodes A, C, and D are all possible, but node B is not without doing things a little differently.
The problem happens here:
curr->neighborPtr = n;
Every time you call AddEdge() to the same vertex, it will simply overwrite that vertex's neighborPtr. You make no effort to traverse the neighborPtrs until you find a null pointer.
Consider adding another while loop for adding edges recursively:
while (curr->neighborPtr != null)
curr = curr->neighborPtr;
curr->neighborPtr = n;
Note that this is not the only issue in your code; you have a few places where you should be guarding against null pointers and are not. For example: in AddEdge(), what happens if the vertex V cannot be found? You are acting under the assumption that it has already been created. If it hasn't, you will end up with some null pointer errors. Keep this in mind if you are trying to make code that is robust in addition to being functional.