i made this linked list class in c++ and it works fine except after i run it the program goes unresponsive. i have located the line that's causing the problem but i have no idea why. Even when i type it differently it still does the same thing.
Here's my list class:
#include <string>
template<class T>
class List : public Object{
private:
Node<T>* first;
Node<T>* last;
int length;
public:
List() : Object(new std::string("List")) {
first = NULL;
last = NULL;
length = 0;
}
~List() {
delete first;
delete last;
}
void Add(T value) {
if(first==NULL)
first = new Node<T>(NULL, value);
else if(last==NULL)
---->last = new Node<T>(first, value);<-----
else
last = new Node<T>(last, value);
length++;
}
T Remove(T value) {
Node<T>* temp = first;
while(temp!=NULL) {
if(temp->GetValue()==value) {
temp->GetPrev()->SetNext(temp->GetNext());
temp->GetNext()->SetPrev(temp->GetPrev());
delete temp;
length--;
return value;
}
temp = temp->GetNext();
}
return 0;
}
T Get(int index) {
Node<T>* temp = first;
int i = 0;
while(temp!=NULL) {
if(i==index)
return temp->GetValue();
i++;
temp = temp->GetNext();
}
return 0;
}
};
when i remove the marked line above the program go unresponsive. This is my Node constructor:
#include <string>
template<class T>
class Node : public Object{
private:
Node* next;
Node* prev;
T value;
public:
Node(Node* prev, T value) : Object(new std::string("Node")){
if(prev!=NULL) {
prev->next = this;
this->prev = next;
}
next = NULL;
this->value = value;
}
~Node() {
delete next;
}
T GetValue() {
return value;
}
Node* GetNext() {
return next;
}
Node* GetPrev() {
return next;
}
};
my object class:
#include <string>
class Object {
private:
std::string* type;
public:
Object() {
type = new std::string("Object");
}
Object(std::string* type) {
this->type = type;
}
~Object() {
delete type;
}
std::string* GetType() {
return type;
}
};
my Test.cpp
#include <iostream>
#include <string>
#include "Object.h"
#include "Node.h"
#include "List.h"
using namespace std;
int main () {
List<int> l;
l.Add(5);
l.Add(93);
l.Add(17);
l.Add(7789);
l.Add(60);
cout << "node 4 is:" << l.Get(3) << endl;
return 0;
}
error image http://i50.tinypic.com/2mw5phi.png
thanks for reading and please help as soon as you can, comment if you need me to supply more info.
Edit: There are many problems with your program, but what might be causing your crash: Your Add-function does not work correctly. It should be something like this:
if(first==NULL) {
first = new Node<T>(NULL, value);
last = first;
} else {
last = new Node<T>(last, value);
}
length++;
Otherwise, it will not correctly insert the second element. Why? With your original code, after the first add, your last is still NULL because of the else. So on the second add, you set last to new Node<T>(NULL, value). Therefore, it will not assign the first element's next pointer. And your list will be inconsistent.
Apart from that, there are double-frees, unnecessary heap-allocation of the string field in your Object class, ownership issues etc. To give you just one more example: Your List destructor will cause a heap corruption due to a double free. Calling delete first will delete all nodes due to the delete next in Node's destructor, as long as the list is consistent. Then you call delete last, but that object was already freed. This will corrupt your program's memory management and can also cause a crash at program exit.
Does this function seem correct to you??
It says GetPrev, but its actually getting next.
Node* GetPrev() {
return next;
}
I found that if I comment out this line in the Node constructor the code compiles:
if (next != NULL) {
// next->next = this;
prev = next;
}
Edit 1:
I also realized that you were doing this in your Node class:
private:
Node* next;
Node* prev;
T value;
Since these objects are declared in the Node class, they are at this time incomplete types. I managed to replicate that problem down to a simple one like this:
template <class T>
struct S {
S* s = new S();
~S() { delete s; }
};
int main() {
S<int> s; // Segmentation fault (core dumped) ./test > .stdout
}
This causes a crash because S is an incomplete type within itself.
I'm getting the same segementation fault as I got in your code. I'm pretty sure it's because the pointers in the Node class are built upon incomplete types; and accessing the data from them is looking into memory that isn't yours, hence the crash.
Related
So i have a Linked list implementation of my own and it can successfully keep integers and call them when needed with overloaded [] operator but when it comes to storing a class in my linked list, it seems that i can't call the class appropriately (using the same [] operator).
Called functions and members of my Linked List;
#include <iostream>
#include <assert.h>
template<typename T>
struct node {
T data;
node<T>* next;
};
template<typename T>
class Vectem {
private:
node<T>* head;
node<T>* last;
int lenght;
public:
void insert(T value) {
last->next = new node<T>;
last = last->next;
last->data = value;
last->next = NULL;
if (isEmpty()) {
head = last;
}
lenght++;
}
node<T>* search(int indx) {
node<T>* current;
current = head;
int count=0;
while (current != NULL) {
if (count == indx) {
break;
}
current = current->next;
count++;
}
return current;
}
T& operator [](int indx) {
assert(indx >= lenght - 1);
T result;
result = search(indx)->data;
return result;
}
};
And here is the main function and the class that i try to store;
#include <iostream>
#include <fstream>
#include <string>
#include "VectemLibrary.h"
class word {
public:
std::string value;
int count;
word(std::string value, int count): value(value),count(count) {
}
word() {
value = "NOT ASSIGNED";
count = 0;
}
word(const word& w1) {
value = w1.value;
count = w1.count;
}
~word() {
std::cout << "Word Destroyed" << std::endl;
}
};
int main()
{
Vectem<word> wordContainer;
word newWord("hello", 1);
wordContainer.insert(newWord);
std::cout << wordContainer[0].value;
}
Visual studio gave me the expection with this message at the last line where i call the first member of linked list with [];
Exception thrown at 0x7A0CF3BE (ucrtbased.dll) in Top 10 words.exe: 0xC0000005: Access violation reading location 0xCCCCCCCC.
I think that my lack of experience with pointers may have caused the problem but if you see something that i can't, Please enlighten me.
There are other problems with the code you posted as well (e.g. isEmpty() is not declared or defined), but I'll focus on the issue you explicitly mentioned.
In your operator:
T& operator [](int indx) {
assert(indx >= lenght - 1);
// You declare this variable on the stack
T result;
result = search(indx)->data;
// And then you return this variable by reference; this is not okay
return result;
}
As mentioned in my code comments (and by #Johnny Mopp in his comment to your post), you shouldn't (can't) return a reference or pointer to a variable declared within the returning function and constructed on the stack. Anything on the stack will be destroyed once the function call ends, so any returned pointers or references to such variables will be dangling references; using said pointers or references will result in undefined behavior.
So you don't want to return a reference to a stack-allocated variable like result; you want to return a reference to the data within the node itself (which is allocated on the heap by insert()), as it will still be a valid reference after the function returns:
return search(indx)->data;
There are several problems with your code, but the most important is that you are not initializing the head, last, or lenght members of Vectem at all. An Access Violation error at address 0xCCCCCCCC is a good indication that uninitialized memory is being accessed, as some compilers/setups fill uninitialized memory with 0xCC bytes, thus head and last are initially 0xCCCCCCCC in your case.
You need to add appropriate constructors to Vectem (as well as a destructor, a copy constructor, and a copy assignment operator, per the Rule of 3), eg:
template<typename T>
class Vectem {
private:
node<T>* head;
node<T>* last;
int lenght;
public:
Vectem() : head(NULL), last(NULL), lenght(0) {}
Vectem(const Vectem &src) : head(NULL), last(NULL), lenght(0)
{
// copy src's data to *this as needed ...
}
~Vectem()
{
// cleanup *this as needed ...
}
Vectem& operator=(const Vectem &rhs)
{
if (&rhs != this) {
// clear *this, and copy rhs's data to *this, as needed ...
}
return *this;
}
...
};
Or, in C++11 and later, you can initialize the members directly in their declarations (also, be sure to add a move constructor and a move assignment operator, per the Rule of 5), eg:
template<typename T>
class Vectem {
private:
node<T>* head = nullptr;
node<T>* last = nullptr;
int lenght = 0;
public:
Vectem() = default;
Vectem(const Vectem &src)
{
// copy src's data to *this as needed ...
}
Vectem(Vectem &&src) : head(src.head), last(src.last), lenght(src.lenght)
{
src.head = nullptr;
src.last = nullptr;
src.lenght = 0;
}
~Vectem()
{
// cleanup *this as needed ...
}
Vectem& operator=(const Vectem &rhs)
{
if (&rhs != this) {
// clear *this, and copy rhs's data to *this, as needed ...
}
return *this;
}
Vectem& operator=(Vectem &&rhs)
{
// clear *this as needed...
head = rhs.head; rhs.head = nullptr;
last = rhs.last; rhs.last = nullptr;
lenght = rhs.lenght; rhs.lenght = 0;
return *this;
}
...
};
That being said, insert() is also buggy, as it is dereferencing last before checking that last is actually pointing at a valid node. Try something more like this instead:
void insert(T value) {
node<T> *n = new node<T>{value, NULL};
if (!head) head = n;
if (last) last->next = n;
last = n;
++lenght;
}
Alternatively:
void insert(T value) {
node<T> **p = (last) ? &(last->next) : &head;
*p = new node<T>{value, NULL};
last = *p;
++lenght;
}
I wrote a tree structure and made a basic search function to look for nodes within the tree. The tree itself uses a sentinel node to mark all ends (parent of the root, child of the leaves), and search simply iterates through nodes until it either finds a match or hits the sentinel node. The search function works fine when I call it on an instance of a tree, however it gets stuck when the tree is a data member of another class. In the following code, "t.search(1)" works, but "embedded_tree.t.search(1)" gets stuck in an infinite loop.
I have narrowed it down to the fact that when the call to embedded_tree.t.search() is made, the content of "&sentinel" correctly points to the sentinel node, but seems to be a new pointer, as it is not equivalent to the contents of root, sentinel.parent, and sentinel.child. From here I am stuck and am not sure how to call it so that &sentinel matches the pointers that were created when the tree was constructed.
#include <iostream>
struct NODE {
int key;
NODE* parent;
NODE* child;
NODE() : key(0), parent(NULL), child(NULL) {};
};
struct TREE {
NODE sentinel;
NODE* root;
TREE()
{
sentinel = *new NODE;
sentinel.parent = &sentinel;
sentinel.child = &sentinel;
root = &sentinel;
}
NODE* search(int k)
{
NODE* x = root;
while (x != &sentinel)
{
if (x->key == k) return x;
x = x->child;
}
return &sentinel;
}
};
struct A {
TREE t;
A() : t(*new TREE()) {};
};
int main()
{
TREE t;
t.search(1);
A embedded_tree;
embedded_tree.t.search(1);
}
You're confusing dynamic memory allocation with stack allocation. When you do
sentinel = *new NODE
bad things happen. Memory gets allocated for NODE sentinel on the stack, then for NODE in new operator, then assignment gets done to sentinel variable, and memory created in new operator is lost. You should rewrite your code to use pointers instead, and add destructors, something like this
#include <iostream>
struct NODE {
int key;
NODE* parent;
NODE* child;
NODE() : key(0), parent(NULL), child(NULL) {};
};
struct TREE {
NODE* sentinel;
NODE* root;
TREE()
{
sentinel = new NODE;
sentinel->parent = sentinel;
sentinel->child = sentinel;
root = sentinel;
}
~TREE() {
if (NULL != sentinel) {
delete sentinel;
sentinel = NULL;
root = NULL;
}
}
NODE* search(int k)
{
NODE* x = root;
while (x != sentinel)
{
if (x->key == k) return x;
x = x->child;
}
return sentinel;
}
};
struct A {
TREE* t;
A() : t(new TREE()) {};
~A() {
if (NULL != t) {
delete t;
t = NULL;
}
}
};
int main()
{
TREE t;
t.search(1);
A embedded_tree;
embedded_tree.t->search(1);
}
However, since we're talking about C++, I'd suggest you to look to smart pointers and containers after you get familiar with manual memory management.
I am trying to write a exception safe generic stack. This is what I have done so far.
#include <iostream>
#include <memory>
#include <exception>
class stk_exception:public exception
{
virtual const char* what() const throw()
{
return "stack underflow";
}
} stk_ex;
template <class T>
struct node
{
T data;
node<T> *next;
};
template <class T>
class stack_generic
{
public:
stack_generic() : _head(nullptr) {
}
void push(T x) {
node<T> *temp(new node<T>());
temp->data = x;
temp->next = _head;
_head = temp;
}
void pop() {
if (_head == nullptr) {
throw stk_ex;
} else {
node<T> *temp = _head;
_head = _head->next;
delete temp;
return;
}
}
T top() {
T x = T();
if (_head == nullptr) {
throw stk_ex;
} else {
return _head->data;
}
}
private:
node<T> *_head;
};
int main()
{
stack_generic<int> s;
s.push(1);
s.push(2);
std::cout << s.top();
s.pop();
std::cout << s.top();
s.pop();
}
I could have used STL list/vector for RAII, but I want to work with raw pointers. So, when I wrap the head pointer in stack with unique_ptr, it throws a compilation error "no matching function for call unique_ptr, default_delete. What's wrong here? Can anyone suggest what should I do to make this class exception safe? Thanks!
EDIT:
Added exception handling for underflow.
defined seperate top and pop methods
The following implementation should be (almost) exception-safe:
void push(T x) {
head = new node<T>{std::move(x), head};
}
T pop(void) {
if (head) {
T result{std::move(head->data)};
auto old = head;
head = head->next;
delete old;
return result;
} else {
cout << "underflow!";
return T{};
}
}
The only problem of this code is the return result. In general, this operation might throw an exception, and in this case, the caller sees an exception, but the stack was nevertheless changed.
You can avoid this problem by separating the function into two functions. The first function returns the top element, and the second function removes it.
Best practice is to use the std::shared_ptr. You could implement the class like this:
#include <iostream>
#include <memory>
#include <exception>
template <class T>
class node
{
public:
node(T data, std::shared_ptr<node<T>> next)
: _data(data), _next(next)
{
}
T data() const
{
return _data;
}
std::shared_ptr<node<T>> next() const
{
return _next;
}
private:
T _data;
std::shared_ptr<node<T>> _next;
};
template <class T>
class stack_generic
{
public:
stack_generic()
: _head(nullptr)
{
}
void push(T x)
{
_head = std::make_shared<node<T>>(x, _head);
}
T pop()
{
if (_head == nullptr) {
throw std::underflow_error("underflow");
} else {
std::shared_ptr<node<T>> temp = _head;
_head = _head->next();
return temp->data();
}
}
private:
std::shared_ptr<node<T>> _head;
};
int main()
{
stack_generic<int> s;
s.push(1);
s.push(2);
std::cout << s.pop();
std::cout << s.pop();
}
Note the following things:
Using of using namespace std; is bad practice.
Use nullptr instead of NULL for modern C++ programs.
Use an exception for the underflow to create a defined behaviour.
Use accessor methods on the node to create a read-only object.
Use a constructor for the node.
Using for example std::shared_ptr to automatically free data.
I'm a complete noob with dynamically allocated memory. Will this have a memory leak or any other memory problem?
#include <iostream.h>
template <class T> class stack
{
struct node
{
T value;
node* next;
};
public:
stack()
{
size = 0;
}
~stack()
{
while(size > 0)
{
node *n = top->next;
delete top;
top = n;
size--;
}
}
void push(T value)
{
node *n = new node;
n->value = value;
if(size == 0)
{
top = n;
}
else
{
n->next = top;
top = n;
}
size++;
}
T pop()
{
if(size<1)
{
std::cerr<<"Stack underflow"<<endl;
exit(0);
}
else
{
node* n = top;
int val = n->value;
top = n->next;
delete n;
size--;
return val;
}
}
int getSize()
{
return size;
}
private:
int size;
node *top;
};
I don't see any memory management errors -- but I do see several other kinds of errors. For example, what happens when T is something other than int? :)
Also, implementing a stack as a linked list is wasteful and will perform relatively poorly when compared to a deque or vector implementation like that used by std::stack.
In addition to the other excellent answers, one more note:
if(size<1)
{
std::cerr<<"Stack underflow"<<endl;
exit(0);
}
I would suggest thinking about either an assert or an exception here. exit is a bit rash, but if you decide to exit, do not exit with 0: that typically indicates success, which is the last thing you want in an error.
You missed the copy constructor/assignment operator of Stack.
When you create objects of Stack::Node you do not always initialization the next member. Write constructor destructor for stack node and everything else becomes simple.
#include <iostream.h>
template <class T> class stack
{
/*
* The stack object contains a RAW pointer (top)
* So when the object is copied with either copy constructor or
* assignment operator when need to handle that fact. The simplist way
* to handle is to make sure it can not happen. To do this make them
* private (You do not need to define them as they can't be used).
*/
Stack(Stack const&); // Not defined
Stack operator=)(Stack const&); // Not defined
struct Node
{
// Initialize Node
Node(Node* n, T v)
:next(v)
,value(v)
{}
~Node() // Destroy whole chain.
{ delete next;
}
// Data
T value;
Node* next;
};
public:
stack()
:size(0)
,top(NULL)
{}
~stack()
{
/// destructor is now simple
delete top;
}
void push(T value)
{
/// As is the push.
top = new node(top, value);
++size;
}
T pop()
{
/// The pop is just the same.
if(size<1)
{
std::cerr<<"Stack underflow"<<endl;
exit(0);
}
else
{
node* n = top;
T val = n->value;
top = n->next;
n->next = NULL; // Set to NULL to stop the delete chaining.
delete n;
size--;
return val;
}
}
// Make this method a constant.
// As it does not change the object.
int getSize() const
{
return size;
}
private:
int size;
node *top;
};
a few other tips:
instead of simulating the stack internally just use a normal list where you have a pointer to the first and last element of the list, there is no need to mimic a stack internally as long as you provide the push/pop functionality.
i would also skip the 'size' member altogether, instead just count the nodes in the list. this way you don't need to keep the size counter and the list synchronized. Just make sure you initialize the pointers to NULL. calculating size would then look something like:
for(Node* p=first; p!=NULL; p=p->next) ++size;
EDIT -- Answered below, missed the angled braces. Thanks all.
I have been attempting to write a rudimentary singly linked list, which I can use in other programs. I wish it to be able to work with built-in and user defined types, meaning it must be templated.
Due to this my node must also be templated, as I do not know the information it is going to store. I have written a node class as follows -
template <class T> class Node
{
T data; //the object information
Node* next; //pointer to the next node element
public:
//Methods omitted for brevity
};
My linked list class is implemented in a seperate class, and needs to instantiate a node when adding new nodes to the end of the list. I have implemented this as follows -
#include <iostream>
#include "Node.h"
using namespace std;
template <class T> class CustomLinkedList
{
Node<T> *head, *tail;
public:
CustomLinkedList()
{
head = NULL;
tail = NULL;
}
~CustomLinkedList()
{
}
//Method adds info to the end of the list
void add(T info)
{
if(head == NULL) //if our list is currently empty
{
head = new Node<T>; //Create new node of type T
head->setData(info);
tail = head;
}
else //if not empty add to the end and move the tail
{
Node* temp = new Node<T>;
temp->setData(info);
temp->setNextNull();
tail->setNext(temp);
tail = tail->getNext();
}
}
//print method omitted
};
I have set up a driver/test class as follows -
#include "CustomLinkedList.h"
using namespace std;
int main()
{
CustomLinkedList<int> firstList;
firstList.add(32);
firstList.printlist();
//Pause the program until input is received
int i;
cin >> i;
return 0;
}
I get an error upon compilation however - error C2955: 'Node' : use of class template requires template argument list - which points me to the following line of code in my add method -
Node* temp = new Node<T>;
I do not understand why this has no information about the type, since it was passed to linked list when created in my driver class. What should I be doing to pass the type information to Node?
Should I create a private node struct instead of a seperate class, and combine the methods of both classes in one file? I'm not certain this would overcome the problem, but I think it might. I would rather have seperate classes if possible though.
Thanks, Andrew.
While the answers have already been provided, I think I'll add my grain of salt.
When designing templates class, it is a good idea not to repeat the template arguments just about everywhere, just in case you wish to (one day) change a particular detail. In general, this is done by using typedefs.
template <class T>
class Node
{
public:
// bunch of types
typedef T value_type;
typedef T& reference_type;
typedef T const& const_reference_type;
typedef T* pointer_type;
typedef T const* const_pointer_type;
// From now on, T should never appear
private:
value_type m_value;
Node* m_next;
};
template <class T>
class List
{
// private, no need to expose implementation
typedef Node<T> node_type;
// From now on, T should never appear
typedef node_type* node_pointer;
public:
typedef typename node_type::value_type value_type;
typedef typename node_type::reference_type reference_type;
typedef typename node_type::const_reference_type const_reference_type;
// ...
void add(value_type info);
private:
node_pointer m_head, m_tail;
};
It is also better to define the methods outside of the class declaration, makes it is easier to read the interface.
template <class T>
void List<T>::add(value_type info)
{
if(head == NULL) //if our list is currently empty
{
head = new node_type;
head->setData(info);
tail = head;
}
else //if not empty add to the end and move the tail
{
Node* temp = new node_type;
temp->setData(info);
temp->setNextNull();
tail->setNext(temp);
tail = tail->getNext();
}
}
Now, a couple of remarks:
it would be more user friendly if List<T>::add was returning an iterator to the newly added objects, like insert methods do in the STL (and you could rename it insert too)
in the implementation of List<T>::add you assign memory to temp then perform a bunch of operations, if any throws, you have leaked memory
the setNextNull call should not be necessary: the constructor of Node should initialize all the data member to meaningfull values, included m_next
So here is a revised version:
template <class T>
Node<T>::Node(value_type info): m_value(info), m_next(NULL) {}
template <class T>
typename List<T>::iterator insert(value_type info)
{
if (m_head == NULL)
{
m_head = new node_type(info);
m_tail = m_head;
return iterator(m_tail);
}
else
{
m_tail.setNext(new node_type(info));
node_pointer temp = m_tail;
m_tail = temp.getNext();
return iterator(temp);
}
}
Note how the simple fact of using a proper constructor improves our exception safety: if ever anything throw during the constructor, new is required not to allocate any memory, thus nothing is leaked and we have not performed any operation yet. Our List<T>::insert method is now resilient.
Final question:
Usual insert methods of single linked lists insert at the beginning, because it's easier:
template <class T>
typename List<T>::iterator insert(value_type info)
{
m_head = new node_type(info, m_head); // if this throws, m_head is left unmodified
return iterator(m_head);
}
Are you sure you want to go with an insert at the end ? or did you do it this way because of the push_back method on traditional vectors and lists ?
Might wanna try
Node<T>* temp = new Node<T>;
Also, to get hints on how to design the list, you can of course look at std::list, although it can be a bit daunting at times.
You need:
Node<T> *temp = new Node<T>;
Might be worth a typedef NodeType = Node<T> in the CustomLinkedList class to prevent this problem from cropping up again.
That line should read
Node<T>* temp = new Node<T>;
Same for the next pointer in the Node class.
As said, the solution is
Node<T>* temp = new Node<T>;
... because Node itself is not a type, Node<T> is.
And you will need to specify the template parameter for the Node *temp in printlist also.
// file: main.cc
#include "linkedlist.h"
int main(int argc, char *argv[]) {
LinkedList<int> list;
for(int i = 1; i < 10; i++) list.add(i);
list.print();
}
// file: node.h
#ifndef _NODE_H
#define _NODE_H
template<typename T> class LinkedList;
template<typename T>class Node {
friend class LinkedList<T>;
public:
Node(T data = 0, Node<T> *next = 0)
: data(data), next(next)
{ /* vacio */ }
private:
T data;
Node<T> *next;
};
#endif//_NODE_H
// file: linkedlist.h
#ifndef _LINKEDLIST_H
#define _LINKEDLIST_H
#include <iostream>
using namespace std;
#include "node.h"
template<typename T> class LinkedList {
public:
LinkedList();
~LinkedList();
void add(T);
void print();
private:
Node<T> *head;
Node<T> *tail;
};
#endif//_LINKEDLIST_H
template<typename T>LinkedList<T>::LinkedList()
: head(0), tail(0)
{ /* empty */ }
template<typename T>LinkedList<T>::~LinkedList() {
if(head) {
Node<T> *p = head;
Node<T> *q = 0;
while(p) {
q = p;
p = p->next;
delete q;
}
cout << endl;
}
}
template<typename T>LinkedList<T>::void add(T info) {
if(head) {
tail->next = new Node<T>(info);
tail = tail->next;
} else {
head = tail = new Node<T>(info);
}
}
template<typename T>LinkedList<T>::void print() {
if(head) {
Node<T> *p = head;
while(p) {
cout << p->data << "-> ";
p = p->next;
}
cout << endl;
}
}
You Should add new node in this way
Node<T>* temp=new node<T>;
Hope you Solved :)
#include<iostream>
using namespace std;
template < class data > class node {
private :
data t;
node<data > *ptr;
public:
node() {
ptr = NULL;
}
data get_data() {
return t;
}
void set_data(data d) {
t = d;
}
void set_ptr(node<data > *p) {
ptr = p;
}
node * get_ptr() {
return ptr;
}
};
template <class data > node < data > * add_at_last(data d , node<data > *start) {
node< data > *temp , *p = start;
temp = new node<data>();
temp->set_data(d);
temp->set_ptr(NULL);
if(!start) {
start = temp;
return temp;
}
else {
while(p->get_ptr()) {
p = p->get_ptr();
}
p->set_ptr(temp);
}
}
template < class data > void display(node< data > *start) {
node< data > *temp;
temp = start;
while(temp != NULL) {
cout<<temp->get_data()<<" ";
temp = temp->get_ptr();
}
cout<<endl;
}
template <class data > node < data > * reverse_list(node<data > * start) {
node< data > *p = start , *q = NULL , *r = NULL;
while(p->get_ptr()) {
q = p;
p = p->get_ptr();
q->set_ptr(r);
r = q;
}
p->set_ptr(r);
return p;
}
int main() {
node < int > *start;
for(int i =0 ; i < 10 ; i ++) {
if(!i) {
start = add_at_last(i , start);
}
else {
add_at_last(i , start);
}
}
display(start);
start = reverse_list(start);
cout<<endl<<"reverse list is"<<endl<<endl;
display(start);
}