// @topic T03020 Lists
// @brief circularly linked list
// circularly_linked_list.cpp
#include <cassert>
#include <iostream>
using namespace std;
class Node
{
friend void print_list( Node const& head, int line );
private:
mutable Node* pnext;
public:
int data;
Node( int value = 0 )
: pnext( NULL ), data( value )
{
pnext = this;
}
Node( Node const& other )
: pnext( NULL ), data( other.data )
{
pnext = this;
other.insert( *this );
}
~Node()
{
remove( *this );
assert( is_single() );
}
Node& insert( Node& other ) const
{
assert( other.is_single() ); // check that other is not already on some list
assert( -1 == distance( other ) ); // check that other is not already on this list
other.pnext = pnext;
pnext = &other;
return other;
}
size_t size() const
{
int size = 1 + pnext->distance( *this );
assert( size > 0 );
return size;
}
int distance( Node const& other ) const
{
if ( &other == this && is_single() ) {
return 0;
} else if ( other.is_single() ) {
// distance cannot be measured
return -1;
}
int hops = 1;
Node const* previous = this;
Node const* iter = pnext;
while ( iter != &other ) {
previous = iter;
if ( previous == this ) {
return -1; // other not found on this list
}
iter = iter->pnext;
++hops;
}
return hops;
}
bool is_single() const
{
return ( pnext == this );
}
bool remove( Node& other )
{
if ( &other == this ) {
// Removing itself from the list:
if ( is_single() ) {
// ignore this call: the node is single
return false;
} else {
// ask your sibling to remove you from the list:
return pnext->remove( other );
}
}
if ( other.is_single() ) // distance cannot be measured
return false;
Node* previous = this;
Node* iter = pnext;
while ( iter != &other ) {
previous = iter;
if ( previous == this ) {
//cout << "Node " << &other << ':' << other.data << " not found\n";
assert( other.is_single() );
return false;
}
iter = iter->pnext;
}
previous->pnext = iter->pnext;
other.pnext = &other; // make node single after successful removal
return true;
}
};
void print_list( Node const& head, int line = 0 )
{
if ( line )
cout << line << '\t';
int list_size = head.size();
int invariant_size = 0;
cout << '[' << list_size << "] ";
Node const* iter = &head;
do {
cout << iter->data << ' ';
iter = iter->pnext;
++invariant_size;
} while ( iter != &head );
assert( invariant_size == list_size );
assert( invariant_size > 1 || head.is_single() );
cout << '\n';
}
int main( )
{
Node n12( 12 );
Node n99( 99 );
Node n37( 37 );
assert( n12.is_single() );
assert( n12.distance( n12 ) == 0 );
assert( n12.size() == 1 );
n12.insert( n99 );
assert( n12.distance( n12 ) == 2 );
assert( n12.size() == 2 );
print_list( n12, __LINE__ ); // 12 99
print_list( n99, __LINE__ ); // 99 12
n99.insert( n37 );
assert( n12.distance( n12 ) == 3 );
print_list( n12, __LINE__ ); // 12 99 37
print_list( n99, __LINE__ ); // 99 37 12
print_list( n37, __LINE__ ); // 37 12 99
Node single;
bool result = n12.remove( single );
assert( result == false );
n12.remove( n99 );
print_list( n12, __LINE__ ); // 12 37
n12.insert( n99 );
print_list( n12, __LINE__ ); // 12 99 37
n12.remove( n12 );
print_list( n99, __LINE__ ); // 99 37
n99.remove( n37 );
assert( n99.is_single() );
assert( n37.is_single() );
assert( n12.is_single() );
print_list( n99, __LINE__ ); // 99
n99.remove( n99 );
print_list( n99, __LINE__ ); // 99
n37.insert( n99 );
n99.insert( n12 );
print_list( n37, __LINE__ ); // 37 99 12
Node n55 = n12;
n55.data = 55;
print_list( n55, __LINE__ ); // 55 37 99 12
result = n99.remove( n99 );
assert( result );
print_list( n99, __LINE__ ); // 99
print_list( n55, __LINE__ ); // 55 37 12
return 0;
}