文章目录
前言
本篇文章可以是数据结构的开篇作,数据结构作为数据存储方面的学科,其中的魅力也是让人着迷的。加油啊,各位!!
一、模拟实现顺序表
什么是顺序表?
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
成员变量
- 🤖用来存储数据的数组,array
- 🤖用来记录已存储的数据个数,size
public class MySeqList {
private int[] array;//存储数据的数组
private int size;//数据个数
}
1.构造方法
//无参数的构造方法
public MySeqList() {
//默认将底层容量大小设置为10
this.array = new int[10];
}
//有参数的构造方法
public MySeqList(int initcapacity) {
//将顺序表的底层容量设置为initcapacity
this.array = new int[initcapacity];
}
2.add方法——新增数据
- 在填加数据前,咱们要考虑是否还有剩余容量可以存储填加进来的数据,如果没有那么就会产生越界访问。
所以需要提供一个判断容量是否已满的方法。
不需要提供给用户,且只在类中使用,所以要用private封装起来。
//判断顺序表是否满了
private boolean isFull() {
if(size == array.length) {
return true;
}
return false;
}
如果数据满了,那么就要进行扩容,所以要提供一个扩容方法
不需要提供给用户,且只在类中使用,所以要用private封装起来。
//扩容方法,将容量扩大两倍
private void dilatancy() {
this.array = Arrays.copyOf(this.array,size*2);
}
1.默认新增方法
默认新增方法,即默认在数组最后进行存储
// 新增元素,默认在数组最后新增
public void add(int data) {
//如果顺序表满了,为其进行扩容
if(isFull()) {
dilatancy();
}
//将数据存储进去,并更新数据个数
array[size++] = data;
}
2.在指定位置新增方法
顺序表的数据一定要连续存储。
所以在插入数据前我们要判断指定位置是否合法。
如上图,下标0,1,2,3的位置都存储了数据,
那么可以在0,1,2,3,4的位置插入数据,其他位置均不合法。
private boolean judgeAddPos(int pos) {
if(pos < 0 || pos > size) {
return false;
}
return true;
}
如果位置不合法,那么我们可以抛出一个运行时异常。
public class SeqListIndexOutOfException extends RuntimeException{
public SeqListIndexOutOfException(String message) {
super(message);
}
}
所以在指定位置新增数据的方法就是:
// 在 pos 位置新增元素
public void add(int pos, int data) {
if(isFull()) {
dilatancy();
}
if(!judgeAddPos(pos)) {
throw new SeqListIndexOutOfException("输入位置不合法");
}
//将要插入数据位置及其后的数据,整体向后挪
for (int i = size; i > pos ; i--) {
array[i] = array[i-1];
}
array[pos] = data;//插入数据
size++;//更新数据个数
}
3. contains——判定是否包含某个元素
// 判定是否包含某个元素
public boolean contains(int toFind) {
//遍历所有数据,如果找到就返回true
for (int i = 0; i < size; i++) {
if(array[i] == toFind) {
return true;
}
}
return false;//走到这里说明数据中没有,返回false
}
4.indexOf——查找某个元素对应的位置
// 查找某个元素对应的位置
public int indexOf(int toFind) {
//遍历所有数据,找到返回下标
for (int i = 0; i < size; i++) {
if(array[i] == toFind) {
return i;
}
}
return -1;没找到返回-1
}
5.get——获取 pos 位置的元素
此时,也要对pos位置的合法性进行判断,判断规则与add方法不同,
因为是获取已有数据,所以pos的位置最大只能为size-1。
也就是0 < = pos < size
public int get(int pos) {
//如果位置不合法,抛出异常
if(pos < 0 || pos >= size) {
throw new RuntimeException("输入位置不合法");
}
return array[pos];//位置合法,返回pos位置上的数据
}
6.set——给 pos 位置的元素设为 value
与get方法相同,要判断pos位置是否合法。
public void set(int pos,int value) {
if(pos < 0 || pos >= size) {
throw new RuntimeException("输入位置不合法");
}
array[pos] = value;
}
7.remove——删除第一次出现的关键字key
public void remove(int toRemove) {
//遍历数据去找到toRemove
for (int i = 0; i < size; i++) {
if(array[i] == toRemove) {
//找到后,依次用后面的数据覆盖前面的数据
for (int j = i; j < size - 1; j++) {
array[i] = array[i+1];
}
size--;//更新数据个数
return;//只删除首个toRemove
}
}
}
8.size——获取顺序表长度
// 获取顺序表长度
public int size() {
return size;
}
9.clear——清空顺序表
// 清空顺序表
public void clear() {
this.size = 0;
}
10.disPlay——打印顺序表
public void disPlay() {
for (int i = 0; i < size; i++) {
System.out.print(array[i] + " ");
}
System.out.println();
}
二、java中提供的ArrayList
【说明】
- ArrayList是以泛型方式实现的,使用时必须要先实例化
- ArrayList实现了RandomAccess接口,表明ArrayList支持随机访问
- ArrayList实现了Cloneable接口,表明ArrayList是可以clone的
- ArrayList实现了Serializable接口,表明ArrayList是支持序列化的
- 和Vector不同,ArrayList不是线程安全的,在单线程下可以使用,在多线程中可以选择Vector或者CopyOnWriteArrayList
- ArrayList底层是一段连续的空间,并且可以动态扩容,是一个动态类型的顺序表
1.ArrayList的构造方法
- 无参构造
ArrayList()
ArrayList<Integer> arrayList = new ArrayList<>();
//构造一个空表
- 指定顺序表初始容量
ArrayList(int initialCapacity)
ArrayList<Integer> arrayList = new ArrayList<>(10);
//构造一个初始容量为10的表
- 利用其他 Collection 构建 ArrayList
ArrayList(Collection<? extends E> c)
参数列表指的是传入的可以是一个继承了接口Collection且数据类型相同的其他类,顺序表,链表,栈,队列等等。
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>(10);
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
arrayList.add(4);
arrayList.add(5);
arrayList.add(6);
ArrayList<Integer> arrayList1 = new ArrayList<>(arrayList);
for (int i = 0; i < arrayList1.size(); i++) {
System.out.print(arrayList1.get(i) + " ");
}
}
arrayList继承了Collection接口
arrayList与arrayList1的存储数据类型相同,
因此可以直接将arrayList当作参数传入,
此时,arrayList1按顺序将arrayList中的所有数据都存储了
2.ArrayList类中的常用方法
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
//1.尾插法,将数据插入到顺序表末尾
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
System.out.println("插入数据后:" + arrayList);
//2.将数据插入到1位置
arrayList.add(1,0);
System.out.println("在下标1位置插入数据后:" + arrayList);
//3.将ary中的所有数据按顺序尾插到arrayList中
ArrayList<Integer> ary = new ArrayList<>();
ary.add(1);
ary.add(2);
ary.add(3);
arrayList.addAll(ary);
System.out.println("将其他顺序表插入后:" + arrayList);
//4.删除index位置的数据
arrayList.remove(2);
System.out.println("删除下标2位置的数据后:" + arrayList);
//5.删除遇到的第一个 ‘1’
arrayList.remove(new Integer(1));
System.out.println("删除‘1’后:" + arrayList);
//此处的‘1’指的是一个Object类及其子类,
//此处如果输入基本类型int,那么会自动识别成index即 4.方法
//ArrayList中存储的是Object类,
//而插入时,输入的是基本类型,但是会自动给你装箱变为Integer类
//所以该方法不能输入基本类型,应输入包装类或自定义类,还包括8. 9. 10.方法
//两个remove构成了重载,传入的参数不同,执行结果也不同。
//6.获取下标 3 位置元素
int ret = arrayList.get(3);
System.out.println("下标3位置的数据:" + ret);
//7.将下标0位置的数据改为-1
arrayList.set(0,-1);
System.out.println("0下标改为-1后:" + arrayList);
//8.判断 ‘1’ 是否在线性表中
boolean flg = arrayList.contains(new Integer(1));
System.out.println("判断是否存在1这个数据" + flg);
//9.返回第一个 ‘1’ 所在下标
int index = arrayList.indexOf(new Integer(1));
System.out.println("第一个 ‘1’ 所在下标" + index);
//10.返回最后一个 ‘1’ 的下标
int lastIndex = arrayList.lastIndexOf(new Integer(1));
System.out.println("最后一个 ‘1’ 所在下标" + lastIndex);
//11.截取arraylist下标[1,5)位置的数据,返回的是一个List类的表
List<Integer> list = arrayList.subList(1,5);
System.out.print("截取到的表:");
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i) + " ");
}
System.out.println();
//12.清空表
arrayList.clear();
}
- 以上所有涉及到位置index的方法,输入的位置均都需要合法。
总结
以上就是今天要分享的数据结构开篇作《顺序表》的内容了,本文介绍了模拟实现的建议顺序表,以及ArrayList类的常用方法。
路漫漫,不止修身也养性。