Circular Doubly Linked List 双向循环链表 C++ 例子

What a circular doubly linked list looks like?


Look at Figure1, It is a circular doubly linked list have 8 nodes. If you compare it and the array in Figure2, you will find that each node in doubly linked list points to the next node and pre node in the list. Because of the way that linked lists are structured, you can easily add or remove nodes at the beginning or the end of a list, or even in the middle of the list. Below is a list class with simple property. We will add "Insert", "Delete" and other function later.

template  class List;

template 
class Node{
	friend List;
private:
	T data;
	Node* pre,* next;
};

template 
class List{
private:
	Node* first;
}


How to insert a node

There are four cases when you insert a node into the linked list. (1) insert the node at the beginning of the list,  (2) insert the node at the middle of the list, (3) insert the node at the end of the list, (4) out of range

(1). The new node will become the new first node in the list.

(3). The new node will become the new tail node in the list.

(4). Throw a exception

We will talk detail about the second case using three figures below.



template
void List::Insert(const int& position, const T& v){
	if(position < 0 || position > Size()){
		throw OutOfBounds();
	}
	Node* newNode = new Node;
	newNode->data = v;

	if(position == 0){// at the beginning of the list
		if(!first){ //the list is empty
			first = newNode;
			first->next = first->pre = first;
		}else{ //the new node became the first node
			newNode->next = first;
			first->pre = newNode;

			newNode->pre = first->pre;
			first->pre->pre->next = newNode;
			first = newNode;
		}
	}else{ //at the middle or end of the list
		Node* nodeBeforePostion = first;
		//find the node before insert position
		for(int i = 1; i < position && nodeBeforePostion; ++i){
			nodeBeforePostion = nodeBeforePostion->next;
		}
		newNode->next = nodeBeforePostion->next;
		newNode->next->pre = newNode;
		newNode->pre = nodeBeforePostion;
		nodeBeforePostion->next = newNode;		
	}
	++size;
}




How to delete a node


There three cases when you delete a node in the list. (1) Delete the first node, (2) Delete a node at the middle position of the list, (3) out of range

(1). The first node's next node become the new first node.

(3). Throw a exception.

Figure 6,7 and 8 show a graphical representation of how the case 2 acts.




template
void List::Delete(const int& position, T& out){
	if(position < 0 || position > Size() || !first){
		throw OutOfBounds();
	}

	if(position == 0){// at the beginning of the list
		out = first->data;
		Node* tmp = first->next;
		if(tmp == first){ //only one node,just delete it
			delete first;
			first = 0;
		}else{ // set first node's next node to be the new first node,delete the old first node
			first->pre->next = first->next;
			first->next->pre = first->pre;
			delete first;
			first = tmp;
		}
	}else{//at the middle or end of the list
		Node* nodeDelete = first;
		//find the node which need to delete
		for(int i = 0; i< position && nodeDelete->next != first; ++i){
			nodeDelete = nodeDelete->next;
		}
		nodeDelete->pre->next = nodeDelete->next;
		nodeDelete->next->pre = nodeDelete->pre;
		out = nodeDelete->data;
		delete nodeDelete;

	}
	--size;
}



Circular Double Linked List Customized Class

#ifndef _List_
#define _List_

#include 

using namespace std;

//exception
class OutOfBounds{
public:
	OutOfBounds(){}
};

template  class List;

template 
class Node{
	friend List;
private:
	T data;
	Node* pre,* next;
};


template 
class List{
	//overwrite operator <<
	template friend ostream& operator<<(ostream& ,List&);
private:
	Node* first;
    int size;

	bool firstTime;//used for print list element.
	Node* current;
	
public:

	List(){first = 0; size = 0;}
	~List();
	void Delete(const int& position, T& out);
	void Delete(const int& position);
	void Insert(const int& position, const T& x);
	void Push_Back(const T& v);
	int Size()const;
	T Front()const;
	T Back()const;
	void Begin();
	void MoveNext();
	bool Valid();
	T GetItemData() const;
	void Clear();

};

template
ostream& operator<< (ostream& out,List& list){
	out << "The list's size: " << list.Size() << endl;
	out << "The list's front: ";
	try{
		out << list.Front() << endl;
	}catch(OutOfBounds ){
		out << "No element in the list" << endl;
	}
	out << "The list's back: ";
	try{
		out << list.Back() << endl;
	}catch(OutOfBounds ){
		out << "No element in the list" << endl;
	}
	out << "Elements in the list:" << endl;
	for(list.Begin(); list.Valid(); list.MoveNext()){
		out << list.GetItemData() << ' ';
	}
	out << endl;
	return out;
}

template
List::~List(){
	Clear();
}

template
void List::Delete(const int& position){
	T value;
	Delete(position, value);
}

template
void List::Delete(const int& position, T& out){
	if(position < 0 || position > Size() || !first){
		throw OutOfBounds();
	}

	if(position == 0){// at the beginning of the list
		out = first->data;
		Node* tmp = first->next;
		if(tmp == first){ //only one node,just delete it
			delete first;
			first = 0;
		}else{ // set first node's next node to be the new first node,delete the old first node
			first->pre->next = first->next;
			first->next->pre = first->pre;
			delete first;
			first = tmp;
		}
	}else{//at the middle or end of the list
		Node* nodeDelete = first;
		//find the node which need to delete
		for(int i = 0; i< position && nodeDelete->next != first; ++i){
			nodeDelete = nodeDelete->next;
		}
		nodeDelete->pre->next = nodeDelete->next;
		nodeDelete->next->pre = nodeDelete->pre;
		out = nodeDelete->data;
		delete nodeDelete;

	}
	--size;
}

template
void List::Insert(const int& position, const T& v){
	if(position < 0 || position > Size()){
		throw OutOfBounds();
	}
	Node* newNode = new Node;
	newNode->data = v;

	if(position == 0){// at the beginning of the list
		if(!first){ //the list is empty
			first = newNode;
			first->next = first->pre = first;
		}else{ //the new node became the first node
			newNode->next = first;
			first->pre = newNode;

			newNode->pre = first->pre;
			first->pre->pre->next = newNode;
			first = newNode;
		}
	}else{ //at the middle or end of the list
		Node* nodeBeforePostion = first;
		//find the node before insert position
		for(int i = 1; i < position && nodeBeforePostion; ++i){
			nodeBeforePostion = nodeBeforePostion->next;
		}
		newNode->next = nodeBeforePostion->next;
		newNode->next->pre = newNode;
		newNode->pre = nodeBeforePostion;
		nodeBeforePostion->next = newNode;		
	}
	++size;
}

template
void List::Push_Back(const T& v){
	Node* newNode = new Node;
	newNode->data = v;
	if(!first){ // the list is empty
		first = newNode;
		first->next = first->pre = first;
	}else{
		Node* lastNode = first->pre;
		first->pre = newNode;
		newNode->next = first;
		lastNode->next = newNode;
		newNode->pre = lastNode;
	}
	++size;
}

template
int List::Size() const{
	return size;
}

template
T List::Front() const{
	if(!first){
		throw OutOfBounds();
	}else{
		return first->data;
	}
}

template
T List::Back() const{
	if(!first){
		throw OutOfBounds();
	}else{
		return first->pre->data;
	}
}

template
void List::Begin(){
	current = first;
	firstTime = true;
}

template
void List::MoveNext(){
	current = current->next;
}

template
bool List::Valid(){
	if(!first || (current == first && !firstTime)){
		return false;
	}else{
		firstTime = false;
		return true;
	}
} 

template
T List::GetItemData()const{
	return current->data;
}

template
void List::Clear(){
	while(Size() != 0){
		Delete(0);
	}
	size = 0;
}

#endif


Test the class


// CustomizedList.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "List.h"
#include 

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{

	List list;
	int deleteValue;
	cout << "after initialize list" << endl;
	cout << list;

	cout << "try to delete with no element" << endl;
	try{
		list.Delete(0);
	}catch(OutOfBounds){
		cout << "delete error" << endl;
	}

	cout << "after call list.Insert(1,1)" << endl;
	try{
		list.Insert(1,1);
	}catch(OutOfBounds){
		cout << "insert error" << endl;
	}
	cout << list;

	cout << "after call list.Insert(0,1)" << endl;
	try{
		list.Insert(0,1);
	}catch(OutOfBounds){
		cout << "insert error" << endl;
	}
	cout << list;

	cout << "try to delete out range" << endl;
	try{
		list.Delete(2);
	}catch(OutOfBounds){
		cout << "delete error" << endl;
	}
	cout << list;

	cout << "after call list.Push_Back(2) " << endl;
	list.Push_Back(2);
	cout << list;

	cout << "delete position 0" << endl;
	try{
		list.Delete(0, deleteValue);
	}catch(OutOfBounds){
		cout << "delete error" << endl;
	}
	cout << "delete value:" << deleteValue << endl;
	cout << list;

	for(int i =0;i< 10; ++i){
		list.Push_Back(i);
	}
	cout << list;

	cout << "after call list.Clear()" << endl;
	list.Clear();
	cout << list;

	int i;
	cin >> i;
	return 0;
}



http://www.waitingfy.com/?p=487

你可能感兴趣的:(数据结构,&,算法)