4.单向链表的常见题型

Posted quxiangxiangtiange

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了4.单向链表的常见题型相关的知识,希望对你有一定的参考价值。

  本篇主要是单向链表题型的实战,比如反转单向链表、查找单向链表的中间节点、判断一个链表是否有环、合并两个有序链表、判断一个单向链表是否是回文链表。

/**
 * Node为链表结点对象
 */
class Node {
    public Integer data;
    public Node next;
    public Node(Integer data){
        this.data = data;
    }
}
public class LinkedListUtil {
    /**
     * 反转一个单向链表
     * 思路:申请两个变量(指针)pre、cur,pre指向null,cur指向头结点,cur充当临时变量保存着当前操作结点的下一结点
     * @param head
     * @return
     */
    public static Node reverseList(Node head){
        Node pre = null;
        Node cur = head;
        while(cur != null){
            cur = head.next;
            head.next = pre;
            pre = head;
            head = cur;
        }
        return pre;
    }

    /**
     * 获得链表的中间节点,若是单节点链表则返回头结点
     * 思路:申请两个变量(指针)pre、cur,pre指向头结点,cur指向头结点的下一个结点,然后pre每次走一步,cur每次走两步,当cur为null或者cur的下一结点为null则此时pre即为中间节点
     * @param head
     * @return
     */
    public static Node getMiddleNode(Node head) {
        if(head == null) {
            return head;
        }
        Node pre = head;
        Node cur = head.next;
        while(cur != null && cur.next != null){
            pre = pre.next;
            cur = cur.next.next;
        }
        return pre;
    }

    /**
     * 判断一个链表是否有环
     * 思路:申请两个变量(指针)pre、cur指向头结点,pre每次走一步,cur每次走两步,若pre等于cur则说明有环
     * @param head
     * @return
     */
    public static boolean isCircle(Node head) {
        Node pre = head;
        Node cur = head;
        while(cur != null && cur.next != null){
            pre=pre.next;
            cur=cur.next.next;
            if(pre == cur){
                return true;
            }
        }
        return false;
    }

    /**
     * 合并两个有序链表为一个升序链表
     *
     * @param head1 有序链表1的头节点
     * @param head2 有序链表2的头节点
     * @return
     */
    public static Node merageOrderedList(Node head1, Node head2) {
        if (head1 == null) {
            return head2;
        }
        if (head2 == null) {
            return head1;
        }
        Node temp1 = head1;
        Node temp2 = head2;
        Node tempHead1 = head1;
        Node tempHead2 = head2;

        /*判断链表1是否升序,若不是则反转链表1*/
        while(temp1 != null && temp1.next != null){
            if(temp1.data > temp1.next.data){
                tempHead1 = reverseList(tempHead1);
                break;
            }
            temp1 = temp1.next;
        }
        /*判断链表2是否升序,若不是则反转链表2*/
        while(temp2 != null && temp2.next != null){
            if(temp2.data > temp2.next.data){
                tempHead2 = reverseList(tempHead2);
                break;
            }
            temp2 = temp2.next;
        }
        //用变量head保存合并后有序链表的头节点
        Node head = null;
        if(tempHead1.data < tempHead2.data){
            head = tempHead1;
            tempHead1 = tempHead1.next;
        }else {
            head = tempHead2;
            tempHead2 = tempHead2.next;
        }
        Node cur = head;
        /*执行合并两个链表*/
        while(tempHead1 != null && tempHead2 != null){
            if(tempHead1.data < tempHead2.data){
                cur.next= tempHead1;
                tempHead1= tempHead1.next;
                cur = cur.next;
            }else{
                cur.next = tempHead2;
                tempHead2 = tempHead2.next;
                cur = cur.next;
            }
        }
        /*执行合并操作结束后,若其中一个链表不为空则将该链表接到合并链表之后*/
        if(tempHead1!= null){
            cur.next = tempHead1;
        }
        if(tempHead2!= null){
            cur.next = tempHead2;
        }
        return head;
    }

    /**
     * 判断一个单向链表是否为回文链表
     * 思路:反转后半部分链表,然后与前半部分比对,若有不同则不是回文链表,否则是回文链表,然后反转链表复原并拼接到前半部分
     * @param head
     * @return
     */
    public static boolean isPalindrome(Node head){
        if(head == null || head.next == null){
            return false;
        }
        boolean flag = true;
        //找到链表的中间节点
        Node pre = getMiddleNode(head);
        //反转后半部分的链表
        Node reverseHead = reverseList(pre.next);
        //用cur临时存储一份反转链表的头结点
        Node cur = reverseHead;
        Node helpHead = head;
        while (cur != null){
            if(!cur.data.equals(helpHead.data)){
                flag = false;
                break;
            }
            cur = cur.next;
            helpHead = helpHead.next;
        }
        pre.next = reverseList(reverseHead);
        return flag;
    }

    public static void main(String[] args){
        Node head = new Node(1);
        head.next = new Node(2);
        head.next.next = new Node(3);
        head.next.next.next = new Node(4);
        boolean isCircle = isCircle(head);
        boolean palindrome = isPalindrome(head);
        Node middle = getMiddleNode(head);

        System.out.println("是否为环:" + isCircle);
        System.out.println("是否是回文串"+palindrome);
        System.out.println("中间节点:" + middle.data);

//        System.out.println();
//        Node reverse = reverseList(head);
//        while (reverse != null){
//            System.out.print(reverse.data + "	");
//            reverse = reverse.next;
//        }
//        System.out.println();
//        Node root = new Node(3);
//        root.next = new Node(5);
//        Node mearge = merageOrderedList(head,reverse);
//        while(mearge != null) {
//            System.out.print(mearge.data + "	");
//            mearge = mearge.next;
//        }
//        Node ress = reverseList(head);
        Node test =  new Node(1);
        test.next = test;
        System.out.println(isCircle(test));
    }
}

 

以上是关于4.单向链表的常见题型的主要内容,如果未能解决你的问题,请参考以下文章

一文通数据结构与算法之——链表+常见题型与解题策略+Leetcode经典题

C语言反转单向链表的代码

认识链表以及其常见操作Java代码实现

Python数据结构与算法篇-- 链表的应用与常见题型

数据结构----顺序表,链表

线性表--04---链表----常见应用场景(快慢指针约瑟夫问题)