【數據結構與算法】-(3)循環鏈表(單向)

1、定義

將單鏈表中終點結點的指針端由空指針改成指向頭結點,就使整個單鏈表造成一個環,這種頭尾相連的單鏈表稱爲單循環鏈表,簡稱循環鏈表(circular linked list)。工具

咱們先討論的是單向循環鏈表,示意圖以下所示:ui

單向循環鏈表結構圖

2、操做

2.1 建立單向循環鏈表

建立邏輯主要有下面的步驟:spa

先判斷是否第一次建立?指針

  1. 是(空鏈表):建立一個結點,使新結點next 指向自身
  2. 否:使尾節點的next=新節點。新節點的next指向頭節點

下面用代碼解釋一下:code

  1. 先定義一個結點(結構體),定一個別名:
//定義結點
typedef struct Node{
    ElemType data;
    struct Node *next;
}Node;

typedef struct Node * LinkList;
複製代碼
  1. 建立一些變量,以供環境使用:
Status CreateList(LinkList *L){
		int item;
    LinkList temp = NULL;
    LinkList target = NULL;
複製代碼
  1. 接下來判斷這個鏈表*L 是否爲空:
if(*L==NULL)
複製代碼
  1. 若是輸入的鏈表是空的——則建立一個結點,使它的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;
        }
複製代碼
  1. 若是鏈表不爲空——則去尋找鏈表的尾結點

這裏尋找尾結點能夠有兩種實現方式:cdn

  1. 遍歷尾結點,根據尾結點指針會指向首元結點來定位到尾結點。blog

    • 一、使得尾結點的next 指向新結點。
    • 二、新結點的next 指向頭結點。
    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;//尾節點指向新節點
    }
    複製代碼
  2. 建立一個工具結點r,用它來靈活處理之後一個結點(後插法內存

  3. 新建一個 rci

    LinkList r = NULL;
    複製代碼
  4. 在該鏈表建立時,將惟一的結點賦值給rget

    //第一次建立
    if(*L == NULL){       
       *L = (LinkList)malloc(sizeof(Node));
       if(!*L) return ERROR;
       (*L)->data = item;
       (*L)->next = *L;
       r = *L;
    複製代碼
  5. 建立新的結點,進行賦值,next指向原鏈表首結點

    temp = (LinkList)malloc(sizeof(Node));
    if(!temp) return  ERROR;
    temp->data = item;
    temp->next = *L;
    複製代碼
  6. 把原最後一個結點的尾結點指向新結點,以及新結點賦值給工具結點r

    r->next = temp;
    複製代碼
這樣,閉環完成,整個過程示意圖能夠用下面的圖實現:
複製代碼

2.2 單向循環鏈表插入數據

分兩種狀況,插入點是否爲首元結點

2.2.1 插入點位首元結點
  1. 建立新結點並進行賦值
  2. 找到鏈表最後的結點——尾結點
  3. 讓新結點的next 指向頭結點
  4. 讓尾結點的 next 指向新的頭結點
  5. 讓頭結點指向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;
複製代碼

如圖所示:

2.2.2 插入點非首元結點
  1. 建立新結點 temp,並判斷成功與否
  2. 找到插入的位置,若是超過鏈表長度,則自動插入隊尾
  3. 經過工具target 找到要插入位置的前一個結點,讓 target->next = temp
  4. 插入結點的前一個結點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;
複製代碼

2.3 單向循環鏈表的刪除

單向循環鏈表的刪除,與順序表的刪除很相似,步驟都是先肯定須要刪除的位置,經過判斷是否首元結點,作不一樣的操做。具體操做步驟以下:

2.3.1 刪除點爲首元結點
  • 若是本鏈表只剩首元結點,則直接將*L 置爲空;

    實施代碼以下:

    if((*L)->next == (*L)){
        (*L) = NULL;
        return OK;
    }
    複製代碼
  • 若是本鏈表還剩其餘結點

    1. 找到尾結點 target
    2. 尾結點 next 指向原來首元結點的下一個結點,即 target->next = (*L)->next
    3. temp 臨時接收首元結點
    4. 新結點爲首元結點
    5. 釋放以前的接收的首元結點 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);
    複製代碼

2.3.2 刪除點爲非首元結點
  1. 找到須要刪除結點的上一個結點,用target表示
  2. temp臨時接受須要刪除的結點
  3. targetnext 指以前指向的下一個結點
  4. 釋放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);
複製代碼

示意圖以下:

2.4 單向鏈表的查詢

這裏僅僅討論下簡單的鏈表查詢,步驟以下:

  1. 循環查找鏈表中給定值的結點
  2. 若查詢的結點指向首元結點,而且此時尾結點值也不爲所需,跳出

實施代碼以下:

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;
    }
複製代碼

3、小結

單向循環鏈表與順序表有些許類似,可是不一樣點在於,它並不是是按照序號排列,而是經過指針的指向進行鏈接,並且有首尾相連的特色。

相關文章
相關標籤/搜索