I am trying to dig into data structures in C++. Therefore I am learning how to write a list. Everything seemed to be working just fine until it came to overloading sum operator +. For two given lists it sums two of the highest values of the lists.
Here is .h file:
typedef struct rob{
int value;
struct rob* next;
}element;
class list{
public:
friend list& operator+(list&,list&);
friend void merge(list& x,list& y);
void show();
bool search(int x);
void append(int x);
bool sortAppend(int x);
list& operator--(int);
bool empty() { return (inf.head==nullptr);}
void clear() { inf.head = nullptr; }
list() { inf.head = inf.tail = nullptr; }
~list() { while(!empty()) { (*this)--;}}
private:
typedef struct{
element* head;
element* tail;
}info;
info inf;
};
I know that in an .h file the typedef may seem a bit C-like, but the header design is copied from the book that I am learning from. I am trying to crack the methods by my own though using authors ideas.
And relevant function definitions:
#include "list.h"
bool list::sortAppend(int x){
element* newElem = new element;
newElem->value = x;
if (empty()){
inf.head=inf.tail=newElem;
newElem->next=nullptr;
return true;
}
else if ( (newElem->value) < (inf.head->value) ){
newElem->next=inf.head;
inf.head=newElem;
return true;
}
else if ( (newElem->value) > (inf.tail->value) ) {
newElem->next=nullptr;
inf.tail->next=newElem;
return true;
}
element* tempHead = inf.head;
while(tempHead!=inf.tail){
if ( (newElem->value) < (tempHead->next)->value) {
newElem->next = (tempHead->next);
tempHead->next = newElem;
return true;
}
else{
tempHead = tempHead->next;
}
}
return false;
}
list& operator+(list& X, list& Y){
list* tempListArr[2] = {&X, &Y};
list* tempList = new list;
for(const list* i: tempListArr)
{
element* tempHead = (i->inf).head;
while(tempHead!= nullptr){
tempList->sortAppend(tempHead->value);
tempHead = tempHead->next;
}
tempList->show();
std::cout << "--\n";
}
return *tempList;
}
For given list containing values:
#include <iostream>
#include "list.cpp"
int main(){
list myList;
myList.sortAppend(5);
myList.sortAppend(2);
myList.sortAppend(4);
list myList2;
myList2.sortAppend(21);
list myList3;
myList3 = myList + myList2;
return 0;
}
Could anyone point me where I made a mistake? I am stuck for a few hours now and I don't know what goes wrong.
Many thanks in advance!
FOLLOW UP:
The sortAppend method surely works. It does create a sorted list as desired.
There must have been something wrong with the + operator definition itself though I have tried, instead of range loop, using for loop for one iteration and still I got a list of two values only.
You are simply not setting inf.tail to the new tail in
else if ((newElem->value) > (inf.tail->value)) {
newElem->next = nullptr;
inf.tail->next = newElem;
inf.tail = newElem; // <-- missing!
return true;
}
You should - at least - change the signature of operator+ to return a list instead of a list reference and return a local object instead of an unowned heap object (which is a memory leak). If you do so you will have to write a copy constructor and copy assignment operator too.
Given your code,
list myListWierd;
myListWierd.sortAppend(2);
myListWierd.sortAppend(4);
myListWierd.sortAppend(5);
myListWierd.show();
shows
2
5
so the sortAppend does not work.
The trouble is around updating either the tail, since operator + relies on using the tail.
I could sort the code out for you and make it work; indeed Andreas' answer does this. But for now, notice you have assumed a function works, but I found a case it doesn't work for by looking at the moving parts - a list we created, that we then try to re-create in a different order. As a general rule, try all the parts in a function that goes wrong, one at a time, maybe as a unit test.
Rather than fixing this, for now, let's make a couple of suggestions.
First, the destructor does nothing, other than walk pointers (using empty which uses head and not tail - so head needs setting as said before)
~list() { while (!empty()) { (*this)--; } }
If you don't want leaks you need to give this more thought.
Next,
list& operator+(list&, list&)
creates a pointer and returns its contents. This is a BAD IDEA. NEVER DO THIS.
For now, change the signature to
list operator+(list&, list&);
and just return a list:
list operator+(list& X, list& Y) {
list* tempListArr[2] = { &X, &Y };
list tempList;//copy it over to the calling vode otherwise DANGER
for (const list* i : tempListArr)
{
element* tempHead = (i->inf).head;
while (tempHead != nullptr) {
tempList.sortAppend(tempHead->value);
std::cout << "Adding " << tempHead->value << '\n';
tempHead = tempHead->next;
}
tempList.show();
std::cout << "--\n";
}
return tempList;
}
Related
This my C++ code:
#include <iostream>
class Node
{
public:
int data;
Node* prev;
Node* next;
};
class Doublyll
{
private:
Node* head;
Node* tail;
public:
Doublyll();
Doublyll(int A[], int num);
~Doublyll();
friend std::ostream& operator<<(std::ostream& os, const Doublyll& src);
int Length(Node* p);
};
// Default Constructor will SET head and tail to NULL
Doublyll::Doublyll()
: head(NULL), tail(NULL)
{
}
// Explicit Construcor
Doublyll::Doublyll(int A[], int num)
: head(NULL), tail(NULL)
{
// std::cout << "Explicit Constructor called!\n";
Node** p = &head;
for (int i = 0; i < num; i++)
{
Node* t = new Node;
t->data = A[i];
if (head == NULL)
t->prev = NULL;
else
t->prev = tail;
t->next = NULL;
*p = t;
p = &(t->next);
tail = t;
}
}
// Destructor
Doublyll::~Doublyll()
{
// std::cout << "Desctructor called!\n";
Node* p = head;
Node* tmp;
while (p != NULL)
{
tmp = p;
p = p->next;
delete tmp;
}
}
// Display using Overloading << Operator
std::ostream& operator<<(std::ostream& os, const Doublyll& src)
{
Node* tmp;
for (tmp = src.head; tmp != NULL; tmp = tmp->next)
std::cout << tmp->data << " ";
std::cout << std::endl;
return os;
}
// Find Length how much Node in linked list
int Doublyll::Length(Node* p)
{
static int count = 0;
if (p != NULL)
{
count++;
Length(p = p->next);
}
return count;
}
int main()
{
int A[] = {2, 4, 6, 8, 10, 12, 14};
int size = sizeof(A) / sizeof(A[0]);
// Create object and linked list
Doublyll l1(A, size);
// Display linked list
std::cout << l1;
// Get length of linked list
int c = l1.Length(l1.head);
std::cout << c << std::endl;
return 0;
}
As you can see, I try to practice Doubly Linked List. Then, I want to count total Node in my linked list.
You can see in int Doublyll::Length(Node* p) I try to Count it using Recursion. Just because I want to practice it with Recursion. But, in my main() somewhow this code: int c = l1.Length(l1.head); said "Head is inaccessible"
I know that is because Head is Private in my Doublyll class. And I can simply change it to Public. OR I can write a function getHead() which will return Head pointer and then pass it as arguments.
So, Is there a way to dircetly pass it from my main() without change the member to public or write a getHead() function? or maybe there's another way to write a Recursion based on my problem, which in the future can also implement it to another recursion like display()? Because it seems like difficult to access if everything is inside class.
Maybe you can also review how I create a Doubly Linked List. Thank you!
Make int Doublyll::Length(Node *p) a private member function and add a public int Doublyll::Length() that takes no arguments and does:
int Doublyll::Length()
{
return Length(head);
}
(also you should probably make both of them const - int Doublyll::Length() const since they shouldn't modify anything)
Then just call l1.Length() in main.
Users of Doublyll shouldn't know about the internals of the class, and it doesn't make sense to ask a Doublyll object for the length from some node that it might not even own. Making Length(Node *p) private prevents nonsense things like l1.Length(l2.head).
As for your implementation of int Doublyll::Length(node *p) it's just wrong. As a comment mentions, you're using a static int count to track the length which will give you the wrong answer if you call the function multiple times. Plus your recursion is wrong since you aren't using the result of the recursive call. Do something like this instead:
int Doublyll::Length(Node *p) const
{
// Base case - no nodes
if (p == nullptr)
return 0;
// Recursive case
return 1 + Length(p->next);
}
Or a solution that allows for tail call optimization:
int Doublyll::Length(Node *p, int count) const
{
// Base case - no more nodes - return count
if (p == nullptr)
return count;
// Recursive case - increment count and go to the next node
return Length(p->next, count+1);
}
int Doublyll::Length() const
{
return Length(head, 0);
}
A common technique when implementing recursive functions is to have one public non-recursive function to start things off (say, Doublyll::Length()), and a second private helper function that actually performs the recursion (something like Doublyll::LengthRecursive()).
This could look something like:
int Doublyll::LengthRecursive(Node* p)
{
static int count = 0;
if (p != NULL)
{
count++;
Length(p = p->next);
}
return count;
}
int Doublyll::Length()
{
return LengthRecursive(head);
}
One way of handling a situation like this is to use two member functions: one that is the public interface and one that is private but has the signature you want for the recursive call.
For example:
class Doublyll
{
private:
Node* head;
Node* tail;
int LengthAux(Node* p); //private recursive implementation
public:
Doublyll();
Doublyll(int A[], int num);
~Doublyll();
friend std::ostream& operator<<(std::ostream& os, const Doublyll& src);
int Length(); // public interface
};
int Doublyll::Length() {
return LengthAux(head);
}
// Find Length how much Node in linked list
int Doublyll::LengthAux(Node* p)
{
static int count = 0;
if (p != NULL)
{
count++;
LengthAux(p->next);
}
return count;
}
...
This is a pretty common pattern used by implementations involving recursion. It is the nature of recursive calls that the signature of the recursive guts of the function is often different than the natural signature of calling the function externally.
I am having a few simple troubles regarding my code. What I am trying to do is build my own "list" code for 2 reasons. First of all, I want to get a deeper understanding of how linked lists work in practice. And secondly, because I am working on a project that requires a list of references, not just copied objects like the standard "list" library offers. I am also attempting to keep my code similiar to how C# works, while keeping the simplicity of python's naming scheme.
The following code is my issue:
// & - Get the address of object
// * - Get the contents of pointer
// int x = 25;
// int* p = &x;
// "p" now contains the pointer address
// "*p" contains the same info as x
// The following are all equal
// x = x + 5;
// x = *p + 5;
// *p = *p + 5;
template <class T> class Link;
template <class T> class Link {
public:
T result;
bool containsData = false;
Link<T> *x;
};
template <class T> class list {
public:
Link<T> start;
int count = 0;
Link<T> *blank(T object) {
Link<T> temp;
return &temp;
}
void append(T object) {
print("Starting");
Link<T> *temp = &start;
while (true) {
print("1");
if (temp->containsData == false) {
break;
}
print("2");
Link<T> *next = temp->x;
temp = next;
}
print("Doing");
temp->containsData = true;
temp->x = blank(object);
print("Done");
count++;
}
void pop(int index);
void clear();
void reverse();
T get(int index);
};
What is happening is that the first iteration works well. However, the second appended item in the list seems to halt at "1", seeming to be completely incapable of moving past "temp->containsData". I've tried putting it in a try-catch block, but it would seem that not even try-catch picks it up for some reason (Which surprised me quite a bit!). It just exits in the middle of trying to find out if the next item in the list is just another link to search through, or whether it is the last one in the list (Hence, containsData set to false).
I have checked, and yes it is the "temp->containsData" part that just crashes out. It seems trying to access "containsData" randomly crashes it. I am aware the code isn't too pretty, that's mainly from my debugging.
If anyone could throw me some pointers (Pun not-intended) as to how to continue, I would be incredibly grateful. Again, I do not want to just use the inbuilt "list" library and call it a day. I want to legit work through this coding trouble.
Thanking you in advance
Andrey :)
Link<T> *blank(T object) {
Link<T> temp;
return &temp;
}
is bad because it is returning a pointer to non-static local object, which will vanish on returning from this function.
Try this instead:
Link<T> *blank(T object) {
return new Link<T>();
}
Just like magic, the moment I post this, THEN stackoverflow decides to point me to a useful post. I've been looking online for hours!
Thanks for the (Surprisingly) quick responses! I managed to find a better way of doing it. Turns out that I was goind about it a bit of an unnecessarily complicated way. The following code seems to work:
template <class T> class Link {
public:
Link<T> *next;
T *item;
};
template <class T> class list {
public:
Link<T> *start = new Link<T>();
int count = 0;
void append(T *object) {
Link<T> *currentValue = start;
while (currentValue->next != nullptr) {
currentValue = currentValue->next;
}
currentValue->next = new Link<T>();
currentValue->item = object;
print(object);
count++;
}
void pop(int index) {
if (index >= count) { throw "index larger than size!"; }
if (index == 0) {
//Deleting the first item in the list
if (count == 1) {
start = new Link<T>();
} else {
start = start->next;
}
} else if (index == count - 1){
//Deleting the last item in the list
Link<T> *currentValue = start;
while (currentValue->next->next != nullptr) {
currentValue = currentValue->next;
}
currentValue->next = new Link<T>();
} else if (index == count - 1) {
//Deleting somewhere in the middle of the list
}
count--;
}
void clear() { start = new Link<T>(); count = 0; }
T get(int index) {
if (index >= count) { throw "index larger than size!"; }
int looper = 0;
Link<T> *currentValue = start;
while (looper != index) {
currentValue = currentValue->next;
looper++;
}
T *temp = currentValue->item;
return *temp;
}
};
Much smaller, works fine, links everything properly.
HOWEVER, thankyou to all the people pointing out that a pointer will disappear once the reference to it disappears. I completely forgot about that.
Thankyou so much for all your help, and I shall (hopefully) be able to finish this code pretty quickly :)
I'm learning C++ and experimenting with it. Now, I have came to a point where I don't really like one of my solutions.
#include <iostream>
using namespace std;
//template<class T>
class List{
public:
struct ListElem {
ListElem(int iElem, ListElem* iNext, ListElem* iPrev): mElem(iElem), pNext(iNext), pPrev(iPrev){
if(pNext != nullptr){
pNext->pPrev = this;
}
if(pPrev != nullptr){
pPrev->pNext = this;
}
}
friend ostream& operator<<(ostream& os,const ListElem& crArg) {
os << " " << crArg.mElem;
if (crArg.pNext)
os << *crArg.pNext;
return os;
}
public:
int mElem;
ListElem* pNext;
ListElem* pPrev;
};
void push_front(int iElem){
if(mHead == nullptr){
mTail = mHead = new ListElem(iElem,mHead,nullptr);
}else{
mHead = new ListElem(iElem,mHead,nullptr);
}
}
void push_back(int iElem){
if(mTail == nullptr){
mHead = mTail = new ListElem(iElem,nullptr,mTail);
}else{
mTail = new ListElem(iElem,nullptr,mTail);
}
}
void invert(){
for(ListElem* elem = mHead; elem != nullptr; elem = elem->pPrev){
ListElem* tmp = elem;
tmp = elem->pNext;
elem->pNext = elem->pPrev;
elem->pPrev = tmp;
}
ListElem* pTmpTail = mTail;
mTail = mHead;
mHead = pTmpTail;
}
friend ostream& operator<<(ostream& os,const List& crArg) {
if (crArg.mHead)
os << *crArg.mHead;
return os;
}
private:
ListElem* mHead = nullptr;
ListElem* mTail = nullptr;
};
int main(){
List l;
l.push_back(1);
l.push_front(10);
l.push_back(40);
l.push_back(30);
// l.push_front(10);
// l.push_front(20);
// l.push_back(30);
cout << l << endl;
l.invert();
cout << l << endl;
return 0;
}
This is my code and I want to invert the list. My function works invert() but it's ugly and, to me, not very good. It's a task that I found and it says: I can only go 1 time through the List and don't use any other helper list or dynamic data structure. Also, it should work for even and odd elements of the list.
What do you think? is there a better way to solve this. Maybe smarter and more readable?
void invert(){
ListElem* lo = mHead;
ListElem* hi = mTail;
while (lo != hi && //have not met
lo->pPrev != hi) // have not crossed
{
std::swap(lo->mElem, hi->mElem);
lo = lo->pNext;
hi = hi->pPrev;
}
}
What this does:
Points lo and hi at the beginning and end of the list
Tests that lo and hi have not yet converged.
Empty list case handled lo and h are both pointing NULL and equal
1 item case handled lo and hi are both pointing to the same node and equal.
Swaps the data at lo and hi's nodes. It does not swap the nodes. For an int, it's much easier to swap the data than to it is to change the 4 links that must be updated. For larger data, this may not hold, but the complexity of the function goes way up. Your call as to whether or not it would be worth it.
Re-points lo and hi to bring them closer to convergence.
Go to 2.
Because the data in the list swaps its way to convergence, there are never more than length / 2 iterations.
The code seems fine to me, but if you want to make thing look better, you can use std::swap.
for(auto elem = mHead; elem; elem = elem->pPrev)
std::swap(elem->pNext, elem->pPrev);
std::swap(mHead, mTail);
I am trying to make a linked list but am running into problems because I am deleting my nodes twice. The problem only arises when a node is passed into a function (if it is passed by reference everything is fine) which leads me to believe that the object being passed into the function is being copied in such a way that the pointers are pointing to nodes from the original list not the new list. I tried to get around this by overloading the = operator but this didn't work either. An explanation of what I'm doing wrong would be great.
Thanks for the help
#include <iostream>
struct node{
node(int n){
if (n == 1){
data = 1;
next = NULL;
}
if (n == 2){
data = 2;
next = new node(1);
next -> next = NULL;
}
}
~node(){
std::cout << data << std::endl;
if (next != NULL) delete next;
}
void operator=(node a){
next = NULL;
}
int data;
node* next;
};
void func2(node v){
}
int main(){
node v(2);
if (v.next -> next == NULL) std::cout << "true\n";
func2(v);
return 0;
}
Your suspicions are correct, but therein lies the problem; when you pass the node into func2, you're only copying the first node, not the entire list. The copy constructor will copy the first node, and the pointer in the first node (which points to the original second node), so when v goes out of scope in func2 it gets deleted once, then gets deleted again when it goes out of scope of main. You'll need to write the copy constructor to do a "deep copy," traversing the entire list and copying every node into a new address.
Remember also that the copy constructor should return *this in most cases, this is in the C++ FAQ and in the book "Effective C++" by Scott Meyers. Thus the signature should be:
node& operator=(const node& node);
If you're going to overload the assignment operator, you should probably also define a copy constructor. Good job explaining the problem, by the way.
Edit: The code would look like this. I apologize that I haven't tested this; I'm on my tablet and editing this is painful...
#include <iostream>
struct node{
node(const node& toCopy) : data(toCopy.data)
{
if(toCopy.next != null) {
next = new node(toCopy);
}
}
node(int n){
if (n == 1){
data = 1;
next = NULL;
}
if (n == 2){
data = 2;
next = new node(1);
next -> next = NULL;
}
}
node& operator=(const node& toCopy) {
if(&toCopy != this) {
data = toCopy.data;
if(next != NULL) {
next = new node(toCopy);
}
}
return *this;
}
~node(){
std::cout << data << std::endl;
if (next != NULL) delete next;
}
int data;
node* next;
};
void func2(node v){
}
int main(){
node v(2);
if (v.next -> next == NULL) std::cout << "true\n";
func2(v);
return 0;
}
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;
}