java实现链表

链表是非常常用的数据结构,常见的链表有单链表、双向链表和双向循环链表。

一个比一个复杂,但实际运用中,越往后越好用。

下面我们使用java分别实现:

一、单链表

单链表特点:
1.单链表的head结点指向第一个数据节点,存数据,没有tail结点
2.单链表的每个节点都有next指针指向下一个节点,但是没有指针指向前驱节点

/**
 * @Author : wangbin
 * @Date : 2/7/2022 11:17 AM
 * @Description: 单链表特点:
 * 1.单链表的head结点指向第一个数据节点,存数据,没有tail结点
 * 2.单链表的每个节点都有next指针指向下一个节点,但是没有指针指向前驱节点
 */
public class SinglyLinkedList<E> implements LinkedList<E> {
    private int size;
    private Node<E> head;

    public SinglyLinkedList() {
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean add(E e) {
        if (head == null) {
            head = new Node<>(e, null);
            size++;
            return true;
        }
        Node<E> cur = head;
        while (cur.next != null) {
            cur = cur.next;
        }
        cur.next = new Node<>(e, null);
        size++;
        return true;
    }

    @Override
    public boolean remove(E e) {
        Node<E> cur = head;
        Node<E> curPrev = head;
        while (!cur.item.equals(e) && cur.next != null) {
            curPrev = cur;
            cur = cur.next;
        }
        if (cur.next == null) {
            return false;
        }
        curPrev.next = cur.next;
        size--;
        return true;
    }

    @Override
    public E get(int index) {
        Node<E> curNode = getNode(index);
        return curNode.item;
    }

    private Node<E> getNode(int index) {
        checkIndex(index);
        Node<E> curNode = head;
        int curIdx = 0;
        while (curNode.next != null && curIdx != index) {
            curIdx++;
            curNode = curNode.next;
        }
        return curNode;
    }

    private Node<E> getPrevNode(int index) {
        checkIndex(index);
        Node<E> curNode = head;
        int curIdx = 0;
        while (curIdx != index - 1) {
            curIdx++;
            curNode = curNode.next;
        }
        return curNode;
    }

    @Override
    public E set(int index, E element) {
        checkIndex(index);
        Node<E> node = getNode(index);
        E oldElement = node.item;
        node.item = element;
        return oldElement;
    }

    @Override
    public void add(int index, E element) {
        if (!isPositionIndex(index)) {
            throw new IndexOutOfBoundsException();
        }
        Node<E> prevNode = getPrevNode(index);
        Node<E> curNode = prevNode.next;
        prevNode.next = new Node<>(element, curNode);
        size++;
    }

    private boolean isPositionIndex(int index) {
        return index >= 0 && index <= size;
    }

    @Override
    public E remove(int index) {
        if (index == 0) {
            E item = head.item;
            head = head.next;
            size--;
            return item;
        }
        Node<E> prevNode = getPrevNode(index);
        Node<E> curNode = prevNode.next;
        prevNode.next = curNode.next;
        size--;
        return curNode.item;
    }

    @Override
    public int indexOf(E o) {
        int curIndex = 0;
        for (Node<E> curNode = head; curIndex < size; curNode = curNode.next) {
            if (curNode.item.equals(o)) {
                return curIndex;
            }
            curIndex++;
        }
        return -1;
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            int nextIndex = 0;

            @Override
            public boolean hasNext() {
                return nextIndex < size;
            }

            @Override
            public E next() {
                return get(nextIndex++);
            }
        };
    }

    private void checkIndex(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException();
        }
    }

    private static class Node<E> {
        E item;
        Node<E> next;

        public Node(E item, Node<E> next) {
            this.item = item;
            this.next = next;
        }
    }
}

二、双向链表

双向链表的特点:
1.双向链表既有head节点,也有tail节点;
2.head节点指向第一个节点,head.prev==null;
3.tail节点指向最后一个节点,tail.next==null;
4.相比双向循环链表,双向链表没有使用哨兵,所以需要处理复杂的边界条件
/**
 * @Author : wangbin
 * @Date : 2/7/2022 11:18 AM
 * @Description: 双向链表的特点:
 * 1.双向链表既有head节点,也有tail节点;
 * 2.head节点指向第一个节点,head.prev==null;
 * 3.tail节点指向最后一个节点,tail.next==null;
 * 相比双向循环链表,双向链表没有使用哨兵,所以需要处理复杂的边界条件
 */
public class DoublyLinkedList<E> implements LinkedList<E> {
    private int size = 0;
    private Node<E> head;
    private Node<E> tail;

    public DoublyLinkedList() {
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean add(E e) {
        if (head == null) {
            Node<E> newNode = new Node<>(e, null, null);
            this.head = newNode;
            this.tail = newNode;
            size++;
        } else {
            Node<E> curNode = head;
            while (curNode.next != null) {
                curNode = curNode.next;
            }
            Node<E> newNode = new Node<>(e, null, curNode);
            curNode.next = newNode;
            this.tail = newNode;
            size++;
        }
        return true;
    }

    @Override
    public boolean remove(E e) {
        for (Node<E> curNode = head; curNode != null; curNode = curNode.next) {
            if (curNode.item.equals(e)) {
                Node<E> prev = curNode.prev;
                Node<E> next = curNode.next;
                if (prev == null) {
                    head = next;
                } else {
                    prev.next = next;
                }
                if (next == null) {
                    tail = prev;
                } else {
                    next.prev = prev;
                }
                size--;
                return true;
            }
        }
        return false;
    }

    @Override
    public E get(int index) {
        checkIndex(index);
        if (index < size / 2) {
            Node<E> curNode = head;
            for (int curIndex = 0; curIndex < index; curIndex++) {
                curNode = curNode.next;
            }
            return curNode.item;
        } else {
            Node<E> curNode = tail;
            for (int curIndex = size - 1; curIndex > index; curIndex--) {
                curNode = curNode.prev;
            }
            return curNode.item;
        }
    }

    private void checkIndex(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException();
        }
    }

    @Override
    public E set(int index, E element) {
        checkIndex(index);
        Node<E> curNode = getNode(index);
        E item = curNode.item;
        curNode.item = element;
        return item;
    }

    private Node<E> getNode(int index) {
        checkIndex(index);
        if (index < size / 2) {
            Node<E> curNode = head;
            for (int curIndex = 0; curIndex < index; curIndex++) {
                curNode = curNode.next;
            }
            return curNode;
        } else {
            Node<E> curNode = tail;
            for (int curIndex = size - 1; curIndex > index; curIndex--) {
                curNode = curNode.prev;
            }
            return curNode;
        }
    }

    @Override
    public void add(int index, E element) {
        checkIndex(index);
        Node<E> oldNode = getNode(index);
        Node<E> prev = oldNode.prev;
        Node<E> newNode = new Node<>(element, null, null);
        if (prev == null) {
            head = newNode;
        } else {
            prev.setNext(newNode);
            newNode.setPrev(prev);
        }
        newNode.setNext(oldNode);
        oldNode.setPrev(newNode);
        size++;

    }

    @Override
    public E remove(int index) {
        checkIndex(index);
        Node<E> node = getNode(index);
        Node<E> next = node.next;//next和prev对象都有可能为null,所有下面需要进行判断
        Node<E> prev = node.prev;
        E item = node.item;

        if (prev == null) {
            head = next;
        } else {
            prev.next = next;
        }
        if (next == null) {
            tail = prev;
        } else {
            next.prev = prev;
        }
        size--;
        return item;
    }

    @Override
    public int indexOf(E o) {
        int curIndex = 0;
        for (Node<E> curNode = head; curNode.next != null; curNode = curNode.next) {
            if (curNode.item.equals(o)) {
                return curIndex;
            }
            curIndex++;
        }
        return -1;
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            private int nextIndex;

            @Override
            public boolean hasNext() {
                return nextIndex < size;
            }

            @Override
            public E next() {
                return get(nextIndex++);
            }
        };
    }

    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        public Node(E item, Node<E> next, Node<E> prev) {
            this.item = item;
            this.next = next;
            this.prev = prev;
        }

        public void setNext(Node<E> next) {
            this.next = next;
        }

        public void setPrev(Node<E> prev) {
            this.prev = prev;
        }
    }
}

三、双向循环链表

双向循环链表特点:
1.有head节点,无tail节点
2.与单链表和双向链表不同,为简化操作,双向循环链表使用一个空哨兵节点作为head节点
3.head节点的next指针指向第一个节点,head节点的prev指针指向最后一个节点;
4.最后一个节点的next指针指向head节点,
5.判断是否为空。head==head.next
/**
 * @Author : wangbin
 * @Date : 2/7/2022 11:18 AM
 * @Description: 双向循环链表特点:
 * 1.有head节点,无tail节点
 * 2.与单链表和双向链表不同,为简化操作,双向循环链表使用一个空哨兵节点作为head节点
 * 3.head节点的next指针指向第一个节点,head节点的prev指针指向最后一个节点;
 * 4.最后一个节点的next指针指向head节点,
 * 5.判断是否为空。head==head.next
 */
public class CircularLinkedList<E> implements LinkedList<E> {
    private int size = 0;
    private Node<E> head;

    public CircularLinkedList() {
        this.head = new Node<>(null, null, null);
        this.head.prev = this.head;
        this.head.next = this.head;
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean isEmpty() {
        return size == 0;
    }

    @Override
    public boolean add(E e) {
        if (head.next == head) {
            Node<E> newNode = new Node<>(e, null, null);
            this.head.next = newNode;
            this.head.prev = newNode;
            newNode.setNext(head);
            newNode.setPrev(head);
            size++;
        } else {
            Node<E> curNode = head;
            while (curNode.next != head) {
                curNode = curNode.next;
            }
            Node<E> newNode = new Node<>(e, head, curNode);
            curNode.next = newNode;
            head.prev = newNode;
            size++;
        }
        return true;
    }

    @Override
    public boolean remove(E e) {
        for (Node<E> curNode = head.next; curNode.item != null; curNode = curNode.next) {
            if (curNode.item.equals(e)) {
                Node<E> prev = curNode.prev;
                Node<E> next = curNode.next;
                prev.next = next;
                next.prev = prev;
                return true;
            }
        }
        return false;
    }

    @Override
    public E get(int index) {
        checkIndex(index);
        if (index < size / 2) {
            Node<E> curNode = head.next;
            for (int curIndex = 0; curIndex < index; curIndex++) {
                curNode = curNode.next;
            }
            return curNode.item;
        } else {
            Node<E> curNode = head.prev;
            for (int curIndex = size - 1; curIndex > index; curIndex--) {
                curNode = curNode.prev;
            }
            return curNode.item;
        }
    }

    private void checkIndex(int index) {
        if (index < 0 || index >= size) {
            throw new IndexOutOfBoundsException();
        }
    }

    @Override
    public E set(int index, E element) {
        checkIndex(index);
        Node<E> curNode = getNode(index);
        E item = curNode.item;
        curNode.item = element;
        return item;
    }

    private Node<E> getNode(int index) {
        checkIndex(index);
        if (index < size / 2) {
            Node<E> curNode = head.next;
            for (int curIndex = 0; curIndex < index; curIndex++) {
                curNode = curNode.next;
            }
            return curNode;
        } else {
            Node<E> curNode = head.prev;
            for (int curIndex = size - 1; curIndex > index; curIndex--) {
                curNode = curNode.prev;
            }
            return curNode;
        }
    }

    @Override
    public void add(int index, E element) {
        checkIndex(index);
        Node<E> oldNode = getNode(index);
        Node<E> prev = oldNode.prev;
        Node<E> newNode = new Node<>(element, oldNode, prev);
        prev.setNext(newNode);
        oldNode.setPrev(newNode);
        size++;
    }

    @Override
    public E remove(int index) {
        checkIndex(index);
        Node<E> node = getNode(index);
        Node<E> next = node.next;
        Node<E> prev = node.prev;
        E item = node.item;
        prev.next = next;
        next.prev = prev;

        size--;
        return item;
    }

    @Override
    public int indexOf(E o) {
        int curIndex = 0;
        for (Node<E> curNode = head.next; curNode.next != head; curNode = curNode.next) {
            if (curNode.item.equals(o)) {
                return curIndex;
            }
            curIndex++;
        }
        return -1;
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            private Node<E> curNode = head.next;

            @Override
            public boolean hasNext() {
                return curNode.item != null;
            }

            @Override
            public E next() {
                E item = curNode.item;
                curNode = curNode.next;
                return item;
            }
        };
    }

    private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        public Node(E item, Node<E> next, Node<E> prev) {
            this.item = item;
            this.next = next;
            this.prev = prev;
        }

        public void setNext(Node<E> next) {
            this.next = next;
        }

        public void setPrev(Node<E> prev) {
            this.prev = prev;
        }
    }
}

 

 
上一篇:21. 合并两个有序链表


下一篇:234.回文链表。双百0ms