文章主要介绍如何利用数组实现线性表“增删改查”基本操作。


目录

  • 一、什么是数组?
  • 二、什么是链表?
  • 三、如何用数组实现线性表?
  • 属性
  • 扩容操作-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);
			
		}
		
		
}