博客
关于我
算法问题——链表问题(中等难度)
阅读量:797 次
发布时间:2023-03-28

本文共 6043 字,大约阅读时间需要 20 分钟。

链表算法与数据结构实现

链表是一种常见的数据结构,广泛应用于编程中的各种场景。以下是一些链表相关的算法和实现,涵盖反转、排序、合并、判断回文以及树与链表转换等内容。


链表反转

反转链表是一项常见的链表操作,用于将链表的方向反转。以下是两种反转链表的实现方法:

  • 反转链表(递归方法)

    递归方法通过递归地交换链表中相邻节点,最终实现链表反转。这种方法适用于较短的链表,但在长链表情况下可能导致栈溢出。

    public ListNode reverseList(ListNode head) {    if (head == null) {        return head;    }    // 设置新的节点    ListNode dumpy = new ListNode(-1);    dumpy.next = head;    ListNode pre = dumpy;    ListNode cur = head;    while (cur.next != null) {        ListNode future = cur.next;        cur.next = future.next;        future.next = pre.next;        pre.next = future;    }    return dumpy.next;}
  • 反转链表(快慢指针方法)

    这种方法利用快慢指针找到链表中点,并将前半部分链表反转,然后与后半部分比较,判断是否为回文。

    public boolean isPalindrome(ListNode head) {    if (head == null) return true;    ListNode midNode = findMidNode(head);    ListNode secondHalfHead = reverseLinked(midNode.next);    ListNode curr1 = head;    ListNode curr2 = secondHalfHead;    boolean palindrome = true;    while (palindrome && curr2 != null) {        if (curr1.val != curr2.val) palindrome = false;        curr1 = curr1.next;        curr2 = curr2.next;    }    return palindrome;}private ListNode reverseLinked(ListNode head) {    ListNode cur = head;    ListNode prev = null;    while (cur != null) {        ListNode nextTemp = cur.next;        cur.next = prev;        prev = cur;        cur = nextTemp;    }    return prev;}private ListNode findMidNode(ListNode head) {    ListNode fast = head;    ListNode low = head;    while (fast.next != null && fast.next.next != null) {        fast = fast.next.next;        low = low.next;    }    return low;}

  • 链表排序

    链表排序可以通过快慢指针找到中间节点,然后递归地将左右子链表排序并合并。

    public ListNode sortList(ListNode head) {    if (head == null || head.next == null) {        return head;    }    // 使用快慢指针    ListNode fast = head.next, slow = head;    while (fast != null && fast.next != null) {        slow = slow.next;        fast = fast.next.next;    }    ListNode tmp = slow.next;    slow.next = null;    // 递归拆分    ListNode left = sortList(head);    ListNode right = sortList(tmp);    // 合并链表    return mergeTwoLists(left, right);}public ListNode mergeTwoLists(ListNode l1, ListNode l2) {    // 创建一个新的链表    ListNode dummyHead = new ListNode(0);    ListNode cur = dummyHead;    while (l1 != null && l2 != null) {        if (l1.val < l2.val) {            cur.next = l1;            cur = cur.next;            l1 = l1.next;        } else {            cur.next = l2;            cur = cur.next;            l2 = l2.next;        }    }    // 任一为空,直接连接另一条链表    if (l1 == null) {        cur.next = l2;    } else {        cur.next = l1;    }    return dummyHead.next;}

    链表反转部分节点

    反转链表中从位置 mn 的部分节点,可以通过逐步交换节点的指针来实现。

    public ListNode reverseBetween(ListNode head, int m, int n) {    if (head == null) return head;    ListNode dumpy = new ListNode(-1);    dumpy.next = head;    ListNode pre = dumpy;    // 找到第 m 个节点    for (int i = 1; i < m; i++) {        pre = pre.next;    }    ListNode cur = pre.next;    for (int i = m; i < n; i++) {        ListNode future = cur.next;        cur.next = future.next;        future.next = pre.next;        pre.next = future;    }    return dumpy.next;}

    二叉树转双向链表

    将二叉树转换为双向链表的常见方法是通过深度优先搜索(DFS),并在访问左右子树时记录父节点的方向。

    public class treeToDoublyList {    class TreeNode {        public int val;        public TreeNode left;        public TreeNode right;        public TreeNode() {}        public TreeNode(int _val) {            val = _val;        }        public TreeNode(int _val, TreeNode _left, TreeNode _right) {            val = _val;            left = _left;            right = _right;        }    }    private TreeNode ans;    private TreeNode removeNode;    private void dfs(TreeNode node, int flag) {        if (node != null) {            dfs(node.left, 0);        }        if (ans == null) {            ans = node;            removeNode = node;        } else {            if (flag == 0) {                removeNode.right = node;                node.left = removeNode;            } else {                removeNode.right = node;                node.left = removeNode;            }            removeNode = node;        }        if (node.right != null) {            dfs(node.right, 1);        }    }    public TreeNode treeToDoublyList(TreeNode root) {        if (root == null) {            return null;        }        ans = null;        removeNode = null;        dfs(root, 0);        return ans;    }}

    判断链表是否为回文

    判断链表是否为回文可以通过反转链表并与原链表比较,或者使用快慢指针法找到中间节点并比较两半的值。

    public boolean isPalindrome(ListNode head) {    if (head == null) return true;    ListNode midNode = findMidNode(head);    ListNode secondHalfHead = reverseLinked(midNode.next);    ListNode curr1 = head;    ListNode curr2 = secondHalfHead;    boolean palindrome = true;    while (palindrome && curr2 != null) {        if (curr1.val != curr2.val) palindrome = false;        curr1 = curr1.next;        curr2 = curr2.next;    }    return palindrome;}public boolean isPalindrome1(ListNode head) {    // 使用快慢指针,慢指针在进行操作的时候,顺带的进行链表的翻转,在进行半个链表之间的比较    if (head == null) {        return true;    }    ListNode dummyNode = new ListNode(0);    dummyNode.next = head;    ListNode slow = dummyNode;    ListNode fast = dummyNode;    while (fast != null && fast.next != null) {        fast = fast.next.next;        // 链表翻转        ListNode temp = slow.next;        slow.next = prev;        prev = slow;        slow = temp;    }    // 比较两部分值    if (slow.val != slow.next.val) {        return false;    }    return true;}

    重排链表

    将链表节点按一定规则重新排列,可以利用栈来实现。

    public void reorderList(ListNode head) {    if (head == null) {        return;    }    // 设置一个栈空间    Deque
    stack = new ArrayDeque<>(); ListNode curr = head; // 将所有节点放入栈中 while (curr != null) { stack.push(curr); curr = curr.next; } curr = head; ListNode stack_curr = new ListNode(Integer.MAX_VALUE); while (curr.next != stack_curr.next) { stack_curr = stack.poll(); stack_curr.next = curr.next; curr.next = stack_curr; curr = curr.next.next; } stack_curr.next = null;}

    以上算法涵盖了链表的基本操作及其扩展应用,适用于不同场景的数据结构问题。

    转载地址:http://ulhfk.baihongyu.com/

    你可能感兴趣的文章
    mysql id自动增长 初始值 Mysql重置auto_increment初始值
    查看>>
    MySQL in 太多过慢的 3 种解决方案
    查看>>
    MySQL InnoDB 三大文件日志,看完秒懂
    查看>>
    Mysql InnoDB 数据更新导致锁表
    查看>>
    Mysql Innodb 锁机制
    查看>>
    MySQL InnoDB中意向锁的作用及原理探
    查看>>
    MySQL InnoDB事务隔离级别与锁机制深入解析
    查看>>
    Mysql InnoDB存储引擎 —— 数据页
    查看>>
    Mysql InnoDB存储引擎中的checkpoint技术
    查看>>
    Mysql InnoDB存储引擎中缓冲池Buffer Pool、Redo Log、Bin Log、Undo Log、Channge Buffer
    查看>>
    MySQL InnoDB引擎的锁机制详解
    查看>>
    Mysql INNODB引擎行锁的3种算法 Record Lock Next-Key Lock Grap Lock
    查看>>
    mysql InnoDB数据存储引擎 的B+树索引原理
    查看>>
    mysql innodb通过使用mvcc来实现可重复读
    查看>>
    mysql insert update 同时执行_MySQL进阶三板斧(三)看清“触发器 (Trigger)”的真实面目...
    查看>>
    mysql interval显示条件值_MySQL INTERVAL关键字可以使用哪些不同的单位值?
    查看>>
    Mysql join原理
    查看>>
    MySQL Join算法与调优白皮书(二)
    查看>>
    Mysql order by与limit混用陷阱
    查看>>
    Mysql order by与limit混用陷阱
    查看>>