数据结构之链表

什么是链表

链表通过指针将一组零散的内存块串联在一起。其中,我们把内存块称为链表的“结点”。为了将所有的结点串起来,每个链表的结点除了存储数据之外,还需要记录链上的下一个结点的地址

特点

  1. 不需要连续的内存空间
  2. 有指针引用
  3. 三种最常见的链表结构:单链表、双向链表和循环链表

单链表

image.png

第一个结点叫作头结点,把最后一个结点叫作尾结点
头结点用来记录链表的基地址。有了它,我们就可以遍历得到整条链表
尾结点特殊的地方是:指针不是指向下一个结点,而是指向一个空地址NULL,表示这是链表上最后一个结点

while(p.next != null){}

数组VS链表

image.png
重要区别

数组链表
访问效率数组简单易用,在实现上使用的是连续的内存空间,可以借助CPU的缓存机制,预读数组中的数据,所以访问效率更高链表在内存中并不是连续存储,所以对CPU缓存不友好,没办法有效预读
写效率插入、删除
内存连续连续不连续,通过指针链接
存储空间数组的缺点是大小固定,一经声明就要占用整块连续内存空间
1. 如果声明的数组过大,系统可能没有足够的连续内存空间分配给它,导致“内存不足(out ofmemory)”
2. 如果声明的数组过小,则可能出现不够用的情况
节省空间
  1. 数组简单易用,在实现上使用的是连续的内存空间,可以借助CPU的缓存机制,预读数组中的数据,所以访问效率更高
  2. 链表在内存中并不是连续存储,所以对CPU缓存不友好,没办法有效预读
  3. 数组的缺点是大小固定,一经声明就要占用整块连续内存空间。如果声明的数组过大,系统可能没有足够的连续内存空间分配给它,导致“内存不足(out ofmemory)”。如果声明的数组过小,则可能出现不够用的情况。

循环链表

循环链表的尾结点指针是指向链表的头结点

双向链表

image.png

每个结点不止有一个后继指针next指向后面的结点,还有一个前驱指针prev指向前面的结点
双向链表需要额外的两个空间来存储后继结点和前驱结点的地址
虽然两个指针比较浪费存储空间,但可以支持双向遍历,这样也带来了双向链表操作的灵活性。那相比单链表,双向链表适合解决哪种问题呢?

  1. B+Tree:Mysql索引 叶子节点 双向链表
  2. Spring AOP 注解,最新的技术,红黑树和链表查找

编程题

如何设计一个LRU缓存淘汰算法

最近使用,只需要维护一个有序的单链表就可以了。有序的指的就是加入的时间排序

实现一个单链表

List:ArrayList、LinkedList
稀疏数组:一般是针对多维

1 2 -1 -1
4 -1 6 -1
9 -1 1 -1
// -1表示没有数据
// a[3][4]; 3*4=12空间,稀疏数组就是真正存的数据远远小于我们开的空间。这种情况 往往会用链表来代替

链表特性:

  1. 知道头结点,通过头结点能遍历整个链表【所有需要声明头结点】
  2. 通过指针指向下一个节点 ,所有有ListNode结构,内存不连续
  3. 访问效率低,更新操作高效
class ListNode<E> {
    E value;        //值
    ListNode next;    //下一个的指针
    ListNode(E value) {
        this.value = value;
        this.next = null;
    }
}
package list;

import java.util.Objects;

/**
 * 单向链表
 *
 * @author zw
 * @create 2023-03-22 22:24
 */
public class MyLinkedList<E> implements MyList<E> {

    /**
     * 单向链表需要指定头节点
     */
    private ListNode<E> head;
    /**
     * 链表长度
     */
    private int size;


    @Override
    public void add(E e) { // O(n)
        ListNode<E> node = new ListNode<>(e);
        ListNode cur = head;
        while (cur != null) {
            cur = cur.next;
        }
        cur.next = node;
        size++;
    }

    @Override
    public void addHead(E e) { // O(1)
        ListNode<E> newNode = new ListNode<>(e);
        // 当前链表为空的情况
        if(head == null){
            head = newNode;
        }else {
            newNode.next = head;
            head = newNode;
        }
        size++;
    }

    @Override
    public void add(E e, int position) { // O(n)
        if (position == 0) {
            addHead(e);
        } else {
            ListNode<E> node = new ListNode<>(e);
            ListNode cur = head;
            for (int i = 1; i <= position; i++) {
                if(position == i){
                    break;
                }
                cur = cur.next;

            }
            cur.next = node;
            size++;
        }
    }

    @Override
    public void removeHead() { // O(1)
        if (size == 0) return;
        head = head.next;
        size--;
    }


    @Override
    public void remove(int index) { // O(n)
        if (index > size - 1) throw new ArrayIndexOutOfBoundsException("越界");
        if (index == 0) {
            removeHead();
            return;
        };
        ListNode curr = head;
        for (int i = 1; i <= index; i++) {
            if (i == index) break;
            curr = curr.next;
        }
        ListNode removeNode = curr.next;
        curr.next = removeNode.next;
        size--;
    }

    @Override
    public void remove(E e) { // O(n)
        if (head.value.equals(e)) {
            removeHead();
            return;
        }
        ListNode beforNode = head;
        ListNode cur = beforNode.next;
        while (cur != null) {
            // 当前节点是首节点
            if (cur.value.equals(e)) {
                beforNode.next = cur.next;
                size--;
                return;
            }
            beforNode = beforNode.next;
        }
    }

    @Override
    public void removeAll(E e) {// O(n)
        ListNode beforNode = head;
        ListNode cur = beforNode.next;
        while (cur != null) {
            // 当前节点是首节点
            if (cur.value.equals(e)) {
                beforNode.next = cur.next;
                size--;
            }
            beforNode = beforNode.next;
        }
        if (head.value.equals(e)) {
            removeHead();
        }
    }

    @Override
    public E get(int index) { // O(n)
        if(index > size -1 ) throw new ArrayIndexOutOfBoundsException("下标越界");
        ListNode<E> curr = head;
        for (int j = 0; j < size; j++) {
            if (index == j) break;
            curr = curr.next;
        }
        return curr.value;
    }

    @Override
    public Boolean isExit(E data) { // O(n)
        ListNode cur = head;
        while(cur != null){
            if(cur.value == data) return true;
            cur = cur.next;
        }
        return false;
    };

    /**
     * 时间复杂度 O(1)
     * @return
     * @throws Exception
     */
    @Override
    public E getFirst() throws Exception {
        return head.value;
    }

    /**
     * 时间复杂度 O(n)
     * @return
     * @throws Exception
     */
    @Override
    public E getLast() throws Exception {
        ListNode<E> curr = head;
        for (int j = 0; j < size; j++) {
            if (size == j) break;
            curr = curr.next;
        }
        return curr.value;
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return Objects.isNull(head.next);
    }


    public void print() {
        StringBuffer sb = new StringBuffer();
        if (size == 0) {
            System.out.println("[]");
            return;
        }

        ListNode curr = head;
        sb.append("size=").append(size).append("  ").append("[");
        while (curr != null) {
            sb.append(curr.value.toString()).append(",");
            curr = curr.next;
        }
        sb.append("]");
        System.out.println(sb.toString());
    }


}

实现一个双向链表

删除头结点

完整链表实现

package list;

/**
 * @author zw
 * @create 2023-03-23 0:35
 */
class DNode<E> {
    E value;        //值
    DNode<E> next;        //下一个的指针
    DNode<E> pre;        //指向的是前一个指针

    DNode(E value) {
        this.value = value;
    }
}

public class DoubleLinkList<E> implements MyList<E> {

    private DNode<E> head;        //头
    private DNode<E> tail;        // 尾
    transient int size = 0;

    @Override
    public void add(E e) {
        if (head == null) addHead(e);
        else {
            DNode newNode = new DNode(e);
            newNode.pre = tail;
            tail.next = newNode;
            tail = newNode;
            size++;
        }
    }

    @Override
    public void addHead(E data) { // O(1)
        DNode newNode = new DNode(data);
        if (head == null) {
            tail = newNode;
        } else {
            head.pre = newNode;
            newNode.next = head;
        }
        head = newNode;
        size++;
    }

    @Override
    public void add(E e, int position) {
        if (position == 0) {
            addHead(e);
        } else if (position == size - 1) {
            add(e);
        } else {
            DNode<E> newNode = new DNode(e);
            DNode<E> node = this.head;
            for (int i = 1; i <= position; i++) {
                node = node.next;
            }
            node.pre.next = newNode;
            newNode.next = node.next;
            node.next.pre = newNode;
            newNode.pre = node.pre;
            size++;
        }
    }


    @Override
    public void removeHead() {
        if (head == null) return;
        if (head.next == null) {
            tail = null;
        } else {
            head.next.pre = null;
        }
        head = head.next;
        size--;
    }

    @Override
    public void removeTail() {
        // 没有节点的情况
        if (head == null) return;
        // 一个节点的情况
        if (head.next == null) {
            tail = null;
            head = null;
        } else {
            tail.pre.next = null;
            tail = tail.pre;
        }
        size--;
    }

    @Override
    public void remove(int position)  {

        // 删除的是头结点
        if (position == 0) {
            removeHead();
            return;
        }
        // 删除的是尾节点
        if (position == size - 1) {
            removeTail();
        }
        if(position>0  && position < size - 1){
            DNode<E> removeNode = head;
            for (int j = 1; j <= position; j++) {
                removeNode = removeNode.next;
            }
            removeNode.pre.next = removeNode.next;
            removeNode.next.pre = removeNode.pre;
            size--;
        }

    }

    @Override
    public void remove(E data) throws Exception {
        DNode<E> removeNode = head.next;
        while (removeNode != null) {
            if (removeNode.value.equals(data)) break;
            removeNode = removeNode.next;
        }
        // 找到了删除节点
        if (removeNode.value.equals(data)) {
            // 头结点
            if (removeNode.equals(head)) removeHead();
                // 尾节点
            else if (removeNode.equals(tail)) removeTail();
            else {
                removeNode.next.pre = removeNode.pre;
                removeNode.pre.next = removeNode.next;
                size--;
            }
        }
    }

    @Override
    public void removeAll(E data) {
        DNode<E> removeNode = head.next;
        while (removeNode != null) {
            if (removeNode.value.equals(data)) {
                // 头结点
                if (removeNode.equals(head)) removeHead();
                    // 尾节点
                else if (removeNode.equals(tail)) removeTail();
                else {
                    removeNode.next.pre = removeNode.pre;
                    removeNode.pre.next = removeNode.next;
                    size--;
                }
            }
            removeNode = removeNode.next;
        }
    }

    @Override
    public E get(int position) throws Exception {
        if (position > size - 1) throw new ArrayIndexOutOfBoundsException("下标越界");
        DNode<E> node = head;
        for (int j = 0; j <= position; j++) {
            if (position == j) return node.value;
            node = node.next;
        }
        return null;
    }

    @Override
    public Boolean isExit(E e) {
        return MyList.super.isExit(e);
    }

    @Override
    public E getFirst()  {
        if (head == null) return null;
        return head.value;
    }

    @Override
    public E getLast()  {
        if (tail == null) return null;
        return tail.value;
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return head == null;
    }

    public void print() {
        StringBuffer sb = new StringBuffer();
        if (size == 0) {
            System.out.println("[]");
            return;
        }

        DNode curr = head;
        sb.append("size=").append(size).append("  ").append("[");
        while (curr != null) {
            sb.append(curr.value.toString()).append(",");
            curr = curr.next;
        }
        sb.append("]");
        System.out.println(sb.toString().replaceAll(",]","]"));
    }
}

测试用例

    public static void main(String[] args) throws Exception{
        DoubleLinkList<Integer> list = new DoubleLinkList<>();
        System.out.println("-----添加测试--------");
        list.add(-1);
        list.print();
        for (int i = 0; i < 5; i++) {
            list.add(i);
        }
        list.print();
        list.addHead(-2);
        list.print();
        list.add(100, 1);
        list.print();

        System.out.println("-----删除测试--------");
        list.removeHead();
        list.removeTail();
        list.print();
        list.remove(1);
        list.print();

        System.out.println("-----查找测试--------");
        System.out.println(list.getFirst());
        System.out.println(list.getLast());
        System.out.println(list.get(1));
    }
-----添加测试--------
size=1  [-1]
size=6  [-1,0,1,2,3,4]
size=7  [-2,-1,0,1,2,3,4]
size=8  [-2,100,0,1,2,3,4]
-----删除测试--------
size=6  [100,0,1,2,3]
size=5  [100,1,2,3]
-----查找测试--------
100
3
1

实现一个单向循环链表

在链表的基础上,将尾节点指向头节点就好

package list;

/**
 * 环形链表
 *
 * @author zw
 * @create 2023-03-23 17:50
 */
public class CircularLinkedList<E> implements MyList<E> {
    private ListNode<E> head;
    private int size;


    @Override
    public void add(E e) {
        ListNode<E> newNode = new ListNode<>(e);
        if (head == null) {
            head = newNode;
        } else {
            ListNode<E> lastNode = getNode(size - 1);
            lastNode.next = newNode;
            newNode.next = head;
        }
        size++;
    }

    @Override
    public void removeHead() {
        remove(0);
    }

    @Override
    public void remove(int position) {
        if (size == 0) return;
        if (position == 0) {
            if (size == 1) {
                head = null;
            } else {
                ListNode<E> lastNode = getNode(size - 1);
                head = head.next;
                lastNode.next = head;
            }
        } else {
            ListNode<E> removeBeforeNode = getNode(position - 1);
            removeBeforeNode.next = removeBeforeNode.next.next;
        }
        size--;
    }

    @Override
    public void remove(E e) {
        if (size == 0) return;
        ListNode<E> curr = this.head;
        for (int i = 0; i < size; i++) {
            if (curr.value.equals(e)) {
                break;
            }
            curr = curr.next;
        }
        size--;
    }

    @Override
    public E get(int position) {
        ListNode<E> node = getNode(position);
        if (node == null) return null;
        return node.value;
    }

    @Override
    public ListNode<E> getNode(int position) {
        if (size == 0) {
            return null;
        }
        if (position == 0) {
            return head;
        }
        ListNode<E> curr = this.head;
        for (int i = 1; i <= position; i++) {
            curr = curr.next;
            if (i == position) {
                break;
            }
        }
        return curr;
    }

    @Override
    public E getFirst() throws Exception {
        ListNode<E> node = getNode(0);
        if (node == null) {
            return null;
        }
        return node.value;
    }

    @Override
    public E getLast() throws Exception {
        ListNode<E> node = getNode(size - 1);
        if (node == null) {
            return null;
        }
        return node.value;
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return !(size > 0);
    }

    public void print() {
        StringBuffer sb = new StringBuffer();
        if (size == 0) {
            System.out.println("[]");
            return;
        }

        ListNode curr = head;
        sb.append("size=").append(size).append("  ").append("[");
        for (int i = 0; i < size; i++) {
            sb.append(curr.value.toString()).append(",");
            curr = curr.next;
        }
        sb.append("]");
        System.out.println(sb.toString().replaceAll(",]","]"));
    }
}

测试用例

    public static void main(String[] args) throws Exception {
        CircularLinkedList<Integer> list = new CircularLinkedList<>();
        System.out.println("-----添加测试--------");
        list.add(-1);
        list.print();
        for (int i = 0; i < 5; i++) {
            list.add(i);
        }
        list.print();

        System.out.println("-----删除测试--------");
        list.removeHead();
        list.removeTail();
        list.print();
        list.remove(1);
        list.print();

        System.out.println("-----查找测试--------");
        System.out.println(list.getFirst());
        System.out.println(list.getLast());
        System.out.println(list.get(1));

        System.out.println("-----监测尾节点是否链接到头节点--------");
        ListNode<Integer> lastNode = list.getNode(list.size - 1);
        ListNode<Integer> headNode = list.getNode(0);
        System.out.println(lastNode.next.equals(headNode));
    }

执行结果

-----添加测试--------
size=1  [-1]
size=6  [-1,0,1,2,3,4]
-----删除测试--------
size=5  [0,1,2,3,4]
size=4  [0,2,3,4]
-----查找测试--------
0
4
2
-----监测尾节点是否链接到头节点--------
true

约瑟夫问题

详细描述我会写在这里

约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3,1。
1 2 3 4 5 6 => 6 1 2 3 4 => 6 1 2 3 =>1 2 3 => 1 3 => 1

核心代码

    /**
     *
     * @param n 数到n的人被杀
     * @return
     */
    private ListNode<E> josephProblem(int n) {
        // 下一个报数人
        ListNode<E> curr = this.head;
        // 上一个报数人
        ListNode<E> beforNnode = null;
        while (!(this.size == 1)) {
            // 循环链表开始杀人
            for (int i = 1; i <= n; i++) {
                if (i == n) {
                    // 杀人,剔除链表
                    beforNnode.next = curr.next;
                    curr = curr.next;
                    size--;
                    String log = String.format("当前报数=%s,被杀人=%s", n, curr.value);
                    System.out.println(log);
                    print();
                } else {
                    curr = curr.next;
                    beforNnode = curr;
                }

            }
        }
        return head;
    }

测试用例

public static void main(String[] args) throws Exception {
    System.out.println("------------约瑟夫问题--------------");
    // 构建链表
    int m = 6;
    CircularLinkedList<Integer> josephProblemList = new CircularLinkedList<>();
    for (int i = 1; i <= m; i++) {
        josephProblemList.add(i);
    }
    josephProblemList.print();
    ListNode<Integer> node = josephProblemList.josephProblem(5);
    System.out.println("剩下的人=" + node.value);
}

测试结果

size=6  [1,2,3,4,5,6]

当前报数=5,被杀人=6
size=5  [1,2,3,4,5]
当前报数=5,被杀人=5
size=4  [1,2,3,4]
当前报数=5,被杀人=4
size=3  [1,2,3]
当前报数=5,被杀人=3
size=2  [1,2]
当前报数=5,被杀人=2
size=1  [1]
剩下的人=1

实现一个双向循环链表

package list;

/**
 * 双向循环链表
 *
 * @author zw
 * @create 2023-03-23 0:35
 */

public class DoubleCircularLinkedList<E> implements MyList<E> {

    private DNode<E> head;        //头
    private DNode<E> tail;        // 尾
    transient int size = 0;

    /**
     * 构建前后两个节点的环
     *
     * @param beforNode
     * @param afterNode
     */
    void buildRing(DNode<E> beforNode, DNode<E> afterNode) {
        beforNode.next = afterNode;
        afterNode.pre = beforNode;
        print();
    }


    @Override
    public void add(E e) {
        if (head == null) addHead(e);
        else {
            DNode newNode = new DNode(e);
            buildRing(tail, newNode);
            buildRing(newNode, head);
            tail = newNode;
            size++;
        }
    }

    @Override
    public void addHead(E data) { // O(1)
        DNode newNode = new DNode(data);
        if (head == null) {
            head = newNode;
            tail = newNode;
            buildRing(head, tail);
        } else {
            buildRing(tail, newNode);
            buildRing(newNode, head);
            head = newNode;
        }
        size++;
    }

    @Override
    public void add(E e, int position) {
        if (position == 0) {
            addHead(e);
        } else if (position == size - 1) {
            add(e);
        } else {
            DNode<E> newNode = new DNode(e);
            DNode<E> node = getNode(position);
            buildRing(node.pre, newNode);
            buildRing(newNode, node.next);
            size++;
        }
    }


    @Override
    public void removeHead() {
        if (size == 0) return;
        else if (size == 1) {
            head = null;
            tail = null;
        } else {
            buildRing(tail, head.next);
            head = head.next;
        }
        size--;
    }

    @Override
    public void removeTail() {
        // 没有节点的情况
        if (head == null) return;
        // 一个节点的情况
        if (head.next == null) {
            tail = null;
            head = null;
        } else {
            buildRing(head, tail.pre);
            tail = tail.pre;
        }
        size--;
    }

    @Override
    public void remove(int position) {
        // 删除的是头结点
        if (position == 0) {
            removeHead();
            return;
        }
        // 删除的是尾节点
        if (position == size - 1) {
            removeTail();
        }
        if (position > 0 && position < size - 1) {
            DNode<E> removeNode = getNode(position);
            buildRing(removeNode.pre, removeNode.next);
            size--;
        }

    }

    @Override
    public void remove(E data) throws Exception {
        DNode<E> removeNode = head.next;
        while (removeNode != null) {
            if (removeNode.value.equals(data)) break;
            removeNode = removeNode.next;
        }
        // 找到了删除节点
        if (removeNode.value.equals(data)) {
            // 头结点
            if (removeNode.equals(head)) removeHead();
                // 尾节点
            else if (removeNode.equals(tail)) removeTail();
            else {
                buildRing(removeNode.pre, removeNode.next);
                size--;
            }
        }
    }

    @Override
    public void removeAll(E data) {
        DNode<E> removeNode = head.next;
        for (int i = 0; i < size; i++) {
            if (removeNode.value.equals(data)) {
                // 头结点
                if (removeNode.equals(head)) removeHead();
                    // 尾节点
                else if (removeNode.equals(tail)) removeTail();
                else {
                    buildRing(removeNode.pre, removeNode.next);
                    size--;
                }
            }
            removeNode = removeNode.next;
        }
    }

    @Override
    public E get(int position) throws Exception {
        if (position > size - 1) throw new ArrayIndexOutOfBoundsException("下标越界");
        DNode<E> node = head;
        for (int j = 0; j <= position; j++) {
            if (position == j) return node.value;
            node = node.next;
        }
        return null;
    }


    @Override
    public DNode<E> getNode(int position) {
        if (size == 0) {
            return null;
        }
        if (position == 0) {
            return head;
        }
        DNode<E> curr = this.head;
        for (int i = 1; i <= position; i++) {
            curr = curr.next;
            if (i == position) {
                break;
            }
        }
        return curr;
    }

    @Override
    public Boolean isExit(E e) {
        return MyList.super.isExit(e);
    }

    @Override
    public E getFirst() {
        if (head == null) return null;
        return head.value;
    }

    @Override
    public E getLast() {
        if (tail == null) return null;
        return tail.value;
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return head == null;
    }




    public void print() {
        StringBuffer sb = new StringBuffer();
        if (size == 0) {
            System.out.println("[]");
            return;
        }

        DNode curr = head;
        sb.append("size=").append(size).append("  ").append("[");
        for (int i = 0; i < size; i++) {
            sb.append(curr.value.toString()).append(",");
            curr = curr.next;
        }
        sb.append("]");
        System.out.println(sb.toString().replaceAll(",]", "]"));
    }

    public static void main(String[] args) throws Exception {
        // 构建链表
        int m = 6;
        DoubleCircularLinkedList<Integer> josephProblemList = new DoubleCircularLinkedList<>();
        for (int i = 1; i <= m; i++) {
            josephProblemList.add(i);
        }
        josephProblemList.print();
        DNode<Integer> node = josephProblemList.josephProblem(5);
        System.out.println("剩下的人=" + node.value);
    }
}

约瑟夫问题

详细描述我会写在这里

约瑟夫问题是个有名的问题:N个人围成一圈,从第一个开始报数,第M个将被杀掉,最后剩下一个,其余人都将被杀掉。例如N=6,M=5,被杀掉的顺序是:5,4,6,2,3,1。
1 2 3 4 5 6 => 6 1 2 3 4 => 6 1 2 3 =>1 2 3 => 1 3 => 1

    /**
     * @param n 数到n的人被杀
     * @return
     */
    private DNode<E> josephProblem(int n) {
        // 下一个报数人
        DNode<E> curr = this.head;
        while (!(this.size == 1)) {
            // 循环链表开始杀人
            for (int i = 1; i <= n; i++) {
                if (i == n) {
                    // 杀人,剔除链表
                    curr.pre.next = curr.next;
                    curr.next.pre = curr.pre;
                    curr = curr.next;
                    size--;
                    String log = String.format("当前报数=%s,被杀人=%s", n, curr.value);
                    System.out.println(log);
                    print();
                } else {
                    curr = curr.next;
                }

            }
        }
        return head;
    }

与单向链表实现的区别:
双向循环链表能通过pre拿到上一个报数节点,而单向循环链表需要临时变量记录

测试用例

public static void main(String[] args) throws Exception {
    // 构建链表
    int m = 6;
    DoubleCircularLinkedList<Integer> josephProblemList = new DoubleCircularLinkedList<>();
    for (int i = 1; i <= m; i++) {
        josephProblemList.add(i);
    }
    josephProblemList.print();
    DNode<Integer> node = josephProblemList.josephProblem(5);
    System.out.println("剩下的人=" + node.value);
}

运行结果

当前报数=5,被杀人=6
size=5  [1,2,3,4,6]
当前报数=5,被杀人=6
size=4  [1,2,3,6]
当前报数=5,被杀人=1
size=3  [1,2,3]
当前报数=5,被杀人=3
size=2  [1,3]
当前报数=5,被杀人=1
size=1  [1]
剩下的人=1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值