Below, we edit up to add a tail and len data member ... also an erase method ...
and we will also, firstly, separate out into its own file, (with guards), the code for a SLL ...
Note, we have NOT added iterators yet, so we are keeping all with public access ...
thus the nested Node class/struct has public access to enable free access to nodes in the SLL ...
// insertSortedEraseSLL.h // // 2017-02-11 //
// Note: still need to code copy ctor... and overloaded operator =
// But these are not needed in the short 'test code' used here. //
#ifndef _insertSortedEraseSLL_H_
#define _insertSortedEraseSLL_H_
template< typename T >
struct List
{
struct Node
{
T val;
Node* next;
Node( const T& val = T(), Node* next = 0 ) : val(val), next(next) {}
} ;
Node* head;
Node* tail;
size_t len;
List() : head(0), tail(0), len(0) {}
~List() { clear(); }
void clear()
{
while( head )
{
Node* del = head;
head = head->next;
delete del;
}
tail = 0;
len = 0;
}
void push_front( const T& val )
{
head = new Node( val, head );
++len;
}
void push_back( const T& val )
{
Node* nNode = new Node( val );
if( len )
{
tail->next = nNode; // B->N
tail = nNode;
}
else tail = head = nNode;
++len;
}
// insert sorted by <= def'n of objects ...
void insert_sorted( const T& val )
{
Node* nNode = new Node( val ); // recall next set to 0 //
// case 1 : NOT inserted as the head node
if( head != 0 && head->val <= val )
{
// find Node to insert after
Node* prev = head;
Node* cur = head->next;
while( cur != 0 && cur->val <= val )
{
prev = cur;
cur = cur->next;
}
// ok found spot ... insert after 'prev'
prev->next = nNode;
//if( cur ) // NOT at end
nNode->next = cur; // link next to 'next' //
if( !cur ) tail = nNode;
}
else // case 2 : insert at head ...
{
nNode->next = head;
head = nNode; // update head //
if( !len ) tail = head;
}
++ len;
}
// used by method insert_sort() that follows ...
void insert_sorted( Node* nNode )
{
// case 1 : NOT inserted as the head node
if( head != 0 && head->val <= nNode->val )
{
// find Node to insert after
Node* prev = head;
Node* cur = head->next;
while( cur != 0 && cur->val <= nNode->val )
{
prev = cur;
cur = cur->next;
}
// ok found spot ... insert after 'prev'
prev->next = nNode;
// if( cur ) // NOT at end
nNode->next = cur; // link next to 'next' //
if( !cur ) tail = nNode;
}
else // case 2 : insert at head ...
{
nNode->next = head;
head = nNode; // update head //
if( !len ) tail = head;
}
++ len;
}
// calls above method insert_sorted( Node* nNode ) //
void insert_sort()
{
if( len > 1 ) // then head and cur != 0 //
{
Node* cur = head; // get copy //
Node* next = cur->next; // get copy //
head = tail = 0;
len = 0;
for( ; ; )
{
insert_sorted( cur );
cur = next; // UPDATE from COPY //
if( !cur ) break;
next = cur->next;
}
}
}
bool erase( Node* ptr )
{
Node* prev = 0;
Node* cur = head;
for( ; cur && cur != ptr; cur = cur->next )
{
prev = cur;
}
// check end conditions //
if( cur ) // found //
{
if( prev )
prev->next = cur->next;
else
head = head->next;
if( cur == tail ) tail = prev;
delete cur;
-- len;
return true;
}
// NOT found //
return false;
}
size_t size() const { return len; }
} ;
#endif
And now a short test program for the above ...
// insertSortedEraseSLL.cpp // // 2017-02-13 //
#include <iostream>
#include <string>
// Note: still need to code copy ctor... and overloaded operator =
// But these are not needed in the short 'test code' used here. //
#include "insertSortedEraseSLL.h"
template< typename T >
void print( const List< T >& lst, std::ostream& os = std::cout )
{
typename List< T >::Node* cur;
cur = lst.head;
while( cur )
{
os << cur->val << ' ';
cur = cur->next;
}
os << "size() = " << lst.size();
}
typedef List< std::string >::Node* MyNode;
MyNode find( List< std::string >& lst, const std::string& val )
{
MyNode cur = lst.head;
while( cur )
{
if( cur->val == val ) return cur;
cur = cur->next;
}
return 0; // NOT found
}
int main()
{
using namespace std;
List< string > my_lst;
cout << "Now testing push_front: ";
my_lst.push_front( "Billy" );
my_lst.push_front( "Sam" );
my_lst.push_front( "Joe" );
my_lst.push_front( "Anne" );
my_lst.push_front( "Jill" );
print( my_lst );
my_lst.insert_sort();
cout << "\nAfter calling my_lst.insert_sort(): ";
print( my_lst );
my_lst.clear();
cout << "\n\nNow testing push_back: ";
my_lst.push_back( "Billy" );
my_lst.push_back( "Sam" );
my_lst.push_back( "Joe" );
my_lst.push_back( "Anne" );
my_lst.push_back( "Jill" );
print( my_lst );
my_lst.insert_sort();
cout << "\nAfter calling my_lst.insert_sort(): ";
print( my_lst );
my_lst.clear();
cout << "\n\nNow testing insert_sorted: ";
my_lst.insert_sorted( "Sam" );
my_lst.insert_sorted( "Joe" );
my_lst.insert_sorted( "Anne" );
my_lst.push_back( "Billy" );
my_lst.push_front( "Jill" );
my_lst.insert_sort();
print( my_lst );
cout << "\n\nFind Billy ... ";
MyNode cur = find( my_lst, "Billy" );
if( cur )
{
cout << "Found ... erasing Billy ...\n";
my_lst.erase( cur );
}
else cout << "NOT Found ... NOT erasing Billy ...\n";
print( my_lst );
cout << "\n\nFind Anne ... ";
cur = find( my_lst, "Anne" );
if( cur )
{
cout << "Found ... erasing Anne ...\n";
my_lst.erase( cur );
}
else cout << "NOT Found ... NOT erasing Anne ...\n";
print( my_lst );
cout << "\n\nFind Sam ... ";
cur = find( my_lst, "Sam" );
if( cur )
{
cout << "Found ... erasing Sam ...\n";
my_lst.erase( cur );
}
else cout << "NOT Found ... NOT erasing Sam ...\n";
print( my_lst );
cout << "\n\nFind Jill ... ";
cur = find( my_lst, "Jill" );
if( cur )
{
cout << "Found ... erasing Jill ...\n";
my_lst.erase( cur );
}
else cout << "NOT Found ... NOT erasing Jill ...\n";
print( my_lst );
cout << "\n\nFind Joe ... ";
cur = find( my_lst, "Joe" );
if( cur )
{
cout << "Found ... erasing Joe ...\n";
my_lst.erase( cur );
}
else cout << "NOT Found ... NOT erasing Joe ...\n";
print( my_lst );
cout << "\nPress 'Enter' to continue/exit ..." << flush;
cin.get();
}