什么是顺序表?
我们说它是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。同时它在逻辑上也是一条连续的直线。
顺序表又是什么用?
顺序表既然是一种表,那么它最基本的功能就是存储数据。除此之外,它还能对存储在里面的数据进行增删查改等操作。
顺序表和数组有什么区别?
相同点:
都是用一段连续的存储单元用来存放数据(物理地址和逻辑上都是线性的)。
不同点:
数组想要对元素进行增删查改等一系列动作时,就需要借助外部的一些方法或者自己手动去实现。而顺序表则不同,只要实例化了一个顺序表后,就能通过顺序表本身的一些公共接口(方法)去实现我们想要得增删查改等操作。
接下来具体实现一个顺序表:
首先了解一下在一般情况下顺序表里需要实现的公共接口(方法):
public class SeqList {
// 打印顺序表
public void display() { }
// 在 pos 位置新增元素
public void add(int pos, int data) { }
// 判定是否包含某个元素
public boolean contains(int toFind) { }
// 查找某个元素对应的位置
public int search(int toFind) { }
// 获取 pos 位置的元素
public int getPos(int pos) { }
// 给 pos 位置的元素设为 value
public void setPos(int pos, int value) { }
//删除第一次出现的关键字key
public void remove(int toRemove) { }
// 获取顺序表长度
public int size() { }
// 清空顺序表
public void clear() { }
}
注意:以上的方法在实现时,如果顺序表中没有我们需要的数,或者我们查找的位置不合法时,可以返回一个-1,因为一个数组的下标没有负数。同时在返回-1前也可以进行下提示。
具体代码实现:
import java.util.Arrays;
//创建一个顺序表
public class SeqList {
private int[] arrayList; //存放顺序表里的数据
private int userSize; //记录顺序表里数据的个数
//初始化数组
public SeqList(){
this.arrayList = new int[3]; //初始化给小一点,减少空间浪费。
}
// 打印顺序表
public void display() {
for (int i = 0; i < this.userSize; i++) {
System.out.print(this.arrayList[i]+" ");
}
}
// 在 pos 位置新增元素,注意:如果需要插入的位置紧挨着的前面没有数据,则将插入失败。
public void add(int pos, int data) {
//扩容
if(this.userSize == this.arrayList.length){
this.arrayList = Arrays.copyOf(this.arrayList,this.userSize+3);
}
if(pos < 0 || pos > this.userSize){
System.out.println("位置不合法"); //提示一下,表示输入的坐标有误。
return; //提前结束程序
}
//插入元素:将元素从最后一个开始向后移一位,将我需要插入的坐标空出来
for (int i = this.userSize-1; i >= pos ; i--) {
this.arrayList[i+1] = this.arrayList[i];
}
//在输入的坐标处插入元素
this.arrayList[pos] = data;
//顺序表的有效数据个数加1
this.userSize++;
}
// 判定是否包含某个元素
public boolean contains(int toFind) {
for (int i = 0; i < this.userSize; i++) {
if(this.arrayList[i] == toFind){
return true;
}
}
return false;
}
// 查找某个元素对应的位置
public int search(int toFind) {
for (int i = 0; i < this.userSize; i++) {
if(this.arrayList[i] == toFind){
return i;
}
}
//提示一下,然后返回-1
System.out.println("未发现该元素");
return -1;
}
// 获取 pos 位置的元素
public int getPos(int pos) {
//先判断输入的坐标是否合法
if(pos < 0 || pos >= this.userSize){
System.out.println("位置不合法");
return -1;
}
return this.arrayList[pos];
}
// 给 pos 位置的元素设为 value
public void setPos(int pos, int value) {
//同样先判断位置是否合法。
if(pos<0 || pos >= this.userSize){
System.out.println("位置不合法");
return;
}
//直接覆盖掉原来的数据。
this.arrayList[pos] = value;
return;
}
//删除第一次出现的关键字key
public void remove(int toRemove) {
int num = -1;
//先判断一下需要删除的数据,在顺序表中是否已存在
//存在,记录一下下标
//不存在,提示一下,结束程序。
for (int i = 0; i < this.userSize; i++) {
if(this.arrayList[i] == toRemove){
num = i;
break;
}
}
if(num == -1){
System.out.println("该数不存在");
return;
}
//从所记录的下标处开始,把后面的数据整体向前移动一位,覆盖掉我所需要删除的数据。
for (int i = num; i < this.userSize-1; i++) {
this.arrayList[i] = this.arrayList[i+1];
}
//数据总数减1
this.userSize--;
}
// 获取顺序表长度
public int size() {
//直接返回数据的个数
return this.userSize;
}
// 清空顺序表
public void clear() {
//注意:这里由于我们使用的是 int 型的数组,直接用下面的代码就可以了。
this.userSize = 0;
//当顺序表里面所存储的数据是引用类型(地址)时,需要将所有元素赋值null
//这是为了让里面的数据都不再指向原先所指向的对象。
//这样编译器才能把存放对象的空间给回收了。
}
}
顺序表的使用:
public class TestDemo01 {
public static void main(String[] args) {
//new一个顺序表
SeqList seqList = new SeqList();
//打印顺序表的内容
seqList.display();
//插入元素
seqList.add(0,1);
seqList.add(1,2);
seqList.add(2,3);
seqList.add(3,4);
seqList.display();
//判断是否包含某个元素
System.out.println("\n"+seqList.contains(2));
//查找某个元素对应的位置
System.out.println(seqList.search(3));
//获取 pos 位置的元素
System.out.println(seqList.getPos(3));
//给 pos 位置的元素设为 value
seqList.setPos(0,100);
seqList.display();
System.out.println();
//删除第一次出现的关键字key
seqList.remove(100);
seqList.display();
System.out.println();
//获取顺序表长度
System.out.println(seqList.size());
//清空顺序表
seqList.clear();
seqList.display();
}
}
运行结果:
通过以上结果,我们可以看到顺序表就成功实现了。
注意:在上面的顺序表中使用了大量的 this.xxx 这种操作,这里也简单说明一下 this 的作用:
this :就是“当前对象的引用”的意思,简单来说就是指当前类里面的成员变量,而不是方法里面的局部变量。主要是为了避免当前对象的某一成员变量和方法内的局部变量同名时,在方法内使用就会默认使用局部变量,而不是对象的成员变量。
同时使用 this 是一个很好的编程习惯,所以这里建议都给加上。