循环链表(circular linked list)是另外一种形式的链式存储结构。它的特点是:指向终指向 端节点的指针域由空指针改为 头结点,这样就使得 整个单链表形成一个环。 这样,从表中的任意一个结点出发均可找到表中的其他结点,如图b所示。
在有头结点的循环链表中,找到开始结点的时间是O(1),但是要想找到其终端结点,则需要从头结点开始遍历整个链表,其时间是O(n)。在实际问题中,我们的很多操作都是在表头或者表尾上进行的,此时只设置头结点的循环链表就不够方便,因此我们设置一个指向表尾结点的指针rear。
循环链表的操作和线性表基本一致,差别仅在于算法中的循环条件不是p或者p->next是否为空,而是它们是否等于头指针。
node.h
#ifndef NODE_H
#define NODE_H
#include <iostream>
template<class Type>
class CirLinklist;
template<class Type>
class Node{
private:
Type data; //数据域
Node<Type>* next; //指针域,存放下一个结点的存储地址
private:
friend class CirLinklist<Type>;
Node() :next(NULL){} //显示默认构造函数
Node(const Type x, Node<Type>* p = NULL) :data(x), next(p){} //自定义构造函数
~Node(){ next = NULL; } //析构函数
public:
Type getData(){ return data };
};
#endif
#ifndef CIRLINKLIST_H
#define CIRLINKLIST_H
#include "node.h"
template<class Type>
class CirLinklist{
private:
Node<Type>* first;
Node<Type>* rear;
public:
CirLinklist();
CirLinklist(Type a [], int len);
~CirLinklist();
public:
int getLength();
Type getData(int i);
int Locate(Type x);
void Insert(int i, Type x);
Type Delete(int i);
void PrintList();
};
#endif
cirlinklist.cpp
#include "cirlinklist.h"
#include <iostream>
using namespace std;
template<class Type>
CirLinklist<Type>::CirLinklist(){
first->next = first;
rear = first;
}
template<class Type>
CirLinklist<Type>::~CirLinklist(){
while (first != rear){
Node<Type>* p = first;
first = first->next;
delete p;
}
delete rear;
}
//尾插法构造
template<class Type>
CirLinklist<Type>::CirLinklist(Type a [], int len){
first = new Node<Type>;
rear = first;
Node<Type>* r = first;
for (int i = 0; i < len; i++){
Node<Type>* s = new Node<Type>;
s->data = a[i];
r->next = s;
r = s;
}
r->next = first;
rear = r;
rear->next = first;
}
template<class Type>
void CirLinklist<Type>::PrintList(){
cout << "头结点";
Node<Type>* p = first->next;
while (p != first){
cout << "-->" << p->data;
p = p->next;
}
cout << "-->头结点" << endl;
}
template<class Type>
int CirLinklist<Type>::getLength(){
Node<Type>* p = first;
int count = 0;
while (p->next != first){
count++;
p = p->next;
}
return count;
}
template<class Type>
Type CirLinklist<Type>::getData(int i){
if (i<1 || i>getLength())
return NULL;
Node<Type>* p = first->next;
int count = 1;
while (p != first&&count < i){
p = p->next;
count++;
}
if (p== first)
throw"位置";
else
return p->data;
}
template<class Type>
int CirLinklist<Type>::Locate(Type x){
Node<Type>* p = first->next;
int count = 1;
while (p->next != first){
if (p->data == x)
return count;
p = p->next;
count++;
}
return 0;
}
template<class Type>
void CirLinklist<Type>::Insert(int i, Type x){
Node<Type>* p = first;
int count = 0;
while (count<=getLength()&&count < i - 1){
p = p->next;
count++;
}
if (p == first)throw"位置";
else{
Node<Type>* s = new Node<Type>;
s->data = x;
s->next = p->next;
p->next = s;
}
}
template<class Type>
Type CirLinklist<Type>::Delete(int i){
Node<Type>* p = first;
int count = 0;
while (count <= getLength() && count < i - 1){
p = p->next;
count++;
}
if (p == first)throw"位置";
else{
Node<Type>* q = p->next;
Type x = q->data;
p->next = q->next;
delete q;
return x;
}
}
main.cpp
#include "cirlinklist.cpp"
int main(){
int a[5] = { 1, 2, 3, 4, 5 };
CirLinklist<int> cl(a, 5);
cl.PrintList();
cout << "该循环链表的长度:" << cl.getLength() << endl;
cout << "第2个结点的元素是:" << cl.getData(2) << endl;
cout << "4在第" << cl.Locate(4) << "个结点" << endl;
cl.Insert(6, 10);
cout << "在第6个结点前插入10:" << endl;
cl.PrintList();
cl.Delete(3);
cout << "删除第3个结点:"<<endl;
cl.PrintList();
return 0;
}
测试结果:
补充一点,实现两个循环链表的首尾相接:
//实现两个循环链表首尾相接
//有两个循环链表tail1和tail2,tail1和tail2分别指向循环链表的尾结点
u = tail1->next; v = tail2->next; //暂存两个循环链表的头结点的地址
tail1->next = v->next; tail2->next = u; //修改指针
tail1 = tail2; //合并后的循环链表有tail1指示