单链表的应用

本文深入探讨单链表的多种关键操作,包括判断两链表是否相交、检测链表环、合并有序链表、链表逆置及查找倒数第K节点,通过实例解析算法思路与实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.判断两个单链表是否相交,若相交输出相交节点的值,否则返回NULL

   /**
     * 两个单链表是否相交,我们先要得到两个链表的长度,计算出长度的差size,接着先让长链表从头节点走size个,
     * 然后两个链表开始同时遍历,若可以遇到相同的节点,说明链表相交,否则遍历到null,说明链表没有相交
     * @param link
     * @return
     */
    public T isLinkIntersect(Link<T> link) {
        Entry<T> cur1 = this.headEntry;
        Entry<T> cur2 = link.headEntry;

        // 先求出两个链表的长度
        int len1 = 0;
        int len2 = 0;
        while (cur1 != null) {
            cur1 = cur1.next;
            len1++;
        }
        while (cur2 != null) {
            cur2 = cur2.next;
            len2++;
        }

        // 再找出是否存在相交节点
        cur1 = this.headEntry;
        cur2 = link.headEntry;
        if (len1 > len2) { // 链表1比较长
            int size = len1 - len2;
            for (int i = 0; i < size; ++i) {
                cur1 = cur1.next;
            }
        } else if (len1 < len2) { // 链表2比较长
            int size = len2 - len1;
            for (int i = 0; i < size; ++i) {
                cur2 = cur2.next;
            }
        }

        while (cur1 != null && cur2 != null) {
            if (cur1 == cur2) { // 两个指针指向同一个节点,说明链表相交
                return cur1.getValue();
            }
            cur1 = cur1.next;
            cur2 = cur2.next;
        }
        return null;
    }

2.判断单链表是否有环,若存在环输出环的入口节点

   /**
     * 1.判断单链表是否有环
     * @return
     */
    public Entry<T> isLoop() {
        Entry<T> fast = headEntry, slow = headEntry;

        // 使用快慢指针解决该问题
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                return fast;
            }
        }
        return null;
    }

    /**
     * 2.若存在环,输出环的入口节点
     * @return
     */
    public Entry<T> getIntersectEntry() {
        Entry<T> meet = isLoop();
        if (meet == null) {
            return null;
        }

        //fast从第一个节点开始走,slow从快慢指针相交的节点开始走,它们相遇的时候,就是环的入口节点
        Entry<T> slow = meet;
        Entry<T> fast = headEntry;
        while (slow != fast) {
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }

   /**
     * 判断单链表是否有环,若有环输出入环节点的值,若没有环返回null
     * @return
     */
    public T getLinkCircleVal() {
        Entry<T> slow = this.headEntry;
        Entry<T> fast = this.headEntry;
        // 使用快慢指针解决该问题
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast) {
                break;
            }
        }

        if (fast == null) {
            return null;
        } else {
            //fast从第一个节点开始走,slow从快慢指针相交的节点开始走,它们相遇的时候,就是环的入口节点
            fast = this.headEntry;
            while (fast != slow) {
                fast = fast.next;
                slow = slow.next;
            }
            return slow.value;
        }
    }

3.两个单链表有序,将其合并成为一个有序单链表​​​​​​​

   /**
     * 两个单链表有序,将其合并成为一个有序单链表
     * @param link
     */
    public Entry<T> merge(Link<T> link) {
        Entry<T> p = new Entry(-1);//自定义实现的单链表不带头结点
        Entry<T> q = p;//返回q,便于查看合并后的结果
        Entry<T> p1 = this.headEntry;
        Entry<T> p2 = link.headEntry;

        // 比较p1和p2节点的值,把值小的节点挂在p的后面
        while (p1 != null && p2 != null) {
            if (p1.value.compareTo(p2.value) >= 0) {
                p.next = p2;
                p2 = p2.next;
            } else {
                p.next = p1;
                p1 = p1.next;
            }
            p = p.next;
        }

        if (p1 != null) {// 链表1还有剩余节点
            p.next = p1;
        }

        if (p2 != null) {// 链表2还有剩余节点
            p.next = p2;
        }
        return q;
    }

4.单链表逆置 

   /**
     * 逆置单链表,思想是从链表第二个节点开始采用头插法重新连接节点
     */
    public void reverse() {
        if (this.headEntry == null) {
            return;
        }

        //从单链表第二个节点开始逆置
        Entry<T> cur = this.headEntry.next;
        this.headEntry.next = null;
        this.tailEntry = this.headEntry;//更新尾结点
        Entry<T> post = null;
        Entry<T> pre = this.headEntry;

        while (cur != null) {
            post = cur.next;
            cur.next = pre;
            pre = cur;
            cur = post;
        }
        this.headEntry = pre;//更新头结点
    }

5. 单链表的倒数第K个节点

   /**
     * 输出单链表中倒数第k个节点的值
     *
     * @param k
     * @return
     */
    public T getLastOfK(int k) {
        int linkLength = getLength(headEntry);
        if (k <= 0 || k > linkLength) {
            return null;
        }

        Entry<T> cur1 = this.headEntry;
        Entry<T> cur2 = this.headEntry;

        // cur1指向第一个节点,cur2指向正数第k个节点
        for (int i = 0; i < k; i++) {
            cur2 = cur2.next;
            if (cur2 == null) {
                return null;
            }
        }
        // 当cur2到达末尾节点时,cur1指向的就是倒数第k个节点
        while (cur2 != null) {
            cur1 = cur1.next;
            cur2 = cur2.next;
        }
        return cur1.value;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值