循环链表,最后一个元素的next指向头结点,这是其核心。
企业链表在结点结构体内只维护一个next指针,结点结构体是构成链表的本质,自定义的结构体内部需要包含一个结点结构体类型的变量。节点的连接和数据访问是通过显示的指针数据类型转换来实现的。
1.next指针连接着整个链表,可以形象理解为一条挂衣服的绳子。
2.每个数据结构体内部包含的结点结构体类型是用来挂衣服的挂钩。
3.头结点还有数据节点都是值形式,不需要手动开辟释放。
4.在每个数据结构体内,节点结构体变量都定义在最前面,这样在指针类型转换不用考虑偏移量就可以获取节点类型指针。
在编写时要注意的点为:
1.结点结构体内部定义next指针时,struct好像不能省略。
2.按值删除时,写法很灵活,在循环体内找到就可以删除,不需要在循环结束后进行额外判断(比较麻烦),删除节点后别忘了size--。
3.打印数据时,可以尝试多轮循环,在每一次遍历到头结点时,直接next。
4.循环链表不能通过结点判空来终止循环。
5字符数组的的比较用strcmp,不像string用==。
Circle_LinkList.h
#pragma once
//链表小节点
typedef struct CIRCLELINKNODE
{
struct CIRCLELINKNODE* next;//struct不能省略,不然报错
}CircleLinkNode;
//链表结构体
typedef struct CIRCLELINKLIST
{
CircleLinkNode head;
int size;
}CircleLinkList;
//比较回调
typedef int (*COMPARENODE)(CircleLinkNode, CircleLinkNode);
//打印回调
typedef void (*PRINTNODE)(CircleLinkNode);
//针对链表结构体操作的API函数
#define CIRCLELINKLIST_TRUE 0
#define CIRCLELINKLIST_FALSE 1
//初始化函数
CircleLinkList* Init_CircleLinkList();
//插入函数
void Insert_CircleLinkList(CircleLinkList* clist, int pos, CircleLinkNode* data);
//获取第一个元素
CircleLinkNode* Front_CircleLinkList(CircleLinkList* clist);
//根据位置删除
void RemoveByPos_CircleLinkList(CircleLinkList* clist, int pos);
//根据值删除
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(CircleLinkNode* clist);
Circle_LinkList.c
#include"Circle_LinkList.h"
#include<stdio.h>
//针对链表结构体操作的API函数
//初始化函数
CircleLinkList* Init_CircleLinkList()
{
CircleLinkList* clist = (CircleLinkList*)malloc(sizeof(CircleLinkList));
clist->head.next = &(clist->head);
clist->size = 0;
return clist;
}
//插入函数
void Insert_CircleLinkList(CircleLinkList* clist, int pos, CircleLinkNode* data)
{
if (clist == NULL || data ==NULL)
{
return;
}
if (pos < 0 || pos >= clist->size)
{
pos = clist->size;
}
//辅助指针变量找结点
CircleLinkNode* pCurrent = &(clist->head);
for (int i = 0; i < pos; i++)
{
pCurrent = pCurrent->next;
}
data->next = pCurrent->next;
pCurrent->next = data;
clist->size++;
}
//获取第一个元素
CircleLinkNode* Front_CircleLinkList(CircleLinkList* clist)
{
if (clist == NULL)
{
return NULL;
}
return clist->head.next;
}
//根据位置删除
void RemoveByPos_CircleLinkList(CircleLinkList* clist, int pos)
{
if (clist == NULL)
{
return;
}
if (pos<0 || pos>=clist->size)
{
return;
}
//根据pos找结点
//辅助指针变量
CircleLinkNode* pCurrent = &(clist->head);
for (int i = 0; i < pos; i++)
{
pCurrent = pCurrent->next;
}
CircleLinkNode* pNext = pCurrent->next;//记录一下这个结点,不需要释放
pCurrent->next = pCurrent->next->next;
clist->size--;
}
//根据值删除
void RemoveByValue_CircleLinkList(CircleLinkList* clist, CircleLinkNode* data, COMPARENODE compare)
{
if (clist == NULL || data ==NULL)
{
return;
}
//这个是循环链表,不能通过不为空来循环
//值判断,不需要从头节点开始
//在循环内进行判断和删除,不要在循环外统一判断,复杂了
//这里很灵活,要注意
CircleLinkNode* pPrev = &(clist->head);
CircleLinkNode* pCurrent = pPrev->next;
for (int i = 0; i < clist->size; i++)
{
if (compare(pCurrent, data) == CIRCLELINKLIST_TRUE)//找到之后就可以在这里进行删除操作,在循环外面操作需要多判断一次
{
pPrev->next = pCurrent->next;
clist->size--;
break;
}
pPrev = pPrev->next;
pCurrent = pPrev->next;
}
}
//获得链表长度
int Size_CircleLinkList(CircleLinkList* clist)
{
if (clist == NULL)
{
return -1;
}
return clist->size;
}
//判空
int IsEmpty_CircleLinkList(CircleLinkList* clist)
{
if (clist == NULL)
{
return -1;
}
if (clist->size == 0)
{
return CIRCLELINKLIST_TRUE;
}
else
{
return CIRCLELINKLIST_FALSE;
}
}
//查找
int Find_CircleLinkList(CircleLinkList* clist, CircleLinkNode* data, COMPARENODE compare)
{
if (clist == NULL || data == NULL)
{
return -1;
}
CircleLinkNode* pCurrent = clist->head.next;
int flag = -1;
for (int i = 0; i < clist->size; i++)
{
if (compare(pCurrent, data) == CIRCLELINKLIST_TRUE)
{
flag = i;
break;
}
pCurrent = pCurrent->next;
}
return flag;
}
//打印结点
void Print_CircleLinkList(CircleLinkList* clist, PRINTNODE print)
{
if (clist == NULL)
{
return;
}
//设置辅助指针变量
CircleLinkNode* pCurrent = clist->head.next;//注意打印多遍的情况
for (int i = 0; i < clist->size*3; i++)
{
if (pCurrent == &(clist->head))//头结点没有保存数据,每次到头结点后直接下一个
{
pCurrent = pCurrent->next;
printf("----------------------------\n");
}
print(pCurrent);
pCurrent = pCurrent->next;
}
}
//释放内存
void FreeSpace_CircleLinkList(CircleLinkNode* clist)
{
if (clist == NULL)
{
return;
}
free(clist);
}
循环链表.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include "Circle_LinkList.h"
#include<vld.h>
typedef struct PERSON
{
CircleLinkNode node;//关键点
char name[64];
int age;
int score;
}Person;
void myPrint(CircleLinkNode* data)
{
Person* p = (Person*)data;
printf("Name: %s, age: %d,score %d\n", p->name, p->age, p->score);
}
int myCompare(CircleLinkNode* data1, CircleLinkNode* data2)
{
Person* p1 = (Person*)data1;
Person* p2 = (Person*)data2;
if (strcmp(p1->name,p2->name)==0 && p1->age == p2->age && p1->score == p2->score)//注意字符数组的比较不像字符串,不能用==
{
return CIRCLELINKLIST_TRUE;
}
else
{
return CIRCLELINKLIST_FALSE;
}
}
int main()
{
//创建循环链表
CircleLinkList* clist = Init_CircleLinkList();
//创建数据
Person p1, p2, p3, p4, p5;//一次定义多个结构体变量
strcpy(p1.name, "aaa");
strcpy(p2.name, "bbb");
strcpy(p3.name, "ccc");
strcpy(p4.name, "ddd");
strcpy(p5.name, "eee");
p1.age = 10;
p2.age = 20;
p3.age = 30;
p4.age = 40;
p5.age = 50;
p1.score = 91;
p2.score = 92;
p3.score = 93;
p4.score = 95;
p5.score = 97;
//数据入链表
Insert_CircleLinkList(clist, 100, (CircleLinkNode*)&p1);
Insert_CircleLinkList(clist, 100, (CircleLinkNode*)&p2);
Insert_CircleLinkList(clist, 100, (CircleLinkNode*)&p3);
Insert_CircleLinkList(clist, 100, (CircleLinkNode*)&p4);
Insert_CircleLinkList(clist, 100, (CircleLinkNode*)&p5);
//打印数据
Print_CircleLinkList(clist, myPrint);
//根据值删除
Person pDel;
strcpy(pDel.name, "ccc");
pDel.age = 30;
pDel.score = 93;
//根据值删除
//RemoveByValue_CircleLinkList(clist, (CircleLinkNode*)&pDel, myCompare);
//打印数据
//Print_CircleLinkList(clist, myPrint);
//获取第一个元素
CircleLinkNode* ret = Front_CircleLinkList(clist);
//myPrint(ret);
//根据位置删除
//RemoveByPos_CircleLinkList(clist, 3);
//Print_CircleLinkList(clist, myPrint);
//获得链表长度
//int length = Size_CircleLinkList(clist);
//printf("链表长度为: %d\n", length);
判空
//if (IsEmpty_CircleLinkList(clist) == CIRCLELINKLIST_TRUE)
//{
// printf("链表为空\n");
//}
//else
//{
// printf("链表不为空\n");
//}
/*Person pFind;
strcpy(pFind.name, "ddd");
pFind.age = 40;
pFind.score = 95;*/
//查找
//int pos = Find_CircleLinkList(clist, (CircleLinkNode*)&pFind, myCompare);
//printf("找的的位置:%d\n", pos);
//释放空间
FreeSpace_CircleLinkList(clist);
system("pause");
return 0;
}
测试结果:
插入:
按值删除:
返回头结点:
按位置删除
返回链表长度:
判空:
查找: