问题:
M个人围成一圈,从第一个开始报数,第N个将被杀掉,最后剩下一个,其余人都将被杀掉。例如M=6,N=5,被杀掉的顺序是:5,4,6,2,3。
解决问题的思路
利用环形链表的闭合性,移动链表指针并删除元素,直至最后一个元素。
源代码
List接口
package com.zarek;
public interface List<E> {
static final int ELEMENT_NOT_FOUND = -1;
/**
*
* @return 元素个数
*/
int size();
/**
* 清空元素
*/
void clear();
/**
* 返回指定位置的元素
* @param index
* @return
*/
int indexOf(E element);
/**
* 判断元素是否存在
* @param element
* @return 布尔值
*/
boolean contains(E element);
/**
* 判断是否为空
* @return
*/
boolean isEmpty();
/**
* 向指定位置添加元素并返回原来位置的元素
* @param index
* @param element
* @return 原来位置的元素
*/
void add(int index,E element);
/**
* 向末尾添加元素并返回原来位置的元素
* @param element
* @return 原来位置的元素
*/
void add(E element);
/**
* 删除指定位置的元素,并返回删除元素
* @param index
* @return 被删除的元素
*/
E remove(int index);
/**
* 获取指定位置的元素并返回
* @param index
* @return 指定位置的元素
*/
E get(int index);
/**
* 设置指定位置的元素,并返回原来此位置的元素
* @param index
* @param element
* @return 原来的元素
*/
E set(int index,E element);
}
抽象类AbstractList
package com.zarek;
public abstract class AbstractList<E> implements List<E> {
protected int size;
public E[] elements;
/**
*
* @return 元素个数
*/
public int size() {
return size;
}
/**
* 是否为空
* @return 布尔值
*/
public boolean isEmpty() {
return size == 0;
}
/**
* 判断元素是否存在
* @param element
* @return 布尔值
*/
public boolean contains(E element) {
return indexOf(element) != ELEMENT_NOT_FOUND;
}
/**
* 向动态数组末尾添加元素并返回原来位置的元素
* @param element
* @return 原来位置的元素
*/
public void add(E element) {
add(size,element);
}
protected void OutOfBounds(int index) {
throw new IndexOutOfBoundsException("index:"+index+",size:"+size);
}
/**
* 检查添加元素的index值是否越界
* @param index
*/
protected void rangeCheckForAdd(int index) {
if(index < 0 || index > size) {
OutOfBounds(index);
}
}
protected void rangeCheck(int index) {
if(index < 0 || index >= size) {
OutOfBounds(index);
}
}
}
双向循环链表
对约瑟夫问题最重要的成员和方法
current 指向当前节点的指针
reset() 让current指向first
next() 让current往后走一步,也就是current = current.next
remove() 删除current当前指向的节点
package com.zarek.circle;
import com.zarek.AbstractList;
public class CircleLinkedList<E> extends AbstractList<E> {
private Node<E> first;
private Node<E> last;
private Node<E> current;
private static class Node<E>{
E element;
Node<E> prev;
Node<E> next;
public Node(Node<E> prev,E element,Node<E> next) {
this.prev = prev;
this.element = element;
this.next = next;
}
}
/**
* 让current指向first
*/
public void reset() {
current = first;
}
/**
* 让current往后走一步,也就是current = current.next
* @return
*/
public E next() {
if(current == null)return null;
current = current.next;
return current.element;
}
/**
* 删除当前节点,并将current = current.next
* @return
*/
public E remove() {
if(current == null)return null;
Node<E> next = current.next;
// remove(indexOf(current.element));
E element = remove(current);
if(size == 0) {
current = null;
}else {
current = next;
}
return element;
}
@Override
public void clear() {
first = null;
last = null;
size = 0;
}
@Override
public int indexOf(E element) {
Node<E> node = first;
if(element == null) {
for (int i = 0; i < size; i++) {
if(node.element == null)return i;
node = node.next;
}
}else {
for (int i = 0; i < size; i++) {
if(element.equals(node.element))return i;
node = node.next;
}
}
return ELEMENT_NOT_FOUND;
}
@Override
public void add(int index, E element) {
rangeCheckForAdd(index);
if(index == size) {
Node<E> node = new Node<E>(last, element, first);
if(last == null) {//这是链表添加的第一个元素
first = node;
last = node;
node.prev = node;
node.next = node;
}else {
last.next = node;
last = node;
first.prev = node;
}
}else {
Node<E> next = node(index);
Node<E> prev = next.prev;
Node<E> node = new Node<E>(prev, element, next);
prev = node;
if(next == first) {//index == 0
first = node;
}
}
size++;
}
@Override
public E remove(int index) {
rangeCheck(index);
return remove(node(index));
}
private E remove(Node<E> node) {
if(size == 1) {
first = null;
last = null;
}else {
node.prev.next = node.next;
node.next.prev = node.prev;
if(node == first) {//如果删除的是第一个节点
first = node.next;
}
if(node == last) {//如果删除的是最后一个节点
last = node.prev;
}
}
size--;
return node.element;
}
@Override
public E get(int index) {
return node(index).element;
}
@Override
public E set(int index, E element) {
Node<E> node = node(index);
E oldE = node.element;
node.element = element;
return oldE;
}
public Node<E> node(int index){
rangeCheck(index);
if(index < (size >> 1)) {
Node<E> node = first;
for (int i = 0; i < index; i++) {
node = node.next;
}
return node;
}else {
Node<E> node = last;
for (int i = size - 1; i > index; i--) {
node = node.prev;
}
return node;
}
}
@Override
public String toString() {
StringBuilder sBuilder = new StringBuilder();
sBuilder.append("size:").append(size).append("[");
Node<E> node = first;
for (int i = 0; i < size; i++) {
if(node.prev == null) {
sBuilder.append("null_");
}else {
sBuilder.append(node.prev.element).append("_");
}
sBuilder.append(node.element);
if(node.next == null) {
sBuilder.append("_null");
}else {
sBuilder.append("_").append(node.next.element).append(",");
}
node = node.next;
}
sBuilder.append("]");
return sBuilder.toString();
}
}
测试代码
package com.zarek;
import com.zarek.circle.CircleLinkedList;
public class Main {
public static void main(String[] args) {
josephus(3);
}
static void josephus(int n) {
CircleLinkedList<Integer> list = new CircleLinkedList<Integer>();
for (int i = 1; i < 9; i++) {
list.add(i);
}
// 指向头节点
list.reset();
// n为要过第几个人删除
int init = n;
System.out.println("删除的顺序是:");
while(!list.isEmpty()) {
// 无论数几个人删除,都可以通过下面的代码执行
while(init-- > 1) {
list.next();
}
// list.next();
// list.next();
int element = list.remove();
System.out.println(element);
if(list.size == 0) {
System.out.println("最后留下的是:"+element);
}
init = n;
}
}
}
总结
约瑟夫问题使用循环链表(单向循环链表和双向循环链表)比较容易解决