动手实现ArrayList和LinkedList

数组链表基本原理

  • 数组和链表是数据结构的基石

  • 很多复杂的数据结构的底层都是数组和链表

数组

  • 数组是最基本的构造类型,它是一组相同类型数据的有序集合

  • 在数组中,随机访问的时间复杂度为O(1),可以通过索引直接访问任何一个元素

  • 插入和删除的时间复杂度为O(n)

  以下是MyArrayList的Java代码实现:

public class MyArrayList<E> implements Iterable<E> {
    // 真正存储数据的底层数组
    private E[] data;
    // 记录当前元素个数
    private int size;
    // 默认初始容量
    private static final int INIT_CAP = 1;

    public MyArrayList() {
        this(INIT_CAP);
    }

    public MyArrayList(int initCapacity) {
        data = (E[]) new Object[initCapacity];
        size = 0;
    }

    // 增
    public void add(int index, E e) {
        checkPositionIndex(index);//检查索引越界
        int cap = data.length;//判断data数组的容量够不够
        if(size==cap){
            resize(2*cap);
        }
        System.arraycopy(data,index,data,index+1,size-index);
        data[index] = e;
        size++;
    }

    public void addLast(E e) {
    int cap = data.length;//判断data数组的容量够不够
        if(size==cap){
            resize(2*cap);
        }
        data[size] = e;
        size++;
    }

    public void addFirst(E e) {
        add(0,e);
    }

    // 删
    public E remove(int index) {
        //检查索引边界
        checkElementIndex(index);
        int cap = data.length;
        //可以缩容,节约空间
        if (size<=cap/4){
            resize(cap/2);
        }
        E deletedValue = data[index];
        System.arraycopy(data,index + 1,data,index,size-index-1);
        size--;
        return deletedValue;
    }

    public E removeFirst() {
        return remove(0);
    }

    public E removeLast() {
        if(size==0){
            throw new NoSuchElementException();
        }
        int cap = data.length;
         //可以缩容,节约空间
        if (size<=cap/4){
            resize(cap/2);
        }
        E deletedValue = data[size-1];
        data[size-1] = null;
        size--;
        return deletedValue;
    }

    // 查
    public E get(int index) {
        checkElementIndex(index);
        return data[index];
    }

    // 改
    public E set(int index, E element) {
        checkElementIndex(index);
        E previousValue = data[index];
        data[index] = element;
        return previousValue;
    }


    // 工具方法
    // 将 data 的容量改为 newCap
    private void resize(int newCap) {
        if(size>newCap){
            return;
        }
        E[] temp = (E[])new Object[newCap];
        for (int i = 0; i <size; i++) {
            temp[i] = data[i];
        }
        
        //System.arrayCopy(data,0,temp,0,size)
        
        data = temp;
    }

    public int size() {
        return size;
    }

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

    private boolean isElementIndex(int index) {
        return index >= 0 && index < size;
    }

    private boolean isPositionIndex(int index) {
        return index >= 0 && index <= size;
    }

    /**
     * 检查 index 索引位置是否可以存在元素
     */
    private void checkElementIndex(int index) {
        if (!isElementIndex(index))
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
    }

    /**
     * 检查 index 索引位置是否可以添加元素
     */
    private void checkPositionIndex(int index) {
        if (!isPositionIndex(index))
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<E>() {
            private int p = 0;

            @Override
            public boolean hasNext() {
                return p != size;
            }

            @Override
            public E next() {
                return data[p++];
            }
        };
    }
}

链表

  • 链表是一种常见的基础数据结构,它由一系列节点(Node)组成,用于存储一连串数据元素。

  • 每个节点包含两部分:数据域(存储实际数据)和指针域(存储下一个节点的地址)

  • 在链表中,随机访问的时间复杂度为O(n)

  • 插入和删除行为本身的时间复杂度为O(1)

    • 插入和删除操作本身(修改指针)非常快

    • 找到插入位置的过程可能需要O(n)的时间

      插入位置时间复杂度
      在头部和尾部插入O(1)
      在中间插入O(n)

动手实现MyLinkedList

import java.util.Iterator;
import java.util.NoSuchElementException;

public class MyLinkedList<E> implements Iterable<E> {
    // 虚拟头尾节点
    final private Node<E> head, tail;
    // 记录元素个数
    private int size;

    // 双链表节点
    private static class Node<E> {
        E val;
        Node<E> next;
        Node<E> prev;

        Node(E val) {
            this.val = val;
        }
    }

    // 构造函数初始化头尾节点
    public MyLinkedList() {
        this.head = new Node<>(null);
        this.tail = new Node<>(null);
        head.next = tail;
        tail.prev = head;
        this.size = 0;
    }


    // **** 增 ****

    public void addLast(E e) {
        // temp <-> x <-> tail
        Node<E> x = new Node<>(e);
        Node<E> temp = tail.prev;
        temp.next = x;
        x.prev = temp;

        x.next = tail;
        tail.prev = x;
        size++;
    }

    public void addFirst(E e) {
        //head <-> x <-> temp
        Node<E> x = new Node<>(e);
        Node<E> temp = head.next;
        temp.prev = x;
        x.next = temp;

        head.next = x;
        x.prev = head;
        size++;
    }

    public void add(int index, E element) {
        checkPositionIndex(index);
        if(index == size){
            addLast(element);
            return;
        }

        // 找到index对应的Node
        Node<E> p = getNode(index);
        Node<E> temp = p.prev;
        // temp <-> p

        //新要插入的Node
        Node<E> x = new Node<>(element);

        p.prev = x;
        temp.next = x;

        x.prev = temp;
        x.next = p;

        // temp <-> x <-> p
        size++;
    }

    // **** 删 ****

    public E removeFirst() {
        if (size<1){
            throw new NoSuchElementException();
        }
        Node<E> x = head.next;
        Node<E> temp = x.next;
        // head <-> x <-> temp
        head.next = temp;
        temp.prev = head;

        x.prev = null;
        x.next = null;

        size--;
        return x.val;
    }

    public E removeLast() {
        if(size<1){
            throw new NoSuchElementException();
        }
        Node<E> x = tail.prev;
        Node<E> temp = x.prev;
        //temp <-> x <-> tail
        tail.prev = temp;
        temp.next = tail;

        x.next = null;
        x.prev = null;
        // temp <-> tail

        size--;
        return x.val;
    }

    public E remove(int index) {
        checkElementIndex(index);
        // 找到index所对应的Node
        Node<E> x = getNode(index);
        Node<E> prev = x.prev;
        Node<E> next = x.next;
        // prev <-> x <-> next
        prev.next = next;
        next.prev = prev;

        x.next = next.prev = null;
        size--;
        return x.val;
    }

    // **** 查 ****

    public E get(int index) {
        checkElementIndex(index);
        // 找到 index 对应的 Node
        Node<E> p = getNode(index);
        return p.val;
    }

    public E getFirst() {
        if (size<1){
            throw new NoSuchElementException();
        }
        return head.next.val;
    }

    public E getLast() {
        if (size<1){
            throw new  NoSuchElementException();
        }
        return tail.prev.val;
    }


    // **** 改 ****

    public E set(int index, E val) {
        checkElementIndex(index);
        // 找到 index 对应的 Node
        Node<E> p = getNode(index);
        E oldVal = p.val;
        p.val = val;

        return oldVal;
    }

    // **** 其他工具函数 ****

    public int size() {
        return size;
    }

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

    private Node<E> getNode(int index) {
        checkElementIndex(index);
        Node<E> p = head.next;
        // TODO: 可以优化,通过 index 判断从 head 还是 tail 开始遍历
        for (int i = 0; i < index; i++) {
            p = p.next;
        }
        return p;
    }

    private boolean isElementIndex(int index) {
        return index >= 0 && index < size;
    }

    private boolean isPositionIndex(int index) {
        return index >= 0 && index <= size;
    }

    /**
     * 检查 index 索引位置是否可以存在元素
     */
    private void checkElementIndex(int index) {
        if (!isElementIndex(index))
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);

    }

    /**
     * 检查 index 索引位置是否可以添加元素
     */
    private void checkPositionIndex(int index) {
        if (!isPositionIndex(index))
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
    }

    @Override
    public Iterator<E> iterator() {
        return new Iterator<>() {
            Node<E> p = head.next;

            @Override
            public boolean hasNext() {
                return p != tail;
            }

            @Override
            public E next() {
                E val = p.val;
                p = p.next;
                return val;
            }
        };
    }
}

以上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值