前言
上次给大家展示了泛型单项循环链表的创建及其方法,接下来,让我们在学完双向链表后,进行双向循环链表的学习。
创建节点类
template<typename T>
class LNode
{
public:
T data;
LNode* next;
LNode* prev;
};
在节点类中,由于是双向链表,有两个指针分别指向节点的前驱和后继
创建链表类由于管理节点
template<typename T>
class Link_list
{
public:
LNode<T>* Head;
int size;
};
泛型双向循环链表的方法
1.初始化链表
template<typename T>
Link_list<T>* init_List()
{
Link_list<T>* L;
L = new Link_list<T>;
L->Head = new LNode<T>;
if (L == NULL)
{
printf("创建泛型双向循环链表失败\n");
}
L->Head->data = NULL;
L->Head->next = new LNode<T>;
L->Head->prev = new LNode<T>;
L->Head->next = L->Head;
L->Head->prev = L->Head;
printf("创建泛型双向循环链表成功\n");
return L;
}
这里先将两个指针分别指回头Head,数据域为空
2.增加节点
template<typename T>
void insert_list(Link_list<T>* L, int pos)
{
LNode<T>* new_Node = new LNode<T>;
LNode<T>* pcurrent = new LNode<T>;
new_Node->data = 0;
new_Node->next = NULL;
new_Node->prev = NULL;
T data;
cout << "请输入要插入的数据" << endl;
cin >> data;
new_Node->data = data;
pcurrent = L->Head;
for (int i = 1; i < pos; i++)
{
pcurrent = pcurrent->next;
}
new_Node->next = pcurrent->next;
pcurrent->next->prev = new_Node;
pcurrent->next = new_Node;
new_Node->prev = pcurrent;
return;
}
在这段代码中,分别初始化两个节点对象,new_Node:用于插入的新节点,pcurrent:用于遍历链表锁定位置
注意:一定要对新节点进行完整的初始化,以便后续插入
3.删除,销毁节点
template<typename T>
void delete_list(Link_list<T>* L,int pos)
{
LNode<T>* pcurrent = new LNode<T>;
LNode<T>* curr = new LNode<T>;
curr->data = 0;
curr->next = NULL;
curr->prev = NULL;
pcurrent = L->Head;
for (int i = 0; i < pos; i++)
{
if (pos < 1)
{
printf("请重新输入:\n");
continue;
}
curr = pcurrent;
pcurrent = pcurrent->next;
}
curr->next = pcurrent->next;
pcurrent->next->prev = curr;
delete pcurrent;
printf("删除成功\n");
return;
}
这里的两个节点对象
1.curr始终在pcurrent前方,用于锁定目标的前驱和为后续连接链表
2.pcurrent用于遍历整条链表,找到目标节点并销毁
3,更改,查询,打印链表
与链式存储的其他数据结构相同,这几种方法只是按照指令访问对应的数据域即可。
template<typename T>
void Change_list(Link_list<T>* L, int pos)
{
LNode<T>* pcurrent = L->Head;
for (int i = 0; i < pos; i++)
{
if (pcurrent == L->Head)
{
pcurrent = L->Head->next;
}
pcurrent = pcurrent->next;
}
T data;
printf("请输入更改后的数据\n");
cin >> data;
pcurrent->data = data;
return;
}
template<typename T>
void search_list(Link_list<T>* L, int pos)
{
LNode<T>* pcurrent = L->Head;
for (int i = 0; i < pos; i++)
{
if (pcurrent == L->Head)
{
pcurrent = L->Head->next;
}
pcurrent = pcurrent->next;
}
cout << pcurrent->data << endl;
}
template<typename T>
void print_list(Link_list<T>* L, int pos)
{
LNode<T>* pcurrent = L->Head->next;
for (int i = 0; i < pos; i++)
{
if (pcurrent == L->Head)
{
pcurrent = L->Head->next;
}
cout << pcurrent->data << "\t";
pcurrent = pcurrent->next;
}
cout << endl;
return;
}
几种方法基本相同 ,都是通过pcurrent指针遍历链表,找到目标后访问其数据域
主函数测试
int main1()
{
Link_list<int>* L = init_List<int>();
while (true)
{
printf("1.增 2.删 3.改 4.查 5.打印\n");
int point;
cin >> point;
switch (point)
{
case 1:
int round;
printf("请输入你要添加的次数:\n");
cin >> round;
for (int i = 0; i < round; i++)
{
int address;
printf("请输入你要插入的位置:\n");
cin >> address;
insert_list<int>(L, address);
}
break;
case 2:
printf("请输入你要删除的位置:\n");
int pos;
cin >> pos;
delete_list<int>(L, pos);
break;
case 3:
printf("请输入你要更改的数据的位置:\n");
int pose;
cin >> pose;
Change_list<int>(L, pose-1);
print_list<int>(L, 9);
break;
case 4:
printf("请输入你要查询的数据的位置:\n");
int add;
cin >> add;
search_list<int>(L, add-1);
break;
case 5:
printf("请输入你要打印的数:\n");
int num;
cin >> num;
print_list<int>(L, num);
break;
}
}
return 0;
}
int main2()
{
Link_list<float>* L = init_List<float>();
while (true)
{
printf("1.增 2.删 3.改 4.查 5.打印\n");
int point;
cin >> point;
switch (point)
{
case 1:
int round;
printf("请输入你要添加的次数:\n");
cin >> round;
for (int i = 0; i < round; i++)
{
int address;
printf("请输入你要插入的位置:\n");
cin >> address;
insert_list<float>(L, address);
}
break;
case 2:
printf("请输入你要删除的位置:\n");
int pos;
cin >> pos;
delete_list<float>(L, pos);
break;
case 3:
printf("请输入你要更改的数据的位置:\n");
int pose;
cin >> pose;
Change_list<float>(L, pose - 1);
print_list<float>(L, 9);
break;
case 4:
printf("请输入你要查询的数据的位置:\n");
int add;
cin >> add;
search_list<float>(L, add - 1);
break;
case 5:
printf("请输入你要打印的数:\n");
int num;
cin >> num;
print_list<float>(L, num);
break;
}
}
return 0;
}
int main()
{
int x;
printf("请输入你要操作的链表类型:\n");
printf("1.整形 2.浮点型\n");
cin >> x;
switch (x)
{
case 1:main1();
case 2:main2();
}
}
可以看到由于是泛型循环链表,操作可以涵盖多种数据类型,甚至自定义类型(不过可能需要运算符重载等操作)
运行结果:
这里我只展示了整形的例子
注意:由于是循环链表的一种,在输入的之后如果访问的值的位置大于链表长度,则会循环的访问
,可以更改循环条件控制访问。