单向循环链表解决约瑟夫问题

这篇博客介绍了如何用C语言通过单向循环链表解决约瑟夫问题。首先定义了链表节点的结构体,然后在`main`函数中创建了一个循环链表,并展示了链表的生成和显示。接着,通过一个循环来模拟约瑟夫问题,每次计数到3时删除一个节点,直至链表只剩下一个元素。博客还包括了链表创建、长度计算、头插法插入节点、按位置删除节点和显示链表元素的自定义函数实现。
摘要由CSDN通过智能技术生成

typedef int data_t;
typedef struct linklist
{
    data_t data;
    struct linklist *next;
}Linklist;   //自定义的结构体作为节点
int main(int argc, char *argv[])

    Linklist * head = Linklist_create(); 

//调用函数创建一个节点初始的单个“自闭”链环,具体函数见下文
    Linklist *p = head;
    Linklist *q = NULL;
    for(int i = 15;i > 1;i--)
    {
        Linklist_insert_head(head,i);
    }                                                    //用头插法生成一个15个元素的单向循环链表
    int lenth = Linklist_lenth(head);   

      /*得到该链表元素个数,这里事先知道元素个数,但为了解决约瑟夫问题的泛用性*/
    printf("lenth = %d\n",lenth);
    Linklist_show(head);  //查看一下所生成的单向循环链表
    int flag = 1;                       //定义一个标志位
    while(lenth > 1)             //当仅剩唯一1个元素时停止循环
    {
        p = p->next;             //p指针移动寻找将要被删除的节点的上一个节点
        q = p->next;            //q指针移动寻找将要被删除的节点
        flag++;
        if(flag == 3)              //当flag计数到3时,q已经指向将要被删除的节点,p指向其上一个节点
        {
            printf("%d ",q->data);   //打印将要被删除的节点数据
            Linklist_delet_pos(p,0);  //把p所指向的节点当作有头单链表的表头,删除其下标为0的节点                                                      // 具体实现功能见下文
            lenth--; //每删除一个,链表元素个数-1
            flag = 0;        //重置标志位,标志位计数逻辑可以根据删除之后p指针位置画图分析
        }
    }
    puts("");
    Linklist_show(p);//打印最终剩下的这个节点的元素
    return 0;

/*以下是上文所使用到的自定义函数的具体功能代码*/

Linklist *Linklist_create()
{
    Linklist *head = (Linklist *)malloc(sizeof(Linklist));
    if(head == NULL)
    {
        perror("malloc");
        return NULL;
    }
    head->data = 1;
    head->next = head;
    return head;
}

int Linklist_lenth(Linklist *head)
{
    int i = 1;
    Linklist *p = head;
    while(p->next != head)
    {
        p = p->next;
        i++;
    }
    return i;
}

void Linklist_insert_head(Linklist *head,data_t data)
{
    Linklist *new = (Linklist *)malloc(sizeof(Linklist));
    if(new == NULL)
    {
        perror("malloc");
        return;
    }
    new->data = data;
    new->next = NULL;
    new->next = head->next;
    head->next = new;
    return;
}

void Linklist_delet_pos(Linklist *head,int pos)
{
    Linklist *p = NULL;
    Linklist *q = head;
    int i=0;
    while(i < pos)
    {
        q = q->next;
        if(q == NULL)
        {
            printf("error post\n");
            return;
        }
        i++;
    }
    p = q->next;
    q->next = p->next;
    free(p);
    p = NULL;
    return;
}

void Linklist_show(Linklist *head)
{
    Linklist *p = head;
    while(p->next != head)
    {
        printf("%d ",p->data);
        p = p->next;
    }
    printf("%d ",p->data);
    puts("");
    return;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值