1,循环链表基于单向链表而生,单向链表的首尾相连,组成一个环状单。循环链表比单向链表多了游标这个概念,游标可以快速的访问当前结点和下一个结点。
2,循环链表在插入第一个元素的时候,需要我们将第一元素的指针域指向其自身,也就构成了循环链表。
3,循环链表在删除链表节点的时候,要注意游标,否则游标容易断开。
4,修改循环链表时候,可以将头部,尾部,非头尾三部分分开考虑。
C++模板类实现带有游标得到单向循环链表代码如下(本次使用工具为vs2017,作者水平有限,如有bug还请指出):
1.模板类的头文件 Circle_List_Cplus.h
#pragma once
//定义链表结点
template<typename T>
struct ListNode
{
struct ListNode<T> *Next;
T data;
};
//定义循环链表模板类
template<typename T>
class Circle_List_Cplus
{
public:
//默认构造函数,生成一个循环链表
Circle_List_Cplus();
//从头部插入节点
int InsertNodeFront(T data);
//从尾部插入节点
int InsertNodeBack(T data);
//从链表的任意位置插入节点
int InsertNode(T data, int index);
//获取任意位置节点
T &GetListNode(int index);
//删除任意位置节点
int DeleteNode(int index);
//获取链表的长度
int GetListLen();
//游标复位,让游标重新指向0号元素的位置
void CursorReset();
//根据传来的节点数据删除节点
int Delete_From_Node(T data);
//获取游标指向的节点位置
T &GetCursorNode();
//返回当前游标的节点数据,并且在游标下移动
T &CursorNext();
//析构函数,释放开辟的资源
~Circle_List_Cplus();
public:
ListNode<T> Head; //循环链表头
ListNode<T> Cursor; //循环链表游标
int ListLen; //循环链表长度
};
2.模板类的实现文件 Circle_List_Cplus.cpp
#include "pch.h"
#include "Circle_List_Cplus.h"
#include "iostream"
using namespace std;
//默认构造函数,生成一个循环链表
template<typename T>
Circle_List_Cplus<T>::Circle_List_Cplus()
{
this->ListLen = 0;
this->Cursor.Next = NULL;
this->Head.Next = NULL;
}
//从头部插入节点
template<typename T>
int Circle_List_Cplus<T>::InsertNodeFront(T data)
{
int ret = 0;
//创建新结点
ListNode<T> *LNode = new ListNode<T>;
if (LNode == NULL)
{
cout << " New LNode Error :InsertNodeFront() \n" << endl;
ret = -1;
return ret;
}
if (this->ListLen == 0) //链表表里还没有数据
{
LNode->data = data; //对于复杂数据类型,要重载=操作符
this->Head.Next = LNode;
LNode->Next = LNode;
this->ListLen++;
}
else
{
LNode->data = data; //对于复杂数据类型,要重载=操作符
LNode->Next = this->Head.Next;
this->Head.Next = LNode;
this->ListLen++;
}
return ret;
}
//从尾部插入节点
template<typename T>
int Circle_List_Cplus<T>::InsertNodeBack(T data)
{
int ret = 0;
//创建新结点
ListNode<T> *LNode = new ListNode<T>;
if (LNode == NULL)
{
cout << " New LNode Error :InsertNodeFront() \n" << endl;
ret = -1;
return ret;
}
if (this->ListLen == 0) //链表表里还没有数据
{
LNode->data = data; //对于复杂数据类型,要重载=操作符
this->Head.Next = LNode;
LNode->Next = LNode;
this->ListLen++;
}
else
{
ListNode<T> *current = this->Head.Next; //current指向0号位置
for (int i = 0; i < this->ListLen - 1; i++) //移动到待插入位置的前面
{
current = current->Next;
}
LNode->data = data; //对于复杂数据类型,要重载=操作符
current->Next = LNode;
LNode->Next = this->Head.Next; //指向0号节点数据
this->ListLen++;
}
return ret;
}
//从链表的任意位置插入节点
template<typename T>
int Circle_List_Cplus<T>::InsertNode(T data, int index)
{
int ret = 0;
//防止越界
if (index < 0 || index > this->ListLen)
{
printf("Insert index error :InsertNode() \n");
ret = -1;
return ret;
}
//创建新结点
ListNode<T> *LNode = new ListNode<T>;
LNode->data = data; //对于复杂数据类型,要重载=操作符
ListNode<T> *current = this->Head.Next; //current指向0号位置
if (this->ListLen == 0) //链表表里还没有数据
{
this->Head.Next = LNode;
LNode->Next = LNode;
this->ListLen++;
}
else
{
if (index == 0) //头部插入元素
{
LNode->Next = this->Head.Next;
this->Head.Next = LNode;
this->ListLen++;
}
else if (index == this->ListLen) //在尾部插入元素
{
for (int i = 0; i < index - 1; i++) //移动到待插入位置的前面
{
current = current->Next;
}
current->Next = LNode;
LNode->Next = this->Head.Next;
this->ListLen++;
}
else
{
for (int i = 0; i < index - 1; i++) //移动到待插入位置的前面
{
current = current->Next;
}
//地址链接
LNode->Next = current->Next;
current->Next = LNode;
this->ListLen++;
}
}
return ret;
}
//获取任意位置节点
template<typename T>
T &Circle_List_Cplus<T>::GetListNode(int index)
{
if (index < 0 || index > this->ListLen - 1)
{
printf("List index error :GetListNode() \n");
}
ListNode<T> *current = this->Head.Next; //current指向0号位置
if (index == 0) //当查找的是第0号数据
{
return current->data;
}
else
{
for (int i = 0; i < index - 1; i++) //移动到待获取位置的前面
{
current = current->Next;
}
return current->Next->data;
}
}
//删除任意位置节点
template<typename T>
int Circle_List_Cplus<T>::DeleteNode(int index)
{
int ret = 0;
if (index < 0 || index > this->ListLen - 1)
{
printf("List index error :DeleteNode() \n");
ret = -1;
return ret;
}
if (this->ListLen == 0)
{
printf("List is not exist DeleteNode() \n");
ret = -1;
return ret;
}
ListNode<T> *current = this->Head.Next; //current指向0号位置
ListNode<T> *tempnode = NULL;
if (index == 0)
{ //删除了第一个位置的元素,此时要找到最后一个元素的位置
this->Head.Next = current->Next; //头节点指向1号节点
tempnode = current; //记录待删除元素的位置
this->Cursor.Next = current->Next; //游标指向1号节点
for (int i = 0; i < this->ListLen - 1; i++) //current刚好指向最后一个元素
{
current = current->Next;
}
current->Next = this->Head.Next;
this->ListLen--;
//释放内存
if (tempnode != NULL)
{
delete tempnode;
}
}
else if (index == this->ListLen - 1) //删除的是最后一个节点数据
{
for (int i = 0; i < index - 1; i++) //current刚好指向最后一个元素的前面一个
{
current = current->Next;
}
tempnode = current->Next; //缓存最后一个元素的地址,然后释放地址
current->Next = this->Head.Next;
this->Cursor.Next = this->Head.Next;
this->ListLen--;
//释放内存
if (tempnode != NULL)
{
delete tempnode;
}
}
else
{
ListNode<T> *tempnode = NULL;
for (int i = 0; i < index - 1; i++) //移动到待删除位置的前面
{
current = current->Next;
}
tempnode = current->Next; //tempnode指向待删除的位置
current->Next = tempnode->Next;
this->Cursor.Next = tempnode->Next;
this->ListLen--;
//释放内存
if (tempnode != NULL)
{
delete tempnode;
}
}
return ret;
}
//获取链表的长度
template<typename T>
int Circle_List_Cplus<T>::GetListLen()
{
return this->ListLen;
}
//游标复位,让游标重新指向0号元素的位置
template<typename T>
void Circle_List_Cplus<T>::CursorReset()
{
this->Cursor.Next = this->Head.Next;
}
//根据传来的节点数据删除节点
template<typename T>
int Circle_List_Cplus<T>::Delete_From_Node(T data)
{
int ret = 0;
int tag = 0;
int i = 0;
ListNode<T> *current = this->Head.Next; //current指向0号位置
for (i = 0; i < this->ListLen; i++) //循环玩之后在cuurrent在最后一个位置
{
if (current->data == data) //注意对于复杂数据类型,这里要重载==操作符
{
tag = 1;
break;
}
current = current->Next;
}
if (tag == 1)
{
DeleteNode(i); //删除元素
}
else
{
cout << "Not find data to delete" << endl;
ret = -1;
return ret;
}
return ret;
}
//获取游标指向的节点位置
template<typename T>
T& Circle_List_Cplus<T>::GetCursorNode()
{
//链表为空
if (this->Head.Next == 0)
{
cout << "List is empty" << endl;
}
return this->Cursor.Next->data;
}
//返回当前游标的节点数据,并且在游标下移动
template<typename T>
T& Circle_List_Cplus<T>::CursorNext()
{
//链表为空
if (this->Head.Next == 0)
{
cout << "List is empty" << endl;
}
ListNode<T> *temp = this->Cursor.Next; //获取当前的游标,在最后一个位置
this->Cursor.Next = temp->Next; //游标指向
return temp->data;
}
//释放资源
template<typename T>
Circle_List_Cplus<T>::~Circle_List_Cplus()
{
ListNode<T> *current = this->Head.Next; //current指向0号位置
ListNode<T> *temp = current->Next; //temp指向1号位置
for (int i=0; i<this->ListLen-1; i++)
{
if (current != NULL)
{
delete current;
}
current = temp;
temp = current->Next;
}
this->Cursor.Next = NULL;
this->ListLen = 0;
this->Head.Next = NULL;
}
3.循环链表的测试文件 _Circle_List_Cplus_Framecpp.cpp
#include "pch.h"
#include "Circle_List_Cplus.cpp"
#include "iostream"
#include "string"
using namespace std;
//自定义人类
class person
{
public:
person()
{
}
person(string name,int age)
{
this->name = name;
this->age = age;
}
person(const person &obj)
{
this->name = obj.name;
this->age = obj.age;
}
//重载=
person & operator=(person &obj)
{
this->name = obj.name;
this->age = obj.age;
return *this;
}
//重载==
bool operator==(person &obj)
{
if (this->name == obj.name && this->age == obj.age)
{
return true;
}
else
{
return false;
}
}
~person()
{
}
public:
int age;
string name;
};
//打印链表的信息
void printf_person(Circle_List_Cplus<person> &obj)
{
cout << "--------------开始打印数据---------------" << endl;
person data;
int tag = 0;
for (int i = 0; i < 2 * obj.ListLen; i++)
{
if (i == obj.ListLen)
{
printf("----第%d次打印数据---- \n", tag + 1);
i = 0;
tag++;
}
if (tag == 2)
{
break;
}
data = obj.GetListNode(i);
cout << data.name << " " << data.age << endl;
printf("\n");
}
cout << "--------------结束打印数据---------------" << endl;
}
//测试链表的增删改查,以及游标功能
void test2()
{
person p1("pxzz", 21), p2("wxxx", 22), p3("iut", 23), p4("dft", 24), p5("hji", 25), p6("kij", 26), p7("kio", 27);
Circle_List_Cplus<person> CLC;
person dd;
//测试插入节点
CLC.InsertNodeFront(p1);
CLC.InsertNodeFront(p2);
CLC.InsertNodeBack(p3);
CLC.InsertNodeBack(p4);
CLC.InsertNode(p5, 0);
CLC.InsertNode(p6, 5);
printf_person(CLC);
//测试删除节点
CLC.DeleteNode(5);
CLC.DeleteNode(0);
CLC.DeleteNode(1);
printf_person(CLC);
//测试游标移动和获取功能
CLC.CursorReset();
dd = CLC.GetCursorNode();
cout << dd.name << " "<< dd.age << endl;
dd = CLC.CursorNext();
cout << dd.name << " " << dd.age << endl;
dd = CLC.CursorNext();
cout << dd.name << " " << dd.age << endl;
dd = CLC.CursorNext();
cout << dd.name << " " << dd.age << endl;
dd = CLC.CursorNext();
cout << dd.name << " " << dd.age << endl;
dd = CLC.CursorNext();
cout << dd.name << " " << dd.age << endl;
dd = CLC.CursorNext();
cout << dd.name << " " << dd.age << endl;
dd = CLC.CursorNext();
cout << dd.name << " " << dd.age << endl;
dd = CLC.CursorNext();
cout << dd.name << " " << dd.age << endl;
printf_person(CLC);
//测试给定数据删除数据
CLC.Delete_From_Node(p2);
printf_person(CLC);
//测试游标移动和获取功能
CLC.CursorReset();
dd = CLC.CursorNext();
cout << dd.name << " " << dd.age << endl;
dd = CLC.CursorNext();
cout << dd.name << " " << dd.age << endl;
dd = CLC.CursorNext();
cout << dd.name << " " << dd.age << endl;
dd = CLC.CursorNext();
cout << dd.name << " " << dd.age << endl;
}
//主函数
int main()
{
test2();
system("pause");
return 0;
}