数据结构与算法之链表

1. 基本知识

1.1 概念

通过指针将一组零散的内存块串联起来。

在这里插入图片描述在这里插入图片描述
1.2 分类
  1. 单链表
  2. 单向循环链表
  3. 双向链表
  4. 双向循环链表
单链表循环链表
双向链表双向循环链表
1.3 链表 VS 数组
  • 数组需要一组连续的内存空间;链表只需要零散的内存空间;
  • 数组的随机访问效率非常高,时间复杂度为 O(1),链表的查找需要遍历,时间复杂度为O(n);
  • 数组的插入和删除涉及到数据的移动效率低下,而链表只需要相邻节点指针的改变,效率较高;
  • 数组在声明时要指定长度,链表不需要。
1.4 链表的实现
package com.baidu.test.construct;
public interface List<T> {

    void add(T data);

    void set(int index, T data);

    T get(int index);

    void remove(int index);

    void remove(T data);

    boolean isEmpty();

    int size();

    void print();
}
1.4.1 单链表
package com.baidu.test.construct.linkedlist;

import com.baidu.test.construct.List;

/**
 * 单链表
 */
public class SinglyLinkedList<T> implements List<T> {

    // 头节点
    private Node<T> head;

    // 当前节点
    private Node<T> current;

    // 长度
    private int size;

    public SinglyLinkedList() {
        this.head = this.current = new Node(null, null);
        this.size = 0;
    }

    /**
     * 添加
     * @param data
     */
    @Override
    public void add(T data) {
        index(size-1);
        current.next = new Node(data, null);
        size++;
    }

    /**
     * 添加
     * @param index
     * @param data
     */
    @Override
    public void set(int index, T data) {
        index(index-1);
        Node node = new Node(data, current.next);
        current.next = node;
        size++;
    }

    /**
     * 获取
     * @param index
     * @return
     */
    @Override
    public T get(int index) {
        index(index);
        return current.data;
    }

    /**
     * 删除
     */
    @Override
    public void remove(T data) {
        if (size == 0) {
            return;
        }

        current = head;
        while (current.next != null && current.next.data != data) {
            current = current.next;
        }
        current.next = current.next.next;
        size--;
    }

    /**
     * 删除
     */
    @Override
    public void remove(int index) {
        index(index-1);
        current.next = current.next.next;
        size--;
    }

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

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

    @Override
    public void print() {
        current = head.next;
        while (current != null) {
            System.out.print(current.data + ",");
            current = current.next;
        }
        System.out.println();
    }

    /**
     * 定位函数,实现当前操作对象的前一个结点,也就是让当前结点对象定位到要操作结点的前一个结点,
     * 该定位为正序定位,其实应该判断index位置,在进行正序或反序定位
     * @param index
     */
    private void index(int index) {
        if (index < -1 && index > size -1) {
            throw new IndexOutOfBoundsException();
        }

        // 说明当前单链表为空链表
        if (index == -1) {
        	current = head;
            return;
        }

        current = head.next;
        int j = 0;
        while (j < index) {
            current = current.next;
            j++;
        }
    }

    /**
     * 单链表反转
     * 1 -> 2 -> 3 -> 4
     * 4 -> 3 -> 2 -> 1
     * @return
     */
    public Node reverseList(Node head) {
        Node pre = null;
        Node next = null;
        while (head != null) {
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        return pre;
    }


    private static class Node<T> {
        private T data;
        private Node<T> next;

        public Node(T data, Node next) {
            this.data = data;
            this.next = next;
        }
    }

    public static void main(String[] args) {
        SinglyLinkedList<String> list = new SinglyLinkedList<>();
        list.add("a");
        list.add("c");
        list.add("d");
        list.set(1, "b");
        list.print();
        System.out.println(list.size());
        System.out.println(list.get(2));
        list.remove("c");
        list.print();
        list.remove(1);
        list.print();

        list = new SinglyLinkedList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        list.add("4");
        list.print();
        Node node = list.reverseList(list.head);
        while (node != null && node.data != null) {
            System.out.print(node.data +",");
            node = node.next;
        }
        System.out.println();
    }

}

1.4.2 单向循环链表
package com.baidu.test.construct.linkedlist;

import com.baidu.test.construct.List;

/**
 * 单向循环链表
 * @param <T>
 */
public class SinglyCycleLinkedList<T> implements List<T> {

    // 头节点
    private Node<T> head;

    // 当前节点
    private Node<T> current;

    // 长度
    private int size;

    public SinglyCycleLinkedList() {
        this.head = this.current = new Node<>(null, null);
        this.head.next = this.head;
        this.size = 0;
    }

    @Override
    public void add(T data) {
        index(size-1);
        Node<T> node = new Node<>(data, current.next);
        current.next = node;
        size++;
    }

    @Override
    public void set(int index, T data) {
        index(index-1);
        Node<T> node = new Node<>(data, current.next);
        current.next = node;
        size++;
    }

    @Override
    public T get(int index) {
        index(index);
        return current.data;
    }

    @Override
    public void remove(int index) {
        index(index-1);
        current.next = current.next.next;
        size--;
    }

    @Override
    public void remove(T data) {
        if (size == 0) {
            return;
        }

        current = head;
        while (current.next != head && current.next.data != data) {
            current = current.next;
        }
        current.next = current.next.next;
        size--;
    }

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

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

    @Override
    public void print() {
        current = head.next;
        while (current != head) {
            System.out.print(current.data);
            current = current.next;
        }
        System.out.println();
    }

    /**
     * 定位函数,实现当前操作对象的前一个结点,也就是让当前结点对象定位到要操作结点的前一个结点,
     * 该定位为正序定位,其实应该判断index位置,在进行正序或反序定位
     * @param index
     */
    private void index(int index) {
        if (index < -1 && index > size -1) {
            throw new IndexOutOfBoundsException();
        }

        if (index == -1) {
        	current = head;
            return;
        }

        current = head.next;
        int j=0;
        while (current != head && j < index) {
            current = current.next;
            j++;
        }
    }

    private class Node<T> {
        private T data;
        private Node<T> next;

        public Node(T data, Node<T> next) {
            this.data = data;
            this.next = next;
        }
    }

    public static void main(String[] args) {
        SinglyCycleLinkedList list = new SinglyCycleLinkedList();
        list.add("a");
        list.add("c");
        list.add("d");
        list.set(1, "b");
        list.print();
        System.out.println(list.size());
        System.out.println(list.get(2));
        list.remove("c");
        list.print();
        list.remove(1);
        list.print();
    }
}

1.4.3 双向链表
package com.baidu.test.construct.linkedlist;

import com.baidu.test.construct.List;

/**
 * 双向链表
 * @param <T>
 */
public class DoubleLinkedList<T> implements List<T> {

    // 头节点
    private Node<T> head;

    // 当前节点
    private Node<T> current;

    // 长度
    private int size;

    public DoubleLinkedList() {
        this.head = this.current = new Node<>(null, null, null);
        size = 0;
    }

    @Override
    public void add(T data) {
        index(size-1);
        Node<T> node = new Node<>(data, current, current.next);
        current.next = node;
        size++;
    }

    @Override
    public void set(int index, T data) {
        index(index-1);
        Node<T> node = new Node<>(data, current, current.next);
        current.next = node;
        size++;
    }

    @Override
    public T get(int index) {
        index(index);
        return current.data;
    }

    @Override
    public void remove(int index) {
        index(index-1);
        current.next.next.prior = current;
        current.next = current.next.next;
        size--;
    }

    @Override
    public void remove(T data) {
        if (size == 0) {
            return;
        }

        current = head;
        if (current.next != null && current.next.data != data) {
            current = current.next;
        }

        current.next.next.prior = current;
        current.next = current.next.next;
        size--;
    }

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

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

    @Override
    public void print() {
        current = head.next;
        while (current != null) {
            System.out.print(current.data);
            current = current.next;
        }
        System.out.println();
    }

    private void index(int index) {
        if (index < -1 && index > size -1) {
            throw new IndexOutOfBoundsException();
        }

        if (index == -1) {
        	current = head;
            return;
        }

        current = head.next;
        int j=0;
        while (j<index) {
            current = current.next;
            j++;
        }
    }

    private class Node<T> {
        private T data;
        private Node<T> prior;
        private Node<T> next;

        public Node(T data, Node<T> prior, Node<T> next) {
            this.data = data;
            this.prior = prior;
            this.next = next;
        }
    }

    public static void main(String[] args) {
        DoubleLinkedList list = new DoubleLinkedList();
        list.add("a");
        list.add("c");
        list.add("d");
        list.set(1, "b");
        list.print();
        System.out.println(list.size());
        System.out.println(list.get(2));
        list.remove("c");
        list.print();
        list.remove(1);
        list.print();
    }
}

1.4.4 双向循环链表
package com.baidu.test.construct.linkedlist;

import com.baidu.test.construct.List;

/**
 * 双向循环链表
 */
public class DoubleCycleLinkedList<T> implements List<T> {

    // 头节点
    private Node<T> head;

    // 当前节点
    private Node<T> current;

    // 长度
    private int size;

    public DoubleCycleLinkedList() {
        this.head = this.current = new Node<>(null, null, null);
        this.head.prior = this.head;
        this.head.next = this.head;
        this.size = 0;
    }

    @Override
    public void add(T data) {
        index(size-1);
        Node<T> node = new Node<>(data, current, current.next);
        current.next = node;
        size++;
    }

    @Override
    public void set(int index, T data) {
        index(index-1);
        Node<T> node = new Node<>(data, current, current.next);
        current.next.next.prior = node;
        current.next = node;
        size++;
    }

    @Override
    public T get(int index) {
        index(index);
        return current.data;
    }

    @Override
    public void remove(int index) {
        index(index-1);
        current.next.next.prior = current;
        current.next = current.next.next;
        size--;
    }

    @Override
    public void remove(T data) {
        if (size == 0) {
            return;
        }

        current = head;
        while (current.next != head && current.next.data != data) {
            current = current.next;
        }

        current.next.next.prior = current;
        current.next = current.next.next;
        size--;
    }

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

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

    @Override
    public void print() {
        current = head.next;
        while (current != head) {
            System.out.print(current.data);
            current = current.next;
        }
        System.out.println();
    }

    private void index(int index) {
        if (index < -1 && index > size-1) {
            throw new IndexOutOfBoundsException();
        }

        if (index == -1) {
        	current = head;
            return;
        }

        current = head.next;
        int j=0;
        while (current != head && j<index) {
            current = current.next;
            j++;
        }
    }

    private class Node<T> {
        private T data;
        private Node<T> prior;
        private Node<T> next;

        public Node(T data, Node<T> prior, Node<T> next) {
            this.data = data;
            this.prior = prior;
            this.next = next;
        }
    }

    public static void main(String[] args) {
        DoubleCycleLinkedList list = new DoubleCycleLinkedList();
        list.add("a");
        list.add("c");
        list.add("d");
        list.set(1, "b");
        list.print();
        System.out.println(list.size());
        System.out.println(list.get(2));
        list.remove("c");
        list.print();
        list.remove(1);
        list.print();
    }
}

2. 链表的应用

2.1 通过链表实现LRU缓存淘汰算法
package com.baidu.test.construct.linkedlist;

import java.util.Scanner;

/**
 * Least Recently Used 最近最少使用
 */
public class LRUWithLInkedList<T> {

    // 链表默认容量
    private final static int DEFAULT_CAPACITY = 10;

    // 头节点
    private Node<T> head;

    // 当前节点
    private Node<T> current;

    // 链表长度
    private int size;

    // 链表容量
    private int capacity;


    public LRUWithLInkedList() {
        this.head = this.current = new Node<>(null, null);
        this.capacity = DEFAULT_CAPACITY;
        this.size = 0;
    }

    public LRUWithLInkedList(int capacity) {
        this.head = this.current = new Node<>(null, null);
        this.capacity = capacity;
        this.size = 0;
    }

    /**
     * 添加元素,链表中存在,则删除原节点,在插入链表头部;
     *          不存在,则判断链表长度,如果长度超长,删除尾节点,否则直接头部插入
     * @param data
     */
    public void add(T data) {
        Node preNode = findValue(data);
        if (preNode == null) { // 不存在
            if (size >= capacity) {
                deleteEndNode();
            }
            insertElementToHead(data);
        } else { // 存在
            deleteByPreNode(preNode);
            insertElementToHead(data);
        }
    }

    /**
     * 根据value在链表中查找是否存在
     * @param data
     * @return 返回该节点的上一个节点
     */
    private Node findValue(T data) {
        if (size == 0) {
            return null;
        }
        current = head;
        while (current.next != null) {
            if (current.next.data.equals(data)) {
                return current;
            }
            current = current.next;
        }
        return null;
    }

    /**
     * 向链表头部插入数据
     */
    private void insertElementToHead(T data) {
        head.next = new Node<>(data, head.next);
        size++;
    }

    /**
     * 删除尾节点
     */
    private void deleteEndNode() {
        index(size-2);
        current.next = null;
        size--;
    }

    /**
     * 删除节点
     */
    private void deleteByPreNode(Node preNode) {
        preNode.next = preNode.next.next;
        size--;
    }

    /**
     * 定位函数
     * @param index
     */
    private void index(int index) {
        if (index < -1 || index > size -1) {
            throw new IndexOutOfBoundsException();
        }
        if (index == -1) {
        	current = head;
            return;
        }
        current = head.next;
        int i=0;
        while (i<index) {
            current = current.next;
            i++;
        }
    }

    private void print() {
        current = head.next;
        while (current != null) {
            System.out.print(current.data + "->");
            current = current.next;
        }
        System.out.println();
    }

    private static class Node<T> {
        private T data;
        private Node<T> next;

        public Node(T data, Node<T> next) {
            this.data = data;
            this.next = next;
        }
    }

    public static void main(String[] args) {
        LRUWithLInkedList<Integer> list = new LRUWithLInkedList<>();
        Scanner scanner = new Scanner(System.in);
        while (true) {
            list.add(scanner.nextInt());
            list.print();
        }
    }

}

#测试结果如下:
1
1->
2
2->1->
3
3->2->1->
4
4->3->2->1->
5
5->4->3->2->1->
6
6->5->4->3->2->1->
7
7->6->5->4->3->2->1->
8
8->7->6->5->4->3->2->1->
2
2->8->7->6->5->4->3->1->
9
9->2->8->7->6->5->4->3->1->
0
0->9->2->8->7->6->5->4->3->1->
10
10->0->9->2->8->7->6->5->4->3->

上面算法的在查找数据的时候,效率不高,因为链表需要一个节点一个节点的循环遍历,因此可以使用双向循环链表 + HashMap 的实现进行改进,实现 O(1) 的时间复杂度。

package com.baidu.test.construct.linkedlist;

import java.util.HashMap;
import java.util.Scanner;

/**
 * 基于双向循环链表 + hashMap 实现的 LRU 算法
 * get:获取时,将数据移到链表头部
 * add:添加时,长度不超限时,链表头部直接插入;超限时,插入链表头部,同时删除链表尾部数据
 * @param <K>
 * @param <V>
 */
public class LRUWithHashMap<K, V> {

    private static final int DEFAULT_CAPACITY = 10;

    // 头节点
    private Node<K, V> head;

    // 尾节点
    private Node<K, V> tail;

    // 链表长度
    private int length;

    // 链表容量
    private int capacity;

    private HashMap<K, Node<K, V>> map;

    public LRUWithHashMap() {
        this(DEFAULT_CAPACITY);
    }

    public LRUWithHashMap(int capacity) {
        this.head = new Node<>();
        this.tail = new Node<>();
        head.next = tail;
        tail.pre = head;
        this.length = 0;
        this.capacity = capacity;
        map = new HashMap<>();;
    }

    /**
     * 添加,是否存在,长度小于等于容量,头插法;否则头插法并且删除表尾节点
     * @param key
     * @param value
     */
    public void add(K key, V value) {
        Node<K, V> node = map.get(key);
        if (node == null) {
            node = new Node<>(key, value);
            map.put(key, node);
            addNode(node);
            if (++length > capacity) {
                Node<K, V> tailNode = popTail();
                map.remove(tailNode.key);
                length --;
            }
        } else {
            node.value = value;
            moveToHead(node);
        }
    }


    /**
     * 获取,将数据移动到表头
     * @param key
     * @return
     */
    public V get(K key) {
        Node<K, V> node = map.get(key);
        if (node == null) {
            return null;
        }

        moveToHead(node);
        return node.value;
    }

    /**
     * 将节点插入头部
     */
    private void addNode(Node<K, V> node) {
        node.next = head.next;
        node.pre = head;

        head.next.pre = node;
        head.next = node;
    }

    /**
     * 将节点移动到头部:先删除该节点,然后在头部新增该节点
     * @param node
     */
    private void moveToHead(Node<K, V> node) {
        removeNode(node);
        addNode(node);
    }

    /**
     * 删除节点
     * @param node
     */
    private void removeNode(Node<K, V> node) {
        node.pre.next = node.next;
        node.next.pre = node.pre;
    }

    /**
     * 弹出尾节点
     * @return
     */
    private Node<K, V> popTail() {
        Node<K, V> tailNode = tail.pre;
        removeNode(tailNode);
        return tailNode;
    }

    private void print() {
        Node<K, V> current = head.next;
        while (current != null && current.value != null) {
            System.out.print(current.value + " -> ");
            current = current.next;
        }
        System.out.println();
    }

    /**
     * 双向循环链表
     * @param <K>
     * @param <V>
     */
    private static class Node<K, V> {
        private K key;
        private V value;
        private Node<K, V> pre;
        private Node<K, V> next;

        public Node() {

        }

        public Node(K key, V value) {
            this.key = key;
            this.value = value;
        }
    }

    public static void main(String[] args) {
        LRUWithHashMap<Integer, Integer> lru = new LRUWithHashMap(6);
        Scanner scanner = new Scanner(System.in);
        while (true) {
            int i = scanner.nextInt();
            if (i == -1) {
                break;
            }
            lru.add(i, i);
            lru.print();
        }

        int value = lru.get(5);
        lru.print();
    }
}

### 运行结果如下:
1
1 -> 
3
3 -> 1 -> 
5
5 -> 3 -> 1 -> 
7
7 -> 5 -> 3 -> 1 -> 
9
9 -> 7 -> 5 -> 3 -> 1 -> 
10
10 -> 9 -> 7 -> 5 -> 3 -> 1 -> 
20
20 -> 10 -> 9 -> 7 -> 5 -> 3 -> 
30
30 -> 20 -> 10 -> 9 -> 7 -> 5 -> 
5
5 -> 30 -> 20 -> 10 -> 9 -> 7 -> 
8
8 -> 5 -> 30 -> 20 -> 10 -> 9 -> 
5
5 -> 8 -> 30 -> 20 -> 10 -> 9 -> 
-1
5 -> 8 -> 30 -> 20 -> 10 -> 9 -> 
2.2 链表常见面试题
  1. 单链表反转
  2. 链表中环的检测
  3. 两个有序的链表合并
  4. 删除链表倒数第n个结点
  5. 求链表的中间结点
package com.baidu.test.construct.linkedlist;

import java.util.HashSet;
import java.util.Set;

/**
 * 链表方面练习:
 *  1. 链表反转
 */
public class LinkedListDemo {

    private static class Node {
        private int data;
        private Node next;

        public Node(int data, Node next) {
            this.data = data;
            this.next = next;
        }
    }

    /**
     * 链表反转
     * @param head
     * @return
     */
    public static Node reverseList(Node head) {
        Node pre = null;
        Node next = null;
        while (null != head) {
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        return pre;
    }

    /**
     * 检测链表中是否存在环,快慢指针法
     * @param head
     * @return
     */
    public static boolean verifyCircle(Node head) {
        if (head == null) {
            return false;
        }
        Node fastNode = head.next;
        Node slowNode = head;
        while (fastNode != null && fastNode.next != null) {
            fastNode = fastNode.next.next;
            slowNode = slowNode.next;
            if (fastNode == slowNode) {
                System.out.println("存在中环,重复节点为:" + fastNode.data);
                return true;
            }
        }
        return false;
    }

    /**
     * 检测链表中是否存在环,足迹法
     * @param head
     * @return
     */
    public static boolean verifyCircleWithMap(Node head) {
        Set set = new HashSet();
        while (null != head) {
            if (set.contains(head.data)) {
                return true;
            }
            set.add(head.data);
            head = head.next;
        }
        return false;
    }

    /**
     * 合并两个有序链表
     * @param node1
     * @param node2
     * @return
     */
    public static Node merge2LinkedList(Node node1, Node node2) {
        Node head = new Node(0, null);
        Node current = head;
        while (node1 != null && node2 != null) {
            if (node1.data < node2.data) {
                current.next = node1;
                node1 = node1.next;
            } else {
                current.next = node2;
                node2 = node2.next;
            }
            current = current.next;
        }
        if (node1 != null) {
            current.next = node1;
        }
        if (node2 != null) {
            current.next = node2;
        }
        return head.next;
    }

    /**
     * 求链表中间节点,快慢指针法
     * @param head
     * @return
     */
    public static Node findMiddleNode(Node head) {
        Node fastNode = head;
        Node slowNode = head;
        while (fastNode != null && fastNode.next != null) {
            fastNode = fastNode.next.next;
            slowNode = slowNode.next;
        }
        return slowNode;
    }

    /**
     * 删除链表倒数第K个节点,快慢指针法
     * @param head
     * @return
     */
    public static Node deleteLastKth(Node head, int k) {
        Node fastNode = head;
        int i=0;
        while (i<k && fastNode != null) {
            fastNode = fastNode.next;
            i++;
        }
        if (fastNode == null) {
            return fastNode;
        }
        while (fastNode != null) {
            fastNode = fastNode.next;
            head = head.next;
        }
        return head;
    }

    /**
     * 约瑟夫问题,N个人围成一圈,第一个人从1开始报数,报M的被杀掉,下一个人接着从1开始报,
     * 循环反复,直到剩下最后一个,那最后胜利者的初始位置在哪里
     */
    public static void yuesefu(Node head, int n) {
        int i=1;
        while (head != head.next) {
            i++;
            if (i%n == 0) {
                i++;
                System.out.print(head.next.data + "->");
                head.next = head.next.next;
            }
            head = head.next;
        }
        System.out.println("安全位置为:" + head.data);
    }

    public static void testYuesefu() {
        Node node11 = new Node(11, null);
        Node node10 = new Node(10, node11);
        Node node9 = new Node(9, node10);
        Node node8 = new Node(8, node9);
        Node node7 = new Node(7, node8);
        Node node6 = new Node(6, node7);
        Node node5 = new Node(5, node6);
        Node node4 = new Node(4, node5);
        Node node3 = new Node(3, node4);
        Node node2 = new Node(2, node3);
        Node node1 = new Node(1, node2);
        node11.next = node1;
        yuesefu(node1, 3);
    }

    public static void testReverseList() {
        Node node11 = new Node(11, null);
        Node node10 = new Node(10, node11);
        Node node9 = new Node(9, node10);
        Node node8 = new Node(8, node9);
        Node node7 = new Node(7, node8);
        Node node6 = new Node(6, node7);
        Node node5 = new Node(5, node6);
        Node node4 = new Node(4, node5);
        Node node3 = new Node(3, node4);
        Node node2 = new Node(2, node3);
        Node node1 = new Node(1, node2);
        Node node = reverseList(node1);
        while (node != null) {
            System.out.print(node.data + "->");
            node = node.next;
        }
        System.out.println();
    }

    public static void testVerifyCircle() {
        Node node11 = new Node(11, null);
        Node node10 = new Node(10, node11);
        Node node9 = new Node(9, node10);
        Node node8 = new Node(8, node9);
        Node node7 = new Node(7, node8);
        Node node6 = new Node(6, node7);
        Node node5 = new Node(5, node6);
        Node node4 = new Node(4, node5);
        Node node3 = new Node(3, node4);
        Node node2 = new Node(2, node3);
        Node node1 = new Node(1, node2);
        node11.next = node5;
        boolean result = verifyCircle(node1);
        System.out.println("检测链表中是否存在环:" + result);
    }

    public static void testVerifyCircleWithMap() {
        Node node11 = new Node(11, null);
        Node node10 = new Node(10, node11);
        Node node9 = new Node(9, node10);
        Node node8 = new Node(8, node9);
        Node node7 = new Node(7, node8);
        Node node6 = new Node(6, node7);
        Node node5 = new Node(5, node6);
        Node node4 = new Node(4, node5);
        Node node3 = new Node(3, node4);
        Node node2 = new Node(2, node3);
        Node node1 = new Node(1, node2);
        node11.next = node5;
        boolean result = verifyCircleWithMap(node1);
        System.out.println("检测链表中是否存在环:" + result);
    }

    public static void testMerge2List() {
        Node node4 = new Node(40, null);
        Node node3 = new Node(30, node4);
        Node node2 = new Node(20, node3);
        Node node1 = new Node(1, node2);

        Node node11 = new Node(51, null);
        Node node10 = new Node(40, node11);
        Node node9 = new Node(39, node10);
        Node node8 = new Node(28, node9);
        Node node7 = new Node(17, node8);
        Node node6 = new Node(6, node7);
        Node node5 = new Node(5, node6);
        Node node = merge2LinkedList(node1, node5);
        while (node != null) {
            System.out.print(node.data + "->");
            node = node.next;
        }
    }

    public static void testFindMiddleNode() {
        Node node11 = new Node(11, null);
        Node node10 = new Node(10, node11);
        Node node9 = new Node(9, node10);
        Node node8 = new Node(8, node9);
        Node node7 = new Node(7, node8);
        Node node6 = new Node(6, node7);
        Node node5 = new Node(5, node6);
        Node node4 = new Node(4, node5);
        Node node3 = new Node(3, node4);
        Node node2 = new Node(2, node3);
        Node node1 = new Node(1, node2);
        Node middleNode = findMiddleNode(node1);
        System.out.println(middleNode.data);
    }

    public static void testDeleteLastKth() {
        Node node11 = new Node(11, null);
        Node node10 = new Node(10, node11);
        Node node9 = new Node(9, node10);
        Node node8 = new Node(8, node9);
        Node node7 = new Node(7, node8);
        Node node6 = new Node(6, node7);
        Node node5 = new Node(5, node6);
        Node node4 = new Node(4, node5);
        Node node3 = new Node(3, node4);
        Node node2 = new Node(2, node3);
        Node node1 = new Node(1, node2);
        Node node = deleteLastKth(node1, 7);
        System.out.println(node.data);
    }

    public static void main(String[] args) {
        System.out.println("约瑟夫问题:");
        testYuesefu();
        System.out.println("链表反转:");
        testReverseList();
        System.out.println("检测链表中是否存在环:");
        testVerifyCircle();
        testVerifyCircleWithMap();
        System.out.println("合并两个有序链表:");
        testMerge2List();
        System.out.println("求链表中间节点:");
        testFindMiddleNode();
        System.out.println("删除倒数第K个节点:");
        testDeleteLastKth();
    }
}

# 测试结果:
约瑟夫问题:
3->6->9->1->5->10->4->11->8->2->安全位置为:7
链表反转:
11->10->9->8->7->6->5->4->3->2->1->
检测链表中是否存在环:
存在中环,重复节点为:7
检测链表中是否存在环:true
检测链表中是否存在环:true
合并两个有序链表:
1->5->6->17->20->28->30->39->40->40->51->求链表中间节点:
6
删除倒数第K个节点:
5
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值