约瑟夫环问题是一个很经典算法。
问题描述:N个人围成一圈,从第一个人开始报数,报到m的人出圈,剩下的人继续从1开始报数,报到m的人出圈;如此往复,直到所有人出圈。(模拟此过程,输出出圈的人的序号)
解决思路:
1、创建一个有N个人的环(可以是数组或链表)
2、从第一个人开始报数,当所报数字等于m时几下这个人的位置(pos = (m-1)%N)
3、删除环中该位置的数据
4、重复1、2、3步骤,直到环中只有一个数据
下面分别用三种不同的数据结构来处理该问题:
1、用数组解决约瑟夫环问题
/**
* 用数组解决约瑟夫环问题
* @param people
* @param num
*/
static void josephusArray(String[] people,int num){
int len = people.length;
while (len>1){
int pos = (num-1)%len;
System.out.println("出圈:"+people[pos]);
//重新生成数组
String[] newpeople = new String[len-1];
int m=0;
//数组拷贝
for(int i=0;i<len;i++){
if(i!=pos){
newpeople[m]=people[i];
m++;
}
}
len--;
}
System.out.println("出圈:"+people[0]);
}
2、用ArrayList解决问题
/**
* 用 ArrayList
* @param people
* @param num
*/
static void josephusArrayList(ArrayList<String> people,int num){
int len = people.size();
while(len>1){
int pos = (num-1)%len;
System.out.println("出圈:"+people.get(pos));
people.remove(pos);
len--;
}
System.out.println("出圈:"+people.get(0));
}
3、用LinkedList解决问题
/**
* 用 LinkedList
* @param people
* @param num
*/
static void josephusLinkedList(LinkedList<String> people,int num){
int len = people.size();
while(len>1){
int pos = (num-1)%len;
System.out.println("出圈:"+people.get(pos));
people.remove(pos);
len--;
}
System.out.println("出圈:"+people.get(0));
}
最后对性能做个比较:
public static void main(String ars[]){
//数组
String[] s=new String[100000];
for(int l=0;l<100000;l++){
s[l]=(((char)(Math.random()*26+'A')+""));
}
long begin = System.currentTimeMillis();
josephusArray(s,6);
System.out.println("数组用时: "+(System.currentTimeMillis()-begin));
//ArrayList
ArrayList<String> s2= new ArrayList();
for(int l=0;l<100000;l++){
s2.add(((char)(Math.random()*26+'A')+""));
}
begin = System.currentTimeMillis();
josephusArrayList(s2,6);
System.out.println("ArrayList用时:"+(System.currentTimeMillis()-begin));
//LinkedList
LinkedList<String> s3= new LinkedList();
for(int l=0;l<100000;l++){
s3.add(((char)(Math.random()*26+'A')+""));
}
begin = System.currentTimeMillis();
josephusLinkedList(s3,6);
System.out.println("LinkedList用时:"+(System.currentTimeMillis()-begin));
}
结果如下:
数组用时: 8938
ArrayList用时:462
LinkedList用时:5
结果分析:
解决约瑟夫环问题时涉及到环中数据的删除操作,数组在内存中占用一组连续的空间,删除某个元素其他元素都要向前移动,除非删除的是最后一个元素,所以用数组解决约瑟夫环问题比较消耗资源;
ArrayList是java在数组的基础上实现的动态数组,对很多细节进行了封装,但本质还是数组;
LinkedList是用链表数据结构实现的,插入和删除数据的时间复杂度都是O(1),因此在解决约瑟夫环问题上有很大优势。