Search and protecting singly linked list in C++ - c++

I have one questions regarding searching elements on a Singly Linked List of ints, in this case, using C++. I'm creating my own version of list for exercising. This is the code
Let's suppose I have two search functions. I know we need to traverse the entire list until find the element because we don't have direct access like arrays.
The two functions are:
bool search(int n); // Traverse the list till find n.
bool search(Node* node, int n); Traverse the list till find n only after *node (included)
1 case: My list has the following elements: [0, 1, 2, 3]
If I search for 3 I easily find at the end of the list. Nice.
QUESTIONS:
2 case: My list has the following elements: [0, 1, 2, 3, 3, 3, 4, 5, 6]
If I search for 3 with:
bool search(int n);
I'm going to get the first 3 element always, except if I have a reference to the second or third 3 element to pass to that function:
bool search(Node* node, int n);
My questions is if that is the correct search algorithm in a singly linked list. The two types of functions or if I should have other types.
Bellow is the code for my actual code (I didn't put the code for searching):
SingleLinkedList.h
struct Node {
int data;
Node* next;
Node(int d = 0)
: data {d}, next {nullptr}
{}
};
class SinglyLinkedList {
public:
SinglyLinkedList();
~SinglyLinkedList();
void display();
bool addFirst(const int); // Add a node to the beginning of the list.
bool addFirst(Node*); // Add a node to the beginning of the list.
bool addLast(const int); // Add a node to the end of the list.
bool addLast(Node*); // Add a node to the end of the list.
private:
Node* head;
Node* tail;
};
SinglyLinkedList.h
#include "SinglyLinkedList.h"
#include <iostream>
SinglyLinkedList::SinglyLinkedList()
: head {nullptr}, tail {nullptr}
{}
SinglyLinkedList::~SinglyLinkedList() {
Node* iterationNode = head;
Node* actualNode {nullptr};
while (iterationNode != nullptr) {
actualNode = iterationNode;
iterationNode = iterationNode->next;
delete actualNode;
}
}
void SinglyLinkedList::display() {
std::cout << "################### Displaying Linked List ###################" << std::endl;
if (head == nullptr) {
std::cout << "Linked List is empty!" << std::endl;
}
else {
Node* iterationNode = head;
std::cout << "[ ";
while (iterationNode != nullptr) {
std::cout << iterationNode->data << " ";
iterationNode = iterationNode->next;
}
iterationNode = nullptr;
std::cout << "]" << std::endl;
}
std::cout << "##############################################################" << std::endl;
}
bool SinglyLinkedList::addFirst(const int n) {
Node* element = new Node {n};
if (head == nullptr) {
head = element;
tail = element;
}
else {
element->next = head;
head = element;
}
return true;
}
bool SinglyLinkedList::addFirst(Node* element) {
if (head == nullptr) {
head = element;
tail = element;
}
else {
element->next = head;
head = element;
}
return true;
}
bool SinglyLinkedList::addLast(const int n) {
Node* element = new Node {n};
if (head == nullptr) {
head = element;
tail = element;
}
else {
tail->next = element;
tail = element;
}
return true;
}
bool SinglyLinkedList::addLast(Node* element) {
if (head == nullptr) {
head = element;
tail = element;
}
else {
tail->next = element;
tail = element;
}
return true;
}
Program.cpp
#include <iostream>
#include "SinglyLinkedList.h"
int main() {
{
SinglyLinkedList list;
list.display();
list.addFirst(5);
list.addFirst(4);
list.addFirst(3);
Node* secondNode = new Node {2};
list.addFirst(secondNode);
Node* firstNode = new Node {1};
list.addFirst(firstNode);
Node* zeroNode = new Node;
list.addFirst(zeroNode);
list.addLast(6);
list.display();
}
system("pause");
}
Another question is, how can I protect my struct in a way the user of the program can not mess up changing the links/references directly. For example, in the Program.cpp, any programmer could simply do this:
secondNode->next = zeroNode

The answer to your first question depends on what you need. If you are doing this as a learning project, implement whatever you see fit. What you have described is appropriate for search by value.
The best way to prevent users from directly accessing your Node members in cases like this is to completely abstract the Node type away. You can do this simply by declaring and defining Node in your source file and use forward declarations of Node* in your header. Users who include your header will then not have any notion of your Node type whatsoever.
// SinglyLinkedList.h
class SinglyLinkedList {
//...//
struct Node* head; // head node is forward declared
//...//
}
// SinglyLinkedList.cc
struct Node {
//...
};
// define ll methods
If you do want the user to know about the Node type, one solution is to make its members private, create a public value accessor method, and make the Node a friend of the SinglyLinkedList class.

Related

I read the input number with getchar(), why is the number reversed in the linked list?

I typed 1234, but the list has 4,3,2,1 in it. I suspect the problem is getchar() itself, or a function in the class, but I have no way to find out.
The link class is responsible for some linked list operations, such as deletion, insertion, etc., while the node class is responsible for creating and assigning nodes.
The createlist class is responsible for the creation of the linked list, which is the main source of the problem. I wrote the debug statement in it, so you can run it and see the results for yourself
using namespace std;
class Node
{
public:
int data;
Node *next;
Node()
{
next = nullptr;
}
Node(int data)
{
this->data = data;
}
Node(const Node &temp)
{
this->data = temp.data;
}
};
class Link
{
public:
Node *head;
int length = 0;
Link()
{
head = new Node();
}
~Link()
{
while (head != nullptr)
{
Node *p = head->next;
free(head);
head = p;
}
}
void insert(const Node &cache)
{
Node *temp = new Node(cache);
temp->next = head->next;
head->next = temp;
length++;
}
};
void Creatlist(Link &link)
{
char cache;
while (1)
{
cache = getchar();
if (cache == '\n')
break;
link.insert(Node(cache - '0'));
cout << cache << " ";
}
cout<<endl;
Node *p = link.head->next;
cout << "in the linklist:";
while (p != nullptr)
{
cout << p->data << " ";
p = p->next;
}
}
int main()
{
Link link;
cout<<"inut numbers:"<<endl;
Creatlist(link);
}```
With the insert you inserted to the FRONT of the list. So you had "1", then "2->1" ... If you want to insert to the end, don't insert at the head, but hake a Node* tail in the class Link and an insert_end function as
//...
Node* temp;
void insert_end(const Node &cache){
Node *temp = new Node(cache);
tail->next=temp;
tail=tail->next;
length++;
}
Alsoin the constructor set tail=head

Counting occurrence in singly linked list by nodes

I am writing a simple app that gets a list and saves the objects as nodes in a singly linked list and we can add(), remove(), copy(), etc. each node depending on the given data set. each node has a char value which is our data and an int count which counts the occurrence of the related char.
e.g. for a list like
a, a, b, b, c, a
there would be three nodes (since there are three different characters) which are:
[a,3,*next] -> [b,2,*next] -> [c,1,*next] -> nullptr
bool isAvailable() checks if the data is already in the list or not.
Q: When inserting a data there are two options:
The data has not been entered: so we have to create a newNodewith the given data, count=1and *next=NULL.
The data is already entered: so we have to count++ the node that has the same data.
I know if the given data is available or not, but how can I point to the node with same data?
Here's the code:
#include "stdafx.h"
#include<iostream>
using namespace std;
class Snode
{
public:
char data;
int count;
Snode *next;
Snode(char d, int c)
{
data = d;
count = c;
next = NULL;
}
};
class set
{
private:
Snode *head;
public:
set()
{
head = NULL;
tail = NULL;
}
~set();
void insert(char value);
bool isAvailable(char value);
};
set::~set()
{
Snode *t = head;
while (t != NULL)
{
head = head->next;
delete t;
}
}
bool set::isAvailable(char value)
{
Snode *floatingNode = new Snode(char d, int c);
while(floatingNode != NULL)
{
return (value == floatingNode);
floatingNode->next = floatingNode;
}
}
void set::insert(char value)
{
Snode *newNode = new Snode(char d, int c);
data = value;
if (head == NULL)
{
newNode->next = NULL;
head = newNode;
newNode->count++;
}
else
{
if(isAvailable)
{
//IDK what should i do here +_+
}
else
{
tail->next= newNode;
newNode->next = NULL;
tail = newNode;
}
}
}
I know if the given data is available or not, but how can I point to the node with same data?
You'll need to start at the head of the list and iterate along the list by following the next pointers until you find the node with the same data value. Once you've done that, you have your pointer to the node with the same data.
Some other notes for you:
bool set::isAvailable(char value)
{
Snode *floatingNode = new Snode(char d, int c);
while(floatingNode != NULL)
{
return (value == floatingNode);
floatingNode->next = floatingNode;
}
}
Why is this function allocating a new Snode? There's no reason for it to do that, just initialize the floatingNode pointer to point to head instead.
This function always returns after looking at only the first node in the linked list -- which is not the behavior you want. Instead, it should return true only if (value == floatingNode); otherwise it should stay inside the while-loop so that it can go on to look at the subsequent nodes as well. Only after it drops out of the while-loop (because floatingNode finally becomes NULL) should it return false.
If you were to modify isAvailable() slightly so that instead of returning true or false, it returned either floatingPointer or NULL, you'd have your mechanism for finding a pointer to the node with the matching data.
e.g.:
// Should return either a pointer to the Snode with data==value,
// or NULL if no such Snode is present in the list
Snode * set::getNodeWithValueOrNullIfNotFound(char value) const
{
[...]
}
void set::insert(char value)
{
Snode * theNode = getNodeWithValueOrNullIfNotFound(value);
if (theNode != NULL)
{
theNode->count++;
}
else
{
[create a new Snode and insert it]
}
}
You had a lot of problems in your code, lets see what are they:
First of all, Snode doesn't need to be a class, rather you can go with a simple strcut; since we need everything public.(not a mistake, but good practice)
You could simple initialize count = 1 and next = nullptr, so that no need of initializing them throw constructor. The only element that need to be initialized through constructor is Snod's data.
Since c++11 you can use keyword nullptr instead of NULL, which denotes the pointer literal.
Member function bool set::isAvailable(char value) will not work as you think. Here you have unnecessarily created a new Snode and cheacking whether it points to nullptr which doesn't allow you to even enter the loop. BTW what you have written in the loop also wrong. What do you mean by return (value == floatingNode); ? floatingNode is a Snode by type; not a char.
Hear is the correct implementation. Since we don't wanna overwrite the head, will create a Node* pointer and assign head to it. Then iterate through list until you find a match. If not found, we will reach the end of the isAvailable() and return false.
inline bool isAvailable(const char& value)
{
Node *findPos = head;
while(findPos != nullptr)
{
if(findPos -> data == value) return true;
else findPos = findPos->next_node;
}
return false;
}
In void set::insert(char value), your logic is correct, but implementation is wrong. Following is the correct implementation.(Hope the comments will help you to understand.
void insert(const char& value)
{
if(head == nullptr) // first case
{
Node *newNode = new Node(value);
newNode->next_node = head;
head = newNode;
}
else if(isAvailable(value)) // if node available
{
Node *temp = head;
while(temp->data != value) // find the node
temp = temp->next_node;
temp->count += 1; // and count it by 1
}
else // all new nodes
{
Node *temp = head;
while(temp->next_node != nullptr) // to find the null point (end of list)
temp = temp->next_node;
temp = temp->next_node = new Node(value); // create a node and assign there
}
}
Your destructor will not delete all what you created. It will be UB, since your are deleting newly created Snode t ( i.e, Snode *t = head;). The correct implementation is as bellow.(un-comment the debugging msg to understand.)
~set()
{
Node* temp = head;
while( temp != nullptr )
{
Node* next = temp->next_node;
//std::cout << "deleting \t" << temp->data << std::endl;
delete temp;
temp = next;
}
head = nullptr;
}
Last but not least, the naming (set) what you have here and what the code exactly doing are both different. This looks more like a simple linked list with no duplicates. This is however okay, in order to play around with pointers and list.
To make the code or iteration more efficient, you could do something like follows. In the isAvailable(), in case of value match/ if you found a node, you could simply increment its count as well. Then in insert(), you can think of, if node is not available part.
Hope this was helpful. See a DEMO
#include <iostream>
// since you wanna have all of Node in public, declare as struct
struct Node
{
char data;
int count = 1;
Node* next_node = nullptr;
Node(const char& a) // create a constrcor which will initilize data
: data(a) {} // at the time of Node creation
};
class set
{
private:
Node *head; // need only head, if it's a simple list
public:
set() :head(nullptr) {} // constructor set it to nullptr
~set()
{
Node* temp = head;
while( temp != nullptr )
{
Node* next = temp->next_node;
//std::cout << "deleting \t" << temp->data << std::endl;
delete temp;
temp = next;
}
head = nullptr;
}
inline bool isAvailable(const char& value)
{
Node *findPos = head;
while(findPos != nullptr)
{
if(findPos -> data == value) return true;
else findPos = findPos->next_node;
}
return false;
}
void insert(const char& value)
{
if(head == nullptr) // first case
{
Node *newNode = new Node(value);
newNode->next_node = head;
head = newNode;
}
else if(isAvailable(value)) // if node available
{
Node *temp = head;
while(temp->data != value) // find the node
temp = temp->next_node;
temp->count += 1; // and count it by 1
}
else // all new nodes
{
Node *temp = head;
while(temp->next_node != nullptr) // to find the null point (end of list)
temp = temp->next_node;
temp = temp->next_node = new Node(value);
}
}
void print() const // just to print
{
Node *temp = head;
while(temp != nullptr)
{
std::cout << temp->data << " " << temp->count << "\n";
temp = temp->next_node;
}
}
};
int main()
{
::set mySet;
mySet.insert('a');
mySet.insert('a');
mySet.insert('b');
mySet.insert('b');
mySet.insert('c');
mySet.insert('a');
mySet.print();
return 0;
}

Linked list search function modifying list

I am trying to implement a doubly linked list in C++ and the add function is working properly but the find node function is modifying the list.
All other function like insertAfter, delete depend on this find function and hence they are also not working as expected.
I am new to C++, so I don't completely understand pointers. I simply tried to replicate my Java program in C++. I know for sure that in the find function the pointer to the head node is causing the problem but I don't completely understand how.
Below is my code :
struct Node{
int data;
Node* next;
Node* prev;
Node(int d) {
data = d;
};
};
struct DLL {
Node* head;
Node* tail;
int size;
//Adding a Node to the Doubly LL
void addNode(Node* n) {
//If LL is empty add the first Node
if (tail == NULL) {
tail = n;
head = n;
}
//Else add add node to the tail. Connect n to the tails next and make n the tail
else {
tail->next = n;
n->prev = tail;
tail = n;
tail->next = NULL;
}
size++;
};
//Finding a random Node in the linked List
//It will return the Node with the FIRST occurrence where data = d
Node* findNode(int d) {
//We will start at the head and then traverse through the entire list to find a Node where data = d
Node* start = head;
if (start == NULL) {
cout<<"No element in the List" <<endl;
return NULL;
}
// If head is the Node we are looking for
if (start->data = d) {
cout<< "Node found with matching data : " << start << endl;
return start;
}
//While next pointer is not null, traverse to search for a match.s
while (start->next != NULL) {
start = start->next;
if (start->data == d) {
cout<< "Node found with matching data : " << start << endl;
return start;
}
}
cout << "No node found with matching data = " << d <<endl;
return NULL;
};
};
start->data = d
This line in your second if block is assigning d to start->data rather than comparing the two.
This is a good time to learn about constness.
Node* findNode(int d) {
//We will start at the head and then traverse through the entire list to find a Node where data = d
Node* start = head;
if (start == NULL) {
cout<<"No element in the List" <<endl;
return NULL;
}
// If head is the Node we are looking for
if (start->data = d) {
cout<< "Node found with matching data : " << start << endl;
return start;
}
This function has write access to the list, and you don't want that. Unfortunately, you abuse this access in the last if statement:
if (start->data = d) {
this code assigns the value of d to start->data and then tests if the value assigned to it was not null.
We can mark this function as const easily:
//////////////////////vvvvv/////////////////
Node* findNode(int d) const {
//We will start at the head and then traverse through the entire list to find a Node where data = d
Node* start = head;
if (start == NULL) {
cout<<"No element in the List" <<endl;
return NULL;
}
// If head is the Node we are looking for
if (start->data = d) {
cout<< "Node found with matching data : " << start << endl;
return start;
}
and now the if will generate a compiler error.
A cleaned up version of your code might look something like the following:
#include <iostream>
struct Node {
int data_;
Node* next_ { nullptr };
Node* prev_ { nullptr };
Node(int data) : data_(data) {}
};
struct DLL {
Node* head_ { nullptr };
Node* tail_ { nullptr };
int size_ { 0 };
//Adding a Node to the Doubly LL
void addNode(Node* node) {
//If LL is empty add the first Node
if (tail_ == nullptr) {
tail_ = node;
head_ = node;
node->prev_ = node->next_ = nullptr;
}
//Else add add node to the tail. Connect n to the tails next and make n the tail
else {
tail_->next_ = node;
node->prev_ = tail_;
tail_ = node;
node->next_ = nullptr;
}
size_++;
}
//Finding a random Node in the linked List
//It will return the Node with the FIRST occurrence where data = d
Node* findNode(int data) const {
//We will start at the head and then traverse through the entire list to find a Node where data = d
//While next pointer is not null, traverse to search for a match.s
for (Node* start = head_; start != nullptr; start = start->next_) {
if (start->data_ == data) {
std::cout << "Node found with matching data : " << start << '\n';
return start;
}
}
std::cout << "No node found with matching data = " << data << '\n';
return nullptr;
}
};
int main()
{
DLL dll;
Node n1(1), n3(3), n5(5);
dll.addNode(&n1);
dll.addNode(&n3);
dll.addNode(&n5);
if (dll.findNode(1) != &n1)
std::cerr << "wrong result for findNode(1)\n";
if (dll.findNode(2) != nullptr)
std::cerr << "wrong result for findNode(2)\n";
if (dll.findNode(3) != &n3)
std::cerr << "wrong result for findNode(3)\n";
if (dll.findNode(4) != nullptr)
std::cerr << "wrong result for findNode(4)\n";
if (dll.findNode(5) != &n5)
std::cerr << "wrong result for findNode(5)\n";
}
Live demo: http://ideone.com/X34EgY

double free or corruption in the Stack destructor

I am pretty sure the problem is at while (!empty()) pop(); because after I commented it out. everything works fine. but it doesn't delete head. what's wrong with this part?
The intention is as follows: LinkedList has two data members, head and tail. When the list is empty, these should both be equal to 0. When the list is non-empty, then both head and tail shall be non-zero, and they should refer to the first and last items in the list respectively. And there shall be a path from head to tail via the next_ pointers. If the list has only one item, then head == tail.
#include <iostream>
//stack using linked list
class LinkedList {
public:
LinkedList() : head(0), tail(0) {}
~LinkedList() {
while (!empty()) pop();
std::cout<< "~LinkedList" << std::endl;
}
void pop() {
node* temp;
temp = head;
for ( ; temp->next_ != 0; temp = temp->next_) {
tail = temp;
}
delete temp;
tail->next_ = 0;
std::cout << "pop()" << std::endl;
} //removes, but does not return, the top element
int top() {
return tail->value_;
} //returns, but does not remove, the top element
bool empty() {
return head == 0;
}
void push(const int& value) {
node* element = new node(value);
if (empty()) {
head = tail = element;
} else {
tail->next_ = element;
tail = element;
}
} //place a new top element
private:
class node {
public:
node(const int& input) : value_(input), next_(0) {};
int value_; //store value
node* next_; //link to the next element
};
node* head;
node* tail;
};
int main() {
LinkedList list;
list.push(1);
list.push(2);
std::cout << list.top() << std::endl;
list.pop();
std::cout << list.top() << std::endl;
return 0;
}
fixed the problem by changing the destructor to the following codes:
~LinkedList() {
while (head != tail) pop();
delete head;
std::cout<< "~LinkedList" << std::endl;
}
You have one part of your problem here
bool empty() {
return head == 0;
}
When is head set to 0 (NULL)? Never?
pop() is wrong. When you have only one element left, both head and tail point to it. So when you delete temp, you are in fact deleting both head and tail, then you are:
accessing tail, which is now a deallocated pointer, and
not setting tail or head back to 0
Your pop() doesn't fix this->head if you pop() the last element in the list.
You could add these checks at the start. This is a boring solution, and perhaps you should change your overall design, but this code should correct your current algorithm for pop. In particular, when popping the last item, both head and tail should be set to zero.
Also, it should be delete tail->next_;, not delete temp;, just before the tail->next_ = 0;
void pop() {
if(head == 0) {
// the list is empty, there's nothing to pop. This should be an error!
}
if((head != 0 && head == tail) {
// there is only one item in the list
delete head;
head = 0;
tail = 0;
}
node* temp;
temp = head;
for ( ; temp->next_ != 0; temp = temp->next_) {
tail = temp;
}
delete tail->next_;
tail->next_ = 0;
std::cout << "pop()" << std::endl;
}
I haven't tested this, but it should fix some of the problems.

C++ Linked List assignment: trouble with insertion and deletion

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;
}