模拟LinkedList - add、get方法

        由于自己看源码时感觉难以看懂,即便看懂,隔一段时间回顾时也经常蒙圈,所以手写源码中的部分,达到模拟的目的,便于理解。

1、简介

LinkedList的数据结构是双向链表,下面将通过代码,模拟并介绍这种数据结构的特点。

2、模拟LinkedList的类名

public class LinkedListTest<E>

3、模拟LinkedList的成员变量


    /**
     * 双向链表大小
     */
    private int size;

    /**
     * 双向链表头节点
     */
    private Node<E> first;

    /**
     * 双向链表尾节点
     */
    private Node<E> last;

4、模拟LinkedList的内部节点类


    /**
     * 双向链表节点类
     */
    private static class Node<E> {
        private E item;
        private Node<E> next;
        private Node<E> prev;

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

5、模拟LinkedList的add方法

    /**
     * 给双向链表添加元素
     *
     * @param e 元素
     * @return
     */
    public boolean add(E e) {

        if (first == null) {
            // 给空的双向链表添加元素
            addNodeOnEmptyLinkedList(e);
        } else {
            // 给双向链表添加元素
            addNodeOnLinkedList(e);
        }
        // 双向链表扩容,每次扩容1个长度
        size++;
        return true;
    }

    /**
     * 给空的双向链表添加元素
     *
     * 这个方法包含以下两个动作:
     * 1、创建新节点:新节点的pre节点、next节点都为空
     * 2、双向链表的first成员变量、last成员变量,都指向新节点
     *
     * @param e
     * @return
     */
    private void addNodeOnEmptyLinkedList(E e) {

        // 创建新节点:新节点的pre节点、next节点都为空
        Node<E> newNode = new Node<>(null, e, null);

        // 双向链表的first成员变量、last成员变量,都指向新节点
        first = last = newNode;

    }

    /**
     * 给双向链表添加元素
     *
     * 这个方法包含以下三个动作:
     * 1、创建新节点,新节点的pre节点为双向链表旧的last成员节点,新节点的next节点为空
     * 2、双向链表的last成员变量更改指针指向:由指向旧last节点,改成指向新节点
     * 3、双向链表旧的last成员节点,其next指针指向新节点
     *
     * @param e
     * @return
     */
    private void addNodeOnLinkedList(E e) {

        // 临时变量指向双向链表旧的last节点
        Node<E> oldLast = last;

        // 创建新节点,新节点的pre节点为双向链表旧的last成员节点,新节点的next节点为空
        Node<E> newNode = new Node<>(oldLast, e, null);

        // 双向链表的last成员变量更改指针指向:由指向旧last节点,改成指向新节点
        last = newNode;

        // 双向链表旧的last成员节点,其next指针指向新节点
        oldLast.next = newNode;

    }

6、模拟LinkedList的get方法


    /**
     * 从双向链表中查询元素
     *
     * @param index 查询元素的下标
     * @return
     */
    public E get(int index) {

        // 校验下标是否合理
        if (index < 0 || index >= size) {
            return null;
        }

        // 寻找节点
        Node<E> findNode;

        // 若查询下标小于双向链表的一半大小,则从头部开始查,否则,从尾部开始查
        if (index < size / 2) {
            findNode = first;
            for (int i = 0; i < index; i++) {
                findNode = findNode.next;
            }
        } else {
            findNode = last;
            for (int i = size - 1; i > index; i--) {
                findNode = findNode.prev;
            }
        }

        return findNode.item;
    }

7、模拟LinkedList使用add、get方法

    /**
     * 使用LinkedListTest,并打印结果
     * 
     * @param args
     */
    public static void main(String[] args) {

        LinkedListTest<String> linkedListTest = new LinkedListTest<>();
        linkedListTest.add("1");
        linkedListTest.add("2");
        linkedListTest.add("3");
        linkedListTest.add("4");
        linkedListTest.add("5");

        StringBuilder sb = new StringBuilder("[");
        for (int i = 0; i < linkedListTest.size; i++) {
            sb.append(linkedListTest.get(i)).append(",");
        }
        sb.delete(sb.length() - 1, sb.length()).append("]");

        System.out.println(sb);

    }

         控制台输出:

[1,2,3,4,5]

        从中可以看出LinkedList的特点:链表无长度限制,添加元素的开销小,访问中间元素的开销大。

 8、附上完整代码


/**
 * 模拟双向链表
 *
 * @author pengxin
 * @date 2022/1/13 14:46
 */
public class LinkedListTest<E> {

    /**
     * 双向链表大小
     */
    private int size;

    /**
     * 双向链表头节点
     */
    private Node<E> first;

    /**
     * 双向链表尾节点
     */
    private Node<E> last;

    /**
     * 双向链表节点对象
     */
    private static class Node<E> {
        private E item;
        private Node<E> next;
        private Node<E> prev;

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

    /**
     * 给双向链表添加元素
     *
     * @param e 元素
     * @return
     */
    public boolean add(E e) {

        if (first == null) {
            // 给空的双向链表添加元素
            addNodeOnEmptyLinkedList(e);
        } else {
            // 给双向链表添加元素
            addNodeOnLinkedList(e);
        }
        // 双向链表扩容,每次扩容1个长度
        size++;
        return true;
    }

    /**
     * 从双向链表中查询元素
     *
     * @param index 查询元素的下标
     * @return
     */
    public E get(int index) {

        // 校验下标是否合理
        if (index < 0 || index >= size) {
            return null;
        }

        // 寻找节点
        Node<E> findNode;

        // 若查询下标小于双向链表的一半大小,则从头部开始查,否则,从尾部开始查
        if (index < size / 2) {
            findNode = first;
            for (int i = 0; i < index; i++) {
                findNode = findNode.next;
            }
        } else {
            findNode = last;
            for (int i = size - 1; i > index; i--) {
                findNode = findNode.prev;
            }
        }

        return findNode.item;
    }

    /**
     * 给空的双向链表添加元素
     *
     * 这个方法包含以下两个动作:
     * 1、创建新节点:新节点的pre节点、next节点都为空
     * 2、双向链表的first成员变量、last成员变量,都指向新节点
     *
     * @param e
     * @return
     */
    private void addNodeOnEmptyLinkedList(E e) {

        // 创建新节点:新节点的pre节点、next节点都为空
        Node<E> newNode = new Node<>(null, e, null);

        // 双向链表的first成员变量、last成员变量,都指向新节点
        first = last = newNode;

    }

    /**
     * 给双向链表添加元素
     *
     * 这个方法包含以下三个动作:
     * 1、创建新节点,新节点的pre节点为双向链表旧的last成员节点,新节点的next节点为空
     * 2、双向链表的last成员变量更改指针指向:由指向旧last节点,改成指向新节点
     * 3、双向链表旧的last成员节点,其next指针指向新节点
     *
     * @param e
     * @return
     */
    private void addNodeOnLinkedList(E e) {

        // 临时变量指向双向链表旧的last节点
        Node<E> oldLast = last;

        // 创建新节点,新节点的pre节点为双向链表旧的last成员节点,新节点的next节点为空
        Node<E> newNode = new Node<>(oldLast, e, null);

        // 双向链表的last成员变量更改指针指向:由指向旧last节点,改成指向新节点
        last = newNode;

        // 双向链表旧的last成员节点,其next指针指向新节点
        oldLast.next = newNode;

    }

    /**
     * 使用LinkedListTest,并打印结果
     *
     * @param args
     */
    public static void main(String[] args) {

        LinkedListTest<String> linkedListTest = new LinkedListTest<>();
        linkedListTest.add("1");
        linkedListTest.add("2");
        linkedListTest.add("3");
        linkedListTest.add("4");
        linkedListTest.add("5");

        StringBuilder sb = new StringBuilder("[");
        for (int i = 0; i < linkedListTest.size; i++) {
            sb.append(linkedListTest.get(i)).append(",");
        }
        sb.delete(sb.length() - 1, sb.length()).append("]");

        System.out.println(sb);

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值