循环链表的定义:
将单链表中最后一个数据元素(业务节点)的next指针指向第一个元素
循环链表拥有单链表的所有操作
创建链表
销毁链表
获取链表长度
清空链表
获取第pos个元素操作
插入元素到位置pos
删除位置pos处的元素
新增功能
:游标的定义
在循环链表中可以定义一个“当前”指针,这个指针通常称为游标,可以通过这个游标来遍历链表中的所有元素。
循环链表新操作
CircleListNode* CircleList_DeleteNode(CircleList* list, CircleListNode* node);
CircleListNode* CircleList_Reset(CircleList* list);
CircleListNode* CircleList_Current(CircleList* list);
CircleListNode* CircleList_Next(CircleList* list);
插入元素的分析
1) 普通位置插入元素
2) 添加第一个元素(第一次插入元素)
3) 最后一个位置插入元素
4) 第一个位置插入元素
在第一个位置插入
删除节点
#ifndef __CIRCLE_LIST_H__
#define __CIRCLE_LIST_H__
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
typedef void CircleList;//数据类型的封装
//业务数据节点
typedef struct _tag_MyCicleListNode
{
struct _tag_MyCicleListNode * next;//只有指针域
}CircleListNode;
CircleList *CircleList_Create();
void CircleList_Destroy(CircleList * list);
void CircleList_Clear(CircleList * list);
int CircleList_Length(CircleList *list);
int CircleList_Insert(CircleList * list, CircleListNode * node,int pos);
CircleListNode * CircleList_Get(CircleList * list,int pos);
CircleListNode * CircleList_Delete(CircleList * list,int pos);
CircleListNode * CircleList_DeleteNode(CircleList * list,CircleListNode *node);
CircleListNode * CircleList_Reset(CircleList * list);
CircleListNode * CircleList_Current(CircleList * list);
CircleListNode * CircleList_Next(CircleList * list);
#endif // !__CIRCLE_LIST_H__
#include "CircleList.h"
//表头结点
typedef struct _tagMyCircleList
{
CircleListNode head;//表头结点里面的头结点,
//里面存放的是指向链表第一个节点的指针
CircleListNode * slider;//游标
int length;//业务数据节点个数
}TCircleList;
/*创建链表*/
CircleList *CircleList_Create()
{
TCircleList * tmp = NULL;
/*为表头结点分配内存*/
tmp = (TCircleList *)malloc(sizeof(TCircleList));
if (NULL == tmp)//合法性检测
{
printf("malloc error!\n");
return NULL;
}
/*初始化表头节点*/
memset(tmp,0,sizeof(TCircleList));
/*返回分配好内存的循环链表表头节点首地址*/
return tmp;
}
/*销毁链表*/
void CircleList_Destroy(CircleList * list)
{
if (list != NULL)
{
free(list);
list = NULL;
}
else{
printf("argv error!\n");
}
return ;
}
/*清空链表*/
void CircleList_Clear(CircleList * list)
{
TCircleList * tmp = NULL;
if (list == NULL)
{
printf("argv error!\n");
return;
}
tmp = (TCircleList *)list;
/*全部恢复初始状态*/
tmp->head.next = NULL;
tmp->slider = NULL;
tmp->length = 0;
return ;
}
/*获取业务节点个数*/
int CircleList_Length(CircleList *list)
{
TCircleList * tmp = NULL;
if (list == NULL)
{
printf("argv error!\n");
return -1;
}
tmp = (TCircleList *)list;
return tmp->length;
}
/*插入节点*/
int CircleList_Insert(CircleList * list, CircleListNode * node, int pos)
{
TCircleList * tmp = NULL;//表头结点辅助指针
CircleListNode * current = NULL;//当前节点指针
CircleListNode * last_node = NULL;//尾节点辅助指针
int i = 0;//循环变量
/*1. 合法性检测*/
if (list == NULL || node == NULL || pos < 0)
{
printf("argv error!\n");
return -1;
}
tmp = (TCircleList *)list;
/*if (pos >= tmp->length)//循环链表不能进行容错纠正, //否则会卡死在第二次循环遍历的第一个节点 { pos = tmp->length; }*/
/*2.当前指针指向表头结点*/
current = &(tmp->head);
/*3.向后跳pos个节点,使得当前指针指向pos-1个节点*/
for (i = 0; i < pos && current->next != NULL;i++)
{
current = current->next;
}
/*4.进行常规的插入操作*/
node->next = current->next;
current->next = node;
/*5.判断此次插入操作是否是第一次插入操作*/
if (tmp->length == 0)
{
tmp->slider = node;//如果是第一次操作,更新游标指向第一个插入的节点
}
/*6.更新此时链表的长度*/
tmp->length++;
/*7.判断此次插入是否是从表头插入(头插法)*/
if (current == &(tmp->head))
{
/*7.1 获取此时链表中最后一个业务节点*/
last_node = CircleList_Get((CircleList *)tmp, tmp->length - 1);
/*7.2 将尾节点指向新插入的头结点*/
last_node->next = node;
}
/*8. 插入成功返回0*/
return 0;
}
CircleListNode * CircleList_Get(CircleList * list, int pos)
{
/*相关辅助变量的声明*/
TCircleList * tmp = NULL;
CircleListNode * current = NULL;
int i = 0;
/*合法性检测*/
if (list == NULL || pos < 0)
{
printf("argv error!\n");
return NULL;
}
tmp = (TCircleList *)list;
/*if (pos >= tmp->length) { pos = tmp->length; }*/
/*当前节点指针的初始化--指向表头结点*/
current = &(tmp->head);
/*向后跳pos个节点--当前指针指向第pos-1个节点*/
for (i = 0; i < pos && current->next != NULL; i++)
{
current = current->next;
}
/*返回目标节点*/
return current->next;
}
CircleListNode * CircleList_Delete(CircleList * list, int pos)
{
/*1. 相关辅助变量的声明*/
TCircleList * tmp = NULL;//表头结点指针
CircleListNode * current = NULL;//当前节点指针
CircleListNode * res_node = NULL;//要删除的节点指针
CircleListNode * last_node = NULL;//最后一个节点指针
int i = 0;//循环变量
/*2. 合法性检测*/
if (list == NULL || pos < 0 )
{
printf("argv error!\n");
return NULL;
}
tmp = (TCircleList *)list;
/*3. 防止对空链表进行删除操作*/
if (tmp->length <= 0)
{
printf("length error!\n");
return NULL;
}
/*if (pos >= tmp->length) { pos = tmp->length; }*/
/*4. 初始化当前节点指针*/
current = &(tmp->head);
/*5. 向后跳pos个节点*/
for (i = 0; i < pos && current->next != NULL; i++)
{
current = current->next;
}
/*6. 判断是否是对头结点进行删除操作*/
if (current == &(tmp->head))
{
//如果删除头结点,要先获取最后一个节点的指针在进行删除操作
last_node = CircleList_Get((CircleList *)tmp, tmp->length - 1);
}
/*7. 进行常规的删除操作*/
res_node = current->next;//获取要删除的节点
current->next = res_node->next;
/*8. 修改此时链表长度*/
tmp->length--;
/*9. 如果删除头结点则需要更新最后一个节点的指向, 否则最后一个节点指向的是一块非法内存空间*/
if (last_node != NULL)
{
last_node->next = current->next;
tmp->head.next = current->next;
}
/*10 .如果删除的节点是游标所指的节点*/
if (tmp->slider == res_node)
{
//将游标指向下一个节点
tmp->slider = res_node->next;
}
/*11. 如果删除该节点以后是空链表--进行清空操作*/
if (tmp->length == 0)
{
tmp->head.next = NULL;
tmp->slider = NULL;
}
/*12. 返回被删除的节点*/
return res_node;
}
/*从给定的链表中删除指定的节点*/
CircleListNode * CircleList_DeleteNode(CircleList * list, CircleListNode *node)
{
/*相关辅助变量声明*/
TCircleList * tmp = NULL;
CircleListNode * current = NULL;
CircleListNode * res_node = NULL;//指向要删除的节点
int i = 0;
/*参数合法性检测*/
if (list == NULL || node == NULL)
{
printf("argv error!\n");
return NULL;
}
tmp = (TCircleList *)list;
/*当前节点辅助指针变量初始化--指向表头结点*/
current = &(tmp->head);
/*遍历链表,寻找与给定节点相同的节点*/
for (i = 0; i < tmp->length && current->next != NULL;i++)
{
/*找到目标节点*/
if (current->next == node)
{
res_node = current->next;//记录目标节点的位置
break;
}
current = current->next;//更新当前节点辅助指针变量
}
/*确实找到目标节点*/
if (res_node != NULL)
{
/*调用节点删除函数*/
CircleList_Delete((CircleList *)tmp, i);//此时的i就是目标节点在链表相应的pos
}
/*返回目标节点*/
return res_node;
}
/*使链表的游标复位--指向第一个业务节点*/
CircleListNode * CircleList_Reset(CircleList * list)
{
TCircleList * tmp = NULL;
/*合法性*/
if (list == NULL)
{
printf("argv error!\n");
return NULL;
}
tmp = (TCircleList *)list;
/*更新游标指向第一个业务节点*/
tmp->slider = tmp->head.next;
return tmp->slider;
}
/*返回当前游标指向的节点*/
CircleListNode * CircleList_Current(CircleList * list)
{
TCircleList * tmp = NULL;
/*合法性*/
if (list == NULL)
{
printf("argv error!\n");
return NULL;
}
tmp = (TCircleList *)list;
return tmp->slider;//返回当前游标指向的节点
}
/*返回当前游标指向的节点并把游标指向下一个节点*/
CircleListNode * CircleList_Next(CircleList * list)
{
TCircleList * tmp = NULL;
CircleListNode * res_node = NULL;//保存当前游标指向的节点
/*合法性*/
if (list == NULL)
{
printf("argv error!\n");
return NULL;
}
tmp = (TCircleList *)list;
/*防止是空链表--游标是空指针*/
if (tmp->slider == NULL)
{
printf("tmp->slider error!\n");
return NULL;
}
res_node = tmp->slider;//记录当前游标指向的节点
tmp->slider = res_node->next;//更新游标指向下一个节点
/*返回当前节点*/
return res_node;
}
#include "CircleList.h"
struct Value
{
CircleListNode header;
int v;
};
void main()
{
int i = 0;
CircleList* list = CircleList_Create();
struct Value v1;
struct Value v2;
struct Value v3;
struct Value v4;
struct Value v5;
struct Value v6;
struct Value v7;
struct Value v8;
v1.v = 1;
v2.v = 2;
v3.v = 3;
v4.v = 4;
v5.v = 5;
v6.v = 6;
v7.v = 7;
v8.v = 8;
CircleList_Insert(list, (CircleListNode*)&v1, CircleList_Length(list));
CircleList_Insert(list, (CircleListNode*)&v2, CircleList_Length(list));
CircleList_Insert(list, (CircleListNode*)&v3, CircleList_Length(list));
CircleList_Insert(list, (CircleListNode*)&v4, CircleList_Length(list));
CircleList_Insert(list, (CircleListNode*)&v5, 5);
CircleList_Delete(list, 0);
for (i = 0; i<2 * CircleList_Length(list); i++)
{
struct Value* pv = (struct Value*)CircleList_Get(list, i);
printf("%d\n", pv->v);
}
printf("\n");
while (CircleList_Length(list) > 0)
{
struct Value* pv = (struct Value*)CircleList_Delete(list, 0);
printf("%d\n", pv->v);
}
printf("aloha\n");
CircleList_Destroy(list);
system("pause");
return;
}
优点:功能强了。
缺点:
代码复杂度提高了
n 个人围成一个圆圈,首先第 1 个人从 1 开始一个人一个人顺时针报数,报到第 m 个人,令其出列。然后再从下一 个人开始从 1 顺时针报数,报到第 m 个人,再令其出列,…,如此下去,求出列顺序。
#include "CircleList.h"
struct Value
{
CircleListNode header;
int v;
};
void main()
{
int i = 0;
CircleList* list = CircleList_Create();
struct Value v1, v2, v3, v4, v5, v6, v7, v8;
v1.v = 1; v2.v = 2; v3.v = 3; v4.v = 4;
v5.v = 5; v6.v = 6; v7.v = 7; v8.v = 8;
CircleList_Insert(list, (CircleListNode*)&v1, CircleList_Length(list));
CircleList_Insert(list, (CircleListNode*)&v2, CircleList_Length(list));
CircleList_Insert(list, (CircleListNode*)&v3, CircleList_Length(list));
CircleList_Insert(list, (CircleListNode*)&v4, CircleList_Length(list));
CircleList_Insert(list, (CircleListNode*)&v5, CircleList_Length(list));
CircleList_Insert(list, (CircleListNode*)&v6, CircleList_Length(list));
CircleList_Insert(list, (CircleListNode*)&v7, CircleList_Length(list));
CircleList_Insert(list, (CircleListNode*)&v8, CircleList_Length(list));
for (i = 0; i < CircleList_Length(list); i++)
{
//获取游标所指元素,然后游标下移
struct Value* pv = (struct Value*)CircleList_Next(list);
printf("%d\n", pv->v);
}
printf("\n");
//重置游标
CircleList_Reset(list);
while (CircleList_Length(list) > 0)
{
struct Value* pv = NULL;
for (i = 1; i < 3; i++)
{
CircleList_Next(list);
}
pv = (struct Value*)CircleList_Current(list);
printf("%d\n", pv->v);
CircleList_DeleteNode(list, (CircleListNode*)pv);
}
CircleList_Destroy(list);
system("pause");
return;
}