一. 顺序表的定义
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
注:该数组实现的思想和 ArrayList 类 里的相应方法 在实现上类似, 有助于理解 ArrayList 类 的用法
二. 接口的实现
首先,我们需要认识到,一个顺表拥有哪些功能。比如:增删查改判定等,那这是我们可以借助接口来实现这些功能。
public interface IList {
// 新增元素,默认在数组最后新增
public void add(int data);
// 在 pos 位置新增元素
public void add(int pos, int data);
// 判定是否包含某个元素
public boolean contains(int toFind);
// 查找某个元素对应的位置
public int indexOf(int toFind);
// 获取 pos 位置的元素
public int get(int pos);
// 给 pos 位置的元素设为 value
public void set(int pos, int value);
//删除第一次出现的关键字key
public void remove(int toRemove);
// 获取顺序表长度
public int size();
// 清空顺序表
public void clear();
// 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
public void display();
//判断顺序表是否满
boolean isFull();
//判断顺序表是否为空
boolean isEmpty();
}
三. 成员变量
我们还需要一些成员变量来助我们实现顺序表。
比如:public int[] elem 数组作为顺序表的载体
public int usedSize 用于记录数组的有效数据
public static final int DEFAULT_CAPACITY 作为数组的默认大小
以及 public MyArrayList() 构造方法来初始化elem数组
public class MyArrayList implements IList {
public int[] elem;
public int usedSize; //记录数组的有效数据
public static final int DEFAULT_CAPACITY = 5; //默认容量
//初始化elem数组
public MyArrayList() {
elem = new int[DEFAULT_CAPACITY];
}
}
四. 实现接口当中的方法
4.1 public void add(int data)方法
该方法的作用即是在数组的尾部插入新元素,即所谓的尾插法。但需要注意的是,因为前面我们通过实现构造方法来初始化elem数组,使得该数组有一定的空间,所以我们需要在每次插入新元素之间线判断数组是否满,如若满了,则需扩容。
那么 if(isFull())语句的所用则是判断是否满,如果满,则用 Arrays 的 copyof() 方法来进行2倍扩容。注:isFull()方法在后面会有介绍
之后则将 data 赋值到 elem 数组的 usedSize 位置上, 然后 usedSize++ 来增加数组的有效数据。
/**
* 新增元素,默认在数组最后新增
* @param data
*/
@Override
public void add(int data) {
// 先判断是否满 满了要扩容
if (isFull()) {
elem = Arrays.copyOf(elem, 2 * elem.length );
}
elem[usedSize] = data;
usedSize++;
}
4.2 public boolean isFull() 方法
/**
* 判断顺序表是否满
* @return
*/
@Override
public boolean isFull() {
return usedSize == elem.length;
}
该方法的类型是 boolean, 如果 usedSize == elem.length, 则返回true , 否则为false。
用于给其他方法中的 if 语句 做判断。
4.3 public void add(int pos, int data) 方法
注意:该方法与前面的 add 方法有些许不同, 该方法是在指定位置插入, 不一定是尾插。
但在插入之间我们还需要判断插入的位置是否 越界 , 则我们可以新写一个 private void CheckPosofAdd(int pos) 方法 来判断, 之所以为 private, 是因为该方法只为 add 方法用。
如果 pos 位置越界, 则抛出异常。(我们还需要新创个类 public class EmptyException 来继承 RuntimeException )
public class EmptyException extends RuntimeException{
public EmptyException() {
}
public EmptyException(String msg) {
super(msg);
}
}
/**
* 检查pos位置 只对上面的方法使用
* @param pos
*/
private void checkPosOfAdd(int pos){
if (pos < 0 || pos > usedSize) {
throw new PosException("pos位置为" + pos);
}
}
还要判断是否需要扩容 (同理前面)
最后, 用 for 循环来将 pos 位置之后的所有元素向后挪一位, 再将 data 赋值到 pos 位置, 然后 usedSiz ++ 即可。
/**
* 在 pos 位置新增元素
* @param pos
* @param data
*/
@Override
public void add(int pos, int data) {
//判断pos位置
checkPosOfAdd(pos);
// 判断是否满 满需要扩容
if (isFull()) {
elem = Arrays.copyOf(elem, 2 * elem.length );
}
for (int i = usedSize - 1; i >= pos; i--) {
elem[i + 1] = elem[i];
}
elem[pos] = data;
usedSize++;
}
4.4 public boolean contains(int toFind) 方法
该方法用于判断是否包含某个元素。
用 for 循环遍历数组, 如果找到 则返回 ture, 否则 false
/**
* 判定是否包含某个元素
* @param toFind
* @return
*/
@Override
public boolean contains(int toFind) {
for (int i = 0; i < elem.length; i++) {
if (toFind == elem[i]) {
return true;
}
}
return false;
}
4.5 public int indexOf(int toFind) 方法
该方法用于查找某个元素的位置
用 for 循环遍历数组, 如果所要查找的元素存在, 则返回此时的下标值, 即 i
/**
* 查找某个元素对应的位置
* @param toFind
* @return
*/
@Override
public int indexOf(int toFind) {
for (int i = 0; i < elem.length; i++) {
if (toFind == elem[i]) {
return i;
}
}
return 0;
}
4.6 public int get(int pos) 方法
该方法的作用是 获取 pos 位置的元素。
但在获取之前我们还需要检查数组是否为空
即 新写一个 public boolean isEmpty() 方法
/**
* 检查pos是否为空
* @return
*/
@Override
public boolean isEmpty() {
return usedSize == 0;
}
除此之外, 我们也需要检查 pos 是否合法, 不合法则抛出异常。(同理前面所提到的异常)
/**
* //检查pos是否合法
* @param pos
*/
private void checkPosOfGet(int pos) {
if (pos < 0 || pos >= this.usedSize) {
throw new PosException("pos位置不合法:" + pos);
}
}
4.7 public void set(int pos, int value) 方法
该方法用于将 pos 位置的值修改为 value
同理,在修改之前, 需要检查 pos 是否合法 , 以及顺序表是否为空。 没问题,则直接赋值。
/**
* 更新 pos 位置的值为 value
* @param pos
* @param value
*/
@Override
public void set(int pos, int value) {
checkPosOfGet(pos);
if (isEmpty()) {
throw new EmptyException("顺序表为空");
}
this.elem[pos] = value;
}
4.8 public void remove(int toRemove) 方法
该方法用于删除第一次出现的值 toRemove
首先,判断顺序表是否为空
然后, 调用 indexof() 方法, 找出 toRemove 的位置, 然后遍历数组, 将 toRemove 后面的元素全部往前挪一位
最后, usedSize -- 即可
/**
* 删除第一次出现的toRemove
* @param toRemove
*/
@Override
public void remove(int toRemove) {
if (isEmpty()) {
throw new EmptyException("顺序表为空,不能删除");
}
int index = indexOf(toRemove);
for (int i = index; i < usedSize - 1; i++) {
elem[i] = elem[i + 1];
}
usedSize--;
}
4.9 public int size() 方法
该方法用于获取数组长度
/**
* 获取顺序表长度
* @return
*/
@Override
public int size() {
return this.usedSize;
}
4.10 public void clear() 方法
清空顺序表 防止内存泄漏
/**
* 清空顺序表 防止内存泄漏
*/
@Override
public void clear() {
elem = null;
}
4.11 public void display() 方法
该方法用于打印顺序表
注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
/**
* 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
*/
@Override
public void display() {
for (int i = 0; i < usedSize; i++) {
System.out.println(elem[i] + " ");
}
System.out.println();
}
五. 全部代码
import java.util.Arrays;
public class MyArrayList implements IList {
public int[] elem;
public int usedSize; //记录数组的有效数据
public static final int DEFAULT_CAPACITY = 5; //默认容量
//初始化elem数组
public MyArrayList() {
elem = new int[DEFAULT_CAPACITY];
}
/**
* 新增元素,默认在数组最后新增
* @param data
*/
@Override
public void add(int data) {
// 先判断是否满 满了要扩容
if (isFull()) {
elem = Arrays.copyOf(elem, 2 * elem.length );
}
elem[usedSize] = data;
usedSize++;
}
/**
* 判断顺序表是否满
* @return
*/
@Override
public boolean isFull() {
return usedSize == elem.length;
}
/**
* 在 pos 位置新增元素
* @param pos
* @param data
*/
@Override
public void add(int pos, int data) {
//判断pos位置
checkPosOfAdd(pos);
// 判断是否满 满需要扩容
if (isFull()) {
elem = Arrays.copyOf(elem, 2 * elem.length );
}
for (int i = usedSize - 1; i >= pos; i--) {
elem[i + 1] = elem[i];
}
elem[pos] = data;
usedSize++;
}
/**
* 检查pos位置 只对上面的方法使用
* @param pos
*/
private void checkPosOfAdd(int pos){
if (pos < 0 || pos > usedSize) {
throw new PosException("pos位置为" + pos);
}
}
/**
* 判定是否包含某个元素
* @param toFind
* @return
*/
@Override
public boolean contains(int toFind) {
for (int i = 0; i < elem.length; i++) {
if (toFind == elem[i]) {
return true;
}
}
return false;
}
/**
* 查找某个元素对应的位置
* @param toFind
* @return
*/
@Override
public int indexOf(int toFind) {
for (int i = 0; i < elem.length; i++) {
if (toFind == elem[i]) {
return i;
}
}
return 0;
}
/**
* 获取 pos 位置的元素
* @param pos
* @return
*/
@Override
public int get(int pos) {
//检查pos是否合法
checkPosOfGet(pos);
//检查pos是否为空
if (isEmpty()) {
throw new EmptyException("顺序表为空");
}
return elem[pos];
}
/**
* 检查pos是否为空
* @return
*/
@Override
public boolean isEmpty() {
return usedSize == 0;
}
/**
* //检查pos是否合法
* @param pos
*/
private void checkPosOfGet(int pos) {
if (pos < 0 || pos >= this.usedSize) {
throw new PosException("pos位置不合法:" + pos);
}
}
/**
* 更新 pos 位置的值为 value
* @param pos
* @param value
*/
@Override
public void set(int pos, int value) {
checkPosOfGet(pos);
if (isEmpty()) {
throw new EmptyException("顺序表为空");
}
this.elem[pos] = value;
}
/**
* 删除第一次出现的toRemove
* @param toRemove
*/
@Override
public void remove(int toRemove) {
if (isEmpty()) {
throw new EmptyException("顺序表为空,不能删除");
}
int index = indexOf(toRemove);
for (int i = index; i < usedSize - 1; i++) {
elem[i] = elem[i + 1];
}
usedSize--;
}
/**
* 获取顺序表长度
* @return
*/
@Override
public int size() {
return this.usedSize;
}
/**
* 清空顺序表 防止内存泄漏
*/
@Override
public void clear() {
elem = null;
}
/**
* 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
*/
@Override
public void display() {
for (int i = 0; i < usedSize; i++) {
System.out.println(elem[i] + " ");
}
System.out.println();
}
}
public class EmptyException extends RuntimeException{
public EmptyException() {
}
public EmptyException(String msg) {
super(msg);
}
}
public interface IList {
// 新增元素,默认在数组最后新增
public void add(int data);
// 在 pos 位置新增元素
public void add(int pos, int data);
// 判定是否包含某个元素
public boolean contains(int toFind);
// 查找某个元素对应的位置
public int indexOf(int toFind);
// 获取 pos 位置的元素
public int get(int pos);
// 给 pos 位置的元素设为 value
public void set(int pos, int value);
//删除第一次出现的关键字key
public void remove(int toRemove);
// 获取顺序表长度
public int size();
// 清空顺序表
public void clear();
// 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
public void display();
//判断顺序表是否满
boolean isFull();
//判断顺序表是否为空
boolean isEmpty();
}
六. ArrayList使用
6.1 ArrayList的构造
ArrayList() | 无参构造 |
ArrayList(Collection<? extends E> c) | 利用其他 Collection 构建 ArrayList |
ArrayList(int initialCapacity) | 指定顺序表初始容量 |
public static void main(String[] args) {
// ArrayList创建,推荐写法
// 构造一个空的列表
List<Integer> list1 = new ArrayList<>();
// 构造一个具有10个容量的列表
List<Integer> list2 = new ArrayList<>(10);
list2.add(1);
list2.add(2);
list2.add(3);
// list2.add("hello"); // 编译失败,List<Integer>已经限定了,list2中只能存储整形元素
// list3构造好之后,与list中的元素一致
ArrayList<Integer> list3 = new ArrayList<>(list2);
// 避免省略类型,否则:任意类型的元素都可以存放,使用时将是一场灾难
List list4 = new ArrayList();
list4.add("111");
list4.add(100);
}
6.2 ArrayList 的 add(E e) 方法
该方法的实现思想类似于我们前面的 public void add(int data) 方法, 尾插 e
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
arrayList.add(4);
System.out.println(arrayList);
}
}
输出结果为:
6.3 ArrayList 的 add (int index, E element) 方法
该方法的实现思想类似于我们前面的 public void add(int pos, int data) 方法,
将 element 插入到 index 位置
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
arrayList.add(4);
arrayList.add(2, 17);
System.out.println(arrayList);
}
}
输出结果为:
6.4 ArrayList 的 remove (int index) 方法
该方法的实现思想类似于我们前面的 public void remove(int toRemove) 方法,
删除 index 位置元素
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(10);
arrayList.add(20);
arrayList.add(30);
arrayList.add(40);
arrayList.remove(2);
System.out.println(arrayList);
}
}
输出结果为:
6.5 ArrayList 的 contains (Object o) 方法
该方法的实现思想类似于我们前面的 public boolean contains(int toFind) 方法,
判断 o 是否在线性表中
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(10);
arrayList.add(20);
arrayList.add(30);
arrayList.add(40);
System.out.println(arrayList.contains(40));
}
}
输出结果:
6.6 ArrayList 的 indexof(Object o)方法
该方法的实现思想类似于我们前面的 public int indexOf(int toFind) 方法, 返回第一个 o 所在下标
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(10);
arrayList.add(20);
arrayList.add(30);
arrayList.add(40);
System.out.println(arrayList.indexOf(20));
}
}
输出结果:
6.7 ArrayList 的 clear() 方法
该方法的实现思想类似于我们前面的 public void clear() 方法, 清空数组
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(10);
arrayList.add(20);
arrayList.add(30);
arrayList.add(40);
System.out.println(arrayList);
System.out.println("=================");
arrayList.clear();
System.out.println(arrayList);
}
}
输出结果:
6.8 ArrayList 的 get(int index) 方法
该方法的实现思想类似于我们前面的 public int get(int pos) 方法,获取下标 index 位置元素
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(10);
arrayList.add(20);
arrayList.add(30);
arrayList.add(40);
System.out.println(arrayList.get(2));
}
}
输出结果:
6.9 ArrayList 的 set (int index, E element) 方法
该方法的实现思想类似于我们前面的 public void set(int pos, int value) 方法
将下标 index 位置元素设置为 element
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(10);
arrayList.add(20);
arrayList.add(30);
arrayList.add(40);
System.out.println(arrayList);
System.out.println("=====================");
arrayList.set(2, 78);
System.out.println(arrayList);
}
}
输出结果:
七. ArrayList 的 遍历
ArrayList 的 遍历 有三种方式, 分别为 for循环、foreach、使用迭代器
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
// 使用下标+for遍历
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i) + " ");
}
System.out.println();
// 借助foreach遍历
for (Integer integer : list) {
System.out.print(integer + " ");
}
System.out.println();
//迭代器
Iterator<Integer> it = list.listIterator();
while(it.hasNext()){
System.out.print(it.next() + " ");
} S
ystem.out.println();
}