C++模板类实现带有游标的双向链表

链表只能从头结点开始访问链表中的数据元素,如果需要逆序访问单链表中的数据元素将极其低效。双链表是链表的一种,由节点组成,每个数据结点中都有两个指针,分别指向直接后继和直接前驱,带有游标的双向链表可以应用在某些特殊的场景。
详细讲解参照https://www.bilibili.com/video/av27904891/?p=1

本次使用工具为vs2017,作者水平有限,若有问题请指出。

链表模板类头文件:Twoway_List_Cplus.h

#pragma once
template<typename T>
struct ListNode
{
	struct ListNode<T> *Next;   //后继
	struct ListNode<T> *Pre;    //前驱
	T	data;
};

template<typename T>
class Twoway_List_Cplus
{
public:
	Twoway_List_Cplus();
	~Twoway_List_Cplus();

	//头部插入数据节点
	int InsertListFront(T data);

	//尾部插入链表
	int InsertListBack(T data);

	//任意位置插入链表
	int InsertList(T data, int index);

	//删除指定位置的链表元素
	int DeleteNode(int index);

	//获取链表指定位置的元素
	int GetListNode(int index, T &redata);

	//获取链表的长度
	int GetListLen();

	//游标复位
	void CursorReset();

	//游标下移动
	void CursorMoveNext();

	//游标上移动
	void CursorMovePre();

	//获取当前游标的元素
	int GetCurrentCursor(T &redata);

	//根据传来的节点数据删除节点
	int Delete_From_Node(T data);

public:
	ListNode<T> Head;
	ListNode<T> Cursor;
	int		 ListLen;
};

链表模板类源文件:Twoway_List_Cplus.cpp

#include "pch.h"
#include "Twoway_List_Cplus.h"
#include "iostream"
using namespace std;

template<typename T>
Twoway_List_Cplus<T>::Twoway_List_Cplus()
{
	//链表的头指针,游标,初始化链表的长度
	this->ListLen	= 0;
	this->Head.Next	= NULL;
	this->Head.Pre		= NULL;
	this->Cursor.Next	= NULL;
	this->Cursor.Pre	= NULL;
}

template<typename T>
Twoway_List_Cplus<T>::~Twoway_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->Cursor.Pre  = NULL;
	this->ListLen = 0;
	this->Head.Next = NULL;
	this->Head.Pre  = NULL;
}

//头部插入数据节点
template<typename T>
int Twoway_List_Cplus<T>::InsertListFront(T data)
{
	int ret = 0;
	ListNode<T> *LNode = new ListNode<T>;   //创建节点,把数据拷贝进来
	if (LNode == NULL)
	{
		cout << "New ListNode Error :InsertListFront()" << endl;
		ret = -1;
		return ret;
	}

	//拷贝数据
	LNode->data = data;         //对于复杂数据类型,要重载=操作符
		
	if (this->ListLen == 0)			    //链表中还没有数据
	{
		this->Head.Next = LNode;
		LNode->Next = NULL;         //后继指向NULL
		LNode->Pre = NULL;          //前驱指向NULL
		this->ListLen++;
	}
	else
	{
		this->Head.Next->Pre = LNode;      //0号位置前驱指向待插入节点
		LNode->Next = this->Head.Next;	   //待插入节点的后继指向0号结点
		LNode->Pre = NULL;			   //前驱指向NULL
		this->Head.Next = LNode;           //头节点的指向待插入节点
		this->ListLen++;
	}
	return ret;
}

template<typename T>
//尾部插入链表
int Twoway_List_Cplus<T>::InsertListBack(T data)
{
	int ret = 0;
	ListNode<T> *LNode = new ListNode<T>;   //创建节点,把数据拷贝进来
	if (LNode == NULL)
	{
		cout << "New ListNode Error :InsertListBack()" << endl;
		ret = -1;
		return ret;
	}
	//拷贝数据
	LNode->data = data;						 //对于复杂数据类型,要重载=操作符
	ListNode<T> *current = this->Head.Next;  //current指向0号几点
	if (this->ListLen == 0)			         //链表中还没有数据
	{
		this->Head.Next = LNode;
		LNode->Next = NULL;				     //后继指向NULL
		LNode->Pre = NULL;				     //前驱指向NULL
		this->ListLen++;
	}
	else
	{
		for (int i = 0; i < this->ListLen - 1; i++) //移动完之后current指向末尾元素
		{
			current = current->Next;
		}
		LNode->Pre = current;	 //待插入节点指向末尾节点
		current->Next = LNode;   //末尾节点指向待插入节点
		LNode->Next = NULL;
		this->ListLen++;
	}
	return ret;
}

template<typename T>
//任意位置插入链表
int Twoway_List_Cplus<T>::InsertList(T data, int index)
{
	int ret = 0;
	ListNode<T> *LNode = new ListNode<T>;   //创建节点,把数据拷贝进来
	if (LNode == NULL)
	{
		cout << "New ListNode Error :InsertList()" << endl;
		ret = -1;
		return ret;
	}
	//拷贝数据
	LNode->data = data;						   //对于复杂数据类型,要重载=操作符
	ListNode<T> *current = this->Head.Next;    //current指向0号几点
	ListNode<T> *temp = NULL;                  //临时指针变量
	if (index < 0 || index > this->ListLen)
	{
		cout << "Insert Index Error :InsertList() " << endl;
		ret = -1;
		return ret;
	}
	if (this->ListLen == 0)			     //链表中还没有数据
	{
		this->Head.Next = LNode;
		LNode->Next = NULL;				 //后继指向NULL
		LNode->Pre = NULL;				 //前驱指向NULL
		this->ListLen++;
	}
	else
	{
		for (int i = 0; i < index - 1; i++)		//移动完之后current指向带插入节点的前一个
		{
			current = current->Next;
		}

		if (index == 0)   //插在0号位置
		{
			this->Head.Next->Pre = LNode;    //0号位置前驱指向待插入节点
			LNode->Next = this->Head.Next;	  //待插入节点的后继指向0号结点
			this->Head.Next = LNode;         //头节点的指向待插入节点
			LNode->Pre = NULL;
			this->ListLen++;
		}

		else if (index == this->ListLen)       //插在最后一个节点
		{
			LNode->Pre = current;	        //待插入节点指向末尾节点
			current->Next = LNode;           //末尾节点指向待插入节点
			LNode->Next = NULL;
			this->ListLen++;
		}
		else
		{
			temp = current->Next;				//temp指向待插入元素的下一个
			temp->Pre = LNode;
			LNode->Next = temp;
			current->Next = LNode;
			LNode->Pre = current;
			this->ListLen++;
		}
	}

	return ret;
}

template<typename T>
//删除指定位置的链表元素
int Twoway_List_Cplus<T>::DeleteNode(int index)
{
	int ret = 0;
	ListNode<T> *current = this->Head.Next;       //current指向0号几点
	ListNode<T> *temp = NULL;                       //临时指针变量
	if (index < 0 || index >= this->ListLen)
	{
		cout << "Insert Index Error :DeleteNode() " << endl;
		ret = -1;
		return ret;
	}
	if (this->ListLen == 0)			     //链表中还没有数据
	{
		cout << "List is empty :DeleteNode() " << endl;
		ret = -1;
		return ret;
	}
	else
	{
		for (int i = 0; i < index - 1; i++)		//移动完之后current指向带插入节点的前一个
		{
			current = current->Next;
		}

		if (index == 0)   //删除的是首节点
		{
			temp = this->Head.Next->Next;     //temp指向1号元素
			temp->Pre = NULL;
			this->Head.Next = temp;           //头节点指向1号位置
			this->Cursor.Next = temp;
			this->Cursor.Pre = NULL;			//游标前驱指向null
			this->ListLen--;
		}

		else if (index == this->ListLen - 1)    //删除的是最后一个节点
		{
			current->Next = NULL;
			this->ListLen--;
			this->Cursor.Next = current;
			this->Cursor.Pre = current->Pre;
		}
		else  //删除的节点非头尾节点
		{
			temp = current->Next->Next;   //temp指向待删除节点的后一个节点
			current->Next = temp;
			temp->Pre = current;
			//设置游标
			this->Cursor.Next = temp;
			this->Cursor.Pre = current;
			this->ListLen--;
		}
	}
	return ret;
}

template<typename T>
//获取链表指定位置的元素
int Twoway_List_Cplus<T>::GetListNode(int index, T &redata)
{
	int ret = 0;
	ListNode<T> *current = this->Head.Next;       //current指向0号几点
	ListNode<T> *temp = NULL;                     //临时指针变量

	if (index < 0 || index > this->ListLen)
	{
		cout << "Index Error :GetListNode() " << endl;
		ret = -1;
		return ret;
	}
	else
	{
		if (this->ListLen == 0)			     //链表中还没有数据
		{
			cout << "List is empty :GetListNode() " << endl;
		}
		else
		{
			if (index == 0)
			{
				redata = current->data;
			}
			else
			{
				for (int i = 0; i < index - 1; i++)			 //移动到待获取位置的前面
				{
					current = current->Next;
				}
				redata = current->Next->data;
			}
		}
	}
	return ret;
}

template<typename T>
//获取链表的长度
int Twoway_List_Cplus<T>::GetListLen()
{
	return this->ListLen;
}

template<typename T>
//游标复位
void Twoway_List_Cplus<T>::CursorReset()
{
	this->Cursor.Next = this->Head.Next;
	this->Cursor.Pre = NULL;
}

template<typename T>
//游标下移动
void Twoway_List_Cplus<T>::CursorMoveNext()
{
	ListNode<T> *current = this->Head.Next;         //current指向0号几点
	ListNode<T> *temp = NULL;                         //临时指针变量

	if (this->Cursor.Next->Next == NULL)   //当前节点是最后一个节点
	{
		printf("\n Cursor is in the end point \n");
	}
	else
	{
		temp = this->Cursor.Next;          //temp=当前游标节点位置
		this->Cursor.Pre = temp;           //游标的上一个节点 = 当前游标节点位置
		this->Cursor.Next = temp->Next;    //游标的下一个节点 = 当前游标节点的下一个位置 
	}
}

template<typename T>
//游标上移动
void Twoway_List_Cplus<T>::CursorMovePre()
{
	ListNode<T> *current = this->Head.Next;         //current指向0号几点
	ListNode<T> *temp = NULL;                         //临时指针变量

	if (this->Cursor.Pre == NULL)
	{
		cout << "\n Cursor is in the start point \n" << endl;
	}
	else
	{
		temp = this->Cursor.Next;          //temp=当前游标节点位置
		this->Cursor.Next = temp->Pre;
		this->Cursor.Pre = temp->Pre->Pre;
	}
}

template<typename T>
//获取当前游标的元素
int Twoway_List_Cplus<T>::GetCurrentCursor(T &redata)
{
	int ret = 0;
	if (this->Head.Next == 0)
	{
		cout << "List is empty" << endl;
		ret = -1;
		return ret;
	}
	redata = this->Cursor.Next->data;
	return ret;
}

template<typename T>
//根据传来的节点数据删除节点
int Twoway_List_Cplus<T>::Delete_From_Node(T data)
{
	int tag = 0;
	int i = 0;
	int ret = 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 << "\n can't find element to delete " << endl;
		ret = -1;
		return ret;
	}	

	return ret;
}

测试链表功能源文件:Twoway_List_Cplus_Frame.cpp

# include"pch.h"
# include"Twoway_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 == this->age)
		{
			return true;
		}
		else
		{
			return false;
		}
	
	}

	~person()
	{
	}

public:
	string name;
	int    age;
};

//打印链表的信息
void printf_person(Twoway_List_Cplus<person> &obj)
{
	cout << "\n--------------开始打印数据---------------" << endl;
	person data;
	int ret = 0;
	int tag = 0;
	for (int i = 0; i < obj.ListLen; i++)
	{
		ret = obj.GetListNode(i,data);
		cout << data.name << "    " << data.age << endl;
	}
	cout << "\n --------------结束打印数据---------------" << endl;
}

//打印游标上下移,获取游标
void Printf_Cursor_Move(Twoway_List_Cplus<person> &obj)
{
	person pp;
	int ret = 0;

	cout << "测试游标下移功能 \n" << endl;
	ret = obj.GetCurrentCursor(pp);
	cout << pp.name << "   " << pp.age << endl;

	obj.CursorMoveNext();
	ret = obj.GetCurrentCursor(pp);
	cout << pp.name << "   " << pp.age << endl;

	obj.CursorMoveNext();
	ret = obj.GetCurrentCursor(pp);
	cout << pp.name << "   " << pp.age << endl;

	obj.CursorMoveNext();
	ret = obj.GetCurrentCursor(pp);
	cout << pp.name << "   " << pp.age << endl;

	obj.CursorMoveNext();
	ret = obj.GetCurrentCursor(pp);
	cout << pp.name << "   " << pp.age << endl;

	cout << "\n 测试游标上移功能 \n" << endl;
	ret = obj.GetCurrentCursor(pp);
	cout << pp.name << "   " << pp.age << endl;

	obj.CursorMovePre();
	ret = obj.GetCurrentCursor(pp);
	cout << pp.name << "   " << pp.age << endl;

	obj.CursorMovePre();
	ret = obj.GetCurrentCursor(pp);
	cout << pp.name << "   " << pp.age << endl;

	obj.CursorMovePre();
	ret = obj.GetCurrentCursor(pp);
	cout << pp.name << "   " << pp.age << endl;

	obj.CursorMovePre();
	ret = obj.GetCurrentCursor(pp);
	cout << pp.name << "   " << pp.age << endl;

}

void test()
{
	int ret = 0;
	person p1("pxzz", 21), p2("wxxx", 22), p3("iut", 23), p4("dft", 24), p5("hji", 25), p6("kij", 26), p7("kio", 27);
	Twoway_List_Cplus<person> TLC;
	person dd;

	//测试插入数据
	cout << "测试链表插入功能 \n" << endl;
	ret = TLC.InsertListFront(p1);
	ret = TLC.InsertListFront(p2);
	ret = TLC.InsertListBack(p3);
	ret = TLC.InsertListBack(p4);
	ret = TLC.InsertList(p5, 0);
	ret = TLC.InsertList(p6, 5);
	printf_person(TLC);

	//测试删除数据
	cout << "测试链表删除功能 \n" <<endl;
	ret = TLC.DeleteNode(0);
	printf_person(TLC);

	ret = TLC.DeleteNode(1);
	printf_person(TLC);

	ret = TLC.DeleteNode(4);
	printf_person(TLC);

	ret = TLC.DeleteNode(3);
	printf_person(TLC);

	//测试游标上下移,获取当前游标,游标复位功能
 	TLC.CursorReset();			   //游标复位
	Printf_Cursor_Move(TLC);

	//测试删除给定节点
	ret = TLC.Delete_From_Node(p2);
	printf_person(TLC);
}


int main()
{
	test();
	system("pause");
	return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值