数据结构与算法笔记(四) 循环链表和双向链表

可以将线性表描述成一个单项循环链表,使链表的应用代码更加简洁和高效循环链表的结构如下图所示。

1,无头节点的循环链表:
 

数据结构与算法笔记(四) 循环链表和双向链表_第1张图片

2.有头节点的循环链表:

数据结构与算法笔记(四) 循环链表和双向链表_第2张图片

 

3.空列表:

数据结构与算法笔记(四) 循环链表和双向链表_第3张图片

 

将单向链表的头节点和尾节点连接起来,就成为了循环链表;

有头节点的循环链表和没有头节点的循环链表:

头节点是链表的一个附加节点,有了这个节点,空表就不用作为特殊情况来先处理了,使程序简化,有了头节点,每个链表至少包含一个节点。

使用头节点的循环链表可以使程序更加简洁,效率更高:

循环链表的实现如下:

#ifndef CIRCULAR_LIST_H 
#define CIRCULAR_LIST_H
#include 

#include "E:\back_up\code\c_plus_code\digui\external_file\linearlist.h"   // ABC文件
// #include "E:\back_up\code\c_plus_code\digui\external_file\chain.h"
/*
template
struct chainNode    // 链表的节点定义 
{
	// 数据成员 
	T element;
	chainNode* next;
	
	// 定义结构体构造方法 
	chainNode() {};
	chainNode(T theElement)
	{
		this->element = theElement;
	} 
	chainNode(T theElement, chainNode* next)
	{
		this->element = theElement;
		this->next = next;
	}
}
*/

template
class circularList : public linearList   // 有头的循环链表
{
	private:
	chainNode* headerNode;
	int listSize;
	
	public:
	circularList(int capacity=10);   // 构造函数 
	circularList(const circularList& c_list);  // 拷贝构造函数
	~circularList();     // 析构函数
	
	//抽象数据类型ADT
	bool empty() const;
	int size() const;
	T& get(int index) const;
	int indexOf(T x) const;
	
	void erase(int index);
	void clear(); 
	void insert(int index, T x);
	void output() const; 
}; 


template
circularList::circularList(int capacity)
{
	if(capacity<1)
	{
		cout << "List size invalid ";
		return;    // 函数结束 
	}
	headerNode = new chainNode();  // 用到了chainNode的无参构造函数
	headerNode->next = headerNode; 
	listSize = 0;
} 

template
circularList::circularList(const circularList& c_list)    // 拷贝构造函数 
{
	listSize = c_list.listSize;
	if(listSize == 0)    // 源链表为空       
	{
		headerNode = new chainNode();
		headerNode->next = headerNode;
		return;
	}
	
	chainNode* sourceNode = c_list.headerNode;
	sourceNode = sourceNode->next;   // 指向源循环链表的第一个元素
	
	headerNode = new chainNode();
	chainNode* targetNode = headerNode;
	targetNode->next = new chainNode(sourceNode->element);   // target 

	while(sourceNode != c_list.headerNode)
	{
		sourceNode = sourceNode->next;
		targetNode->next = new chainNode(sourceNode->element);
		targetNode = targetNode->next;
	}
	targetNode->next = headerNode;	
}


/*
析构函数没有写对,会遇到程序运行完后即使输出
结果正确,但是会陷入死循环,而且不会出现press 
any key to continue 
*/
template   // 测试完璧 
circularList::~circularList()     // 析构函数 
{
	chainNode* sourceNode = headerNode->next;   // sourceNode指向链表的第一个元素 
	//sourceNode = sourceNode->next; 
    while(sourceNode->next!=headerNode)
    {
    	headerNode->next = sourceNode->next;
    	delete sourceNode;
    	sourceNode = headerNode->next;      // sourceNode指向新的元素 
        //listSize--;
	}
    delete headerNode;     // 删除头节点 
    listSize = 0;
    
}


template     // 测试完毕 
bool circularList::empty() const
{
	return listSize==0;
} 

template   // 测试完毕 
int circularList::size() const
{
	return listSize;
}

template   // 测试完毕 
T& circularList::get(int index) const
{
	/*  
	if(index>listSize-1)     // 这里抛出异常最好 
	{
		cout << "The index is invalid" << endl;
		return;
	}
	*/
	chainNode* sourceNode = headerNode;   // 指向链表第一个元素
	for(int i=0; i<=index; i++)
	{
		sourceNode = sourceNode->next;
	}
	return sourceNode->element;	
}

template    // 测试完毕 
int circularList::indexOf(T x) const    // 查找对应元素的下表 
{
	chainNode* sourceNode = headerNode->next;    // 指向链表第一个元素
	int cnt = 0;
	// bool found_flag = false;    // 标志位 
	while(sourceNode!=headerNode)
	{
		if(sourceNode->element == x)
		{ 
			return cnt;
		}
		sourceNode = sourceNode->next;
		cnt++;
	}
	return -1;  
}


template   // 测试完毕 
void circularList::insert(int index, T x)
{
	/*
	if(index<0 || index>listSize)    // 这里可以写return,但是应该统一为抛出异常; 
	{
		return;
	}
	*/
	// 插入这里应该判断一些情况
	if(index == 0)   // 在链表首个位置插入元素
	{
		headerNode->next = new chainNode(x, headerNode); 	
	} 
	else if(index == listSize)   // 在链表末尾插入元素
	{
		chainNode* sourceNode = headerNode->next;
		while(sourceNode->next != headerNode)
		{
			sourceNode = sourceNode->next;
		}
		// 此时sourceNOde指向最后一个元素
		sourceNode->next = new chainNode(x, headerNode); 
		/*
		for(int i=0; inext;
		}
		// sourceNode
		sourceNode = new chainNode(x, headerNode);
		*/
	} 
	else
	{
		chainNode* sourceNode = headerNode;
		for(int i=0; inext;
		}
		// sourceNode指向第index-1个元素
		chainNode* temp = sourceNode->next;
		sourceNode->next = new chainNode(x, temp);    // 插入对应的元素 
	}
	
	listSize++;
	
}


template   // 测试完毕 
void circularList::erase(int index)
{
	/*
	if(index<0 || index>listSize)
	{
		cout << "The index is invalid" << endl;
		return 0;
	}
	*/
	if(index == 0)   // 删除链表的头节点
	{
		chainNode* currentNode = headerNode->next;
		headerNode->next = currentNode->next;
		delete currentNode;
	} 
	else if(index == listSize-1)    //  删除链表的尾节点
	{
		chainNode* currentNode = headerNode;
		for(int i=0; inext;
		}
		//delete currentNode->next;
		chainNode* deleteNode = currentNode->next;
		currentNode->next = headerNode;
		delete deleteNode;
	} 
	else
	{
		chainNode* sourceNode = headerNode;
		for(int i=0; inext;
		}
		// sourceNode指向链表的第index-1个元素
		chainNode* deleteNode = sourceNode->next;   // 指向需要删除的元素 
		sourceNode->next = deleteNode->next;   
		delete deleteNode; 
	}
	listSize--;
} 


template    // 测试完毕 
void circularList::clear()    // 修改 
{
	chainNode* sourceNode = headerNode->next;
	while(sourceNode!=headerNode)
	{
		headerNode->next = sourceNode->next;
		delete sourceNode;
		sourceNode = headerNode->next;
	} 
	listSize = 0;
	
} 

template   // 测试完毕 
void circularList::output() const
{
	chainNode* currentNode = headerNode;
	 
	/*
	int cnt = 0;
	while(currentNode!=headerNode)
	{
		cout << currentNode->element << " ";
		if((cnt+1)%10 == 0)
		{
			cout << endl;
		}
		currentNode = currentNode->next;
	}
	cout << endl;
	*/	
	for(int i=0; inext;
		cout << currentNode->element << " ";
		if((i+1)%10 == 0)
		{
			cout << endl;
		}
		
	}
	cout << endl;
}

#endif

 

上述循环链表中的放方法均以通过测试:

main.cpp

#include 
#include 
#include 
#include "E:\back_up\code\c_plus_code\digui\external_file\linearlist.h"
#include "E:\back_up\code\c_plus_code\digui\external_file\arraylist.h" 
#include "E:\back_up\code\c_plus_code\digui\external_file\chain.h"
#include "E:\back_up\code\c_plus_code\digui\external_file\circularlist.h"    // 循环链表 
using namespace std;

// 实现友元函数


int main(int argc, char *argv[])
{
	circularList c1(10);
	for(int i=0; i<10; i++)
	{
		c1.insert(i, i*2);
	}

	cout << "The list size is " << c1.size() << endl;
	c1.output();
	
	c1.insert(3, 4.4);
	c1.insert(5, 3.4);
	cout << "The list size is " << c1.size() << endl;
	c1.output();
	
	circularList c2;
	c2 = c1;
	cout << "The list size is " << c2.size() << endl;
	c2.output();
	
	c2.erase(0);
	c2.erase(5);
	cout << "The list size is " << c2.size() << endl;
	c2.output();
	
	/*
	c1.insert(3, 4.4);
	c1.insert(0, 1.1);
	cout << "The list size is " << c1.size() << endl;
	c1.output();
	
	c1.erase(0);
	c1.erase(5);
	cout << "The list size is " << c1.size() << endl;
	c1.output();
	
	
	circularList c2;
	c2 = c1;
	cout << "The list size is " << c2.size() << endl;
	c2.output();
	
    
	return 0;     
}


运行结果:

数据结构与算法笔记(四) 循环链表和双向链表_第4张图片

给循环链表添加方法:

1.在链表的末尾插入元素, push_back()

2.在链表的末尾删除元素:

template
void circularList::push_back(T x)
{
	chainNode* currentNode = headerNode->next;
	while(currentNode->next != headerNode)
	{
		currentNode = currentNode->next;
	}
	currentNode->next = new chainNode(x, headerNode);
	listSize++;
}

 
template
void circularList::pop_back()
{
	chainNode* currentNode = headerNode;
	for(int i=0; inext;
	}
	delete currentNode->next;
	currentNode->next = headerNode;
	listSize--;
}

 

------------------------------------------------------------分割线------------------------------------------------------------

双向链表:

如果每个元素节点既有一个指向后继的指针,又有一个指向前驱的指针,就会方便应用,这样的链表叫做双向链表,其中每个节点都有两个指针,next和previous 。定义一个双向链表,它有两个数据成员,firstNode和 lastNode,分别指向链表的首节点和尾节点。

例如,对于链表中元素的查找工作,当index

双项链表的实现:
双向链表的节点定义:

template
struct doubleChainNode    // 双向链表的节点定义  
{
	T element;   // 数据域
	doubleChainNode* previous;   // 指向前去的指针
	doubleChainNode* next;       // 指向后继的指针
	
	// 构造函数 
	doubleChainNode()   
	{
		
	} 
	doubleChainNode(T theElement)
	{
		this->element = theElement;
	}
	doubleChainNode(T theElement, doubleChainNode* thePrevious, doubleChainNode* theNext)
	{
		this->element = theElement;
		this->previous = thePrevious;
		this->next = theNext;
	} 
};

双向链表类的定义:
这里的双向链表doubleChain依然作为抽象类linearList(线性表)的派生类:

#ifndef DOUBLE_CHAIN_H
#define DOUBLE_CHAIN_H
#include 
#include 
#include "E:\back_up\code\c_plus_code\chain\external_file\linearlist.h"   // ABC文件
#include 


template
struct doubleChainNode    // 双向链表的节点定义  
{
	T element;   // 数据域
	doubleChainNode* previous;   // 指向前去的指针
	doubleChainNode* next;       // 指向后继的指针
	
	// 构造函数 
	doubleChainNode()   
	{
		
	} 
	doubleChainNode(T theElement)
	{
		this->element = theElement;
	}
	doubleChainNode(T theElement, doubleChainNode* thePrevious, doubleChainNode* theNext)
	{
		this->element = theElement;
		this->previous = thePrevious;
		this->next = theNext;
	} 
};


// 定义模板类
template
class doubleChain : public linearList
{
	private:
	doubleChainNode* firstNode;   // 指向链表的首节点 
	doubleChainNode* lastNode;    // 指向链表的尾节点 
	int listSize;
	
	public:
	doubleChain(int capacity=10);  
	doubleChain(const doubleChain& d_chain);
	~doubleChain();   // 析构函数
	
	// ADT abstract data type
    bool empty() const;
	int size() const;
	T& get(int index) const;
	int indexOf(T x) const;
	
	void erase(int index);
	void clear(); 
	void insert(int index, T x);
	
	void push_back(T x);    // 在末尾插入元素 
	void pop_back();        // 在末尾删除元素 
	
	void output() const; 
	
};


template
doubleChain::doubleChain(int capacity)
{
	if(capacity<1)
	{
		cout << "The capacity is invalid" << endl;
		return;
	}
	firstNode = NULL;
	lastNode = NULL;
	listSize = 0;
}

template
doubleChain::doubleChain(const doubleChain& d_chain)
{
	listSize = d_chain.listSize;
	if(listSize==0)     // 复制空链表 
	{
		firstNode = NULL;
		lastNode = NULL;
	}
	else     // 非空链表 
	{
		doubleChainNode* sourceNode = d_chain.firstNode;
		firstNode = new doubleChainNode(sourceNode->element, NULL, NULL);
		
		doubleChainNode* targetNode = firstNode; 
		while(sourceNode != NULL)
		{
			sourceNode = sourceNode->next;   // sourcexuNode向后移动 
			targetNode->next = new doubleChainNode(sourceNode->element, targetNode, NULL);
			targetNode = targetNode->next;
			lastNode = targetNode;
		}
		//lastNode = targetNode;   
	} 
} 

template
doubleChain::~doubleChain()    // 析构函数 
{
	doubleChainNode* currentNode = firstNode;
	while(currentNode != NULL)
	{
		firstNode = currentNode->next;
		delete currentNode;
		currentNode = firstNode;
	} 
	//delete currentNode;
	//listSize = 0;
}

template
bool doubleChain::empty() const
{
	return listSize==0;
}

template
int doubleChain::size() const
{
	return listSize;
}

template
T& doubleChain::get(int index) const
{
	// 判断index的合法性
	// 双向链表的索引 
	if(index* currentNode = firstNode;
		int cnt=0;
		while(currentNode != NULL)
		{
			if(cnt == index)
			{
				return currentNode->element;
			}
			currentNode = currentNode->next;
			cnt++; 
		}
	} 
	else                  // 从后向前找 
	{
		doubleChainNode* currentNode = lastNode;
		int cnt = 0;
		while(currentNode != NULL)
		{
			if(cnt == listSize-index-1)
			{
				return currentNode->element;
			}
			currentNode = currentNode->previous;
			cnt++;
		}
	} 	
}

template
int doubleChain::indexOf(T x) const
{
	doubleChainNode* currentNode = firstNode;
	int cnt = 0;
	while(currentNode != NULL)   // 从头找到尾,包含最后一个元素 
	{
		if(currentNode->element == x)
		{
			return cnt;
		}
		currentNode = currentNode->next;
		cnt++;
	}
	return -1; 
} 

template
void doubleChain::insert(int index, T x)
{
	if(index==0)   // 在链表的头部插入元素
	{
		if(listSize==0)
		{
			//doubleChainNode* tempNode = firstNode->next;
			firstNode = new doubleChainNode(x, NULL, NULL);  // 第一个节点 
			lastNode = firstNode; 
		}
		else
		{
			firstNode = new doubleChainNode(x, NULL, firstNode);
		}
	} 
	else if(index == listSize) // 最后一个位置 
	{
		//oubleChainNode* tempNode = lastNode->previous;
		//lastNode = new doubleChainNode(x, lastNode, NULL);
		lastNode->next = new doubleChainNode(x, lastNode, NULL);
		lastNode = lastNode->next;    
	}
	else
	{
		doubleChainNode* currentNode = firstNode;
		for(int i=0; inext;
		}
		// currentNode指向第index个节点
		doubleChainNode* former = currentNode->previous;
		former->next = new doubleChainNode(x, former, currentNode); 
	}
	listSize++;
}

template
void doubleChain::erase(int index)     // 测试通过 
{
	// 检查index的合法性
	if(index == 0)   // 删除首个元素 
	{
		doubleChainNode* currentNode = firstNode;
		firstNode = firstNode->next;
		firstNode->previous = NULL;
		delete currentNode; 
	} 
	else if(index==listSize-1)
	{
		doubleChainNode* currentNode = lastNode;
		lastNode = lastNode->previous;
		lastNode->next = NULL;
		delete currentNode;
	}
	else
	{
		if(index<=listSize/2)     // 从左至右查找 
		{
			doubleChainNode* currentNode = firstNode;
			// int cnt=0;
		    for(int i=0; inext;
	    	}
	    	// currentNode指向第index个节点
			doubleChainNode* former = currentNode->previous;
			doubleChainNode* latter = currentNode->next;
			former->next = latter;
			latter->previous = former;
			delete currentNode; 
		} 
		else
		{
			doubleChainNode* currentNode = lastNode;
			// int cnt=0;
		    for(int i=0; iprevious;
	    	}
			// currentNode指向第index个节点
			doubleChainNode* former = currentNode->previous;
			doubleChainNode* latter = currentNode->next;
			former->next = latter;
			latter->previous = former;
			delete currentNode;  
		}
	}
	listSize--;
} 


template
void doubleChain::clear()   // 清除链表所有元素 
{
	doubleChainNode* currentNode = firstNode;
	while(currentNode != NULL)
	{
		firstNode = currentNode->next;
		delete currentNode;
		currentNode = firstNode;
	}
	listSize = 0;
	firstNode = NULL;
	lastNode = NULL;
}

template
void doubleChain::push_back(T x)   // 链表的右端插入一个元素 
{
	if(listSize==0)   // 空链表 
	{
		firstNode = new doubleChainNode(x, NULL, NULL);
		lastNode = firstNode;
		listSize++;
	}
	else       // 非空链表 
	{
		lastNode->next = new doubleChainNode(x, lastNode, NULL);
		lastNode = lastNode->next;
		listSize++;
	}
} 

template
void doubleChain::pop_back()    // 删除链表最右端的元素 
{
	if(listSize==1)    // 链表中仅有一个元素   
	{
		delete firstNode;
		firstNode = NULL;
		lastNode = NULL;
		listSize = 0;
	} 
	else               // 大于一个元素 
	{
	    doubleChainNode* currentNode = lastNode;
		lastNode = lastNode->previous;
		lastNode->next = NULL;
		delete currentNode;
		listSize--;
	}
}

template
void doubleChain::output() const   // 输出函数 
{
	doubleChainNode* currentNode = firstNode;
	for(int i=0; ielement << "  ";
		if((i+1)%10==0)
		{
			//cout << endl;
		}
		currentNode = currentNode->next;
	}
	cout << endl;
}

#endif


双向链表的测试:

#include 
#include 
#include 
#include "E:\back_up\code\c_plus_code\chain\external_file\linearlist.h"
#include "E:\back_up\code\c_plus_code\chain\external_file\arraylist.h" 
#include "E:\back_up\code\c_plus_code\chain\external_file\chain.h"
#include "E:\back_up\code\c_plus_code\chain\external_file\circularlist.h"    // 循环链表 
#include "E:\back_up\code\c_plus_code\chain\external_file\doublechain.h"     // 双向链表 

using namespace std;

// 实现友元函数


int main(int argc, char *argv[])
{
	doubleChain d_chain1;
	// 测试insert函数:
	cout << "--------------Insert test----------" << endl;
	 for(int i=0; i<10; i++)
	{
		d_chain1.insert(i, i+1);
	} 
	d_chain1.output();
	
	d_chain1.insert(2, 1.1); 
	d_chain1.output(); 
	d_chain1.insert(7, 2.7);
	d_chain1.output(); 
	cout << "----------------------------------" << endl;
	
	cout << "--------------erase test----------" << endl;
	cout << "The list size is " << d_chain1.size() << endl; 
	d_chain1.erase(4);
	d_chain1.output();
	cout << "-----------------------------------" << endl;
	
	cout << "---------------index test----------------" << endl;
	double find_m = 3;
	cout << "The index of " << find_m << " is " << d_chain1.indexOf(find_m) << endl;
	double find_n = 8;
	cout << "The index of " << find_n << " is " << d_chain1.indexOf(find_n) << endl;
	
	int index_test = 3;
	cout << "The index " << index_test << " is " << d_chain1.get(index_test) << endl;
	
	index_test = 5;
	cout << "The index " << index_test << " is " << d_chain1.get(index_test) << endl;
	
	
	cout << "-------------push_pop_back---------------------" << endl;
	d_chain1.push_back(5.20);
	d_chain1.output();
	d_chain1.pop_back();
	d_chain1.output();
	
	
	cout << "-----------------------------------" << endl;
	cout << "Clearing the list....." << endl;
	d_chain1.clear();
	cout << "The list is empty? " << d_chain1.empty() << endl;
	cout << "------Push_back and pop_back an element----------" << endl;
	d_chain1.push_back(5.20);
	d_chain1.output();
	d_chain1.pop_back();
	d_chain1.output();
    
	return 0;     
}


测试结果:

数据结构与算法笔记(四) 循环链表和双向链表_第5张图片

拷贝构造函数的测试:

#include 
#include 
#include 
#include "E:\back_up\code\c_plus_code\chain\external_file\linearlist.h"
#include "E:\back_up\code\c_plus_code\chain\external_file\arraylist.h" 
#include "E:\back_up\code\c_plus_code\chain\external_file\chain.h"
#include "E:\back_up\code\c_plus_code\chain\external_file\circularlist.h"    // 循环链表 
#include "E:\back_up\code\c_plus_code\chain\external_file\doublechain.h"     // 双向链表 

using namespace std;

// 实现友元函数


int main(int argc, char *argv[])
{
	doubleChain d_chain1;
	// 测试insert函数:
	cout << "--------------Insert test----------" << endl;
	 for(int i=0; i<10; i++)
	{
		d_chain1.insert(i, i+1);
	} 
	d_chain1.output();
		
	
	cout << "---------------Copy constructor test---------------"<< endl; 
	doubleChain d_chain2;
	d_chain2 = d_chain1;
	d_chain2.output();
	
	cout << "--------------Insert test----------" << endl;
	d_chain2.insert(2, 1.1); 
	d_chain2.output(); 
	d_chain2.insert(7, 2.7);
	d_chain2.output(); 
	cout << "----------------------------------" << endl;
	
	
	cout << "--------------erase test----------" << endl;
	cout << "The list size is " << d_chain2.size() << endl; 
	d_chain2.erase(4);
	d_chain2.output();
	cout << "-----------------------------------" << endl;
	
	
	cout << "---------------index test----------------" << endl;
    double find_m = 3;
	cout << "The index of " << find_m << " is " << d_chain2.indexOf(find_m) << endl;
    double find_n = 8;
	cout << "The index of " << find_n << " is " << d_chain2.indexOf(find_n) << endl;
	
	int index_test = 3;
	cout << "The index " << index_test << " is " << d_chain2.get(index_test) << endl;
	
	index_test = 8;
	cout << "The index " << index_test << " is " << d_chain2.get(index_test) << endl;
	
	
	cout << "-------------push_pop_back---------------------" << endl;
	d_chain2.push_back(5.20);
	d_chain2.output();
	d_chain2.pop_back();
	d_chain2.output();
	
	cout << "Clearing the list...." << endl;
	d_chain2.clear();
	cout << "The list is empty? " << d_chain2.empty() << endl;
		
    
	return 0;     
}


测试结果:
数据结构与算法笔记(四) 循环链表和双向链表_第6张图片

----------------------------------------------------------end------------------------------------------------------------------

你可能感兴趣的:(data,structure,and,algorithm)