带头结点的链表操作题

主体

/**
* 带头结点的单链表
*
* @param <T>
*/
public class LinkWithHead<T> {
    private Node<T> head;

    private int size;

    private class Node<T> {
        public Node<T> next;
        public T data;

        public Node(T data, Node<T> next) {
            this.next = next;
            this.data = data;
        }
    }

    /**
     * 构造函数
     * 这里是关键,区别了有头结点和无头结点的链表
     * 这里的head≠null,但是head的value是null,head的next结点是null
     */
    public LinkWithHead() {
        this.head = new Node<T>(null, null);
        this.size = 0;
    }
}
复制代码

判断链表是否为空

	/**
     * 判断链表是否为空
     *
     * @return
     */
    private boolean isEmpty() {
        return head.next == null;
    }
复制代码

添加一个结点

    /**
     * 添加一个结点
     *
     * @param node
     */
    private void insert(Node<T> node) {
        Node<T> temp = head;
        while (temp.next != null) {
            temp = temp.next;
        }
        temp.next = node;
        size++;
    }
复制代码

在指定位置添加一个结点

 /**
     * 指定位置添加一个结点
     *
     * @param node
     * @param index
     */
    private void insert(Node<T> node, int index) {
        if (index > size + 1 || size < 0) {
            throw new ArrayIndexOutOfBoundsException();
        }
        if (head == null && index == 0)
            head.next = node;
        else {
            int currentIndex = 0;
            Node<T> temp = head;
            while (currentIndex < index) {
                temp = temp.next;
                currentIndex++;
            }
            node.next = temp.next;
            temp.next = node;
            size++;
        }
    }
复制代码

删除一个结点(循环法)

/**
     * 移除一个结点(循环)
     *
     * @param node
     */
    private void remove(Node<T> node) {
        if (head == node) {
            head = null;
            size = 0;
        } else {
            Node<T> temp = head;
            while (temp.next != node) {
                temp = temp.next;
            }
            temp.next = temp.next.next;
            size--;
        }
    }
复制代码

删除指定位置的结点

/**
     * 删除指定索引的结点
     *
     * @param index
     */
    private void removeByIndex(int index) {
        if (index < 1 || index > size - 1) {
            throw new ArrayIndexOutOfBoundsException();
        }
        int current = 0;
        Node<T> temp = head;
        while (current < index) {
            temp = temp.next;
            current++;
        }
        temp.next = temp.next.next;
    }
复制代码

删除结点时间复杂度O(1)

 /**
     * 删除结点2
     * 此处需要确认
     *
     * @param node
     */
    private void remove2(Node<T> node) {
        if (head == node) {
            head = null;
            size = 0;
        } else {
            Node<T> temp = node.next;
            node.data = temp.data;
            node.next = temp.next;
            size--;
        }
    }
复制代码

用栈的方式删除指定位置结点

 /**
     * 用栈的方式删除指定索引的结点
     *
     * @param index
     */
    private void removeByStack(int index) {
        Stack<Node<T>> stack = new Stack<>();
        stack.push(head);
        int current = 0;
        while (head != null) {
            head = head.next;
            current++;
            if (current != index)
                stack.push(head);
        }
        while (!stack.isEmpty()) {
            stack.peek().next = head;
            head = stack.pop();
        }
    }
复制代码

删除链表中的重复数据

 /**
     * 删除重复数据
     */
    private void removeDuplication() {
        HashSet<T> set = new HashSet<>();
        Node<T> previous = head;
        Node<T> current = head.next;
        set.add(head.data);
        while (current != null) {
            if (!set.contains(previous.data)) {
                set.add(previous.data);
                previous = current;
                current = current.next;
            } else {
                previous.next = current.next;
                current = current.next;
            }
        }
    }

复制代码

删除链表中倒数第K个结点


 /**
     * 移除倒数第K个结点
     *
     * @param k
     */
    private void removeLastKthNode(int k) {
        if (k < 0 || k > size)
            throw new ArrayIndexOutOfBoundsException();
        Node<T> temp = head;
        for (int i = 0; i < k; i++) {
            temp = temp.next;
        }
        Node<T> previous = head;
        while (temp.next != null) {
            temp = temp.next;
            previous = previous.next;
        }
        previous.next = previous.next.next;
    }
复制代码

反转链表

    /**
     * 反转链表递归
     */
    private Node<T> reverse(Node<T> node) {
        if (node == null || node.next == null)
            return node;
        Node<T> previous = reverse(node.next);
        node.next.next = node;
        node.next = null;
        return previous;
    }

    /**
     * 链表反转非递归
     *
     * @param head
     * @return
     */
    private Node<T> reverse2(Node<T> head) {
        Node<T> previous = null;
        while (head != null) {
            Node<T> temp = head.next;
            head.next = previous;
            previous = head;
            head = temp;
        }
        return previous;
    }

    private void reverse3(Node<T> head) {
        Stack<Node<T>> stack = new Stack<>();
        while (head != null) {
            stack.push(head);
            head = head.next;
        }
        Node<T> first = null;
        while (!stack.isEmpty()) {
            Node<T> temp = stack.pop();
            first.next = temp;
            first = temp;
        }
    }
复制代码

查找一个未知长度链表的中间项

 /**
     * 查找一个未知长度的链表的中间结点
     *
     * @return
     */
    private Node<T> findMiddle() {
        Node<T> p = head;
        Node<T> q = head;
        while (q != null && q.next != null && q.next.next != null) {
            p = p.next;
            q = q.next.next;
        }
        return p;
    }
复制代码

判断两个链表是否相交

 /**
     * 判断两个链表是否相交
     * 参考http://blog.csdn.net/zengzhen_csdn/article/details/49761869
     * 此方法时间复杂度为O(m+n)
     *
     * @param h1
     * @param h2
     * @return
     */
    private boolean isIntersect(Node<T> h1, Node<T> h2) {
        if (h1 == null || h2 == null)
            return false;
        while (h1 != null) {
            h1 = h1.next;
        }
        while (h2 != null) {
            h2 = h2.next;
        }
        return h1 == h2;
    }
复制代码

判断链表是否有环,有环的话找出环的入口

private boolean isLoop() {
        Node<T> fast = head;
        Node<T> slow = head;
        while (slow.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast)
                return true;
        }
        return false;
    }


    private Node<T> findLoopNode() {
        Node<T> fast = head;
        Node<T> slow = head;
        while (slow.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            if (slow == fast)
                break;
        }
        slow = head;
        while (slow != fast) {
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }
复制代码

转载于:https://juejin.im/post/5a65bb7a518825732d7fb945

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值