知识重新梳理(数据结构与算法)顺序存储列表之线性表

  • 首先,感觉这几天做题的思路和基本概念有点懵逼,所以删掉之前的,自己从新整理认识一下它们的基本概念和用法。以待后面懵逼时来鞭策自己。

线性表的概念

  • 学习一个东西之前,你得先了解这个东西是什么?线性表,从字面意思上理解,它肯定是一种线性的,或者是“一对一”的关系。
  • 他的第一个数据元素没有前驱,这个数据元素被称为开始节点也乐意成为头节点;最后一个数据元素没有后续,这个数据元素称为终端节点或者尾结点;除了第一个和最后一个数据元素之外,其他数据元素有且仅有一个前驱和一个后续。
  • 它是零个或多个数据元素的有限序列。零个的时候,只不过是一个空表

实现

  • 概念了解完之后,下面开始用代码了解其实现方法。
  • 首先其重要的一个实现接口是List,list接口主要有以下几种定义:
    在这里插入图片描述
    定义接口方法
package com.snow.线性表;
/**
 * List是线性表的最终父接口 
 * */
public interface List<E> {
	
	/**
	 * 获取线性表中元素的个数(线性表的长度)
	 * @return 线性表中有效元素的个数
	 * */
	public int getSize();
	
	/**
	 * 判断线性表是否为空
	 * @return 是否为空的布尔类型值
	 * */
	public boolean isEmpty();
	
	/**
	 * 在线性表中指定的index角标处添加元素e
	 * @param index 指定的角标 0<=index<=size
	 * @param e	要插入的元素
	 * */
	public void add(int index,E e);
	
	/**
	 * 在线性表的表头位置插入一个元素
	 * @param e 要插入的元素 指定在角标0处
	 * */
	public void addFirst(E e);
	
	/**
	 * 在线性表的表尾位置插入一个元素
	 * @param e 要插入的元素 指定在角标size处
	 * */
	public void addLast(E e);
	
	/**
	 * 在线性表中获取指定index角标处的元素
	 * @param index 指定的角标 0<=index<size
	 * @return 该角标所对应的元素
	 * */
	public E get(int index);
	
	/**
	 * 获取线性表中表头的元素
	 * @return 表头元素 index=0
	 * */
	public E getFirst();
	
	/**
	 * 获取线性表中表尾的元素
	 * @return 表尾的元素 index=size-1
	 * */
	public E getLast();
	
	/**
	 * 修改线性表中指定index处的元素为新元素e
	 * @param index 指定的角标
	 * @param e 新元素
	 * */
	public void set(int index,E e);
	
	/**
	 * 判断线性表中是否包含指定元素e 默认从前往后找
	 * @param e 要判断是否存在的元素
	 * @return 元素的存在性布尔类型值
	 * */
	public boolean contains(E e);
	
	/**
	 * 在线性表中获取指定元素e的角标 默认从前往后找
	 * @param e 要查询的数据
	 * @return 数据在线性表中的角标
	 * */
	public int find(E e);
	
	/**
	 * 在线性表中删除指定角标处的元素 并返回
	 * @param index 指定的角标 0<=index<size
	 * @return 删除掉的老元素
	 * */
	public E remove(int index);
	
	/**
	 * 删除线性表中的表头元素
	 * @return 表头元素
	 * */
	public E removeFirst();
	
	/**
	 * 删除线性表中的表尾元素
	 * @return 表尾元素
	 * */
	public E removeLast();
	
	/**
	 * 在线性表中删除指定元素e
	 * */
	public void removeElement(E e);
	
	/**
	 * 清空线性表
	 * */
	public void clear();	
}

线性表接口定义完了之后,接下来就是它的顺序存储结构。

  • 概念:它指的是用一段地址连续的存储单元,依次存储线性表的数据元素。是不是跟数组很像?不只是像,其实就是用数组实现的。
  • 实现:查阅API发现,List接口的子类ArrayList它本身用数组形式实现了List的方法,并且有自己特有的方法。所以直接用ArrayList实现List接口方法且实现自己的方法就可以了。
  • ArrayList自己特有的方法:
    在这里插入图片描述
    代码实现:
package com.snow.线性表;

/**
 * 用顺序存储结构实现的List-顺序线性表-顺序表
 * */
public class ArrayList<E> implements List<E> {
	
	private static int DEFAULT_SIZE=10; //容器的默认容量
	private E[] data;	//存储数据元素的容器
	private int size;	//线性表的有效元素的个数 
						//data.length表示线性表的最大容量Capacity
	/**
	 *容量默认为10
	 * */
	public ArrayList(){
		this(DEFAULT_SIZE);
	}
	/**
	 * 容量为指定capacity
	 * */
	public ArrayList(int capacity){
		this.data=(E[]) new Object[capacity];
		this.size=0;
	}
	/**
	 * 将数组封装成线性表
	 * */
	public ArrayList(E[] arr){
		data=(E[]) new Object[arr.length]; //在内部创建一个新数组
		for(int i=0;i<arr.length;i++) {  //将外部传入的数组对内部的数组遍历赋值
			data[i]=arr[i];//赋值完成后如果外部修改传入的数组中的值,对内部的线性表的值是没有影响的
		}
		size=arr.length; 
	}
	
	@Override
	public int getSize() { //获取有效元素的长度
		
		return size;
	}

	@Override
	public boolean isEmpty() {//判空
		
		return size==0;
	}

	@Override
	public void add(int index, E e) { //在指定下标添加元素e
		if(index<0 || index>size) { //如果e的角标不在数组内 
                          
			throw new ArrayIndexOutOfBoundsException("角标越界");
		} 
		if(size==data.length) {  //如果有效元素的个数达到线性表的存储的最大容量进行扩容
			resize(2*data.length); //调用扩容函数
		}
		for(int i=size-1;i>=index;i--) {//插入时得先将元素后移 再插
			data[i+1]=data[i];
		}
		data[index]=e;  //插入指定下标位置
		size++;
	}
 //扩容 
	public void resize(int newLen) {
		E[] newData=(E[]) new Object[newLen];//改变data的长度
		for(int i=0;i<size;i++){
			newData[i]=data[i];
		}
		data=newData;//新数组的长度
	}
	
	@Override
	public void addFirst(E e) {//表头添加元素
		add(0,e);
	}

	@Override
	public void addLast(E e) { //尾部添加
		add(size,e);
	}

	@Override
	public E get(int index) { //获取指定角标的元素
		
		if(index<0||index>size-1){//判断角标是否越过有效元素的个数,或是数组最小下标位置
			throw new ArrayIndexOutOfBoundsException("get函数角标越界");
		}
		
		return data[index];
	}

	@Override
	public E getFirst() {  //获取头元素
		return get(0); //获取指定头位置的下标的元素

	}

	@Override
	public E getLast() {  //获取尾元素
		return get(size-1);//这里的尾元素不是数组最后一个元素,而是有效元素的最后一个位置的元素,size-1.
	}

	@Override
	public void set(int index, E e) {  //更改指定位置元素
		if(index<0 || index>size-1) {
			throw new ArrayIndexOutOfBoundsException("get函数角标越界");
		}
		data[index]=e;//直接替换
	}

	@Override
	public boolean contains(E e) { //是否包含e元素
		if(isEmpty()) {  //判空,数组为空,不包含
			return false;
		}
		for(int i=0;i<size;i++) {//不为空得话遍历查找 如果存在,则直接返回true,不再向下查找
			if(data[i]==e) { 
				return true;
			}
		}
		return false;
	}

	@Override
	public int find(E e) {//查找e元素
		if(isEmpty()){
			return -1;
		}
		for(int i=0;i<size;i++){
			if(data[i]==e){
				return i;
			}
		}
		return -1;
	}
	
	@Override
	public E remove(int index) {  //删除某一位置的元素
		if(index<0 || index>size-1) {  
			throw new ArrayIndexOutOfBoundsException("删除的角标越界");
		}
		E e=get(index); //将要删除的元素取出来
		for(int i=index;i<size-1;i++) {//将该元素位置后面的元素向前移动
			data[i]=data[i+1];
		}
		size--; //注意移动完了,有效元素也减一
//注意,这里内部数组中有效元素并没有减少,只是你有效元素位置指针指向了前一个位置,当前指向的元素和后一个元素是相同的,因为在移动元素的时候,是覆盖的移动,当下次再添加元素的时候,就将原来的覆盖了。
		if(data.length>DEFAULT_SIZE&&size<=data.length/4) {
			resize(data.length/2);
		} //缩容就是扩1/2
		return e;//返回删除的元素
	}

	@Override
	public E removeFirst() { //删除头元素
		return remove(0);
	}

	@Override
	public E removeLast() { //删除尾元素
		return remove(size-1);
	}

	@Override
	public void removeElement(E e) {
		int index=find(e);//找到该元素对应的下标
		if(index==-1){
			throw new IllegalArgumentException("删除元素不存在");
		}
		remove(index);//根据下标删除
	}

	@Override
	public void clear() {
		size=0; //有效元素置空
	}
	
	@Override
	public String toString() {  //打印线性表的方法,优化输出效果
		StringBuilder sb = new StringBuilder();
		sb.append("ArrayList:szie="+size+",capacity="+data.length+"\n");
		if(isEmpty()) {
			sb.append("[]");
		}else {
			sb.append('[');
			for(int i=0;i<size;i++) {
				sb.append(data[i]);
				if(i==size-1) {
					sb.append(']');
				}else {
					sb.append(',');
				}
			}
		}
		return sb.toString();
	}

	public int getCapacity(){ //获得该线性表当前的容量大小,也就是数组的大小
		return data.length;
	}
	public void swap(int i,int j){ //交换两个元素得角标

		E temp=data[i];
		data[i]=data[j];
		data[j]=temp;
	}
	@Override
	public boolean equals(Object obj) {  //重写equals方法,如果两个线性表有效元素个数相同,元素也一样视为相等
		if(obj==null) {
			return false;
		}
		if(obj==this) {
			return true;
		}
		if(obj instanceof ArrayList) { //判断传进来的对象是不是线性表
			ArrayList list = (ArrayList) obj; //将传进来的对象进行强转
			if(this.getSize()==list.getSize()) {  //比较两个线性表有效元素个数相同是否相同
				for(int i=0;i<size;i++) { //逐个比较每个元素是否相同
					if(data[i]!=list.data[i]) { //不一样 返回false
						return false;
					}
				}
				return true;
			}
			return false;
		}
		return false;
	}

}

  • 代码中也有注释,而且是边敲代码边写的注释。花了一个小时的整理,希望自己不要再忘记啦!!!!纯自己手打,测试已经通过。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值