循環單向鏈表與約瑟夫問題

循環鏈表介紹

先不急著看約瑟夫問題是什么,先了解循環鏈表的結構,那什么是循環鏈表?

循環,顧名思義,從鏈表中第一個節點出發,還會遇到第一個節點,形成循環的一環。也就是說鏈表中最后一個節點的下一個節點是第一個節點,但是頭節點也是一個節點,所以最后一個節點的下一個節點應該是頭節點才對。

如下圖,有兩種情況:

其中更大的長方形是節點的數據域,更小的長方形是節點的指針域,指向鏈表中的下一個節點。

循環鏈表的代碼實現

因為解決約瑟夫問題,只需要初始化、插入、打印功能,所以別的功能就沒實現。

節點定義

首先,循環鏈表和普通鏈表節點的結構體定義一模一樣,那就寫出來吧。

typedef struct _LoopLinkList //循環鏈表
{int date;struct _LoopLinkList* next;
}LinkNode,LinkList;

?循環鏈表的初始化

初始化循環鏈表,其中函數的參數是一個指向頭節點的指針,如圖所示:

兩個箭頭有些重疊了,不過無傷大雅。

函數參數中的取地址符?& 是引用的意思,為C++特有的,相當于就在使用這個一級指針 L ,無需使用二級指針來接收這個一級指針 L 的地址,如果去掉這個 & ,會發生什么事呢?那就是 L 這個指針所指向的地址無法改變,但是可以改變所指向的變量的值。

bool initLinkList(LinkList *&L)
{L = new LinkNode;     //為頭結點申請空間if (!L) return false; // L為空指針,生成頭結點失敗L->next = L; //頭結點指向自己L->date = -1;return true;
}

如果上面那段話不太明白,可以先跳過,等寫完所有代碼,然后把初始化函數參數中的 & 去掉,在 IDE 中調試一下即可得出答案。

循環鏈表的插入(尾插法)

其中函數的參數節點指針 node 指向新加節點。

bool InsertBack(LinkList* &L, LinkNode* node)
{if (!L || !node) return false; //如果鏈表頭結點未創建或者傳入的結點指針指向空//分兩種情況,一是鏈表為空,只有頭結點存在if (L->next == L){node->next = L;L->next = node;}else{LinkNode* p = L;while (p->next != L){p = p->next;} //找到最后一個節點p->next = node;node->next = L;}return true;
}

循環鏈表的打印

從頭節點開始打印,直到又為頭節點。

bool LinkPrint(LinkList* L)
{if (!L) return false;LinkNode* p = L;p = L ->next;while (p != L){printf("%d ", p->date);p = p->next;}return true;
}

約瑟夫問題

解決了循環鏈表,就開始約瑟夫問題了,哈哈,這故事有很多的分支,我之前聽過的不是下面這種。

據說著名猶太歷史學家Josephus有過以下的故事:在羅馬人占領喬塔帕特后,39 個猶太人與Josephus及他的朋友躲到一個洞中,39個猶太人決定寧愿死也不要被敵人抓到,于是決定了一個自殺方式,41個人排成一個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺,然后再由下一個重新報數,直到所有人都自殺身亡為止。然而Josephus 和他的朋友并不想遵從。首先從一個人開始,越過k-2個人(因為第一個人已經被越過),并殺掉第k個人。接著,再越過k-1個人,并殺掉第k個人。這個過程沿著圓圈一直進行,直到最終只剩下一個人留下,這個人就可以繼續活著。問題是,給定了和,一開始要站在什么地方才能避免被處決。Josephus要他的朋友先假裝遵從,他將朋友與自己安排在第16個與第31個位置,于是逃過了這場死亡游戲。

——摘自約瑟夫問題_百度百科

?不過看完這個故事應該大概了解了約瑟夫問題,這個問題可以用循環鏈表解決,每一個人都是鏈表中一個節點,只要某個節點報數報到出圈的那個號碼,就把這個節點從鏈表中刪除。

由于原問題的人數實在太多,我這里就簡化一下,一共 10 人,報數報到 9 的人出圈,并且要求求出第五輪出圈的號碼,還有最后一個出圈的人的號碼,所以添加了兩個整型變量 loops、num來記錄。

首先在進入這個函數之前已經把 10 個節點插入了鏈表,第 n 個節點的值為 n ,例如:第一個節點的數據域為 1 。

代碼實現

其中函數參數 interval 為間隔,也就是出圈的號碼 9 。

bool Joseph(LinkList* &L,int interval)
{if ( !L || L->next == L) return false; // 頭節點未初始化或者是空鏈表if (interval < 1) return false; //報數的間隔也不能小于 1 , 1 的話還能玩,也就是一報數就死LinkNode* p = L , *q = NULL ; // q 指向要刪除的節點, p 指向要刪除的節點的前一個節點int loops = 0 , num = 0 ;     //loops表示進行到第幾輪,num保存著出圈的人的號碼int j = 1;while (L->next != L) //不為空鏈表{while ( j < interval ) //一直報數,除非j等于出圈的數-1,這時候指針p就指向了要刪除的節點的前一個節點{if (p->next != L){j++;}	p = p->next;}if (p->next == L) //如果p指向最后一個節點,那肯定不能刪除頭節點,應該刪除第一個節點,所以p賦值為頭節點{p = L;}//刪除q = p->next;num = q->date;p->next = q->next;delete q;j = 1;loops++;cout <<endl<< "這是第"<<loops<<"輪:" ;LinkPrint(L);if (loops == 5){printf("\n第5輪出圈的是:%d", num);}}printf("最后一個出圈的是:%d\n", num);return true;
}

?可能有人會想為什么其中循環的條件不是 i <= j 呢?因為在單向鏈表中,你刪除一個節點前,必須要讓刪除節點的上一個節點的next 指針指向刪除節點的下一個節點。

所以指向要刪除的節點的上一個節點就方便很多了

如下圖:

?

完整代碼以及運行結果

#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>using namespace std;
//結點結構體
typedef struct _LoopLinkList
{int date;struct _LoopLinkList* next;
}LinkNode,LinkList;//初始化
bool initLinkList(LinkList* &L)
{ L = new LinkNode;if (!L) return false; L->next = L; //指向自己L->date = -1;return true;
}//尾插法
bool InsertBack(LinkList* L, LinkNode* node)
{if (!L || !node) return false; if (L->next == L) //鏈表為空,只有頭結點{node->next = L;L->next = node;}else{LinkNode* p = L;while (p->next != L){p = p->next;}p->next = node;node->next = L;}return true;
}//打印
bool LinkPrint(LinkList* L)
{if (!L) return false;LinkNode* p = L;p = L ->next;while (p != L){printf("%d ", p->date);p = p->next;}return true;
}//解決joseph問題
bool Joseph(LinkList*& L, int interval)
{if (!L || L->next == L) return false; // 頭節點未初始化或者為空鏈表if (interval < 1) return false;  //報數的間隔LinkNode* p = L, * q = NULL; int loops = 0, num = 0;     //loops表示進行到第幾輪,num保存著最后一個出圈的人的號碼int j = 1;while (L->next != L) {while (j < interval) {if (p->next != L){j++;}p = p->next;}if (p->next == L) {p = L;}//此時 p 指向要刪除節點的前一個節點(不為最后一個節點)q = p->next;num = q->date;p->next = q->next;delete q;j = 1;loops++;cout << endl << "這是第" << loops << "輪:";LinkPrint(L);if (loops == 5){printf("\n第5輪出圈的是:%d", num);}}printf("最后一個出圈的是:%d\n", num);return true;
}
int main(void)
{LinkList* L = NULL ;LinkNode* e = NULL;//1.初始化循環鏈表initLinkList(L);//2.尾插循環鏈表for (int i = 1; i <= 10; i++){e = new LinkNode;e->date = i;e->next = NULL;InsertBack(L, e);}//3.打印鏈表LinkPrint(L);Joseph(L, 9);return 0;
}

---------------------------------------------------------------------------------------------------------------------------------

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/207710.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/207710.shtml
英文地址,請注明出處:http://en.pswp.cn/news/207710.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python 使用 watchdog 實現類似 Linux 中 tail -f 的功能

一、代碼實現 import logging import os import threading import timefrom watchdog.events import FileSystemEventHandler from watchdog.observers import Observerlogger logging.getLogger(__name__)class LogWatcher(FileSystemEventHandler):def __init__(self, log_…

《opencv實用探索·十五》inRange二值化圖像

opencv接口如下&#xff1a; void inRange(InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst);函數實現二值化功能&#xff0c;主要是將在兩個閾值內的像素值設置為白色&#xff08;255&#xff09;&#xff0c;而不在閾值區間內的像素值設置為黑色&am…

一篇文章帶你快速入門 Nuxt.js 服務端渲染

1. Nuxt.js 概述 1.1 我們一起做過的SPA SPA&#xff08;single page web application&#xff09;單頁 Web 應用&#xff0c;Web 不再是一張張頁面&#xff0c;而是一個整體的應用&#xff0c;一個由路由系統、數據系統、頁面&#xff08;組件&#xff09;系統等等&#xff0…

什么是HTTPS加密協議?HTTPS安全傳輸原理,SSL和TLS介紹,NGINX如何配置SSL證書

HTTPS介紹 HTTPS是超文本傳輸協議&#xff08;HTTP&#xff09;的安全版本。它使用SSL&#xff08;安全套接層&#xff09;或TLS&#xff08;傳輸層安全&#xff09;加密協議來保護數據傳輸的安全性和機密性&#xff0c;以防止未經授權的訪問和竊聽。HTTPS協議通常用于處理敏感…

HbuilderX使用Uniapp+Vue3安裝uview-plus

如果你是vue2版本想使用uniapp去配置uviewui庫可以參考之前的文章 小程序的第三方ui庫推薦較多的還是uview的&#xff0c;看起來比較美觀&#xff0c;功能也比較完善&#xff0c;下面將提一下Vue3安裝uview-plus庫的教程 創建項目 安裝 首先進入官網 uView-Plus 直接下載并導…

預訓練--微調

預訓練–微調 一個很簡單的道理&#xff0c;如果我們的模型是再ImageNet下訓練的&#xff0c;那么這個模型一定是會比較復雜的&#xff0c;意思就是這個模型可以識別到很多種類別的即泛化能力很強&#xff0c;但是如果要它精確的識別是否某種類別&#xff0c;它的表現可能就不…

07-2 Python模塊和命名空間

1. 模塊 概念&#xff1a;其實就是一個Python文件&#xff0c;正常文件有的變量&#xff0c;函數&#xff0c;類&#xff0c;模塊都有 功能:模塊可以被其它程序引入&#xff0c;以使用該模塊中的函數等功能。 示例&#xff1a;test-module.py調用mymodule.py模塊中的now_time…

充電樁IC

充電樁IC 電子元器件百科 文章目錄 充電樁IC前言一、充電樁IC是什么二、充電樁IC的類別三、充電樁IC的應用實例四、充電樁IC的工作原理總結前言 充電樁IC的設計和功能會根據不同的充電協議和市場需求進行調整和定制。目前市場上有許多不同型號和廠家的充電樁IC可供選擇,以滿足…

一篇文章帶你快速入門 Vue 核心語法

一篇文章帶你快速入門 Vue 核心語法 一、為什么要學習Vue 1.前端必備技能 2.崗位多&#xff0c;絕大互聯網公司都在使用Vue 3.提高開發效率 4.高薪必備技能&#xff08;Vue2Vue3&#xff09; 二、什么是Vue 概念&#xff1a;Vue (讀音 /vju?/&#xff0c;類似于 view) …

Mysql 日期函數大全

一、時間函數 &#xff08;一&#xff09;、獲取當前時間 1、NOW() 獲取當前日期和時間&#xff0c;在程序一開始執行便拿到時間 返回格式 YYYY-MM-DD hh:mm:ss eg&#xff1a; NOW() 得到 2023-12-03 12:20:02 NOW(),SLEEP(2),NOW() 得到 2023-12-03 12:20:02 | 0 | 2023-…

目標檢測——OverFeat算法解讀

論文&#xff1a;OverFeat: Integrated Recognition, Localization and Detection using Convolutional Networks 作者&#xff1a;Pierre Sermanet, David Eigen, Xiang Zhang, Michael Mathieu, Rob Fergus, Yann LeCun 鏈接&#xff1a;https://arxiv.org/abs/1312.6229 文章…

Go語言-讓我印象深刻的13個特性

我們正在加速進入云原生時代&#xff0c;Go語言作為云原生的一塊基石&#xff0c;確有它的獨到之處。本文介紹Go語言的幾個讓我印象深刻的特性。 1、兼顧開發效率和性能 Go語言兼顧開發效率和性能。可以像Python那樣有很快的開發速度&#xff0c;也可以像C那樣有很快的執行速…

SpringAOP專欄二《原理篇》

上一篇SpringAOP專欄一《使用教程篇》-CSDN博客介紹了SpringAop如何使用&#xff0c;這一篇文章就會介紹Spring AOP 的底層實現原理&#xff0c;并通過源代碼解析來詳細闡述其實現過程。 前言 Spring AOP 的實現原理是基于動態代理和字節碼操作的。不了解動態代理和字節碼操作…

【C語言】函數遞歸詳解(一)

目錄 1.什么是遞歸&#xff1a; 1.1遞歸的思想&#xff1a; 1.2遞歸的限制條件&#xff1a; 2.遞歸舉例&#xff1a; 2.1舉例1&#xff1a;求n的階乘&#xff1a; 2.1.1 分析和代碼實現&#xff1a; 2.1.2圖示遞歸過程&#xff1a; 2.2舉例2&#xff1a;順序打印一個整數的…

機器學習---集成學習的初步理解

1. 集成學習 集成學習(ensemble learning)是現在非常火爆的機器學習方法。它本身不是一個單獨的機器學 習算法&#xff0c;而是通過構建并結合多個機器學習器來完成學習任務。也就是我們常說的“博采眾長”。集 成學習可以用于分類問題集成&#xff0c;回歸問題集成&#xff…

多線程并發Ping腳本

1. 前言 最近需要ping地址&#xff0c;還是挺多的&#xff0c;就使用python搞一個ping腳本&#xff0c;記錄一下&#xff0c;以免丟失了。 2. 腳本介紹 首先檢查是否存在True.txt或False.txt文件&#xff0c;并在用戶確認后進行刪除&#xff0c;然后從IP.txt的文件中讀取IP地…

CSS——sticky定位

1. 大白話解釋sticky定位 粘性定位通俗來說&#xff0c;它就是相對定位relative和固定定位fixed的結合體&#xff0c;它的觸發過程分為三個階段 在最近可滾動容器沒有觸發滑動之前&#xff0c;sticky盒子的表現為相對定位relative【第一階段】&#xff0c; 但當最近可滾動容…

【MATLAB】tvfEMD信號分解+FFT+HHT組合算法

有意向獲取代碼&#xff0c;請轉文末觀看代碼獲取方式~也可轉原文鏈接獲取~ 1 基本定義 TVFEMDFFTHHT組合算法是一種結合了總體變分模態分解&#xff08;TVFEMD&#xff09;、傅里葉變換&#xff08;FFT&#xff09;和希爾伯特-黃變換&#xff08;HHT&#xff09;的信號分解方…

vivado時序方法檢查8

TIMING-30 &#xff1a; 生成時鐘所選主源管腳欠佳 生成時鐘 <clock_name> 所選的主源管腳欠佳 &#xff0c; 時序可能處于消極狀態。 描述 雖然 create_generated_clock 命令允許您指定任意參考時鐘 &#xff0c; 但是生成時鐘應引用在其直接扇入中傳輸的時鐘。此…

電子學會C/C++編程等級考試2021年06月(五級)真題解析

C/C++等級考試(1~8級)全部真題?點這里 第1題:數字變換 給定一個包含5個數字(0-9)的字符串,例如 “02943”,請將“12345”變換到它。 你可以采取3種操作進行變換 1. 交換相鄰的兩個數字 2. 將一個數字加1。如果加1后大于9,則變為0 3. 將一個數字加倍。如果加倍后大于…