线性表是一种按顺序储存数据是的常用结构,大多数的线性表都支持以下的典型操作:
从线性表提取插入删除一个数据;
找出线性表中的某一个元素;
找出线性表中的元素;
确定线性表中是否包含某一个元素,确定线性表是否为空;
实现线性表的方法有两种:
1、数组(arry),数组是动态的创建的,如果元素超过了数组的容量,就会创建一个新的数组并且把当前的数组元素复制到更大的数组里;
2、连式结构(linked structure)。连式结构有节点构成,节点是动态创建的。
方便起见,把数组称为MyArrayList,把连式结构称为MylinkedList,他们有相同的操作,却有这不同的实现。
设计一个好用的线性表,通常把一些通用的操作归纳为一个接口和抽象类,抽象类提供接口实现的框架,以更好地实现接口。把这样的接口叫MyList,把这样的抽象类叫MyAbstractList。
以下是接口MyList的代码:
public interface MyList<E> { public void add(E e); public void add(int index,E e); public void clear(); //清除所有元素 public boolean contains(E e); public E get(int index); public int indexOf(E e); public boolean isEmpty(); public int lastIndexOf(E e); public boolean remove(E e); public E remove(int index); //删除指定元素 public Object set(int index, E e); //在指定位置插入元素 public int size(); }
下面是MyAbstractList代码(实现了各方法):
public abstract class MyAbstractList<E> implements MyList<E> { protected int size = 0; //声明size protected MyAbstractList(){} protected MyAbstractList(E[] objects){ for(int i = 0;i<objects.length;i++){ add(objects[i]); } } public void add(E e){ add(size,e); } public boolean isEmpty(){ return size==0; } public int size(){ return size; } public boolean remove(E e){ if(indexOf(e) >=0){ remove (indexOf(e)); return true; } else return false; } }
下面先讲数组的线性表示:
数组是一种固定大小的数据结构,一旦创建就无法改变,但仍然可以用数组来实现动态的数据结构,方法是当数组大小不够用的时候,就创建一个更大的数组类来替换当前数组。
初始状态时,默认大小,创建一个类型为E[ ] 的数组data。向数组中插入一个新的元素时,首先确认数组是否有足够的空间,若不够,则创建一个为当前数组两倍的数组,然后复制元素到新的数组里面。现在在指定的下标处插入新的元素,并且要将指定下标后面的所有元素的下标都增加一。若是删除元素,则要把后面元素下标都减少一。
大体思路是:
+ MyArrayList() 创建默认数组
+MyArrayList(E[ ] objects) 由对象数组创建一个数组
—ensureCapacity() 如果需要就扩大数组
+trimToSize() 将数组大小缩小至线性表的当前大小
下面是MyArrayList实现MyAbstractList的代码:
public class MyArrayList<E> extends MyAbstractList<E> { public static final int INITIAL_CAPACITY = 16; //定义初始容量 private E[] data = (E[])new Object[INITIAL_CAPACITY]; //创建默认数组 public MyArrayList() { } //由对象数组创建一个数组 public MyArrayList(E[] objects) { for (int i = 0; i < objects.length; i++) add(objects[i]); // Warning: don抰 use super(objects)! } //在指定下标处增加元素 public void add(int index, E e) { //如果需要调用数组增加两倍的方法 ensureCapacity(); // 把指定下标后面的数的下标全部加一 for (int i = size - 1; i >= index; i--) data[i + 1] = data[i]; data[index] = e; size++; } //如果需要,数组增加两倍的方法 private void ensureCapacity() { if (size >= data.length) { E[] newData = (E[])(new Object[size * 2 + 1]); System.arraycopy(data, 0, newData, 0, size); data = newData; } } //清空元素 public void clear() { data = (E[])new Object[INITIAL_CAPACITY]; size = 0; } //是否包含某一元素的方法 public boolean contains(E e) { for (int i = 0; i < size; i++) if (e.equals(data[i])) return true; return false; } //给定下标,获得下标所指定的元素 public E get(int index) { return data[index]; } //从第一个元素开始搜索某一元素 ,有则返回下标值,否则返回-1 public int indexOf(E e) { for (int i = 0; i < size; i++) if (e.equals(data[i])) return i; return -1; } //从最后一个元素开始 public int lastIndexOf(E e) { for (int i = size - 1; i >= 0; i--) if (e.equals(data[i])) return i; return -1; } //删除元素 public E remove(int index) { E e = data[index]; for (int j = index; j < size - 1; j++) data[j] = data[j + 1]; //最后一个元素为空 data[size - 1] = null; size--; return e; } //替换 public E set(int index, E e) { E old = data[index]; data[index] = e; return old; } //重写Object中的方法,返回一个表示包含数组中全部元素的字符串 public String toString() { StringBuilder result = new StringBuilder("["); for (int i = 0; i < size; i++) { result.append(data[i]); if (i < size - 1) result.append(", "); } return result.toString() + "]"; } //将数组大小缩小至线性表的当前大小 public void trimToSize() { if (size != data.length) { E[] newData = (E[])(new Object[size]); System.arraycopy(data, 0, newData, 0, size); data = newData; } } }
测试的一个事例:
public class TestList { public static void main(String[] args) { //创建一个线性表 MyList<String> list = new MyArrayList<String>(); //加入一个元素 list.add("喜欢"); list.add(0,"我"); list.add("你"); System.out.println(list); list.add(1,"非常"); list.add(1,"很"); System.out.println(list); list.remove(1); System.out.println(list); list.set(3, "你 ,爱你一万年"); System.out.println(list); } }
再来讲链表:
由于MyArrayList是有数组实现的,在使用get()、set函数会是 高效的,但是在用add()和remove时效率却并不高,因为可能要移动大量的元素。为提高效率,可以采用链式结构来实现线性表。东西有点多,写到笔记二去吧。