当前位置:首页 > C语言
线性表之无头结点的单向循环链表实验
来源:靑龍一笑的博客  作者:靑龍一笑  发布时间:2022-10-07 11:18:47  点击量:153  评论:0

    约瑟夫环是一个数学的应用问题,有这么一个故事:在罗马人占领乔塔帕特后,39 个犹太人与约瑟夫及他的朋友躲到一个洞中,39 个犹太人决定宁死也不要被敌人抓到,于是决定了一个自杀方式:41 个人排成一个圆圈,由第 1 个人开始报数,每次数到 3 的人就必须自杀,然后再由下一个人重新报数,直到所有人都自杀身亡为止。然而约瑟夫和他的朋友并不想遵从,约瑟夫要他的朋友先假装遵从,他将朋友与自己安排在第 16 个与第 31 个位置,于是逃过了这场死亡游戏。
    约瑟夫环问题的实现如下:

1、joseph.h 文件

/*
 * 线性表的链式存储结构(无头结点的单向循环链表)
 */
#ifndef JOSEPH_H__
#define JOSEPH_H__

/*
 * 单向链表结构
 */
typedef struct node_st {
    int data; // 数据结点
    struct node_st *next; // 指向下一个结点的指针
}joseph;

/*
 * 初始化,创建单向链表
 */
joseph * joseph_create(int);

/*
 * 遍历单向链表
 */
void joseph_show(joseph *);

/*
 * 从单向链表的指定位置删除数据
 */
void joseph_kill(joseph **, int);

#endif

2、joseph.c 文件

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

#include "joseph.h"

/*
 * 初始化,创建单向链表
 */
joseph * joseph_create(int n) {
    int i = 1; // 循环索引值
    joseph *head, *node, *tail; // 头结点、当前结点、尾结点
    head = malloc(sizeof(*head));
    if (head == NULL) {
        return NULL;
    }

    // 给结点赋值
    head->data = i;
    // 刚初始化的单向循环链表的头结点的下一个结点就是本身
    head->next = head;

    // 从头结点开始往下继续构建其它结点
    node = head;
    i++;
    while (i <= n) {
        tail = malloc(sizeof(*tail));
        if (tail == NULL) {
            return NULL;
        }
        // 给尾结点赋值
        tail->data = i;
        // 尾结点的下一个结点必须指向到头结点
        tail->next = head;
        // 将前一个结点的下一个结点指向到尾结点
        node->next = tail;
        // 将当前结点指向到尾结点
        node = tail;
        // 继续
        i++;
    }

    return head;
}

/*
 * 遍历单向链表
 */
void joseph_show(joseph *ptr) {
    joseph *node = ptr; // 当前结点
    for (node = ptr; node->next != ptr; node=node->next) {
        printf("%d ", node->data);
    }
    printf("%d\n", node->data);

    return; // 无返回值
}

/*
 * 从单向链表的指定位置删除数据
 */
void joseph_kill(joseph **ptr, int n) {
    int i = 1; // 循环索引值
    joseph *node = *ptr, *prev; // 当前结点,前一个结点
    while (node != node->next) {
        // 通过 while 循环,走到要删除的位置,并且得到前一个结点
        while (i < n) {
            prev = node;
            node = node->next;
            i++;
        }

        // 输出要删除的数据
        printf("%d ", node->data);
        // 将前一个结点的下一个结点,指向到要删除结点的下一个结点
        prev->next = node->next;
        // 释放要删除结点所占内存
        free(node);
        // 将当前结点指向到前一个结点的下一个结点,即原先要删除结点的下一个结点
        node = prev->next;
        // 改变循环索引值,重新开始下一轮
        i = 1;
    }

    // 得到最后的一个幸存者
    *ptr = node;

    return; // 无返回值
}

3、main.c 文件

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

#include "joseph.h"

int main() {
    int num; // 参与人数
    int dead; // 出局者编号
    joseph *list; // 无头单向环链

    printf("请输入参与人数:");
    scanf("%d", &num);
    printf("请输入出局者编号:");
    scanf("%d", &dead);

    list = joseph_create(num);
    if (list == NULL) {
        fprintf(stderr, "初始化无头单向环链 list 失败!\n");
        exit(1);
    }

    printf("参与者:");
    joseph_show(list);
    printf("出局者顺序:");
    joseph_kill(&list, dead);
    printf("\n幸存者:");
    joseph_show(list);

    exit(0);
}

4、Makefile 文件

OBJS=main.o joseph.o
CC=gcc
CFLAGS+=-c -Wall -g
joseph:$(OBJS)
    $(CC) $^ -o $@
%.o:%.c
    $(CC) $^ $(CFLAGS) -o $@
clean:
    $(RM) *.o joseph -r

    执行效果:

root@RicenOS:~# make
gcc main.c -c -Wall -g -o main.o
gcc joseph.c -c -Wall -g -o joseph.o
gcc main.o joseph.o -o joseph
root@RicenOS:~# ./joseph
请输入参与人数:41
请输入出局者编号:3
参与者:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
出局者顺序:3 6 9 12 15 18 21 24 27 30 33 36 39 1 5 10 14 19 23 28 32 37 41 7 13 20 26 34 40 8 17 29 38 11 25 2 22 4 35 16
幸存者:31
版权所有 © 2005-2023 靑龍一笑的博客  Powered by C.S.Ricen
Copyright © 2005-2023 by www.ricensoftwares.com.cn  All Rights Reserved.

欢迎光临本站,这里是靑龍一笑的博客。

因资金匮乏,本站已迁到国外的免费空间,可能导致本站的访问速度较慢,由此给您带来的不便,敬请谅解。

您可以通过下方的“支持本站建设”链接,给本站提供资金支持。

Free Web Hosting