数据结构

2018-11-08 单向链表的一系列操作

2018-11-09  本文已影响0人  秋林格瓦斯

我们在这篇文章主要记录下链表的基本操作. 主要包括

首先定义单向链表, 数据包含整型的变量和下一个节点的指针.

 public static class Node {
        private int data;
        private Node next;

        public Node(int data, Node next) {
            this.data = data;
            this.next = next;
        }

        public int getData() {
            return data;
        }
    }

定义print方法,顺序打印链表的值.验证结果的正确性.

public static void print(Node list) {
        while (list != null) {
            System.out.print(list.data);
            list = list.next;
        }

        System.out.println("======================");
    }

一. 反转链表

链表前进的过程中记录下前一个节点的指针. 同时改变当前节点的指针. 使当前节点指向前一个节点.最后返回反转后的链表. 我练习的时候,犯了一个错误. 我想用同一个变量表示反转前, 反转后的链表. 但是这样是行不通的. 因为这里面list传递过来的是一个引用. 而我再list.next = prev; 这一行代码把list的内在属性改变了. 相当于list.next =null; list没有下一个节点了. list 中只有头结点的数据. 这里需要注意.

 /**
     * 反转链表
     *
     * @param list 入参链表
     * @return 反转链表
     */
    public static Node reverse(Node list) {
        Node prev = null;
        Node current = list;
        Node head = null;
        while (current != null) {
            Node next = current.next;
            current.next = prev;
            prev = current;
            if (next == null) {
                head = current;
            }
            current = next;
        }
        return head;

    }

 @Test
    public void reverseTest() {
        Node head = new Node(1, null);
        head.next = new Node(2, null);
        print(head);
        Node rNode = reverse(head);
        System.out.println("++++反转链表+++");
        print(rNode);
    }

二 . 检测环

使用快慢指针操作. 快指针一次走两步. 慢指针一次走一步. 如果存在环. 那么就会存在扣圈的情况. 终将相遇.
这里注意处理边界条件即可

   /**
     * 检测链表中是否存在环
     *
     * @param head
     * @return
     */
    private boolean checkCircle(Node head) {
        if (head == null) {
            return false;
        }

        Node fast = head;
        Node slow = head;

        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast == slow) {
                return true;
            }
        }
        return false;
    }

 @Test
    public void checkCircleTest() {
        Node one = new Node(1, null);
        Node two = new Node(2, null);
        Node three = new Node(3, null);
        Node four = new Node(4, null);
        one.next = two;
        two.next = three;
        three.next = four;
        four.next = two;

        boolean hasCircle = checkCircle(one);
        System.out.println(hasCircle);
    }

三. 两个有序的链表合并

面试有碰到过问两个有序数组合并的情况. 和这种应该类似. 就是首先比较两个链表中第一个元素的值. 把较小节点的作为新链表的头结点.移动节点到下一个位置. 然后在循环体中比较. 较小的放到新链表中. 并移动到下一个节点的位置. 最后考虑一种情况. 有可能一个链表已经移动到尾节点. 这时候把另外一个链表剩余的那部分节点.添加到新链表. 并返回新链表.

**
     * 合并两个有序链表
     *
     * @param list1 链表1
     * @param list2 链表2
     * @return 合并后的链表
     */
    private Node merge(Node list1, Node list2) {
        Node head;

        if (list1 == null) {
            return list2;
        }
        if (list2 == null) {
            return list1;
        }

        if (list1.data < list2.data) {
            head = list1;
            list1 = list1.next;
        } else {
            head = list2;
            list2 = list2.next;
        }

        Node current = head;
        while (list1 != null && list2 != null) {
            if (list1.data < list2.data) {
                current.next = list1;
                list1 = list1.next;
            } else {
                current.next = list2;
                list2 = list2.next;
            }
            current = current.next;

        }
        if (list1 != null) {
            current.next = list1;
        } else {
            current.next = list2;
        }

        return head;
    }

@Test
    public void mergeTest() {
        Node one = new Node(1, null);
        Node two = new Node(2, null);
        Node three = new Node(3, null);
        Node four = new Node(4, null);
        Node five = new Node(5, null);

        one.next = three;
        three.next = five;
        two.next = four;

        Node list1 = one;
        Node list2 = two;

        print(list1);
        print(list2);
        Node mergeList = merge(list1, list2);
        print(mergeList);
    }

四. 删除倒数第K个节点

我先跑,如果你能追上我. 我就跟你嘿嘿嘿. 就是这么骚气. 我怎么知道倒数第K个节点. 这里也是用两个指针. fast 指针先跑K个单位. slow这时候开始跑. fast跑到结尾的时候. slow此时的位置恰好就是倒数第K个位置.
这就把问题转化成小学数学题了.

/**
     * 删除倒数第k个数据
     *
     * @param list
     * @param k
     */
    private Node deleteLastKTest(Node list, int k) {
        int i = 1;
        Node slow = list;
        Node fast = list;
        while (fast != null && i < k) {
            fast = fast.next;
            i++;
        }

        if (fast == null) {
            return list;
        }

        Node pre = null;
        while (fast.next != null) {
            fast = fast.next;
            pre = slow;
            slow = slow.next;
        }


        if (pre == null) {
            list = list.next;
        } else {
            pre.next = pre.next.next;
        }
        return list;


    }

@Test
    public void deleteLastKTest() {
        Node one = new Node(1, null);
        Node two = new Node(2, null);
        Node three = new Node(3, null);
        Node four = new Node(4, null);
        Node five = new Node(5, null);

        one.next = two;
        two.next = three;
        three.next = four;
        four.next = five;

        int k = 5;
        Node node = deleteLastKTest(one, k);
        print(node);
    }

五. 求链表的中间结点

快慢指针. 一个二倍速fast. 一个一倍速slow. fast 走到结尾. slow恰好走一半.

 /**
     *  返回中间节点
     * @param list
     * @return
     */
    private Node middleNode(Node list) {
        if(list==null){
            return null;
        }
        Node fast = list;
        Node slow = list;
        while(fast.next!=null && fast.next.next!=null){
            fast = fast.next.next;
            slow = slow.next;
        }

        return slow;
    }

 @Test
    public void middleNodeTest() {
        Node one = new Node(1, null);
        Node two = new Node(2, null);
        Node three = new Node(3, null);
        Node four = new Node(4, null);
        Node five = new Node(5, null);
        Node six = new Node(6,null);

        one.next = two;
        two.next = three;
        three.next = four;
        four.next = five;
        five.next = six;

        Node node = middleNode(one);
         System.out.println(node.data);
    }
上一篇下一篇

猜你喜欢

热点阅读