手动实现LinkedList 和 ArrayList

        学过java的同学都知道,LinkedList 和 ArrayList 是java中两个非常重要的数据结构,也是面试的时候常考的题型,我们平常可能自己用jdk给我们封装好的api非常方便,但是作为一个程序员,我们要有自己造轮子的能力,这样可以极大的提升我们的编程能力。

        1.ArrayList

        ArrayList 的底层其实是动态数组,如果了解过C++中的vector的同学应该不会陌生,ArrayList和vector的原理类似,vector的底层维护一个泛型数组,ArrayList底层维护的是一个Object类的数组,我们可以思考一下这样做的好处,因为java中Object类是所有类的直接或者间接超类,所以维护一个Object类的数组就可以转换成任意类的数组,加之java中的泛型只能是类类型的,这样更能保护数据的安全性,这也是为什么java要为基本数据类型设计包装类的原因了。

        代码部分:

import java.util.Iterator;

/**
 * @author DJS
 * Date create 17:33 2022/8/30
 * Modified By DJS
 **/

public class ArrayList <E> implements Iterable<E> {

    private static final int DEFAULT_SIZE = 0; // 数组的默认大小
    private static final int DEFAULT_CAPACITY = 50; // 数组的默认容量, 默认为50

    private int size; // 数组元素个数
    private int capacity; // 数组容量大小

    private Object[] arr; // 底层维护的数组

    /**
     *  无参构造方法:
     *  构造出一个空的arraylist, 大小和容量都使用默认值
     * */
    public ArrayList () {
        // 将arr 初始化
        size = DEFAULT_SIZE;
        capacity = DEFAULT_CAPACITY;
        arr = new Object[capacity];
    }

    /**
     *  method name: add
     *  param: E data
     *  return: void
     *  利用尾插法将元素插入
     * */
    public void add(E data) {
        // 如果达到最大容量, 进行扩容操作
        if (size == capacity) {
            capacity *= 2;
            Object[] tmp = new Object[capacity];
            // 复制数组元素
            System.arraycopy(arr, 0, tmp, 0, arr.length);
            arr = tmp;
        }
        // 将数据插入到尾部
        arr[size] = data;
        size++;
    }

    /**
     *  method name: get
     *  param: int index
     *  return: E
     *  获取index位置的元素
     * */
    @SuppressWarnings("unchecked")
    public E get(int index) {
        if (index < 0 || index > size)
            throw new ArrayIndexOutOfBoundsException("Index out of range");
        return (E)arr[index];
    }

    /**
     * method name: indexOf
     * param: E data
     * return: int
     * 获取值为data的下标
     * */
    public int indexOf(E data) {
        for (int i = 0; i < size; i++)
            if (arr[i].equals(data))
                return i;
        return -1;
    }

    public boolean findIf(E data) {
        for (int i = 0; i < size; i++)
            if (arr[i].equals(data))
                return true;
        return false;
    }

    public void remove(int idx) {
        if (idx < 0 || idx > size) throw new ArrayIndexOutOfBoundsException("Out of array");
        if (size - 1 - idx >= 0)
            System.arraycopy(arr, idx + 1, arr, idx, size - 1 - idx);
    }

    @Override
    public Iterator<E> iterator() {
        return new Iter<>();
    }
    
    // implement interface Iterator and Iterable to suppose Enhanced for
    private static class Iter<E> implements Iterator<E> {

        private int current_idx;
        private final ArrayList<E> array;

        @Override
        public boolean hasNext() {
            return ++current_idx < array.size;
        }

        @Override
        @SuppressWarnings("unchecked")
        public E next() {
            return (E) array.arr[++current_idx];
        }

        public Iter() {
            current_idx = -1;
            array = new ArrayList<>();
        }
    }
    
    

}

以上是一个ArrayList的简单实现。

接下来我们来讲解LinkedList, 实际上LinkedList 就是一个双向链表,这是其底层原理,因为java原生的api并没有给我们提供栈和队列这两种数据结构的实现,所以我们通常也会使用LinkedList来模拟栈和队列。

以下是LinkedList手动代码实现

import java.util.Iterator;

/**
 * @author DJS
 * Date create 17:34 2022/8/30
 * Modified By DJS
 *
 * 双向链表的实现
 **/

public final class LinkedList<E> implements Iterator<E>, Iterable<E> {

    /**
     * head: 头指针
     * tail: 尾指针
     * size: 链表的元素个数
     * */

    private int size;

    private final Node<E> head;
    private final Node<E> tail;

    private Node<E> cur_ptr;

    @Override
    public boolean hasNext() {
       return cur_ptr.next != tail;
    }

    @Override
    public E next() {
        E data = cur_ptr.next.data;
        cur_ptr = cur_ptr.next;
        return data;
    }

    @Override
    public Iterator<E> iterator() {
        cur_ptr = head;
        return this;
    }

    private static class Node<E> {
        /**
         *  prev: 节点前驱
         *  next: 节点后继
         *  data: 数据域
         * */

        public Node<E> prev;
        public Node<E> next;

        public E data;

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

    public LinkedList() {
        head = new Node<E>(null, null, null);
        tail = new Node<E>(head, null, null);
        cur_ptr = head;
        head.next = tail;
        this.size = 0;
    }

    public LinkedList(int size, E data) {
        this();
        for (int i = 0; i < size; i++) insert(data);
    }

    // 在指定位置插入
    public void insert(int index, E data) throws Exception {
        if (index < 0 || index > size) throw new Exception("Out of index");
        if (index == size) {
            insert(data);
            return;
        }

        Node<E> cur = head;
        for (int i = 0; i < index; i++) cur = cur.next;

        // 插入操作
        cur.next = new Node<E>(cur, cur.next, data);
        cur.next.prev = cur;
        cur.next.next.prev = cur.next;

        this.size++;
    }

    // 尾插法
    public void insert(E data) {
        Node<E> cur = tail.prev;
        cur.next = new Node<E>(cur, tail, data);
        tail.prev = cur.next;

        this.size++;
    }

    public void insert_head(E data) {
        try {
            insert(0, data);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public E front() {
        if (head.next != null) return head.next.data;
        else return null;
    }

    public E back() {
        if (tail.prev != null) return tail.prev.data;
        else return null;
    }

    public int size() {
        return this.size;
    }

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

    public void remove(int index) {
        if (this.isEmpty() || index > size) throw new NullPointerException("None Node");

        Node<E> cur = head;
        for (int i = 0; i < index; i++) cur = cur.next;

        Node<E> tmp = cur.next;
        cur.next = tmp.next;
        tmp.next.prev = cur;
        tmp.next = null;
        tmp.prev = null;

        this.size--;
    }

    public void pop() {
        if (this.isEmpty()) throw new NullPointerException("None Node");

        Node<E> tmp = head.next;
        head.next = tmp.next;
        tmp.next.prev = head;
        tmp.prev = null;
        tmp.next = null;

        this.size--;
    }

    public void reverse() {
        if (isEmpty()) return;
        reverse(head.next);
    }

    private Node<E> reverse(Node<E> curr) {
        if (curr.next == tail) {
            head.next = curr;
            curr.prev = head;
            return curr;
        }
        Node<E> pre = reverse(curr.next);
        pre.next = curr;
        curr.prev = pre;
        curr.next = tail;
        tail.prev = curr;
        return curr;
    }

    public E getMid() {
        if (isEmpty()) return null;
        Node<E> low = this.head;
        Node<E> fast = this.head;

        while (fast != tail) {
            low = low.next;
            fast = fast.next.next;
        }

        return low.data;
    }


}

我再LinkedList中还实现了两个算法,一个是反转链表,另外一个是通过快慢指针取到链表的中间值。具体操作可以参考我提供的实现。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值