文章目录
- 前言
- 一、循环链表是什么?
- 二、单循环链表
- 三、单循环链表基本操作的实现
- 总结
前言
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;elsereturn 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;
}
测试现象:
总结
路漫漫其修远兮,吾将上下而开摆。
有任何疑问和补充,欢迎交流。(但我显然不会)