顺序表
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。顺序表属于线性表的一种
1.定义顺序顺序表
public class SeqList { public int[] elem; public int usedSize;//目前存储元素个数 //默认容量 private static final int DEFAULT_SIZE = 10; public SeqList() { this.elem = new int[DEFAULT_SIZE]; } }
上方定义类SeqList即是顺序表,定义elem数组存储数据,定义usedSize表示当前数组中包含多少个元素,定义DEFAULT_SIZE值为了在构造方法中将顺序表初始化为DEFAULT_SIZE大小的数组。
2.顺序表功能
public void display() { } // 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
public void add(int data) { } // 新增元素,默认在数组最后新增
public void add(int pos, int data) { } // 在 pos 位置新增元素
public boolean contains(int toValue) { return true; } // 判定是否包含某个元素
public int indexOf(int toValue) { return -1; } // 查找某个元素对应的位置
public int get(int pos) { return -1; } // 获取 pos 位置的元素
public void set(int pos, int value) { } // 给 pos 位置的元素设为 value
public void remove(int toRemove) { } //删除第一次出现的关键字key
public int size() { return 0; } // 获取顺序表长度
public void clear() { } // 清空顺序表
上面是顺序表当中常用的函数。
3.函数实现(java实现)?
打印顺序表display()函数
public void display() { for (int i = 0; i < this.usedSize; i++) { System.out.print(elem[i]+" "); } System.out.println(); }
代码解读:
打印函数顾名思义就是将顺序表中所有的数据打印出来。打印完的标准就是将顺序表中的数组完全输出,因此用usedSize作为终止条件,
新增元素函数add() (默认在数组最后新增)
public void add(int data) { if (this.usedSize == elem.length) { this.elem = Arrays.copyOf(elem, elem.length * 2; } elem[usedSize] = data; usedSize++; }/
代码解读:
此函数是增加顺序表中元素的函数。增加元素时,有一点需要注意,你的顺序表是否含有空间放入新的元素。使用函数isFull()判断,若没有满就正常增加,若已满,先对顺序表扩容,再进行增加。
如何判断顺序表满没满?当数组的长度等于数组中包含元素就为满。
当数据载入顺序表成功后,数组中包含元素个数usedSize就需要加1。
在 pos 位置新增元素add()函数(与上方函数构成重载)
public void add(int pos, int data) { if (pos < 0 || pos > usedSize) { throw new ArrayIndexException("下标非法,请检查"); } if (this.usedSize == elem.length) { this.elem = Arrays.copyOf(elem, elem.length * 2; } for (int i = usedSize - 1; i >= pos; i--) { elem[i + 1] = elem[i]; } elem[pos] = data; usedSize++; }
代码解读:
我们要判断传过来的下标的合法性;分析pos的取值范围:我们要把新增函数放到现在已有元素之间,因此我们可以知道,pos的范围应该是 0<=pos<usedSize.若给定的下标不合法,我们就抛出一个异常,让程序停下来。
再者这个函数功能也是添加,因此我们也需要判断顺序表空间的问题。
若我们插入的位置已有元素,我们需把从pos位置的元素向后移,为data数据挪开位置。
当数据载入顺序表成功后,数组中包含元素个数usedSize就需要加1。
判定是否包含某个元素contains()函数
public boolean contains(int toValue) { for (int i = 0; i < usedSize; i++) { if (elem[i] == toValue) { return true; } } return false; }
代码解读:
拿到需要找的数据toValue,遍历数组,将数组中的所有值与toValue进行比较,若数组中的值有与toValue相等,那么就返回true,否则返回false。
查找某个元素对应位置indexOf() 函数
public int indexOf(int toValue) { for (int i = 0; i < usedSize; i++) { if (elem[i] == toValue) { return i; } } return -1; }
代码解读:
同上方思想一致,拿到需要找的数据toValue,遍历数组,将数组中的所有值与toValue进行比较,若数组中的值有与toValue相等,那么就返回下标i,否则返回-1。
获取pos位置的元素get()函数
public int get(int pos) { if(pos<0||pos>=usedSize){ throw new ArrayIndexException("下标非法,请查看!"); } return elem[pos]; }
代码解读:
我们要判断下标是否合法,我们需要顺序表中的元素,因此pos不能超过顺序表中第一个元素的下标和最后一个元素的下标,即下标是0<=pos<usedSize,如果不在这个范围内,我们抛出一个异常,让程序停下来。
将pos位置的元素更新为value set()函数
public void set(int pos, int value) { if(pos<0||pos>=usedSize){ throw new ArrayIndexException("下标错误,请查看!"); } elem[pos] = value; }
代码解读:
同上方一样,我们要判断下标是否合法,我们需要顺序表中的元素,因此pos不能超过顺序表中第一个元素的下标和最后一个元素的下标,即下标是0<=pos<usedSize,如果不在这个范围内,我们抛出一个异常,让程序停下来。
最后将value赋到pos位置
删除第一个关键字key remove()函数
public boolean remove(int key) { int index = indexOf(key); if (index == -1) { System.out.println("没有这个数据"); return false; } for (int i = index; i < usedSize - 1; i++) { elem[i] = elem[i + 1]; } usedSize--; elem[usedSize] = 0; return true; }
代码解读:
我们先调用indexOf()函数,判断顺序表中是否有我们删除的值,若有找到这个值的下标,没有就返回false。有就以覆盖的方式,将index下标的元素用他后一个元素覆盖,一直往复到最后一个元素,因为删除了一个元素,因此将使用大小usedSize减一,因为在覆盖时,最后一个后面没有元素了,因此没有覆盖,我们将他置为0。
获得顺序表的长度size()函数
public int size() { return usedSize; }
代码解读:
当前数组中包含多少个元素,顺序表就是多长,因此顺序表的长度就是usedSize的大小。
清空顺序表clear()函数
public void clear() { usedSize = 0; }
代码解读:
因为所有的函数都是围绕这usedSisz进行构造的,我们只需将usedSize置为0,其他函数就无法进行运行(此处并非范例)
其中异常的定义:
package SeqList; public class ArrayIndexException extends RuntimeException{ public ArrayIndexException() { } public ArrayIndexException(String message) { super(message); } }
4.程序实例运行
package SeqList; import java.awt.*; public class test { public static void main(String[] args) { SeqList seqList =new SeqList(); //添加数据 seqList.add(1); seqList.add(2); seqList.add(3); seqList.add(4); seqList.add(5); //打印 System.out.print("当前数组元素:"); seqList.display(); //值所在的下标 System.out.print("值所在的下标:"); System.out.println(seqList.indexOf(3)); //是否包含这个值 System.out.print("是否包含这个值:"); System.out.println(seqList.contains(2)); //获得下标所在位置元素 System.out.print("获得下标所在位置元素:"); System.out.println(seqList.get(3)); //修改下标的值 System.out.print("修改下标的值:"); seqList.set(3,12); seqList.display(); //删除关键字key System.out.print("删除关键字key:"); seqList.remove(2); seqList.display(); //获得长度 System.out.print("获得当前顺序表长度:"); System.out.println(seqList.size()); } }
上方实例运行结果如下:
小节
顺序表也是分情况使用的,如何判断呢?总结了它的优缺点,可以作为参考。
优点:
无需为表示表中元素之间的逻辑关系而增加额外的存储空间。
可以快速地获取表中任意位置的元素。
缺点:
插入和删除操作需要移动大量元素(时间复杂度高)。
当线性表长度变化较大时,难以确定存储空间的容量。
造成存储空间的“碎片”。(当我们添加元素时,例如我们有101个元素,数组初始大小为100,扩容为1.5倍,初始大小无法存储全部元素,因此需要扩容,扩容为150大小,这就浪费了49个空间)