基本概念
循环链表的定义:将单链表中最后一个数据元素的next指针指向第一个元素

循环链表拥有单链表的全部操作

创建链表
销毁链表
获取链表长度
清空链表
获取第pos个元素操作
插入元素到位置pos
删除位置pos处的元素

新增功能:游标的定义

在循环链表中能够定义一个“当前”指针,这个指针通常称为游标,能够通过这个游标来遍历链表中的全部元素。

循环链表新操作

将游标重置指向链表中的第一个数据元素
CircleListNode* CircleList_Reset(CircleList* list);

获取当前游标指向的数据元素
CircleListNode* CircleList_Current(CircleList* list);

将游标移动指向到链表中的下一个数据元素
CircleListNode* CircleList_Next(CircleList* list);

直接指定删除链表中的某个数据元素
CircleListNode* CircleList_DeleteNode(CircleList* list, CircleListNode* node);
// 依据元素的值 删除 元素 pk依据元素的位置 删除 元素

最后加了一个循环链表的应用:求解约瑟夫问题

约瑟夫问题-循环链表典型应用
n 个人围成一个圆圈,首先第 1 个人从 1 開始一个人一个人顺时针报数,报到第 m 个人,令其出列。

然后再从下一 个人開始从 1 顺时针报数,报到第 m 个人。再令其出列,…。如此下去,求出列顺序。

代码:

// circlelist.h
// 循环链表API声明#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);// 清空链表
void CircleList_Clear(CircleList* list);// 获取链表的长度
int CircleList_Length(CircleList* list);// 在pos位置插入结点node
int CircleList_Insert(CircleList* list,CircleListNode* node, int pos);// 获取pos位置的结点
CircleListNode* CircleList_Get(CircleList* list, int pos);// 删除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
// circlelist.cpp
// 循环链表API实现#include <iostream>
#include <cstdio>
#include "circlelist.h"typedef struct _tag_CircleList
{CircleListNode header;CircleListNode *silder;int length;
}TCircleList;// 创建链表
CircleList* CircleList_Create()
{TCircleList *ret = (TCircleList *)malloc(sizeof(TCircleList));if (ret == NULL) {return NULL;}// 初始化ret->header.next = NULL;ret->silder = NULL;ret->length = 0;return ret;
}// 销毁链表
void CircleList_Destroy(CircleList* list)
{if (list == NULL) {return;}free(list);return;
}// 清空链表
void CircleList_Clear(CircleList* list)
{if (list == NULL) {return;}TCircleList *tList = (TCircleList *)list;tList->header.next = NULL;tList->silder = NULL;tList->length = 0;return;
}// 获取链表的长度
int CircleList_Length(CircleList* list)
{if (list == NULL) {return -1;}TCircleList *tList = (TCircleList *)list;return tList->length;
}// 在pos位置插入结点node
int CircleList_Insert(CircleList* list, CircleListNode* node, int pos)
{if (list == NULL || node == NULL || pos < 0) {return -1;}TCircleList *tList = (TCircleList *)list;CircleListNode *cur = (CircleListNode *)tList;for (int i = 0; i < pos; ++i) {cur = cur->next;}node->next = cur->next;cur->next = node;// 假设是第一次插入if (tList->length == 0) {tList->silder = node;}++tList->length; // 记得长度加1// 假设是头插法if (cur == (CircleListNode *)tList) {// 获取最后一个元素CircleListNode *last = CircleList_Get(tList, tList->length - 1);last->next = cur->next;}return 0;
}// 获取pos位置的结点
CircleListNode* CircleList_Get(CircleList* list, int pos)
{// 由于是循环链表,所以这里不须要排除pos>length的情况if (list == NULL || pos < 0) {return NULL;}TCircleList *tList = (TCircleList *)list;CircleListNode *cur = (CircleListNode *)tList;for (int i = 0; i < pos; ++i) {cur = cur->next;}return cur->next;
}// 删除pos位置的结点
CircleListNode* CircleList_Delete(CircleList* list, int pos)
{TCircleList *tList = (TCircleList *)list;CircleListNode *ret = NULL;if (tList != NULL && pos >= 0 && tList->length > 0) {CircleListNode *cur = (CircleListNode *)tList;for (int i = 0; i < pos; ++i) {cur = cur->next;}// 若删除头结点,须要求出尾结点CircleListNode *last = NULL;if (cur == (CircleListNode *)tList)  {last = CircleList_Get(tList, tList->length - 1);}ret = cur->next;cur->next = ret->next;--tList->length;// 若删除头结点if (last != NULL) {tList->header.next = ret->next;last->next = ret->next;}// 若删除的元素为游标所指的元素if (tList->silder == ret) {tList->silder = ret->next;}// 若删除元素后链表长度为0if (tList->length == 0) {tList->header.next = NULL;tList->silder = NULL;}}return ret;
}// 依据结点的值进行数据删除
CircleListNode* CircleList_DeleteNode(CircleList* list, CircleListNode* node)
{TCircleList *tList = (TCircleList *)list;CircleListNode *ret = NULL;if (list != NULL && node != NULL) {CircleListNode *cur = (CircleListNode *)tList;int i = 0;for (i = 0; i < tList->length; ++i) {if (cur->next == node) {ret = cur->next;break;}cur = cur->next;}// 假设找到if (ret != NULL) {CircleList_Delete(tList, i);}}return ret;
}// 重置游标
CircleListNode* CircleList_Reset(CircleList* list)
{TCircleList *tList = (TCircleList *)list;CircleListNode* ret = NULL;if (list != NULL) {tList->silder = tList->header.next;ret = tList->silder;}return NULL;
}// 获取当前游标所指结点
CircleListNode* CircleList_Current(CircleList* list)
{TCircleList *tList = (TCircleList *)list;CircleListNode* ret = NULL;if (list != NULL) {ret = tList->silder;}return ret;
}// 将原始游标所指结点返回给上层,然后让游标移到下一个结点
CircleListNode* CircleList_Next(CircleList* list)
{TCircleList *tList = (TCircleList *)list;CircleListNode* ret = NULL;if (list != NULL && tList->silder != NULL) {ret = tList->silder;tList->silder = ret->next;}return ret;
}
// joseph.h
// 用循环链表API求解约瑟夫问题#include <cstdio>
#include "circlelist.h"const int maxp = 8;struct Person
{CircleListNode circlenode;int id;
};void joseph()
{Person s[maxp];for (int i = 0; i < maxp; ++i) {s[i].id = i + 1;}CircleList *list = NULL;list = CircleList_Create();// 插入元素for (int i = 0; i < maxp; ++i) {// 尾插法int ret = CircleList_Insert(list, (CircleListNode *)&s[i], CircleList_Length(list));if (ret < 0) {printf("function CircleList_Insert err: %d\n", ret);}}// 遍历链表for (int i = 0; i < CircleList_Length(list); ++i) {Person *tmp = (Person *)CircleList_Get(list, i);if (tmp == NULL) {printf("function CircleList_Get err.\n");}printf("age: %d\n", tmp->id);}// 求解约瑟夫问题while (CircleList_Length(list) > 0){Person* pv = NULL;for (int i = 1; i < 3; i++){CircleList_Next(list);}pv = (Person*)CircleList_Current(list);printf("%d ", pv->id);CircleList_DeleteNode(list, (CircleListNode *)pv); //依据结点的值,进行结点元素的删除}printf("\n");CircleList_Destroy(list);}
// main.cpp
// 循环链表測试程序#include <iostream>
#include <cstdio>
#include "circlelist.h"
#include "joseph.h"const int maxn = 5;struct Student
{CircleListNode circlenode;char name[32];int age;
};void play01()
{Student s[maxn];for (int i = 0; i < maxn; ++i) {s[i].age = i + 1;}CircleList *list = NULL;list = CircleList_Create(); // 创建链表// 插入元素for (int i = 0; i < maxn; ++i) {// 尾插法int ret = CircleList_Insert(list, (CircleListNode *)&s[i], CircleList_Length(list));if (ret < 0) {printf("function CircleList_Insert err: %d\n", ret);}}// 遍历链表// 这里遍历打印两边,能够证明这是一个循环链表for (int i = 0; i < 2 * CircleList_Length(list); ++i) {Student *tmp = (Student *)CircleList_Get(list, i);if (tmp == NULL) {printf("function CircleList_Get err.\n");}printf("age: %d\n", tmp->age);}// 删除结点,通过结点位置while (CircleList_Length(list)) {Student *tmp = (Student *)CircleList_Delete(list, CircleList_Length(list) - 1);if (tmp == NULL) {printf("function CircleList_Delete err.\n");}printf("age: %d\n", tmp->age);}// 销毁链表CircleList_Destroy(list);}int main()
{play01(); // 为了測试数据的生命周期,所以另写一个函数调用执行joseph();return 0;
}

转载于:https://www.cnblogs.com/jzssuanfa/p/7156802.html

循环链表设计与API实现相关推荐

  1. java api 设计_Java API设计实践

    使你的API在模块化和非模块化Java环境中都可用 在优锐课的java学习分享中,对微服务有了更深层次的新概念.关于API设计实践一点就通了. 介绍 了解设计Java API时应应用的一些API设计实 ...

  2. api怎么写_月薪几十K 的人是怎么设计REST API

    前言 作为一名优秀的后端程序员,你照着产品需求设计好了模型,设计好了关联关系. 把这些模型和关系一再打磨了一番之后,你想是时候把API设计出来,与前端沟通了. 这时候问题来了: 一旦 API 进入前端 ...

  3. 设计优秀API的五大规则

    人们在如何设计一款优秀的API上有着很强烈的意识.在互联网上有关API方面的网页和书籍有很多很多.本文我们将重点关注设计优秀API的规则. 规则就是当发生任何变化时,应当遵循"最小惊奇原则& ...

  4. 我去头条面试,面试官问我如何设计好API,看看我是如何吊打面试官的!

    作者 | 点击关注 ???? 来源 | Java开发宝典(ID:javakaifabaodian) 头图 | CSDN 下载自东方 IC "语言首先是写给人看的,只是恰巧(incidenta ...

  5. jOOQ是如何设计事务API(详细指南)

    从jOOQ 3.4开始,我们在jOOQ的JDBC之上有一个简化事务逻辑的API,从jOOQ 3.17和 #13502 开始,在R2DBC之上也将提供一个同等的API,用于反应式应用. 与所有的jOOQ ...

  6. 如何更好的设计RESTful API(创建公开API)

    https://zhuanlan.zhihu.com/p/24592119?utm_source=tuicool&utm_medium=referral 作者:知秋z 链接:https://z ...

  7. VBS 请求WebAPI接口_如何设计WEB API

    前言 我一直认为WEB API设计是后端工程师的活,对WEB API设计规范理解的不是很深,正是因为之前看过不同后端工程师的Web API设计难以对接前端产品,导致经常需要修改接口,浪费了很多时间,专 ...

  8. 如何设计一个API快速开发平台?

    点击上方☝码猿技术专栏 轻松关注,设为星标! 及时获取有趣有料的技术 来源:toutiao.com/i6914469326074479108/ 在我之前谈API网关的时候曾经谈到过快速开发平台,即将A ...

  9. 如何设计一个API接口

    在日常开发中,总会接触到各种接口.前后端数据传输接口,第三方业务平台接口.一个平台的前后端数据传输接口一般都会在内网环境下通信,而且会使用安全框架,所以安全性可以得到很好的保护.这篇文章重点讨论一下提 ...

最新文章

  1. CentOS7种搭建FTP服务器
  2. StatsD!次世代系统监控的核心
  3. [USACO08JAN]跑步Running
  4. 解决开机自检D盘问题
  5. 春天就是要搞技术啊!
  6. 深度学习(六)——CNN进化史
  7. php干扰函数,php – 类构造函数干扰另一个类
  8. C#浅拷贝与深拷贝区别
  9. kafka通过脚本一次启动集群
  10. 谈谈asp.net中的% %,%= %,%# %%$ %的使用
  11. Linux修改文件出现错误E45:“readonly” option is set(add ! to override)退出不了vim
  12. 存根类 Stub详解
  13. 基于ICP算法计算点集之间的变换矩阵(旋转、平移)
  14. python二元一次方程组用鸡兔同笼的思路来写编程_python二元一次方程组用鸡兔同笼的思路来写编程_《应用二元一次方程组——鸡兔同笼》......
  15. ROS从入门到精通5-5:局部路径规划插件开发案例(以DWA算法为例)
  16. Linux重启后硬盘挂载失效问题解决
  17. 高性能日志:如何提升日志性能避免 IO 瓶颈?
  18. 高新企业申报是什么?需要怎么申请?
  19. mybatis-plus存数组对象,并从数据库查出这个数组
  20. SQL Server个人笔记(1)

热门文章

  1. keras学习笔记-黑白照片自动着色的神经网络-Beta版
  2. 揭示地理数据分布规律的方法
  3. 实现API接口调用--来源阿里云大学-归档
  4. 8能达到go速度吗 php_相同逻辑的php与golang代码效率对比,最好语言落谁家…
  5. ibatis resultclass java.util.list_mybatis 动态sql返回一个List封装类报错求解决方法
  6. 网络安全人才短缺加剧,企业如何不拘一格降人才?
  7. python怎么安装pin库_Python库之numpy库的安装教程
  8. 在vscode中怎样debug调试go程序
  9. JavaScript中的call、apply、bind如何使用
  10. 112. Path Sum