【数据结构】顺序表和ArrayList

线性表

线性表是 n 个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表有顺序表、链表、栈和队列等。

线性表在逻辑上是一条连续的直线,但在物理结构上不一定连续,线性表在物理上存储时,通常以数组和链式结构的形式存储。分别如下图所示:

顺序表(顺序结构):
顺序表

线性表(链式结构):
线性表

顺序表

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

首先定义一个顺序表类:

public class ArrayList {
    public int[] elem;
    public int usedSize;  //数组中数据的个数

    public ArrayList() {
        this.elem = new int[5];  //初始化数组容量为5
    }
    public ArrayList(int capacity) {
        this.elem = new int[capacity];  //也支持传递参数来初始化数组容量
    }
}

为了方便查看顺序表中的数据,先实现一个遍历顺序表的方法:

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

获取顺序表的长度,可以直接将 usedSize 返回:

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

运行结果:

size


判断顺序表中是否包含某一元素:

public boolean contains(int num){
    for (int i = 0; i < this.usedSize; i++) {
    //这里的数据是基本数据类型,所以用了==
    //如果顺序表中的数据是其他类型,需要视情况更改
        if (num == this.elem[i]){	
            return true;
        }
    }
    return false;
}

运行结果:
contain


返回某个元素对应的下标,这个和上面的类似,只需将返回值更改即可:

public int index(int num){
    for (int i = 0; i < this.usedSize; i++) {
        if (num == this.elem[i]){
            return i;
        }
    }
    return -1;
}

运行结果:

index


在实现增加元素的方法前,我们需要先实现一个判断数组是否还能添加数据,也就是判断数组满了没有:

//返回true,说明数组中的数据个数和数组的长度相等,也就意味着数组满了
public boolean isFull() {
    return this.usedSize == this.elem.length;
}

数组满了,就需要扩充数组:

//扩充数组大小
public void resize() {
    //每次扩大一倍
    this.elem = Arrays.copyOf(this.elem, this.elem.length * 2);
}

扩充后:

扩充


接下来就可以实现增加元素的方法了,默认在数组最后添加:

public void add(int num) {
    //添加数据时,需要先判断数组中是否还有位置能够添加数据
    if (isFull()) {
        resize();
    }
    this.elem[this.usedSize] = num;
    this.usedSize++;
}

运行效果:

添加数据


在指定位置添加数据时,需要判断位置是否合理:

public boolean checkIndex(int pos) {
    if (pos < 0 || pos > this.usedSize) {
        throw new IndexOutOfException("位置不合法");
    }
    return true;
}

这里我们使用了一个自定义异常:

public class IndexOutOfException extends RuntimeException {
    public IndexOutOfException() {
    }

    public IndexOutOfException(String mes) {
        super(mes);
    }
}

现在就可以在指定位置添加元素了:

public void add(int pos, int data) {
    checkIndex(pos);
    if (isFull()) {
        resize();
    }
    for (int i = this.usedSize; i > pos; i--) {
        this.elem[i] = this.elem[i - 1];
    }
    this.elem[pos] = data;
    this.usedSize++;

}

运行效果:

指定位置添加


更改指定位置元素的值:

public void set(int pos,int data){
    checkIndex(pos);	//同样需要检查位置
    this.elem[pos]=data;
}

运行效果:

更改指定位置的值


删除第一次出现的关键字 key:

public boolean remove(int toRemove) {
    //先检查是否有这个数
    int index = index(toRemove);
    if (-1 == index) {
        System.out.println("没有这个数据");
        return false;
    } else {
        for (int i = index; i < this.usedSize - 1; i++) {
            this.elem[i] = this.elem[i + 1];
        }
        this.usedSize--;
        this.elem[usedSize] = 0;//这里是基本数据类型,置为 0就行,如果为引用类型,需要置为空
        return true;
    }
}

运行结果:

删除第一次出现的元素

ArrayList

ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它没有固定大小的限制,我们可以添加或删除元素。

ArrayList 是以泛型方式实现的,使用时需要先实例化。
ArrayList 实现了 RandomAccess 接口,所以 ArrayList 支持随机访问。
ArrayList 实现了 Cloneable 接口,所以 ArrayList 可以克隆。
ArrayList 实现了 Serializable 接口,所以 ArrayList 支持序列化。
ArrayList 底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表。

ArrayList的构造

无参构造:

无参构造ArrayList


指定初始容量构造:

指定容量构造ArrayList


利用其它列表构造:

利用其它列表构造ArrayList

注意: 如果在省略了类型,那么什么类型的数据都可以存放,这就可能会错误存取一些数据。

无数据类型

ArrayList常见操作

ArrayList 是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。

添加元素 add():

add方法


访问元素 get():

get方法


修改元素 set():

set方法


删除元素 remove():

remove方法


计算大小 size():

计算大小


遍历列表:

遍历


截取部分 list:

List<E> subList(int fromIndex, int toIndex)

截取subList

除了上面常用的操作方法,ArrayList 还提供了很多其他的操作方法,需要时可以到下面的网址查询:ArrayList 操作方法

ArrayList案例(杨辉三角)

先给出题目链接,有兴趣的可以一试:LeetCode–118. 杨辉三角

题目描述:
杨辉三角

题目分析:

杨辉三角分析

根据分析我们可以得出下面这段代码:

public static void main(String[] args) {
    int[][] arr = new int[5][5];
    for (int i = 0; i < 5; i++) {
        for (int j = 0; j <= i; j++) {
            if (i == j || j == 0) {
                arr[i][j] = 1;
            } else {
                arr[i][j] = arr[i - 1][j] + arr[i - 1][j - 1];
            }
        }
    }

    for (int i = 0; i < arr.length; i++) {
        for (int j = 0; j <= i; j++) {
            System.out.print(arr[i][j]+" ");
        }
        System.out.println();
    }
}

运行结果:

二维数组的杨辉三角

但是,我们来看题目,并不是用数组随便做出来就行,有固定要求的:

题目要求

方法都大同小异,只不过写法上不同,先来看解析:

杨辉三角解析

代码:

public static List<List<Integer>> generate(int numRows) {
    //生成一个 lists,lists里存放list,每个list里的数据类型是Integer
    List<List<Integer>> lists = new ArrayList<>();
    for (int i = 0; i < numRows; i++) {
        //这里并不知道杨辉三角有几层,所以每次for循环就从新new一个
        List<Integer> list = new ArrayList<>();
        for (int j = 0; j <= i; j++) {
            if (j == 0 || j == i) {
                //和数组一样,只不过使用add方法把 1 加入到每个单独的list里
                list.add(1);
            } else {
                //其他值获取到也是使用add加入到list
                list.add(lists.get(i - 1).get(j) + lists.get(i - 1).get(j - 1));
            }
        }
        //每个list完成后添加到lists
        lists.add(list);
    }
    //返回lists即可
    return lists;
}

运行效果:

杨辉三角运行截图

Arraylist的问题

  1. ArrayList 使用连续的空间,这使得查询很快,只需给出下标即可查询某一元素,但也正因为是连续的空间,所以在任意位置插入和删除元素时,都会涉及其他元素的移动。
  2. 扩容时申请新的空间,拷贝数据,再释放旧的空间,会有不少的消耗。
  3. 扩容的时候,不是添加一个数据就只加一个数据的空间,而是按倍数增加空间,有时候只增加一个数据,剩下的空间就会浪费。

面对以上的问题,我们就需要使用其他的数据结构 ------ 链表。

  • 11
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值