ArrayList和顺序表

线性表

线性表是n个具有相同特性的数据元素的有限序列。线性表是一种结构,常见的线性表:顺序表、链表、栈、队列……
线性表在逻辑上是线性结构,也就是连续的一条直线,但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

数组表:
在这里插入图片描述链表:在这里插入图片描述

顺序表

顺序表是用一段物理地址连续的存储单元依次数据元素的线性结构,一般情况下采用数组存储,在数组上完成数据的增删查改。
我们先自己有代码实现,这样才能更好理解源代码是如何是实现的,要学习类,跟着源码学习。
接口的实现

public class MyArrayList {


    public int[] elem;

    public int usedSize;//0

    //默认容量

    private static final int DEFAULT_SIZE = 10;//static:数组属于类,不属于对象,final:不可修改数据


    public MyArrayList() {

        this.elem = new int[DEFAULT_SIZE];

    }


    /**
     * 打印顺序表:该方法并不是顺序表中的方法,为了方便看测试结果给出的
     * <p>
     * 根据usedSize判断即可
     */

    public void display() {
        if(isEmpty()==false){
            throw new NullException("数组空异常");
        }

        for (int i = 0; i < this.size(); i++) {
            System.out.print(this.elem[i] + " ");
        }
        System.out.println();
    }


    // 新增元素,默认在数组最后新增

    public void add(int data) {

        //1、检查当前的顺序表是不是满了?
        if (isFull()) {
            //2、如果满了就要扩容,扩容成原来的两倍
            this.elem= Arrays.copyOf(this.elem,2*this.elem.length);

            //throw new IndexOutOfException("数组越界访问");//throw就需要catch
        }
        this.elem[this.size()] = data;
        this.usedSize++;
    }


    /**
     * 判断当前的顺序表是不是满的!
     *
     * @return true:满   false代表空
     */

    public boolean isFull() {
//        if(this.size()>=this.elem.length){
//            return true;
//        }
//        return false;
        return this.size()>=this.elem.length;
    }

    /**
     * 判断访问的下标是否正确
     * @param pos
     * @return
     */

    private boolean checkPosInAdd(int pos) {
        //下标数字小于0或者大于等于目前长度
        if(pos<0||pos>=size()){

            throw new IndexOutOfException("下标访问异常");
        }

        return true;//合法

    }


    /**
     *  在 pos 位置新增元素
     *  漏:如果Pos下标不合法,那么就会抛出一个PosWrongFullException
     * @param pos
     * @param data
     */

//异常声明throws:处在方法声明中参数列表后,当方法中抛出运行时异常,用户不想处理该异常,借此throws将异常抛出给方法的调用者来处理。
    public void add(int pos, int data) throws IndexOutOfException {
       //不能满的时候添加元素
        if(isFull()){
            System.out.println("满了");
            throw new IndexOutOfException("数组已经满了,不能再添加了");
        }
       //不合法下标--因为是条件,所以可以添加到最后一个位置上
        if(pos<0||pos>size()){
            throw new IndexOutOfException("下标不合法");
        }
//        //特殊位置--就在末尾加
//        if()
//         不能隔着存入元素-判断下标是否合理--发现这个代码也包含了特殊位置末尾
        //pos一定是合法的
        //1、开始挪动数据
        for (int i = size()-1; i >=pos; i--) {
            this.elem[i+1]=this.elem[i];
        }
//        int i=size()-1;
//        while(i>pos){
//            this.elem[i]=this.elem[i+1];
//            i--;
//        }
        //2、插入数据
        this.elem[pos]=data;
        //3、总数据加加
        this.usedSize++;
        //先移动后添加


    }

    /**
     * 判定是否包含某个元素
     * @param toFind
     * @return
     */

    public boolean contains(int toFind) {
        //万一要是数组为空怎么办——会发生空异常

        if(isEmpty()==false){
            throw new NullException("数组为空");
        }

        for (int i = 0; i < this.size(); i++) {
            if(this.elem[i]==toFind){
                System.out.println("找到了,在第"+(i+1)+"个");
                return true;
            }
        }


        return false;

    }

    // 查找某个元素对应的位置

    public int indexOf(int toFind) {
//首先判断数组不能为空
        if(isEmpty()==false){
            throw new NullException("数组为空");
        }
        for (int i = 0; i < size(); i++) {
            if(this.elem[i]==toFind){
                return i+1;
            }
        }
        return -1;

    }


    // 获取 pos 位置的元素

    public int get(int pos) {
        //数组是否为空
        if(isEmpty()==false){
            throw new NullException("数组为空");
        }
        //访问下标位置是否合法--这里是访问,因此当下标等于数组长度时,也不可以
        if(checkPosInAdd(pos)==false){
            throw new IndexOutOfException("下标不合法");
        }

        return this.elem[pos];


    }

    /**
     * 判断数组不为空
     * true 不空      false 空
     * @return
     */

    private boolean isEmpty() {
        if(this.size()==0){
            return false;
        }
        return true;

    }

    // 给 pos 位置的元素设为【更新为】 value

    public void set(int pos, int value) {
//数组是否为空
        if(isEmpty()==false){
            throw new NullException("数组为空");
        }
        //访问下标位置是否合法--这里是访问,因此当下标等于数组长度时,也不可以
        if(checkPosInAdd(pos)==false){
            throw new IndexOutOfException("下标不合法");
        }
        this.elem[pos]=value;

    }


    /**
     * 删除第一次出现的关键字key
     *
     * @param key
     */

    public void remove(int key) {
        //判断是否为空
        if(isEmpty()==false){
            throw new NullException("数组为空,无法删除");
        }
        //第一种方法
//        //先找到在哪里,然后再先移
//        int i = 0;
//        for (i = 0; i < size(); i++) {
//            if(this.elem[i]==key){
//                break;//找到就退出来
//            }
//        }
//        //说明已经找到了
//        if(i<size()) {
//            for (int j = i; j < size() - 1; j++) {//限制条件是size()-1,因为如果是限制条件是size(),数组遍历到最后一个元素,就会发生数组越界,
//                //当删除的是最后一个元素,这个代码就不行
//                this.elem[j] = this.elem[j + 1];
//            }
//            this.usedSize--;
//
//        }
//        //特殊位置:删除最后一个元素
//        if(i==size()-1){
//            this.usedSize--;
//        }
//
          //第二种方法
        int index=this.indexOf(key);
        if(index==-1){
            System.out.println("没有这个数字");
            return;//无返回值
        }
        for(int i=index;i<this.size()-1;i++){
            this.elem[i]=this.elem[i+1];
        }
        this.usedSize--;
    }


     //获取顺序表长度

    public int size() {

return this.usedSize;
    }
    // 清空顺序表

    public void clear() {
this.usedSize=0;
//如果数组是引用类型的,就需要一个一个NULL
//        for (int i = 0; i < size(); i++) {
//            this.elem[i]=null;
//        }

    }
}

ArrayList简介

ArrayList使用

JAVA集合类一般都在java.util包里面:
在这里插入图片描述

ArrayList的构造

方法解释
ArrayList(int Capacity)指定顺序表初始容量
ArrayList()无参构造,默认为空数组(推荐这个写法)
ArrayList(Collection<? extends E> c)利用其他Collection构建ArrayList

第一个构造方法:
在这里插入图片描述
第二种构造方法:
可以发现当不指定大小创建数组,默认为空数组
在这里插入图片描述
在这里插入图片描述第三种构造方法:
构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。
在java中,为了获取实际的数组,这个数组包含了列表的内容,可以调用toArray()方法来实现
copyOf:数组的拷贝
在这里插入图片描述

         //ArrayList创建,推荐写法
        //构造一个空的列表
        ArrayList<Integer> list1=new ArrayList<>();
        
        ArrayList<Integer> list2=new ArrayList<>(3);
        list2.add(1);
        list2.add(2);
        //list2.add("hello");//编译异常,ArrayList<Integer> 已经限定了,list2中只能存储整型元素
         
        //list3构造完成好之后,与list2中的元素一致
        ArrayList<Integer> list3=new ArrayList<>(list2);
        
        //可以不用指定顺序表数据类型,并且任何元素都可以存放,使用时将是一场灾难crisis
        ArrayList list4=new ArrayList();
        list4.add("hello");
        list4.add(520);

ArrayList常见操作

方法解释
boolean add(E e)尾插 e
void add(int index, E element)将 e 插入到 index 位置
boolean addAll(Collection<? extends E> c)尾插 c 中的元素
E remove(int index)删除 index 位置元素
boolean remove(Object o)删除遇到的第一个 o
E get(int index)获取下标 index 位置元素
E set(int index, E element)将下标 index 位置元素设置为 element
void clear()清空
boolean contains(Object o)判断o是否在线性表中
int indexOf(Object o)返回第一个o所在下标
int lastIndexOf(Object o)返回最后一个o的下标
List subList(int fromIndex, int toIndex)截取部分list
  List<String> list=new ArrayList<>();
        list.add("hello");
        list.add("java");
        list.add("jvm");
        list.add("测试课程");

        System.out.println(list);
        //获取list有效元素个数
        System.out.println(list.size());

        //获取和设置index位置上的元素,注意index必须介于[0.size())间
        System.out.println(list.get(1));
        list.set(1,"h");
        System.out.println(list.get(1));

        //在list的index位置插入指定元素,index及后续的元素逐一往后移动
        list.add(1,"喵喵");
        System.out.println(list);

        //删除指定元素,找到了就删除,该元素之后的元素逐一往前覆盖
        list.remove("jvm");
        System.out.println(list);
        //删除list中index位置上的元素,注意访问的下标要合法,否则下界越界异常
        list.remove(3);
        System.out.println(list);
        //检测是否包含指定元素,包含返回true,否则返回false
        if(list.contains("jvm")){
            System.out.println("包含jvm");
        }else{
            System.out.println("不包含");
        }
        //查找指定元素第一次出现的位置:indexOf从前往后找,lastIndexOf从后往前找
        list.add("JavaSE");
        System.out.println(list.indexOf("JavaSE"));
        System.out.println(list.lastIndexOf("JavaSE"));
        //使用list中[0,2)之间的元素构成一个新的ArrayList返回
        List<String> ret=list.subList(0,2);
        System.out.println(ret);
        list.clear();
        System.out.println(list.size());

在这里插入图片描述

ArrayList的遍历

 ArrayList<Integer> list1=new ArrayList<>();
        list1.add(1);
        list1.add(2);
        list1.add(3);
        //fori遍历
        for (int i = 0; i < list1.size(); i++) {
            System.out.print(list1.get(i)+" ");
        }
        //for-each遍历
        for (Integer integer:list1) {
            System.out.println(integer+" ");
        }
        //使用迭代器:Iterator-父类,listIterator-子类
        Iterator<Integer> it=list1.listIterator();
        while(it.hasNext()){
            System.out.print(it.next()+" ");
        }

在这里插入图片描述

ArrayList的扩容机制

在这里插入图片描述

提出一个问题:
当我们调用不带参数的构造方法的时候,它是如何添加数据的?
在这里插入图片描述其中Math.max(10,var1):返回其中的最大值。
总结:当我们调用不带参数的构造方法的时候,第一次的add的时候,才将分配大小为10的内存。
放在第11个的时候(grow)怎么扩容?
采用当前长度的1.5倍扩容。在这里插入图片描述## 顺序表的思考
1、扩容之后,可能就带来空间的浪费
2、当前顺序表,每次删除一个元素或者插入一个元素【比如删除/插入都是第一个元素】,都需要将每个元素移动
总结顺序表:
ArrayList不适合使用在频繁的插入和删除的场景,适合给定下标位置进行查看元素,此时可以到达O(1)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值