循环链表实现与约瑟夫问题

循环链表API函数头文件

circlelist.h

#pragma once

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);

CircleListNode* CircleList_Get(CircleList* list, int pos);

int CircleList_Insert(CircleList* list, CircleListNode* node, int pos);

CircleListNode* CircleList_Delete(CircleList* list, int pos);

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

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

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

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

circlelist.cpp

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "circlelist.h"

typedef struct _tag_CircleList
{
	int length;
	CircleListNode header;	//链表的头部
	CircleListNode* slider;		//循环链表新增功能:游标
}TCircleList;		//定义一个底层的句柄

CircleList* CircleList_Create()
{
	TCircleList* ret = (TCircleList*)malloc(sizeof(TCircleList));
	memset(ret, 0, sizeof(TCircleList));

	ret->length = 0;
	ret->header.next = NULL;	//链表头部指向的下一个为NULL
	ret->slider = NULL;
	return ret;
}

void CircleList_Destroy(CircleList* list)	//释放内存
{
	if (list != NULL)
	{
		free(list);
		list = NULL;
	}
}

void CircleList_Clear(CircleList* list)	//初始化
{
	TCircleList* sList = NULL;
	if (list == NULL)
	{
		return;
	}
	sList = (TCircleList*)list;
	sList->length = 0;
	sList->header.next = NULL;
	sList->slider = NULL;
}

int CircleList_Length(CircleList* list)
{
	int ret = 0;
	TCircleList* sList = NULL;
	if (list == NULL)
	{
		ret = -1;
		printf("func CircleList_Length() err: %d\n", ret);
		return ret;
	}
	sList = (TCircleList*)list;
	ret = sList->length;
	return ret;
}

CircleListNode* CircleList_Get(CircleList* list, int pos)
{
	int i = 0;
	CircleListNode* ret = NULL;
	TCircleList* sList = NULL;
	CircleListNode* current;
	if (list == NULL || pos < 0)
	{
		printf("func CircleList_Get() err: %d\n", ret);
		return ret;
	}
	sList = (TCircleList*)list;

	current = &(sList->header);
	for (i = 0; i < pos && (current->next != NULL); i++)
	{
		current = current->next;	//跳pos次,让current指向插入位置前节点
	}
	ret = current->next;
	return ret;
}

int CircleList_Insert(CircleList* list, CircleListNode* node, int pos)
{
	int ret = 0, i = 0;
	TCircleList* sList = NULL;
	CircleListNode* current;
	CircleListNode* last = NULL;	//第二个辅助指针变量
	if (list == NULL || node == NULL || pos < 0)
	{
		ret = -2;
		printf("func CircleList_Insert() err: %d\n", ret);
		return ret;
	}
	sList = (TCircleList*)list;
	current = &(sList->header);	
	//和CircleListNode* current=(CircleListNode*)sList一样,因为函数入口地址重叠
	for (i = 0; i < pos && (current->next != NULL); i++)	
	{
		current = current->next;
	}
	//1 让node连接后续链表
	node->next = current->next;	
	//2 让前面的节点连接到新的node结点
	current->next = node;

	//如果插入的是第一个结点,让游标指向它
	if (sList->length == 0)
	{
		sList->slider = node;
	}

	sList->length++;

	//若是头插法,需求出尾部结点;判断是头插法
	//if (current == (CircleListNode*)sList)  //一开始是这里出现了问题,尾结点和头结点没有连起来
	if (current == &(sList->header))
	{
		last = CircleList_Get(sList, sList->length - 1);
		last->next = current->next;		//3 尾结点连接头结点
	}
	return ret;
}

CircleListNode* CircleList_Delete(CircleList* list, int pos)
{
	int i = 0;
	CircleListNode* ret = NULL;
	TCircleList* sList = NULL;
	CircleListNode* current;
	CircleListNode* last = NULL;	//第二个辅助指针变量
	if (list == NULL || pos < 0)
	{
		printf("func CircleList_Delete() err: %d\n", ret);
		return ret;
	}
	sList = (TCircleList*)list;

	current = &(sList->header);		
	for (i = 0; i < pos && (current->next != NULL); i++)
	{
		current = current->next;	
	}

	//若删除头结点,需求出尾部结点;判断
	//if (current == (CircleListNode*)sList)
	if (current == &(sList->header))
	{
		last = CircleList_Get(list, sList->length - 1);	//求的是删除前的最后结点
	}

	//1 缓存被删除的节点位置
	ret = current->next;
	//2 连接
	current->next = ret->next;
	sList->length--;

	若删除头结点,需求出尾部结点;判断
	//if (current == (CircleListNode*)sList)
	//{
	//	last = CircleList_Get(list, sList->length - 1);
	//}

	//判断没有全部删除完
	if (last != NULL)
	{
		sList->header.next = ret->next;		//这个应该是和2重复的了
		last->next = ret->next;
	}

	//若删除的是游标指向的元素,让游标下移
	if (sList->slider == ret)
	{
		sList->slider = ret->next;
	}

	//全部删除完
	if (sList->length == 0)
	{
		sList->header.next = NULL;
		sList->slider = NULL;
	}
	return ret;
}

//将游标重置指向链表中的第一个数据元素
CircleListNode* CircleList_Reset(CircleList* list)
{
	CircleListNode* ret = NULL;
	TCircleList* sList = NULL;
	if (list == NULL)
	{
		printf("func CircleList_Reset() err: %d\n", ret);
		return ret;
	}
	sList = (TCircleList*)list;
	sList->slider = sList->header.next;
	ret = sList->slider;
	return ret;
}

//获取当前游标指向的数据元素
CircleListNode* CircleList_Current(CircleList* list)
{
	CircleListNode* ret = NULL;
	TCircleList* sList = NULL;
	if (list == NULL)
	{
		printf("func CircleList_Current() err: %d\n", ret);
		return ret;
	}
	sList = (TCircleList*)list;
	ret = sList->slider;	//直接返回游标
	return ret;
}

//将游标移动指向到链表中的下一个数据元素
CircleListNode* CircleList_Next(CircleList* list)
{
	CircleListNode* ret = NULL;
	TCircleList* sList = NULL;
	if (list == NULL)
	{
		printf("func CircleList_Next() err: %d\n", ret);
		return ret;
	}
	sList = (TCircleList*)list;

	//ret = sList->slider;	//直接返回游标
	//sList->slider = ret->next;

	if (sList->slider != NULL)
	{
		ret = sList->slider;	//直接返回游标
		sList->slider = ret->next;
	}

	return ret;
}

//直接指定删除链表中的某个数据元素
CircleListNode* CircleList_DeleteNode(CircleList* list, CircleListNode* node)
{
	int i = 0;
	CircleListNode* ret = NULL;
	TCircleList* sList = NULL;
	CircleListNode* current;
	CircleListNode* last;	//第二个辅助指针变量
	if (list == NULL || node == NULL)
	{
		printf("func CircleList_DeleteNode() err: %d\n", ret);
		return ret;
	}
	sList = (TCircleList*)list;
	current = &(sList->header);

	//遍历
	for (i = 0; i < sList->length; i++)
	{
		if (current->next == node)
		{
			ret = current->next;
			break;
		}
		current = current->next;
	}

	if (ret != NULL)
	{
		CircleList_Delete(sList, i);		//根据位置删除
	}
	return ret;
}

测试框架与约瑟夫问题(m=3)

约瑟夫问题-循环链表典型应用

n 个人围成一个圆圈,首先第 1 个人从 1 开始一个人一个人顺时针报数,报到第 m 个人,令其出列。然后再从下一 个人开始从 1 顺时针报数,报到第 m 个人,再令其出列,…,如此下去,求出列顺序。

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "circlelist.cpp"

typedef struct _Value
{
	CircleListNode circlenode;	
	int v;
}Value;

void main()
{
	int ret = 0, i = 0;
	CircleList* list = NULL;

	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;

	list = CircleList_Create();//创建线性表
	if (list == NULL)
	{
		ret = -3;
		printf("func CircleList_Create() ret:%d \n", ret);
		return;
	}

	ret = CircleList_Insert(list, (CircleListNode*)&v1, CircleList_Length(list));	//尾插法
	ret = CircleList_Insert(list, (CircleListNode*)&v2, CircleList_Length(list));	//尾插法
	ret = CircleList_Insert(list, (CircleListNode*)&v3, CircleList_Length(list));	//尾插法
	ret = CircleList_Insert(list, (CircleListNode*)&v4, CircleList_Length(list));	//尾插法
	ret = CircleList_Insert(list, (CircleListNode*)&v5, CircleList_Length(list));	//尾插法
	ret = CircleList_Insert(list, (CircleListNode*)&v6, CircleList_Length(list));	//尾插法
	ret = CircleList_Insert(list, (CircleListNode*)&v7, CircleList_Length(list));	//尾插法
	ret = CircleList_Insert(list, (CircleListNode*)&v8, CircleList_Length(list));	//尾插法

	//使用游标来遍历
	for (i = 0; i < CircleList_Length(list); i++)
	{
		Value* pv = (Value*)CircleList_Next(list);	//一开始的游标值不应该为NULL?
		printf("pv->v: %d\n", pv->v);
	}
	CircleList_Reset(list);	//重置游标

	//此处用来判断出现 pv 是 nullptr 现象的原因,所以上面一开始应该遍历2遍看是不是循环链表
	//Value* pv = NULL;
	//for (i = 0; i < 8; i++)		
	//{
	//	CircleList_Next(list);
	//}
	//pv = (Value*)CircleList_Current(list);
	//printf("pv->v: %d\n", pv->v);	//pv 是 nullptr,说明尾端的next没有指向头部


	//删除元素
	printf("\n约瑟夫问题输出:\n");
	while (CircleList_Length(list) > 0)	
	{
		Value* pv = NULL;

		for (i = 1; i < 3; i++)		//实现约瑟夫问题 从1数到3,令3出列
		{
			CircleList_Next(list);
		}
		pv = (Value*)CircleList_Current(list);

		printf("pv->v: %d\n", pv->v);	//pv 是 nullptr
		CircleList_DeleteNode(list, (CircleListNode*)pv);
	}

	CircleList_Destroy(list);

	system("pause");
}

经验教训:

  1. 一开始测试时应该先遍历2遍证明其是否是循环链表。
  2. 教程里虽然说  current = &(sList->header)  和  CircleListNode* current=(CircleListNode*)sList 一样,因为函数入口地址重叠;但是程序上使用时应该是不要交叉混用,开始赋值和作判断条件使用时应该统一用 current = &(sList->header) 或另一个
  3. 调试的时候真的要耐心,一步一步的来,不要着急,细心地去发现问题、理解问题并解决问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值