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! ;)
Related
I am tasked with removing all duplicate entries in the linked list. Assuming the list is ordered from smallest to largest, therefore all I need to do is remove the duplicates next to each other.
For example: If the list contains {1,2,2,2,3,3,4,5,5,5,5,5,6} before calling remove_duplicates(), it should contain{1,2,3,4,5,6} after.
My problem is that my code will print the duplicates as well whenever remove_duplicates() is called.
Here is my code:
list.cpp:
#include <iostream>
using namespace std;
#include "list.h"
// on some machines member variables are not automatically initialized to 0
List::List()
{
m_head = NULL;
m_length = 0;
}
// delete all Nodes in the list
// since they are dynamically allocated using new, they won't go away
// automatically when the list is deleted
// Rule of thumb: destructor deletes all memory created by member functions
List::~List()
{
while (m_head)
{
Node *tmp = m_head;
m_head = m_head->m_next;
delete tmp;
}
}
// always insert at the front of the list
// Note: this works even in the SPECIAL CASE that the list is empty
void List::insert(int value)
{
if (!m_head || value < m_head->m_value)
{
m_head = new Node(value, m_head);
}
else
{
Node *ptr = m_head;
while (ptr->m_next != NULL && value > ptr->m_next->m_value)
{
ptr = ptr->m_next;
}
ptr->m_next = new Node(value, ptr->m_next);
}
m_length++;
}
// iterate through all the Nodes in the list and print each Node
void List::print()
{
for (Node *ptr = m_head; ptr; ptr = ptr->m_next)
{
cout << ptr->m_value << endl;
}
}
void List::remove_duplicates()
{
Node *curr = m_head;
Node *temp = m_head;
Node *delPtr = NULL;
if(curr == NULL)
{
return;
}
if(curr != NULL)
{
if(curr -> m_value == curr ->m_next ->m_value)
{
delPtr = curr;
curr = curr -> m_next;
temp ->m_next = curr;
delete delPtr;
}
else
{
curr = curr -> m_next;
}
}
}
list.h:
class List
{
public:
List();
~List();
void insert(int value); // insert at beginning of list
void print(); // print all values in the list
int length() {return m_length;}
void remove_duplicates();
int *convert_to_array(int &size);
private:
class Node
{
public:
Node(int value, Node *next)
{m_value = value; m_next = next;}
int m_value;
Node *m_next;
};
Node *m_head;
int m_length;
};
main.cpp:
#include <assert.h>
#include <iostream>
using namespace std;
#include "list.h"
int main()
{
List list;
int value;
// read values and insert them into list
while (cin >> value)
{
list.insert(value);
}
cout << "printing original list: \n";
list.print();
list.remove_duplicates();
cout << "printing list after removing duplicates: \n";
list.print();
}
Note: Everything has been given to me by my instructor, the only code that I am supposed to write is void List::remove_duplicates()
I have looked up other examples on stackoverflow, but none seem to help me with my situation.
Also, I do want to mention that I am still very new to Linked Lists and how they function. Therefore I am not exactly sure where to go from here. Any help would be appreciated
You need to iterate over your list using both the Address of the current pointer, and the current pointer. See Linus on Understanding Pointers. Since you don't just want to delete a node with a certain value, but you want to scan forward in the list deleting ALL nodes with that value, you want to loop over each node, and within the loop scan-forward deleting ALL nodes with the value of the current node.
You do that by checking the m_next->m_value and if it the same as the current node value, you REPLACE the node at the current pointer ADDRESS with the next node content. Since you still have a pointer to the node you have replaced, you can simply delete that node and then update the pointer from the address of the current node.
This presumes your list is in SORT-ORDER as you show in your question. If it isn't, you would need to scan the list multiple times. In sort-order as shown, you could do:
/* list must be in sort order */
void List::remove_duplicates()
{
Node **pp = &m_head, /* current address of head (pointer-to-pointer) */
*p = m_head; /* pointer to head */
/* loop over each node */
for (; p; pp = &p->m_next, p = p->m_next) {
/* while m_next and current value == next value */
while (p->m_next && (*pp)->m_value == p->m_next->m_value)
{
*pp = p->m_next; /* set node at current address to next node */
delete p; /* delete original node at that address */
p = *pp; /* update pointer to current node address */
}
}
}
(essentially if the current node and next have the same m_value you are throwing away the current node (and properly deleting the memory) and replacing it with the next)
Then for example, if your list originally contained:
0 0 1 1 1 2 3 4 4 5 6 6 6 7 8 9 9 9
calling list.remove_duplicates() would result in:
0 1 2 3 4 5 6 7 8 9
Look things over and let me know if you have further questions.
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;
}
So I have to create a linked list for class and I am stuck with my List::Current() function. For some reason I'm getting a handling error when I try to call the function.
List.h
class List {
private:
struct Node {
int data;
Node* next;
Node() : next(NULL){} //define our own default constructor
Node(int data) : next(NULL), data(data){}
};
typedef struct Node* NodeRef;
NodeRef head;
NodeRef tail;
NodeRef iterator; //points to one node at a time
int size;
public:
int current();
List.cpp
// initialize the values when they are instantiated
List::List() : head(NULL), tail(NULL), iterator(NULL), size(0)
{}
int List::current() {
return iterator->data;
}
void List::push_front(int data) //Inserting a new node in the front of the list
{
if (size == 0) //If there is no nodes in the list, execute the if statement
{
head = new Node(data); //create a new node, and have head point to it
iterator = tail = head; //have tail point to the new node also.
}
else //If there are nodes in the list, execute the else statement
{
NodeRef newNode = new Node(data); //create a new node
newNode->next = head; //have the next pointer point to the head of the next node.
head = newNode; //have the head pointer point to the new node inserted at the beginning of the list
}
size++; //Increment the size counter
}
void List::push_back(int data) //Inserting a node at the end of a list
{
if (size == 0) //If there are no nodes in the list, execute the if statement
{
tail = new Node(data); //Create a new node and have the tail pointer point to it.
iterator = head = tail; //Have the head pointer point to the new node also.
}
else //If there is atleast 1 node in the list, execute the else statement
{
NodeRef newNode = new Node(data); //Create a new node
tail->next = newNode; //Have the tail
tail = newNode; //Have the tail pointer point to the new node.
newNode->next = NULL;
}
size++;
}
void List::begin() //Set the iterator to the head of the list
{
iterator = head;
}
void List::scroll() //Allows us to scroll through the list
{
if (iterator == NULL)
cout << "Iterator is pointing to null" << endl;
else
iterator = iterator->next;
}
LinkedList.cpp
#include "stdafx.h"
#include "List.h"
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[]) {
List B; //Create a new list
B.push_front(5);
B.push_front(4);
B.push_front(3);
B.push_back(10);
cout << B.current() << endl;
system("PAUSE");
return 0;
}
I left some code out because I didn't think listing the other functions that worked properly were necessary to get the point across. If you would like everything I could post that.
I think this solved my issues.
Your issue is you aren't setting iterator.
Personally I wouldn't include it as part of the class and have something like begin() or head() which retrieves an iterator class instance with the head pointer. Then the current and iteration methods would be a part of your iteration class.
But for your current design you could check in push_front to see if the iterator is NULL, and if so set it equal to head. Or you could have a begin_iteration method which sets it to the head, which would also allow you to do more than one iteration through the list.
Edit
Now that you have revealed your entire implementation, you need to set iterator in 2 places. At the end of push_front, and if there is no head in push_back. In other words anywhere you set head, you need to set iterator.
Also how do you move iterator forward? Can you restart the iteration?
Just want to know if there are any flaws/inconsistencies/memory leaks in this implementation of deleting a linked list:
// Function to delete the entire linked list
void deleteList(Node** head) {
Node* current = *head;
Node* next;
while (current != 0) {
next = current->next;
delete current;
current = next;
}
*head = 0;
}
Edit:
struct Node {
int data;
Node* next;
Node(int data) : data(data){}
};
It would be more C++ if you passed head pointer by reference, not by pointer:
void deleteList(Node * & head)
{
// (...)
head = nullptr; // NULL in C++ pre-11
}
Also, to keep code a little more tidy, you can move declaration of next inside the loop:
while (current != 0)
{
Node * next = current->next;
delete current;
current = next;
}
My only worries about memory leak would concern properly freeing node's contents, but since you store a simple int, there shouldn't be any problems there.
Assuming, that your list have valid pointers to nodes and that head pointer is valid too, everything else seems fine.
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
}