约瑟夫环问题-单项循环链表

问题描述:

1-n个人按顺时针方向围坐在圆桌周围 ,每个人持有一个密码(正整数)
一开始任选一个正整数作为报数上限值m,从第一个人开始顺时针从1开始报数直到m停止
报m的人出列,将他的密码作为新的m值,从他的顺时针方向下一个人开始从1报数
报到m出列,循环下去,直到所有人出列。

 

算法逻辑:

建立n个结点(无头结点)的单循环链表
从链表的第一个结点起循环计数,寻找第m个节点
找到后将其password作为新的m值,并从链表中删除该结点
循环,直到链表为空

注意事项:

!!ATTENTION!!  函数形参只能值传递,如果用指针做形参开辟内存,或者指针本身作为要修改的值,则注意用指针的指针

!!ATTENTION!!  注意循环执行的条件,如果还想要多执行几步:
要么中间设置一个 条件语句和变量,作为返回值进行判断;
要么最后再重复几步。
 

//自定义结构体类型(结点) 
typedef struct NodeType {
    int id;
    int password;
    struct NodeType * next;
} NodeType;

//函数声明 
void CreateList (NodeType **, int);
int IsEmptyList (NodeType *);
void JosephusOperate (NodeType **, int);
void PrintList (NodeType *);


int main(){
    int n = 0;
    int m = 0;
    NodeType * p = NULL;
    
    printf("请输入人数 n = ");
    scanf("%d",&n);
    printf("请输入初始密码 m = ");
    scanf("%d",&m);
    
    CreateList (&p, n);

    printf("-------打印链表如下-------\n");
    PrintList (p);
    
    printf("-------依次出队顺序如下-------\n");
    JosephusOperate (&p, m);
}


//创建单循环链表 
void CreateList( NodeType **pHead, int n) {
    int i = 1;                               //n个节点,从i开始循环录入 
    int ipassword = 0;                       //循环录入的每个人的密码 
    NodeType *pNew = NULL; 
    NodeType *pCurr = NULL; 

    for ( i=1; i<=n; i++) {
        //开辟一个结点(第一次是首元结点) 
        printf("请输入第%d个人的初始密码:",i);
        scanf("%d", &ipassword);
        pNew = (NodeType *) malloc (sizeof (NodeType));
        printf("i=%d, addre=%d\n", i, pNew);
        if (!pNew){
            printf ("Error");
            exit (ERROR);
        }
        pNew -> id = i;
        pNew -> password = ipassword;
        pNew -> next = NULL;
        
        if (*pHead == NULL) {
            *pHead = pCurr = pNew ;
            pCurr -> next = *pHead;          //next域指向pHead,形成循环链表 
        } 
        else {                               //尾插法: 
            pNew -> next = pCurr -> next;    //新结点pNew的next域指向pHead 
            pCurr -> next = pNew;            //pCurr指向新结点pNew,pNew链入表中 
            pCurr = pNew;                    //pCurr作为动态标尺,后移一位 
        }    
        printf("phead=%d\n", *pHead);
    }
    printf("完成单向循环链表的创建!\n"); 
}


//打印链表看是否成功创建了
void PrintList (NodeType *ppHead) {
    NodeType * pCurrent = ppHead;
    if (!IsEmptyList(ppHead)) {
        printf("--ID----PASSWORD----\n");
        do{
            printf("%4d %7d\n",pCurrent->id, pCurrent->password);
            pCurrent = pCurrent -> next;
        } while(pCurrent != ppHead);
    }
}


//判断链表是否为空
int IsEmptyList (NodeType *Head) {
    if(Head) 
        return 0;
    else {
        printf("The list is empty!\n");
        return 1;
    }
} 


//约瑟夫环运行函数(打印、删除节点,再依次计数) 
void JosephusOperate(NodeType **pHead, int ipassword) {
    int j = 0;
    NodeType * pPre = *pHead;
    NodeType * pCur = *pHead;
    NodeType * pDel = NULL;
    int k = 1;

    //切记,有可能第一个m==1,则第一个人站起来就出列,即第一个结点就需要删除
    //所以pCur应指向第一个结点,pPre指向尾结点 
    while (pPre -> next != *pHead) 
        pPre = pPre -> next;        
        
    while (k){
        for (j=1; j < ipassword; j++) {
            pPre = pCur;
            pCur = pCur -> next;
        }                                    //找到密码对应的人 
        if (pPre == pCur) k=0;
        ipassword = pCur -> password;
        printf("第 %d 个人出列,他的密码是:%d\n", pCur->id, pCur->password);
        pPre -> next = pCur -> next;
        pDel = pCur;
        pCur = pCur -> next;
        free (pDel);
    } 
    *pHead = NULL;
}


 

  • 11
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值