单向循环链表-约瑟夫问题

本文介绍了单向循环链表的基本操作,包括初始化、插入、删除等,并提供了相关函数的实现。随后通过约瑟夫问题展示了循环链表的应用,详细展示了如何利用循环链表解决报数问题并输出出圈编号。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单向循环链表

无论插入或者删除链表的末尾结点的Next指针永远指向头结点 达到循环的目的,
生活当中那些事物是循环的呢?
一是时间 ,二是一周,三是人的工作,生活 都是循环 …我们发现无法打破, 生活该继续的继续,
唯一的是生活方式发生改变,其他的事物都无任何变化,可能有人离世,可能有人出世,
有人以某种职业干到不能干为止,这些都是属于事物循环
让我们看看单向循环链表的图:

单向循环链表
在这个单向循环链表里很清楚的看到 链表的数据域 链接指针域 是个循环的姿态 所以判断是否结束不要判断为nullptr,而是判断某个结点是否跟头结点有一一定的关系
关于单向循环链表 :头部添加,尾部添加 元素 ,在某个位置插入元素 ,在某个位置删除元素 获取某个位置的元素,查找某个位置的结点 这些就简单操作,就没有必要的投入这些细节,如果还不熟悉这些链表的操作
就看这些:
单向链表操作函数:
链表添加元素 web link
链表插入元素 web link
链表删除元素 web link
获取链表元素 web link
查找链表结点 web link
链接链表结点 web link
解除链接结点 web link
本质都是一样的,但是链表的末尾的Next指针域指向头结点

单向循环链表基本操作

函数声明

#ifndef __LOOPLINKLIST_H__
#define __LOOPLINKLIST_H__
//循环链表结点元素类型
using LoopLinkNodeElemType = int;

using ElemType = LoopLinkNodeElemType;

//循环链表结点
using LinkNode  =  struct __LoopLinkNode;

//循环链表结点
struct __LoopLinkNode {

	ElemType value;

	LinkNode* next;
};


//循环链表
using LoopLinkList = struct __LoopLinkList;

//循环链表
struct __LoopLinkList {

	//链表结点指针指向首结点
	LinkNode* list;

	//元素个数
	size_t size;

};

//初始化循环链表
bool initLoopLinkList(LoopLinkList& List);
//创建首节点
LinkNode* creatorLinkNode(void);
//创建节点并且初始化数据
LinkNode* creatorLinkNode(ElemType const  & value);
//循环链表尾部插入
void LoopLinkListInsert_back(LoopLinkList& List, LinkNode*& Newnode);
//循环链表头部插入
void LoopLinkListInsert_froot(LoopLinkList& List, LinkNode*& Newnode);
//链接结点
void  Link(LinkNode*& node, LinkNode*& Newnode);
//遍历链表元素
void showLoopLinkList(LoopLinkList& List);

#endif

创建单向循环链表code:
函数实现

#include "LoopLinkList.h"
#include<iostream>
using namespace std;

bool initLoopLinkList(LoopLinkList& List){

    List.list = creatorLinkNode();
    List.size = 0u;

    return true;
}

LinkNode* creatorLinkNode(void){

    LinkNode* node = new LinkNode;
    node->next = node;
    return node;
}

单向循环链表 头部添加元素code:
函数实现

LinkNode* creatorLinkNode(ElemType const& value){

    LinkNode* node = new LinkNode;
    node->value = value;
    node->next = nullptr;
    return node;
}

void LoopLinkListInsert_froot(LoopLinkList& List, LinkNode*& Newnode){
    Link(List.list, Newnode);
    ++List.size;
}

单向循环链表 尾部添加元素code:
函数实现

void LoopLinkListInsert_back(LoopLinkList& List, LinkNode*& Newnode){
    LinkNode* current = List.list;
  
    while (current->next  != List.list) {

        current = current->next;
    }
  
    Link(current, Newnode);
    ++List.size;
}

单向循环链表 链接结点操作code:
函数实现

void  Link(LinkNode*& node, LinkNode*& Newnode) {

    Newnode->next = node->next;
    node->next = Newnode;
}

单向循环链表 遍历操作code:
函数实现

void showLoopLinkList(LoopLinkList& List){
    for (LinkNode* iter = List.list->next; iter != List.list; iter = iter->next) {
        cout << "链表数据元素为:" << iter->value << "\t";
    }
    cout << endl;
}

学会了基本操作后,来看看约瑟夫问题吧

单向循环链表-约瑟夫问题

有 10 个小朋友按编号顺序 1,2,。。。,10 顺时针方向围成一圈。从 1 号开 始顺时针方向 1,2,。。。,9 报数,凡报数 9 者出列(显然,第一个出圈为 编号 9 者)。 最后一个出圈者的编号是多少?第 5 个出圈者的编号是多少?

画图分析:

约瑟夫问题

代码实现

bool Joseph(LoopLinkList& List, int interval){

    const  LinkNode* const  head = List.list;

    //遍历结点
    LinkNode* current = List.list;

    //待出列的结点
    LinkNode* deleteNode = nullptr;
    //返回值
    bool ret = true;

    int i = 0;//报数
    int j = 0;//报数的数量
    int times = 0;//当前进行第几轮 轮数
    ElemType num{};

    do {

        if (!List.size || current->next == head) {

            cerr << "链表为空!" << endl;
            ret = false;
            break;
        }

        if (interval < 1) {
            cerr << "报数的数目太低!" << endl;
            ret = false;
            break;

        }
      
        do{
            
            i += interval;

           //查找 第i个结点 current 指向该结点的上一个结点
            while (current->next){

                if (current->next!= head) {
                    ++j;
                }

                if (j >= i) {
                    break;
                }
                current = current->next;
            }

            ++times;
            if (current->next) {
                deleteNode = current->next;//临时保存被删的结点以备释放
            }
            //deleteNode = current->next;
            if (deleteNode){
                num = deleteNode->value;
            }        

            if (times==5){
                cout << "第" << times << "出圈的编号:" << num << endl;
                cout << endl;
            }

            if (deleteNode) {
                cout << " 当前结点: " << num << "\t上一个结点: " << current->value << "\t 下一个结点:" << deleteNode->next->value << endl;
                cout << endl;
            } 

            if (deleteNode) {
                current->next = deleteNode->next;
            }

            delete deleteNode;//释放被删的结点
            showLoopLinkList(List);
            cout << endl;

        } while (List.list->next != head);
         
        cout << "最后出圈的编号:" << num << endl;
        cout << endl;

    } while (false);

    return ret;
}

约瑟夫问题运行结果:

链表数据元素为:1        链表数据元素为:2        链表数据元素为:3        链表数据元素为:4        链表数据元素为:5        链表数据元素为:6        链表数据元素为:7        链表数据元素为:8        链表数据元素为:9        链表数据元素为:10       

 当前结点: 9    上一个结点: 8    下一个结点:10

链表数据元素为:1        链表数据元素为:2        链表数据元素为:3        链表数据元素为:4        链表数据元素为:5        链表数据元素为:6        链表数据元素为:7        链表数据元素为:8        链表数据元素为:10

 当前结点: 8    上一个结点: 7    下一个结点:10

链表数据元素为:1        链表数据元素为:2        链表数据元素为:3        链表数据元素为:4        链表数据元素为:5        链表数据元素为:6        链表数据元素为:7        链表数据元素为:10

 当前结点: 10   上一个结点: 7    下一个结点:-842150451

链表数据元素为:1        链表数据元素为:2        链表数据元素为:3        链表数据元素为:4        链表数据元素为:5        链表数据元素为:6        链表数据元素为:7

 当前结点: 2    上一个结点: 1    下一个结点:3

链表数据元素为:1        链表数据元素为:3        链表数据元素为:4        链表数据元素为:5        链表数据元素为:6        链表数据元素为:7

第5出圈的编号:5

 当前结点: 5    上一个结点: 4    下一个结点:6

链表数据元素为:1        链表数据元素为:3        链表数据元素为:4        链表数据元素为:6        链表数据元素为:7        

 当前结点: 3    上一个结点: 1    下一个结点:4

链表数据元素为:1        链表数据元素为:4        链表数据元素为:6        链表数据元素为:7

 当前结点: 4    上一个结点: 1    下一个结点:6

链表数据元素为:1        链表数据元素为:6        链表数据元素为:7

 当前结点: 1    上一个结点: -842150451   下一个结点:6

链表数据元素为:6        链表数据元素为:7

 当前结点: 6    上一个结点: -842150451   下一个结点:7

链表数据元素为:7

 当前结点: 7    上一个结点: -842150451   下一个结点:-842150451

最后出圈的编号:7
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小森程序员

若能帮助到你,小费自愿付费

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值