C语言环形链表解决循环报数问题

文章描述了一种方法,通过链表表示好人和坏人在环形座位上的排列,利用循环报数机制,找出最小的k值,使得当报到k时,所有坏人都死亡而好人存活。文中详细介绍了如何使用链表操作模拟报数过程以及两种删除策略:实际删除和逻辑删除。
摘要由CSDN通过智能技术生成

问题

有m个好人和m个坏人坐成一个圈,前m个人是好人,后m个人是坏人。现在他们开始循环报数,要求从编号为1的人开始报,如果有人报到k则他必须死亡,而死掉的人下一个人则继续从1开始报数。请求出最小的k使得,所有的坏人都死掉而好人都活下来。1<=m<=12.

分析

用首尾相连的链表可以表示“坐成一个圈”的情况:

//链表的节点声明
struct ListNode {
    int val;
    struct ListNode* next;
};
// 在尾部插入节点
struct ListNode* insertAtTail(struct ListNode* head, int val) {
    struct ListNode* new_node = (struct ListNode*)malloc(sizeof(struct ListNode));
    new_node->val = val;
    new_node->next = NULL;
    if (head == NULL) {
        return new_node;
    }
    struct ListNode* p = head;
    while (p->next != NULL) {
        p = p->next;
    }

    p->next = new_node;
    return head;
}
int main(){
	//创建链表1->2->3->4->5->6
	 struct ListNode* p = NULL;
	 int m = 3;
	 for (int x = 1; x <= 2*m; x++)
	 {
	     p = insertAtTail(p, x);
	 }
	  
	 //遍历到最后一个节点
	 struct ListNode* q = p;
	 while (q->next != NULL) {
	     q = q->next;
	 }
	 //首节点和尾节点相连
	 q->next = p;
 ...
}

模拟循环报数:

struct ListNode* getCount(struct ListNode* head,int m,int k) {
    struct ListNode* p = head;
    struct ListNode* prev = NULL;
    int i = 1;

	//count记录被删除的节点的个数
    int count = 0;
    //从首节点开始遍历
    while(true) {
    	//如果报数到k,则删除该节点。
        if (i % k == 0) {
            count++;
            prev->next = p->next;
            if (p->val <= m) {
                break;
            }
            free(p);
            p = prev->next;
            //重新从1开始接着报数
            i = 1;
        }

        prev = p;
        p = p->next;
        i++;
    }
    printf("\n");
    return head;
}

循环k=m+1,m+2,…,2m的情况:

 for (int x = m+1; x <= 2*m; x++) {
     //复制链表1->2->3->4->5->6
     struct ListNode* p2 = NULL;
     for (int i = 0; i < 2 * m; i++) {
         p2 = insertAtTail(p2, i + 1);
     }
     q = p2;
     while (q->next != NULL) {
         q = q->next;
     }
     q->next = p2;
     

     int k = x;
     p = getCount(p, m, k);
     p = p2;
 }
    

这种方法是实际的删除,也可以用逻辑删除实现。增加逻辑删除标志位deleteFlag,deleteFlag=0表示未删除,deleteFlag=1表示已删除。

  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值