java 数据结构 LinkedList的基本实现

我用图表示每一个操作:

  • 初始化操作(即new LinkedList()后的情况)

初始化

  • 新增

这里写图片描述

  • 删除

这里写图片描述

代码:

/**
 * LinkedList implement
 */
public class MyLinkedList<T> implements Iterable<T> {


    /**
     * 头节点
     */
    private Node<T> first;

    /**
     * 尾节点
     */
    private Node<T> end;

    /**
     * 元素的数量
     */
    private int theSize;

    public MyLinkedList() {

        /**
         * 构造方法中将头尾节点连接起来
         * 以下三句代码就是连接的代码
         * 第一句将头节点实例化
         * 第二句将尾节点实例化,并且把尾节点的prev指向头节点
         * 第三局将头结点的next指向尾节点
         */
        first = new Node(null, null, null);
        end = new Node(null, first, null);
        first.next = end;
        /**
         * size初始化
         */
        theSize = 0;
    }

    @Override
    public Iterator<T> iterator() {
        return new MyIterator();
    }

    private class MyIterator<T> implements Iterator<T> {

        /**
         * 代表当前指向的节点
         */
        private Node current;

        public MyIterator() {
            /**
             * 构造方法把current指向第一个节点(即头结点的下一个节点)
             * 因为头尾节点是不计算在元素内的
             * 比如一个3个元素,即size==3的linkedList,实际有5个节点,因为多了头尾节点
             */
            current = first.next;
        }

        @Override
        public boolean hasNext() {
            /**
             * 判断是否有下一个节点
             * 当current指向了尾节点时,说明没有下一个节点了
             */
            return current != end;
        }

        @Override
        public T next() {
            /**
             * 获取当前节点内的元素
             */
            T element = (T) current.element;
            /**
             * 变化current的值为下一个节点
             */
            current = current.next;
            return element;
        }

        @Override
        public void remove() {
            /**
             * 调用MyLinkedList内部的remove方法(current.prev的原因是我们每次在调了iterator.next()方法获取元素后,current实际已经指向了下一个节点,要想删除当前的元素,实际是删除current的前一个节点内的元素,即current.prev)
             */
            MyLinkedList.this.remove(current.prev);
        }
    }

    /**
     * 这个类代表一个节点
     * next代表这个节点连接的下一个节点
     * prev代表上一个节点
     * element是这个节点的元素
     *
     * @param <T>
     */
    private static class Node<T> {

        private Node next;

        private Node prev;

        private T element;

        public Node() {
        }

        public Node(Node next, Node prev, T element) {
            this.next = next;
            this.prev = prev;
            this.element = element;
        }
    }

    public T get(int index) {
        Node node;
        node = getNode(index);
        return (T) node.element;
    }

    /**
     * 添加一个元素
     *
     * @param t
     * @return
     */
    public boolean add(T t) {
        return add(t, theSize);
    }

    public boolean add(T t, int index) {
        /**
         *首先获取指定索引的节点
         */
        Node old = getNode(index);
        /**
         * 我们新增一个节点,把新节点的next指向老节点,prev指向老节点的上一个节点
         * 然后分别把新节点的上一个节点的next和下一个节点的prev都指向新节点
         */
        Node newNode = new Node(old, old.prev, t);

        newNode.prev.next = newNode.next.prev = newNode;

        theSize++;
        return true;
    }

    /**
     * 获取指定索引的节点
     *
     * @param index
     * @return
     */
    public Node getNode(int index) {
        if (theSize < index) {
            throw new RuntimeException();
        }
        if (index == 0) {
            return first.next;
        }

        /**
         * 判断索引是在元素数量/2后的前半段还是后半段
         */
        Node node;
        if (theSize / index <= 2) {
            node = end;
            // 在右边,则从尾节点开始遍历
            for (int i = index; i < theSize; i++) {
                node = node.prev;
            }
        } else {
            node = first;
            // 在左边,则从头节点开始遍历
            for (int i = 0; i <= index; i++) {
                node = node.next;
            }
        }
        return node;
    }

    public T remove(int index) {
        Node node = getNode(index);
        T remove = (T) remove(node);
        return remove;
    }

    private T remove(Node<T> node) {
        /**
         * 删除即是把需要删除元素所在节点的上一个节点指向该节点的下一个节点(即绕过该节点)
         */
        node.prev.next = node.next;
        node.next.prev = node.prev;
        T element = node.element;
        node = null;
        theSize--;
        return element;
    }

    public int indexOf(T t) {
        Node node = first;
        for (int i = 0; i < theSize; i++) {
            node = node.next;
            T element = (T) node.element;
            if (t == element) {
                return i;
            }
        }
        return -1;
    }


}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中有许多常用的数据结构,下面我会介绍一些基本的操作方法。 1. 数组(Array): - 创建数组:可以使用关键字new来创建数组对象,指定数组的类型和长度。 - 访问元素:通过索引访问数组元素,索引从0开始。 - 修改元素:可以直接通过索引修改数组中的元素值。 - 遍历数组:使用for循环或者增强for循环来遍历数组中的元素。 2. 链表(LinkedList): - 添加元素:使用add方法在链表末尾添加元素。 - 插入元素:使用add方法在指定位置插入元素。 - 删除元素:使用remove方法删除指定位置的元素。 - 获取元素:使用get方法获取指定位置的元素。 - 遍历链表:使用迭代器或者增强for循环来遍历链表中的元素。 3. 栈(Stack): - 入栈:使用push方法将元素压入栈顶。 - 出栈:使用pop方法将栈顶元素弹出。 - 获取栈顶元素:使用peek方法获取栈顶元素,但不会将其移除。 - 判断栈是否为空:使用isEmpty方法判断栈是否为空。 4. 队列(Queue): - 入队:使用offer方法将元素添加到队尾。 - 出队:使用poll方法将队首元素移除。 - 获取队首元素:使用peek方法获取队首元素,但不会将其移除。 - 判断队列是否为空:使用isEmpty方法判断队列是否为空。 这些是Java中常用的数据结构基本操作方法,希望对你有所帮助!如果有其他问题,请继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值