参考《数据结构-java语言描述》
线性表的顺序表指的是用一组连续的存储单元依次存储线性表中的数据元素,通常采用数组来描述顺序表
顺序表的存储结构示意图
顺序表实现相关操作
1、初始化
顺序表的初始化是为顺序表分配一个预定义大小的内存空间,无参构造函数设置数组长度为maxSize,有参构造函数设置数组的长度为n,length设置为0,表明顺序表为空表没有数据元素。
public class ArraysequenceList<T> implements sequenceList<T> {
final int maxSize=10; //无参时数组的初始化长度
private T[] listArray;//存储元素的数组对象
private int length; //保存顺序表的当前长度即顺序表中数据元素的个数
//初始化
public ArraysequenceList() {
length=0;
listArray=(T[]) new Object[maxSize];
}
public ArraysequenceList(int n) {
length=0;
listArray=(T[])new Object[n];
}
2、插入
顺序表的插入过程
顺序表插入需要注意以下几点:
- 要检测插入位置的有效性,这里pos的有限范围是:1<= pos <=length+1,其中length为顺序表的长度(即顺序表中元素的个数)。当pos=length+1 表示插入位置为顺序表的尾部
- 顺序表中数据区域有listArray.length个存储单元,所以在向顺序表中做插入操作时先检测表空间是否满了,在表满的情况,需要重新分配两倍的内存空间,并把原数组中的数据元素复制到扩容数组中
- 注意数据的移动方向,从表尾开始,到pos位置结束,所有元素依次往后移动一位
- 往pos位置插入元素,对应数组中的索引为pos-1
- 顺序表长度为加1,返回true
public boolean add(T obj, int pos) {
//校验参数的有效性
if(pos<1 || pos>length+1){
System.out.println("pos值不合法");
return false;
}
//表满的时候对其进行扩容
/* if(length==listArray.length){
T[] temp=(T[])new Object[length*2];
for(int i=0;i<length;i++){
temp[i]=listArray[i];
}
listArray=temp;
}*/
if (length== listArray.length){
T[] temp=listArray;
listArray=(T[])new Object[length*2];
for(int i=0;i<length;i++){
listArray[i]=temp[i];
}
}
//从表尾开始,到pos位置结束,所有元素依次向后移动一位
for(int i=length;i>=pos;i--){
listArray[i]=listArray[i-1];
}
//往pos位置插入元素,对应数组中的索引为pos-1
listArray[pos-1]=obj;
//length加1
length++;
return true;
}
3、删除
上图为顺序表的删除过程
顺序表的删除操作需要注意以下几点
- 当表空时不能做删除操作
- 需要检查删除位置的有效性,删除位置pos的有效范围 1<= pos<=length
- 注意数据的移动方向,把删除位置pos之后的数据元素依次向前移动一位,最后顺序表的长度减1
- 返回已备份的被删除的元素
public T remove(int pos) {
if(isEmpty()){
System.out.println("表空,无法进行删除操作");
return null;
}
if(pos<1||pos>length){
System.out.println("pos参数非法");
return null;
}
T old=listArray[pos];
//这里i为什么是i<=length ,而不是小于length?原因把listArray[length-1]置空
for(int i=pos;i<=length;i++){
listArray[i-1]=listArray[i];
}
length--;
return old;
}
4、查找
注意点:
- 判断顺序表非空,如果表空则返回-1,没有查找到返回-1,该查找方法到了返回元素所在位置,而不是索引
- 最简单的方式,就是把需要查找的元素依次与顺序表中的元素依次进行比较!
public int find(T obj) {
if(isEmpty()){
return -1;
}
for(int i=0;i<length;i++){
if(listArray[i].equals(obj)){
return i+1;
}
}
return -1;
}
5、获取
注意点::
- 判单顺序表非空
- 判断pos值有效。1<= pos <= lenght
- 获取pos位置的数据元素,数组中对应的索引为pos-1
public T value(int pos) {
if(isEmpty()){
System.out.println("表空,无法进行获取操作");
return null;
}
if(pos<1 ||pos>length){
System.out.println("pos非法");
return null;
}
return listArray[pos-1];
}
6、修改
注意点:
- 判断顺序表非空
- 形参pos值有效 ,1<= pos <=length
- 修改pos位置的值,其索引为pos-1
public boolean modify(T obj, int pos) {
if(isEmpty()){
System.out.println("表空,无法进行修改操作");
return false;
}
if(pos<1 ||pos>length){
System.out.println("pos非法");
return false;
}
listArray[pos-1]=obj;
return true;
}
7、判空
当length等于0时,顺表为空表
public boolean isEmpty() {
return length==0;
}
8、求长度
返回顺序表中的长度length值即可
public int size() {
return length;
}
9、正序遍历
循环,依次输出数组中的元素
public void nextOrder() {
for(int i=0;i<length;i++){
System.out.print(listArray[i]+" ");
}
System.out.println();
}
10、销毁
public void clear() {
listArray=null;
length=0;
}
最后对ArrayList 中的add(int index, E element)方法进行解析
add(int index,E element)的源码如下。index表示索引,element插入的数据元素
public void add(int index, E element) {
rangeCheckForAdd(index); //检查index的有效性,无效则返回下标越界异常
ensureCapacityInternal(size + 1); // 当表满的时候对数组进行扩容
System.arraycopy(elementData, index, elementData, index + 1,
size - index); //数组间元素的复制操作,下面会有该方法的详细介绍
elementData[index] = element; //在索引位置插入
size++; //长度加1
}
public static native void arraycopy(Object src, int srcPos,Object dest, int destPos, int length);
* @param src the source array. 原数组
* @param srcPos starting position in the source array. 原数组的索引
* @param dest the destination array. 目标数组
* @param destPos starting position in the destination data. 目标数组的索引
* @param length the number of array elements to be copied. 复制原数组中数据元素的个数
* @exception IndexOutOfBoundsException if copying would cause
* access of data outside array bounds. 数组下标越界,目标数组的长度小于复制元素的个数
* @exception ArrayStoreException if an element in the <code>src</code>
* array could not be stored into the <code>dest</code> array
* because of a type mismatch. 类型不匹配
* @exception NullPointerException if either <code>src</code> or
* <code>dest</code> is <code>null</code>. 原数组和目标数组为null
从原数组(src)的指定索引(srcPos)开始截取length个数据元素,拷贝到目标数组(dest),从目标数组的指定索引(desPos)开始进行覆盖。简单的讲就是数组之间的复制。
简单示例:
public static void main(String[] args) {
char[]srcChar={'1','2','3','4','5','6'};
char[]tarChar={'7','8','9','A'};
System.arraycopy(srcChar,2,tarChar,0,3);
System.out.println(Arrays.toString(tarChar));
}
输出的结果:
简单讲解:
从原数组(srcChar)的指定索引2开始。截取3个数据元素。也就是截取原数组中的3,4,5这个三个数据元素。拷贝到目标数组(tarChar)中。从指定索引0开始,也就是从7开始,对目标索引中的7,8,9这三个数据元素进行覆盖。
接下来下面的代码段进行详解
System.arraycopy(elementData, index, elementData, index + 1,size - index);
从原数组(elementData)的索引(index)开始截取数组的长度(size-index)对目标数组(elementData)从(index+1)开始往后的数据元素进行覆盖。就相当于把elementData数组中的数据元素从索引位置开始往后移动了一位