黑马数据结构笔记之使用循环链表解决约瑟夫问题
1 思想:一个人从1依次喊一个数,喊到指定数时,该人退出队伍,下一个人重新从1开始喊。
代码实现:
1)头文件:
#ifndef CIRCLELIST_H
#define CIRCLELIST_H
//挂钩结构体
typedef struct CSNode{
struct CSNode *next;
}CircleSNode;
//管理链表结构体
typedef struct CList{
CircleSNode head;
int size;
}CircleList;
//查找回调函数
typedef int (*MYCOMPAER)(CircleSNode *c1,CircleSNode *c2);
//打印回调函数
typedef void (*PRINT)(CircleSNode *c);
//链表初始化
CircleList *Init_CircleList();
//插入链表
int Insert_CircleList(CircleList *clist,int pos,CircleSNode *data);
//删除 -根据位置
int DelByPos_CircleList(CircleList *clist,int pos);
//删除 -根据值
int DelByValue_CircleList(CircleList *clist,CircleSNode *data,MYCOMPAER comp);
//查找
int Find_CircleList(CircleList *clist,CircleSNode *data,MYCOMPAER comp);
//打印
int Print_CircleList(CircleList *clist,PRINT print);
//获取第一个元素
CircleSNode *GetFront_CircleList(CircleList *clist);
//返回链表大小
int GetSize_CircleList(CircleList *clist);
//销毁内存
int Destory_CircleList(CircleList *clist);
#endif
2).cpp文件:
#include"CircleList.h"
#include<stdio.h>
#include<stdlib.h>
//链表初始化
CircleList *Init_CircleList(){
CircleList *clist=(CircleList*)malloc(sizeof(CircleList));
clist->head.next=&(clist->head); //使链表尾部指向头结点--循环
clist->size=0;
return clist;
}
//插入链表
int Insert_CircleList(CircleList *clist,int pos,CircleSNode *data){
if(clist==NULL){
return -1;
}
//数据为空也没必要插入
if(data==NULL){
return -1;
}
if(pos<0 || pos>clist->size){
pos=clist->size;
}
//插入
//先找到要插入前一节点
CircleSNode *pPre=&(clist->head);
for(int i=0;i<pos;i++){
pPre=pPre->next;
}
//开始插入
data->next=pPre->next;
pPre->next=data;
clist->size++;
return 0;
}
//删除 -根据位置
int DelByPos_CircleList(CircleList *clist,int pos){
if(clist==NULL){
return -1;
}
if(pos<0||pos>=clist->size){
printf("输入下标有误,数组越界了!\n");
return -1;
}
//删除
//找到要删除点的前一节点
CircleSNode *pPre=&(clist->head);
for(int i=0;i<pos;i++){
pPre=pPre->next;
}
//开始删除
pPre->next=pPre->next->next;
clist->size--;
return 0;
}
//删除 -根据值
int DelByValue_CircleList(CircleList *clist,CircleSNode *data,MYCOMPAER comp){
if(clist==NULL){
return -1;
}
if(data==NULL){
return -1;
}
/* while删除
int i=0;
CircleSNode *pPre=&(clist->head);
CircleSNode *pCur=clist->head.next;
while(pCur!=&(clist->head)){
if(comp(pCur,data)){
break;
}
pPre=pCur;
pCur=pCur->next;
i++;
}
//如果找到i肯定会少加一次1
if(i==clist->size){
printf("没有找到可删除的值\n");
return -1;
}
//开始删除
pPre->next=pCur->next;
*/
//for删除
CircleSNode *pPre=&(clist->head);
CircleSNode *pCur=clist->head.next;
for(int i=0;i<clist->size;i++){
if(comp(pCur,data)){
break;
}
pPre=pCur;
pCur=pCur->next;
}
//开始删除
pPre->next=pCur->next;
clist->size--;
return 0;
}
//查找
int Find_CircleList(CircleList *clist,CircleSNode *data,MYCOMPAER comp){
if(clist==NULL){
return -1;
}
if(data==NULL){
return -1;
}
int i=0;
CircleSNode *pCur=clist->head.next;
while(pCur!=&(clist->head)){
if(comp(pCur,data)){
break;
}
pCur=pCur->next;
i++;
}
//如果找到i肯定会少加一次1
if(i==clist->size){
printf("没有找到可删除的值\n");
return -1;
}
return i;
}
//打印
int Print_CircleList(CircleList *clist,PRINT print) {
if(clist==NULL){
return -1;
}
/*
CircleSNode *pCur=clist->head.next;
while(pCur!=&(clist->head)){
print(pCur);
pCur=pCur->next;
}
*/
CircleSNode *pCur=clist->head.next;
for(int i=0;i<clist->size;i++){
//多次打印,在打印之前,跳过头结点
if(pCur==&(clist->head)){
pCur=pCur->next;
}
print(pCur);
pCur=pCur->next;
}
return 0;
}
//获取第一个元素
CircleSNode *GetFront_CircleList(CircleList *clist){
return clist->head.next;
}
//返回链表大小
int GetSize_CircleList(CircleList *clist){
return clist->size;
}
//销毁内存
int Destory_CircleList(CircleList *clist){
if(clist==NULL){
return -1;
}
free(clist);
return 0;
}
3)主函数测试:
#include"CircleList.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define M 8
#define N 3
//自定义类型
typedef struct Num{
CircleSNode node; //每个自定义类型都使用挂钩串联
int num;
}MyNum;
//打印回调函数
void MyPrint(CircleSNode *cs){
MyNum *p=(MyNum *)cs;
printf("%2d",p->num);
}
//比较回调函数
int MyCompare(CircleSNode *cs1,CircleSNode *cs2){
MyNum *p1=(MyNum *)cs1;
MyNum *p2=(MyNum *)cs2;
if(p1->num==p2->num){
return 1;
}
return 0;
}
void test01(){
//创建链表
CircleList *clist=Init_CircleList();
//创建数据
MyNum m[M];
for(int i=0;i<M;i++){
m[i].num=i+1;
Insert_CircleList(clist,i,(CircleSNode*)&m[i]); //不是插入m数组,而是对象
}
//打印
Print_CircleList(clist,MyPrint);
printf("\n");
//约瑟夫重点开始
//循环按规律不断删除
int count=1; //记录那个人喊的数,用于判断是否与规定的数相等然后删除 并非是下标
CircleSNode *pCur=clist->head.next;
while(clist->size>1){
if(count==N){
//可以先输出看看,但要先转有数据的类型
MyNum *tmp=(MyNum*)pCur;
printf("%2d",tmp->num);
//按值删除
//删除前保存下一节点
CircleSNode *pNext=pCur->next;
DelByValue_CircleList(clist,pCur,MyCompare);
//clist->size--; 不需要自行写,调用函数做了
pCur=pNext;
//若是头结点,则指向下一节点
if(pCur==&(clist->head)){
pCur=pCur->next;
}
count=1; //不用continue跳出是因为1肯定不等于N,所以让他执行下面,继续往后跳
}
//依旧要判断是否为头结点
pCur=pCur->next;
if(pCur==&(clist->head)){
pCur=pCur->next;
}
count++;
}
if(clist->size==1){
MyNum *tmp=(MyNum*)GetFront_CircleList(clist);
printf("\n");
printf("%d\n",tmp->num);
}else{
printf("程序出错\n");
}
//销毁内存
Destory_CircleList(clist);
}
int main(){
test01();
return 0;
}