线性表之顺序表--类似于java库中的ArrayList

下面笔者将结束一种简单的数据结构-线性表中的顺序表。相信大家也会在程序中时常用到ArrayList这个类,对这个ArrayList的相关方法的使用也并不陌生。笔者所实现的一个顺序表(MyArrayList)和java类库中的ArrayList相似,但是没有类库中的复杂,只是简单的介绍ArrayList中的重要方法,以加深对顺序表的学习和理解,如果在程序中还是建议读者采用类库中的ArrayList。当然笔者也可以参照类库中的ArrayList自己实现一个自己的顺序表。

线性表:即具有相同类型的有限序列。       顺序表:是用一段地址连续的存储单元(数组)依次存储线性表的数据元素,元素之间在物理位置上具有邻接关系。

    链表: 用一组任意的存储单元(内存空间可以不连续)存放线性表的元素,在C语言中通过指针链接每个元素,而java中则通过引用实现这种链接。

接下来,笔者先介绍顺序表,再介绍链表以及它俩之间的区别。

笔者定义了一个自己的顺序表类: MyArrayList   用 data 数组以及 length 存放数据元素以及数据的大小,并在构造函数中初始化。在这里笔者也通过泛型可以传递任何对象参数。

	private Object data[];
	private int length;

	// 不制定线性表默认大小为10
	public MyArrayList() {
		this(10);
	}

	// 创建制定大小的线性表
	public MyArrayList(int n) {
		data = new Object[n];
		length = 0;
	}

	// 传入数组创建线性表
	public MyArrayList(T a[]) {
		this.data = new Object[a.length];
		for (int i = 0; i < a.length; i++) {
			data[i] = a[i];
		}
		length = a.length;
	}

顺序表中插入元素。若不制定插入位置,则默认在数组的最后面插入;若当前数组已满,则扩展数组的大小为当前数组大小的两倍,并将数据插入到制定位置。插入式,若在数组的最后面插入(且数组未满),时间复杂度为常数,当数组已满或者在数组中间插入,需要将插入位置后面的元素分别后移,所以时间复杂度为O(n)。综上,时间复杂度为O(n)。

	// 在制定位置插入
	public void add(int n, T t) {
		if (n > length || n < 0) {
			throw new ArrayIndexOutOfBoundsException("参数不合法");
		}
		if (length == data.length) { // 扩展数组,这里选择扩展为2倍
			Object[] obj = new Object[data.length * 2];
			for (int i = 0; i < data.length; i++) {
				obj[i] = data[i];
			}
			data = obj;
		}
		for (int i = length; i > n; i--) { // 中间插入,后面的项往后移动
			data[i] = data[i - 1];
		}
		data[n] = t;
		length++;
	}

	// 插入一个元素,默认在在数组项的最后面插入
	public boolean add(T t) {
		add(length, t);
		return true;
	}

查找: 按位查找, 直接获取指定位置的元素,时间复杂度为 常数。
	// 按照位置查找元素
	@SuppressWarnings("unchecked")
	public T get(int i) {
		if (i < 0 && i > length) {
			throw new ArrayIndexOutOfBoundsException("参数不合法");
		}
		return (T) data[i - 1];
	}

按值查找,并返回元素位置,时间复杂度为 O(n)。
	// 获取元素所在的位置
	public int indexOf(T t) {
		for (int i = 0; i < length; i++) {
			if (data[i].equals(t)) {
				return i + 1;
			}
		}
		return 0;
	}


删除: 由于需要保持数据在存储空间的物理位置的连续性,若删除的为最后一个元素,时间复杂度为常数,否则删除一个元素后需要将删除位置后面的所有元素前移一位,所以时间复杂度为O(n)。
	// 删除元素
	public boolean remove(T t) {
		try {
			int i = this.indexOf(t);
			remove(i);
			return true;
		} catch (ArrayIndexOutOfBoundsException e) {
			return false;
		}
	}

	// 已知元素的位置,删除元素
	public Object remove(int n) {
		if (n >= length || n < 0) {
			throw new ArrayIndexOutOfBoundsException("参数不合法");
		}
		Object o = data[n - 1];
		for (int i = n - 1; i < length - 1; i++) {
			data[i] = data[i + 1];
		}
		length--;
		return o;
	}

顺序表的 判空、获取大小、遍历。 判空、获取大小时间复杂度都为常数,遍历为O(n)
	// 判断是否为空
	public boolean isEmpty() {
		return length == 0;
	}

	// 获取线性表的大小
	public int size(){
		return length;
	}
	
	// 访问整个顺序
	public void print(){
		for(int i = 0; i < length; i++){
			System.out.print(data[i] + " ");
		}
	}


由上面可知,顺序表中采用数组存储元素,在顺序表中插入或删除元素,即在数组中间中间插入或删除元素,需要付出很高的代价,插入或删除元素后相关的元素都必须作相应的移动,然而在线性表中查找就相对容易,制定位置后即可通过数组的下标找到元素。在接下来的链表中我们可以看到链表中插入删除非常容易,而查找就必须遍历链表才能返回结果。


全部代码以及测试

package org.TT.myArrayList;

/**
 * @author Administrator
 *
 * @param <T>
 */
public class MyArrayList<T> {

	private Object data[];
	private int length;

	// 不制定线性表默认大小为10
	public MyArrayList() {
		this(10);
	}

	// 创建制定大小的线性表
	public MyArrayList(int n) {
		data = new Object[n];
		length = 0;
	}

	// 传入数组创建线性表
	public MyArrayList(T a[]) {
		this.data = new Object[a.length];
		for (int i = 0; i < a.length; i++) {
			data[i] = a[i];
		}
		length = a.length;
	}

	// 在制定位置插入
	public void add(int n, T t) {
		if (n > length || n < 0) {
			throw new ArrayIndexOutOfBoundsException("参数不合法");
		}
		if (length == data.length) { // 扩展数组,这里选择扩展为2倍
			Object[] obj = new Object[data.length * 2];
			for (int i = 0; i < data.length; i++) {
				obj[i] = data[i];
			}
			data = obj;
		}
		for (int i = length; i > n; i--) { // 中间插入,后面的项往后移动
			data[i] = data[i - 1];
		}
		data[n] = t;
		length++;
	}

	// 插入一个元素,默认在在数组项的最后面插入
	public boolean add(T t) {
		add(length, t);
		return true;
	}

	// 按照位置查找元素
	@SuppressWarnings("unchecked")
	public T get(int i) {
		if (i < 0 && i > length) {
			throw new ArrayIndexOutOfBoundsException("参数不合法");
		}
		return (T) data[i - 1];
	}

	// 获取元素所在的位置
	public int indexOf(T t) {
		for (int i = 0; i < length; i++) {
			if (data[i].equals(t)) {
				return i + 1;
			}
		}
		return 0;
	}

	// 删除元素
	public boolean remove(T t) {
		try {
			int i = this.indexOf(t);
			remove(i);
			return true;
		} catch (ArrayIndexOutOfBoundsException e) {
			return false;
		}
	}

	// 已知元素的位置,删除元素
	public Object remove(int n) {
		if (n >= length || n < 0) {
			throw new ArrayIndexOutOfBoundsException("参数不合法");
		}
		Object o = data[n - 1];
		for (int i = n - 1; i < length - 1; i++) {
			data[i] = data[i + 1];
		}
		length--;
		return o;
	}

	// 判断是否为空
	public boolean isEmpty() {
		return length == 0;
	}

	// 获取线性表的大小
	public int size(){
		return length;
	}
	
	// 访问整个顺序
	public void print(){
		for(int i = 0; i < length; i++){
			System.out.print(data[i] + " ");
		}
	}
	
	public static void main(String[] args) {
		String a[] = { "a", "b", "c", "d", "e", "f", "g"};
		MyArrayList<String> list = new MyArrayList<>(a);
		list.print();
		list.add(3,"TT");
		list.add("h");
		
		System.out.println();
		System.out.println("在第三个元素后面添加:0 ,在最后面添加:20 ");
		System.out.print("添加后: ");
		list.print();
		
		list.remove(1);
		list.remove("g");
		
		System.out.println();
		System.out.println("删除第二个元素: b , 删除指定元素: g");
		System.out.print("删除后:");
		list.print();
		
		System.out.println();
		System.out.println("顺序表是否为空: " + list.isEmpty());
		System.out.println("顺序表的大小: " + list.size());
	}

}

测试结果

测试


  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值