C++模板类实现带有游标的单向循环链表

本文详细介绍了一种基于C++的单向循环链表实现,包括链表的基本操作如插入、删除、查找等,以及游标功能的实现,通过具体代码示例展示了如何构建和操作循环链表。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 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;
}

 

请使用模板参数设计实现单向链表模板类LinkList,应能根据需求构建相应类型数据结点的单向链表结构,main(void)完成对其的测试。 设计要求: (1)设计实现结点模板类Node,结点的数据域应能各种类型数据;其中成员函数getData(void)的作用是获取结点的数据域。构造函数输出信息“Node Constructor run”,拷贝构造函数输出信息“Node CopyConstructor run”,析构函数输出信息“Node Destructor run” (2)在结点模板类Node的支持下设计实现结点单向链表模板类LinkList,其中: ①LinkList类的数据包括结点链表的头结点headNode和游标position(游标用于表示当前操作位置) ②有参构造函数实现由数组构建链表的功能,构造函数输出信息“LinkList Constructor run”;拷贝构造函数输出信息“LinkList CopyConstructor run”,析构函数输出信息“LinkList Destructor run” ③设计实现成员函数insertNode(n),其功能为在游标位置后插入一个同类型结点n。 ④设计实现成员函数searchNode(value),其功能为在链表中查找数据域等于value的结点,若查找成功的同时修改游标位置。 ⑤设计实现成员函数getSize(),其功能为返回链表中的元素个数。 ⑥设计实现成员函数next(),其功能为使游标移动到下一个结点。 ⑦设计实现成员函数currNode()const,其功能为返回当前结点。 ⑧设计实现成员函数delNode(),其功能为移除当前结点。 ⑨设计实现成员函数show(),其功能为输出链表。 提示: 1 g++下定义模板类时,成员函数名不要带模板参数; 2 delete只能删除new产生的结点 裁判测试程序样例: #include <iostream> using namespace std; /*请在这里填写答案*/ int main() { int i,a[5]= {0,1,2,3,4}; for(i=0;i<5;i++) scanf("%d",&a[i]); LinkList<int> l1(a,5),l2(l1); cout<<l2.getSize()<<endl; l1.show(); if (l2.searchNode(2)) cout<<"Found:"<<l2.currNode().getData()<<endl; else cout<<"Not Found"<<endl; l2.delNode(); Node <int> *p1=new Node<int>(11); l2.insertNode(*p1); l2.show(); return 0; } 输入样例: 1 2 3 4 5 输出样例: Node Constructor run Node Constructor run Node Constructor run Node Constructor run Node Constructor run Node Constructor run LinkList Constructor run Node Constructor run Node Constructor run Node Constructor run Node Constructor run Node Constructor run Node Constructor run LinkList CopyConstructor run 5 [1][2][3][4][5] Found:2 Node Constructor run [1][11][3][4][5] Node Destructor run Node Destructor run Node Destructor run Node Destructor run Node Destructor run LinkList Destructor run Node Destructor run Node Destructor run Node Destructor run Node Destructor run Node Destructor run Node Destructor run LinkList Destructor run Node Destructor run
最新发布
05-11
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值