2.链表

链表(单链表)是一种通过指针将一组零散的内存块串联起来的数据结构,每个链表的结点除了存储的数据之外,还需要记录链上的下一个节点的地址

  • 链表的插入和删除(给定节点指针)时间复杂度O(1),但遍历删除的时间复杂度是O(n)

  • 双向链表:每个结点不止有一个后继指针指向后面的结点,还有一个前驱指针指向前面的结点。在删除指定指针指向的节点时,时间复杂度仅为O(1)若链表是有序链表,那么查找时可以向前向后遍历,平均能少遍历一半的数据

  • 链表有关算法

    • 单链表反转
      定义两个节点curr,pre。curr.next指向pre,然后curr、pre后移一位,重复直到最后一个节点。​

    • 检测环
      1.快慢指针,快指针每次走两步,慢指针每次走一步。​相遇则说明有环
      2.遍历链表并将节点值加入散列表中,若有重复的说明有环​

    • 有序链表合并
      定义一个哨兵,每次加入较小节点,最后加入较长链表剩余部分

    • 删除倒数第k个节点
      定义快慢指针,从头节点开始快指针先走k-1步,然后快慢同时走,快指针走到表尾时慢指针指向的就是倒数第k个

    • 求中间节点
      快慢指针,快指针每次两步慢指针每次一步,快指针走到表尾慢指针指向中间节点

    • 判断回文
      快慢指针找到中点,慢指针移动过程中同时反转链表,然后从中点至两端一起移动并判断

链表Java实现


public class myLinkedlist {
    public Node head;

    public myLinkedlist() {
        head = new Node(-1);
    }

    /**
     * 将data加到链表尾部
     *
     * @param data
     * @return
     */
    public boolean append(int data) {
        Node iter = head;
        while (iter.next != null) iter = iter.next;
        iter.next = new Node(data);
        return true;
    }

    /**
     * 将value插入到index之后
     *
     * @param index
     * @return
     */
    public boolean insertAfter(int index, int value) {
        Node iter = head;
        while (iter.data != index && iter.next != null) iter = iter.next;
        if (iter.data != index && iter.next == null) {
            System.out.println("链表中无对应节点!");
            return false;
        }

        Node temp = iter.next;
        iter.next = new Node(value);
        iter.next.next = temp;

        return true;
    }

    public boolean delete(int index) {
        Node iter = head;
        while (iter.next != null && iter.next.data != index) iter = iter.next;
        if (iter.data != index && iter.next == null) {
            System.out.println("链表中无对应节点!");
            return false;
        }
        Node temp = iter.next.next;
        iter.next = temp;
        return true;
    }

    /**
     * 反转链表
     */
    public void reverse() {
        Node iter = head.next;

        if (iter.next == null)
            return;

        Node pre = iter;
        Node mid = iter.next;
        Node after = mid.next;
        pre.next = null;

        //after为null时说明mid是最后一个
        while (after != null) {
            //每次将mid指向pre
            mid.next = pre;
            pre = mid;
            mid = after;
            after = after.next;
        }
        mid.next = pre;
        head.next = mid;
    }

    public boolean isPalindrome() {
        if (head.next == null) {
            System.out.println("链表为空!");
            return false;
        }
        //只有两个节点
        if (head.next.next.next == null) {
            int first = head.next.data;
            int second = head.next.next.data;
            if (first == second)
                return true;
            else
                return false;
        }
        Node fast;//快指针
        Node slow;//慢指针
        fast = slow = head.next;
        int fStep;//快指针步数
        int sStep;//慢指针步数
        fStep = sStep = 0;
        while (fast.next != null) {
            fast = fast.next;
            fStep++;
        }
        sStep = fStep / 2;

        //慢指针向前移动,同时将单链表反转
        Node pre, mid, after;
        pre = slow;
        mid = slow.next;
        after = mid.next;

        slow.next = null;

        while (sStep > 0) {
            mid.next = pre;
            pre = mid;
            mid = after;
            after = after.next;
            sStep--;
        }

        Node toStart, toEnd;
        //奇数遍历起点
        if (fStep % 2 == 1) {
            toStart = pre;
            toEnd = mid;
        }
        //偶数遍历起点
        else {
            toStart = pre.next;
            toEnd = mid;
        }

        do {
            if (toStart.data != toEnd.data)
                return false;
            toStart = toStart.next;
            toEnd = toEnd.next;
        } while (toStart != null && toEnd != null);
        return true;
    }

    public String toString() {
        StringBuilder builder = new StringBuilder();
        Node iter = head;
        int size = 0;
        while (iter.next != null) {
            builder.append(iter.next.data + ",");
            size ++;
            iter = iter.next;
        }
        return builder.toString() + "\t(size: " + size + ")";
    }

    public void linkedlistTest(){
        myLinkedlist test = new myLinkedlist();
        test.append(1);
        System.out.println(test.toString());
        test.delete(1);
        System.out.println(test.toString());
        test.append(2);
        System.out.println(test.toString());
        test.insertAfter(1,3);
        System.out.println(test.toString());
        test.delete(2);
        System.out.println(test.toString());
        test.append(4);
        test.append(5);
        test.append(6);
        System.out.println(test.toString());
        test.reverse();
        System.out.println(test.toString());
        test.reverse();
        System.out.println(test.toString());
        //测试是否为回文串
        test.append(1);
        test.append(2);
        test.append(3);
        test.append(2);
        test.append(1);
        System.out.println(test.isPalindrome());
    }


}

class Node {
    int data;
    Node next;

    protected Node(int data) {
        this.data = data;
        this.next = null;
    }
}
posted @ 2020-07-03 16:20  codespoon  阅读(158)  评论(0编辑  收藏  举报