java约瑟夫环迭代器_Josephus约瑟夫环问题的不同实现方法与总结
/************************************************************************/
/*? ? ? ? ? ? ? ? ? Josephus問(wèn)題——數(shù)組實(shí)現(xiàn)? ? ? ? ? ? ? ? ? ? ? ? ? */
/************************************************************************/
#include
#include
int Josephus(int times, int number, int id){
int *a;
int i, count = 0, t = 0;
a = (int *)malloc(sizeof(int) * number);
for(i = 0; i < number; i++)
a[i] = i + 1;? ? ? ? ? ? // 數(shù)組a用于儲(chǔ)存每個(gè)元素的編號(hào)
i = id - 1;
while(count < number - 1){
if(a[i] != 0)
t++;
if(t == times){
t = 0;
count++;
printf("%4d", a[i]);
a[i] = 0;? ? ? ? ? ? ? ? // 當(dāng)該元素被剔除時(shí),該數(shù)組元素置為0
}
i++;
if(i == number)
i = 0;
}
for(i=0;i
if(a[i]!=0)
{
printf("\n最后剩余的結(jié)點(diǎn)是:%4d\n",a[i]);
return;
}
}
int main(){
int times, number, id;
printf("請(qǐng)輸入總?cè)藬?shù):");
scanf("%d", &number);
printf("請(qǐng)輸入報(bào)數(shù)周期:");
scanf("%d", ×);
printf("請(qǐng)輸入開(kāi)始報(bào)數(shù)的編號(hào):");
scanf("%d", &id);
Josephus(times, number, id);
return 0;
}
/************************************************************************/
/* 總結(jié):
優(yōu)點(diǎn)為可以得出每次被剔除的元素編號(hào)
缺點(diǎn)為內(nèi)存空間占用較大,沒(méi)有數(shù)學(xué)歸納法快速? ? ? ? ? ? ? ? ? ? ? ? */
/************************************************************************/
/************************************************************************/
/*? ? ? ? ? ? ? ? ? Josephus問(wèn)題——循環(huán)鏈表實(shí)現(xiàn)? ? ? ? ? ? ? ? ? ? ? */
/************************************************************************/
#include
#include
typedef struct LNode
{
int data;
struct LNode *next;
}LNode,*Linkhead;
void Josephus(int m,int n,int k)
{
Linkhead p,r,head = NULL;
int i;
for(i = 1;i <= n;i++)
{
p = (Linkhead)malloc(sizeof(LNode));//申請(qǐng)一個(gè)新的鏈結(jié)點(diǎn)
p->data = i;//存放第i個(gè)結(jié)點(diǎn)的編號(hào)
if(head == NULL)
head = p;
else
r->next = p;? ? ? // 因?yàn)镮nsert和Del操作都需要之前一個(gè)節(jié)點(diǎn)的地址,故用r來(lái)存儲(chǔ)。其作用類(lèi)似棧的top
r = p;
}
p->next = head;//至此,建立一個(gè)循環(huán)鏈表
p = head;
for(i = 1;i < k;i++)
{
r=p;
/*請(qǐng)注意,此行不是多余的,因?yàn)楫?dāng)k!=1,但m=1時(shí)如果沒(méi)有這條語(yǔ)句,此時(shí)刪除動(dòng)作無(wú)法完成*/
p=p->next;
}? ? ? ? //此時(shí)p指向第1個(gè)出發(fā)結(jié)點(diǎn)
while(p->next != p)
{
for(i = 1;i < m;i++)
{
r = p;
p = p->next;
}? ? ? ? ? ? ? ? ? ? ? ? //p指向第m個(gè)結(jié)點(diǎn),r指向第m-1個(gè)結(jié)點(diǎn)
r->next = p->next;? ? ? ? //刪除第m個(gè)結(jié)點(diǎn)
printf("%4d",p->data);? ? //依次輸出刪除結(jié)點(diǎn)的編號(hào)
free(p);? ? ? ? ? ? ? ? //釋放被刪除結(jié)點(diǎn)的空間
p = r->next;? ? ? ? ? ? //p指向新的出發(fā)結(jié)點(diǎn)
}
printf("\n最后剩余的結(jié)點(diǎn)是:%4d\n",p->data);//輸出最后一個(gè)結(jié)點(diǎn)的編號(hào)
}
int main(){
int times, number, id;
printf("請(qǐng)輸入總?cè)藬?shù):");
scanf("%d", &number);
printf("請(qǐng)輸入報(bào)數(shù)周期:");
scanf("%d", ×);
printf("請(qǐng)輸入開(kāi)始報(bào)數(shù)的編號(hào):");
scanf("%d", &id);
Josephus(times, number, id);
return 0;
}
/************************************************************************/
/* 總結(jié):
優(yōu)點(diǎn)為可以得出每次被剔除的元素編號(hào)
缺點(diǎn)為相較數(shù)組方法需要更多的計(jì)算量
總體而言與數(shù)組方法相差無(wú)幾? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? */
/************************************************************************/
/************************************************************************/
/*? ? ? ? ? ? Josephus問(wèn)題——數(shù)學(xué)歸納法直接計(jì)算? ? ? ? ? ? ? ? ? ? ? */
/************************************************************************/
#include
int main() {
int answer = 0;
int times, number, i, id;? ? // number為環(huán)內(nèi)總元素個(gè)數(shù),times為報(bào)數(shù)周期, id為從第幾個(gè)元素開(kāi)始報(bào)數(shù)
printf("請(qǐng)分別輸入總?cè)藬?shù)和循環(huán)次數(shù):");
scanf("%d %d", &number, ×);
printf("起始報(bào)號(hào)者的編號(hào):");
scanf("%d", &id);
for(i = 1; i <= number; i++) {
answer = (answer + times) % i;? ? ? // 核心算法,利用數(shù)學(xué)歸納法得出
}
if(answer + id == number)
printf("Survial: %d\n", number);? ? // 防止當(dāng)幸存者為最后一個(gè)編號(hào)時(shí)輸出0的情況
else
printf("Survival: %d\n",(answer + id) % number);
// 這邊利用number對(duì)answer進(jìn)行取余操作以防止編號(hào)數(shù)值超過(guò)最大編號(hào)(溢出)
return 0;
}
對(duì)于Josephus問(wèn)題有兩個(gè)地方是可以進(jìn)行優(yōu)化的。 (總?cè)藬?shù)為N,編號(hào)為從0~N-1;經(jīng)過(guò)M次報(bào)數(shù)去除一個(gè)成員,剩余成員個(gè)數(shù)為numleft, 記M%numleft為mPrime)
1、被移除的成員離上一個(gè)成員之間的距離是M%numleft-1(報(bào)數(shù)次為M%numleft).當(dāng)M大于N時(shí),該計(jì)算方式將節(jié)省大量時(shí)間
2、當(dāng)mPrime大于numleft的時(shí)候可以反向遍歷該表來(lái)查找要去除的成員。這樣可以節(jié)省時(shí)間。同樣這也就要求了該表必須是一個(gè)雙向表才行。(即含有Previous方法)
該算法實(shí)現(xiàn)原理即為:
第一輪,必定為編號(hào)M%N-1的成員被去除,第二輪為在第一輪的基礎(chǔ)上即從編號(hào)為M%N的成員開(kāi)始正移mPrime-1個(gè)單位(或者反移numleft-mPrime-1個(gè)單位)。若將M%N即為編號(hào)0,開(kāi)始重新編號(hào),那么第二輪被刪除的成員編號(hào)便是M%(numleft)-1,由此可得該輪要被刪除的成員與上一輪去除成員之間的距離為M%numleft,這里可利用迭代器來(lái)實(shí)現(xiàn)。
這里我們便可以得到成員編號(hào)與該輪成員數(shù)目的關(guān)系是:(n表示該輪所剩余的成員數(shù)目,Index(n)表示該輪成員的編號(hào)(從0開(kāi)始))
Index(n) = (Index(n - 1) + m) % n。
那么按照這個(gè)過(guò)程,我們這樣一直移除元素下去,肯定能夠找到最后一個(gè)被移除的元素。
這個(gè)元素則對(duì)應(yīng)只有一個(gè)元素的環(huán),很顯然,它的值為0。也就是Index(1) = 0。
對(duì)于這個(gè)元素的索引,它對(duì)應(yīng)兩個(gè)元素的索引是多少呢?
按照前面的過(guò)程,我們倒推回去就是了。Index(2) = (Index(1) + m) % 2。
那么對(duì)應(yīng)3個(gè),4個(gè)元素的呢?我們這樣一路繼續(xù)下去就可以找到對(duì)應(yīng)到n個(gè)元素的索引了。
所以,我們發(fā)現(xiàn)了一個(gè)有意思的數(shù)學(xué)歸納關(guān)系:
f(1) = 0,? f(n) = (f(n - 1) + m) % n。
按照這個(gè)關(guān)系,我們可以得到最后一個(gè)被取出來(lái)的元素對(duì)應(yīng)到n個(gè)元素的環(huán)里的索引值。
至此,我們可以發(fā)現(xiàn),利用count計(jì)數(shù)從而刪除成員的方法與此相比起來(lái)遜色不少,故之后我們將采用此方法來(lái)解決問(wèn)題。
該問(wèn)題的最終解決程序可參見(jiàn)另一篇文章: Java實(shí)現(xiàn) Josephus約瑟夫環(huán)問(wèn)題? http://www.linuxidc.com/Linux/2017-05/144055.htm
總結(jié)
以上是生活随笔為你收集整理的java约瑟夫环迭代器_Josephus约瑟夫环问题的不同实现方法与总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: mysql数据库二进制_Mysql数据库
- 下一篇: 嵌入式编程要不要学数据结构_少儿编程要不