1. 程式人生 > >19-迴圈連結串列基本運算實現

19-迴圈連結串列基本運算實現

1. 迴圈連結串列的抽象資料型別(ADT)

迴圈連結串列——ADT

ADT List
{
    資料物件:
         D = {ai | ai∈ElemType, i=1,2,…,n, n≧0 } //ElemType為型別識別符號
    資料關係:
         R = {<ai-1, ai> | ai-1, ai∈D, i=2,3,…,n }
    資料操作:
        (1)Init_CircleLinkList();//初始化迴圈連結串列
        (2)Insert_CircleLinkList(circlelist , pos , circlenode);//插入節點
(3)Front_CircleLinkList(circlelist);//獲得第一個節點 (4)RemoveByPos_CircleLinkList(circlelist , pos);//根據位置刪除節點 (5)RemoveByValue_CircleLinkList(circlelist , circlenode);//根據值去刪除節點 (6)Size_CircleLinkList(circlelist);//獲得連結串列的長度 (7)IsEmpty_CircleLinkList(circlelist);//判斷是否為空 (8
)Find_CircleLinkList(circlelist , circlenode);//根據值查詢節點 (9)Print_CircleLinkList(circlelist);//列印連結串列節點 (10)FreeSpace_CircleLinkList(circlelist);//釋放連結串列的記憶體 }

2. 迴圈連結串列的基本運算實現

CycleList.h檔案

#ifndef CIRCLELINKLIST
#define CIRCLELINKLIST

#include<stdio.h>
#include<stdlib.h>
//定義連結串列的結點 typedef struct CIRCLELINKNODE{ struct CIRCLELINKNODE* next;//結構體指標域 }CircleLinkNode; /* 如果把head定義成指標的話,那麼在給CircleLinkList分配記憶體的時候,因為head也是指標所以也要給head節點分配記憶體, 在釋放記憶體的時候要先釋放head,然後再釋放CircleLinkList。因此在結構體中不把head定義成指標的話,這時候我們在 給CircleLinkList分配記憶體的同時head也會分配記憶體,釋放記憶體的時候只要通過釋放CircleLinkList,同時head也會釋放,方便很多 */ //定義連結串列 typedef struct CIRCLELINKLIST{ CircleLinkNode head;//這裡不把head定義成指標,但實際上head->next是一個指標 int size; //連結串列長度(連結串列中的有效節點個數) }CircleLinkList; //迴圈連結串列的基本運算實現 #define CIRCLELINKLIST_TRUE 1 #define CIRCLELINKLIST_FALSE 0 //比較節點和輸出連結串列這兩個函式指標其實是回撥用的 //比較節點 typedef int(*COMPARENODE)(CircleLinkNode*, CircleLinkNode*); //輸出連結串列 typedef void(*PRINTNODE)(CircleLinkNode*); //初始化函式 CircleLinkList* Init_CircleLinkList(); //插入函式 //插入 clist:連結串列 pos:位置 data:插入的資料,不管使用者傳入任何型別資料,統一轉成CircleLinkNode*型別處理,這麼做的好處是API實現者不用關心使用者傳什麼資料,只需提供資料統一處理方式,供呼叫者呼叫API void Insert_CircleLinkList(CircleLinkList* clist, int pos, CircleLinkNode* data); //獲得第一個元素 CircleLinkNode* Front_CircleLinkList(CircleLinkList* clist); //根據位置刪除 void RemoveByPos_CircleLinkList(CircleLinkList* clist,int pos); //根據值去刪除 不用管使用者傳入什麼型別資料,只需通過回撥函式compare來呼叫使用者的結果就可以了 void RemoveByValue_CircleLinkList(CircleLinkList* clist, CircleLinkNode* data, COMPARENODE compare); //獲得連結串列的長度 int Size_CircleLinkList(CircleLinkList* clist); //判斷是否為空 int IsEmpty_CircleLinkList(CircleLinkList* clist); //查詢 int Find_CircleLinkList(CircleLinkList* clist, CircleLinkNode* data, COMPARENODE compare); //列印節點 不確定使用者傳入的資料,交給使用者來做, 我們只需通過回撥函式呼叫使用者的結果就行 void Print_CircleLinkList(CircleLinkList* clist, PRINTNODE print); //釋放記憶體 void FreeSpace_CircleLinkList(CircleLinkList* clist); #endif

CycleList.c檔案

#include "CircleLinkList.h"

//初始化函式
CircleLinkList* Init_CircleLinkList()
{
    //給連結串列分配記憶體
    CircleLinkList *cList = (CircleLinkList *)malloc(sizeof(CircleLinkList));
    //連結串列節點指向自己(迴圈連結串列)
    cList->head.next = &(cList->head);
    //初始連結串列長度
    cList->length = 0;
    return cList;
}


/*
    功能:插入函式

    引數:
         clist:連結串列
         pos:位置
         data:插入的資料,不管使用者傳入任何型別資料,統一轉成CircleLinkNode*型別處理,
         這麼做的好處是API實現者不用關心使用者傳什麼資料,只需提供資料統一處理方式,供呼叫者呼叫API
*/
void Insert_CircleLinkList(CircleLinkList* clist, int pos, CircleLinkNode* data)
{
    //連結串列是否有效
    if(clist == NULL)
    {
        return;
    }
    //資料是否有效
    if(data == NULL)
    {
        return;
    }
    //位置是否有效
    if(pos < 0 || pos > clist->length)
    {
        return;
    }

    //定義pCurrent指標指向頭結點
    CircleLinkNode *pCurrent = &(clist->head);
    int i;
    for(i = 0; i < clist->length; i++)
    {
        pCurrent = pCurrent->next;
    }
    //讓新節點指向頭結點
    data->next = pCurrent->next;
    //同時把頭結點指向新節點
    pCurrent->next = data;

    //連結串列長度+1
    clist->length++;
}

//獲得第一個元素
CircleLinkNode* Front_CircleLinkList(CircleLinkList* clist)
{
    if(clist == NULL)
    {
        return NULL;
    }

    return clist->head.next;
}

//根據位置刪除
void RemoveByPos_CircleLinkList(CircleLinkList* clist,int pos)
{
    if(clist == NULL || pos < 0 || pos >= clist->length)
    {
        return;
    }

    CircleLinkNode *pCurrent = &(clist->head);
    int i;
    for(i = 0; i < pos; i++)
    {
        pCurrent = pCurrent->next;
    }

    //快取要刪除的節點,並指向下一個節點
    CircleLinkNode *pNext = pCurrent->next;
    pCurrent->next = pNext->next;
    clist->length--;
}

//根據值去刪除            不用管使用者傳入什麼型別資料,只需通過回撥函式compare來呼叫使用者的結果就可以了
void RemoveByValue_CircleLinkList(CircleLinkList* clist, CircleLinkNode* data, COMPARENODE compare)
{
    if(clist == NULL || data == NULL)
    {
        return;
    }

    //pPrev先把head節點拿到,pPre記錄刪除的節點的前驅節點
    CircleLinkNode *pPre = &(clist->head);
    //從head->next有效節點開始遍歷,pCurrent記錄要刪除的節點
    CircleLinkNode *pCurrent = pPre->next;

    //遍歷查詢要刪除的資料
    int i;
    for(i = 0; i < clist->length; i++)
    {
        //進行比較,查詢是否是要刪除的元素
        if(compare(pCurrent , data) == CIRCLELINKLIST_TRUE)
        {
            //判斷滿足條件說明找到了,直接讓當前節點的前驅節點指向當前節點的後繼節點
            pPre->next = pCurrent->next;
            //連結串列大小-1
            clist->length--;
            break;
        }

        //如果pCurrent不是要刪除的資料,說明沒有找到,那麼pPrev把當前pCurrent節點記錄下來
        pPre = pCurrent;
        //繼續往下找要刪除的節點
        pCurrent = pCurrent->next;
    }
}

//獲得連結串列的長度
int Size_CircleLinkList(CircleLinkList* clist)
{
    if(clist == NULL)
    {
        return -1;
    }
    return clist->length;
}

//判斷是否為空
int IsEmpty_CircleLinkList(CircleLinkList* clist)
{
    if(clist == NULL)
    {
        return -1;
    }
    return clist->length;
}

//根據資料值查詢
int Find_CircleLinkList(CircleLinkList* clist, CircleLinkNode* data, COMPARENODE compare)
{
    if(clist == NULL || data == NULL)
    {
        return -1;
    }

    //從第一個節點開始遍歷
    CircleLinkNode *pCurrent = clist->head.next;
    //find_flag標記查詢結果,-1表示沒查詢到,0表示查詢到了
    int find_flag = -1;
    int i;
    for(i = 0; i < clist->length; i++)
    {
        //說明查詢到了
        if(compare(pCurrent , data) == CIRCLELINKLIST_TRUE)
        {
            find_flag = 0;
            break;
        }
        //如果沒找到就繼續往下找
        pCurrent = pCurrent->next;
    }

    //返回查詢標記
    return find_flag;
}

//列印節點   不確定使用者傳入的資料,交給使用者來做,  我們只需通過回撥函式呼叫使用者的結果就行
void Print_CircleLinkList(CircleLinkList* clist, PRINTNODE print)
{
    if(clist == NULL)
    {
        return;
    }

    if(clist->length == 0)
    {
        return;
    }

    //遍歷連結串列,pCurrent記錄每個節點
    CircleLinkNode *pCurrent = clist->head.next;
    int i;
    for(i = 0; i < clist->length; i++)
    {
        //遍歷之前,判斷pCurrent是否指向了head節點,如果指向了head節點,那麼從head節點開始遍歷
        if(pCurrent == &(clist->head))
        {
            pCurrent = pCurrent->next;
        }
        //如果pCurrent沒有指向head節點,那麼就從第一個有效節點開始輸出
        print(pCurrent);
        pCurrent = pCurrent->next;
    }

}

//釋放記憶體
void FreeSpace_CircleLinkList(CircleLinkList* clist)
{
    if(clist == NULL)
    {
        return;
    }

    free(clist);
    clist = NULL;
}

main.c檔案

#define _CRT_SECURE_NO_WARNINGS
#include <string.h>
#include"CircleLinkList.h"

typedef struct PERSON{
    CircleLinkNode node;
    char name[64];
    int age;
    int score;
}Person;

//列印函式
void print_test(CircleLinkNode *node)
{
    if(node == NULL)
    {
        return;
    }
    Person *p = (Person *)node;
    printf("name = %s , age = %d , score = %d\n" , p->name , p->age , p->score);
}

//比較函式
int compare_test(CircleLinkNode *node1 , CircleLinkNode *node2)
{
    Person *p1 = (Person *)node1;
    Person *p2 = (Person *)node2;

    //判斷要查詢的資料,name,age,score是否相等
    if(strcmp(p1->name,p2->name) == 0 && p1->age == p2->age && p1->score == p2->score)
    {
        return CIRCLELINKLIST_TRUE;
    }
    return CIRCLELINKLIST_FALSE;
}


int main(void)
{
    //建立迴圈連結串列
    CircleLinkList *clist = Init_CircleLinkList();

    Person p1,p2,p3,p4,p5;
    strcpy(p1.name, "zhangsan");
    strcpy(p2.name,"lisi");
    strcpy(p3.name, "wangwu");
    strcpy(p4.name, "zhaoliu");
    strcpy(p5.name, "wanger");
    p1.age = 10;
    p2.age = 20;
    p3.age = 30;
    p4.age = 40;
    p5.age = 50;
    p1.score = 60;
    p2.score = 70;
    p3.score = 80;
    p4.score = 90;
    p5.score = 100;

    //插入資料
    Insert_CircleLinkList(clist , 0 , (CircleLinkNode *)&p1);
    Insert_CircleLinkList(clist , 1 , (CircleLinkNode *)&p2);
    Insert_CircleLinkList(clist , 2 , (CircleLinkNode *)&p3);
    Insert_CircleLinkList(clist , 3 , (CircleLinkNode *)&p4);
    Insert_CircleLinkList(clist , 4 , (CircleLinkNode *)&p5);

    printf("-------------列印連結串列節點------------\n");
    Print_CircleLinkList(clist,print_test);

    //刪除第3個節點資料
    RemoveByValue_CircleLinkList(clist, (CircleLinkNode *)&p3, compare_test);
    printf("-------------刪除第3個節點資料後------------\n");
    Print_CircleLinkList(clist,print_test);

    //釋放記憶體
    FreeSpace_CircleLinkList(clist);
    printf("-------------釋放記憶體------------\n");
    return 0;
}

測試結果:
這裡寫圖片描述