算法 数据结构 链表实现容器 手撸单向链表 单向链表添加修改删除获取大小 链表实现自定义容器 链表数据结构 单向链表手写LinkedList容器 单向哨兵链表 数据结构(四)

1. 链表特点:

                   

2. 时间复杂度:                               

随机访问性能

根据 index 查找,时间复杂度 O(n)

插入或删除性能

  • 起始位置:O(1)

  • 结束位置:如果已知 tail 尾节点是 O(1),不知道 tail 尾节点是 O(n)

  • 中间位置:根据 index 查找时间 + O(1)

3. 单链表实现容器:

package com.nami.algorithm.study.day04;

import java.io.Serializable;
import java.util.Iterator;
import java.util.function.Consumer;

/**
 * 单向链表
 * 非线程安全
 * beyond u self and trust u self.
 *
 * @Author: lbc
 * @Date: 2023-09-01 9:07
 * @email: [email protected]
 * @Description: keep coding
 */
public class SinglyLinkedList<E> implements Serializable, Iterable<E>, Cloneable {

    /**
     * 容器已添加的元素
     */
    private int size;
    /**
     * 头指针
     */
    private Node head;

    /**
     * 向链表添加数据
     *
     * @param element 添加的元素
     */
    public void addFirst(E element) {
        this.head = new Node(element, this.head);
        ++this.size;
    }

    /**
     * 向链表尾部添加数据
     *
     * @param element
     */
    public void addLast(E element) {
        Node last = getLast();
        if (last == null) {
            addFirst(element);
            return;
        }
        last.next = new Node(element, null);
        ++this.size;
    }

    public Node getNode(int index) {
        if (index > size) {
            throw new IndexOutOfBoundsException("元素不存在");
        }

        Node p = this.head;
        for (int i = 0; i != index; i++) {
            p = p.next;
        }

        return p;
    }

    /**
     * 获取容器指定位置的值
     *
     * @param index
     * @return
     */
    public E get(int index) {
        if (index > size) {
            throw new IndexOutOfBoundsException("元素不存在");
        }

        Node node = getNode(index);
        if (null == node) {
            throw new NullPointerException("元素不存在");
        }
        return (E) node.value;
    }

    /**
     * 向指定位置插入节点
     * 写的比较冗余
     * 弃用
     * @param index
     * @param e
     */
    @Deprecated
    public void add0(int index, E e) {
        if (index == 0) {
            addFirst(e);
        }
        if (index > size) {
            throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
        }

        Node p = this.head;
        int i = 0;
        while (true) {
            if (i == index - 1) {
                p.next = new Node(e, p.next);
                this.size++;
                break;
            }
            p = p.next;
            i++;
        }
    }

    /**
     * 向元素指定节点添加值
     *
     * @param index
     * @param e
     */
    public void add(int index, E e) {
        if (index == 0) {
            addFirst(e);
            return;
        }
        if (index > size) {
            throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
        }

        // 获取先前节点
        Node prev = getNode(index - 1);
        if (prev == null) {
            throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
        }
        prev.next = new Node(e, prev.next);
        ++this.size;
    }

    /**
     * 移除容器内第一个元素
     */
    public void removeFirst() {
        if (this.head == null) {
            return;
        }
        this.head = this.head.next;
        --this.size;
    }

    /**
     * 移除容器内指定位置元素
     *
     * @param index
     */
    public void remove(int index) {
        if (index > size) {
            throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
        }
        if (index == 0) {
            removeFirst();
            return;
        }
        Node prev = getNode(index - 1);
        if (prev == null) {
            throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
        }

        // 获取index元素的后一个节点,也行。但是需要多找一次
        Node node = getNode(index);
        if (node == null) {
            throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
        }
        prev.next = node.next;
        --this.size;
    }

    /**
     * 获取容器大小
     *
     * @return
     */
    public int size() {
        return this.size;
    }

    /**
     * addLast 方法使用
     * 获取容器最后节点Node信息
     *
     * @return
     */
    private Node getLast() {
        if (this.head == null) {
            return null;
        }
        Node node;
        for (node = this.head; node.next != null; node = node.next) {
        }
        return node;
    }

    /**
     * 迭代器遍历
     *
     * @return
     */
    @Override
    public Iterator iterator() {
        return new NodeIterator();
    }

    /**
     * 匿名内部类
     * 内部类使用到了外部类的成员变量时,不能使用static修饰
     */
    private class NodeIterator implements Iterator {

        Node node = head;
        private int nextIndex;

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

        @Override
        public Object next() {
            Object value = node.value;
            node = node.next;
            ++this.nextIndex;
            return value;
        }
    }

    /**
     * while实现
     *
     * @param consumer
     */
    public void forEach(Consumer consumer) {
        Node firstNode = this.head;
        while (firstNode != null) {
            consumer.accept(firstNode.value);
            firstNode = firstNode.next;
        }
    }

    /**
     * for循环实现
     *
     * @param consumer
     */
    public void forEach2(Consumer consumer) {
        for (Node firstNode = this.head; firstNode != null; firstNode = firstNode.next) {
            consumer.accept(firstNode.value);
        }
    }

    /**
     * Node类型 节点对象
     * 二者为组合关系,所以 由外部类变为内部类,对外隐藏实现细节
     */
    private static class Node<E> {

        /**
         * 值
         */
        private E value;

        /**
         * 下一个节点
         */
        private Node<E> next;


        public Node(E value, Node next) {
            this.value = value;
            this.next = next;
        }
    }

}

4. 哨兵链表:

                    一个不参与数据存储的特殊 Node 作为哨兵,它一般被称为哨兵或哑元,拥有哨兵节点的链表称为带头链表

               注:大白话就是容器类的this.head 赋值了一个无意义的Node节点,保持head非空

package com.nami.algorithm.study.day04;

import java.io.Serializable;
import java.util.Iterator;
import java.util.function.Consumer;

/**
 * 单向哨兵链表
 * 非线程安全
 * beyond u self and trust u self.
 *
 * @Author: lbc
 * @Date: 2023-09-01 9:07
 * @email: [email protected]
 * @Description: keep coding
 */
public class SentinelLinkedList<E> implements Serializable, Iterable<E>, Cloneable {

    /**
     * 容器已添加的元素
     */
    private int size = 1;
    /**
     * 头指针
     * 哨兵节点: head 赋值一个头节点
     */
    private Node head = new Node("sentinelNode", null);

    /**
     * 向链表添加数据
     *
     * @param element 添加的元素
     */
    public void addFirst(E element) {
//        this.head.next = new Node(element, this.head.next);
//        ++this.size;
        add(0, element);
    }

    /**
     * 向链表尾部添加数据
     *
     * @param element
     */
    public void addLast(E element) {
        Node last = getLast();
        last.next = new Node(element, null);
        ++this.size;
    }

    private Node getNode(int index) {
        Node p = this.head;
        for (int i = -1; i != index; i++) {
            p = p.next;
        }

        return p;
    }

    /**
     * 获取容器指定位置的值
     *
     * @param index
     * @return
     */
    public E get(int index) {
        if (index > size) {
            throw new IndexOutOfBoundsException("元素不存在");
        }

        Node node = getNode(index);
        return (E) node.value;
    }


    /**
     * 向元素指定节点添加值
     *
     * @param index
     * @param e
     */
    public void add(int index, E e) {
        if (index > size) {
            throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
        }

        // 获取先前节点
        Node prev = getNode(index - 1);
        if (prev == null) {
            throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
        }
        prev.next = new Node(e, prev.next);
        ++this.size;
    }

    /**
     * 移除容器内第一个元素
     */
    public void removeFirst() {
       remove(0);
    }

    /**
     * 移除容器内指定位置元素
     *
     * @param index
     */
    public void remove(int index) {
        if (index > size-1) {
            throw new IndexOutOfBoundsException(String.format("index [%d] 不合法%n", index));
        }

        // index =0 返回的是哨兵
        Node prev = getNode(index - 1);

        prev.next = prev.next.next;
        --this.size;
    }

    /**
     * 获取容器大小
     *
     * @return
     */
    public int size() {
        return this.size - 1;
    }

    /**
     * addLast 方法使用
     * 获取容器最后节点Node信息
     *
     * @return
     */
    private Node getLast() {
        Node node;
        for (node = this.head; node.next != null; node = node.next) {
        }
        return node;
    }

    /**
     * 迭代器遍历
     *
     * @return
     */
    @Override
    public Iterator iterator() {
        return new NodeIterator();
    }

    /**
     * 匿名内部类
     * 内部类使用到了外部类的成员变量时,不能使用static修饰
     */
    private class NodeIterator implements Iterator {

        Node node = head.next;
        private int nextIndex;

        @Override
        public boolean hasNext() {
            return nextIndex < SentinelLinkedList.this.size-1;
        }

        @Override
        public Object next() {
            Object value = node.value;
            node = node.next;
            ++this.nextIndex;
            return value;
        }
    }

    /**
     * while实现
     *
     * @param consumer
     */
    public void forEach(Consumer consumer) {
        Node firstNode = this.head.next;
        while (firstNode != null) {
            consumer.accept(firstNode.value);
            firstNode = firstNode.next;
        }
    }

    /**
     * for循环实现
     *
     * @param consumer
     */
    public void forEach2(Consumer consumer) {
        for (Node firstNode = this.head.next; firstNode != null; firstNode = firstNode.next) {
            consumer.accept(firstNode.value);
        }
    }

    /**
     * Node类型 节点对象
     * 二者为组合关系,所以 由外部类变为内部类,对外隐藏实现细节
     */
    private static class Node<E> {

        /**
         * 值
         */
        private E value;

        /**
         * 下一个节点
         */
        private Node<E> next;


        public Node(E value, Node next) {
            this.value = value;
            this.next = next;
        }
    }

}

5. 如测试出现问题,请联系我更正

猜你喜欢

转载自blog.csdn.net/qq_33919114/article/details/132623105