19-迴圈連結串列基本運算實現
阿新 • • 發佈:2019-02-18
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;
}
測試結果: