1. 什么是顺序表
【概念】
- 顺序表底层是一个数组,其物理(内存)上连续,逻辑上也连续;
- 需要注意的是,不论是什么数据结构,在某个位置插数据时,不能隔空插,比如0下标有元素,1下标没有,2下标则不能插;
【与数组的区别】
- 比数组多了一个变量来计数; 原因是,按照常规思路计算数组大小(遇到0终止),若数组中有一个值就是0呢?所以用变量计数,插入一个数据,负责计数的变量就++;
2. 实现顺序表CRUD
2.1 题目
1.打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
public void display();
// 2.新增元素,默认在数组最后新增
public void add(int data);
// 3.在 pos 位置新增元素
public void add(int pos, int data);
// 4.判定是否包含某个元素
public boolean contains(int toFind) ;
// 5.查找某个元素对应的位置
public int indexOf(int toFind);
// 6.获取 pos 位置的元素
public int get(int pos);
// 7.给 pos 位置的元素设为 value
public void set(int pos, int value);
// 8.删除第一次出现的关键字key
public void remove(int toRemove) ;
// 9.获取顺序表长度
public int size();
// 10.清空顺序表
public void clear();
2.2 实现
【前期准备】
- 准备数组和计数器
- 准备内存
public class MyArrayList {
//只定义数组,没分配内存
private int elem[];
//计数器
private int usedSize;
//默认分配的内存大小
private static final int default_size = 10;
//代码调用者 自由指定内存大小 err
public MyArrayList(int size) {
this.elem = new int[size];
}
//若调用无参构造方法,则默认内存大小 err
public MyArrayList(){
this.elem = new int[default_size];
}
}
0. 打印顺序表
【代码逻辑】
- 找思路:遍历数组
- 写代码框架:无
- 填充代码:无
- 完善代码逻辑严谨性:无
【代码实现】
public void display() {
for (int i = 0; i < this.usedSize; i++) {
System.out.print(this.elem[i] + " ");
}
System.out.println();
}
1. 增(2道)
【需考虑】
- 数组是否满,满了扩容
- 判断位置合法性
1.1 新增元素,默认在数组最后新增
【代码逻辑】
- 找思路:在usedSize位置插数据,再usedSize++
- 写代码框架:无
- 填充代码:无
- 完善代码逻辑严谨性:数组是否扩容
【代码实现】
public void add(int data) {
//数组是否扩容
checkCapacity();
//在usedSize位置插数据
this.elem[this.usedSize] = data;
//usedSize++
this.usedSize++;
}
1.2 在 pos 位置新增元素
【画图】
【代码逻辑】
- 找思路:从数组末位置到pos位置的所有数往后移动一位;在pos位置加data
- 写代码框架
public void add(int pos, int data) {
//1. 循环将所有数据往后移动
for (int i = this.usedSize-1; i >= pos; i--) {
}
//2. 在pos位置加data
this.elem[pos] = data;
//3. usedSize++;
usedSize++;
}
- 填充代码
for (int i = this.usedSize-1; i >= pos; i--) {
this.elem[i+1] = this.elem[i];
}
- 完善代码严谨性
public void add(int pos, int data) {
//检查位置合法性
checkPosOnAdd(pos);
//是否需要扩容
checkCapacity();
...
...
}
【代码实现】
public void add(int pos, int data) {
//检查位置合法性
checkPosOnAdd(pos);
//是否需要扩容
checkCapacity();
//1. 从pos位置开始,所有数据往后移动
for (int i = this.usedSize-1; i >= pos; i--) {
this.elem[i+1] = this.elem[i];
}
//2. 在pos位置加data
this.elem[pos] = data;
//3. usedSize++;
usedSize++;
}
2. 查(4道)
【需考虑】
- 数组是否为空(usedSize 是否为0)
- 判断位置合法性
2.1 判定是否包含某个元素
【代码逻辑】
- 找思路:遍历顺序表,数组中的元素如果等于toFind,return true
- 写代码框架:无
- 填充代码:无
- 完善代码严谨性:判断顺序表是否为空
【代码实现】
public boolean contains(int toFind) {
//判断顺序表是否为空
isEmpty();
for (int i = 0;i<usedSize;i++) {
if (elem[i] == toFind) {
return true;
}
}
return false;
}
2.2 查找某个元素对应的位置
【代码逻辑】
- 找思路:遍历顺序表,数组中的元素如果等于toFind,return i
- 写代码框架:无
- 填充代码:无
- 完善代码严谨性:判断顺序表是否为空
【代码实现】
public int indexOf(int toFind) {
//判断顺序表是否为空
isEmpty();
for (int i = 0;i<usedSize;i++) {
if (elem[i] == toFind) {
return i;
}
}
return -1;
}
2.3 获取 pos 位置的元素
【代码逻辑】
- 找思路:直接return 数组的pos下标
- 写代码框架:无
- 填充代码:无
- 完善代码严谨性:判断顺序表是否为空;判断pos位置合法性
【代码实现】
public int get(int pos) {
//判断pos位置合法性
checkPosOnAdd(pos);
//判断顺序表是否为空
isEmpty();
return this.elem[pos];
}
2.4 获取顺序表长度
【代码逻辑】
- 找思路:usedSize是计数器,直接return usedSize;
- 写代码框架:无
- 填充代码:无
- 完善代码严谨性:无
【代码实现】
public int size() {
return this.usedSize;
}
3. 改(1道)
【需考虑】
- 数组是否为空(usedSize 是否为0)
- 判断位置合法性
3.1 给 pos 位置的元素设为 value
【代码逻辑】
- 找思路:将数组pos下标改为value
- 写代码框架:无
- 填充代码:无
- 完善代码严谨性:判断pos位置合法性;判断顺序表是否为空
【代码实现】
public void set(int pos, int value) {
//检查pos合法性
checkPosOnAdd(pos);
//判断顺序表是否为空
isEmpty();
//将pos位置改为value
this.elem[pos] = value;
}
4. 删(2道)
【需考虑】
- 数组是否为空(usedSize 是否为0)
- 判断位置合法性
4.1 删除第一次出现的关键字key
【画图】
【代码逻辑】
- 找思路:找key下标,删除是从key开始遍历顺序表,key后一个数据覆盖key
- 写代码框架:无
- 填充代码:无
- 完善代码严谨性:(i+1)+1>=usedSize,会越界访问;判断顺序表是否为空
【代码实现】
public void remove(int key) {
//找到key下标,如果返回值为-1,抛异常
int ret = indexOf(key); //indexOf中包含isEmpty
if (ret == -1) {
throw new RuntimeException();
}
//删除key
for (int i =ret;i<usedSize-1;i++) {
this.elem[i] = this.elem[i+1];
}
this.usedSize--;
}
4.2 清空顺序表
【代码逻辑】
- 找思路:usedSize是计数器,直接将usedSize置为0;
- 写代码框架:无
- 填充代码:无
- 完善代码严谨性:无
【代码实现】
public void clear() {
this.usedSize = 0;
}