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

来源:互联网 发布:剑侠情缘2白金版 mac 编辑:程序博客网 时间:2024/05/29 15:45

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

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

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

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

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

private Object data[];private int length;// 不制定线性表默认大小为10public 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;// 不制定线性表默认大小为10public 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());}}
测试结果

测试


1 0
原创粉丝点击