【数据结构】链表

本文详细探讨了链表的各种操作,包括单链表和双向链表的反转,用链表实现队列和栈,以及双端队列的构建。此外,还介绍了如何进行K个节点的组内逆序调整,两个链表的相加,以及两个有序链表和多个有序链表的合并。通过大量的测试用例确保了这些操作的正确性。
摘要由CSDN通过智能技术生成

1 链表反转

public class Code01_ReverseList {

    public static class Node {
        public int value;
        public Node next;

        public Node(int data) {
            value = data;
        }
    }

    public static class DoubleNode {
        public int value;
        public DoubleNode last;
        public DoubleNode next;

        public DoubleNode(int data) {
            value = data;
        }
    }

    /**
     * 单链表反转
     */
    public static Node reverseLinkedList(Node head) {
        Node pre = null;
        Node next = null;
        while (head != null) {
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }

        return pre;
    }

    /**
     * 双向链表反转
     */
    public static DoubleNode reverseDoubleList(DoubleNode head) {
        DoubleNode pre = null, next = null;
        while (head != null) {
            next = head.next;
            head.next = pre;
            head.last = next;
            pre = head;
            head = next;
        }
        return pre;
    }

    // for test
    public static Node generateRandomLinkedList(int len, int value) {
        int size = (int) (Math.random() * len) + 1;

        size--;
        Node head = new Node((int) (Math.random() * value) + 1);
        Node pre = head;
        while (size != 0) {
            Node cur = new Node((int) (Math.random() * value) + 1);
            pre.next = cur;
            pre = cur;
            size--;
        }
        return head;
    }

    // for test
    public static List<Integer> getLinkedListOriginOrder(Node head) {
        List<Integer> list = new ArrayList<>();
        while (head != null) {
            list.add(head.value);
            head = head.next;
        }
        return list;
    }

    // 单链表对数器
    public static boolean checkLinkedListReversed(List<Integer> list, Node head) {
        for (int i = list.size() - 1; i >= 0; i--) {
            if (!list.get(i).equals(head.value)) {
                return false;
            }

            head = head.next;
        }
        return true;
    }

    // for test
    public static DoubleNode generateRandomDoubleList(int len, int value) {
        int size = (int) (Math.random() * len) + 1;

        size--;
        DoubleNode head = new DoubleNode((int) (Math.random() * value) + 1);
        DoubleNode pre = head;
        while (size != 0) {
            DoubleNode cur = new DoubleNode((int) (Math.random() * value) + 1);
            pre.next = cur;
            cur.last = pre;
            pre = cur;
            size--;
        }
        return head;
    }

    // for test
    public static List<Integer> getDoubleListOriginOrder(DoubleNode head) {
        List<Integer> list = new ArrayList<>();
        while (head != null) {
            list.add(head.value);
            head = head.next;
        }
        return list;
    }

    // 双端链表对数器
    public static boolean checkDoubleListReversed(List<Integer> list, DoubleNode head) {
        DoubleNode end = null;
        for (int i = list.size() - 1; i >= 0; i--) {
            if (!list.get(i).equals(head.value)) {
                return false;
            }

            end = head;
            head = head.next;
        }

        // 尾部
        for (int i = 0; i < list.size(); i++) {
            if (!list.get(i).equals(end.value)) {
                return false;
            }

            end = end.last;
        }

        return true;
    }

    public static void main(String[] args) {
        int len = 50;
        int value = 100;
        int testTime = 100000;

        for (int i = 0; i < testTime; i++) {
            Node node = generateRandomLinkedList(len, value);
            List<Integer> list1 = getLinkedListOriginOrder(node);
            node = reverseLinkedList(node);
            if (!checkLinkedListReversed(list1, node)) {
                System.out.println("Oops1");
            }

            DoubleNode doubleNode = generateRandomDoubleList(len, value);
            List<Integer> list2 = getDoubleListOriginOrder(doubleNode);
            doubleNode = reverseDoubleList(doubleNode);
            if (!checkDoubleListReversed(list2, doubleNode)) {
                System.out.println("Oops2");
            }
        }
    }
}

2 链表实现队列和栈

public class Code02_LinkedListToQueueAndStack {

    public static class Node<V> {
        public V value;
        public Node<V> next;

        public Node(V v) {
            value = v;
            next = null;
        }
    }

    public static class MyQueue<V> {
        Node<V> head;
        Node<V> tail;
        int size;

        public int size() {
            return size;
        }

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

        public void offer(V value) {
            Node<V> cur = new Node<>(value);
            if (tail == null) {
                head = cur;
                tail = cur;
            } else {
                tail.next = cur;
                tail = cur;
            }
            size++;
        }

        public V poll() {
            if (head == null) {
                return null;
            }

            size--;
            V value = head.value;
            head = head.next;
            // 最后一个节点
            if (head == null) {
                tail = null;
            }
            return value;
        }

        public V peek() {
            return head == null ? null : head.value;
        }
    }

    public static class MyStack<V> {
        Node<V> head;
        int size;

        public int size() {
            return size;
        }

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

        public void push(V value) {
            Node<V> cur = new Node<>(value);

            if (head == null) {
                head = cur;
            } else {
                cur.next = head;
                head = cur;
            }
            size++;
        }

        public V pop() {
            if (head == null) {
                return null;
            }

            size--;
            V value = head.value;
            head = head.next;
            return value;
        }

        public V peek() {
            return head == null ? null : head.value;
        }
    }

    // 对数器测试
    public static void testQueue() {
        MyQueue<Integer> myQueue = new MyQueue<>();
        Queue<Integer> testQueue = new LinkedList<>();

        int testTime = 5000000;
        int maxValue = 200000000;
        System.out.println("队列测试开始!!");

        for (int i = 0; i < testTime; i++) {
            if (myQueue.size != testQueue.size()) {
                System.out.println("Oops");
                break;
            }

            double random = Math.random();
            if (random < 0.33) {
                int value = (int) (Math.random() * maxValue);
                myQueue.offer(value);
                testQueue.offer(value);
            } else if (random < 0.66) {
                if (!myQueue.isEmpty()) {
                    if (!myQueue.poll().equals(testQueue.poll())) {
                        System.out.println("Oops");
                        break;
                    }
                }
            } else {
                if (!myQueue.isEmpty()) {
                    if (!myQueue.peek().equals(testQueue.peek())) {
                        System.out.println("Oops");
                        break;
                    }
                }
            }
        }

        if (myQueue.size != testQueue.size()) {
            System.out.println("Oops");
            return;
        }

        while (!myQueue.isEmpty()) {
            if (!myQueue.poll().equals(testQueue.poll())) {
                System.out.println("Oops");
                break;
            }
        }

        System.out.println("队列测试结束!!");
    }

    // 对数器测试
    public static void testStack() {
        MyStack<Integer> myStack = new MyStack<>();
        Stack<Integer> testStack = new Stack<>();

        int testTime = 5000000;
        int maxValue = 200000000;
        System.out.println("栈测试开始!!");

        for (int i = 0; i < testTime; i++) {
            if (myStack.size != testStack.size()) {
                System.out.println("Oops");
                break;
            }

            double random = Math.random();
            if (random < 0.33) {
                int value = (int) (Math.random() * maxValue);
                myStack.push(value);
                testStack.push(value);
            } else if (random < 0.66) {
                if (!myStack.isEmpty()) {
                    if (!myStack.pop().equals(testStack.pop())) {
                        System.out.println("Oops");
                        break;
                    }
                }
            } else {
                if (!myStack.isEmpty()) {
                    if (!myStack.peek().equals(testStack.peek())) {
                        System.out.println("Oops");
                        break;
                    }
                }
            }
        }

        if (myStack.size != testStack.size()) {
            System.out.println("Oops");
            return;
        }

        while (!myStack.isEmpty()) {
            if (!myStack.pop().equals(testStack.pop())) {
                System.out.println("Oops");
                break;
            }
        }

        System.out.println("栈测试结束!!");
    }

    public static void main(String[] args) {
        testQueue();

        System.out.println("-----------------------------");

        testStack();
    }
}

3 双端队列

public class Code03_DoubleLinkedListToDeque {

    public static class Node<V> {
        public V value;
        public Node<V> last;
        public Node<V> next;

        public Node(V v) {
            value = v;
            last = null;
            next = null;
        }
    }

    public static class MyDeque<V> {
        Node<V> head;
        Node<V> tail;
        int size;

        public int size() {
            return size;
        }

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

        public void offerTail(V value) {
            Node<V> cur = new Node<>(value);
            if (tail == null) {
                head = cur;
                tail = cur;
            } else {
                tail.next = cur;
                cur.last = tail;
                tail = cur;
            }
            size++;
        }

        public V pollHead() {
            if (head == null) {
                return null;
            }

            size--;
            V value = head.value;
            if (head == tail) {
                head = null;
                tail = null;
            } else {
                head = head.next;
                head.last = null;
            }
            return value;
        }

        public V peekHead() {
            return head == null ? null : head.value;
        }

        public void offerHead(V value) {
            Node<V> cur = new Node<>(value);
            if (head == null) {
                head = cur;
                tail = cur;
            } else {
               cur.next = head;
               head.last = cur;
               head = cur;
            }
            size++;
        }

        public V pollTail() {
            if (tail == null) {
                return null;
            }

            size--;
            V value = tail.value;
            if (head == tail) {
                head = null;
                tail = null;
            } else {
                tail = tail.last;
                tail.next = null;
            }
            return value;
        }

        public V peekTail() {
            return tail == null ? null : tail.value;
        }
    }

    public static void testMyDeque() {
        MyDeque<Integer> myDeque = new MyDeque<>();
        Deque<Integer> testDeque = new LinkedList<>();

        int testTime = 5000000;
        int maxValue = 200000000;
        System.out.println("双端测试开始!");

        for (int i = 0; i < testTime; i++) {
            if (myDeque.size != testDeque.size()) {
                System.out.println("Oops");
                break;
            }

            double random = Math.random();
            if (random < 0.33) {
                int value = (int) (Math.random() * maxValue);

                double rate = Math.random();
                if (rate < 0.5) {
                    myDeque.offerHead(value);
                    testDeque.offerFirst(value);
                } else {
                    myDeque.offerTail(value);
                    testDeque.offerLast(value);
                }

            } else if (random < 0.66) {
                if (!myDeque.isEmpty()) {
                    double rate = Math.random();
                    if (rate < 0.5) {
                        if (!myDeque.pollHead().equals(testDeque.pollFirst())) {
                            System.out.println("Oops");
                            break;
                        }
                    } else {
                        if (!myDeque.pollTail().equals(testDeque.pollLast())) {
                            System.out.println("Oops");
                            break;
                        }
                    }
                }
            } else {
                if (!myDeque.isEmpty()) {
                    double rate = Math.random();
                    if (rate < 0.5) {
                        if (!myDeque.peekHead().equals(testDeque.peekFirst())) {
                            System.out.println("Oops");
                            break;
                        }
                    } else {
                        if (!myDeque.peekTail().equals(testDeque.peekLast())) {
                            System.out.println("Oops");
                            break;
                        }
                    }
                }
            }
        }

        if (myDeque.size != testDeque.size()) {
            System.out.println("Oops");
            return;
        }

        while (!myDeque.isEmpty()) {
            if (!myDeque.pollHead().equals(testDeque.pollFirst())) {
                System.out.println("Oops");
                break;
            }
        }

        System.out.println("双端测试结束!");
    }

    public static void main(String[] args) {
        testMyDeque();
    }
}

4 K 个节点组内逆序调整

在这里插入图片描述

public class Code04_ReverseNodesInKGroup {
    public static class ListNode {
        public int val;
        public ListNode next;
    }

    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode start = head;
        ListNode end = getKGroupEnd(head, k);
        if (end == null) {
            return head;
        }

        // 第一组
        head = end;
        reverse(start, end);

        // 上一组结尾
        ListNode lastEnd = start;
        while (lastEnd.next != null) {
            // 第二组开始节点
            start = lastEnd.next;
            end = getKGroupEnd(start, k);
            // 不足 k 个直接返回
            if (end == null) {
                return head;
            }
            // 第n-1组
            reverse(start, end);
            // 上一组反转的节点指向当前组反转的起始节点
            lastEnd.next = end;
            // 更新最新的结束节点
            lastEnd = start;
        }

        return head;
    }

    /**
     * 获取 node 开始的第 k 的节点
     */
    public ListNode getKGroupEnd(ListNode start, int k) {
        while (k-- > 0 && start != null) {
            start = start.next;
        }
        return start;
    }

    /**
     * 翻转 start - end 的顺序
     */
    public void reverse(ListNode start, ListNode end) {
        end = end.next;
        ListNode pre = null;
        ListNode cur = start;
        ListNode next = null;
        while (cur != end) {
            next = cur.next;
            // 反转
            cur.next = pre;
            pre = cur;
            cur = next;
        }
        // 指向 end 的后一个节点
        start.next = end;
    }
}

5 两个链表相加

在这里插入图片描述

public class Code05_AddTwoNumbers {

    public static class ListNode {
        public int val;
        public ListNode next;

        public ListNode(int val) {
            this.val = val;
        }

        public ListNode(int val, ListNode next) {
            this.val = val;
            this.next = next;
        }
    }

    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        // 分开链表和短链表
        int len1 = getLength(l1);
        int len2 = getLength(l2);

        // l 长链表 s 短链表
        ListNode l, s;
        if (len1 >= len2) {
            l = l1;
            s = l2;
        } else {
            l = l2;
            s = l1;
        }

        ListNode curL = l,
                curS = s,
                lastL = null;
        // 进位
        int carry = 0;
        while (curS != null) {
            int sum = curL.val + curS.val + carry;
            curL.val = sum % 10;
            // 更新进位
            carry = sum / 10;

            lastL = curL;
            curL = curL.next;
            curS = curS.next;
        }

        while (curL != null) {
            int sum = curL.val + carry;
            curL.val = sum % 10;
            // 更新进位
            carry = sum / 10;

            lastL = curL;
            curL = curL.next;
        }

        if (carry != 0) {
            lastL.next = new ListNode(carry);
        }

        return l;
    }

    public int getLength(ListNode node) {
        int len = 0;
        while (node != null) {
            len++;
            node = node.next;
        }
        return len;
    }
}

6 两个有序链表的合并

在这里插入图片描述

public class Code06_MergeTwoSortedLinkedList {

    public static class ListNode {
        public int val;
        public ListNode next;
    }

    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        if (list1 == null || list2 == null) {
            return list1 == null ? list2 : list1;
        }

        // 找较小的作为返回的节点
        ListNode head = list1.val < list2.val ? list1 : list2;
        // 从下一个节点开始遍历
        ListNode cur1 = head.next;
        ListNode cur2 = head == list1 ? list2 : list1;
        ListNode pre = head;
        while (cur1 != null && cur2 != null) {
            if (cur1.val < cur2.val) {
                // 小的指向大的值
                pre.next = cur1;
                // 下一个几点
                cur1 = cur1.next;
            } else {
                pre.next = cur2;
                cur2 = cur2.next;
            }

            pre = pre.next;
        }

        // 连接较长链表的后续节点
        pre.next = cur1 == null ? cur2 : cur1;
        return head;
    }
}

7 合并 K 个有序链表

在这里插入图片描述

public class Code01_MergeKSortedLists {

    public class ListNode {
        int val;
        ListNode next;
        ListNode() {}
        ListNode(int val) { this.val = val; }
        ListNode(int val, ListNode next) { this.val = val; this.next = next; }
    }

	/**
     * 使用小顶堆实现
     * 1. 将每个链表的头节点放入小顶堆.
     * 2. 从小顶堆弹出第一个节点,连接到新链表最后,并将该节点的下一个节点(非空)放入堆中
     * 3. 重复步骤2,知道堆为空
     */
    public static ListNode mergeKLists(ListNode[] lists) {
        if (lists == null || lists.length == 0) {
            return null;
        }

        // 使用小顶堆
        PriorityQueue<ListNode> heap = new PriorityQueue<>(Comparator.comparingInt(o -> o.val));

        // 将每个链表的都节点放入堆中
        for (ListNode h : lists) {
            if (h != null) {
                heap.offer(h);
            }
        }

        if (heap.isEmpty()) {
            return null;
        }

        // 头节点
        ListNode head = heap.poll();
        if (head.next != null) {
            heap.add(head.next);
        }

        ListNode pre = head;
        // 非空
        while (!heap.isEmpty()) {
            ListNode cur = heap.poll();
            if (cur.next != null) {
                heap.add(cur.next);
            }

            pre.next = cur;
            pre = cur;
        }

        return head;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值