数据结构-约瑟夫问题的两种实现(顺序表、链表)

  1. 顺序表
  2. 循环链表(不带头节点)
    值得注意的是,其实两种方法都是利用了循环的结构,想象成一个时钟的表盘

1.顺序表
较为简单,以下代码:

/* 
约瑟夫问题的顺序表实现

author: Qian Jipeng(C)
date: 2019-3-21

*/

#include <stdio.h>
#include <stdlib.h>

#define maxsize 100
typedef struct node
{
    int data[maxsize];
    int length;
}SeqList, *PSeqList;

/* 初始化 */
PSeqList Init(){
    PSeqList L;
    L = (PSeqList)malloc(sizeof(SeqList));
    if (L){
        L->length = 0;
    }
    return L;       /* 返回顺序表指针 */
}

/* 插入 */
int InSeqList(PSeqList L, int i, int e){
    if(i < 1 || i > L->length+1 || L->length >= maxsize){
        printf("插入失败!\n");
        return 0;
    }
    else{
        int j;
        L->data[i-1] = e;
        for (j=L->length; j>=i; j--){
            L->data[j] = L->data[j-1];          /* 依次往后移动 */
        }
        L->length ++;

    }
    return 1;

}

/* 删除 */
int DelSeqList(PSeqList L, int i, int *x){
    if ( i < 1 || i > L->length){
		printf("删除位置不合法\n");
		return 0;
	}
	
	int j;
	int tmp;		// 保存将被删除的元素
	tmp = L->data[i-1];
	
	for (j = i ; j <= L->length; j++ ){			// 从第I 个开始往前移动一位
		L->data[j-1] = L->data[j];
	}
	L->length --;
	//printf("删除第 %d 个位置元素 %d 成功!\n", i, tmp);
    return 1;
}

// 功能函数 s 开始, 数到  m 
int yusefu_SeqList(PSeqList L, int s, int m){
    int x;
    int i;
    int s1;
    int w;      // 保存删除的元素
    if( L-> length == 0){
        printf("表空!\n");
        return 0;
    }
    s1 = s -1;

    // 依次出去
    for (i = L->length; i > 0; i--){
        
        /* 关键步骤 */
        s1 = (s1+m-1) % i;
        w = L -> data[s1];      // 下标 s1, 是第s1+1 个元素!!!
        DelSeqList(L, s1+1, &x);
        printf("出列: %d\n", w);
    }
    return 1;
}

int main(){
    int len;        // 序列长度
    int num[maxsize];       // 用来存输入的数
    PSeqList L = (PSeqList)malloc(sizeof(SeqList));
    printf("输入序列元素个数: ");
    scanf("%d", &len);
    printf("输入约瑟夫序列(空格分开): ");


    // 依次插入
    for (int l = 0; l < len; l++ ){
        scanf("%d", &num[l]);
        InSeqList(L, l+1, num[l]);
        //printf(" %d ", num[l]);
    }

    yusefu_SeqList(L, 2, 5);
    
    return 0;
}

2.循环链表
这里的循环链表是没有头结点的,为了操作方便,否则每每循环到头结点还要跳过这个头结点,我的做法是:
1. 先把第一个元素放入第一个节点(即首元节点),只有数据域,指针域置空
2. 接着用个循环,创建剩下的单个节点,同样只有数据域
3. 再把这些节点连接起来

代码如下:

/*  约瑟夫问题的循环链表实现
* author: Qian Jipeng(C)
* date: 2019-3-24
* version: 2.0(1.0 aborted for too complexed)

*/


#include <stdio.h>
#include <stdlib.h>

/* node definition */
typedef struct node{
    int data;
    struct node * next;
}linklist;


/* 
\brief: crate the linklist and do insert, return the first node's ptr 
\param: n ->> the size of the serises
\return: the first node's ptr
*/

/* creat the node in range(1, n)*/
linklist * initLink(int n){
    linklist * head = (linklist*)malloc(sizeof(linklist));

    /* the first node initionalized (not head node)*/
    head->data = 1;
    head->next = NULL;        
    
    /* a ptr to move through the list */
    linklist * tmp = head;

    /* we satrt with the second node for a loop */
    for (int i = 2; i <= n; i ++) {
        linklist * body = (linklist*)malloc(sizeof(linklist));

        /* creat and init single node */
        body -> data = i;
        body -> next = NULL;

        /* connect the single nodes together */
        tmp -> next = body;
        tmp = tmp -> next;
    }

    //printf("%d\n", tmp->data);
    /* now tmp is just the last node */
    tmp -> next = head;     /*connect the head and the rear */
    return head;
    /* by this method, we created a loop linklist */
}

void yusefu(linklist * head,int k,int m){
    linklist * tail = head;
    
    //找到链表第一个结点的上一个结点,为删除操作做准备
    while (tail -> next != head) {
        tail = tail -> next;
    }

    linklist * p = head;

    //找到编号为k的人(或者是第几个开始,可以改)
    while (p -> data != k) {
        tail = p;
        p = p->next;
    }

    //从编号为k的人开始,只有符合p->next==p时,说明链表中除了p结点,所有编号都出列了,
    while (p -> next != p) {
        //找到从p报数1开始,报m的人,并且还要知道数m-1de人的位置tail,方便做删除操作。
        for (int i = 1; i < m; i ++) {
            tail = p;
            p = p -> next;
        }
        tail->next=p->next;//从链表上将p结点去除
        printf("%d \t",p -> data);
        free(p);
        p = tail -> next;//继续使用p指针指向出列编号的下一个编号
    }

    /* the last one */
    printf("%d \n",p -> data);
    free(p);

}


int main() {

    linklist * head=initLink(10);
  
    yusefu(head, 2, 5);
    return 0;
}

关注我的github

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值