I was going through insertion of a node on BST recursively and I found an implementation below (check rinsert() function in the code below). The recursive function returns a pointer of the newly inserted node.
If the node is inserted lets say to the leaf node of height 4 for a tree. Shouldn't all the nodes along the path from height 3 to root be referencing some garbage pointer?
You can also find a test() function which actually returns a garbage pointer when the function doesn't run into an explicit return statement.
When I ran an inorder traversal using rinsert(), I was getting the BST without any garbage values.
Can anybody please help me understand what is going on in the rinsert() function?
struct Node {
Node* left;
Node* right;
int key;
Node(int key) {
this->key = key;
left = NULL;
right = NULL;
}
};
class BST {
Node* root;
public:
BST(int key) {
root = new Node(key);
}
Node* rinsert(Node* cur, int key) {
if (!cur) return new Node(key);
if (key < cur->key)
cur->left = rinsert(cur->left, key);
else
cur->right = rinsert(cur->right, key);
}
void inorder(Node* node) {
if (node == NULL) return;
inorder(node->left);
cout<<node->key<<" ";
inorder(node->right);
}
Node* getRoot() {
return root;
}
};
// function to return garbage pointer
Node* test() {
if (0) return new Node(2);
}
int main() {
BST bst = BST(2);
bst.rinsert(bst.getRoot(), 3);
bst.rinsert(bst.getRoot(), 1);
bst.rinsert(bst.getRoot(), 0);
bst.rinsert(bst.getRoot(), 7);
bst.rinsert(bst.getRoot(), 8);
bst.rinsert(bst.getRoot(), 4);
bst.rinsert(bst.getRoot(), 9);
bst.inorder(bst.getRoot());
// is it really a garbage pointer?
Node* t = test();
cout<<endl;
cout<<t->key;
}
output:
0 1 2 3 4 7 8 9
253425920
Yes the function is bugged because although it promises to return a Node* it doesn't in all cases.
The correct code (untested) is
Node* rinsert(Node* cur, int key) {
if (!cur) return new Node(key);
if (key < cur->key)
cur->left = rinsert(cur->left, key);
else
cur->right = rinsert(cur->right, key);
return cur; // new code
}
The lack of a return statement means the posted code invokes undefined behaviour. Unfortunately undefined behaviour does not mean a program will not work, it does not mean that the function will return a garbage pointer. Just by chance, in this case, the right pointer happens to be in the right register for the return value to be correct. So the code 'works'. On a different compiler (or even a different day) you might not be so lucky.
Related
I have implemented binary search tree in C++ and for some reason I am not seeing where the segmentation fault occurs. But I do notice that when I comment out root = node in the first conditional statement in addNode the error goes away. What exactly is a segmentation fault and how does it related to pointers?
#include <iostream>
#include <iomanip>
using namespace std;
class bstNode
{
public:
int value;
bstNode *left;
bstNode *right;
bstNode(){};
~bstNode(){};
bstNode(int value)
{
this->value = value;
this->left = NULL;
this->right = NULL;
}
bstNode(int value, bstNode *left, bstNode *right)
{
this->value = value;
this->left = left;
this->right = right;
}
bstNode *root;
void addNode(int value)
{
if (root == NULL)
{
bstNode *node = new bstNode(value);
root = node;
}
else
{
bstNode *focusNode = root;
bstNode *parent;
while (focusNode != NULL)
{
if (value > focusNode->value)
{
focusNode = focusNode->right;
if (focusNode == NULL)
{
focusNode->right = new bstNode(value);
}
}
else
{
focusNode = focusNode->left;
if (focusNode == NULL)
{
focusNode->left = new bstNode(value);
}
}
}
}
}
static void printBST(bstNode *node)
{
while (node != NULL)
{
printBST(node->left);
cout << node->value;
printBST(node->right);
}
}
};
int main()
{
bstNode *node = new bstNode();
node->addNode(7);
node->addNode(2);
node->addNode(18);
node->addNode(6);
node->addNode(4);
node->addNode(23);
bstNode::printBST(node->root);
return 0;
}
The immediate error is this
if (focusNode == NULL) {
focusNode->left = new bstNode(value);
}
this is clearly wrong, if a pointer is null you cannot use it. You have this in multiple places. Fix that and then update the question once you have got past that. How did I know this? I ran your code under my debugger and it told me immediatley, you should learn how to get the most out of your debugger.
Next
void addNode(int value)
as a method for a class defined as
class bstNode {
public:
int value;
is very bad practice. In that method what does value refer to? The argument or the member variable. Get into the habit of giving member variables specific names like this
class bstNode {
public:
int value_;
Also minor nits. The accepted style for naming classes is with leading Caps like this
class BstNode {
public:
int value_;
or even
class BSTNode
class bstNode {
public:
int value_;
using namespace std;
I'd advise against doing this in general. It's hard to be sure what's in namespace std, but the short summary is "a lot, and more all the time", so making all of it visible directly can lead to problems.
bstNode(){};
~bstNode(){};
These don't really accomplish anything useful. The point of a constructor is to initialize the object, but these just leave the object uninitialized, which can lead to problems--especially segmentation faults when/if you try to dereference an uninitialized pointer.
bstNode(int value){
this->value = value;
this->left = NULL;
this->right = NULL;
}
This is better, but I'd prefer to use a member initializer list instead of assignments inside the body of the ctor, and I'd prefer nullptr over NULL:
bstNode(int value)
: value(value)
, left(nullptr)
, right(nullptr) {}
This next one:
bstNode(int value, bstNode* left, bstNode* right){
this->value = value;
this->left = left;
this->right = right;
}
...is pretty nicely written (though it could also use a member initializer list, which is usually preferable), but only rarely useful when building a binary search tree, because in normal use you only ever insert new leaf nodes, not new internal nodes.
void addNode(int value){
if (root == NULL){
bstNode* node = new bstNode(value);
root = node;
}
else{
bstNode* focusNode = root;
bstNode* parent;
while(focusNode != NULL){
if(value > focusNode->value){
focusNode = focusNode->right;
if(focusNode == NULL){
focusNode->right = new bstNode(value);
}
}
else{
focusNode = focusNode->left;
if(focusNode == NULL){
focusNode->left = new bstNode(value);
}
}
}
}
}
This is at least one obvious source of a segmentation fault--you dereference a pointer immediately after verifying that it's null.
At least for a first attempt, I think I'd use a recursive implementation, which tends to be simpler:
void addNode(int value, bstNode *&node = root) {
if (node == nullptr) {
node = new node(value);
} else if (value < node->value) {
addNode(value, node->left);
} else if (value > node->value) {
addNode(value, node->right);
} else {
// attempt at inserting duplicate value
}
}
Note that this passes a reference to a pointer, so we can modify the "current" pointer, rather than having to track the parent pointer while traversing the tree.
static void printBST(bstNode* node){
while(node != NULL){
printBST(node->left);
cout << node->value;
printBST(node->right);
}
}
Since we're doing this recursively, we don't need (or even want) a loop. Traversing the left sub-tree, the current node, and the right subtree traverses the entire tree, with no iteration needed.
Also note that this doesn't print any delimiter between the numbers in the nodes, so a tree containing 12, 34 and a tree containing 1, 2, 3, 4 will both be printed out as 1234, which probably isn't very useful. Fortunately, adding a delimiter is pretty easy.
static void printBST(bstNode* node){
if (node != nullptr){
printBST(node->left);
cout << node->value << ' ';
printBST(node->right);
}
}
In the the following code...
while(focusNode != NULL){
if(value > focusNode->value){
focusNode = focusNode->right;
if(focusNode == NULL){
focusNode->right = new bstNode(value);
}
}
else{
focusNode = focusNode->left;
if(focusNode == NULL){
focusNode->left = new bstNode(value);
}
}
}
...you are referencing the children of a node that is guaranteed to be NULL because you verified that using the conditional statement. Since the node itself does not exist, it doesn't have properties like children. Imagine you're trying to communicate with the child of a person who has never existed.
The variable focusNode stores an address of a node. What focusNode->value does is that it goes to the node whose address focusNode stores and retrieves the value property from there.
When focusNode is NULL, it doesn't point to any node, thus you can't go there and retrieve its value property.
I wrote the code that you can replace with your while loop. I have tested it and it works:
while(true){
if(value > focusNode->value){
if(focusNode->right == NULL){
focusNode->right = new bstNode(value);
return;
} else focusNode = focusNode->right;
}
else{
if(focusNode->left == NULL){
focusNode->left = new bstNode(value);
return;
} else focusNode = focusNode->left;
}
}
I also fixed your printBST function. In the printBST function use if instead of while, because the the code inside the while loop would be executed an infinite number of times instead of printing the BST once.
static void printBST(bstNode* node){
if(node != NULL){
printBST(node->left);
cout << node->value <<" ";
printBST(node->right);
}
}
I am currently learning data structures, I was trying to create a function insert to insert a node at the nth position but I am always getting a segmentation error could you please help.
#include <iostream>
using namespace std;
struct node {
int data;
node* next;
};
struct node* head = NULL;
void insert(int dat, int pos) {
node* temp = new node;
temp->data = dat;
temp->next = NULL;
if (pos == 1) {
temp->next = head;
head = temp;
return;
}
node* newtemp = head;
for (int i = 0; i <= pos - 1; i++) {
newtemp = newtemp->next;
}
temp->next = newtemp->next;
newtemp->next = temp;
}
void print() {
node* temp = head;
while (temp != NULL) {
cout << temp->data;
temp = temp->next;
}
cout << endl;
}
int main() {
head = NULL;
insert(4, 1);
insert(6, 2);
print();
}
It should be
i<pos-1
temp->next=newtemp->next;
newtemp->next=temp;
And you should check if the Linkedlist have the position you have given
ie, if you pass to add node in 6th position to a Linkedlist having 2 nodes, it will give you segmentation fault.
By NULL->next
So you should check whether the linked list have the length less than or equal to position.
flag=false;
while(temp!=NULL)
{
if(i==Pos){
flag=true;
break;
}
temp=temp->next;
i++;
}
if flag is false then length is insufficient else do your stuff in temp
Look at this statement of insert() function:
for (int i = 0; i <= pos - 1; i++) {
For inserting element 6, you are giving positing 2.
First iteration:
initialize i with 0
0 <= 2 - 1 ==> true
newtemp = newtemp->next
[After this statement, newtemp is NULL because your linked list has only one element]
i++ ==> i is now 1
Second iteration
1 <= 2 - 1 ===> true
newtemp = newtemp->next
[newtemp is NULL and this statment will attempt to access next of a NULL
which is resulting in segmentation fault]
I hope you understood the cause of segmentation fault and a simple change can solve this problem - add NULL check for newtemp node, like this
for (int i = 0; i < pos && newtemp->next != NULL; i++) {
Your code does not check the validity of a pos value passed and with your current implementation it will add the element at the end of list if the pos value is greater than size of linked list. May you want to throw error when the value of pos is not valid. Also, you are not releasing the memory allocated for linked list nodes. Follow the good programming practice - release allocated memory before program exit.
Additional:
Since you are implementating the linked list in c++, you should use the object oriented concepts in you implementation. For e.g. bundle the data and functions operate on that data in one unit:
class Node {
private:
int data;
Node* next;
public:
// Add constructor for initialization of memeber variables
// Add destructor for cleanup and release memory
void insert(int dat, int pos);
void print();
};
A better implementation would be to separate the node and linkedlist in two different classes and bind their data with respective operations in them. For e.g.
class Node {
private:
int data;
Node* next;
public:
Node();
Node(const int& val);
void setData(const int& val);
int getData() const;
void setNext(Node* const nodePtr);
Node* getNext() const;
};
Singly linked list class LinkedList consisting of Node objects:
class LinkedList {
private:
Node* headNode;
Node* tailNode;
Node* currNode;
unsigned int count;
public:
LinkedList(); // constructor
// other overload of constructor, copy constructor, assignment operator, move semantics ....
~LinkedList(); // destructor
bool insertNode(const Node& newNode);
// other overload of insert, like insert at given position, at head of list, at tail of list etc..
unsigned int getCount() const;
Node* getHeadNode() const;
Node* getCurrNode() const;
Node* getTailNode() const;
bool deleteNode(const Node& node);
// other overload of delete node like detete tail node, delete head node etc.
bool deleteList();
};
#include <iostream>
using namespace std;
class Node{
public:
int data;
Node* left_child;
Node* right_child;
Node(int x){
data = x;
left_child = NULL;
right_child = NULL;
}
};
class BST{
public:
//Initially root is null
Node* root = NULL;
void insert(Node* node, int data){
if(node == NULL){
node = new Node(data);
return;
}
if(data < node->data){
insert(node->left_child,data);
}
else if(data > node->data){
insert(node->right_child,data);
}
}
void just_insert(int data){
insert(root,data);
}
void print(Node* node){
if(node == NULL){
return;
}
cout<<node->data<<" ";
print(node->left_child);
print(node->right_child);
}
void just_print(){
print(root);
}
};
int main() {
//For fast IO
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n,x;
cin>>n;
BST bst = BST();
for(int i=0; i<n; i++){
cin>>x;
bst.just_insert(x);
}
bst.just_print();
return 0;
}
What is wrong with this implementation of BST ? I am giving 8 values as input:
8
3
5
1
6
8
7
2
4
But when I invoke the print function. I do not get any output.
Am I missing out on some pointer logic ? The insert function goes recursively down the tree, to find a place to insert the value
The print function also works recursively.
Lets take a look at these lines from the insert function:
if(node == NULL){
node = new Node(data);
return;
}
The problem here is that the argument node is passed by value and is like any other local variable, and like any other local variable it will go out of scope once the function returns, and all changes to the variable will be lost.
What you need is to pass the pointer by reference, like
void insert(Node*& node, int data){ ... }
// ^
// Note ampersand here
You never assign to root in your BST class because your assignment to node in the insert class is not visible outside the insert function. You can fix this by passing the Node pointer by reference to the insert function:
void insert(Node*& node, int data)
typedef struct treeNode {
treeNode* left;
treeNode* right;
int data;
treeNode(int d) {
data = d;
left = NULL;
right = NULL;
}
}treeNode;
void insert(treeNode *root, int data) {
if (root == NULL) {
cout << &root;
root = new treeNode(data);
}
else if (data < root->data) {
insert(root->left, data);
}
else {
insert(root->right, data);
}
}
void inorderTraversal(treeNode* root) {
if (root == NULL)
return;
inorderTraversal(root->left);
cout<<root->data;
inorderTraversal(root->right);
}
int main() {
treeNode *root = new treeNode(1);
cout << &root << endl;
insert(root, 2);
inorderTraversal(root);
return 0;
}
So I'm pretty tired, but I was whipping some practice questions up for interview prep and for some reason this BST insert is not printing out that any node was added to the tree. Its probably something im glossing over with the pointers, but I can't figure it out. any ideas?
void insert(treeNode *root, int data) {
if (root == NULL) {
cout << &root;
root = new treeNode(data);
}
This change to root is lost as soon as the function ends, it does not modify the root passed as argument but its own copy of it.
Take note that when u insert the node, use pointer to pointer (pointer alone is not enough):
So, here is the fixed code:
void insert(treeNode **root, int data) {
if (*root == NULL) {
cout << root;
*root = new treeNode(data);
}
else if (data < (*root)->data) {
insert(&(*root)->left, data);
}
else {
insert(&(*root)->right, data);
}
}
And in main:
int main() {
treeNode *root = new treeNode(1);
cout << &root << endl;
insert(&root, 2);
inorderTraversal(root);
return 0;
}
Your logic is correct!
The only issue is that when you create a local variable, even if it is a pointer, its scope is local to the function. In your main:
...
insert(root, 2);
...
function call sends a copy of the root which is a pointer to treeNode (not the address of root). Please note that
void insert(treeNode *root, int data)
gets a treeNode pointer as an argument (not the address of the pointer). Attention: This function call may look like "call by pointer" (or reference) but it is actually "call by value". The root you define in the main function and the root inside the insert method have different addresses in the stack (memory) since they are different variables. The former is in main function stack in the memory while the latter is in insert method. Therefore once the function call insert finishes executing, its stack is emptied including the local variable root. For more details on memory refer to: stacks/heaps.
Of course the data in the memory that you allocated using:
*root = new treeNode(data);
still stays in the heap but you have lost the reference to (address of) it once you are out of the insert function.
The solution is either passing the address of original root to the function and modifying it (as K-ballo and dip has suggested) OR returning the modified local root from the function. For the first approach please refer to the code written by dip in his/her answer.
I personally prefer returning the modified root from the function since I find it more convenient especially when implementing other common BST algorithms. Here is your function with a slight modification of your original code:
treeNode* insert(treeNode *root, int data) {
if (root == NULL) {
root = new treeNode(data);
}
else if (data < root->data) {
root->left=insert(root->left, data);
}
else {
root->right=insert(root->right, data);
}
return treeNode;
}
The function call in main will be:
int main() {
treeNode *root = new treeNode(1);
cout << &root << endl;
root = insert(root, 2);
inorderTraversal(root);
return 0;
}
Hope that helps!
After a while seeing some complicated methods of dealing with the Binary tree i wrote a simple program that can create, insert and search a node i hope it will be usefull
/*-----------------------Tree.h-----------------------*/
#include <iostream>
#include <queue>
struct Node
{
int data;
Node * left;
Node * right;
};
// create a node with input data and return the reference of the node just created
Node* CreateNode(int data);
// insert a node with input data based on the root node as origin
void InsertNode (Node* root, int data);
// search a node with specific data based on the root node as origin
Node* SearchNode(Node* root, int data);
here we define the node structure and the functions mentioned above
/*----------------------Tree.cpp--------------*/
#include "Tree.h"
Node* CreateNode(int _data)
{
Node* node = new Node();
node->data=_data;
node->left=nullptr;
node->right=nullptr;
return node;
}
void InsertNode(Node* root, int _data)
{
// create the node to insert
Node* nodeToInsert = CreateNode(_data);
// we use a queue to go through the tree
std::queue<Node*> q;
q.push(root);
while(!q.empty())
{
Node* temp = q.front();
q.pop();
//left check
if(temp->left==nullptr)
{
temp->left=nodeToInsert;
return;
}
else
{
q.push(temp->left);
}
//right check
if(temp->right==nullptr)
{
temp->right=nodeToInsert;
return;
}
else
{
q.push(temp->right);
}
}
}
Node* SearchNode(Node* root, int _data)
{
if(root==nullptr)
return nullptr;
std::queue<Node*> q;
Node* nodeToFound = nullptr;
q.push(root);
while(!q.empty())
{
Node* temp = q.front();
q.pop();
if(temp->data==_data) nodeToFound = temp;
if(temp->left!=nullptr) q.push(temp->left);
if(temp->right!=nullptr) q.push(temp->right);
}
return nodeToFound;
}
int main()
{
// Node * root = CreateNode(1);
// root->left = CreateNode(2);
// root->left->left = CreateNode(3);
// root->left->left->right = CreateNode(5);
// root->right = CreateNode(4);
// Node * node = new Node();
// node = SearchNode(root,3);
// std::cout<<node->right->data<<std::endl;
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;
}