循环链表概述
循环链表是单链表的另一种形式,它是一个首尾相接的链表。它的特点是表中最后一个节点的指针域由NULL改为指向头结点或者线性表的第一个节点,整个链表形成一个环,就得到了单链形式的循环链表。因此,再循环链表中,从表的任意一个节点出发均可找到表中的其他节点。
头结点形式为下图
如下图所有节点都被连接到一个环上
循环链表和单链表的主要差异就在于循环的条件判断上,原来是 p->next == NULL,现在是 p->next != 头结点 ,则循环未结束。
如果用头指针表示循环链表,则需 O(n) 时间找到最后一个结点。若改用尾指针表示循环链表,此时查找开始结点和终端结点都很方便了。(这是由循环链表的特点决定的)如图:
此时若尾指针用rear指示,则查找终端结点时间是O(1),而开始结点,其实就是 rear->next->next ,其时间复杂也为O(1)。
合并两个链表
合并后
循环链表的实现
CList.h
typedef struct CNode
{
int data;
struct CNode *next;
}CNode,*CList;
void InitList(CList plist); //初始化
bool Insert_head(CList plist,int val); //头插法
bool Insert_tail(CList plist,int val); //尾插法
CNode *Search_pri(CList plist,int key); //查找前驱
bool Delete(CList plist,int key); //删除
bool IsEmpty(CList plist); //是否为空
void Destroy(CList plist); //摧毁
int GetLength(CList plist); //得到长度
void Show(CList plist); //显示函数
CList.cpp
#include "CList.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
void InitList(CList plist)//初始化
{
assert(plist != NULL);
plist->next = plist; // 与单链表不同 ,初始化时使头节点的next指针域指向头节点本身
}
static CNode*GetNode(int val)
{
CNode *pGet = (CNode*)malloc(sizeof(CNode));
assert(pGet != NULL);
pGet->data = val;
pGet->next = NULL;
return pGet;
}
bool Insert_head(CList plist,int val) //头插法
{
assert(plist != NULL);
CNode *pGet = GetNode(val);
pGet->next = plist->next;
plist->next = pGet;
return true;
}
bool Insert_tail(CList plist,int val) //尾插法
{
assert(plist != NULL);
CNode *pGet = GetNode(val);
CNode *p = plist;
while (p->next != plist) // 与单链表不同,循环条件发生变化
{
p = p->next;
}
p->next = pGet;
pGet->next = plist; // 与单链表不同,pGet->next = NULL 改为 pGet->next = plist
return true;
}
CNode *Search_pri(CList plist,int key) //查找前驱
{
assert(plist != NULL);
CNode *p = plist;
while (p->next != plist) // 与单链表不同,循环条件发生变化
{
if (p->next->data == key)
{
return p;
}
p = p->next;
}
return NULL;
}
bool Delete(CList plist,int key) //删除
{
assert(plist != NULL);
CNode *p = Search_pri(plist,key);
if (p == NULL)
{
return false;
}
CNode *pDel = p->next;
p->next = pDel->next;
free(pDel);
pDel = NULL;
return true;
}
bool IsEmpty(CList plist) //是否为空
{
return plist->next == plist; // 与单链表不同,判断条件发生变化
}
void Destroy(CList plist) //摧毁
{
CNode *pDel = NULL;
while (plist->next != plist) // 与单链表不同,循环条件发生变化
{
pDel = plist->next;
plist->next = pDel->next;
free(pDel);
}
pDel = NULL;
}
int GetLength(CList plist) //得到长度
{
int len = 0;
CNode *p = plist->next;
while (p != plist) // 与单链表不同,循环条件发生变化
{
len++;
p = p->next;
}
return len;
}
void Show(CList plist) //显示函数
{
CNode *p = plist->next;
while (p != plist) // 与单链表不同,循环条件发生变化
{
printf("%d ",p->data);
p = p->next;
}
printf("\n");
}
test.cpp
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<vld.h>
#include"Clist.h"
int main()
{
CNode head;//头结点
InitList(&head);
for(int i = 0; i < 10;i++)
{
Insert_tail(&head,i);
}
Insert_head(&head,-1);
Insert_head(&head,-2);
Show(&head);
CNode *p = Search_pri(&head,3);
printf("%d\n",p->data);
printf("len == %d\n",GetLength(&head));
Delete(&head,9);
Show(&head);
printf("len == %d\n",GetLength(&head));
Destroy(&head);
return 0;
}