Double-Linked Lists

Download: tag.zip

Before STL we had to write our own versions of linked-lists. This is mine.

See:

tag.h
tag.cpp

A small test program is contained within the definition file (tag.cpp).

tag.h


/* tag.h
*
*   tags are used to maintain double-linked lists
*
*/
#if !defined(__TAG_H)
#define __TAG_H

class List;

class Node {
public:
	Node *next;
	Node *prev;
	Node(): next(0), prev(0) { }
	virtual ~Node() { }
	virtual void show() { }
	virtual long size() { return sizeof( Node); }
	friend List;
};

class List {
	Node *top;
	Node *bottom;
	int length;
public:
	List(): top(0), bottom(0), length(0) { }
	~List() { clear(); }

	Node *first() { return top; }
	Node *last()  { return bottom; }
	int count() const { return length; }

	void append(Node *np);
	void prepend(Node *np);
	void clear();
	int index(Node *np);
	void insert(Node *np, int n);
	void after(Node *np, Node *after);
	int extract(Node *np);
	void remove(Node *np);
	void show();
	long size();

	Node *operator [](int n);
};

#endif


tag.cpp


/*** tag.cpp  $Revision:   1.1  $  $Date:   23 Jan 1991 21:10:20  $
*
*  Maintain double-linked lists
*
***/
#include "stdio.h"
#include <string>
#include "tag.h"
using namespace std;

#if defined(TAG_TEST)

class Label: public Node {
public:
	string item;
	Label(char *name) { item = name; }
	~Label() { printf("Deleting node: %s\n",item.c_str()); }
	void show();
};

List labels;

#define MAXC 128
char text[MAXC];
void print(const char *text);
void show_list(List &lp);

void main()
{
	int i,ntag=0;
	Node *np;

	for (i=0; i<6; i++) {
		sprintf_s(text,MAXC-1,"tag %d",++ntag);
		np = new Label(text);
		labels.append(np);
	}
	show_list(labels);

	np = labels[5];
	printf("testing index function (offset 5): %d\n",labels.index(np));
	if (np) {
		print("\nnode at position 5 is ");
		np->show();
		print("\n\n");
	}

	ntag = 3;
	printf("\n Remove node %d\n\n",ntag);
	labels.remove(labels[ntag-1]);
	show_list(labels);
}

void print(const char *text)
{
	fputs(text,stdout);
}

void Label::show()
{
	sprintf_s(text,MAXC-1,"%8x %8x %8x  ",this,next,prev);
	print(text);
	print(item.c_str());
	print("\n");
}

void show_list(List &lp)
{
	sprintf_s(text,MAXC-1,"\n%8s %8s %8s %8s\n","list","first","last","length");
	print(text);
	sprintf_s(text,MAXC-1,"%8x %8x %8x ",&lp,lp.first(),lp.last());
	print(text);
	sprintf_s(text,MAXC-1,"%8d\n\n",lp.count());
	print(text);
	sprintf_s(text,MAXC-1,"%8s %8s %8s\n","node","next","prev");
	print(text);
	lp.show();
	print("\n\n");
}

#endif

void List::show()
{
	Node *np;
	for (np=first(); np; np=np->next) np->show();
}

long List::size()
{
	Node *np;
	long sum = sizeof(List);
	for (np=first(); np; np=np->next) sum += np->size();
	return sum;
}

/* remove
*
*  Cut specified node from list and return it
*  to the list of available nodes.
*
*/
void List::remove(Node *np)
{
	if (extract(np)) delete np;
}

/*
*
*  Clear all nodes from list
*
*/

void List::clear()
{
	while (length) remove(top);
}


/* append
*
*  Add node to bottom of list
*
*/
void List::append(Node *np)
{
	Node *c;
	if (!np) return;
	c = bottom;
	np->next = 0;
	np->prev = c;
	bottom = np;
	if (c) c->next = np;
	else top = np;
	length++;
}

/* prepend
*
*  Add node to top of list
*
*/
void List::prepend(Node *np)
{
	Node *c;
	if (!np) return;
	c = top;
	np->prev = 0;
	np->next = c;
	top = np;
	if (c) c->prev = np;
	else bottom = np;
	length++;
}

//  Extract specified node from list

int List::extract(Node *np)
{
	Node *next, *prev;
	int n = index(np);
	if (!n) return 0;
	next = np->next;
	prev = np->prev;
	if (prev) prev->next = next;
	else top = next;
	if (next) next->prev = prev;
	else bottom = prev;
	np->next = np->prev = 0;
	length--;
	return 1;
}

// returns position if node is in list and 0 otherwise.

int List::index(Node *np)
{
	Node *tp;
	int position;
	position = 0;
	for (tp=top; tp; tp=tp->next) {
		position++;
		if (tp==np) return position;
	}
	return 0;
}
	

//  returns node from specified offset (index-1) in list

Node *List::operator [](int n)
{
	int i;
	Node *np;
	if (n<0) return 0;
	np = top;
	for (i=0; i<n; i++) {
		if (np) np = np->next;
		else break;
	}
	return np;
}


//   add node after specified position in list

void List::insert(Node *np, int n)
{
	Node *cur, *pre;
	if (!np) return;
	cur = (*this)[n];
	if (cur) {
		pre = cur->prev;
		if (pre) {
			np->prev = cur->prev;
			np->next = cur;
			pre->next = np;
			cur->prev = np;
			length++;
		}
		else prepend(np);
	}
	else append(np);
}

// add node after specified node (which should be in the list)

void List::after(Node *np, Node *aft)
{
	Node *post;
	if (!aft) prepend(np);
	else if (index(aft) > 0) {
		post = aft->next;
		aft->next = np;
		np->prev = aft;
		np->next = post;
		post->prev = np;
		length++;
	}
}


Results


    list    first     last   length
  411100   323f18   322dc0        6

    node     next     prev
  323f18   323f48        0  tag 1
  323f48   323f78   323f18  tag 2
  323f78   323fa8   323f48  tag 3
  323fa8   323fd8   323f78  tag 4
  323fd8   322dc0   323fa8  tag 5
  322dc0        0   323fd8  tag 6


testing index function (offset 5): 6

node at position 5 is   322dc0        0   323fd8  tag 6



 Remove node 3

Deleting node: tag 3

    list    first     last   length
  411100   323f18   322dc0        5

    node     next     prev
  323f18   323f48        0  tag 1
  323f48   323fa8   323f18  tag 2
  323fa8   323fd8   323f48  tag 4
  323fd8   322dc0   323fa8  tag 5
  322dc0        0   323fd8  tag 6


Deleting node: tag 1
Deleting node: tag 2
Deleting node: tag 4
Deleting node: tag 5
Deleting node: tag 6


Maintained by John Loomis, updated Tue Feb 13 00:30:28 2007