数据结构-顺序表Java简单实现

本文详细解析了顺序表的数据结构原理及其实现方法,包括基本操作如添加、删除、获取等的时间复杂度分析,并提供了完整的Java代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、顺序表的优缺点

顺序表是用数组来实现,其优缺点如下:

(一)优点

getset所花费的时间短,时间复杂度为O(1)。

(二)缺点:

addremove所花费的时间长,最坏的情况是在0位置进行,时间复杂度为O(N);最好的情况是在末端进行,时间复杂度为O(1)。

二、线性结构的基本操作

一般地有add、remove、get、set、size、isEmpty、indexOf、clear、trimToSize、ensureCapaticy。

(一)成员变量

先来看看成员变量先。

/**
	 * 数组默认初始化大小
	 */
	private final static int DEFAULT_CAPACITY = 10;
	
	/**
	 * 用于存放元素的数组
	 */
	private T[] mArray;
	
	/**
	 * 当前有效元素的个数
	 */
	private int mCurrentSize;
	
	/**
	 * 记录改动过的次数
	 */
	private int mModCount;

(二)add

要往List中添加一个元素,后面的元素依次向后移动一个位置,腾出一个位置出来,再把元素插入到这个腾出来的位置中,如果把元素添加在List末端则不需要移动元素,直接插入到末端,如果添加的时候空间不够得动态申请更大的空间才能存放;下图是把S元素添加到List中第三个位置的示意图(用画图工具画的,粗糙了点,随便吐槽),未添加之前List的有效元素有5个,第一步是把最后一个元素(索引为4的T)往后移动一个位置(索引为5的位置),第二步是把索引3的元素(R)往后移动到索引为4的位置,第三步是把索引为2的元素(E)往后移动到索引为3的位置,最后把S元素添加到索引为2的位置,添加后List中就有6个元素;举个栗子:可以想象成排队,小明非要插队进来,后面的人就要往后退一步,从最后面的人开始退。


/**
	 * 添加元素到表末尾
	 * @param t 要添加的元素
	 * @return 添加是否成功
	 */
	public boolean add(T t) {
		add(size(), t);
		return true;
	}
	
	/**
	 * 添加元素到指定位置
	 * @param pIndex 指定的位置
	 * @param t 要添加的元素
	 */
	public void add(int pIndex, T t) {
		if (pIndex < 0 || pIndex > size()) {
			throw new ArrayIndexOutOfBoundsException(pIndex);
		}
		//检查空间是否足够
		if (size() == mArray.length) {
			//加1是保证当size为0的情况也能扩容
			ensureCapaccity(size() * 2 + 1);
		}
		for (int i = size(); i > pIndex; i--) {
			mArray[i] = mArray[i-1];
		}
		mArray[pIndex] = t;
		mCurrentSize++;
		mModCount++;
	}

(三)remove

删除List中的一个元素,一般要把要删除的元素取出来存放到一个位置,这个被删除元素后面的元素依次先前移动,如果是删除List中最后一个元素则不需要移动元素,最后把被删除的元素返回,下图是把索引为2的M元素从List中删除,第一步是把要删除的元素先存到另一个地方,第二步是把索引为3的元素(O)往前移动到索引为2的位置,第三步是把索引为4的元素(V)向前移动到索引为3的位置,第四步是把索引为5的元素(E)向前移动到索引为4的位置,然后把索引为5的位置置空,最后把M元素返回;举个栗子:可以想象成排队,老师看不惯小明插队行为,来叫小明去办公室一趟,先把小明揪出来,然后后面的人往前移动,最后小明被拖到办公室。


/**
	 * 删除在表中指定位置的元素
	 * @param pIndex 元素的位置
	 * @return 被删除的元素
	 */
	public T remove(int pIndex) {
		if (pIndex < 0 || pIndex >= size()) {
			throw new ArrayIndexOutOfBoundsException(pIndex);
		}
		T _RmElement = mArray[pIndex];
		for(int i = pIndex; i < size() - 1; i++) {
			mArray[i] = mArray[i + 1];
		}
		mArray[size() - 1] = null;
		mCurrentSize--;
		mModCount++;
		return _RmElement;
	}

(四)get

获取在表中指定位置的元素,下图是获取索引为3的元素;举个栗子:可以想想比如老师想看看队伍中排在第四个位置的是不是小明。


/**
	 * 得到在表中指定位置的元素
	 * @param pIndex 指定的位置
	 * @return 指定位置的元素
	 */
	public T get(int pIndex) {
		if (pIndex < 0 || pIndex >= size()) {
			throw new ArrayIndexOutOfBoundsException(pIndex);
		}
		return mArray[pIndex];
	} 

(五)set

设置在表中指定位置的元素,下图是把索引为3的e设置为E;举个栗子:可以想象成在排好队后,这时小刚才过来,老师看小明不顺眼把小明揪了出来,让小刚排在原来小明排的位置,小明不用排队。


/**
	 * 设置在表中指定位置的元素
	 * @param pIndex 指定的位置
	 * @param t 要设置的元素
	 */
	public void set(int pIndex, T t) {
		if (pIndex < 0 || pIndex >= size()) {
			throw new ArrayIndexOutOfBoundsException(pIndex);
		}
		mArray[pIndex] = t;
		mModCount++;
	}

(六)size

获取表的长度,下图表的长度就为4,;举个栗子:想象下在排队,老师想知道有多少个人在排。


/**
	 * 得到当前表的大小
	 * @return 返回当前表的大小
	 */
	public int size() {
		return mCurrentSize;
	}

(七)isEmpty

判断当前表是不是空的;举个栗子:想象下比如老师召集班里的同学去排队,老师想知道是不是没有人去排队。

/**
	 * 表当前是否是空表
	 * @return 是否是空表
	 */
	public boolean isEmpty() {
		return size() == 0;
	}

(八)indexOf

查找某个元素在表中的索引位置,下图是查找D在表中的索引位置;举个栗子:比如在排好的队里老师想知道小明站在哪个位置,以方便联系到他。


/**
	 * 查找指定元素在表中的位置
	 * @param o 要找的元素
	 * @return 元素在表中的位置
	 */
	public int indexOf(Object o) {
		if (o == null) {
            for (int i = 0; i < size(); i++)
                if (mArray[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size(); i++)
                if (o.equals(mArray[i]))
                    return i;
        }
        return -1;
	}

(九)clear

清空表中所有元素,下图就是清空的示意图;举个栗子:又是排队,老师说解散。


/**
	 * 清空所有元素 并把数组恢复到初始大小
	 */
	public void clear() {
		mCurrentSize = 0;
		ensureCapaccity(DEFAULT_CAPACITY);
		mModCount++;
	}

(十)trimToSize

保留有效元素长度,下图有效元素到索引为3(包含3)的位置,4到7的就不要了;举个栗子:开会搬来凳子,本来这一列有8张凳子的,但只坐了4个人,后面的4张凳子就被收走了。


/**
	 * 只保留有效元素长度
	 */
	public void trimToSize() {
		ensureCapaccity(size());
		mModCount++;
	}

(十一)ensureCapaticy

动态扩容数组到指定长度,如果指定的长度小于当前长度就不处理,下图就是把一个长度为4的数组扩容到长度为7;举个栗子:开会搬凳子排队,目前只有4张凳子,但有8个人要排,所以至少要有8张凳子。


/**
	 * 用于扩容数组保障数组容量足够使用
	 * @param pNewCapacity 新的数组容量大小
	 */
	private void ensureCapaccity(int pNewCapacity) {
		if (pNewCapacity < mCurrentSize) {
			return;
		}
		
		T[] _OldArr = mArray;
		mArray = (T[]) new Object[pNewCapacity];
		for(int i = 0; i < size(); i++) {
			mArray[i] = _OldArr[i];
		}
	}

三、完整的代码

import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;

public class MyArrayList<T> implements Iterable<T> {
	
	/**
	 * 数组默认初始化大小
	 */
	private final static int DEFAULT_CAPACITY = 10;
	
	/**
	 * 用于存放元素的数组
	 */
	private T[] mArray;
	
	/**
	 * 当前有效元素的个数
	 */
	private int mCurrentSize;
	
	/**
	 * 记录改动过的次数
	 */
	private int mModCount;
	
	public MyArrayList() {
		clear();
	}
	
	/**
	 * 用于扩容数组保障数组容量足够使用
	 * @param pNewCapacity 新的数组容量大小
	 */
	private void ensureCapaccity(int pNewCapacity) {
		if (pNewCapacity < mCurrentSize) {
			return;
		}
		
		T[] _OldArr = mArray;
		//泛型数组不能new只能强制转化
		mArray = (T[]) new Object[pNewCapacity];
		for(int i = 0; i < size(); i++) {
			mArray[i] = _OldArr[i];
		}
	}
	
	/**
	 * 得到当前表的大小
	 * @return 返回当前表的大小
	 */
	public int size() {
		return mCurrentSize;
	}
	
	/**
	 * 清空所有元素 并把数组恢复到初始大小
	 */
	public void clear() {
		mCurrentSize = 0;
		ensureCapaccity(DEFAULT_CAPACITY);
		mModCount++;
	}
	
	/**
	 * 表当前是否是空表
	 * @return 是否是空表
	 */
	public boolean isEmpty() {
		return size() == 0;
	}
	
	/**
	 * 查找指定元素在表中的位置
	 * @param o 要找的元素
	 * @return 元素在表中的位置
	 */
	public int indexOf(Object o) {
		if (o == null) {
            for (int i = 0; i < size(); i++)
                if (mArray[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size(); i++)
                if (o.equals(mArray[i]))
                    return i;
        }
        return -1;
	}
	
	/**
	 * 只保留有效元素
	 */
	public void trimToSize() {
		ensureCapaccity(size());
		mModCount++;
	}
	
	/**
	 * 设置在表中指定位置的元素
	 * @param pIndex 指定的位置
	 * @param t 要设置的元素
	 */
	public void set(int pIndex, T t) {
		if (pIndex < 0 || pIndex >= size()) {
			throw new ArrayIndexOutOfBoundsException(pIndex);
		}
		mArray[pIndex] = t;
		mModCount++;
	}
	
	/**
	 * 得到在表中指定位置的元素
	 * @param pIndex 指定的位置
	 * @return 指定位置的元素
	 */
	public T get(int pIndex) {
		if (pIndex < 0 || pIndex >= size()) {
			throw new ArrayIndexOutOfBoundsException(pIndex);
		}
		return mArray[pIndex];
	} 
	
	/**
	 * 添加元素到表末尾
	 * @param t 要添加的元素
	 * @return 添加是否成功
	 */
	public boolean add(T t) {
		add(size(), t);
		return true;
	}
	
	/**
	 * 添加元素到指定位置
	 * @param pIndex 指定的位置
	 * @param t 要添加的元素
	 */
	public void add(int pIndex, T t) {
		if (pIndex < 0 || pIndex > size()) {
			throw new ArrayIndexOutOfBoundsException(pIndex);
		}
		//检查空间是否足够
		if (size() == mArray.length) {
			//加1是保证当size为0的情况也能扩容
			ensureCapaccity(size() * 2 + 1);
		}
		for (int i = size(); i > pIndex; i--) {
			mArray[i] = mArray[i-1];
		}
		mArray[pIndex] = t;
		mCurrentSize++;
		mModCount++;
	}
	
	/**
	 * 删除在表中指定位置的元素
	 * @param pIndex 元素的位置
	 * @return 被删除的元素
	 */
	public T remove(int pIndex) {
		if (pIndex < 0 || pIndex >= size()) {
			throw new ArrayIndexOutOfBoundsException(pIndex);
		}
		T _RmElement = mArray[pIndex];
		for(int i = pIndex; i < size() - 1; i++) {
			mArray[i] = mArray[i + 1];
		}
		mArray[size() - 1] = null;
		mCurrentSize--;
		mModCount++;
		return _RmElement;
	}

	/**
	 * 获取迭代器
	 */
	@Override
	public Iterator<T> iterator() {
		return new ArrayListIterator();
	}
	
	/**
	 * 迭代器类
	 *
	 */
	private class ArrayListIterator implements Iterator<T> {

		/**
		 * 当前索引位置
		 */
		private int mIndex;
		
		/**
		 * 用于判断表是否被修改过,如果不等于mModCount说明被修改过
		 */
		private int mExpectedModCount = mModCount;
		
		/**
		 * 用于判断元素能否被删除
		 */
		private boolean mCanRemove = false;
		
		/**
		 * 是否有下一个元素
		 */
		@Override
		public boolean hasNext() {
			return mIndex < size();
		}

		/**
		 * 下一个元素
		 */
		@Override
		public T next() {
			if (checkIsModify()) {
				throw new ConcurrentModificationException();
			}
			if (!hasNext()) {
				throw new NoSuchElementException();
			}
			T t = get(mIndex++);
			mCanRemove = true;
			return t;
		}
		
		/**
		 * 删除元素,必须在next()方法执行后操作
		 */
		@Override
		public void remove() {
			if (checkIsModify()) {
				throw new ConcurrentModificationException();
			}
			if (!mCanRemove) {
				throw new IllegalStateException();
			}
			MyArrayList.this.remove(--mIndex);
			mExpectedModCount++;
			mCanRemove = false;
		}
		
		/**
		 * 检查List是否被修改过
		 * @return 被修改过返回true 否则返回false
		 */
		private boolean checkIsModify() {
			return mExpectedModCount != mModCount;
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值