循环链表设计与API实现
基本概念
循环链表的定义:将单链表中最后一个数据元素的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; } // 若删除元素后链表长度为0 if (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; }
循环链表设计与API实现的更多相关文章
- Spring Boot入门系列(二十一)如何优雅的设计 Restful API 接口版本号,实现 API 版本控制!
前面介绍了Spring Boot 如何快速实现Restful api 接口,并以人员信息为例,设计了一套操作人员信息的接口.不清楚的可以看之前的文章:https://www.cnblogs.com/z ...
- Laravel5设计json api时候的一些道道
对于返回数据格式没规整的问题 在开发api的时候,这个问题是和客户端交涉最多的问题,比如一个user结构,返回的字段原本是个user_name的,它应该是string类型.但是呢,由于数据库设计这个字 ...
- 双向链表设计与API实现
为什么需要双向链表? 单链表的结点都只有一个指向下一个结点的指针 单链表的数据元素无法直接访问其前驱元素 逆序访问单链表中的元素是极其耗时的操作! 双向链表的定义 在单链表的结点中增加一个指向其前驱的 ...
- Flask 学习篇一: 搭建Python虚拟环境,安装flask,并设计RESTful API。
前些日子,老师给我看了这本书,于是便开始了Flask的学习 GitHub上的大神,于是我也在GitHub上建了一个Flask的项目. 有兴趣可以看看: https://github.com/Silen ...
- 设计 REST API 的13个最佳实践
写在前面 之所以翻译这篇文章,是因为自从成为一名前端码农之后,调接口这件事情就成为了家常便饭,并且,还伴随着无数的争论与无奈.编写友好的 restful api 不论对于你的同事,还是将来作为第三方服 ...
- 使用 Python 和 Flask 设计 RESTful API
近些年来 REST (REpresentational State Transfer) 已经变成了 web services 和 web APIs 的标配. 在本文中我将向你展示如何简单地使用 Pyt ...
- 13 个设计 REST API 的最佳实践
原文 RESTful API Design: 13 Best Practices to Make Your Users Happy 写在前面 之所以翻译这篇文章,是因为自从成为一名前端码农之后,调接口 ...
- 学习设计接口api(转)
介绍 先说说啥是 Api 吧,以下摘自百度百科: API (Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于 ...
- Spring Boot Security 整合 OAuth2 设计安全API接口服务
简介 OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版.本文重点讲解Spring Boot项目对OAuth2进行的实现,如果你对OAut ...
随机推荐
- SpringBatch简介
spring Batch是一个轻量级的.完善的批处理框架,旨在帮助企业建立健壮.高效的批处理应用.SpringBatch是Spring的一个子项目,使用Java语言并基于Spring框架为基础开发,使 ...
- Dubbo框架应用之(四)--Dubbo基于Zookeeper实现分布式实例
上三篇文章主要是解决了概念性的补充和学习,充分结合实战来深入理解 入门实例解析 第一:provider-提供服务和相应的接口 创建DemoService接口 package com.unj.dubbo ...
- Android倒计时器——CountDownTimer
Android倒计时器--CountDownTimer 说明 第一个参数是倒计时的时间 第二个参数是多长时间执行一次回调 /** * @param millisInFuture The number ...
- EBS业务学习之应付管理
应付款系统是供应链管理的最后一个环节,它使公司能够支付供应商提供的货物和服务的费用.供应链管理的目标是保持低库存量但又有充足的存货以满足要求,仓库中的库存就等于钱,因此,应付款管理的目标是尽可能地推迟 ...
- SpriteKit游戏Delve随机生成地牢地图一个Bug的修复
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) Delve是一个很有意思的地牢探险类型的游戏,其中每一关的地图 ...
- android 网络获取json并且显示(2)
1.将要的取得的json数据格式如下: 我们封装之前的类用google提供的JSONArray和JSONObject类对json字符串进行解析. 对于姚明显示每一条数据,我们封装了一个类如下: pub ...
- mysql进阶(二十七)数据库索引原理
mysql进阶(二十七)数据库索引原理 前言 本文主要是阐述MySQL索引机制,主要是说明存储引擎Innodb. 第一部分主要从数据结构及算法理论层面讨论MySQL数据库索引的数理基础. ...
- actionbar详解(二)
经过前面两篇文章的学习,我想大家对ActionBar都已经有一个相对较为深刻的理解了.唯一欠缺的是,前面我们都只是学习了理论知识而已,虽然知识点已经掌握了,但是真正投入到项目实战当中时会不会掉链子还很 ...
- Xcode7.2如何真机调试iOS 9.3的设备
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 本猫的mac系统为10.10,Xcode版本为7.2 本猫将i ...
- numpy教程:排序、搜索和计数
http://blog.csdn.net/pipisorry/article/details/51822775 numpy排序.搜索和计数函数和方法.(重新整合过的) ],, , ], [, , ]] ...