Valhalla Legends Archive

Programming => General Programming => C/C++ Programming => Topic started by: Telos on November 22, 2003, 07:08 PM

Title: Doubly Linked List - Request for comments
Post by: Telos on November 22, 2003, 07:08 PM
I wrote this doubly linked list to learn more about data structures.  I think the bugs have been worked out but this may not be the case.  If anyone has comments for how it could be made better I want to know.


// Node.h
#ifndef _NODE_H_
#define _NODE_H_

#include <iostream.h>

class Node
{
public:
   Node();
   Node( Node *PointedNode );
   virtual ~Node();

   void   DisplayContents( void ) { cout << Contents << endl; }

   Node   *Next;
   Node   *Prev;

// Better to inherit this class than put the data directly in like this.
   char   Contents[256];
};

#endif



// LinkedList.h
#ifndef _LINKEDLIST_H_
#define _LINKEDLIST_H_

#include "Node.h"

class LinkedList
{
public:
   LinkedList();
   ~LinkedList();

   Node         *First;
   Node         *Last;

   void          InsertAtFront( Node *NewNode );
   void          InsertAtBack( Node *NewNode );
   void          InsertInOrder( Node *NewNode, bool CaseSensitive );
   void          RemoveFromFront( void );
   void          RemoveFromBack( void );
   void          RemoveByIndex( unsigned int Index );
   Node         *GetNodeByIndex( unsigned int Index );
   unsigned int    GetNodeCount( ) { return NodeCount; }

private:
   unsigned int   NodeCount;
};

#endif



// Node.cpp
#include "Node.h"

Node::Node()
{
   Next = false;
   Prev = false;
}

Node::Node( Node *PointedNode )
{
   Next = PointedNode;
   Prev = PointedNode;
}

Node::~Node()
{

}



// LinkedList.cpp
#include <string.h>

#include "LinkedList.h"

LinkedList::LinkedList()
{
   First = new Node;
   Last = new Node( First );

   First->Next = Last;
   Last->Prev = First;

   // Unneeded but useful during debugging
   strcpy(First->Contents, "[First]");
   strcpy(Last->Contents, "[Last]");

   NodeCount = 0;
}

LinkedList::~LinkedList()
{

}

void LinkedList::InsertAtBack( Node *NewNode )
{
   NewNode->Prev = Last->Prev;
   NewNode->Next = Last;
   Last->Prev->Next = NewNode;
   Last->Prev = NewNode;

   NodeCount++;
}

void LinkedList::InsertAtFront( Node *NewNode )
{
   NewNode->Prev = First;
   NewNode->Next = First->Next;
   First->Next->Prev = NewNode;
   First->Next = NewNode;

   NodeCount++;
}

void LinkedList::InsertInOrder( Node *NewNode, bool CaseSensitive )
{
   int i;
   int strResult;
   int strResult2;
   Node *TempNode;

   if( GetNodeCount() == 0 )
   {
      InsertAtFront( NewNode );
      return;
   }

   for( i = 1; i <= GetNodeCount(); i++ )
   {
      TempNode = GetNodeByIndex( i );
      if( CaseSensitive )
      {
         strResult = strcmp( NewNode->Contents, TempNode->Contents );
         strResult2 = strcmp( NewNode->Contents, TempNode->Next->Contents );
      } else {
         strResult = _stricmp( NewNode->Contents, TempNode->Contents );
         strResult2 = _stricmp( NewNode->Contents, TempNode->Next->Contents );
      }

      if( (strResult < 0) && (TempNode->Prev == First) )
      {
         InsertAtFront( NewNode );
         return;
      }

      if( (strResult > 0) && (strResult2 < 0) )
      {
         NewNode->Prev = TempNode;
         NewNode->Next = TempNode->Next;
         TempNode->Next = NewNode;
         TempNode->Next->Prev = NewNode;

         NodeCount++;
      }

      if( (strResult > 0) && (TempNode->Next == Last) )
      {
         InsertAtBack( NewNode );
         return;
      }
   }
}

void LinkedList::RemoveFromBack()
{
   if( NodeCount < 1 ) return;

   Node *TempNode = Last->Prev;

   TempNode->Prev->Next = Last;
   Last->Prev = TempNode->Prev;

   delete TempNode;
   NodeCount--;
}

void LinkedList::RemoveFromFront()
{
   if( NodeCount < 1 ) return;

   Node *TempNode = First->Next;

   TempNode->Next->Prev = First;
   First->Next = TempNode->Next;

   delete TempNode;
   NodeCount--;
}

void LinkedList::RemoveByIndex( unsigned int Index )
{
   if( NodeCount < 1 ) return;

   unsigned int i;
   Node *TempNode;

   TempNode = this->First;
   for( i = 0; i < Index; i++ )
   {
      TempNode = TempNode->Next;
   }

   TempNode->Prev->Next = TempNode->Next;
   TempNode->Next->Prev = TempNode->Prev;

   delete TempNode;
   NodeCount--;
}

Node *LinkedList::GetNodeByIndex( unsigned int Index )
{
   unsigned int i;
   Node *ReturnedNode;

   ReturnedNode = this->First;
   for( i = 0; i < Index; i++ )
   {
      ReturnedNode = ReturnedNode->Next;
   }

   return ReturnedNode;
}



// LinkedListTest.cpp
#include "Node.h"
#include "LinkedList.h"

#include <string.h>
#include <stdlib.h>

int main()
{
   LinkedList    MyList;
   Node      *MyNode;

   int          Count;

   MyNode = new Node;
   strcpy(MyNode->Contents, "a");

   //MyList.InsertAtBack( MyNode );
   MyList.InsertInOrder( MyNode, true );

   MyNode = new Node;
   strcpy(MyNode->Contents, "b");

   //MyList.InsertAtFront( MyNode );
   MyList.InsertInOrder( MyNode, true );

   MyNode = new Node;
   strcpy(MyNode->Contents, "c");

   //MyList.InsertAtBack( MyNode );
   MyList.InsertInOrder( MyNode, true );

   MyNode = new Node;
   strcpy(MyNode->Contents, "FIRST");

   //MyList.InsertAtFront( MyNode );
   MyList.InsertInOrder( MyNode, true );

   cout << MyList.GetNodeCount() << endl;
   for( Count = 1; Count <= MyList.GetNodeCount(); Count++ )
   {
      MyNode = MyList.GetNodeByIndex( Count );
      cout << Count << ": ";
      MyNode->DisplayContents();
   }

   MyList.RemoveFromBack();
   cout << MyList.GetNodeCount() << endl;
   for( Count = 1; Count <= MyList.GetNodeCount(); Count++ )
   {
      MyNode = MyList.GetNodeByIndex( Count );
      cout << Count << ": ";
      MyNode->DisplayContents();
   }

   MyList.RemoveFromFront();
   cout << MyList.GetNodeCount() << endl;
   for( Count = 1; Count <= MyList.GetNodeCount(); Count++ )
   {
      MyNode = MyList.GetNodeByIndex( Count );
      cout << Count << ": ";
      MyNode->DisplayContents();
   }
   system("PAUSE");

   return 0;
}
Title: Re:Doubly Linked List - Request for comments
Post by: iago on November 22, 2003, 08:18 PM
It looks really nice!

I'm glad you used iterative stuff rather than recursive, that's the biggest mistake I normally see.

From there, it's a short change to write a binary tree.  You should do that :)
Title: Re:Doubly Linked List - Request for comments
Post by: Skywing on November 22, 2003, 08:20 PM
In my experience it's generally more useful to use templates instead of virtual functions for datastructures like this.
Title: Re:Doubly Linked List - Request for comments
Post by: Telos on November 22, 2003, 08:29 PM
Quote from: Skywing on November 22, 2003, 08:20 PM
In my experience it's generally more useful to use templates instead of virtual functions for datastructures like this.

Could you possibly explain what you mean?  I am not sure what use templates would be in this case.
Title: Re:Doubly Linked List - Request for comments
Post by: iago on November 22, 2003, 08:43 PM
I don't know how to create a templated class, but it would be like this:
Say you wanted to store an int in your list

DoubleList <int> blah;
blah.add(5);
..etc.

It'll assume that all data being added is an int.  It's nice, but doesn't port well to other languages (like Java) and is rather nasty to implement (this badly needs to be fixed).
Title: Re:Doubly Linked List - Request for comments
Post by: Telos on November 22, 2003, 08:46 PM
From what I know about templates it would look like


template <class T>
class LinkedList
{
 ...
 T *First;
 T *Last;
 ...
};

// then

LinkedList <Node> LL;
LinkedList <SomeDataStructure> LL;



...  Ok I see where templates would be good now you don't need to answer Skywing.
Title: Re:Doubly Linked List - Request for comments
Post by: iago on November 22, 2003, 08:48 PM
I was goign to say you got your code tags backwards, but you fixed that :P


Yes, using a template would be much nicer :)
Title: Re:Doubly Linked List - Request for comments
Post by: CupHead on November 25, 2003, 09:20 AM
Someone want to turn this into a nice DLL I can use from VB?   :P
Title: Re:Doubly Linked List - Request for comments
Post by: Kp on November 25, 2003, 09:39 AM
Quote from: Telos on November 22, 2003, 08:46 PM
From what I know about templates it would look like


template <class T>
class LinkedList
{
 ...
 T *First;
 T *Last;
 ...
};

// then

LinkedList <Node> LL;
LinkedList <SomeDataStructure> LL;



...  Ok I see where templates would be good now you don't need to answer Skywing.

Actually, I think he meant for you to use type T for the contained data, not for the nodes.  Then you'd be able to do LinkedList<MyBot> to create a list of MyBot objects, or LinkedList<int> to get a LL of ints.
Title: Re:Doubly Linked List - Request for comments
Post by: Telos on November 25, 2003, 10:47 AM
Like


template <class T>
class LinkedList
{
 ...
 Node<T> *First;
 Node<T> *Last;
 ...
};

// with

template <class T>
class Node
{
 Node *Prev;
 Node *Next;
 T Contents;
};

// and

struct contentStruct
{
 char szData[256];
};

// then

LinkedList<contentStruct> MyList;
?
Title: Re:Doubly Linked List - Request for comments
Post by: Kp on November 25, 2003, 11:30 AM
Quote from: Telos on November 25, 2003, 10:47 AM
Like
?

Exactly.
Title: Re:Doubly Linked List - Request for comments
Post by: Telos on November 25, 2003, 12:20 PM
With a templated node like that what is the best way to go about doing the InsertInOrder function because there will not be any standard comparison?
Title: Re:Doubly Linked List - Request for comments
Post by: iago on November 25, 2003, 01:35 PM
hmm, I don't think there is one.  That's a good reason NOT to do it templated, I guess :)

Perhaps don't sort?
Title: Re:Doubly Linked List - Request for comments
Post by: Eibro on November 25, 2003, 01:35 PM
Quote from: Telos on November 25, 2003, 12:20 PM
With a templated node like that what is the best way to go about doing the InsertInOrder function because there will not be any standard comparison?
Why not? The user should define these operators for type T.
Title: Re:Doubly Linked List - Request for comments
Post by: Telos on November 25, 2003, 02:11 PM
Eibro - The list takes care of what position nodes are inserted so the user would have to derive from the linked list class in order to overload the order function.  If the user does not do this then they will have to either maintain a seperate list with its own order function before inserting or modify the linked list class version of InsertInOrder.
Title: Re:Doubly Linked List - Request for comments
Post by: Eibro on November 25, 2003, 04:41 PM
No they wouldn't. Take std::list for example.
You'll need to remove case sensitivity, since this only makes sense for strings alike. Use operators < > == in the InsertInOrder function. The user will need to overload these operators for their type in order to use the InsertInOrder function.

Or you could go the route of std::sort and accept a function or functor for the purposes of comparison.
Title: Re:Doubly Linked List - Request for comments
Post by: iago on November 25, 2003, 06:25 PM
What if they just want to put in int's, or some other type?

In Java, you could just use the interface Comparable, but this isn't Java.  

I still think the best way is either to not sort it or to use an abstract class for data.
Title: Re:Doubly Linked List - Request for comments
Post by: Adron on November 28, 2003, 09:36 AM
Inserting items in order into a linked list is a bad idea anyway; a list is no good for sorting. A skiplist or a tree would work better.

If you absolutely want to sort the list anyway, do like Eibro suggests. I see no problem at all with just sorting based on the regular operators, < > =, applied to the items. Those operators exist for the built-in types, and if you want to make a sorted list of some class all you have to do is define the comparison operators for that class.