虽然现在开发多用Java了,闲着没事拿指针来练练手还是挺有意思的。约瑟夫的问题的解决方案有很多,可以用一个循环10不到解决,但要推导出一个公式;用一维数组加两个循环也可以,这种删除一个数据,后面元素的下标都要跟着变,不太可取。
#include
#include
typedef struct Linknode
{
int data;
struct Linknode *pNext;
}node,*PNODE;
//尾部插入
PNODE addback(PNODE phead,int data){
PNODE pnew= (PNODE)malloc(sizeof(node));
pnew->data=data;
if(phead==NULL){//一个节点的环
phead=pnew;
pnew->pNext=phead;
}
else{//多个节点
PNODE p=phead;
while(p->pNext!=phead){//循环到尾部
p=p->pNext;
}
p->pNext=pnew;//链接到新的节点
pnew->pNext=phead;//头尾相连
}
return phead;
}
//头部插入
PNODE addfront(PNODE phead,int data){
PNODE pnew=((PNODE)malloc(sizeof(node)));
pnew->data=data;
//一个节点的环
if(phead==NULL){
phead=pnew;
pnew->pNext=phead;
}else{//多个节点
PNODE p=phead;
while(p->pNext!=phead){//循环到尾部
p=p->pNext;
}
p->pNext=pnew;
pnew->pNext=phead;
phead=pnew;
}
return phead;
}
void showall(PNODE phead){
printf("----------------showall-----------------\n");
if(phead==NULL){
return;
}else if(phead->pNext==phead){//只有一个节点
printf("%d,%p,%p",phead->data,phead,phead->pNext);
}else{
PNODE p=phead;
while(p->pNext!=phead){
printf("\n%d,%p,%p",p->data,p,p->pNext);
p=p->pNext;
}
printf("\n%d,%p,%p",p->data,p,p->pNext); //补充相等的情况
}
}
PNODE findfirst(PNODE phead,int data){//找到第一个对应值为data的结点
if(phead==NULL){
return NULL;
}else if(phead->pNext==phead){
//只有一个节点
if(phead->data==data){
return phead;
}
}else{
PNODE p=phead;
while(p->pNext!=phead){
if(p->data==data){
return phead;
}
p=p->pNext;
}
if(p->data==data){
return phead;
}
}
}
PNODE deletefirst(PNODE phead,int data,PNODE* ppNext){//删除第一个对应值为data的结点
PNODE p1=NULL;
PNODE p2=NULL;
p1=phead;
while(p1->pNext!=phead){
if(p1->data==data){
break;
}else{
p2=p1;
p1=p1->pNext;
}
}
if(p1!=phead){
p2->pNext=p1->pNext;
*ppNext=p1->pNext;
free(p1);
}else{//刚好是头结点
PNODE p=phead;
while(p->pNext!=phead){
p=p->pNext;
}
phead=phead->pNext;
*ppNext=p1->pNext;
free(p1);
p->pNext=phead;
}
return phead;
}
int getnum(PNODE phead){//计算结点的个数
if(phead==NULL){
return 0;
}else if(phead->pNext==phead){
//只有一个节点
return 1;
}else{
int i=1;
PNODE p=phead;
while(p->pNext!=phead){
i++;
p=p->pNext;
}
return i;
}
}
//如果存在结点值为finddata的结点,则在其前面插入data
PNODE insertfirst(PNODE phead,int finddata,int data){
PNODE p1=NULL;
PNODE p2=NULL;
p1=phead;
while(p1->pNext!=phead){
if(p1->data==finddata){
break;
}else{
p2=p1;
p1=p1->pNext;
}
}
PNODE pnew=((PNODE)malloc(sizeof(node)));
pnew->data=data;
if(p1!=phead){
pnew->pNext=p1;
p2->pNext=pnew;
}else{//刚好是头结点
PNODE p=phead;
while(p->pNext!=phead){//循环到尾部
p=p->pNext;
}
p->pNext=pnew;
pnew->pNext=phead;
phead=pnew;
}
return phead;
}
main(){
//printf("node有%d字节\n",sizeof(node));
//printf("PNODE有%d字节\n",sizeof(PNODE));
PNODE phead=NULL;
printf("----------------addfront-----------------\n");
for(int i=0;i<5;i++){
phead=addfront(phead,i);//插入数据
}
showall(phead);
//printf("\n----------------addback-----------------\n");
//phead=NULL;
//for(int i=0;i<5;i++){
//phead=addback(phead,i);//插入数据
//}
//showall(phead);
//
//printf("\n---- findfirst(找到第一个值为3的结点)-----------------\n");
//PNODE pfind=findfirst(phead,3);
//pfind->data=77777;
//showall(phead);
//
//printf("\n------deletefirst(删除值为2的结点)-----------------\n");
//phead=deletefirst(phead,2);
//showall(phead);
//
//printf("\n------insertfirst(在结点为4的前面插入999999999)-----------------\n");
//phead=insertfirst(phead,4,999999999);
//showall(phead);
printf("\n\n\n");
//约瑟夫问题
PNODE p=phead;
while(getnum(phead)!=1){
for(int i=1;i<=3;i++){
p=p->pNext;
}
phead=deletefirst(phead,p->data,&p);
//删除之后p要从下一个结点继续,所以需有第 3个参数改变其地址
printf("\n");
showall(phead);
}
printf("\n");
printf("最后剩下的是%d\n",phead->data);
}