1. 程式人生 > 其它 >基礎---迴圈連結串列的實現

基礎---迴圈連結串列的實現

3.迴圈連結串列的實現

3.1定義一個結點
typedef struct list{
    int data;
    struct list *next;
}list;
//data為儲存的資料,next指標為指向下一個結點
//和單鏈表的結點一樣。
3.2初始化一個結點
//初始結點
list *initlist(){
    list *head=(list*)malloc(sizeof(list));
    if(head==NULL){
        printf("建立失敗,退出程式");
        exit(0);
    }else{
        head->next=NULL;
        return head;
    }
}
//由於迴圈連結串列的特殊性,已經為之後的方便使用,一個初始化好的迴圈連結串列的頭結點的next需要指向自身。
//所以上面的操作是不完整的,在具體使用的時候,我們還需要在主函式里加上如下操作:
在主函式重呼叫可以是這樣
    //////////初始化頭結點//////////////
    list *head=initlist();
    head->next=head;
3.3建立迴圈連結串列

注意是’建立---插入資料‘,這說明一個迴圈連結串列的建立是在資料逐個的插入中完成的。

但這個插入還和插入操作的插入不一樣,那個插入是在目標位置,而這個插入是在表的末尾(雖然迴圈連結串列沒有什麼開始結束之類的,但名義上的head和end還是有的)

//建立——插入資料
int insert_list(list *head){
    int data;   //插入的資料型別
    printf("請輸入要插入的元素:");
    scanf("%d",&data);
  
    list *node=initlist();
    node->data=data;
    //初始化一個新的結點,準備進行連結
  
    if(head!=NULL){
        list *p=head;
        //找到最後一個數據
        while(p->next!=head){//①
            p=p->next;
        }
        p->next=node;
        node->next=head;
        return 1;
    }else{
        printf("頭結點已無元素\n");
        return 0;
    }
  
}
//①前面的單鏈表和雙向連結串列通過NULL找到連結串列的結尾,而迴圈連結串列通過連結串列頭next的地址head找到連結串列名義上的結尾。迴圈連結串列也正是通過這種方法實現在連結串列所謂結尾的插入。
3.4插入新結點
//插入元素
list *insert_list(list *head,int pos,int data){
    //三個引數分別是連結串列,位置,引數
    list *node=initlist();  //新建結點
    list *p=head;       //p表示新的連結串列
    list *t;
    t=p;
    node->data=data;
    if(head!=NULL){
        for(int i=1;i<pos;i++){
            t=t->next;  //走到需要插入的位置處
        }
        node->next=t->next;
        t->next=node;
        return p;
    }
    return p;
}
3.5刪除結點
//刪除元素
int delete_list(list *head) {
    if(head == NULL) {
        printf("連結串列為空!\n");
        return 0;
    }
    //建立臨時結點儲存頭結點資訊(目的為了找到退出點)
    //如果不這麼建立的化需要使用一個數據進行計數標記,計數達到連結串列長度時自動退出
    //迴圈連結串列當找到最後一個元素的時候會自動指向頭元素,這是我們不想讓他發生的------①
    list *temp = head;        //此時temp指向頭結點  
    list *ptr = head->next;	  //此時ptr指向頭結點的下一個節點
  
    int del;
    printf("請輸入你要刪除的元素:");
    scanf("%d",&del);
  
    while(ptr != head) {
        if(ptr->data == del) {		
            if(ptr->next == head) {    //判斷刪除節點是否為尾結點
                temp->next = head;
                free(ptr);
                return 1;				//跳出迴圈
            }
            temp->next = ptr->next;    //核心刪除操作程式碼
            free(ptr);					//說明了ptr是目標刪除結點。
            //printf("元素刪除成功!\n");
            return 1;
        }
        temp = temp->next;
        ptr = ptr->next;	//標準的遍歷操作。
    }c
    printf("沒有找到要刪除的元素\n");
    return 0;
}
//觀察前面的連結串列就能明白是什麼意思。前面連結串列用while和NULL判斷迴圈並退出,而迴圈列表沒有NULL。為了避免死迴圈,我們需要採用其他策略——例如利用連結串列頭的地址當作迴圈條件判斷跳出迴圈,當然也可以用程式碼註釋中說的計數器來判斷終止迴圈。
3.6迴圈連結串列的遍歷
//遍歷元素
int display(list *head) {
    if(head != NULL) {
        list *p  = head;
        //遍歷頭節點到,最後一個數據
        while(p->next != head ) {
            printf("%d   ",p->next->data);
            p = p->next;
        }
        printf("\n");   //習慣性換行 ( o=^•ェ•)o ┏━┓
        //把最後一個節點賦新的節點過去
        return 1;
    } else {
        printf("頭結點為空!\n");
        return 0;
    }
}
//關鍵還是找到合適的終止迴圈條件。目前已知的就是計數器和連結串列頭地址。
3.7完整的迴圈連結串列程式碼
 #include<stdio.h>
#include<stdlib.h>
typedef struct list{
    int data;
    struct list *next;
}list;
//data為儲存的資料,next指標為指向下一個結點
 
//初始結點
list *initlist(){
    list *head=(list*)malloc(sizeof(list));
    if(head==NULL){
        printf("建立失敗,退出程式");
        exit(0);
    }else{
        head->next=NULL;
        return head;
    }
}
 
//建立--插入資料
int create_list(list *head){
    int data;   //插入的資料型別
    printf("請輸入要插入的元素:");
    scanf("%d",&data);
 
    list *node=initlist();
    node->data=data;
    //初始化一個新的結點,準備進行連結
 
    if(head!=NULL){
        list *p=head;
        //找到最後一個數據
        while(p->next!=head){
            p=p->next;
        }
        p->next=node;
        node->next=head;
        return 1;
    }else{
        printf("頭結點已無元素\n");
        return 0;
    }
 
}
 
//插入元素
list *insert_list(list *head,int pos,int data){
    //三個引數分別是連結串列,位置,引數
    list *node=initlist();  //新建結點
    list *p=head;       //p表示新的連結串列
    list *t;
    t=p;
    node->data=data;
    if(head!=NULL){
        for(int i=1;i<=pos;i++){
            t=t->next;
        }
        node->next=t->next;
        t->next=node;
        return p;
    }
    return p;
}
 
//刪除元素
int delete_list(list *head) {
    if(head == NULL) {
        printf("連結串列為空!\n");
        return 0;
    }
    //建立零時結點儲存頭結點資訊(目的為了找到退出點)
    //如果不這麼建立的化需要使用一個數據進行計數標記,計數達到連結串列長度時自動退出
    //迴圈連結串列當找到最後一個元素的時候會自動指向頭元素,這是我們不想讓他發生的
    list *temp = head;          
    list *ptr = head->next;
 
    int del;
    printf("請輸入你要刪除的元素:");
    scanf("%d",&del);
 
    while(ptr != head) {
        if(ptr->data == del) {
            if(ptr->next == head) { //迴圈結束的條件換成ptr->next == head
                temp->next = head;
                free(ptr);
                return 1;
            }
            temp->next = ptr->next;
            free(ptr);
            //printf("元素刪除成功!\n");
            return 1;
        }
        temp = temp->next;
        ptr = ptr->next;
    }
    printf("沒有找到要刪除的元素\n");
    return 0;
}
 
 
//遍歷元素
int display(list *head) {
    if(head != NULL) {
        list *p  = head;
        //遍歷頭節點到,最後一個數據
        while(p->next != head ) {
            printf("%d   ",p->next->data);
            p = p->next;
        }
        printf("\n");   //習慣性換行 ( o=^•ェ•)o ┏━┓
        //把最後一個節點賦新的節點過去
        return 1;
    } else {
        printf("頭結點為空!\n");
        return 0;
    }
}
 
int main(){
    //////////初始化頭結點//////////////
    list *head=initlist();
    head->next=head;
    ////////通過插入元素完善連結串列/////////
    for(int i=0;i<5;i++){   //只是演示使用,不具體提供輸入
        create_list(head);
    }
    display(head);
    ////////////插入元素////////////////
    head=insert_list(head,1,10);
    display(head);
    ////////////刪除元素////////////////
    delete_list(head);
    display(head);
    return 0;
}