資料結構實戰——Joseph 環的實現
問題描述
約瑟夫環問題(Joseph)又稱丟手絹問題:已知 m 個人圍坐成一圈,由某人起頭,下一個人開始從 1 遞增報數,報到數字 n 的那個人出列,他的下一個人又從 1 開始報數,數到 n 的那個人又出列;依此規律重複下去,直到 m 個人全部出列約瑟夫環結束。如果從 0 ~ (m-1) 給這 m 個人編號,請輸出這 m 個人的出列順序。
解決思路
本題的解決思路有兩種:一是用迴圈連結串列解決,這會在後續的部落格中給出解決方法;二是用線性表陣列表示法解決。
線性表陣列解決方式有 2 種:1 是利用上篇部落格提到的 ListDelete 函式,凡是數到 n 的那個出列元素直接刪去;2 是設定標記,凡是數到 n 的那個出列元素,置為 -1 ,下一輪開始值為 -1 的不參與報數。
如何用陣列表示迴圈呢,即現在的問題是,數到 m-1 ,如何再尋回至0 ?這裡可以採用 取模運算子 % ,即 i = (i+1) % m ,其中 i = [ 0 , m-1] 。
詳細程式碼
/* 實現Joseph Ring */ #include <stdio.h> #include <string.h> #include <stdlib.h> #include "SlistOperation.h" void InitJoseph(SLIST &L, int num){ for(int i=1;i<=num;i++){ ListInsert(L,i,i-1); } } void Joseph_1(SLIST L, int jump){ int st = 0, pos = 1, item, temp; while(!ListEmpty(L)){ while( st != jump ){ GetElem(L,pos,temp); //獲取當前pos位序的元素temp if (pos < ListLength(L)) //獲取temp的後繼item NextElem(L,temp,item); else item = L.A[0]; pos = LocateElem(L,item); //獲取後繼item的位序 st++; //用於判斷出圈元素 } ListDelete(L,pos,temp); //滿足條件的pos即刪除並列印 printf("%d ",temp); st = 1; if (pos > ListLength(L)) pos = 1; } printf("\n"); } void Joseph_2(SLIST L, int num, int jump){ int i = 0, pos = 1; for (int j = 0; j < num; j++){ //規定輸出次數為m while (i != jump){ if (pos == ListLength(L)) //獲取下一位 pos = 1; else pos++; if (L.A[pos-1] >= 0) //當前位置為-1,說明已出列 i++; } i = 0; printf("%d ",L.A[pos-1]); L.A[pos-1] = -1; //出列位記為-1 } } int main(){ int m,n; SLIST L; InitList(L); printf("請輸入環的總數: "); scanf("%d",&m); printf("請輸入跳數:"); scanf("%d",&n); if (m<=0 || n<=0){ printf("Input Error\n"); system("pause"); return 0; } InitJoseph(L,m); printf("\n變換前的初始環為:"); ListTravers(L); printf("\n約瑟夫環解法一為:"); //ListDelete()刪除出隊元素 Joseph_1(L,n); printf("\n約瑟夫環解法二為:"); //出隊元素置為-1 Joseph_2(L,m,n); printf("\n"); return 0; }
程式執行的結果示例,截圖如下:
數學求解
數學求解的思路是將約瑟夫問題歸納為數學問題,即推匯出遞推公式。好處是合理採用數學策略,使得程式設計簡單,時間複雜度為 O(n),但是隻能得到最後出列的那個人的序號。 對於 m 個人,編號為 0~(m-1) ,其中第 k 個人出列,即 k-1 出列。 -> 0, 1,... ... ,k-1,k,k+1,... ...,m-1 (1) 出列元素為 (n-1) % m。 -> 0, 1,... ... ,k-2,k,k+1,... ...,m-1 延長此序列為: -> 0, 1,... ... ,k-2,k,k+1,... ...,m-1,m,m+1,... ...,m+k-2 出去 0~k-2 元素 -> k,k+1,... ...,m-1,m,m+1,... ...,m+k-2 減去k -> 0, 1,... ... ,m-2(2) 上述過程演示的就是 m 個人到 m-1 個人的變化,即可以通過遞推得到約瑟夫環最後一個輸出元素。現在從(2)回推 (1) ,假設(2)中只剩下最後一個元素 x,如果回推到(1)中對應的位序是x`,那麼問題就得到了解決。 顯然我們可以得到 x` = (x+k) % m,於是就可以得到遞推公式:f[1] = 0;f[i] = (f[i-1] + n) % i ,(i > 1)。相關推薦
資料結構實戰——Joseph 環的實現
問題描述 約瑟夫環問題(Joseph)又稱丟手絹問題:已知 m 個人圍坐成一圈,由某人起頭,下一個人開始從 1 遞增報數,報到數字 n 的那個人出列,他的下一個人又從 1 開始報數,數到 n 的那個人又出列;依此規律重複下去,直到 m 個人全部出列約瑟夫環結束。如
資料結構基礎及STL實現(複習)
目錄 動態陣列 棧 佇列 優先佇列 動態陣列 srand(time(0)); std::vector<int> qwq; for(int i = 1;i <= 10;++i) qwq.push_back(rand(
資料結構實戰完全手冊-夏曹俊-專題視訊課程
資料結構實戰完全手冊—85人已學習 課程介紹 資料結構是程式設計的必修知識,它是程式設計的基本功,並且在企業面試、日常工作、研究生入學考試中都佔有重要的地位。不同於其他課程,本課程從
資料結構——棧操作的實現
#include <stdio.h> #include <malloc.h> #define OK 1 #define ERROR 0 #define INFEASIBLE -1 #define OVERFLOW -2 #define TRUE 1 #define FALSE
c_資料結構_隊的實現
# 鏈式儲存#include<stdio.h> #include<stdlib.h> #define STACK_INIT_SIZE 100//儲存空間初始分配量 #define STACKINCREMENT 10//儲存空間分配增量 #define TURE 1 #defi
【資料結構】堆的實現
文章目錄 Heap.h Heap.c Test.c Heap.h #ifndef __HEAP_H__ #define __HEAP_H__ #include<assert.h> #include
(資料結構)HashTable的實現
#include<iostream> #include<iomanip> #include<vector> #include<list> using namespace std; template<class Iterator,clas
資料結構-佇列-連結串列實現
程式碼實現 //佇列 連結串列實現 #include <stdio.h> #include <stdlib.h> #include <stdbool.h> //定義一個連結串列 typedef struct _Node Node; struct
資料結構-佇列-順序表實現-C語言
佇列定義 對於一個存取的n個內容,最先進入的最先出去(First In,First Out:FIFO),即稱為佇列. 比如,食堂排隊,最先去的,最先得到飯菜; 關鍵步驟:入隊出隊 程式碼實現 //迴圈佇列 順序表實現 #include <stdio
資料結構-堆疊-連結串列實現
/* * 堆疊 連結串列實現 * * */ #include <stdio.h> #include <stdlib.h> #include <stdbool.h> //定義結構 typedef struct _Stack * Stack; s
資料結構之連結串列實現佇列
#include<stdio.h>#include<malloc.h>#include<stdlib.h>#define OK 1#define ERROR 0typedef struct Node{ int data; struct Node *next;}Node,*L
資料結構&堆&heap&priority_queue&實現
目錄 什麼是堆? 大根堆 小根堆 堆的操作 什麼是堆? 堆是一種資料結構,可以用來實現優先佇列 大根堆 大根堆,顧名思義就是根節點最大。我們先用小根堆的建堆過程學習堆的思想。 小根堆 下圖為小根堆建堆過程 堆的操作 上浮 下沉 插入 彈出 取頂 堆排序 STL heap 所在庫 #include
【資料結構與演算法-java實現】二 複雜度分析(下):最好、最壞、平均、均攤時間複雜度的概念
上一篇文章學習了:如何分析、統計演算法的執行效率和資源消耗? 點選連結檢視上一篇文章:複雜度分析上 今天的文章學習以下內容: 最好情況時間複雜度 最壞情況時間複雜度 平均情況時間複雜度 均攤時間複雜度 1、最好與最壞情況時間複雜度 我們首先
資料結構——使用Java棧實現【括號匹配】
給定一個只包括 '(',')','{','}','[',']'的字串,判斷字串是否有效。 有效字串需滿足: 左括號必須用相同型別的右括號閉合。 左括號必須以正確的順序閉合。 注意空字串可被認為是有效字串。 參考leetcode.com或leetcode-cn.com
資料結構實戰01
題目: 這是一個約瑟夫環問題,用C語言陣列解決如下 #define MAXN 100 void printring(int a[],int n,int i,int k){ int b[MAXN],j,s; for(j=0;j<n;j++){ b[
資料結構C/C++程式碼實現 棧連結串列基本操作
實現棧連結串列基本操作: #include<stdio.h> #include<stdlib.h> typedef int ElemType; typedef struct linknode { ElemType data; stru
資料結構C/C++程式碼實現 順序表棧基本操作
順序表棧基本操作的實現 原始碼: #include<stdio.h> #include<stdlib.h> #include<iostream> using namespace std; #define MAXSIZE 100 //#d
資料結構學習筆記——C++實現雙向迴圈連結串列模板類(超詳解)
定義了兩個標頭檔案分別放置結點類模板(Node.h)和雙鏈表模板(DoubleLinkList.h), 然後在原始檔的main函式中測試。 Node.h #pragma once # include <iostream> template <class
【資料結構】順序表實現十進位制轉換任意進位制
/* & File : 進位制準換 * Author : Laugh * Copyright: Laugh * 主題 :對於輸入的任意一個非負十進位制小數,列印輸出與其等值的任意進位制小數 * Date : 2018/10/14 */
資料結構(C語言實現):判斷兩棵二叉樹是否相等,bug求解
判斷兩棵二叉樹是否相等。 遇到了bug,求大神幫忙!!! C語言原始碼: #include <stdio.h> #include <stdlib.h> #include <malloc.h> #define OK 1 #define