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.
Related
Being a beginner for C++, I was able to get to the point of making a linkedlist using classes and not templates or vectors, and reached to a point where i can ad a node to the end, delete a node from the end (by value) and print the node. However, I now want to know how to be able to clear the complete set of nodes thereby clearing the complete linkedlist, without using any specialized functions or special headers.
I went through the following resources of reference but could not set or align my understanding with them as the following sources have done using different methods:-
Can't figure out how to clear a linked list in c++?
Linked List Delete Method
(yes i tried getting ideas from java even though i dont know java but just tried too)
C programming Linked Lists delete node at position N
How would I clear a linked list? (came closest to make me understand it but some confusion)
Book: Deitel and Deitel (surprisingly near to my thought only that they have shown using templates or vectors)
Book: Primer (a little bit hard for me to understand)
Any help would be highly appreciated. Please try and forgive some of my bad habbits of programming like using namespace std and etc, etc, as my aim is to get the DeleteAll function working(clearing the complete list), look at the block of code which is commented totally in the last function of the class LinkedList.
Then look at the Case 4 where i am trying to call it in the main function.this my first time with the concept of linked list, and yes it seems very intimidating.
#include <iostream>
#include <cstdlib>
#include "ctype.h" //for enabling the recognition of data types for different illegal user inputs for main program
using namespace std;
// Node class
class Node
{
int data;
Node* next;
public:
Node(){};
void setData(int aData)
{
data = aData;
}
void setNext(Node* aNext)
{
next = aNext;
}
int Data()
{
return data;
}
Node* Next()
{
return next;
}
};
// LinkedList Class
class LinkedList
{
private:
Node *head;
public:
List()
{
head = NULL;
}
// printing contents of list
void Print()
{
Node *tmp = head;
// but if no Nodes then following
if (tmp==NULL)
{
cout<<"\n \t\tcannot find any Nodes: List EMPTY\n";
return;
}
//if one node is found
else if (tmp->Next()==NULL)
{
cout<<tmp->Data();
cout<<"-->";
cout<<"NULL"<<endl;
}
//else more nodes then parse and print the list
else
{
do
{
cout<<tmp->Data();
cout<<"-->";
tmp = tmp->Next();
}
while(tmp!=NULL);
cout<<"";
cout<<"X"<<endl;
}
}
//Append or add a node to the linked list
void Append(int data)
{
//creates a new node;
Node *newNode = new Node();
newNode->setData(data);
newNode->setNext(NULL);
//create a temp pointer for further linking to be facilitated
Node *tmp = head;
//but before setting next link to point last node to new node
//we need to check if we are at the end of the list and if not then traverse to the end of node
if(tmp !=NULL)
{
while(tmp->Next() !=NULL)
{
tmp = tmp->Next();
}
tmp->setNext(newNode);
}
else
{
head = newNode;
}
}
//Delete a node from list BY VALUE
void Delete(int data)
{
//again create a temp pointer.
Node *tmp = head;
//again if no nodes
if (tmp==NULL)
{
cout<<"\n \t\tNo Nodes to delete\n";
return;
}
//Last node in the list which is the same as only one node left in list then following
else if(tmp->Next()==NULL)
{
delete tmp;
head = NULL;
}
//again parse through the nodes again to delete the data related node.
else
{
Node *prev;
do
{
if(tmp->Data()==data)
{
break;
}
else
{
prev = tmp;
tmp = tmp->Next();
}
}
while(tmp != NULL);
//once the data is found and located then readjust the linkage of previous with next and
//delete the current node
prev->setNext(tmp->Next());
delete tmp;
}
}
//
// int Deleteall()
// {
// again create a temp pointer.
// Node *tmp = head;
//
//
// again if no nodes
// if (tmp==NULL)
// {
// cout<<"\n \t\tNo Nodes to delete\n";
// return 0;
// }
//
// Last node in the list which is the same as only one node left in list then following
// else if(tmp->Next()==NULL)
// {
// delete tmp;
// head = NULL;
// }
//
// again parse through the nodes again to delete the data related node.
// else
// {
// Node *prev;
//
// while(tmp);
// {
//
// once the data is found and located then readjust the linkage of previous with next and
// delete the current node
// prev->setNext(tmp->Next());
// delete tmp;
// }
// } return 0;
// }
};
//Now call through the main function
int main()
{
//New List
LinkedList list1;
int usrdata, choice;
while(choice)
{
cout<<"\n\nPlease choose an action to be performed on the LinkedList\n\ninput 1 for adding/appending a node\ninput 2 for printing the list\ninput 3 for deleting the node by value\ninput 4 to exit\n\n";
cin>>choice;
switch(choice)
{
case 1 :
cout<<"\nEnter your desired data for adding/appending\n";
cin>>usrdata;
list1.Append(usrdata);
list1.Print();
continue;
case 2 :
cout<<"\nPrinting\n";
list1.Print();
break;
case 3 :
cout<<"\nEnter your desired data for removal/deleting\n";
cin>>usrdata;
list1.Delete(usrdata);
list1.Print();
break;
case 4 :
cout<<"\n deleting n exiting...\n";
// list1.Deleteall();
list1.Print();
goto end;
default :
cout<<"I think you should go home now you seem tired\n";
}
}
end:
cout<<"\n\nThis statement was reached because either you chose to exit or entered a wrong/illegal value or operation\n\n";
system("pause");
return 0;
}
How to get the last function (completely commented lines) DeleteAll working to clear the entire list without using any other specialized headers or special functions etc.
Delete all is actually a simple process.
Here is the algorithm:
current node is head
while the current node is not null
get the next node
delete the current node
current node is next node
set head to null
You don't have to worry about maintaining links as you are removing everything.
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?
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! ;)
So I've been searching forums, but im still very new to the language and linked lists so I can barely decipher the results.
basically I made a delete function for my linked list.
I can currently Create a list, traverse the list, sort the list, search the list, and insert before any node in the linked list. I recycled some code from the insert to locate the point in the list where I could delete. My main point of confusion is how to link the previous points to the node that is after the one I am deleting.
I won't write a whole new linked list implementation but i can point out some of the problems with the code for you.
The trick is to stay one node ahead of the one you want to delete.
I have renamed entry to current for clarity
nodetype *current , *first, *next;
int akey;
// With this line your search will start from the second element.
// current =start->ptr;
// Should be
current = start;
// this is not needed. I am assuming the last node has NULL value for '->ptr'
// last=start;
next = current->ptr;
cout<<"Input Data You Would Like To Delete"<<endl;
cin>>akey;
// Check if the first node contains the data
// Assuming the list will have at least one element. i.e. current is not NULL
while (current->adata == akey)
{
// Delete it.
delete current;
// Update current for the while loop
current = next;
// update next too.
next = current->ptr;
}
// Now we know the first element doesn't contain the data.
// Update the pointer to the begging of the new list if anything is removed from the top.
first = current;
// This has unnecessary checks.
// ****Specifically (akey!=current->adata) will
// prevent you from entering the loop if it is false.
// while((akey!=current->adata)&&(current->ptr !=NULL))
while(next != NULL) // This should be enough
{
if(next->adata == akey)
{
// make the current node (before the 'deletion point')
// lined to the one after the 'deletion point (next of the next)
current->ptr = next->ptr;
// delete the node.
delete next;
// Make the next pointer point to the new next.
next = current->ptr
}
// Otherwise advance both current and next.
else {
current = next;
next = next->ptr;
}
}
// Use this to test it.
current = first;
while(current){
cout<<current->adata<<", ";
current = current->ptr;
}
This is not the cleanest way. However it is similar to your implementation so you can see where you went wrong.
#include <iostream>
#include <string>
// blank line(s) after includes
using namespace std; // some people will say to avoid this
// but I use it in examples for brevity
// blank line(s) around class def
class nodetype
{ // bracket on its own line
public: // non indented visibility specifier
nodetype(int value, nodetype *p) // constructor first declared in class
{
adata = value; // level of indentation for fn body
ptr = p; // spaces around operators like =
}
// blank line(s) between fns and vars
int adata;
nodetype *ptr;
};
// blank line(s) between class and fn
void LinkedListDelete(nodetype **start, int akey)
{
nodetype *current, **previous; // pointer *s are connected to vars
// blank line between section
previous = start;
current = *start;
// blank line between section
// I use blank lines a lot, they help
// me to organize my thoughts
while((current != NULL) && (akey != current->adata))
{ // indentation inside nested scope
previous = ¤t->ptr; // no space for unary operators like &
current = current->ptr; // assignments justified to same level
}
if (current != NULL)
{
*previous = current->ptr; // no space for unary *, space for =
delete current;
}
// more blank lines between sections
return;
}
void LinkedListPrint(nodetype *list) // no space for unary *
{ // brackets on their own lines
while (list != NULL) // space around !=
{
cout << "(Node: " << list->adata << ") ";
list = list->ptr; // spaces around <<
}
cout << endl;
}
int main()
{
nodetype *node = new nodetype(5, new nodetype(10, // justified stuff
new nodetype(7, new nodetype(14,
new nodetype(23, NULL)))));
// blank lines
cout << "Build linked list: ";
LinkedListPrint(node);
cout << "Removed node 7: ";
LinkedListDelete(&node, 7);
LinkedListPrint(node);
return 0;
}
I made this code based on the code you provided. It's not quite the same, I changed some things, but it does what you want it to. I had to guess what the structure of nodetype was, and I added a constructor for my convenience. I added some comments pointing out aspects of my style.
Notice that it's easier to read than the code you originally provided. Style is important. People will tell you that you have to use X or Y style, but what really matters is that you pick whatever style you like and stick to it consistently; it will make it easier for you to read and understand your own code quickly.
Believe me you, when you've written a lot of code, you stop being able to remember all of it at once, and being able to figure out what you were doing quickly is essential.
Consider the structure given below,
struct info
{
int data;
struct info *next;
};
if you use the above structure to store records in your linked list, then the following code can be used to delete elements from your linked list,
void delitem()
{
info *curr,*prev;
int tdata;
if(head==NULL)
{
cout<<"\nNo Records to Delete!!!";
}
cout<<"\nEnter the Data to be deleted: ";
cin>>tdata;
prev=curr=head;
while((curr!=NULL)&&(curr->data!=tdata))
{
prev=curr;
curr=curr->next;
}
if(curr==NULL)
{
cout<<"\nRecord not Found!!!";
return;
}
if(curr==head)
{
head=head->next;
cout<<"\nData deleted: "<<tdata;
}
else
{
prev->next=curr->next;
if(curr->next==NULL)
{
temp=prev;
}
cout<<"\nData deleted: "<<tdata;
}
delete(curr);
}
I think it is too simple and easy to delete a node or insert ine in linked-list but it requires precise understanding of its MECHANISM. this example shows how to add and remove nodes however it is not a full program but it reveals the mechanism of adding and deleting and moving alinked-list:
#include <iostream>
using namespace std;
//class Data to store ages. in a real program this class can be any other
//class for example a student class or customer...
class Data
{
public:
Data(int age):itsAge(age){}
~Data(){}
void SetAge(int age){itsAge=age;}
int getAge()const{return itsAge;}
private:
int itsAge;
};
//the most important part of the program is the linked0list
class Node
{
public:
//we just make itsPtrHead when created points to Null even if we pass a pointer to Data that is not NULL
Node(Data* pData): itsPtrData(pData),itsPtrHead(NULL),itsCount(0){}
Data* getPdata()const;
Node* getPnext()const;
int getCount()const{return itsCount;}
void insertNode(Data*);//import bcause it shoes the mechanism of linked-list
void deleteNode(int);//most significant in this program
Data* findData(int&,int);
void print()const;
private:
Data* itsPtrData;
Node* itsPtrHead;
int itsCount;
};
Data* Node::getPdata()const
{
if(itsPtrData)
return itsPtrData;
else
return NULL;
}
Node* Node::getPnext()const
{
return itsPtrHead;
}
void Node::insertNode(Data* pData)
{
Node* pNode=new Node(pData);//create a node
Node* pCurrent=itsPtrHead;//current node which points first to the first node that is the "head bode"
Node* pNext=NULL;//the next node
int NewAge=pData->getAge();//the new age that is past to insertNode function
int NextAge=0;//next age
itsCount++;//incrementing the number of nodes
//first we check wether the head node "itsPtrHead" points NULL or not
//so if it is null then we assign it the new node "pNode" and return from insert function
if(!itsPtrHead)
{
itsPtrHead=pNode;
return;
}
//if the condition above fails (head is not null) then check its value and
//compare it with new age and if the new one is smaller than the head
//make this new one the head and then the original node that head points to it make it its next node to the head
if(itsPtrHead->getPdata()->getAge() > NewAge)
{
pNode->itsPtrHead=itsPtrHead;
itsPtrHead=pNode;
//exit the function
return;
}
//if the condition above fails than we move to the next node and so on
for(;;)
{
//if the next node to the current node is null the we set it with this new node(pNode) and exit
if(!pCurrent->itsPtrHead)
{
pCurrent->itsPtrHead=pNode;
return;
}
//else if it not null(next node to current node)
//then we compare the next node and new node
pNext=pCurrent->itsPtrHead;
NextAge=pNext->getPdata()->getAge();
//if next node's age is greater than new then we want new node
//to be the next node to current node then make the original next to current to be the next to its next
if(NextAge > NewAge)
{
pCurrent->itsPtrHead=pNode;
pNode->itsPtrHead=pNext;
//exitting
return;
}
//if no condition succeeds above then move to next node and continue until last node
pCurrent=pNext;
}
}
// delete a node is a bit different from inserting a node
void Node::deleteNode(int age)
{
//deleting a node is much like adding one the differecne is a bit trickier
Node* pTmp=itsPtrHead;
Node* pCurrent=itsPtrHead;
Node* pNext=NULL;
//1 checking for wether age (node contains age) to be deleted does exist
for(;pTmp;pTmp=pTmp->itsPtrHead)
{
if(pTmp->getPdata()->getAge() == age)
break;
}
//if age to be deleted doesn't exist pop up a message and return
if(!pTmp)
{
cout<<age<<": Can't be found!\n";
return;
}
int NextAge=0;
for(;;)
{
//if age to be deleted is on the head node
if(itsPtrHead->getPdata()->getAge() == age)
{
//store the next to head node
pTmp=itsPtrHead->itsPtrHead;
//delete head node
delete itsPtrHead;
//assign the head new node (node after the original head)
itsPtrHead=pTmp;
//decrement the count of nodes
itsCount--;
//exiting gracefully
return;
}
//moving to next node
pNext=pCurrent->itsPtrHead;
NextAge=pNext->getPdata()->getAge();
//checking next node age with age to be deleted. if they
//match delete the next node
if(NextAge == age)
{
//next node holds the target age so we want its NEXT node
//and store it in pTmp;
pTmp=pNext->itsPtrHead;//Next node of the target node
//pCurrent doesn't yet hold the target age but it is the
//previous node to target node
//change the next node of pCurrent so that it doesn't
//point to the target node but instead to the node right
//after it
pCurrent->itsPtrHead=pTmp;
//delete the target node (holds the target age)
delete pNext;
//decrement number of nodes
itsCount--;
//exit
return;
}
//if pNext doesn't point to target node move to the next node
//by making pCurrent points to the next node in the list
pCurrent=pNext;
}
}
void Node::print()const
{
Node* pTmp=itsPtrHead;
while(pTmp)
{
cout<<"age: "<<pTmp->getPdata()->getAge()<<endl;
pTmp=pTmp->itsPtrHead;
}
}
int main()
{
//note this is not a real proram just we show how things works
Data* pData=new Data(6);
Node theNode(pData);
theNode.print();
pData=new Data(19);
theNode.insertNode(pData);
pData=new Data(20);
theNode.insertNode(pData);
pData=new Data(23);
theNode.insertNode(pData);
pData=new Data(25);
theNode.insertNode(pData);
pData=new Data(30);
theNode.insertNode(pData);
pData=new Data(27);
theNode.insertNode(pData);
pData=new Data(33);
theNode.insertNode(pData);
pData=new Data(18);
theNode.insertNode(pData);
theNode.print();
cout<<endl<<endl;
//int age;
//int index;
//cout<<"Age to finde: ";
//cin>>age;
//cout<<endl;
//theNode.Find(index,age);
//cout<<age<<" : Found on index: "<<index<<endl;
//theNode.modify(age);
//theNode.print();
int age;
cout<<"age to delete: ";
cin>>age;
cout<<endl;
theNode.deleteNode(age);
theNode.print();
cout<<endl<<endl<<endl;
return 0;
}
//modify and other member functions are not the purpose of this program
void Delete()
{
int num;
cout<<"enter node to delete"<<endl;
cin>>num;
node *nodeptr=head;
node *prev;
if(head==0)
{
cout<<"list is empty"<<endl;
}
else if(head->data==num)
{
node *t=head;
head=head->next;
delete t;
}
else
{
nodeptr=head;
prev=head;
while(nodeptr!=NULL)
{
if(nodeptr->data==num)
{
prev->next=nodeptr->next;
node *tem=nodeptr->next;
delete tem;
}
prev=nodeptr;
nodeptr=nodeptr->next;
}
}
}
I am working on a linked list implementation in C++. I am making progress but am having trouble getting the insertion functionality and deletion functionality to work correctly. Below is list object in the C++ header file:
#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
{
Node() : sentinel(0) {}
int number;
Node* next;
Node* prev;
Node* sentinel;
};
//
// 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 and inserting a new node to the linked list,
// retrieving and deleting a specified node in the list
//
void addNode(int num);
void insertNode(Node* current);
void deleteNode(Node* current);
Node* retrieveNode(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
And here is the implementation (.cpp) file:
#include "linkList.h"
#include <iostream>
using namespace std;
//
// Adds a new node to the linked list
//
void List::addNode(int num)
{
Node *newNode = new Node;
newNode->number = num;
newNode->next = m_listHead;
m_listHead = newNode;
++m_listSize;
}
//
// NOTWORKING: Inserts a node which has already been set to front
// of the list
//
void List::insertNode(Node* current)
{
// check to see if current node already at
// head of list
if(current == m_listHead)
return;
current->next = m_listHead;
if(m_listHead != 0)
m_listHead->prev = current;
m_listHead = current;
current->prev = 0;
}
//
// NOTWORKING: Deletes a node from a specified position in linked list
//
void List::deleteNode(Node* current)
{
current->prev->next = current->next;
current->next->prev = current->prev;
}
//
// Retrieves a specified node from the list
//
Node* List::retrieveNode(unsigned position)
{
if(position > (m_listSize-1) || position < 0)
{
cout << "Can't access node; out of list bounds";
cout << endl;
cout << endl;
exit(EXIT_FAILURE);
}
Node* current = m_listHead;
unsigned pos = 0;
while(current != 0 && pos != position)
{
current = current->next;
++pos;
}
return current;
}
After running a brief test program in the client C++ code, here is the resulting output:
Number of nodes: 10
Elements in each node:
9 8 7 6 5 4 3 2 1 0
Insertion of node 5 at the list head:
4 9 8 7 6 5 4 9 8 7
Deletion of node 5 from the linked list
As you can see, the insertion is not simply moving node 5 to head of list, but is overwriting other nodes beginning at the third position. The pseudo code I tried to implement came from the MIT algorithms book:
LIST-INSERT(L, x)
next[x] <- head[L]
if head[L] != NIL
then prev[head[L]] <- x
head[L] <- x
prev[x] <- NIL
Also the deletion implementation is just crashing when the method is called. Not sure why; but here is the corresponding pseudo-code:
LIST-DELET'
next[prev[x]] <- next[x]
prev[next[x]] <- prev[x]
To be honest, I am not sure how the previous, next and sentinel pointers are actually working in memory. I know what they should be doing in a practical sense, but looking at the debugger it appears these pointers are not pointing to anything in the case of deletion:
(*current).prev 0xcdcdcdcd {number=??? next=??? prev=??? ...} Node *
number CXX0030: Error: expression cannot be evaluated
next CXX0030: Error: expression cannot be evaluated
prev CXX0030: Error: expression cannot be evaluated
sentinel CXX0030: Error: expression cannot be evaluated
Any help would be greatly appreciated!!
You have got an error in addNode(). Until you fix that, you can't expect insertNode to work.
Also, I think your design is quite silly. For example a method named "insertNode" should insert a new item at arbitrary position, but your method insertNode does a pretty different thing, so you should rename it. Also addNode should be renamed. Also as glowcoder wrote, why are there so many sentinels? I am affraid your class design is bad as a whole.
The actual error is that you forgot to set prev attribute of the old head. It should point to the new head.
void List::addNode(int num)
{
Node *newNode = new Node;
newNode->number = num;
newNode->next = m_listHead;
if(m_listHead) m_listHead->prev = newNode;
m_listHead = newNode;
++m_listSize;
}
Similarly, you have got another error in deleteNode(). It doesn't work when deleting last item from list.
void List::deleteNode(Node* current)
{
m_listSize--;
if(current == m_listHead) m_listHead = current->next;
if(current->prev) current->prev->next = current->next;
if(current->next) current->next->prev = current->prev;
}
Now you can fix your so-called insertNode:
void List::insertNode(Node* current)
{
int value = current->number;
deleteNode(current);
addNode(value);
}
Please note that I wrote everything here without compiling and testing in C++ compiler. Maybe there are some bugs, but still I hope it helps you at least a little bit.
In deleteNode, you are not handling the cases where current->next and/or current->prev is null. Also, you are not updating the list head if current happens to be the head.
You should do something like this:
node* next=current->next;
node* prev=current->prev;
if (next!=null) next->prev=prev;
if (prev!=null) prev->next=next;
if (m_listhead==current) m_list_head=next;
(Warning: I have not actually tested the code above - but I think it illustrates my idea well enough)
I am not sure what exactly your InsertNode method does, so I can't offer any help there.
OK.
As #Al Kepp points out, your "add node" is buggy. Look at Al's code and fix that.
The "insert" that you are doing does not appear to be a normal list insert. Rather it seems to be a "move to the front" operation.
Notwithstanding that, you need to delete the node from its current place in the list before you add it to the beginning of the list.
Update
I think you have misunderstood how insert should work. It should insert a new node, not one that is already in the list.
See below for a bare-bones example.
#include <iostream>
// List Node Object
//
struct Node
{
Node(int n=0);
int nData;
Node* pPrev;
Node* pNext;
};
Node::Node(int n)
: nData(n)
, pPrev(NULL)
, pNext(NULL)
{
}
//
// List object
//
class CList
{
public:
//
// Contstructor
//
CList();
//
// methods to inspect list
//
Node* Head() const;
unsigned Size() const;
Node* Get(unsigned nPos) const;
void Print(std::ostream &os=std::cout) const;
//
// methods to modify list
//
void Insert(int nData);
void Insert(Node *pNew);
void Delete(unsigned nPos);
void Delete(Node *pDel);
private:
//
// Internal data
//
Node* m_pHead;
unsigned m_nSize;
};
/////////////////////////////////////////////////////////////////////////////////
CList::CList()
: m_pHead(NULL)
, m_nSize(0)
{
}
Node *CList::Head() const
{
return m_pHead;
}
unsigned CList::Size() const
{
return m_nSize;
}
void CList::Insert(int nData)
{
Insert(new Node(nData));
}
void CList::Insert(Node *pNew)
{
pNew->pNext = m_pHead;
if (m_pHead)
m_pHead->pPrev = pNew;
pNew->pPrev = NULL;
m_pHead = pNew;
++m_nSize;
}
void CList::Delete(unsigned nPos)
{
Delete(Get(nPos));
}
void CList::Delete(Node *pDel)
{
if (pDel == m_pHead)
{
// delete first
m_pHead = pDel->pNext;
if (m_pHead)
m_pHead->pPrev = NULL;
}
else
{
// delete subsequent
pDel->pPrev->pNext = pDel->pNext;
if (pDel->pNext)
pDel->pNext->pPrev = pDel->pPrev;
}
delete pDel;
--m_nSize;
}
Node* CList::Get(unsigned nPos) const
{
unsigned nCount(0);
for (Node *p=m_pHead; p; p = p->pNext)
if (nCount++ == nPos)
return p;
throw std::out_of_range("No such node");
}
void CList::Print(std::ostream &os) const
{
const char szArrow[] = " --> ";
os << szArrow;
for (Node *p=m_pHead; p; p = p->pNext)
os << p->nData << szArrow;
os << "NIL\n";
}
int main()
{
CList l;
l.Print();
for (int i=0; i<10; i++)
l.Insert((i+1)*10);
l.Print();
l.Delete(3);
l.Delete(7);
l.Print();
try
{
l.Delete(33);
}
catch(std::exception &e)
{
std::cerr << "Failed to delete 33: " << e.what() << '\n';
}
l.Print();
return 0;
}