单向环形链表实现及约瑟夫问题解决方案

冷暖自知 提交于 2020-01-13 08:43:03

实现类:

package demo03_LinkedList;

import java.util.Iterator;

public class CircleSingleLinkedList<T> implements Iterable<T> {
    private Node<T> first;
    private Node<T> last;
    private int size = 0;

    public CircleSingleLinkedList() {
    }

    public CircleSingleLinkedList(T elem) {
        this.first = new Node<>();
        first.temp = elem;
        first.next = first;
        last = first;
        size++;
    }

    // 添加元素
    public void add(T elem) {
        if (size == 0) {
            first = new Node<>();
            first.temp = elem;
            first.next = first;
            last = first;
            size++;
        } else {
            Node<T> node = new Node<>();
            last.next = node;
            node.temp = elem;
            node.next = first;
            last = node;
            size++;
        }
    }

    // 根据先进先出原则删除元素,并返回被删除的元素
    public T getQueue() {
        if (size == 0)
            throw new RuntimeException("空链表,无法删除元素");
        T elem = first.temp;
        if (size == 1) {
            first = last = null;
            size--;
            return elem;
        }
        first = first.next;
        last.next = first;
        size--;
        return elem;
    }

    // 根据后进先出原则删除元素,并返回被删除的元素
    public T getStack() {
        if (size == 0)
            throw new RuntimeException("空链表,无法删除元素");

        T elem = last.temp;
        Node<T> previous = getPrevious(first);
        if (previous == last) { // 只有一个结点
            last = first = null;
            size--;
            return elem;
        }
        previous.next = first;
        last.next = null;
        last = previous;
        size--;
        return elem;
    }

    // 返回当前链表last结点的前一位结点
    private Node<T> getPrevious(Node<T> node) {
        Node<T> previous = node;
        if (previous.next == last) {
            return previous;
        } else {
            previous = previous.next;
            return getPrevious(previous);
        }
    }

    // 修改链表中第一个检索到的指定元素值为想要修改成的指定值,并返回被修改的元素
    public T alterElement(T beforeElem, T afterElem) {
        Node<T> node = searchNode(beforeElem);
        T elem = node.temp;
        node.temp = afterElem;
        return elem;
    }

    // 根据指定值查找链表信息,返回检索到的第一个指定值所在的结点
    public Node<T> searchNode(T elem) {
        if (size == 0)
            throw new RuntimeException("空链表");

        Node<T> node = first;
        while (true) {
            if (elem.equals(node.temp))
                return node;
            if (node.next == first)
                break;
            node = node.next;
        }
        throw new RuntimeException("链表中不存在指定值");
    }

    // 判断是否包含指定元素
    public boolean contains(T elem) {
        if (size == 0)
            throw new RuntimeException("空链表");

        Node<T> node = first;
        while (true) {
            if (elem.equals(node.temp))
                return true;
            if (node.next == first)
                break;
            node = node.next;
        }
        return false;
    }

    // 获取链表中最先放入链表的元素
    public T getFirstElement(){
        return first.temp;
    }

    // 获取链表中最后放入链表的元素
    public T getLastElement(){
        return last.temp;
    }

    // 判空
    public boolean isEmpty() {
        return size == 0;
    }

    // 获取链表中元素数量
    public int getSize() {
        return size;
    }

    public Node<T> getFirst() {
        return first;
    }

    public void setFirst(Node<T> first) {
        this.first = first;
    }

    public Node<T> getLast() {
        return last;
    }

    public void setLast(Node<T> last) {
        this.last = last;
    }

    @Override
    public String toString() {
        StringBuilder str = new StringBuilder();
        str.append("Link = {");
        Node<T> node = first;
        while (true) {
            if (node == null)
                break;
            if (node.next == first) {
                str.append(node.temp);
                break;
            }
            str.append(node.temp + ",");
            node = node.next;
        }
        str.append("} -- size = " + size);
        return str.toString();
    }

    // 后进先出迭代器
    public Iterator<T> stackIterator() {
        return new StackIterator();
    }

    // 后进先出迭代器封装内部类
    private class StackIterator implements Iterator<T> {
        private Node<T> newFirst = first;
        private Node<T> newLast = last;
        private int n = size;
        private T elem = null;

        @Override
        public boolean hasNext() {
            return n != 0;
        }

        @Override
        public T next() {
            elem = newLast.temp;
            newLast = getStackPrevious(newFirst);
            n--;
            return elem;
        }

        public Node<T> getStackPrevious(Node<T> node){
            Node<T> previous = node;
            if (previous.next == newLast){
                return previous;
            }else {
                previous = previous.next;
                return getStackPrevious(previous);
            }
        }
    }

    // 先进先出迭代,支持增强for
    @Override
    public Iterator<T> iterator() {
        return new QueueIterator();
    }

    //先进先出迭代器内部类
    private class QueueIterator implements Iterator<T> {
        private Node<T> node = first;
        private int n = size;

        @Override
        public boolean hasNext() {
            return n != 0;
        }

        @Override
        public T next() {
            T elem = node.temp;
            node = node.next;
            n--;
            return elem;
        }
    }

    // 结点类
    private class Node<T> {
        private T temp;
        private Node<T> next;
    }
   
/**
     * 约瑟夫问题解决方案:
     * start: 表示从第几个小孩开始数(k)
     * count: 表示要数几下(m)
     */
    public static <T> void countBoy(CircleSingleLinkedList<T> link, int start, int count) {
        // 判断参数是否符合要求
        if (link.size == 0 || start < 1 || start > link.size || count <= 0) {
            System.out.println("参数输入有误,请重新输入");
            return;
        }

        // 打印参与游戏小孩信息
        System.out.println("参与做游戏的小孩及其编号为:");
        System.out.println(link.toString());

        // 将指针移动到起始报数位置
        for (int i = 1; i < start; i++) {
            link.first = link.first.next;
            link.last = link.last.next;
        }

        int cnt = 0;
        T temp = null;
        System.out.println("游戏开始:");
        while (link.size > 0) {
            if (link.first == link.last) {
                temp = link.first.temp;
                link.first = link.last = null;
                link.size--;
                cnt++;
                System.out.printf("第%d次,%s出圈了!\n", cnt, temp);
            } else {
                // 将指针移动到报数完毕的小孩位置
                for (int i = 1; i < count; i++) {
                    link.first = link.first.next;
                    link.last = link.last.next;
                }
                // 小孩出圈(从链表中移除最后报数的小孩)
                temp = link.first.temp;
                link.last.next = link.first.next;
                link.first = link.first.next;
                link.size--;
                cnt++;
                System.out.printf("第%d次,%s出圈了!\n", cnt, temp);
            }
        }
        System.out.printf("参与游戏的小孩还有%d个,游戏结束!", link.size);
    }

    /**
     * 创建单向循环链表
     * num: 链表中包含的元素个数
     * clazz: 链表中存储元素类型的类
     */
    public static CircleSingleLinkedList creatLink(int num, Class clazz) {
        CircleSingleLinkedList link = new CircleSingleLinkedList();
        for (int i = 1; i < num + 1; i++) {
            try {
                // 利用反射获取构造函数
                Constructor constructor = clazz.getConstructor(int.class);
                Object boy = constructor.newInstance(i);
                link.add(boy);
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        return link;
    }
}

测试类:

package demo03_LinkedList;

import java.util.Iterator;

public class Test {
    public static void main(String[] args) {
        CircleSingleLinkedList<Integer> link = new CircleSingleLinkedList<>();
        try {
            for (int i = 1; i < 11; i++) {
                link.add(i);
            }
            System.out.println(link.toString());
            int length = link.getSize();
            System.out.println("按照先进先出原则删除元素:");
            for (int i = 0; i < length ; i++) {
                Integer integer = link.getQueue();
                System.out.print(integer + " ");
            }
            System.out.println();
            for (int i = 1; i < 11; i++) {
                link.add(i);
            }
            System.out.println(link.toString());
            System.out.println("按照后进先出原则删除元素:");
            for (int i = 0; i < length; i++) {
                System.out.print(link.getStack() + " ");
            }
            System.out.println();
            for (int i = 1; i < 11; i++) {
                link.add(i);
            }
            System.out.println("先进先出迭代:");
            for (Integer integer : link) {
                System.out.print(integer + " ");
            }
            System.out.println();
            System.out.println("后进先出迭代:");
            Iterator<Integer> it = link.stackIterator();
            while (it.hasNext()){
                System.out.print(it.next() + " ");
            }
        } catch (RuntimeException e) {
            e.printStackTrace();
        }finally {

        }
    }
}

测试结果:

Link = {1,2,3,4,5,6,7,8,9,10} -- size = 10
按照先进先出原则删除元素:
1 2 3 4 5 6 7 8 9 10 
Link = {1,2,3,4,5,6,7,8,9,10} -- size = 10
按照后进先出原则删除元素:
10 9 8 7 6 5 4 3 2 1 
先进先出迭代:
1 2 3 4 5 6 7 8 9 10 
后进先出迭代:
10 9 8 7 6 5 4 3 2 1 

Joseph(约瑟夫)问题:
设编号为 1,2,… n 的 n 个人围坐一圈,约定编号为 k(1<=k<=n)的人从 1 开始报数,数到m 的那个人出列,它的下一位又从 1 开始报数,数到 m 的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
代码:


/**
 * 约瑟夫问题解决方案:
 * start: 表示从第几个小孩开始数(k)
 * count: 表示要数几下(m)
 */
public static <T> void countBoy(CircleSingleLinkedList<T> link, int start, int count) {
    // 判断参数是否符合要求
    if (link.size == 0 || start < 1 || start > link.size || count <= 0) {
        System.out.println("参数输入有误,请重新输入");
        return;
    }

    // 打印参与游戏小孩信息
    System.out.println("参与做游戏的小孩及其编号为:");
    System.out.println(link.toString());

    // 将指针移动到起始报数位置
    for (int i = 1; i < start; i++) {
        link.first = link.first.next;
        link.last = link.last.next;
    }

    int cnt = 0;
    T temp = null;
    System.out.println("游戏开始:");
    while (link.size > 0) {
        if (link.first == link.last) {
            temp = link.first.temp;
            link.first = link.last = null;
            link.size--;
            cnt++;
            System.out.printf("第%d次,%s出圈了!\n", cnt, temp);
        } else {
            // 将指针移动到报数完毕的小孩位置
            for (int i = 1; i < count; i++) {
                link.first = link.first.next;
                link.last = link.last.next;
            }
            // 小孩出圈(从链表中移除最后报数的小孩)
            temp = link.first.temp;
            link.last.next = link.first.next;
            link.first = link.first.next;
            link.size--;
            cnt++;
            System.out.printf("第%d次,%s出圈了!\n", cnt, temp);
        }
    }
    System.out.printf("参与游戏的小孩还有%d个,游戏结束!", link.size);
}

/**
 * 创建单向循环链表
 * num: 链表中包含的元素个数
 * clazz: 链表中存储元素类型的类
 */
public static CircleSingleLinkedList creatLink(int num, Class clazz) {
    CircleSingleLinkedList link = new CircleSingleLinkedList();
    for (int i = 1; i < num + 1; i++) {
        try {
            // 利用反射获取构造函数
            Constructor constructor = clazz.getConstructor(int.class);
            Object boy = constructor.newInstance(i);
            link.add(boy);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
    return link;
}

测试:

package demo03_LinkedList;

import java.util.Scanner;

public class JosephTest {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入参与游戏的小孩数量:");
        int num = sc.nextInt();
        CircleSingleLinkedList link = CircleSingleLinkedList.creatLink(num, Boy.class);
        System.out.println("请输入起始报数小孩编号:");
        int start = sc.nextInt();
        System.out.println("请输入报数次数:");
        int count = sc.nextInt();
        CircleSingleLinkedList.countBoy(link, start, count);
    }


}

class Boy {
    private int num;

    public Boy() {
    }

    public Boy(int num) {
        this.num = num;
    }

    @Override
    public String toString() {
        return "Boy" + num;
    }
}

测试结果:

请输入参与游戏的小孩数量:
5
请输入起始报数小孩编号:
1
请输入报数次数:
2
参与做游戏的小孩及其编号为:
Link = {Boy1,Boy2,Boy3,Boy4,Boy5} -- size = 5
游戏开始:1,Boy2出圈了!2,Boy4出圈了!3,Boy1出圈了!4,Boy5出圈了!5,Boy3出圈了!
参与游戏的小孩还有0,游戏结束!
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!