文章目录
- 前言
- 一、循环链表是什么?
- 二、单循环链表
- 三、单循环链表基本操作的实现
- 总结
前言
T_T此专栏用于记录数据结构及算法的(痛苦)学习历程,便于日后复习(这种事情不要啊)。所用教材为《数据结构 C语言版 第2版》严蔚敏。有关线性表的顺序存储见线性表概念及顺序表的实现,有关单链表见线性表的链式存储(单链表)
一、循环链表是什么?
循环链表(CircularLinked List)是除单链表之外另一种形式的链式存储结构。其特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环。(贪吃蛇尾巴咬了头)循环链表从表中任一结点出发均可找到表中其他结点,下图所示为单链的循环链表。类似地,还可以有多重链的循环链表。
二、单循环链表
循环单链表的操作和单链表基本一致,差别仅在于:当链表遍历时,判别当前指针p是否指向表尾结点的终止条件不同。在单链表中,判别条件为p!=NULL或p->next!=NULL,而循环单链表的判别条件为p!=L或p->next!=L。
有关单链表的操作实现见单链表
在某些情况下,若在循环链表中设立尾指针而不设头指针,可使一些操作简化。例如,将两个线性表合并成一个表时,仅需将第一个表的尾指针指向第二个表的第一个结点,第二个表的尾指针指向第一个表的头结点,然后释放第二个表的头结点。
下面给出两个循环单链表的合并操作实现:
p=B->next->next;
B->next=A->next;
A->next = p;
效果:
三、单循环链表基本操作的实现
#include <iostream>
using namespace std;
#define OK 1
#define fail 0
#define overflow -1
#define not_exist -2
typedef int Status;
typedef int Elemtype;
typedef struct Lnode {
Elemtype data;
Lnode* next;
}Lnode, * Llist;
Llist L;
Elemtype e;
//初始化循环单链表,创建尾指针和头结点
Status InitList(Llist& L)
{
L = new Lnode; //尾指针
if (!L)return fail; //如果创建失败
L->data = 123456; //头结点
L->next = L;
return OK;
}
//创建循环单链表,头插法,创建i个结点
//先创建的后访问,头结点和首元结点位于两端
Status CreatList_Head(Llist &L, int i)
{
Llist Ltemp = L;
if (i < 1)return fail; //至少创建1个结点
Lnode* p = new Lnode; //创建第一个结点时,需要将L指向该结点,确保L为尾指针
cin >> p->data;
p->next = L;
L->next = p;
L = p;
i--;
while (i--)
{
Lnode* p = new Lnode;
cin >> p->data;
p->next = L->next->next;
L->next->next = p;
}
return OK;
}
//创建循环单链表,尾插法,创建i个结点
//先创建的先访问,头结点和首元结点位于链表同端
Status CreatList_End(Llist &L, int i)
{
if (i < 1)return fail; //至少创建1个结点
while (i--)
{
Lnode* q = new Lnode;
cin >> q->data;
q->next = L->next;
L->next = q;
L = q;
}
return OK;
}
//得到第i个结点的值,注意头结点下一个结点开始算第一个结点
//e为得到的结点数据值
Status GetElem(Llist L, int i, Elemtype* e)
{
Llist p = L->next;
if (i < 1 || p == L)return overflow; //如果i不合法或链表为空,则失败
while (i--)
{
if (p != L)
p = p->next;
else
return overflow;
}
*e = p->data;
return OK;
}
//查找某个值在链表中的位置,注意头结点下一个结点开始算第一个结点
//e为要查找的数据值
Lnode* LocatElem(Llist L, Elemtype e)
{
Llist p = L->next->next;
if (L->data == e)
return L;
while (p != L && p->data != e)
{
p = p->next;
}
if (p == L)return NULL;
return p;
}
//在第i个位置后插入一个结点,注意头结点下一个结点开始算第一个结点
//e插入的结点的数据值
Status InsertElem(Llist L, int i, Elemtype e)
{
Llist p = L->next;
if (i < 1)return fail; //如果i不合法则失败
while (p != L && i > 1)
{
p = p->next;
i--;
}
if (p == L || i != 1)return fail; //如果链表不存在第i个位置,则失败
Lnode* q = new Lnode;
q->data = e;
q->next = p->next;
p->next = q;
return OK;
}
//删除在第i个位置的结点,注意头结点下一个结点开始算第一个结点
Status DeleteElem(Llist L, int i)
{
Llist p = L->next;
if (i < 1)return fail; //如果i不合法则失败
while (p != L && i > 1)
{
p = p->next;
i--;
}
if (p == L || i != 1)return fail; //如果链表不存在第i个位置,则失败
Llist q = p->next;
p->next = q->next;
delete q;
q = NULL;
return OK;
}
//销毁链表
Status DestoryList(Llist L)
{
Llist p = L->next;
while (p != L)
{
Llist q = p;
p = p->next;
delete q;
q = NULL;
}
delete p;
p = NULL;
return OK;
}
//合并两个循环单链表
//L1_end和L2_end均为尾指针
Status CirculateList_Merge(Llist L1_end, Llist L2_end)
{
Llist p = L1_end->next;
L1_end->next = L2_end->next->next;
delete L2_end->next;
L2_end->next = NULL;
L2_end->next = p;
return OK;
}
int main() //测试程序
{
InitList(L);
cout << L << endl;
cout << L->data << endl;
cout << L->next << endl;
cout << CreatList_Head(L, 5) << endl;
for (int i = 1; i < 6; i++)
cout <<GetElem(L, i, &e)<< " " << e << " ";
cout << endl;
cout << InsertElem(L, 1, 99) << endl;
cout << GetElem(L, 1, &e) << " " << e << endl;
cout << LocatElem(L, 99) << endl;
cout << L->next->next << endl;
DeleteElem(L, 1);
for (int i = 0; i < 7; i++)
cout << GetElem(L, i, &e) << e << " ";
DestoryList(L);
cout << L->data << endl;
return 0;
}
测试现象:
总结
路漫漫其修远兮,吾将上下而开摆。
有任何疑问和补充,欢迎交流。(但我显然不会)