顺序表
大家好,今天为大家讲解一下属于数据结构中的最最最简单的一种结构——顺序表,在讲解顺序表之前,先大概简单的了解一下什么是集合?为什么要有集合?集合与数组的区别?
什么是集合:
集合就是一个存放数据的容器,准确来说就是存放数据引用的容器;
集合类存放的都是对象的引用,而不是对象的本身;
集合类型主要有三种:set(集)、list(列表)、map(映射)
集合的特点:
集合是用于存储对象的容器,对象是用来封装数据的,对象多了也就需要集中式管理
对象的多少是不确定的,所以集合不用定义大小
集合和数组的区别:
数组是固定长度的,集合是可变长度的;
数组可以存储基本数据类型,也可以存储引用数据类型;集合只能存储引用数据类型;
数组存储的元素必须是同意一个数据类型;集合存储对象可以是不同数据类型;
List的定义
List是一种线性存储结构,是有n个具有相同特性的的数据组成的优先序列;而栈、队列、顺序表、链表都是线性表;下面要讲解的就是关于顺序表的内容:
顺序表:顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性存储结构;:
首先,顺序表是一个序列,在有多个元素时,除了第一个元素无前驱,最后一个元素无后继,其余每一个元素都有一个前驱和后继;我相信许多书上也都是这样说的;前驱和后继什么意思呢?就像是在等红灯时,许多车都排在一个车道上,除了第一个车前面没有车,最后一个车后面没有车,而中间每一个车的前面和后面都有一个车,这就是说每一个车都有一个前驱和后继;
而数组也就是一个顺序表,当然至于“顺序表”这个定义有的小伙伴可能理解的不是太清楚,这里呢零零柒也提及一下,下面我举个例子你就明白了;
问大家一个问题,下面这张图是一个顺序表吗?,答案:不是,因为在上面提及过,顺序表除了第一个和最后一个元素之外,其余的元素都有一个前驱和后继;这句话希望大家好好的记住;
ArrayList
在实例化对象时,格式如下:
List是collection接口下的一个子接口,而ArrayList是实现List接口的一个集合类,这个类的底层是由数组实现的,既然是由数组实现,那就可以进行一系列的增删查改操作;下面先来介绍以下ArrayList的常用方法和构造方法;
ArrayList的构造方法
方法 | 解释 |
---|---|
ArrayList() | 无参构造方法 |
ArrayList(Collection<? extends E> c) | 利用其他Collection构建ArrayList |
ArrayList(int intialCapacity) | 指定顺序表的初始容量 |
举例说明
public static void main(String[] args) {
//利用不带哦参数的构造方法创建顺序表
List<Integer> list1 = new ArrayList<>();
list1.size();//大小为0
//利用带参数的构造方法创建顺序表
List<Integer> list2 = new ArrayList<>(10);
list2.size();//大小为10
list2.add(1);
list2.add(2);
list2.add(3);
//利用其他的集合构建顺序表
List<Integer> list3 = new ArrayList<>(list2);
list3.add(9);
//list3 里面存储的是 1 2 3 9;
System.out.println(list3);
}
ArrayList常用方法
ArrayList的方法非常多,但是常用的也就那么几个,只要掌握了这些常用的方法,就可以应对大部分的学习和日常的工作,当再遇见不会的方法时,一查即可;
方法 | 解释 |
---|---|
boolean add(E e) | 尾插元素 e |
void add(int index, E element) | 将 element 插入到 index 位置 |
boolean addAll(Colection<? extends E> c) | 尾插集合 c 中的元素 |
E remove(int index) | 删除 index 位置的元素 |
boolean remove (Object 0) | 删除遇到的第一个 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 所在的下标 |
方法使用:
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
//顺序表中存储 1 2 3
System.out.println(list);
//在3下标的位置插入10
list.add(3, 10);
//但是如果直接在5下标的位置插入10就会报错
//list.add(5, 10);
//因为顺序表中的元素除第一个和最后一个外其余元素都必须有一个前驱和后继
System.out.println(list);
List<Integer> list2 = new ArrayList<>();
list2.addAll(list);
System.out.println(list2);
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(2);
list.add(5);
list.remove(1);
//结果集中剩下 1 3 2 5
System.out.println(list);
//删除遇到的第一个2
list.remove(2);
System.out.println(list);
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
//获取2下标的元素
list.get(4);
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
//将2下标位置的元素设置成10;
list.set(2, 10);
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
//判断2是否在顺序表中
boolean ret = list.contains(2);
System.out.println(ret);
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(2);
//返回第一个2所在位置的下标
int ret = list.indexOf(2);
System.out.println(ret);
}
ArrayList常用方法的模拟实现
要想真正理解ArrayList,必须亲自模拟实现他的众多方法;下面请看代码
public class MyArrayList {
private int[] array;
private int size;
private int index;
private final int DEFAULT_SIZE = 3;
// 默认构造方法
public MyArrayList(){
this.array = new int[DEFAULT_SIZE];
}
// 新增元素,默认在数组最后新增
public void add(int data) {
//判断数组是否满
if(isFull()) {
//扩容
resize();
}
array[size] = data;
size++;
}
public boolean isFull(){
return array.length == size;
}
public void resize(){
this.array = Arrays.copyOf(array, array.length+2);
}
// 在 pos 位置新增元素
public void add(int pos, int data) {
if(pos < 0 && pos > size) {
System.out.println("位置不合法");
return;
}
//判断数组是否装满
if(isFull()) {
resize();
}
for(int i = size-1; i>=pos; i--) {
array[i+1] = array[i];
}
array[pos] = data;
size++;
}
// 判定是否包含某个元素
public boolean contains(int toFind) {
//判断数组是否为空
if(size() == 0) {
return false;
}
for(int i = 0; i<size; i++) {
if(array[i] == toFind) {
return true;
}
}
return false;
}
// 查找某个元素对应的位置
public int indexOf(int toFind) {
//判断数组是否为空
if(size() == 0) {
return -1;
}
for(int i = 0; i<size; i++) {
if(array[i] == toFind) {
return i;
}
}
return -1;
}
// 获取 pos 位置的元素
public int get(int pos) {
if(size()==0) {
return -1;
}
if(pos > size()) {
return -1;
}
return array[pos];
}
// 给 pos 位置的元素设为 value
public void set(int pos, int value) {
if(size() == 0) {
return;
}
if(pos >= size()) {
return;
}
array[pos] = value;
}
//删除第一次出现的关键字key
public void remove(int toRemove) {
//判断数组是否为空
if(size() == 0) {
return;
}
for(int i = 0; i<size; i++) {
if(array[i]== toRemove) {
delete(i);
size--;
return;
}
}
}
public void delete(int pos) {
for(int i = pos; i<size-1; i++) {
array[i] = array[i+1];
}
}
// 获取顺序表长度
public int size() {
return array.length;
}
// 清空顺序表
public void clear() {
this.array = null;
size = 0;
}
// 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
public void display() {
if(size() == 0) {
return;
}
for(int i = 0; i<size; i++){
System.out.print(array[i] + " ");
}
}
}
ArrayList的说明
说明一:
ArrayList是以泛型方式实现的,使用时必须要先实例化
说明二:
ArrayList实现了Random接口,表明ArrayList是一种随机访问模式的;
说明三:
ArrayList实现了Cloneable接口,表明ArrayList是可以被clone的;
说明四:
ArrayList不是线程安全的,在单线程下可以使用;
说明五:
ArrayList的底层是一段连续的空间,是由数组实现的,并且是一个动态型的顺序表,因为,当使用默认的构造方法创建ArrayList时,该数组会先被初始为空数组,当首次向里面添加数据时,该数组会再被扩容到长度为10的数组,当然,.也可以调用它带参数的构造方法,指定数组的容量,如果向数组中添加的元素超过了数组的长度限制,也会出发自动扩容,而这里的自动扩容其实是数组的拷贝,ArrayList也支持缩容,但是不支持自动缩容,如果想要缩减ArrayList的容量,可以调用它的trimToSize方法;
扩容机制源代码讲解:
有的同学可能认为,这不就是一个数组么,有什么难的呢,还需要写这么一大篇文章,但是在这里零零柒想说的是,不仅难的知识要去仔细揣摩,简单的知识更应该做到了如指掌,永远要保持一个空杯心态,静下心来学习,一点一点的进步;
以上就是零零柒对顺序表的理解,您学废了么😎,如果有什么建议欢迎大家私聊我!!!