linkedList方法的源码理解1

关于linkedList的一些理解,欢迎各位大佬指错

import util.Iterable;
import util.Iterator;
import util.List;

import java.util.NoSuchElementException;

public class LinkedList<T> implements List<T> {

    @Override
    public Iterable<T> iterator() {
        return null;
    }

    /**
     * 定义了内部类,用来表示链表中节点的是四种情况
     *
     * @param <t>
     */
    private class Node<t> {
        //链表单个节点的三个属性
        Node<T> prve;   //节点的头(头指针)
        T t;    //节点的值
        Node<T> next;   //节点的尾(尾指针)

        /**
         * 全参构造,同时也代表了了中间节点
         * 特点是:头指针指向不为空,有值(可以为null),尾指针指向不为空
         *
         * @param prve //中间节点的头
         * @param t    //中间节点的值
         * @param next //中间节点的尾
         */
        public Node(Node<T> prve, T t, Node<T> next) {
            this.prve = prve;
            this.t = t;
            this.next = next;
        }

        /**
         * 代表尾节点
         * 特点是:头指针指向不为空,有值(可以为null),尾指针指向为空
         *
         * @param prve //尾节点的头
         * @param t    //尾节点的值
         */
        public Node(Node<T> prve, T t) {
            this(prve, t, null);
        }

        /**
         * 代表了这个链表只有一个节点
         * 特点是:头指针指向为空,有值(可以为null),尾指针指向为空
         *
         * @param t //节点的值
         */
        public Node(T t) {
            this.t = t;
        }

        /**
         * 代表头节点
         * 特点是:头指针指向为空,有值(可以为null),尾指针指向不为空
         *
         * @param t    //头节点的值
         * @param next 头节点的尾
         */
        public Node(T t, Node<T> next) {
            this(null, t, next);
        }

    }

    private int size;   //表示链表中节点(元素)的个数
    private Node<T> root;   //表示链表的头节点
    private Node<T> curr;   //表示链表的尾节点

    /**
     * 定义了一个方法,这个方法是用来寻找对应下标在链表中对应的值
     *
     * @param index //所需要的下标
     * @return //返回值为 这个下标对应的值
     */
    Node<T> node(int index) {
        /**
         * 将链表一分为二,当index的值小于链表数量的一半时执行 if
         * 大于链表数量的一半时执行else
         */
        if (index < (size >> 1)) {
            Node<T> x = root;   //声明一个链表节点x,并将x的赋值为root
            //循环遍历,直到遍历到下标为index-1
            for (int i = 0; i < index; i++) {
                x = x.next;//每次循环将x的值变为当前节点next(尾指针)所指向的值(就是下一个节点的值)
            }
            return x;//返回index下标对应的值
        } else {
            Node<T> x = curr;//声明一个链表节点x,并将x的赋值为curr
            //循环遍历,直到遍历到下标为index+1
            for (int i = size - 1; i > index; i--) {
                x = x.prve;//每次循环将x的值变为当前节点prve(头指针)所指向的值(就是上一个节点的值)
            }
            return x;//返回index下标对应的值
        }
    }


    @Override
    public boolean add(T t) {
        /**
         * 当size的值为0时执行 if
         * 部位0时执行else
         */
        if (size == 0) {
            /**
             * 当为0时,代表链表里一个元素都没有
             * 所以头元素就等于这个新增的元素
             * 尾元素也等于这个新增的元素
             * 同时这个节点的头指针和尾指针也没有需要指向的内容
             */
            root = new Node<>(t);
            curr = root;
        } else {
            /**
             * 不为0时,我们需要把这个节点加到末尾
             * 调用尾节点方法,声明一个节点temp
             * 同时这个尾节点的头指针指向的是原来链表的尾节点
             * 所以,头指针的值是curr,这个节点的值是t
             */
            Node<T> temp = new Node<>(curr, t);
            curr.next = temp;//原来链表的尾节点的尾指针应当指向新增的节点,所以将temp赋给curr.next
            curr = temp;    //执行完上面的操作之后,现在链表的尾节点应当变成新增的节点。所以把curr的值变为temp
        }
        size++;//每执行一次增加操作,size++
        return true;
    }

    @Override
    public void add(int index, T t) {//在指定下标添加元素
        /**
         * 先判定下标是狗越界,越界就抛异常
         */
        if (index < 0 || index >= size) {
            throw new ArrayIndexOutOfBoundsException("index out of bounds:" + index);
        }
        //第一中情况,指定下标是0
        if (index == 0) {
            addFirst(t);//直接调用在头部增加函数的方法
        } else if (index == size-1) {//第二中情况,指定下标是尾
            add(t);//直接调用上面的方法(上面方法就是在末尾添加元素)
        } else {//第三种情况,在中间添加元素
            //声明一个节点x,并调用node方法,将x的附值为需要下标在原链表对应的值
            Node<T> x = node(index);
            /**
             * 声明一个节点temp,并赋值为需要添加的元素
             * 同时头指针对应的值为x的头指针所指向的节点(元素)(原链表对应下标的前一个节点)
             * 值为t
             * 尾指针指向的值为x
             */
            Node<T> temp = new Node<>(x.prve, t, x);
            x.prve.next = temp;//在插入之后,原链表对应下标的前一个节点的尾指针应当指向新增的节点
            x.prve = temp;//在插入之后,原链表对应下标的头指针应当指向新增的节点
        }
        size++;//每执行一次增加操作,size++
    }

    @Override
    public boolean addAll(T[] arr) {
        if (null == arr) {//先判定所加集合 是否为空。为空加了没变化
            System.out.println("所加集合为空");
            return false;
        }
        //直接用循环(或者迭代器)依次重复add方法加节点的过程,直到所有元素都被加到末尾
        for (T t : arr) {
            add(t);
            size++;//每执行一次增加操作,size++
        }
        return true;
    }

    @Override
    public boolean addAll(int index, T[] arr) {
        /**
         * 先判定下标是狗越界,越界就抛异常
         */
        if (index < 0 || index >= size) {
            throw new ArrayIndexOutOfBoundsException("index out of bounds:" + index);
        }
        if (null == arr) {//先判定所加集合 是否为空。
            add(index, (T) arr);//为null也可以加,所以调用一次在指定位置加的方法
        }
        //直接用循环(或者迭代器)依次重复add(在指定位置加)方法加节点的过程,直到所有元素都被加到末尾
        for (T t : arr) {
            add(index, t);
            size++;//每执行一次增加操作,size++
        }
        return true;
    }

    @Override
    public void addFirst(T t) {//在头部增加
        if (size == 0) {
            /**
             * 当为0时,代表链表里一个元素都没有
             * 所以头元素就等于这个新增的元素
             * 尾元素也等于这个新增的元素
             * 同时这个节点的头指针和尾指针也没有需要指向的内容
             */
            root = new Node<>(t);
            curr = root;
        } else {
            /**
             * 不为0时,我们需要把这个节点加到头部
             * 调用头节点方法,声明一个节点temp
             * 同时这个头节点的头指针指向的是原来链表的头节点
             * 所以,这个节点尾指针的值是root,这个节点的值是t
             */
            Node<T> temp = new Node<>(t, root);
            root.prve = temp;//原来链表的头节点的头指针应当指向新增的节点,所以将temp赋给root.prve
            root = temp;//执行完上面的操作之后,现在链表的头节点应当变成新增的节点。所以把root的值变为temp
        }
        size++;//每执行一次增加操作,size++
    }

    @Override
    public void addLast(T t) {//在末尾加一个节点,直接调用add方法,一样
        add(t);
    }

    @Override
    public void clear() {//清除链表中所有元素
        /**
         * 直接用循环将每个节点都变为空
         * 先声明一个节点x。将头节点的值赋给x
         * 循环的条件值节点x不存在,所以会一直循环
         */
        for (Node<T> x = root; x != null; ) {
            Node<T> next = x.next;//将(x.next就是)下一个节点的值给新声明的节点next
            x.t = null;//将x的值置空
            x.next = null;//将x的头指针的引用置空
            x.prve = null;//将x的尾指针置空
            x = next;//将节点x赋值为next(下一个节点)
        }
        root = curr = null;//循环结束之后,再将头和尾置空
        size = 0;//循环结束之后,将size置0
    }

    @Override
    public Object clone() {//就是浅拷贝一份链表
        Node<T> clone;//声明一个新链表clone
        /**
         * 直接用循环
         * 将头节点的值赋给clone
         * 循环的条件值clone这个节点不存在,所以会一直循环
         * 每循环一次clone的值变为原节点的下一个
         */
        for (clone = root; clone != null; clone = clone.next) {
            add(clone.t);//每次循环其实都是调用add方法,就是一个一个节点往clone上面加
        }

        return clone;//返回clone
    }

    @Override
    public int indexOf(Object o) {//寻找指定元素的下标(从左往右第一次出现)
        int index = 0;//声明下标,并先假定为0;
        /**
         * 如果需要寻找的元素为null则执行if
         * 如果需要寻找的元素不是null则执行else
         */
        if (o == null) {
            /**
             * 直接用循环
             * 先声明一个节点x。将头节点的值赋给x
             * 循环的条件值x这个节点不存在
             * 每循环一次的值变为原节点的下一个
             */
            for (Node<T> x = root; x != null; x = x.next) {
                if (x.t == null) {//如果x对应的值t为null执行{ }里的内容
                    return index;//能执行这行代码就表示找到了,返回这个下标
                }
                index++;//每循环一次index++
            }
        } else {
            /**
             * 直接用循环
             * 先声明一个节点x。将头节点的值赋给x
             * 循环的条件值x这个节点不存在
             * 每循环一次的值变为原节点的下一个
             */
            for (Node<T> x = root; x != null; x = x.next) {
                if (o.equals(x.t))//如果x对应的值t和所需要寻找的值相等执行{ }中的内容
                    return index;//能执行这行代码就表示找到了,返回这个下标
                index++;//每循环一次index++
            }
        }
        return -1;//上面的结果都不成立,就是没找到。返回-1
    }

    @Override
    public int LastIndexOf(Object o) {//寻找指定元素的下标(从右往左第一次出现,也就是从左往右最后一次出现)
        int index = size-1;//声明下标,并先假定为size;
        /**
         * 如果需要寻找的元素为null则执行if
         * 如果需要寻找的元素不是null则执行else
         */
        if (o == null) {
            /**
             * 直接用循环
             * 先声明一个节点x。将尾节点的值赋给x
             * 循环的条件值x这个节点不存在
             * 每循环一次的值变为原节点的上一个
             */
            for (Node<T> x = curr; x != null; x = x.prve) {
                if (x.t == null) {//如果x对应的值t为null执行{ }里的内容
                    return index;//能执行这行代码就表示找到了,返回这个下标
                }
                index--;//每循环一次index++
            }
        } else {
            /**
             * 直接用循环
             * 先声明一个节点x。将尾节点的值赋给x
             * 循环的条件值x这个节点不存在
             * 每循环一次的值变为原节点的上一个
             */
            for (Node<T> x = curr; x != null; x = x.prve) {
                if (o.equals(x.t)) {//如果x对应的值t和所需要寻找的值相等执行{ }中的内容
                    return index;//能执行这行代码就表示找到了,返回这个下标
                }
                index--;//每循环一次index++
            }
        }
        return -1;//上面的结果都不成立,就是没找到。返回-1
    }

    @Override
    public boolean contains(Object t) {//判断所要寻找的元素在链表中是否存在
        /**
         * 直接调用indexOf方法
         * 因为如果存在,调用indexOf方法之后会返回一个下标。
         * 这个下标肯定不为-1.所以不等于-1.返回值为true
         * 如果不存在indexOf返回值为-1,-1 != -1 为false
         */
        return -1 != indexOf(t);
    }

    @Override
    public int size() {//记录链表中元素的个数
        return size;//返回个数
    }

后面还有一半,关于迭代器的方法没具体些,因为自己掌握的还不是很好。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值