16 - 11 - 06 约瑟夫问题(链表应用)-------《深入浅出数据结构》

来源:互联网 发布:java long占几个字节 编辑:程序博客网 时间:2024/06/01 08:43

约瑟夫问题

【问题描述

设编号分别为:1,2,...,n的n个人围坐一圈。约定序号为k(1 <= k < = n)的人从1开始计数,数到m的那个人出列,他的下一位又从1开始计数,数到m的那个人又出列,依次类推,直到所有人出列为止。

算法思路

用一个不带头结点的循环链表来处理Josephu问题:先构成一个有n个结点的单循环链表,然后从第k结点起从1计数,计到m时,对应结点从链表中删除;然后再从被删除结点的下一个结点起又从1开始计数....,直到所有结点都列出时算法结束。

【代码如下:】

#include <stdio.h>

#include <stdlib.h>

 

typedef struct _node_

{

    int data;

    struct _node_ *next;

    

}ListNode;


ListNode* get_node(int data)  //函数listnode*类型

                               //返回指针值。

{

    ListNode *temp;       

 

    //循环创建一个又一个节点

    temp = (ListNode *)malloc(sizeof(ListNode));

    temp->data = data;   //循环赋值

 

    return temp;

}   //创建完之后,这些temp所指向的区域并没有连接起来,所以需要挨个插入。


//插入也是循环插入,不断地执行这个insert函数//(ListNode **p)表示接受形参是“指针的地址”

//即:指针的指针;(ListNode *q)接受指针。

int insert_data(ListNode **p,ListNode *q)

{

    static ListNode *head;    //静态变量

    

if(*p == NULL)  //因为pmove地址为空,所以

    {                //进入这个循环

        *p = q;           

        head = q;         //设置开头

        

}else{               //这个风格不错- -

        (*p)->next = q;    

        q->next = head;

        //改变移动指针

        *p = q;          

     }

    return 0;

}

//此时已经进入了第二次循环,q的值也相应改变//head的地址始终没变!//q->next 的地址是不变的。

   *p->next存储的地址不变的!

//而且*p->next,q->next,head地址相同!!!!//*p、q的地址在一起相同的在一起不断的递增!

下面:把q换成temp:

     (*p)->next = temp;    //1、

     temp->next = head;

     *p = temp;      认真看!

//因为 每一次循环都出现:temp->next = head;,这样整个链表是一个循环链表,head的地址始终是不变的

ListNode *create_loop(int n)

{

    int i = 0;

    ListNode *temp = NULL;

    ListNode *pmove = NULL;

for(i = 1 ; i <= n ; i ++)

    {

        temp = get_node(i);

        insert_data(&pmove,temp);

             //pmove=NULL(注意!)

    }

    return pmove;

}

 

 

 

 

int delete_data(ListNode **p,ListNode *q)

{

    (*p)->next = q->next;

    free(q);

    q = NULL;

 

return 0;

}

int main()

{

    ListNode *p,*q,*temp;

    int i = 0;

    int n,k,m;

 

    printf("input n k m:");

    scanf("%d%d%d",&n,&k,&m);

    while(getchar()!= '\n');

    

    //创建约瑟夫环

    p= create_loop(n);

 

    //第一个人的位置

    q = p->next;

 

    //找到 k 个人

    for( i = 1 ; i < k ; i ++ )

    {

        p = p->next;

        q = q->next;

    }

 

    while(q != p)

    {    

        for(i = 1;i < m;i ++)

        {

            p = p->next;

            q = q->next;

        }

        

        printf("%d ",q->data);

        delete_data(&p,q);

        q = p->next;

    }

 

    printf("%d\n",p->data);

    

    return 0;

}

1 0
原创粉丝点击