循环链表设计与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;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-07 06:07:57

循环链表设计与API实现的相关文章

使用 Python 和 Flask 设计 RESTful API

近些年来 REST (REpresentational State Transfer) 已经变成了 web services 和 web APIs 的标配. 在本文中我将向你展示如何简单地使用 Python 和 Flask 框架来创建一个 RESTful 的 web service. 什么是 REST? 六条设计规范定义了一个 REST 系统的特点: 客户端-服务器: 客户端和服务器之间隔离,服务器提供服务,客户端进行消费. 无状态: 从客户端到服务器的每个请求都必须包含理解请求所必需的信息.换

基于Django RESTframework设计Restful API

导语 ? 关于RESTful的问题,在最近的面试中遇到很多,之前有过一定的了解,但没有系统性的总结分析.所以现在结合Django RESTframework来加深对RESTful的理解,同时梳理这过程的一些知识点. 什么是RESTful? ?这个问题是最容易想到的,首先要分析这个问题,网上的其他文章都会讲到有关REST(Representational State Transfer),中文翻译:"表述性状态传递",再白话一点就是对资源的表述性状态传递.刚开始,看到这里头都大了,那我们来

2、设计Web Api分层架构

一.创建Model层 using System; namespace SCM.API.MODEL { public partial class USR_MSTR { public string USR_USER { get; set; } public string USR_NAME { get; set; } public string USR_GROUP { get; set; } public string USR_DEPT { get; set; } public string USR_

api 设计 多api一起访问

查看了下别的api的返回示例 我选出这样的返回样式 { "resultcode":"200", "reason":"Successed!", "result":{ "count": 11, "commentlist": [] }, "notice"-. } 当前api访问的错误和原因加 非当前api的处理(比如notice 通知 注:来自开源中国i

从涂鸦到发布——理解API的设计过程(转)

英文原文:From Doodles to Delivery: An API Design Process 要想设计出可以正常运行的Web API,对基于web的应用的基本理解是一个良好的基础.但如果你的目标是创建出优秀的API,那么仅凭这一点还远远不够.设计优秀的API是一个艰难的过程,如果它恰巧是你当前的工作任务,那么你很可能会感到手足无措. 不过,优秀的设计绝对是可以实现的.本文所描述的流程将帮助你获得成功,我们将共同研究什么是优秀的设计,以及迭代式的流程如何帮助我们实现这一目标.我们还将叙

HTTP-API-DESIGN 怎样设计一个合理的 HTTP API (一)

这个附件的幻灯片是我最近给团队分享关于设计 HTTP API 的时候,结合 这篇 和我们团队历史上的一些错误,总结出来一些适合内部的经验. 简介. 这次分享主要关注以下几部分: HTTP + JSON API 的最佳实践 更关注 API 使用和概念上的一致性 这些使用上的经验,并不是最终的.唯一的解决方案 同时也无法处理任意环境中遇到的全部问题 同时还会举出一些 badcase,这些 badcase 一般是我负责的或者开发的服务中遇到的问题. 背景知识. 在 HTTP API 实践中,涉及到了以

用产品思维设计API(一)——RESTful就是个骗局

用产品思维设计API(一)--RESTful就是个骗局 前言 最近公司内部在重构项目代码,包括API方向的重构,期间遇到了很多的问题,不由得让我重新思考了下. - 一个优雅的API该如何设计? - 前后端分离之后,API真的解耦分离了吗? - 不断的版本迭代,API的兼容性该如何做? 年前,我司内部的接口已经进入了一个完全的重构阶段,参考了市面上各大平台的API和文档,自己也总结出了很多的心得.这里向大家分享一下,接下来一个月,我们向从下面几个方面向大家介绍一个优雅的API(至少我认为挺优雅)该

用产品思维设计API(二)——数据解耦,才是前后分离的本质

用产品思维设计API(二)--数据解耦,才是前后分离的本质 前言 最近公司内部在重构项目代码,包括API方向的重构,期间遇到了很多的问题,不由得让我重新思考了下. - 一个优雅的API该如何设计? - 前后端分离之后,API真的解耦分离了吗? - 不断的版本迭代,API的兼容性该如何做? ps.这里所说的API仅为Web API,提供APP\WEB开发使用. 年前,我司内部的接口已经进入了一个完全的重构阶段,参考了市面上各大平台的API和文档,自己也总结出了很多的心得.这里向大家分享一下,接下来

出色的 JavaScript API 设计秘诀

设计是一个很普遍的概念,一般是可以理解为为即将做的某件事先形成一个计划或框架. (牛津英语词典)中,设计是一种将艺术,体系,硬件或者更多的东西编织到一块的主线.软件设计,特别是作为软件设计的次类的API设计,也是一样的.但是API设计常常很少关注软件发展,因为为其他程序员写代码的重要性要次于应用UI设计和最终用户体验. 但是API设计,作为我们自己写的库中提供的公共接口,能够向调用我们代码的开发者表现出我们库的一些特点和功能,所以API设计和UI设计一样重要.事实上,两者都是为应用可以提供更好的