05数据结构与算法—双向循环链表解决约瑟夫问题

思路:

约瑟夫环问题:

约瑟夫环问题的一种描述是:编号为1.2.3…….n的n个人按顺时针方向围坐一圈

,每人手持一个密码(正整数),开始任意选一个整数作为报数上限值,从第一

个人开始顺时针自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密

码作为新的m值,从他顺时针下一个人开始重新从1开始报数,如此下去直到所有

的人全部都出列为止。

代码实现:

头文件.h

#pragma once
#include <iostream>
using namespace std;
//结点
typedef struct SNode {
	struct SNode *next;
}Snode;
typedef struct CircleList {
	Snode head;
	int size;
}Clist;
typedef void (*PRINT)(Snode*);
typedef int(*MYCOMPARE)(Snode*,Snode*);
Clist* init_Clist();//初始化链表
void insert_Clist(Clist *list,int pos,Snode *data);//插入
void deletevalue_Clist(Clist *list,Snode *data,MYCOMPARE myc);//按值删除
void deltepos_Clist(Clist *list,int pos);//按下标删除
void print_Clist(Clist *list,PRINT print);//打印链表
void Free_Clist(Clist *list);//摧毁内存
int findpos_Clist(Clist *list,Snode *data,MYCOMPARE myc);//按值返回下标

xxx.cpp

#include "Josephus.h"
//初始化链表
Clist* init_Clist() {
	Clist* list = (Clist*)malloc(sizeof(Clist));
	list->size = 0;
	list->head.next = &(list->head);//循环链表的特点!
	return list;
}
//插入
void insert_Clist(Clist* list, int pos, Snode* data) {
	if (list == NULL) {
		cout<<"链表未被创建!" << endl;
	}
	if (pos<0 || pos>list->size) {
		pos = list->size;
	}
	Snode* pre =&(list->head);
	for (int i = 0;i<pos;i++) {
		pre = pre->next;
	}
	Snode* pcur = pre->next;
	data->next = pcur;
	pre->next = data;
	list->size++;

}
//按值删除
void deletevalue_Clist(Clist* list, Snode* data, MYCOMPARE myc) {
	if (list == NULL) {
		cout<<"链表数据为空!" << endl;
	}
	Snode* Pre = &(list->head);
	Snode* pCur = list->head.next;
	for (int i = 0; i <list->size; i++) {
		if (myc(pCur,data)) {
			break;
		}
		Pre = pCur;//提前存放,起到防止错乱作用
		pCur = pCur->next;
	}
	//开始删除
	Pre->next = pCur->next;
	list->size--;

	/*Snode* pre =&(list->head);
	int pos = findpos_Clist(list,data,myc);
	for (int i = 0; i < pos;i++) {
		if (myc(data,pre) == 1) break;
			pre = pre->next;
	}
	Snode* pcur = pre->next;
	pre->next = pcur->next;
	list->size--;*/

}//按下标删除
void deltepos_Clist(Clist* list, int pos) {
	if (list == NULL) {
		cout<<"链表数据为空!" << endl;
	}
	Snode* pre = &(list->head);
	for (int i = 0;i<pos;i++) {
		pre = pre->next;
	}
	
	pre->next =pre->next->next;
	list->size--;
}//打印链表
void print_Clist(Clist* list, PRINT print) {
	Snode* node = list->head.next;
	for (int i = 0;i<list->size;i++) {
		print(node);
		node = node->next;
	}

}//摧毁内存
void Free_Clist(Clist* list) {
	if (list == NULL) {
		cout<<"链表数据已为空了!" << endl;
	}
	free(list);
	cout<<"内存已被摧毁!" << endl;
}

int findpos_Clist(Clist* list,Snode *data,MYCOMPARE myc)
{
	if (list == NULL) {
		cout<<"链表数据为空!" << endl;
	}
	Snode* node = list->head.next;
	for (int i = 0;i<list->size;i++) {
		if (myc(data, node) == 1) {
			return i;
		}
	}
	return 0;
}

主函数运行测试

#include "Josephus.h"
#define M 8
#define N 5
typedef struct MYnum {
	Snode node;
	int num;
}Mynum;
void print(Snode *data) {
	Mynum* Mnum = (Mynum*)data;
	cout << Mnum->num<<" ";

}
int myc(Snode *t1,Snode *t2) {
	Mynum* s1 = (Mynum*) t1;
	Mynum* s2 = (Mynum*)t2;
	if (s1->num == s2->num) return 1;
	else return 0;
}
void test() {
	Clist* list = init_Clist();
	Mynum num[8];
	for (int i = 0;i<M;i++) {
		num[i].num = i + 1;
		insert_Clist(list,0,(Snode*)&num[7-i]);
	}
	cout<<"双向循环链表数据值:";
	Snode* node =&(list->head);
	print_Clist(list,print);
	cout<<"\n进行约瑟夫循环问题被叫出排序为:" << endl;
	Snode* pCur = list->head.next;
	for (int i = 0; list->size != 1; i++) {
		for (int j = 0; j <N; j++) {
			node = node->next;
			if (node == &(list->head)) { node = node->next; }
		}
		print(node);
		cout << " ";

		deletevalue_Clist(list, node, myc);


	}
	cout<<"剩余的最后一个数为:";
	print_Clist(list, print);
	//int count = 1;     //记录那个人喊的数,用于判断是否与规定的数相等然后删除    并非是下标 
	//print_Clist(list, print);
	//while (list->size > 1) {
	//	if (count == N) {
	//	
	//		//可以先输出看看,但要先转有数据的类型
	//		Mynum* tmp =(Mynum*)pCur;
	//		printf("%2d",tmp->num);

	//		//按值删除
	//		//删除前保存下一节点
	//		Snode* pNext = pCur->next;
	//		deletevalue_Clist(list, pCur, myc);
	//		//clist->size--;// 不需要自行写,调用函数做了
	//		pCur = pNext;
	//		//若是头结点,则指向下一节点
	//		if (pCur == &(list->head)) {
	//			pCur = pCur->next;
	//		}
	//		count = 1;     //不用continue跳出是因为1肯定不等于N,所以让他执行下面,继续往后跳

	//	}
	//	//依旧要判断是否为头结点
	//	pCur = pCur->next;
	//	if (pCur == &(list->head)) {
	//		pCur = pCur->next;
	//	}
	//	count++;
	//}

	//if (list->size == 1) {
	//	Mynum* tmp = (Mynum*)(list);
	//	printf("\n");
	//	printf("%d\n", tmp->num);
	//}
	//else {
	//	printf("程序出错\n");
	//}
}
int main() {
	test();

	return 0;
}

测试效果

总结: 

这里跟之前不一样的地方是按值删除的函数实现,这里不能用下标查找方式进行删除,以防双向循环导致错乱。主要在主函数测试实现约瑟夫问题代码的实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值