数据结构课程设计之约瑟夫(Joeph)环

约瑟夫Joeph环,刚一听觉得挺难,但其实就是一个链表,并不是多难。具体的要求如下:

[问题描述]

约瑟夫(Joeph)问题的一种描述是:编号为1,2,…,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人全部出列为止。试设计一个程序求出出列顺序。 

[基本要求]

利用单向循环链表存储结构模拟此过程,按照出列的顺序印出各人的编号。

[测试数据]

m的初值为20;密码:3,1,7,2,4,8,4(正确的结果应为6,1,4,7,2,3,5)。

[实现提示]

程序运行后首先要求用户指定初始报数上限值m,然后读取各人的密码。设n≤30。


算法的实现其实并不难,需要自定义一个Node类,即节点类,里面有成员变量no、pass、position,分别是节点的编号,节点的密

码,节点对应的图片的编号。然后建立单向循环链表,即链表的尾节点指向头结点,利用初始密码m遍历链表,找到对应的节点,将

的编号输出,并得到它的密码作为新的m值继续遍历,直到删除全部的节点为止。而最主要的是动画的实现,利用线程的休眠和不

断地重画可以实现动画效果,需要注意的是,循环中的repaint方法只会执行一次,即最后执行一次,如何让它每次循环都执行一

次,出现动画效果呢?这里把循环放在一个线程中即可,而它执行一次是因为主线程的阻塞问题。

主要的代码如下:

               new Thread(new Runnable(){
public void run()
{
//输出报数的人的编号,即出列
Node points;   //中间的辅助节点
for(int k=0;k<n;k++)
{
String m1 = String.valueOf(m);  //将int型的值转为string类型的值
l7.setText(m1);  //在m值的显示处显示当前m值

points = pointer;
if(m==1)  //当密码为1 时的操作
{
number(n-k,m,pointer.no,pointer.position);

while(points.next != pointer)
{
points = points.next;
}

try 
{
Thread.sleep(m*1000+500);
} catch (InterruptedException e1)
    {
e1.printStackTrace();
}

remove(pointer.position,n,pointer);
Node p = pointer;
for(int i=p.position;i<(n-k-1);i++)
{
p.next.position = p.next.position-1;
p = p.next;
}

m = pointer.pass;  //重新辅密码m的值

String no1 = String.valueOf(pointer.no);
t4.setText(no1);  //单个输出出列者的编号


ta1.setText(ta1.getText()+no1+ "\n");  //在主框中输出全部的出列人的编号

pointer = pointer.next;  //删除找到的节点
points.next = pointer;
}
else  //密码不为1时的操作
{
number(n-k,m,pointer.no,pointer.position);

for(int l=1;l<m;l++)
{
points = pointer;
pointer = pointer.next;
}

try 
{
Thread.sleep(m*1000+500);
} catch (InterruptedException e1)
    {
e1.printStackTrace();
}

remove(pointer.position,n,pointer);
Node p = pointer;
for(int i=p.position;i<(n-k-1);i++)
{
p.next.position = p.next.position-1;
p = p.next;
}

m = pointer.pass;  //重新辅密码m的值

      String no2 = String.valueOf(pointer.no);
      t4.setText(no2);  //单个输出出列者的编号


      ta1.setText(ta1.getText()+no2+ "\n");  //在主框中输出全部的出列人的编号
     
pointer = pointer.next;  //删除找到的节点
points.next = pointer;
}

}
}
}).start();

这里的remove和number方法是擦除相应的图片和报数的方法,这里的报数方法比较难写,原来用数组存的图发现它和循环的i很难有

一定的关系,所以在思索后决定用ArrayList存这些图片,问题就解决了,两个方法的具体代码如下:

public void remove(int n,int n1,Node pointer)  //删除图片的方法,即有人出列,n为出列的人的图片的编号,n1为总人数,pointer是要删除的节点
{
jl1.get(n).setIcon(null);
jl2.get(n).setText(null);
jl1.remove(n);
jl2.remove(n);
p1.repaint();  
}


public void number(final int n,final int m,final int no,final int position)  //n为当前人数,m为密码值,no为删除的人后面的人的编号,position为删除的人的后面的人的图片编号
{
new Thread(new Runnable(){
public void run()
{
int i = 0;
int num1;

while(i<m)
{
num1 = position+i;
if(num1>=n)
{
num1 = num1%n;
}

String st = String.valueOf(i+1);  //将数字转换成字符串

if(jl1.get(num1).getIcon() != null)
{
jl2.get(num1).setText(st);
repaint();

try 
{
Thread.sleep(1000);
} catch (InterruptedException e1)
   {
e1.printStackTrace();
}

jl2.get(num1).setText(null);
repaint();
}

i = i+1;
}
}
}).start();


}
}


最后做出的动画效果在预料之中,算是比较好的一次课设,前后大概一个星期,感触颇深,发现自己还是开发实践的次数少,经验

少。但也让我明白:不迈出第一步,永远也到不了终点!



源码下载地址:


CSDN: http://download.csdn.net/download/u014267402/9696076

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值