链表相关算法详解:揭秘链表操作的奥秘

2023-12-15 09:30:26

标题:链表相关算法详解:揭秘链表操作的奥秘

引言:
链表是数据结构中常见的一种形式,它由一系列节点组成,每个节点包含数据和指向下一个节点的指针。链表操作是编程中常用的技术之一,本文将详细介绍链表的常见操作及相关算法,并通过举例说明,帮助读者更好地理解和运用链表。

一、链表的基本操作
1.1 链表的创建
链表的创建可以通过动态分配内存来实现。我们首先创建一个头节点,然后根据需要逐个添加其他节点。

举例说明:
假设我们要创建一个链表存储学生信息,每个节点包含学生的姓名和年龄。我们首先创建一个头节点,然后逐个添加其他节点。

1.2 链表的插入
链表的插入操作是指在链表的指定位置插入一个新节点。插入节点的关键是找到插入位置的前一个节点,然后将新节点的指针指向下一个节点,再将前一个节点的指针指向新节点。

举例说明:
假设我们有一个已经创建好的链表,现在要在第二个节点后插入一个新节点,新节点的值为“张三”,年龄为20。

1.3 链表的删除
链表的删除操作是指删除链表中的某个节点。删除节点的关键是找到要删除节点的前一个节点,然后将前一个节点的指针指向要删除节点的下一个节点。

举例说明:
假设我们有一个已经创建好的链表,现在要删除第三个节点。

1.4 链表的查找
链表的查找操作是指在链表中查找某个特定值的节点。查找节点的关键是遍历链表,逐个比较节点的值,直到找到目标节点或链表结束。

举例说明:
假设我们有一个已经创建好的链表,现在要查找值为“李四”的节点。

二、链表的常见算法
2.1 链表的反转
链表的反转是指将链表中的节点顺序颠倒。反转链表的关键是修改节点的指针指向,使每个节点的指针指向前一个节点。

代码实现:

/**
     * 链表反转(递归实现)
     *
     * @param head 1->2->3->4->5->null
     *             1->2<-3<-4<-5
     * @return
     */
    public static ListNode reverse(ListNode head) {
        if (head.next == null) {
            return head;
        }
        ListNode subNode = reverse(head.next);
        head.next.next = head;
        head.next = null;
        return subNode;
    }

    /**
     * 链表反转(迭代实现)
     *
     * @param head null 1 -> 2 -> 3 -> 4 -> 5 -> null    pre:null cur:1  next=2
     *             null <-1  2 -> 3 -> 4 -> 5 -> null    pre:1 cur:2  next=3
     *             null <-1 <- 2  3 -> 4 -> 5 -> null   pre:2 cur:3 next=4
     *             null <-1 <- 2 <- 3  4->5 -> null     pre:3 cur:4 next=5
     *             null <-1 <- 2 <- 3 <- 4  5 -> null   pre:4 cur:5 next=6
     *             null <-1 <- 2 <- 3 <- 4 <- 5 null    pre:5 cur:null 
     * @return
     */
    public static ListNode reverse2(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        ListNode next = null;
        while (cur != null) {
            next = cur.next;
            cur.next = pre;

            pre = cur;
            cur = next;
        }
        return pre;
    }

/**
     * 链表前m-n个反转(递归实现)
     *
     * @param head
     * @return
     */
    public static ListNode reverseMN(ListNode head, int m, int n) {
        if (m == 1) {
            return reverseN(head, n);
        }
        head.next = reverseMN(head.next, m - 1, n - 1);
        return head;
    }


    /**
     * 链表前m-n个反转(迭代实现)
     *
     * @param head
     * @return null -> 1 -> 2 <- 3 <- 4  5
     */
    public static ListNode reverseMN2(ListNode head, int m, int n) {
        ListNode pre = null;
        ListNode cur = head;
        ListNode next = head;
        ListNode mNode = null;
        int k = 1;
        while (cur != null && k <= n) {
            next = cur.next;
            if (k == m) {
                mNode = cur;
            }
            if (k >= m) {
                cur.next = pre;
            }
            pre = cur;
            cur = next;
            k++;
        }
        mNode.next.next = pre;
        mNode.next = cur;
        return head;
    }
/**
     * k个一组反转链表(不足k时不反转)
     *
     * @param head
     * @param k
     * @return
     */
    public static ListNode reverseKGroup(ListNode head, int k) {
        int i = 0;
        ListNode node = head;
        while (i < k) {
            if (node == null) {
                return head;
            }
            i++;
            node = node.next;
        }

        ListNode pre = head;
        ListNode newNode = reverseN2(head, k);
        pre.next = reverseKGroup(node, k);
        return newNode;
    }

2.2 链表的合并
链表的合并是指将两个有序链表合并成一个有序链表。合并链表的关键是比较两个链表的节点值,将较小值的节点插入到新链表中。

代码实现:

/**
     * 合并有序链表(非递归)
     *
     * @param aNode a链表
     * @param bNode b链表
     * @return 合并链表
     */
    public static LinkNode<Integer> mergeOrderLinkedListA(LinkNode<Integer> aNode, LinkNode<Integer> bNode) {
        LinkNode<Integer> tempNode = new LinkNode<Integer>();
        LinkNode<Integer> mergeNode = tempNode;

        while (aNode != null || bNode != null) {
            if (aNode == null) {
                tempNode.next = bNode;
                tempNode = tempNode.next;
                bNode = bNode.next;
                continue;
            }

            if (bNode == null) {
                tempNode.next = aNode;
                tempNode = tempNode.next;
                aNode = aNode.next;
                continue;
            }

            if (aNode.value >= bNode.value) {
                tempNode.next = bNode;
                bNode = bNode.next;
            } else {
                tempNode.next = aNode;
                aNode = aNode.next;
            }
            tempNode = tempNode.next;
        }
        return mergeNode.next;
    }


    /**
     * 合并有序链表(递归)
     *
     * @param aNode a链表
     * @param bNode b链表
     * @return 合并链表
     */
    public static LinkNode<Integer> mergeOrderLinkedListB(LinkNode<Integer> aNode, LinkNode<Integer> bNode) {
        LinkNode<Integer> mergeNode = null;
        if (aNode != null && bNode != null) {
            if (aNode.value >= bNode.value) {
                mergeNode = bNode;
                mergeNode.next = mergeOrderLinkedListB(aNode, bNode.next);
            } else {
                mergeNode = aNode;
                mergeNode.next = mergeOrderLinkedListB(aNode.next, bNode);
            }
        }

        if (aNode == null) {
            mergeNode = bNode;
        }

        if (bNode == null) {
            mergeNode = aNode;
        }
        return mergeNode;
    }

    /**
     * 合并多个有序链表(递归)
     *
     * @param linkNodes 多个链表
     * @return 排序链表
     */
    public static LinkNode<Integer> mergeMoreOrderLinkedList(List<LinkNode<Integer>> linkNodes) {
        LinkNode<Integer> mergeNode = null;
        for (int i = 0; i < linkNodes.size(); i++) {
            if (linkNodes.get(i) == null) {
                linkNodes.remove(i);
            }
        }

        if (linkNodes.size() == 1) {
            mergeNode = linkNodes.get(0);
            return mergeNode;
        }

        if (linkNodes.isEmpty()) {
            mergeNode = null;
            return mergeNode;
        }

        Integer min = linkNodes.get(0).value;
        int minKey = 0;
        for (int i = 0; i < linkNodes.size(); i++) {
            if (linkNodes.get(i) != null && linkNodes.get(i).value < min) {
                min = linkNodes.get(i).value;
                minKey = i;
            }
        }

        mergeNode = linkNodes.get(minKey);
        LinkNode minLinkNode = linkNodes.get(minKey);
        minLinkNode = minLinkNode.next;
        if (minLinkNode == null) {
            linkNodes.remove(minKey);
        } else {
            linkNodes.set(minKey, minLinkNode);
        }
        mergeNode.next = mergeMoreOrderLinkedList(linkNodes);

        return mergeNode;
    }

2.3 链表的环检测
链表的环检测是指判断链表中是否存在环。环检测的关键是使用快慢指针,如果两个指针相遇,则链表中存在环。

代码实现:

/**
     * 判断链表是否有环
     *
     * @param listNode
     * @return
     */
    public static boolean isCycleLinkedNode(ListNode listNode) {
        if (listNode == null) {
            return false;
        }
        ListNode slow = listNode;
        ListNode fast = listNode;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                return true;
            }
        }
        return false;
    }

结论:
本文详细介绍了链表的基本操作和常见算法,并通过举例说明,帮助读者更好地理解和运用链表。掌握链表操作的技巧,对于解决实际问题和提高编程能力都具有重要意义。希望本文能为读者提供帮助,欢迎大家留言交流。

文章来源:https://blog.csdn.net/fudaihb/article/details/134998242
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。