约瑟夫环问题的解决

约瑟夫环问题介绍

已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为1的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。



# include <stdio.h>
# include <stdlib.h>
# include <assert.h>
typedef int DataTp;

typedef struct node
{
    DataTp elem;
    struct node*pnext;

}NODE;

typedef NODE* LinkList;



NODE* CreatList(int n);
void MakeLoop(LinkList phead);
void DeleteNode(LinkList phead,LinkList paim);

int main (void)
{
    int sum,num;  //总人数 , 退出人的编号
    int i;
    
    LinkList pstart;  //头节点 
    LinkList paim;    //待删除的目标节点的地址 
    LinkList pt;      
    
    puts("输入总人数");
    scanf("%d",&sum);   
    puts("输入退出的编号");
    scanf("%d",&num);

    pstart=CreatList(sum);  //建立链表
    MakeLoop(pstart);       //变为循环链表
    
    pt=pstart->pnext; //取出第一个数据节点地址
    
    while(sum!=0) 
    {

        for(i=0;i<num-1;i++)
            pt=pt->pnext;      //往后寻址,找到退出目标的地址
     
        paim=pt;              //临时保存。确定删除节点的地址 
        pt=pt->pnext;         //确定下次循环的头为pt
        
        printf("退出的是%d号
",paim->elem);
        DeleteNode(pstart,paim);         //删除
           
        sum--;                          //总人数减少

    }
    
   
    return 0;
}


NODE* CreatList(int n)
{
    int i;
    NODE*p1,*p2;

    NODE * phead;
	
	phead=(NODE*)malloc(sizeof(NODE));
	if(phead==NULL)
	{
		fputs("memory error!
",stderr);
        exit(EXIT_FAILURE);
		
	} 
	
	phead->pnext=NULL;
	
	
    /////////////////////////////////
    for(i=0;i<n;i++)
    {
        p1=(NODE*)malloc(sizeof(NODE)); //分配内存
        if(p1==NULL)                    //检查合法性
        {
           fputs("memory error!
",stderr);
           exit(EXIT_FAILURE);
        }
        p1->elem=i+1;                  //补全结点信息
        p1->pnext=NULL;

        if(phead->pnext==NULL)         //链接
             phead->pnext=p1;
        else
             p2->pnext=p1;

        p2=p1;                          //重置
    }


   return phead;
}


void MakeLoop(LinkList phead)
{
    NODE*p=phead->pnext; //取出第一个数据节点 
    
    assert(p!=NULL);
    
    while(p->pnext!=NULL)
         p=p->pnext;
         
    p->pnext=phead->pnext;   // 链接,构成循环链表

    return ;
}

void DeleteNode(LinkList phead,LinkList paim)
{


    NODE*p=phead->pnext;  //取出第一个数据节点 
    
    assert(p!=NULL);
    
    while(p->pnext!=paim)
        p=p->pnext;
    
    p->pnext=p->pnext->pnext;
    
	if(paim==phead->pnext)   //如果删除的是第一个数据节点, 
	  phead->pnext=p->pnext; //改变头节点指针域的值,使它始终指向 
	                         //循环链链表的某一个节点。而不丢失链表节点                                                        
    free(paim);
    return ;
}




链表初始状态:

刚开始写这个程序的时候,遇到一个Bug,那就是没有解决链表丢失问题。比如当退出的节点刚好为1号节点时

,1号节点就会被Free掉,这样就不能通过phead来访问各个节点了,整个链表就丢失了。

于是我在DeleteNode()函数里加了一个判断:当删除节点为第一个数据节点时,更改头节点的指针域的值,

使指向第一个数据节点的下一个节点,这样链表就不会丢失了。






原文地址:https://www.cnblogs.com/lulipro/p/5052628.html