数据结构 | ArrayList与顺序表

集合框架

Java集合框架,又被称为容器container,是定义在 java.util 包下的一组 接口interfaces 和其实现的 类classes .

其主要表现为将多个元素置于一个单元中,用于对这些元素进行快速便捷的 存储store , 检索retrieve , 管理manipulate ,即平时俗称的 增删查改CRUD .

也就是说,集合框架是很多类组成的,每个类的背后就是一种数据结构.

线性表

线性表(linear list) 是n个具有相同特性的数据元素的有限序列.线性表是一种在实际中广泛使用的数据结构,常见的线性表: 顺序表,链表,栈,队列...

线性表在逻辑上是线性结构,是连续的一条址线; 但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储.

顺序表

顺序表是用一段物理地址连续的存储单元 依次存储 数据元素的线性结构,一般情况下采用 数组 存储.在数组上完成数据的增删查改.

顺序表接口的实现

1.在src包底下创建以下类和接口

2.IList接口代码实现

public interface IList {
    public void add(int data);
    // 在 pos 位置新增元素
    public void add(int pos, int data);
    // 判定是否包含某个元素
    public boolean contains(int toFind);
    // 查找某个元素对应的位置
    public int indexOf(int toFind);
    // 获取 pos 位置的元素
    public int get(int pos);
    // 给 pos 位置的元素设为 value
    public void set(int pos, int value);
    //删除第一次出现的关键字key
    public void remove(int toRemove);
    // 获取顺序表长度
    public int size();
    // 清空顺序表
    public void clear();
    // 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
    public void display();

    boolean isFull();

    boolean isEmpty();
}

3.MyArrayList类代码实现

import java.util.Arrays;

public class MyArrayList implements IList {
    public int[] elem;
    public int usedSize;
    //默认的容量
    public static final int DEFAULT_CAPACITY = 5;
    public MyArrayList() {
        elem = new int[DEFAULT_CAPACITY];
    }

    //添加元素,默认添加到数组的最后位置
    @Override
    public void add(int data) {
        //1.判断数组是否满了,满了要扩容
        if(isFull()) {
            elem = Arrays.copyOf(elem,2*elem.length);
        }
        elem[usedSize] = data;
        usedSize++;
    }

    /**
     * 给pos位置 添加一个元素(即指定位置插入元素)
     * @param pos
     * @param data
     */
    @Override
    public void add(int pos, int data) {
        //1.pos位置的判断
        checkPosOfAdd(pos);
        if(isFull()) {
            elem = Arrays.copyOf(elem,2*elem.length);
        }
        /**
         *   1.elem的下标i是 最后 一个存储的数据元素的位置,所以是usedSize-1 (移动元素,从后往前移动)
         *   2.i下标的元素赋值给i+1下标的元素
         *   3.i-- 往前挪一个
         *   4.当 i < pos 时结束
         *   5.将要添加的元素data 放到elem的pos位置 (元素放进去)
         *   6.usedSize++
         */

        for (int i = usedSize - 1; i >= pos; i--) {
            elem[i+1] = elem[i];
        }//(移动元素,从后往前移动)
        elem[pos] = data;//(元素放进去)
        usedSize++;

    }

    public void checkPosOfAdd(int pos) {
        if(pos <0 || pos > usedSize) {
            throw new PosException("pos位置为:" + pos);
        }
    }

    //查找当前元素 是否存在
    @Override
    public boolean contains(int toFind) {
        for (int i = 0; i < usedSize; i++) {
            if(elem[i] == toFind) {
                return true;
            }
        }
        return false;
    }

    //查找当前元素的下标
    @Override
    public int indexOf(int toFind) {
        for (int i = 0; i < usedSize; i++) {
            if(elem[i] == toFind) {
                return i;
            }
        }
        return -1;
    }


    //获取pos位置的值
    @Override
    public int get(int pos) {
        //1.pos位置不合法怎么办
        checkPosOfGet(pos);
        //2.为空怎么办
        if(isEmpty()) {
            throw new EmptyException("顺序表为空");
        }
        return elem[pos];
    }

    public void checkPosOfGet(int pos) {
        if(pos < 0 || pos >= this.usedSize) {
            throw new PosException("pos位置不合法" + pos);
        }
    }

    @Override
    public boolean isEmpty() {
        return usedSize == 0;
    }

    /**
     * 更新pos位置的值为value
     * @param pos
     * @param value
     */
    @Override
    public void set(int pos, int value) {
        checkPosOfGet(pos);
        if (isEmpty()) {
            throw new EmptyException("顺序表为空");
        }
        this.elem[pos] =value;
    }

    /**
     * 删除toRemove这个数字
     * @param toRemove
     */
    @Override
    public void remove(int toRemove) {
        if(isEmpty()) {
            throw new PosException("顺序表为空,不能删除");
        }
        int index = indexOf(toRemove);
        for (int i = index; i <usedSize-1 ; i++) {
            elem[i] = elem[i+1];
        }
        usedSize--;
    }

    @Override
    public int size() {
        return this.usedSize;
    }


    /**
     *清空顺序表 防止内存泄漏
     *
     *引用数据类型,将每个对象都置为null
     *基本数据类型,将元素置为0
     */
    @Override
    public void clear() {
        usedSize = 0;
    }

    //打印顺序表当中的所有元素
    @Override
    public void display() {
        for (int i = 0; i < usedSize; i++) {
            System.out.print(elem[i] +" ");
        }
        System.out.println();
    }

    @Override
    public boolean isFull() {
        return usedSize == elem.length;
    }


}

 4.异常类处理

//Pos位置不合法异常
public class PosException extends RuntimeException{
    public PosException() {

    }

    public PosException(String message) {
        super(message);
    }
}



//顺序表为空异常
public class EmptyException extends RuntimeException{
    public EmptyException() {
    }

    public EmptyException(String message) {
        super(message);
    }
}

5.Test测试代码实现

public class Test {
public static void main(String[] args) {
        MyArrayList myArrayList = new MyArrayList();
        myArrayList.add(10);
        myArrayList.add(20);
        myArrayList.add(30);
        myArrayList.add(40);
        myArrayList.display();

        myArrayList.remove(40);
        myArrayList.display();
    }
}

 6.运行结果

                     

ArrayList

ArrayList是Java已经实现好的顺序表,我们只需要学习掌握ArrayList里面的方法!

ArrayList的构造方法

当我们学习一个新的类时,一定要先从构造方法入手~

方法解释
ArrayListI()无参构造
ArrayList(int initiCapacity)指定顺序表初始容量
ArrayList( Collection<? extends E> c)利用其他Collection构建ArrayList
(1)无参构造
        //构造一个空的列表
        ArrayList<Integer> arrayList = new ArrayList<Integer>();
        arrayList.add(99);//将99存入顺序表 下同
        arrayList.add(88);
        arrayList.add(75);
        arrayList.add(64);
        System.out.println(arrayList);

ArrayList是以泛型方式实现的,使用时先实例化.

ArrayList()无参构造就是在创建的时候不需要 参数 去创建,至于他的初始化的内存是多少,是怎么样初始化的,下文会提到.

(2)指定顺序表初始容量
  //构造一个容量大小为10的列表
        ArrayList<Integer> arrayList = new ArrayList<Integer>(10);
        arrayList.add(11);//将11存入顺序表 下同
        arrayList.add(22);
        arrayList.add(75);
        arrayList.add(64);
        System.out.println(arrayList);

上面的是没有参数的,这里就是有参数的了,在括号里面增加的 参数 就是关于这个顺序表的 初始容量,也就是大小. 

(3)利用其他Collection构建ArrayList
    //创建的 参数 其实就是用其他List的大小作为参数
    ArrayList<Integer> arrayList = new ArrayList<Integer>();
        arrayList.add(99);
        arrayList.add(88);
        arrayList.add(75);
        arrayList.add(64);
        System.out.println(arrayList);

    List<Number> arrayList1 = new ArrayList(arrayList);//把arraylist的大小作为参数传参
    arrayList1.add(99999999);//也有自己的add方法
    System.out.println(arrayList1);//打印输出[99, 88, 75, 64, 99999999],"把另一个集合 拿过来 构造当前的集合"

    //ArrayList<String> arrayList2 = new ArrayList<>(arrayList);//error
    /**
      满足ArrayList实现了Collection接口的条件,但是不满足传入的参数是E类型或者E的子类类型().
      传入的参数arrayList是Integer,和String无关系.既不是String类型也不是Stringent的子类类型
    */

ArrayList( Collection<? extends E> c)要同时满足两点:

  1. 顺序表要实现Collection接口
  2. 传入的参数是E类型本身 或者 E的子类类型 (? 表示通配符)
 ArrayList的subList()方法
ArrayList<Integer> arrayList = new ArrayList<Integer>();
        arrayList.add(99);
        arrayList.add(88);
        arrayList.add(75);
        arrayList.add(64);
        System.out.println(arrayList);

        List<Number> arrayList1 = new ArrayList(arrayList);
        arrayList1.add(99999999);
        System.out.println(arrayList1);//打印输出[99, 88, 75, 64, 99999999]

        //subList截取
        List<Number> list =arrayList1.subList(0,2);//下标
        System.out.println(list);
        //[99, 88, 75, 64, 99999999]

        //我们认为截取后list的值是[99, 88]
        System.out.println("=======================");
        list.set(0,199);
        System.out.println(list);//把list里面0下标的值改为199,就认为变成[199,88]
        System.out.println(arrayList1);//arrayList1里面的值不变,还是[99, 88, 75, 64, 99999999]
        /**
         * 实际输出:
         * [199, 88] list中
         * [199, 88, 75, 64, 99999999] arrayList1中
         * List<Number> list =arrayList1.subList(0,2);不是产生新的对象
         * list和arrayList1指向的是同一个对象
         * */

 

截取list中 [0,2)之间的元素 可以发现,arraylist1 和 list共用的是一个数组.list中发生改变时,arraylist1中的数据也会随之改变.

因此,截取方法不是产生一块新的对象,而是指向的同一个引用 .

ArrayList的遍历 
 public static void main3(String[] args) {
        //ArrayList的遍历
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(10);
        arrayList.add(20);
        arrayList.add(30);
        arrayList.add(40);
        //第一种 直接输出
        System.out.println(arrayList);
        //第2种遍历方式  for
        for (int i = 0; i < arrayList.size(); i++) {
            System.out.print(arrayList.get(i) + " ");
        }
        System.out.println();
        //3、for-each
        for (int x:           //自动装箱
             arrayList) {
            System.out.print(x + " ");
        }
        System.out.println();
        //4.迭代器(有多种使用方式)
        Iterator<Integer> it1 = arrayList.iterator();//iterator继承自Iterator
        while (it1.hasNext()) {
            System.out.print(it1.next() + " ");
        }
        System.out.println();
        //5
        Iterator<Integer> it2 = arrayList.listIterator();//listIterator继承自Iterator
        while (it2.hasNext()) {
            System.out.print(it2.next() + " ");
        }
        System.out.println();
        //6.从后向前遍历
        ListIterator<Integer> it3 = arrayList.listIterator(arrayList.size());
        //arrayList.size()是一个方法调用,它返回了arrayList列表的大小或元素数量。
        // 在这里,ListIterator<Integer> it3 = arrayList.listIterator(arrayList.size())的作用是
        // 创建一个ListIterator对象it3,并将其定位在arrayList列表的 末尾 位置。
        while (it3.hasPrevious()) {
            System.out.print(it3.previous() + " ");
        }
        System.out.println();
    }
深度学习 ArrayList的无参构造

ArrayList的add()方法  

通过观察ArrayList的源码 ,发现:

总结:

  1. 当我们进行ArrayList()的无参构造时,初始大小为0. 当我们第一次add(存放数据元素)时,会分配大小为10给数组,而当10个放满的时候,进行1.5倍扩容。如果调用的是给定容量的构造方法(括号里面带参数),那么顺序表的大小,就是你指定的容量,放满了之后也是1.5倍的扩容。
  2. 检测是否真正需要扩容,如果是调用grow准备扩容
  3. 使用copyOf进行扩容


寄语:不要忘了你希望的远方 

  • 24
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值