文章主要介绍如何利用数组实现线性表“增删改查”基本操作。
目录
- 一、什么是数组?
- 二、什么是链表?
- 三、如何用数组实现线性表?
- 属性
- 扩容操作-grow
- 添加操作-add
- 获取操作-get
- 移除操作-remove
- 替换操作-replace
- 总结
一、什么是数组?
数组的特点:
1.有下标索引,基于下标操作速度很快
2.数组存储占用一块连续的空间
3.插入操作慢,且增加数据不能扩容
4.删除操作需要后置数据前移
二、什么是链表?
链表的特点:
1. 链表数据以节点的形式分散存储
2.不需要扩容
3.删除和插入操作很快
三、如何用数组实现线性表?
基本属性
1. 存储的数组
2.size:表示元素数量,即下一次要存储的下标
3.length:当前线性表的长度
代码如下(示例):
private Object[] values= {};
//元素数量,下一次要存储的下标
private int size;
//当前数组链表长度
private int length;
//默认的初始容量
private static final int def_length=10;
//简单的构造方法,不传入参数
public CArrayList() {
length=def_length;
values=new Object[length];
size=0;
}
//初始化方法
private void init(int initLength){
length=initLength;
values=new Object[length];
size=0;
}
//初始化数组链表长度,传入参数为自定义长度,分三种情况
public CArrayList(int initLength) {
//必须大于0
if(initLength<=0) {
throw new IllegalArgumentException("initLength<=0");
}
//小于等于10,默认初始化长度为10
if(initLength<=10) {
this.init(def_length);
}
//大于10并且不会太大,自己定义长度
if(initLength>10 && initLength< Integer.MAX_VALUE-100) {
this.init(initLength);
}
}
//初始化数组链表,传入数组作为参数
public CArrayList(Object[] initValues) {
if (initValues.length==0) {
this.init(def_length);
}else {
this.init(initValues.length);
for(int i=0;i<length;i++) {
Object initValue=initValues[i];
if(initValue!=null) {
values[size++]=initValue;//size=0,size+=1
}
}
}
}
添加操作-grow
当数组元素个数等于length时改变length,使其扩充至原来的1.5倍
代码如下(示例):
//扩容到原来的1.5倍
private void grow() {
int oldLength=length;
int newLength=oldLength+(oldLength >> 1);//扩充1.5倍
length=newLength;
Object[] newValues=new Object[length];
for(int i=0;i<oldLength;i++) {
newValues[i]=values[i];
}
//替换
values=newValues;
newValues=null;
System.out.println("扩容后长度为"+length);
}
添加操作-add
添加操作会使用到上面的扩容操作
代码如下(示例):
//添加元素
public void add(Object e) {
//万一不够长,就扩容
if(size==length) {
grow();
}
values[size++]=e;
}
//在特定位置插入元素
public void add(int index,Object e) {
if(index<0||index>size) {
throw new ArrayIndexOutOfBoundsException("index必须大于0小于等于"+size);
}
if(index==size) {
add(e);
}else {
if(size==length) {
grow();
}
int i=size;
while(i!=index) {
values[i]=values[i-1];
i--;
}
values[index]=e;
size++;
}
}
//尾部插入数组
public void addAll(Object[] arrays) {
for(int i=0;i<arrays.length;i++) {
add(arrays[i]);
}
}
//指定位置插入数组
public void addAll(int index,Object[] arrays) {
for(int i=0;i<arrays.length;i++) {
add(index++,arrays[i]);
}
}
//添加一个数组链表
public void addAll(CArrayList calist) {
for(int i=0;i<calist.size;i++) {
add(calist.values[i]);
}
}
获取操作-get
查找元素要注意下标检查
代码如下(示例):
//下标检查
private boolean checkIndex(int index) {
if(index<0||index>=size) {
throw new ArrayIndexOutOfBoundsException("index必须大于0小于"+size);
}
return true;
}
//根据下表查找元素对象
public Object get(int index) {
checkIndex(index);
return values[index];
}
//根据元素查找有无(适用于无重复元素的数组链表)
public int gete(Object e) {
for(int i=0;i<size;i++) {
if(get(i)==e) {
// System.out.println("该元素下标为"+i);
return i;
}
}
// System.out.println("没有该元素!");
return -1;
}
//获取元素的下标 - 多个下标
public int[] getElementindex(Object e){
int[] getIndex=new int[size];//定义返回数组,用于保存多个下标,最多不超过size
int index=0;
for(int i=0;i<size;i++) {
if(get(i)==e) {
getIndex[index++]=i;
}
}
if (index==0) {
System.out.println("没有该元素!");
return new int[] {};
}
int[] mannyIndex=new int[index];//定义一个新数组
mannyIndex=java.util.Arrays.copyOf(getIndex,index);//将原来数组截断,只把下标保存到新数组
getIndex=null;//将原数组删除
return mannyIndex;
}
删除操作-remove
删除元素后要记得把后面的数据前移,填补上删除的空缺
代码如下(示例):
//依据下标删除
public void remove(int index) {
checkIndex(index);
for(int i=index;i<size-1;i++) {
values[i]=values[i+1];
}
values[size-1]=null;
size--;
}
//依据元素删除,有可能删除多个
public void removeElement(Object e){
while(gete(e)!=-1) {
remove(gete(e));
}
}
//移除一段数据
public void removeAll(int si,int ei) {
if (si==ei) {
remove(si);
}else {
int left=si<ei?si:ei;
int right=si<ei?ei:si;
//删除right-left+1次起始点坐标的数
for(int i=right-left+1;i>0;i--) {
remove(left);
}
}
}
替换操作-replace
用到前面获取元素下标的方法
代码如下(示例):
//替换,可能替换多个
public void replace(Object oldValue, Object newValue){
int[] oldValueindex=getElementindex(oldValue);
if(oldValueindex.length!=0) {
for(int j=0;j<oldValueindex.length;j++) {
int index=oldValueindex[j];
values[index]=newValue;
}
}
}
//替换单个
public void replace(int index, Object newValue){
checkIndex(index);
values[index]=newValue;
}
//根据索引批量替换数据
public void replaceAll(int index,Object[] newValues){
for(int i=0;i<newValues.length;i++) {
replace(index++,newValues[i]);
}
}
总结
这里附上全部代码
package myplace;
public class CArrayList {
private Object[] values= {};
//元素数量,下一次要存储的下标
private int size;
//当前数组链表长度
private int length;
//默认的初始容量
private static final int def_length=10;
//简单的构造方法,不传入参数
public CArrayList() {
length=def_length;
values=new Object[length];
size=0;
}
//初始化方法
private void init(int initLength){
length=initLength;
values=new Object[length];
size=0;
}
//初始化数组链表长度,传入参数为自定义长度,分三种情况
public CArrayList(int initLength) {
//必须大于0
if(initLength<=0) {
throw new IllegalArgumentException("initLength<=0");
}
//小于等于10,默认初始化长度为10
if(initLength<=10) {
this.init(def_length);
}
//大于10并且不会太大,自己定义长度
if(initLength>10 && initLength< Integer.MAX_VALUE-100) {
this.init(initLength);
}
}
//初始化数组链表,传入数组作为参数
public CArrayList(Object[] initValues) {
if (initValues.length==0) {
this.init(def_length);
}else {
this.init(initValues.length);
for(int i=0;i<length;i++) {
Object initValue=initValues[i];
if(initValue!=null) {
values[size++]=initValue;//size=0,size+=1
}
}
}
}
//扩容到原来的1.5倍
private void grow() {
int oldLength=length;
int newLength=oldLength+(oldLength >> 1);//扩充1.5倍
length=newLength;
Object[] newValues=new Object[length];
for(int i=0;i<oldLength;i++) {
newValues[i]=values[i];
}
//替换
values=newValues;
newValues=null;
System.out.println("扩容后长度为"+length);
}
//添加元素
public void add(Object e) {
//万一不够长,就扩容
if(size==length) {
grow();
}
values[size++]=e;
}
//在特定位置插入元素
public void add(int index,Object e) {
if(index<0||index>size) {
throw new ArrayIndexOutOfBoundsException("index必须大于0小于等于"+size);
}
if(index==size) {
add(e);
}else {
if(size==length) {
grow();
}
int i=size;
while(i!=index) {
values[i]=values[i-1];
i--;
}
values[index]=e;
size++;
}
}
//尾部插入数组
public void addAll(Object[] arrays) {
for(int i=0;i<arrays.length;i++) {
add(arrays[i]);
}
}
//指定位置插入数组
public void addAll(int index,Object[] arrays) {
for(int i=0;i<arrays.length;i++) {
add(index++,arrays[i]);
}
}
//添加一个数组链表
public void addAll(CArrayList calist) {
for(int i=0;i<calist.size;i++) {
add(calist.values[i]);
}
}
//下标检查
private boolean checkIndex(int index) {
if(index<0||index>=size) {
throw new ArrayIndexOutOfBoundsException("index必须大于0小于"+size);
}
return true;
}
//根据下表查找元素对象
public Object get(int index) {
checkIndex(index);
return values[index];
}
//根据元素查找有无(适用于无重复元素的数组链表)
public int gete(Object e) {
for(int i=0;i<size;i++) {
if(get(i)==e) {
// System.out.println("该元素下标为"+i);
return i;
}
}
// System.out.println("没有该元素!");
return -1;
}
//获取元素的下标 - 多个下标
public int[] getElementindex(Object e){
int[] getIndex=new int[size];//定义返回数组,用于保存多个下标,最多不超过size
int index=0;
for(int i=0;i<size;i++) {
if(get(i)==e) {
getIndex[index++]=i;
}
}
if (index==0) {
System.out.println("没有该元素!");
return new int[] {};
}
int[] mannyIndex=new int[index];//定义一个新数组
mannyIndex=java.util.Arrays.copyOf(getIndex,index);//将原来数组截断,只把下标保存到新数组
getIndex=null;//将原数组删除
return mannyIndex;
}
//依据下标删除
public void remove(int index) {
checkIndex(index);
for(int i=index;i<size-1;i++) {
values[i]=values[i+1];
}
values[size-1]=null;
size--;
}
//依据元素删除,有可能删除多个
public void removeElement(Object e){
while(gete(e)!=-1) {
remove(gete(e));
}
}
//移除一段数据
public void removeAll(int si,int ei) {
if (si==ei) {
remove(si);
}else {
int left=si<ei?si:ei;
int right=si<ei?ei:si;
//删除right-left+1次起始点坐标的数
for(int i=right-left+1;i>0;i--) {
remove(left);
}
}
}
//替换,可能替换多个
public void replace(Object oldValue, Object newValue){
int[] oldValueindex=getElementindex(oldValue);
if(oldValueindex.length!=0) {
for(int j=0;j<oldValueindex.length;j++) {
int index=oldValueindex[j];
values[index]=newValue;
}
}
}
//替换单个
public void replace(int index, Object newValue){
checkIndex(index);
values[index]=newValue;
}
//根据索引批量替换数据
public void replaceAll(int index,Object[] newValues){
for(int i=0;i<newValues.length;i++) {
replace(index++,newValues[i]);
}
}
public static void main(String[] args) {
Object[] initValues= {1,2,2,3,3,3,4,4,4,4,5};
CArrayList calist=new CArrayList(initValues);
//向下标为2 的位置插入元素8,后面的元素向后移
//calist.add(2,8);
//在尾部添加一个数组
//Object[] addArrays= {11,22,33};
//calist.addAll(addArrays);
//在指定位置插入一个数组
//calist.addAll(2,addArrays);
//添加一个数组链表
//CArrayList addList=new CArrayList(addArrays);
//calist.addAll(addList);
//查找有无元素e
//calist.gete(5);
//获取多个下标
// int[] index=calist.getElementindex(3);
// for(int j=0;j<index.length;j++) {
// System.out.println("该元素下标为"+index[j]+" ");
// }
// System.out.println();
//删除元素
//calist.removeElement(2);
//删除一段数据
//calist.removeAll(3,4);
//替换
//calist.replace(4, 6);
//批量替换
//calist.replaceAll(5, addArrays);
//打印数组元素
for(int i=0;i<calist.length;i++) {
System.out.print(calist.values[i]+" ");
}
System.out.println();
System.out.println ("当前size:" + calist.size);
System.out.println ("当前length:" + calist.length);
}
}