数据结构-线性表(1)
线性表
线性表的定义
-
线性表(linear list)是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列.
-
线性表是一种抽象数据 类型;数组是一种具体的数据结构。线性表与数组的逻辑结构是不一样的,线性表是元素之 间具有1对1的线性关系的数据元素的集合,而数组是一组数据元素到数组下标的一一映射。 并且从物理性质来看,数组中相邻的元素是连续地存储在内存中的;线性表只是一个抽象的 数学结构,并不具有具体的物理形式,线性表需要通过其它有具体物理形式的数据结构来实 现。在线性表的具体实现中,表中相邻的元素不一定存储在连续的内存空间中,除非表是用 数组来实现的。对于数组,可以利用其下标在一个操作内随机存取任意位置上的元素;对于 线性表,只能根据当前元素找到其前驱或后继,因此要存取序号为i的元素,一般不能在一 个操作内实现,除非表是用数组实现的。
线性表的顺序存储与实现
1.1List接口
package cn.wjy.list;
public interface List {
/**
* 返回线性表的大小,及数据元素的个数
*
* @return
*/
public int getSize();
/**
* 判断线性表是否为空
*
* @return
*/
public boolean isEmpty();
/**
* 判断线性表是否包含数据元素e
*
* @param e
* @return
*/
public boolean contains(Object e);
/**
* 返回数据元素e在线性表中的序号
*
* @param e
* @return
*/
public int indexOf(Object e);
/**
* 将数据元素e插入到线性表中i号位置
*
* @param i
* @param e
* @throws OutOfBoundaryException
*/
public void insert(int i, Object e) throws OutOfBoundaryException;
/**
* 将数据元素e插入到元素obj之前
*
* @param obj
* @param e
* @return
*/
public boolean insertBefore(Object obj, Object e);
/**
* 将数据元素e插入到元素obj之后
*
* @param obj
* @param e
* @return
*/
public boolean insertAfter(Object obj, Object e);
/**
* 删除线性表中序号为i的元素,并返回之
*
* @param i
* @return
* @throws OutOfBoundaryException
*/
public Object remove(int i) throws OutOfBoundaryException;
/**
* 删除线性表中第一个与e相同的元素
*
* @param e
* @return
*/
public boolean remove(Object e);
/**
* 替换线性表中序号为i的数据元素为e,返回原数据元素
*
* @param i
* @param e
* @return
* @throws OutOfBoundaryException
*/
public Object replace(int i, Object e) throws OutOfBoundaryException;
/**
* 返回线性表中序号为i的数据元素
*
* @param i
* @return
* @throws OutOfBoundaryException
*/
public Object get(int i) throws OutOfBoundaryException;
}
1.2出现序号越界时抛出异常
public class OutOfBoundaryException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 1L;
public OutOfBoundaryException(String err) {
super(err);
}
}
1.3 Strategy 接口
-
所有数据元素的类型都使用 Object 来替代,这样做是 为了程序的通用性,即一种抽象数据类型的实现可以用于所有数据元素。但是这样做带来了 另一个需要解决的问题,即完成数据元素之间比较大小或是否相等的问题。在使用 Object 类型的变量指代了所有数据类型之后,那么所有种类的数据元素的比较就都需要使用 Object 类型的变量来完成,但是不同数据元素的比较方法或策略是不一样的。例如字符串的比较是 使用 java.lang.String 类的 compareTo 和 equals 方法;而基本的数值型数据是使用关系运算符 来完成的;其他各种不同的类的比较方法就更加千差万别多种多样了,即使同一个类的比较 方法在不同的情况下也会不同,例如两个学生之间的比较有时可以用学号的字典顺序来进 行,有时可能又需要使用成绩来比较。因此我们无法简单的在两个 Object 类型的变量之间 使用"= ="、"<"等关系运算符来完成各种不同数据元素之间的比较操作,同时 Java 也不提供 运算符的重载.
-
使用 Strategy 接口可以实现各种不同数据元素相互之间独立的比较策略。在实现各种抽 象数据类型时,例如线性表,可以使用 Strategy 接口变量来完成形式上的比较,然后在创建 每个抽象数据类型的实例时,例如一个具体的用于学生的线性表时,可以引入一个实际实现了 Strategy 接口的策略类对象,例如实现了 Strategy 接口的学生比较策略类对象。使用这一策略的另一优点在于,一旦不想继续使用原先的比较策略对象,随时可以使用另一个比较 策略对象将其替换,而不用修改抽象数据类型的具体实现。
package cn.wjy.list;
public interface Strategy {
/**
* 判断两个数据元素是否相等
*
* @param obj1
* @param obj2
* @return
*/
public boolean equal(Object obj1, Object obj2);
/**
* 判断两个数据元素的大小 obj1>obj2 return -1; obj1=obj2 return 0; obj1<obj2 reurn 1
*
* @param obj1
* @param obj2
* @return
*/
public int compare(Object obj1, Object obj2);
}
package cn.wjy.list;
public class DefaultStrategy implements Strategy {
@Override
public boolean equal(Object obj1, Object obj2) {
return obj1.toString().equals(obj2.toString());
}
@Override
public int compare(Object obj1, Object obj2) {
int temp = obj1.toString().compareTo(obj2.toString());
if (temp == 0) {
return 0;
} else if (temp > 0) {
return 1;
} else {
return -1;
}
}
}
package cn.wjy.list;
public class StudentStrategy implements Strategy {
@Override
public boolean equal(Object obj1, Object obj2) {
if (obj1 instanceof Student && obj2 instanceof Student) {
Student s1 = (Student) obj1;
Student s2 = (Student) obj2;
return s1.getSId().equals(s2.getSId());
} else {
return false;
}
}
@Override
public int compare(Object obj1, Object obj2) {
if (obj1 instanceof Student && obj2 instanceof Student) {
Student s1 = (Student) obj1;
Student s2 = (Student) obj2;
return s1.getSId().compareTo(s2.getSId());
} else {
return obj1.toString().compareTo(obj2.toString());
}
}
}
2.线性表的数组实现
public class ListArray implements List {
private final int LEN = 9;// 数组的默认大小
private Strategy strategy; // 数据元素比较策略
private int size;// 线性表中数据元素的个数
private Object[] elements; // 数据元素数组
public ListArray() {
this(new DefaultStrategy());
}
public ListArray(Strategy strategy) {
this.strategy = strategy;
size = 0;
elements = new Object[LEN];
}
@Override
public int getSize() {
return size;
}
@Override
public boolean isEmpty() {
return size == 0;
}
@Override
public boolean contains(Object e) {
return indexOf(e) != -1;
}
@Override
public int indexOf(Object e) {
for (int i = 0; i < size; i++)
if (strategy.equal(e, elements[i]))
return i;
return -1;
}
/**
* 扩充数组
*/
private void expandSpace() {
Object[] a = new Object[elements.length * 2];
for (int i = 0; i < elements.length; i++)
a[i] = elements[i];
elements = a;
}
@Override
public void insert(int i, Object e) throws OutOfBoundaryException {
if (i < 0 || i > size)
throw new OutOfBoundaryException("错误,指定的插入序号越界");
if (size >= elements.length)
expandSpace();
for (int j = size; j > i; j--)
elements[j] = elements[j - 1];
elements[i] = e;
size++;
return;
}
@Override
public boolean insertBefore(Object obj, Object e) {
int i = indexOf(obj);
if (i < 0)
return false;
insert(i, e);
return true;
}
@Override
public boolean insertAfter(Object obj, Object e) {
int i = indexOf(obj);
if (i < 0)
return false;
insert(i + 1, e);
return true;
}
@Override
public Object remove(int i) throws OutOfBoundaryException {
if (i < 0 || i >= size)
throw new OutOfBoundaryException("错误,指定的插入序号越界");
Object obj = elements[i];
for (int j = i; j < size - 1; j++)
elements[j] = elements[j + 1];
elements[--size] = null;
return obj;
}
@Override
public boolean remove(Object e) throws OutOfBoundaryException {
int i = indexOf(e);
if (i < 0)
return false;
remove(i);
return true;
}
@Override
public Object replace(int i, Object e) throws OutOfBoundaryException {
if (i < 0 || i >= size)
throw new OutOfBoundaryException("错误,指定的序号越界");
Object obj = elements[i];
elements[i] = e;
return obj;
}
@Override
public Object get(int i) throws OutOfBoundaryException {
if (i < 0 || i >= size)
throw new OutOfBoundaryException("错误,指定的序号越界");
return elements[i];
}
}