循环链表的设计与实现
循环链表定义: 将单链表中最后一个数据元素中的next指针指向第一个元素。
循环链表的设计
定义一个结构体用来存储指针与指针之间的关系:
typedef struct _tag_CircleListNode
{
struct _tag_CircleListNode *next;
}CircleListNode;
定义一个头结点用来存储链表:
typedef struct _tag_CircleList
{
CircleListNode header;
CircleListNode *slider; //游标
int length;
}TCircleList;
数据元素定义实例:
struct Value
{
CircleListNode node;
int v;
};
循环链表新增功能: 游标
游标的意义: 在循环链表中,可以定义”当前指针”。这个指针通过游标来遍历链表中的所有元素。
循环链表新增的操作
(1)获取当前游标指向的数据元素;
(2)将游标重置指向到链表第一元素;
(3)将游标移动到链表中的下一个数据元素;
(4)将游标移动到链表中的下一个数据元素。
循环链表重要算法
- 循环链表的插入算法
- 第一个位置插入元素
- 普通位置插入元素
- 添加第一个元素(第一次插入)
- 最后一个位置插入元素
- 第一个位置插入元素
- 循环链表的删除算法
- 普通位置(包含末尾)删除
- 删除第一个元素
- 普通位置(包含末尾)删除
循环链表优点、缺点与应用
优点:
(1)循环链表在单链表的基础上做了一个增强;
(2)循环链表可以完全取代单链表的使用;
(3)循环链表的Next和Current操作可以更高效地遍历链表中的所有元素。
缺点: 代码复杂度提高了。
应用:
约瑟夫问题: n 个人围成一个圆圈,首先第 1 个人从 1 开始一个人一个人顺时针报数,报到第 m 个人,令其出列。然后再从下一 个人开始从 1 顺时针报数,报到第 m 个人,再令其出列,…,如此下去,求出列顺序。
循环链表的实现
- CircleList.h
#ifndef _CIRCLELIST_H_
#define _CIRCLELIST_H_
typedef void CircleList;
typedef struct _tag_CircleListNode
{
struct _tag_CircleListNode *next;
}CircleListNode;
//创建链表
CircleList * CircleList_Create();
//销毁链表
void CircleList_Destroy(CircleList *list);
//获取链表长度
int CircleList_Length(CircleList *list);
//清空链表
void CircleList_Clear(CircleList *list);
//获取pos个位置的元素的操作
CircleListNode * CircleList_Get(CircleList *list, int pos);
//插入元素到位置pos
int CircleList_Insert(CircleList* list, CircleListNode *node, int pos);
//删除位置pos处的元素
CircleListNode * CircleList_Delete(CircleList *list, int pos);
//add
//获取当前游标指向的数据元素
CircleListNode * CircleList_Current(CircleList *list);
//将游标重置指向到链表中的第一个元素
CircleListNode * CircleList_Reset(CircleList *list);
//将游标移动到链表中的下一个元素的位置
CircleListNode * CircleList_Next(CircleList *list);
//直接指定删除链表中某个数据元素
CircleListNode* CircleList_DeleteNode(CircleList *list, CircleListNode * node);
#endif
- CircleList.c
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include "CircleList.h"
typedef struct _tag_CircleList
{
CircleListNode header;
CircleListNode *slider; //游标
int length;
}TCircleList;
//创建链表
CircleList * CircleList_Create()//O(1)
{
TCircleList* ret = (TCircleList*)malloc(sizeof(TCircleList));
if (ret == NULL)
{
return NULL;
}
ret->length = 0;
ret->slider = NULL;
ret->header.next = NULL;
return ret;
}
//销毁链表
void CircleList_Destroy(CircleList *list)//O(1)
{
if (list == NULL)
{
return;
}
free(list);
return ;
}
//获取链表长度
int CircleList_Length(CircleList *list)//O(1)
{
TCircleList *tList = (TCircleList *)list;
int ret = -1;
if (list == NULL)
{
return ret;
}
ret = tList->length;
return ret;
}
//清空链表
void CircleList_Clear(CircleList *list)//O(1)
{
TCircleList *sList = (TCircleList *)list;
if (sList == NULL)
{
return;
}
sList->length = 0;
sList->slider = NULL;
sList->header.next = NULL;
return ;
}
//获取pos个位置的元素的操作
CircleListNode * CircleList_Get(CircleList *list, int pos)//O(n)
{
TCircleList * sList = (TCircleList *)list;
CircleListNode *ret = NULL;
int i = 0;
if (list == NULL || pos < 0)
{
return NULL;
}
CircleListNode *current = (CircleListNode *)sList;
for (i = 0;i < pos;i++)
{
current = current->next;
}
ret = current->next;
return ret;
}
//插入元素到位置pos
int CircleList_Insert(CircleList* list, CircleListNode *node, int pos)//O(n)
{
int ret = 0, i = 0;
TCircleList *sList = (TCircleList *)list;
if (list == NULL || node == NULL || pos < 0)
{
return -1;
}
CircleListNode *current = (CircleListNode *)sList;
for (i = 0;(i < pos) && (current->next != NULL);i++)
{
current = current->next;
}
//current->next 0号结点的地址
node->next = current->next;//1
current->next = node;//2
//若第一次插入结点
if (sList->length == 0)
{
sList->slider = node;
}
sList->length++;
//若头插法 current 仍然指向头部
//(原因是: 跳0步,没有跳走)
if (current == (CircleListNode *)sList)
{
//获取最后一个元素
CircleListNode *last = CircleList_Get(sList, sList->length - 1);
last->next = current->next;//3
}
return ret;
}
//删除位置pos处的元素
CircleListNode * CircleList_Delete(CircleList *list, int pos)//O(n)
{
TCircleList *sList = (TCircleList *)list;
CircleListNode *ret = NULL;
int i = 0;
if ((sList != NULL) && (pos >= 0) && (sList->length > 0))
{
// CircleListNode * current = (CircleListNode *)(&(sList->header));
CircleListNode * current = (CircleListNode *)sList;
CircleListNode * last = NULL;
for (i = 0;i < pos;i++)
{
current = current->next;
}
//若删除的是第一个元素(头结点)
if (current == (CircleListNode *)sList)
{
last = (CircleListNode *)CircleList_Get(sList, sList->length - 1);
}
//求要删除的元素
ret = current->next;
current->next = ret->next;//1
sList->length--;
//判断链表是否为空
if (last != NULL)
{
sList->header.next = ret->next;
last->next = ret->next;//2
}
//若删除的元素 为游标所指的元素
if (sList->slider == ret)
{
sList->slider = ret->next;
}
//若删除元素后,链表的长度为0
if (sList->length == 0)
{
sList->header.next = NULL;
sList->slider = NULL;
}
}
return ret;
}
//add
//获取当前游标指向的数据元素
CircleListNode * CircleList_Current(CircleList *list)//O(1)
{
TCircleList *sList = (TCircleList *)list;
CircleListNode *ret = NULL;
if (sList != NULL)
{
ret = sList->slider;
}
return ret;
}
//将游标重置指向到链表中的第一个元素
CircleListNode * CircleList_Reset(CircleList *list)//O(1)
{
TCircleList *sList = (TCircleList *)list;
CircleListNode *ret = NULL;
if (sList != NULL)
{
sList->slider = sList->header.next;
ret = sList->slider;
}
return ret;
}
//将游标移动到链表中的下一个元素的位置
CircleListNode * CircleList_Next(CircleList *list)//O(1)
{
TCircleList *sList = (TCircleList *)list;
CircleListNode *ret = NULL;
if ((sList != NULL) && (sList->slider != NULL))
{
ret = sList->slider;
sList->slider = ret->next;
}
return ret;
}
//直接指定删除链表中某个数据元素
CircleListNode* CircleList_DeleteNode(CircleList *list, CircleListNode * node)//O(n)
{
TCircleList *sList = (TCircleList *)list;
CircleListNode *ret = NULL;
int i = 0;
if (sList != NULL)
{
CircleListNode *current = (CircleListNode *)sList;
//查找node在循环链表中的位置
for (i = 0;i < sList->length;i++)
{
if (current->next == node)
{
ret = current->next;
break;
}
current = current->next;
}
//如果ret找到,根据i去删除
if (ret != NULL)
{
CircleList_Delete(sList, i);
}
}
return ret;
}
- 循环链表求解约瑟夫问题
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include "CircleList.h"
struct Value
{
CircleListNode node;
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));
printf("获取元素:");
for (i = 0;i < CircleList_Length(list);i++)
{
//获取游标所指所元素,然后游标下移
struct Value *tmp = (struct Value *)CircleList_Next(list);
printf("%d\t", tmp->v);
}
printf("\n");
//重置游标
CircleList_Reset(list);
while (CircleList_Length(list)>0)
{
struct Value * tmp = NULL;
for (i = 1;i < 3;i++)
{
CircleList_Next(list);
}
tmp = (struct Value *)CircleList_Current(list);
printf(" 删除%d\t", tmp->v);
CircleList_DeleteNode(list, (CircleListNode *)tmp);
}
CircleList_Destroy(list);
printf("\n");
system("pause");
return;
}
- 约瑟夫问题求解结果