List集合

本文介绍了如何实现自定义动态数组`MyArrayList`,包括添加、删除、查找等操作,并对比了`ArrayList`和`Vector`的区别。同时讲解了链表数据结构的`MyLinkList`实现,以及迭代器`hasNext`和`next`方法的功能。此外,提到了栈和队列的数据结构,以及`Set`集合的特性。
摘要由CSDN通过智能技术生成

目录

自定义动态数组

Vector和ArrayList

迭代器的hasNext和next方法什么意思?

队列

 Set集合

Collection系列的集合框架图


List接口的实现类有很多,常见的有:

ArrayList:动态数组

Vector: 动态数组

LinkList: 双向链表

Stack:栈

自定义动态数组

package com.atguigu.list;

import java.util.Arrays;
import java.util.Iterator;

/*
MyArrayList模仿ArrayList动态数组类的实现。
MyArrayList是一个容器,是一个集合,用来存储对象的。
(1)元素的类型是什么?不确定,可以使用泛型
<E>:Element Type元素类型
(2)内部是动态数组,要有数组结构
暂且声明为Object[]
(3)声明一个实例变量来记录实际存储的元素个数
 */
public class MyArrayList<E> implements Iterable<E>{
//    private E[] all = new E[5];//无法创建
    private Object[] all = new Object[5];
    private int total;

    /**
     * 添加元素
     * @param e E:添加一个元素到当前集合中
     */
    public void add(E e){
        //考虑数组是否已满,需要扩容
        grow();

/*        all[total] = e;
        total++;*/
        all[total++] = e;
    }

    private void grow() {
        //考虑数组是否已满,需要扩容
        if (total >= all.length) {
//            all = Arrays.copyOf(all, all.length+1);
//            all = Arrays.copyOf(all, all.length*2);
            all = Arrays.copyOf(all, all.length + (all.length >> 1));//扩容为原来1.5倍
        }
    }

    /**
     * 添加元素
     * @param e E:添加一个元素到当前集合中
     */
    public void add(int index, E e){
        //检查下标
        if(index<0 || index>total){
            throw new IndexOutOfBoundsException(index +"越界");
        }

        //考虑数组是否已满,需要扩容
        grow();

        //把[index]位置的元素往后移动
        /*
        假设all.length = 10,total= 7, index = 3,正常下标[0,6]
        all[6] -> all[7]
        all[5] -> all[6]
        all[4] -> all[5]
        all[3] -> all[4]
        移动元素的个数是4, total - index
         */
        System.arraycopy(all, index, all, index+1, total-index);

        all[index] = e;
        total++;
    }

    /**
     * 返回index位置的元素
     * @param index int 下标
     * @return E 元素
     */
    public E get(int index){
        //判断index合法性
        checkIndex(index);
        return (E) all[index];
    }

    private void checkIndex(int index) {
        //判断index合法性
        if(index<0 || index>=total){
            throw new IndexOutOfBoundsException(index +"越界");
        }
    }

    /**
     * 查询obj在当前集合中的位置。
     * @param obj Object
     * @return int 如果有多个重复的,只返回第1个的下标。如果不存在返回-1;
     */
    public int indexOf(Object obj){
        /*
        思路:遍历all数组,如果元素和obj一样,就返回下标,如果遍历完没有一样的,返回-1
         */
        if(obj != null) {
            for (int i = 0; i < total; i++) {
                if (obj.equals(all[i])) {
                    return i;
                }
            }
        }else{
            for (int i = 0; i < total; i++) {
                if (all[i] == obj) {//null == null是相等的
                    return i;
                }
            }
        }
        return -1;
    }

    /**
     * 查询obj在当前集合中的位置。
     * @param obj Object
     * @return int 如果有多个重复的,只返回最后1个的下标。如果不存在返回-1;
     */
    public int lastIndexOf(Object obj){
        /*
        思路:遍历all数组,如果元素和obj一样,就返回下标,如果遍历完没有一样的,返回-1
         */
        if(obj != null) {
            for (int i = total-1; i >=0; i--) {
                if (obj.equals(all[i])) {
                    return i;
                }
            }
        }else{
            for (int i = total-1; i >=0; i--) {
                if (all[i] == obj) {//null == null是相等的
                    return i;
                }
            }
        }
        return -1;
    }

    /**
     * 判断obj是否在当前集合中
     * @param obj Object 查询的目标对象
     * @return boolean 存在就返回true,不存在返回false
     */
    public boolean contains(Object obj){
        return indexOf(obj) != -1;//如果存在,下标就不会是-1,
    }

    /**
     * 修改index位置的元素
     * @param index int 下标
     * @param e E 目标对象
     */
    public void set(int index, E e){
        //判断index合法性
        checkIndex(index);

        all[index] = e;
    }

    /**
     * 替换集合中obj元素为e
     * @param obj Object 目标对象
     * @param e E 新对象
     */
    public void set(Object obj, E e){
        /*
        两种实现方案:一种替换所有找到的,第二种是替换第一个找到的
         */
        //这里选择实现第二种
        int index = indexOf(obj);
        if(index != -1) {
            set(index, e);
        }
    }

    /**
     * 删除index位置的元素
     * @param index int 下标
     */
    public void remove(int index){
        /*
        思路:先把index位置后面往前移动,再把最后一个位置置为null
         */
        /*
        假设all.length=10, total = 7, index = 3, 有效元素的范围[0,6]
        all[4]->all[3]
        all[5]->all[4]
        all[6]->all[5]
        一共往前复制了3个元素,total-index-1
         */
        System.arraycopy(all, index+1, all, index, total-index-1);
//        all[total-1] = null;
//        total--;
        all[--total]= null;
    }

    /**
     * 删除目标对象
     * @param obj Object 目标对象
     */
    public void remove(Object obj){
        /*
        方案:(1)删除所有重复的obj(2)删除第一个找到的obj
         */
        //这里选择方案二
        int index = indexOf(obj);
        if(index != -1) {
            remove(index);
        }
    }

    /**
     * 把现在集合中的所有元素用数组返回
     * @return Object[] 返回元素的数组
     */
    public Object[] toArray(){
        return Arrays.copyOf(all, total);
    }


    /**
     * 获取元素个数的方法
     * @return int
     */
    public int size(){
        return total;
    }

    @Override
    public Iterator<E> iterator() {
        return new Itr();
    }

    private class Itr implements Iterator<E>{
        int cursor;

        @Override
        public boolean hasNext() {
            return cursor < total;
        }

        @Override
        public E next() {
            return (E) all[cursor++];
        }
    }
        /*
    hasNext() 判断当前位置有没有元素
	其实应该是currentIsPresent()   current:当前位置,present:存在
next() 取出当前位置的元素,并把引用/下标指向下一个元素
	  其实应该是fetchAndMoveNext()   fetch:获取,moveNext:移到下一个
     */
}

Vector和ArrayList

1.区别

  1. 链表与动态数组区别
            动态数组底层的物理结构是数组,因此根据索引访问效率非常高。但是末尾位置的插入和删除效率不高,因为涉及到移动元素。另外添加操作涉及到扩容问题,就会增加时空消耗。
            链表底层的物理结构是链表,因此根据索引访问的效率不高,但是插入和删除不需要移动元素,只需要修改前后元素的指向关系即可,而且链表的添加不会涉及到扩容问题。

  2.         

链表自己实现

package MyLinkList;

/*
 *(1)链式结构,首先要有结点
 *(2)双链表可以从前往后也可以从后往前遍历节点,所以需要记录第一个节点地址和最后一个节点地址
 */

import java.util.Iterator;

public class MyLinkList<E> implements Iterable<E>{
    private Node first;
    private Node last;
    private int total;

    public void add(E data) {
        Node newNode = new Node(last, data, null);

        if (last != null) {
            last.next = newNode;
        } else {
            first = newNode;
        }

        last = newNode;
        total++;
    }

    public int size() {
        return total;
    }

    private Node findNode(Object obj) {
        Node node = first;
        if (obj == null) {
            while (node != null) {
                if (node.data == null) {
                    return node;
                }
                node = node.next;
            }
        } else {
            while (node != null) {
                if (obj.equals(node.data)) {
                    return node;
                }
                node = node.next;
            }
        }
        return null;
    }

    @Override
    public Iterator<E> iterator() {
        return new Itr();
    }

    private class Itr implements Iterator<E> {
        Node node = first;
        @Override
        public boolean hasNext() {
            return node != null;
        }

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

    public void remove(Object obj) {
        // 第一步找到目标节点
        Node node = findNode(obj);
        if (node == null) {
            return;
        }

        if (node.prev == null) {
            first = node.next;
        } else {
            node.prev.next = node.next;
        }

        if (node.next == null) {
            last = node.prev;
        } else {
            node.next.prev = node.prev;
        }

        node.prev = null;
        node.next = null;
        node.data = null;
        total--;
    }


    // 双链表的节点类型
    private class Node {
        Node prev;
        E data;
        Node next;

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

}

迭代器的hasNext和next方法什么意思?

  1. hasNext判断当前位置有没有元素,其实应该是currentIsPresent()
  2. next取出当前位置的元素,并把引用/下标指向下一个元素,其实应该是fetchAndMoveNext

  1. 体现栈结构的操作方法:
    a.peek()方法:查看栈顶元素,不弹出
    b.pop()方法:弹出栈
    c.push方法:压入栈

队列

LinkLIst实现了queue的接口,下面的队列的方法,LinkList是都可以使用的。

而且LinkedList还实现了Deque接口(双端队列)

 Set集合

  1. collection集合总揽
    List接口:可以重复、有序、根据索引操作等
    Queue接口:先进先出
    Deque接口:可以先进先出,可以后进先出,可以先进后出...
    set接口:不允许元素重复,有一些是有序的,有一些是无序的。
            底层的存储顺序和添加的顺序绝对不一致。
  2. set也是collection接口的子接口,但是没有扩展新的方法,所以用的都是collection接口的方法。
  3. Set实现类有:HashSet,TreeSet,LinkedHashSet
    ​​​​HashSet:无序,且不重复
    TreeSet: 自动按照顺序排序,string是按照Unicode编码排序,指定排序,对于自己新增的类,必须实现comparator,
    LinkedHashSet:不可重复,有序(按照添加顺序),底层不是按照添加顺序存储的,但是会有一个链表记录它们的添加顺序。
        //先按照长度排序,长度相同的按照字母unicode排序
        HashSet<String> set = new HashSet<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                int lenResult = o1.length() - o2.length();
                return lenResult == 0 ? o1.compareToIgnoreCase(o2) : lenResult;
            }
        });

Collection系列的集合框架图

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值