循环链表设计与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 ...
随机推荐
- Spring Security 基础登录实例
1 新建Java Web项目 导入Jar: 2 修改web.xml <?xml version="1.0" encoding="UTF-8"?> & ...
- 异步请求引发的Chrome死锁
浏览器支持的并发异步请求数目是有限的,当需要的资源过多时候(远远大于并发数目),就需要自己管理XHR请求. 在实现自己的XHR的Manger时候,当请求数目达到2000多的时候,经常会遇到chrome ...
- 亲密接触Redis-第三天(Redis的Load Balance)
前言 上两天讲述了Redis的基本搭建和基于HA的集群布署方式以及相关的策略和注意点.今天开始讲述Redis的Cluster功能,而这块目前来说网上资料不是太全,就算有1,2篇也只是单讲服务端的搭建也 ...
- SuperVideo,一款直播,点播,投屏并有的app
应用名称:SuperVideo应用简介: 1.聚合海量视频,视频源来源于搜狐,乐视,优酷, 腾讯等主流视频网站的丰富视频内容,最新院线大片,热播剧随时看 2.基于百度云解码,享受云解码支持RMVB,M ...
- 传Lua对象到Cpp
传Lua对象到Cpp (金庆的专栏) 摘自:http://raycast.net/lua-intf 以下代码演示了Lua函数和表传入Cpp进行处理: std::string acceptStuff(L ...
- [nginx]统计文件下载是否完整思路(flask)
有一个需求是统计文件是否被用户完整下载,因为是web应用,用js没有找到实现方案,于是搜索下nginx的实现方案,把简单的探索过程记录下. 实验一 最原始的思路,查看日志,下载了一个文件之后我们看日志 ...
- JavaWeb 文件 上传 下载
文件上传下载对于一个网站来说,重要性不言而喻.今天来分享一个JavaWeb方式实现的文件上传下载的小例子. 项目依赖 项目目录 工作流程 文件上传 表单处的设置 服务器端 上传功能的实现 upload ...
- Dynamics CRM2013 流程拷贝
在CRM中工作流是一个非常不错的功能,在实际业务场景中能满足各种业务需求.在我们设置一个工作流的时候,同一个实体一个逻辑功能可能需要多个工作流来实现,而多个工作流的不同之处可能只是启动时间或者是步骤中 ...
- GC真正的垃圾:强、软、弱、和虚 对象
垃圾回收的基本思想就是判断一个对象是否可触及性,说白了就是判断一个对象是否可以访问,如果对象对引用了,说明对象正在被使用,如果发现对象没有被引用,说明对象已经不再使用了,不再使用的对象可以被回收,但是 ...
- The Chain Of Responsibility (1)
今天分享一下,设计模式中的责任链模式,其余的不过多叙述. 思路 在正式接触责任连之前,我们可以想象到的应该是一个链,链表?要处理一件事需要一个链似得?其实答案差不多就是这样.设计模式也都是从朴素的思维 ...