循环链表--模拟约瑟夫环

约瑟夫(joseph):编号为1,2,。。。,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m值,从他在顺时针方向的下一个人开始重新从1报数,如此下去,直到所有人全部出列为止。试设计一个程序显示出列顺序。

〖基本要求〗:利用单向循环链表存储结构模拟此过程,按照出列的顺序打印出各人的编号。

〖测试数据〗:m的初值为20,密码:3,1,7,2,4,8,6

目录

1. 头文件

2. 声明 

3.创建一个循环单链表

4. 循环单链表的链表数

5. 打印该链表

6. 删除操作

7. 出列操作 

8. 主函数


简洁版

只实现循环链表功能

1.头文件

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

2.结构体


typedef struct LinkList{
    int data;
    int table;
    struct LinkList* next;
}PNode;

3. 创建空链表(无头)

PNode* creatNullList(void) {
	PNode* llist = (PNode*)malloc(sizeof(PNode));
	return llist;
}

4.插入操作

void insert_llist(PNode* llist, int n, int a[]) {
	PNode* p = llist;            //防止第一节点丢失

	p->data = a[0];              //将第一节点赋值,不为空(密码)
	p->table = 1;                //为了可以打印出下标

	int i;
	for ( i = 1; i < n; i++) {   //从第二结点开始循环
		PNode* q = (PNode*)malloc(sizeof(PNode));
		q->next = llist;         //q->next = p;
		q->table = i + 1;
		q->data = a[i];
		p->next = q;             //第一节点产生
		p = q;                   //p指针向后移动
	}
}

 5.打印链表操作

void dump_llist(PNode* llist) {
	printf("[1] : %d\n", llist->data);      //由于循环链表,while条件限制,
                                            //先打印第一结点
	int no = 2;
	PNode* pnode = llist->next;
	while (pnode != llist) {
		printf("[%d] : %d\n", no, pnode->data);
		pnode = pnode->next;
		no++;
	}
}

6. joseph--具体操作+打印出列操作

void joseph_llist(PNode* llist, int value, int sum) {
	PNode* p = NULL;
	PNode* q = NULL;
	p = llist;
	while (sum) {                               //sum == 0 全部出列
		int count = 1;
		while (count != value) {                //循环到报数人结束循环
			q = p;
			p = p->next;
			count++;
		}
		printf("\n[%d] : %d", p->table,p->data);  

		value = p->data;                        //准备继续循环条件
		q->next = p->next;
		p = q->next;                            //删除结点,最后free链表,这里没有free
		sum--;
	}
}

7.主函数

int main() {
	PNode* llist = creatNullList();
	int a[] = { 3,1,7,2,4,8,6 };
	insert_llist(llist, 7, a);
	dump_llist(llist);
	joseph_llist(llist, 20, 7);
	free(llist);
}

 8.运行代码-----正确

 

说一下错误吧:

链表的开始可以有头无头,上面为无头,下面为有头,链表为循环链表,有头会多算一个结点,将头链表算进去,怎么会打印出正确链表...

由于没有头节点,所以会将第一个结点拿出来单独赋值,打印,注意一下 

/*为什么要单独赋值,不单独赋值joseph函数应该有问题*-*,但我没看出来 0^0,

^-^希望你可以找出原因*/

en,细节细节,写博客的时候发现我打印 table 排的不对,又稍加修改,作业更加完美,哈哈。


1. 头文件

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

2. 声明 

typedef struct Cirnode {
    int data;
    struct Cirnode* next;
}CNode,* Link;

//以下两个函数可以简化

//创建空循环链表
Link createNullLink(void) {
    Link head = (Link)malloc(sizeof(CNode));
    if (head != NULL) {
        head->next = head;
    }
    else {
        printf("Out of space");
    }
    return head;
}
//入列
void insertCNode(Link head, int a[], int n) {
    Link rear = head;
    for (int i = 0; i < n; i++) {
        Link p = (Link)malloc(sizeof(CNode));
        p->data = a[i];
        p->next = head;
        rear->next = p;
        rear = p;
    }
}

3.创建一个循环单链表

Link newLink(int a[], int n) {
    Link head = (Link)malloc(sizeof(CNode));
    head->next = head;
    Link rear = head;
    for (int i = 0; i < n; i++) {
        Link node = (Link)malloc(sizeof(CNode));
        node->data = a[i];
        node->next = head;
        rear->next = node;
        rear = node;
    }
    return head;
}


4. 循环单链表的链表数

int length(Link head) {
    Link p = head;
    int count = 0;
    while (p->next != head) {
        count++;
        p = p->next;
    }
    return count;
}

5. 打印该链表

void displayNode(Link head) {
    Link p = head->next;
    while (p != head) {
        printf("%d->", p->data);
        p = p->next;
    }
    printf("head \n");
}

6. 删除操作

void deleteCNode(Link head, Link p) {
    Link q = head;
    while (q->next != p) {
        q = q->next;
    }
    q->next = p->next;
    free(p);
}

7. 出列操作 

bool joseph_CNode(Link head, int n, int num) {        // 链表 第几个人出列  链表有几个人
    int count = num;
    Link p = head->next;                //p开始循环
    int m = n;                                //报m的出列
    int value;                            //获取出列人的值
    m = m % count;                            //从p开始,第m个人出列,排除了链表不够长的情况
    for (int i = 0; ; ) {
        i++;
        if (i >= m) {
            break;
        }
        p = p->next;
    }
    value = p->data;                    //获取出列人的值
    printf("%d->", value);                //打印出列人
    deleteCNode(head, p);                //删除出列人
    count--;                            //总人数-1;
    while (p->next != head) {            //使用递归,打印其他的人
        return joseph_CNode(head, value, count);
    }
}

8. 主函数

int main() {
    int a[] = { 3,1,7,2,4,8,6 };
    Link head = newLink(a , 7);
    displayNode(head);
    printf("%d \n", length(head));            
    joseph_CNode(head, 20, );
    printf("head");
}

 与上面版本答案不一样,上面版本正确

注:在出列操作for循环中,做了修改,先加一再判断;不然就是报第21号的人出列;

我理解错题意了...以为打印密码,结果是打印下标,下标需要在结构体的时候多建一个变量就可以,我用了table

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值