将单链表中终点结点的指针端由空指针改成指向头结点,就使整个单链表造成一个环,这种头尾相连的单链表称为单循环链表,简称循环链表(circular linked list)。工具
咱们先讨论的是单向循环链表,示意图以下所示:ui
建立逻辑主要有下面的步骤:spa
先判断是否第一次建立?指针
下面用代码解释一下:code
//定义结点
typedef struct Node{
ElemType data;
struct Node *next;
}Node;
typedef struct Node * LinkList;
复制代码
Status CreateList(LinkList *L){
int item;
LinkList temp = NULL;
LinkList target = NULL;
复制代码
*L
是否为空:if(*L==NULL)
复制代码
next
指向本身:Status CreateList(LinkList *L){
printf("输入节点的值,输入0结束\n");
while(1)
{
scanf("%d",&item);
if(item==0) break;
//若是输入的链表是空。则建立一个新的节点,使其next指针指向本身 (*head)->next=*head;
if(*L==NULL)
{
*L = (LinkList)malloc(sizeof(Node));
if(!L)exit(0);
(*L)->data=item;
(*L)->next=*L;
}
复制代码
这里寻找尾结点能够有两种实现方式:cdn
遍历尾结点,根据尾结点指针会指向首元结点来定位到尾结点。blog
else{
for (target = *L; target->next != *L; target = target->next);
// 为新结点开辟内存空间
temp=(LinkList)malloc(sizeof(Node));
// 如开辟失败,返回错误
if(!temp) return ERROR;
// 新结点写入数据
temp->data=item;
temp->next=*L; //新节点指向头节点
target->next=temp;//尾节点指向新节点
}
复制代码
建立一个工具结点r
,用它来灵活处理之后一个结点(后插法)内存
新建一个 r
ci
LinkList r = NULL;
复制代码
在该链表建立时,将惟一的结点赋值给r
get
//第一次建立
if(*L == NULL){
*L = (LinkList)malloc(sizeof(Node));
if(!*L) return ERROR;
(*L)->data = item;
(*L)->next = *L;
r = *L;
复制代码
建立新的结点,进行赋值,next
指向原链表首结点
temp = (LinkList)malloc(sizeof(Node));
if(!temp) return ERROR;
temp->data = item;
temp->next = *L;
复制代码
把原最后一个结点的尾结点指向新结点,以及新结点赋值给工具结点r
r->next = temp;
复制代码
这样,闭环完成,整个过程示意图能够用下面的图实现:
复制代码
分两种状况,插入点是否为首元结点
next
指向头结点next
指向新的头结点temp
——临时的新结点具体代码实现以下:
temp = (LinkList)malloc(sizeof(Node));
if (temp == NULL) {
return ERROR;
}
temp->data = num;
for (target = *L; target->next != *L; target = target->next);
temp->next = *L;
target->next = temp;
*L = temp;
复制代码
如图所示:
temp
,并判断成功与否target
找到要插入位置的前一个结点,让 target->next = temp
next
指向新结点,新结点next
指向target
原来的next 位具体代码实现以下:
temp = (LinkList)malloc(sizeof(Node));
if (temp == NULL) {
return ERROR;
}
temp->data = num;
for ( i = 1,target = *L; target->next != *L && i != place - 1; target = target->next,i++) ;
temp->next = target->next;
target->next = temp;
复制代码
单向循环链表的删除,与顺序表的删除很相似,步骤都是先肯定须要删除的位置,经过判断是否首元结点,作不一样的操做。具体操做步骤以下:
若是本链表只剩首元结点,则直接将*L 置为空;
实施代码以下:
if((*L)->next == (*L)){
(*L) = NULL;
return OK;
}
复制代码
若是本链表还剩其余结点
target
next
指向原来首元结点的下一个结点,即 target->next = (*L)->next
temp
临时接收首元结点temp
实施代码以下:
// 步骤 1⃣️
for (target = *L; target->next != *L; target = target->next);
// 步骤 2⃣️
temp = *L;
// 步骤 3⃣️
*L = (*L)->next;
// 步骤 4⃣️
target->next = *L;
// 步骤 5⃣️
free(temp);
复制代码
target
表示temp
临时接受须要删除的结点target
的next
指以前指向的下一个结点temp
结点实施代码以下:
// 步骤 1⃣️
for(i=1,target = *L;target->next != *L && i != place -1;target = target->next,i++);
// 步骤 2⃣️
temp = target->next;
// 步骤 3⃣️
target->next = temp->next;
// 步骤 4⃣️
free(temp);
复制代码
示意图以下:
这里仅仅讨论下简单的链表查询,步骤以下:
实施代码以下:
int i = 1;
LinkList p;
p = L;
// 1⃣️ 寻找链表中的结点 data == value
while (p->data != value && p->next != L) {
i++;
p = p->next;
}
// 2⃣️ 当尾结点指向头结点就会直接跳出循环,因此要额外增长一次判断尾结点的data == value;
if (p->next == L && p->data != value) {
return -1;
}
复制代码
单向循环链表与顺序表有些许类似,可是不一样点在于,它并不是是按照序号排列,而是经过指针的指向进行链接,并且有首尾相连的特色。