利用Java手写LinkedList

本文详细介绍了Java中LinkedList的实现原理,包括链表节点的定义、节点插入与删除的操作,以及如何通过下标获取节点。文章还讨论了LinkedList与ArrayList在内存消耗和效率上的差异,并提出了虚拟头节点的概念以简化操作。此外,还介绍了双向链表的结构及其优势,以及如何在LinkedList中实现双向链表的添加、删除等操作。
摘要由CSDN通过智能技术生成

利用Java手写LinkedList

和ArrayList不同的是,LinkedList是采用链表实现的,链表的特点就是每个节点存储的是value和下个节点的地址,所以不存在类似ArrayList的扩容问题,添加节点只需要一个新的节点对象然后链表末尾指向它就可以了。参考Java官方的LinkedList实现:java.util.LinkedList。不过Java官方使用双向链表实现。

链表和节点

链表有n多个链表节点组成,每个节点存储的都是元素+下个节点的内存地址。如何得到节点中存储的元素实际上是通过从链表的头一个节点开始迭代,然后得到当前节点。

私有属性

动态数组大小size,以及用于存放该动态数组的头节点first

注意:为什么要有头节点?

是因为链表元素的获取是利用迭代来不断得到next元素的,也就是说你迭代到了中间某一元素后,你就没有办法回溯了,你这个链表就暂时停留在这里了(因为该元素前的所以链表的内存地址已丢失),所以就需要保存一个头节点的内存地址,以确保每次都能够从头开始依次访问链表中的元素

public class LinkedList<E> {
   

    /**
     * 动态数组大小
     */
    private int size;

    /**
     * 头节点
     */
    private Node<E> first;
    
}	

节点类

通过静态内部类的方式来声明链表中的节点Node类

public class LinkedList<E> {
   

    /**
     * 动态数组大小
     */
    private int size;

    /**
     * 头节点
     */
    private Node<E> first;
    
    /**
     * 静态内部类
     */
    private static class Node<E>{
   

        /**
         * 该节点存储的元素
         */
        private E element;

        /**
         * 该节点所指向的下一个节点
         */
        private Node<E> next;

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

Node类主要包含节点存储的具体元素、下个节点的内存地址,以及节点的构造方法(指定元素,以及指定下一个节点)。

通过下标获得具体node节点

链表与数组不同的是,它是利用迭代来定位到具体某个节点的,再很多add、remove的场景中我们可能会经常需要定位到某个具体的节点(因为需要获取该节点前后的节点)

	/**
     * 获取具体某一下标的节点
     * @param index      下标
     * @return           该下标的node节点
     */
    private Node<E> node(int index){
   
        Node<E> node = first;
        for (int i = 0; i < index; i++) {
   
            node = node.next;
        }
        return node;
    }

可以看到上述方法就是通过for循环的方式,node.next不断迭代获得node节点,最后获取到位于index位置的node元素。

构造方法

LinkedList不同于ArrayList,因为它不需要初始化数组容量,所以它没有构造函数。

基本方法

和ArrayList类似,LinkedList具有以下基本方法

public class LinkedList<E> {
   


    /**
     * 动态数组大小
     * @return      动态数组大小
     */
    public int size(){
   }

    /**
     * 动态数组是否为空
     * @return      动态数组是否为空
     */
    public Boolean isEmpty(){
   }

    /**
     * 添加元素
     * @param element   元素
     */
    public void add(E element){
   }

    /**
     *
     *  0 1 2 3 4 5 6 7 8 9
     *  1 2 3   4 5 6 7 8
     * 向指定位置添加元素
     * @param index     位置
     * @param element   元素
     */
    public void add(int index,E element){
   }

    /**
     *
     *  0 1 2 3 4 5 6 7 8 9
     *  a b c 1 d e f g h
     * 移除指定位置的元素
     * @param index     位置
     */
    public void remove(int index){
   }

    /**
     * 删除指定元素
     * @param element   元素
     */
    public void remove(E element){
   }

    /**
     * 清空动态数组中的元素
     */
    public void clear(){
   }

    /**
     * 修改指定位置的元素
     * @param index      位置
     * @param element    元素
     */
    public void set(int index,E element){
   }

    /**
     * 获得指定位置的元素
     * @param index     位置
     * @return          元素
     */
    public E get(int index){
   }

    /**
     * 判断数组是否包含该元素
     * @param element    元素
     * @return           true包含,false不包含
     */
    public Boolean contains(E element){
   }

    /**
     * 该元素第一次出现的下标
     * @param element    元素
     * @return           下标
     */
    public int indexOf(E element){
   }

    @Override
    public String toString() {
   }
}

size()

返回动态数组的大小

public int size() {
    
    return size; 
}

isEmpty()

返回该动态数组是否为空,即判断size是否为0

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

toString()

打印该链表,依旧是从头节点开始迭代然后打印

	@Override
    public String toString() {
   
        StringBuilder string = new StringBuilder();
        string.append("LinkedList{");
        string.append("size=" + size + ", elements=[");
        Node<E> node = first;
        for (int i = 0; i < size; i++) {
   
            string.append(node.element);
            node = node.next;
            if (i!=size-1){
   
                string.append(", ");
            }
        }
        string.append("]");
        string.append("}");
        return string.toString();
    }

indexOf()和contains()

indexOf(E element)就是返回该元素所在的位置下标,如果不存在则返回-1。同样地,利用从first开始迭代node,如果节点的元素等于传入的元素则直接返回该下标。

    @Override
    public int indexOf(E element) {
   
        Node<E> node = first;
        for (int i = 0; i < size; i++) {
   
            if ( (node.element).equals(element) ) return i;
            node = node.next;
        }
        return -1;
    }

contains(E element)就是判断链表是否包含该元素,如果包含则返回true。

	@Override
    public boolean contains(E element) {
   
        return indexOf(element) >= 0;
    }

get()

通过节点下标获得该节点

	@Override
    public E 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值