數據結構(4)線性表之單循環鏈表

數據結構(4)線性表之單循環鏈表

前言

所謂單循環鏈表,實際上就是在單鏈表的基礎上,使最後一個結點的next指針再指向頭結點,形成循環的效果。這樣,從表中任何一個結點出發都可以找到其他結點的位置。

尾指針

顧名思義,尾指針是指向鏈表的最後一個結點。在單循環鏈表中,設立尾指針能使得一些操作簡化,例如兩個單循環鏈表的合併。

img_2

img_3

我們之前所寫的管理結構,是既包括頭指針又包括尾指針的,因此在實現某些操作時就很方便了。

單循環鏈表和單鏈表的實現思路、注意事項都是一樣的,只是需要額外注意的是,在我們的管理結構中要注意保持last的next指針始終指向頭結點,達到循環的效果。

附:單鏈表的實現思路及注意事項
數據結構(2.1)線性表之單鏈表的表示和實現
數據結構(2.2)線性表之單鏈表的具體實現

  • 鏈表爲空

鏈表爲空

  • 鏈表非空

鏈表非空

全部代碼

單循環鏈表的各項操作與單鏈表並無差別,只是在判斷鏈表結束的條件有差別,之前是判斷next指針是否爲空,現在需要判斷是否爲頭結點。因此實現代碼並沒有巨大的改變,只是在一些判斷條件上做出改變。

SCList.h

#ifndef SCList_h
#define SCList_h

#include <stdio.h>
#include <malloc.h>
#include <assert.h>

#define ElemType int

//結點的結構
typedef struct Node{
    ElemType data;
    struct Node *next;
}Node, *Pnode;

//鏈表的結構
typedef struct List{
    Pnode first;
    Pnode last;
    int size;
}List;

//初始化單循環鏈表
void InitSCList(List *list);

//1.尾部插入
void push_back(List *list,ElemType x);
//2.頭部插入
void push_fount(List *list,ElemType x);
//3.展示
void show_list(List *list);
//4.尾部刪除
void pop_back(List *list);
//5.頭部刪除
void pop_fount(List *list);
//6.按值插入(要求插入前的鏈表是有序的(此處爲順序
void insert_val(List *list,ElemType x);
//7.按值查找
Node* find(List *list,ElemType x);
//8.獲取長度
int length(List *list);
//9.按值刪除
void  delete_val(List *list,ElemType x);
//10.排序
void sort(List *list);
//11.逆置(前後轉換
void resver(List *list);
//12.清除單鏈表 ->只清除數據,保留頭結點
void clearList(List *list);
//13.摧毀 ->包括頭結點在內一起摧毀
void destroy(List *list);

//生成一個結點
Node* getNode(ElemType x);
#endif /* SCList_h */

SCList.cpp

#include "SCList.h"

//初始化單循環鏈表
void InitSCList(List *list){
    Node *s = (Node *)malloc(sizeof(Node));
    assert(s != NULL);
    list->first = list->last = s;
    
    //讓最後一個結點的next指向頭部,形成循環
    list->last->next = list->first;
    list->size = 0;
}

//1.尾部插入
void push_back(List *list,ElemType x){
    Node *s = getNode(x);
    
    //將這個結點接到鏈表尾部
    list->last->next = s;
    
    //重新設置last指針的指向
    list->last = s;
    
    //讓最後一個結點的next指向頭部,形成循環
    list->last->next = list->first;
    list->size ++;
}


//2.頭部插入
void push_fount(List *list,ElemType x){
    Node *s = getNode(x);
    
    s->next = list->first->next;
    list->first->next = s;
    
    //判斷是否是第一個結點
    if (list->last == list->first) {
        //是,更改last指針的指向
        list->last = s;
    }
    
    list->size ++;
}

//3.展示
void show_list(List *list){
    Node *p = list->first->next;
    
    while (p != list->first) {
        printf("%4d",p->data);
        p = p->next;
    }
    printf("\n");
}


//4.尾部刪除
void pop_back(List *list){
    if (list->size == 0) {
        printf("無可刪除的結點!\n");
        return;
    }
    
    //尋找倒數第二個結點
    Node *p = list->first;
    while (p->next != list->last) {
        p = p->next;
    }
    
    //釋放它後一個結點(即最後一個結點)
    free(list->last);
    //更改last指針的指向
    list->last = p;
    //讓最後一個結點的next指向頭部,形成循環
    list->last->next = list->first;
    list->size --;
}

//5.頭部刪除
void pop_fount(List *list){
    if (list->size == 0) {
        printf("無可刪除的結點!\n");
        return;
    }
    
    Node *p = list->first->next;
    list->first->next = p->next;
    free(p);
    
    //判斷是否是最後一個結點
    if(list->size == 1){
        //重新設置last的指向
        list->last = list->first;
    }
    
    list->size --;
}
//6.按值插入(要求插入前的鏈表是有序的(此處爲順序
void insert_val(List *list,ElemType x){
    Node *p = list->first;
    
    //尋找插入位置
    while (p->next != list->last && p->next->data < x) {
        p = p->next;
    }
    
    //到達了最後一個結點後,還需要與最後一個結點的值進行比較
    //判斷是否比最後一個結點大
    if (p->next == list->last && p->next->data < x) {
        //是,直接進行尾部插入
        push_back(list, x);
    }else{
        //其他狀況,直接在該位置進行插入
        Node *s = getNode(x);
        
        s->next = p->next;
        p->next = s;
        list->size ++;
    }
}
//7.按值查找
Node* find(List *list,ElemType x){
    if (list->size == 0) {
        return NULL;
    }
    
    //遍歷整個鏈表
    Node *p = list->first->next;
    while (p != list->first && p->data != x) {
        p = p->next;
    }
    
    //判斷是否回到頭部
    if (p == list->first) {
        //是,說明鏈表中沒有要找的數據
        return NULL;
    }else{
            return p;
    }
}
//8.獲取長度
int length(List *list){
    return list->size;
}

//9.按值刪除
void  delete_val(List *list,ElemType x){
    if (list->size == 0) {
        printf("鏈表爲空,無法刪除!\n");
        return;
    }
    
    Node *p = find(list, x);
    if (p == NULL) {
        printf("要刪除的數據不存在!\n");
        return;
    }
    
    //判斷是否是最後一個結點
    if (p == list->last) {
        //是,直接尾部刪除
        pop_back(list);
    }else{
        //判斷是否是倒數第二個結點
        if (p->next == list->last) {
            //是,需要修改last指針的指向
            list->last = p;
        }
        Node *s = p->next;
        p->data = s->data;
        p->next = s->next;
        free(s);
        list->size --;
    }
}

//10.排序
void sort(List *list){
    if (list->size <= 1) {
        return;
    }
    
    Node *s = list->first->next;
    Node *q = s->next;
    
    //將鏈表尾部斷開
    list->last->next = NULL;
    //重新設置last指針
    list->last = s;
    //讓鏈表再次循環
    list->last->next = list->first;
    
    while (q != NULL) {
        s = q;
        q = q->next;
        //進行按值插入
        insert_val(list, s->data);
        free(s);
        list->size --;
        
//        //尋找插入位置
//        Node *p = list->first;
//        while (p->next != list->last && p->next->data < s->data) {
//            p = p->next;
//        }
//
//        //判斷是否是最後一個結點
//        if (p->next == list->last && p->next->data < s->data) {
//            //是,直接進行尾部插入
//            s->next = list->last->next;
//            list->last->next = s;
//            list->last = s;
//
//        }else{
//            s->next = p->next;
//            p->next = s;
//        }
        
    }
}

//11.逆置(前後轉換
void resver(List *list){
    if (list->size <= 1) {
        return;
    }
    
    Node *s = list->first->next;
    Node *q = s->next;
    
    list->last->next = NULL;
    list->last = s;
    list->last->next = list->first;
    
    while (q != NULL) {
        s = q;
        q = q->next;
        //進行頭部插入
        push_fount(list, s->data);
        free(s);
        list->size--;
        
//        //進行頭部插入
//        s->next = list->first->next;
//        list->first->next = s;
    }
}

//12.清除單鏈表 ->只清除數據,保留頭結點
void clearList(List *list){
    Node *p = list->first->next;
    while (p != list->first) {
        p = p->next;
        pop_fount(list);
    }
    
}
//13.摧毀 ->包括頭結點在內一起摧毀
void destroy(List *list){
    clearList(list);
    free(list->first);
    list->first = list->last = NULL;
}

//生成一個結點
Node* getNode(ElemType x){
    Node *s = (Node *)malloc(sizeof(Node));
    assert(s != NULL);
    
    s->data = x;
    s->next = NULL;
    
    return s;
}

Main.cpp

#include "SCList.h"

int main(int argc, const char * argv[]) {
   
    List myList;
    InitSCList(&myList);
    
    //保存要輸入的數據
    ElemType item;
    //保存要查找的地址
    Node *p = NULL;
    int select = 1;
    while (select) {
        printf("**************************************\n");
        printf("* [1] push_back      [2] push_front  *\n");
        printf("* [3] show_list      [4] pop_back    *\n");
        printf("* [5] pop_front      [6] insert_val  *\n");
        printf("* [7] find           [8] length      *\n");
        printf("* [9] delete_val     [10] sort       *\n");
        printf("* [11] resver        [12] clear      *\n");
        printf("* [13*] destroy       [0] quit_system*\n");
        printf("**************************************\n");
        printf("請選擇:");
        scanf("%d",&select);
        if (select == 0) {
            break;
        }
        switch (select) {
            case 1:
                //尾部插入
                printf("請輸入要插入的數據(-1結束):");
                scanf("%d",&item);
                while (item != -1) {
                    push_back(&myList, item);
                    scanf("%d",&item);
                }
                break;
            case 2:
                //頭部插入
                printf("請輸入要插入的數據(-1結束):");
                scanf("%d",&item);
                while (item != -1) {
                    push_fount(&myList, item);
                    scanf("%d",&item);
                }
                break;
            case 3:
                //展示單鏈表
                show_list(&myList);
                break;
            case 4:
                //尾部刪除
                pop_back(&myList);
                break;
            case 5:
                //頭部刪除
                pop_fount(&myList);
                break;
            case 6:
                //按值插入
                printf("請輸入要插入的數據:\n");
                scanf("%d",&item);
                insert_val(&myList, item);
                break;
            case 7:
                //按值查找
                printf("請輸入要查找的值:\n");
                scanf("%d",&item);
                p = find(&myList, item);
                if (p == NULL) {
                    printf("要查找的數據不存在!\n");
                }else{
                    printf("地址爲:%p\n",p);
                }
                break;
            case 8:
                //展示鏈表長度
                printf("鏈表的長度爲:%d\n",length(&myList));
                break;
            case 9:
                //按值刪除
                printf("請輸入要刪除的值:\n");
                scanf("%d",&item);
                delete_val(&myList, item);
                break;
            case 10:
                //排序
                sort(&myList);
                break;
            case 11:
                //逆置(前後轉換
                resver(&myList);
                break;
            case 12:
                //清除
                clearList(&myList);
                break;
            case 13:
                destroy(&myList);
                break;
            default:
                printf("輸入的命令有誤,請重新插入\n");
                break;
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章