將單鏈表中終點結點的指針端由空指針改成指向頭結點,就使整個單鏈表造成一個環,這種頭尾相連的單鏈表稱爲單循環鏈表,簡稱循環鏈表(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;
}
複製代碼
單向循環鏈表與順序表有些許類似,可是不一樣點在於,它並不是是按照序號排列,而是經過指針的指向進行鏈接,並且有首尾相連的特色。