約瑟夫問題有很多種解法及其變種,這裡的約瑟夫環問題是這樣的:
約瑟夫環(約瑟夫問題)是乙個數學的應用問題:已知n個人(以編號1,2,3...n分別表示)圍坐在一張圓桌周圍。從編號為k的人開始報數,數到m的那個人出列;他的下乙個人又從1開始報數,數到m的那個人又出列;依此規律重複下去,直到圓桌周圍的人全部出列.
大多數的約瑟夫環問題解法是利用面向過程的方法編寫的(其實我沒有看過多少。這裡我給出乙個利用c++物件導向的程式設計思想編寫的**,用於解決上面的約瑟夫環問題。這裡的核心演算法也是動態鍊錶。
首先闡述一下我的演算法思想:
每個參加遊戲的人看做是乙個鍊錶中的乙個結點,結點的內容為:
想像一下n個人圍坐成一圈,手拉著手。這裡的鍊錶實現也是一樣的,將n個結點首尾相連,形成乙個環。像這樣:
現在假設某一結點是表頭,如:
又假設關鍵數(要數的那個數)m=3,那麼第一輪出局的將會是表頭下乙個的下乙個(表頭的第三個),如圖所示:
要將這個結點踢出局外,也就是將它上乙個結點的指向下乙個結點的指標指向要出局的結點的下一結點,同時為了保持這個環,還要設定要出局的結點的下一結點的指向上一結點的指標指向要出局的結點的上一結點。如圖:
最後不要忘了刪除那個不要的結點。對分配在堆上的物件,c++是要手動進行記憶體管理的。
上面是主要的思想,下面是演算法的實現
首先定義結點:
struct _josephus
;
然後定義操作的類
//操作類
class josephus
~josephus();
void createlink();//建立整個鍊錶,並儲存表頭在head裡。整個鍊錶將構成乙個環
void action();//利用建立好的鍊錶,並返回結果
vectorjose;//儲存的結果
private:
int count;//參加遊戲的人數
int number;//關鍵數字m
_josephus* head;//表頭
renode startagain(_josephus*);//傳入(新的)開始的結點,返回renode並且完成搭橋過程
};
void createlink();將用於建立這個鍊錶,並將表頭儲存在josephus類的資料成員head中。 函式定義如下:
void josephus::createlink()
//將這個鍊錶構成乙個環
next->next = head;
head->previous = next;
this->head = head;
}
這個函式應該不難,大家先這樣看看吧。
renode startagain(_josephus*)是乙個主要的函式,大家應該也注意到了前面的返回型別renode到底是什麼呢?下面我來和大家說說吧。
renode的定義如下:
//下面是輔助類
struct renode
;
成員result儲存的是要出局的那個人的編號,而curr是下一輪要開始的結點。有了這個輔助結構,演算法會簡單很多。
renode startagain(_josephus*)的函式定義如下:
renode josephus::startagain(_josephus* head)
else
//退出while時,head剛好是數到this->number的那個結點
//步驟2.得到renode
//設定renode
node.curr = head->next;
node.result = head->data;
//步驟3.
head->previous->next = head->next;
head->next->previous = head->previous;
進行記憶體管理——釋放游離的結點的記憶體
delete head;
}return node;
}
最後我們來看看最後乙個函式void josephus::action();它的作用是將每一輪要出局的人的編號儲存在類的jose中,jose是乙個[code=c]vectot[/code],用於儲存整個遊戲的結果,並且開始新一輪的遊戲,直到所有人都出局。
函式void josephus::action();的定義如下:
void josephus::action()
}
到此,整個演算法的思想和主要的**都列出來了。
下面給出完整的實現**:
在檔案中josephus.h
#pragma once
#ifndef __josehpus__hh
#define __josehpus__hh
#includeusing std::vector;
//真正的結點
struct _josephus
;//下面是輔助類
struct renode
;//操作類
class josephus
~josephus();
void createlink();//建立整個鍊錶,並儲存表頭在head裡。整個鍊錶將構成乙個環
void action();//利用建立好的鍊錶,並返回結果
vectorjose;//儲存的結果
private:
int count;
int number;
_josephus* head;//表頭
renode startagain(_josephus*);//傳入(新的)開始的結點,返回renode並且完成搭橋過程
};#endif
在檔案josephus.cpp中
#include "josephus.h"
josephus::~josephus()
void josephus::createlink()
//將這個鍊錶構成乙個環
next->next = head;
head->previous = next;
this->head = head;
}void josephus::action()
}renode josephus::startagain(_josephus* head)
else
//退出while時,head剛好是數到this->number的那個結點
//步驟2.得到renode
//設定renode
node.curr = head->next;
node.result = head->data;
//步驟3.
head->previous->next = head->next;
head->next->previous = head->previous;
進行記憶體管理——釋放游離的結點的記憶體
delete head;
}return node;
}
最後還有乙個用於輔助的標頭檔案,內容如下:
在nhelper.h中
#include#ifndef __namespacehelper__hh__
#define __namespacehelper__hh__
#define nh__hh using std::cin;using std::cout;using std::endl;
#endif
JAVA求解約瑟夫環
與前面我們介紹的大多數程式問題一樣,約瑟夫環問題也是來自於乙個故事。這個故事發生在乙個名叫約瑟夫的猶太人身上,據說在羅馬人占領喬塔帕特後,39 個猶太人與約瑟夫及他的朋友躲到乙個洞中,39個猶太人決定寧願死也不要被敵人到,於是決定了乙個自殺方式,41個人排成乙個圓圈,由第1個人 開始報數,每報數到第...
兩種方法求解 約瑟夫環
題目描述 已知n個人 以編號1,2,3.n分別表示 圍坐在一張圓桌周圍。從編號為0的人開始報數,數到2的那個人出列 他的下乙個人又從0開始報數,數到2的那個人又出列 依此規律重複下去,直到圓桌周圍的人全部出列。解法一 基於陣列實現 public void solution int totalnum,...
使用單鏈表求解約瑟夫環問題
約瑟夫環 約瑟夫問題 是乙個數學的應用問題 已知n個人 以編號1,2,3.n分別表示 圍坐在一張圓桌周圍。從編號為k的人開始報數,數到m的那個人出列 他的下乙個人又從1開始報數,數到m的那個人又出列 依此規律重複下去,直到圓桌周圍的人全部出列。單鏈表參考 約瑟夫環運作如下 1 一群人圍在一起坐成環狀...