[数据结构][Java]顺序表的使用和模拟实现(超详细!)
·
一、模拟实现
顺序表的底层结构是数组,我们通过自定义类MyArrayList模拟其核心功能,支持元素的增、删、改、查等操作:
- 顺序表结构需要的三个基本属性
public class MyArrayList {
private int[] elem; //数组,存储数据元素,这里以存储int类型为例
private int usedSize; //顺序表当前长度
private final int DEFAULT_SIZE = 10; //默认容量
}
- 提供构造方法
//不带参数构造方法
public MyArrayList() {
this.elem = new int[DEFAULT_SIZE];
}
//带参数构造方法(指定初始容量)
public MyArrayList(int capacity) {
this.elem = new int[capacity];
}
其中,usedSize默认为零,无需在构造方法中设置值
- 遍历打印
public void display() {
for(int i = 0; i < this.usedSize; i++) { //遍历数组
System.out.print(this.elem[i] + " ");
}
System.out.println(); //换行,美化输出
}
- 判断当前数组是否已满
public boolean isFull() {
return this.usedSize == this.elem.length;
}
当usedSize等于数组长度是,说明数组已满,需要扩容
- 新增元素,默认在最后新增
import java.util.Arrays;
public void add(int data) {
//数组已满需要扩容,以扩容到原长度2倍为例
if(isFull()) {
this.elem = Arrays.copyOf(this.elem, this.elem.length * 2);
}
this.elem[usedSize] = data;
this.usedSize++; //元素个数+1
}
- 指定位置新增元素,第一个元素下标为0
public void add(int pos, int data) {
//判断位置是否合法
if(pos < 0 || pos > usedSize) {
System.out.println("插入位置不合法!"); //此处也可抛出异常
}
//数组已满需要扩容,以扩容到原长度2倍为例
if(isFull()) {
this.elem = Arrays.copyOf(this.elem, this.elem.length * 2);
}
//从插入位置开始,每个元素需要向后移一位(空出位置插入新元素)
//从后向前移动,避免元素被覆盖
for(int i = this.usedSize - 1; i >= pos; i--) {
this.elem[i + 1] = this.elem[i];
}
this.elem[pos] = data; //在pos位置放入新元素
this.usedSize++; //元素个数+1
}

- 判断是否包含某个元素
public boolean contains(int toFind) {
//遍历数组查找
for(int i = 0; i < this.usedSize; i++) {
if(this.elem[i] == toFind) {
return true;
}
}
return false;
}
- 查找某个元素位置,返回元素第一次出现的位置
public int indexOf(int toFind) {
//遍历数组查找
for(int i = 0; i < this.usedSize; i++) {
if(this.elem[i] == toFind) {
return i;
}
}
return -1; //找不到返回-1
}
- 获取pos位置元素
public int get(int pos) {
//判断位置是否合法
if(pos < 0 || pos >= usedSize) {
System.out.println("位置不合法!"); //此处也可抛出异常
}
return this.elem[pos];
}
- pos位置元素更新为value
public void set(int pos, int value) {
//判断位置是否合法
if(pos < 0 || pos >= usedSize) {
System.out.println("位置不合法!"); //此处也可抛出异常
}
this.elem[pos] = value;
}
- 删除第一次出现的关键字key
public void remove(int key) {
//找到元素位置
int index = indexOf(key);
//处理元素不存在情况
if(index == -1) {
System.out.println("没有这个元素!"); //此处也可抛出异常
return;
}
//删除元素:让后面的元素一次向前移一位,覆盖掉要删除的元素
for(int i = index + 1; i < usedSize; i++) {
this.elem[i - 1] = this.elem[i];
}
//元素个数-1
this.usedSize--;
}
- 删除所有关键字key
public void removeAll(int key) {
int count = 0; //记录非key元素个数
//遍历数组,将非key元素放到count位置
for(int i = 0; i < this.usedSize; i++) {
if(this.elem[i] != key) {
elem[count++] = elem[i];
}
}
this.usedSize = count; //修改元素个数
}
- 获取顺序表长度
public int size() {
return this.usedSize;
}
- 清空顺序表
public void clear() {
this.usedSize = 0;
//若存储累类型为引用类型(如String, Object),需额外将元素置为null
//for(int i = 0; i < this.usedSize; i++) {
// this.elem[i] = null;
//}
//this.usedSize = 0;
}
[注意]
对于基本类型(int、double 等),直接置usedSize=0即可;
对于引用类型,需先将元素置为null(释放对象引用),再重置usedSize,避免内存泄漏。
二、用法
1. 常用构造方法
| 构造方法 | 说明 |
|---|---|
| ArrayList() | 无参构造,初始容量10 |
| ArrayList(Collection<? extends E> c) | 利用其他集合构建ArrayList |
| ArrayList(int capacity) | 制定初始容量 |
2. 顺序表中一些常用方法
| 方法 | 功能 |
|---|---|
| boolean add(E e) | 尾部新增元素 |
| void add(int index, E element) | 指定位置新增元素 |
| boolean contains(Object o) | 判断是否包含元素 |
| E get | 获取指定位置元素 |
| int indexOf(Object o) | 查找元素第一次出现的位置(未找到返回 - 1) |
| E remove(int index) | 删除指定位置元素(返回被删除元素) |
| boolean remove(Object o) | 删除第一次出现的元素 |
| E set(int index, E element) | 修改指定位置元素,返回旧元素 |
| int size() | 返回元素个数 |
| void clear() | 清空顺序表 |
| boolean isEmpty | 判断是否为空 |
3. 遍历方法
- for 循环
- for each 循环(无法获取下标,适合只遍历不修改)
for(Integer num : list) {
System.out.print(num + " ");
}
- 迭代器
以Integer类型为例:
import java.util.Iterator();
Iterator < Integer > it = list.iterator();
while(it.hasNext()) {
System.out.print(it.next() + " ");
}
三、总结
顺序表是线性表的一种实现方式,底层通过数组存储数据,元素在内存中连续存放。通过对顺序表中方法的模拟实现,我们可以清楚地知道顺序表有如下特点:
- 元素按属性排列,可通过下标直接访问
- 插入/删除元素师需要移动大量元素,效率较低
- 容量固定,可动态扩容
因此,顺序表适合一些查询操作频繁,插入/删除操作较少的场景。
更多推荐



所有评论(0)