思路:
约瑟夫环问题:
约瑟夫环问题的一种描述是:编号为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;
}
测试效果
总结:
这里跟之前不一样的地方是按值删除的函数实现,这里不能用下标查找方式进行删除,以防双向循环导致错乱。主要在主函数测试实现约瑟夫问题代码的实现。