以下代码,只需要去查看扩容和缩容部分代码即可
/**
* 线性表之顺序表的扩容和缩容
*在容量已满的情况下,添加元素会报错,这个时候可以扩容
* 本例中判断元素已满的情况下,如果还要添加元素,会将容量变为之前的两倍
* 在删除元素后,可能会造成容量的浪费,因此可以缩小容量
* 本例中删除元素后,判断如果元素个数小于容量的四分之一,则将容量变为之前的二分之一
*
* 步骤:
* 第一步:创建一个方法,这个方法实现先保存原始数组,
* 然后将数组重新指定容量,再将保存的数组赋复制进来
*
* 第二部:在添加元素前判断是否满了,在删除元素后判断是否元素个数小于某个标准
* 然后执行上面的方法
*
*特别注意:
* 注意判断时候arr.length和自定义的方法length()不一样,
* 自己定义的表示返回顺序表的元素个数,是针对顺序表的
* 这里的arr.length是数组自带的,表示数组的长度,
* 即使数组没有填满也是表示初始化的长度,
* 没有填满的部分表现为null
*/
package mypackage;
import java.util.Arrays;
import java.util.Iterator;
//<T>泛型表示支持任意类型
//要实现遍历就要实现 Iterable接口
class SequenceList<T> implements Iterable<T>{
// 成员变量,数组和元素个数
private T[] arr;
private int N;
//构造方法,传入容量初始化顺序表,
public SequenceList(int capacity) {
this.arr = (T[])new Object[capacity];
//注意不能是this.arr =new T[capacity];,只能强转化
//初始化元素个数为0
this.N = 0;
}
// 清除
public void clear(){
N=0;
}
//判断是否为空
public boolean isEmpty(){
return N==0;
}
//获取元素个数
public int length(){
return N;
}
// 获取,根据索引获得元素
public T get(int i){
return arr[i];
}
// 添加元素
public void append(T t){
// 添加元素,如果元素已满了,将容量扩为2倍
// 注意这里的arr.length和上面定义的方法length()不一样,
// 自己定义的表示返回顺序表的元素个数
// 这里的arr.length数组自带的,表示数组的长度,
// 即使数组没有填满也是表示初始化的长度,
// 没有填满的部分表现为null
if(N>=arr.length){
resize(2*arr.length);
}
arr[N++]=t;
//或者
//arr[N]=t;
//N++
}
// 在某个位置插入元素
public void insert(int i,T t){
// 插入元素,如果元素已满了,将容量扩为2倍
// 注意这里的arr.length和上面定义的方法length()不一样,
// 自己定义的表示返回顺序表的元素个数
// 这里的arr.length数组自带的,表示数组的长度,
// 即使数组没有填满也是表示初始化的长度,
// 没有填满的部分表现为null
if(N>=arr.length){
resize(2*arr.length);
}
//将i之后的元素后移一个位置
for (int index=N;index>i;index--){
arr[index]=arr[index-1];
}
// 插入,插入要N++
arr[i]=t;
N++;
}
// 删除某个位置的元素并返回这个值
public T remove(int i){
// 先保存这个元素
T cunrrent=arr[i];
// 如果是删除的尾部的元素
if(i==N-1){
N--;
// 如果删除非尾部元素
}else if(i<N-1){
// 循环将这个元素的后一个元素往前移动一个位置
for (int index=i;index<N-1;index++){
arr[index]=arr[index+1];
}
// 同时N--
N--;
}
// 如果删除元素后剩余元素小于数组的四分之一,就缩小容量为原容量的二分之一
if(N<arr.length/4){
resize(arr.length/2);
}
return cunrrent;
}
// 查找,返回某个值的索引
public int indexOf(T t) {
for (int i = 0; i < N; i++) {
if (arr[i].equals(t)) {
return i;
}
}
// 如果没找到就返回-1
return -1;
}
// 为了输出好理解,重写 toString()
@Override
public String toString() {
// copyOf是复制arr的前N个元素,返回新的数组
return Arrays.toString(Arrays.copyOf (arr,N));
}
// 遍历的话,要重写此方法
@Override
public Iterator<T> iterator() {
// 返回的Iterator对象,创建一个内部类实现这个接口
return new SIterator();
}
// 创建一个内部类实现Iterator接口
public class SIterator implements Iterator{
// 定义一个遍历的游标
private int cusor;
public SIterator(){
// 初始化为0索引位置
this.cusor=0;
}
//重写两个方法
@Override
public boolean hasNext() {
// 这个方法判断是否超出最大索引,如果超出会停止遍历
return cusor<N;
}
@Override
public Object next() {
// 这个方法会遍历得每个元素
return arr[cusor++];
}
}
/*
@Override
public Iterator<T> iterator() {
// 也可以使用匿名内部类的方法
return new Iterator<T>() {
int cusor=0;
@Override
public boolean hasNext() {
return cusor<N;
}
@Override
public T next() {
return arr[cusor++];
}
};
}*/
// 改变数组的容量
public void resize(int newsize){
// 保存当前数据,注意这里其实是将整个数组的长度都赋值给了temp,包括null的
// 但是并不影响,因为后面的for循环,只是循环有元素的N个值,null的不会再赋值给arr
T[] temp=arr;
// 新的容量
arr=(T[])new Object[newsize];
// 循环将数据装进去
for (int i=0;i<N;i++){
arr[i]=temp[i];
}
}
}
//测试
public class Test {
public static void main(String[] args) {
// 创建一个顺序表,容量为4
SequenceList<Integer> list = new SequenceList<>(4);
// 添加元素元素
list.append(1);
list.append(2);
list.append(3);
list.append(4);
//初始容量为4,但是添加了5个元素,看会不会报错,没报错表示扩容成功
list.append(5);
System.out.println("添加元素后的顺序表"+list);
// 开始遍历
for(Integer ls:list){
System.out.println("遍历元素---"+ls);
}
// 返回元素个数
int length1 = list.length();
System.out.println("元素个数"+length1);
// 插入元素,如果满了就不能再插入
list.insert(0, 100);
System.out.println("在指定处插入元素100后的顺序表"+list);
// 删除元素
Object remove = list.remove(1);
System.out.println("删除指定索引处的元素是"+remove);
System.out.println("删除元素后的顺序表"+list);
// 根据索引获得元素
System.out.println("获取指定索引处的元素是"+list.get(0));
// 返回某个值的索引
System.out.println("指定元素对应的索引为"+list.indexOf(100));
// 清空
list.clear();
System.out.println("清空元素后的顺序表"+list);
// 是否为空
System.out.println("判断是否为空"+list.isEmpty());
}
}
结果: