链表只能从头结点开始访问链表中的数据元素,如果需要逆序访问单链表中的数据元素将极其低效。双链表是链表的一种,由节点组成,每个数据结点中都有两个指针,分别指向直接后继和直接前驱,带有游标的双向链表可以应用在某些特殊的场景。
详细讲解参照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;
}