虽然java库已经有成熟的顺序表实现,但是自己写一个能加深对顺序表的认识。
何为顺序表呢?
在《数据结构(C语言版)》一书中,顺序表的描述如下:
线性表的顺序表示(下文称为顺序表)指的是用一组地址连续的存储单元依次存储线性表的数据元素。
以元素在计算机内“物理位置相邻”来表示线性表中数据元素之间的逻辑关系。每一个数据元素的存储位置都和线性表的起始位置相差一个和数据元素在线性表中的位序成正比的常数。由此,只要确定了存储线性表的起始位置,线性表中任一数据元素都可以随机存取,所以顺序表是一种随机存取的存储结构。
如图所示,先假设顺序表中存放的数据的类型都是一样的,则每个结点所占用的存储控件大小也相同,这里记为c个存储单元。这里以结点所占的第一个单元的存储地址作为该结点的存储地址,并设第一个结点的存储地址是b,那么结点ai的存储地址可以通过下式计算。
从公式中我们可以看出顺序表的一个特点:两结点逻辑上相邻,那么其对应的物理位置(内存中)也相邻。
关于顺序表的更多特性这里就不多说了,稍微总结一下顺序表结构的优势和劣势。
优势:随机存(在顺序表表尾追加结点)取(读取结点)。
劣势:插入操作、删除操作以及扩容操作需要移动大量结点。
代码如下:
package ds.linerlist;
/**
* 顺序表的实现
*
* @author Abyss_CMG
*
* @param <E>
*/
public class LinerList<E> {
private static final int DEFAULT_LENGTH = 10; // DEFAULT_LENGTH:线性表默认初始化容量大小
private static final int DEFAULT_EXPANSION_LENGTH = 5; // DEFAULT_EXPANSION_LENGTH:线性表扩容时默认扩大大小
private Object[] objData = null; // objData:用于存放线性表的数据
private int nCapacity = 0; // nCapacity:用于标志线性表的容量
private int nUsedLen = 0; // nUsedLen:用于标志线性表已存放的数据长度
/**
* 若实例化线性表时没有定义大小,则默认大小为10
*/
public LinerList() {
this(DEFAULT_LENGTH);
}
/**
* 初始化线性表,并声明保存线性表数据的数组大小
*
* @param nInitSize
* 顺序表的初始大小
*/
public LinerList(int nInitSize) {
if (nInitSize >= 0) {
nCapacity = nInitSize;
if ((objData = new Object[nInitSize]) == null) {
System.out.println("初始化失败:无法分配内存");
}
nUsedLen = 0;
} else {
System.out.println("初始化大小不能小于0:" + nInitSize);
}
}
/**
* 判断线性表是否满容量
*
* @return 满容量返回true,否则返回false
*/
private boolean isFull() {
return (nUsedLen == nCapacity) ? true : false;
}
/**
* 判断线性表是否为空
*
* @return 若为空表则返回true,否则返回false
*/
private boolean isEmpty() {
return (nUsedLen == 0) ? true : false;
}
/**
* 扩大线性表容量
*/
private void expanedList() {
nCapacity += DEFAULT_EXPANSION_LENGTH;
Object[] objNewData = new Object[nCapacity];
System.arraycopy(objData, 0, objNewData, 0, nUsedLen);
objData = objNewData;
}
/**
* 在线性表尾部追加数据
*
* @param eData
* 待追加的数据
* @return
*/
public void add(E eData) {
if (isFull()) {
expanedList();
}
objData[nUsedLen++] = eData;
}
/**
* 在线性表的某个位置插入数据
*
* @param eData
* 待插入的数据
* @param destPos
* 插入数据的位置
* @return
*/
public boolean insert(E eData, int nDestPos) {
if (nDestPos < 0) {
System.out.println("插入数据失败:插入位置错误");
return false;
}
if (isFull()) {
expanedList();
}
System.arraycopy(objData, nDestPos, objData, nDestPos + 1, nUsedLen
- nDestPos);
objData[nDestPos] = eData;
nUsedLen++;
return true;
}
/**
* 删除指定位置的数据
*
* @param nDestPos
* 删除数据的位置
* @return
*/
public boolean delete(int nDestPos) {
if (isEmpty()) {
System.out.println("线性表为空,删除失败");
return false;
}
if ((nDestPos < 0) || (nDestPos > nUsedLen)) {
System.out.println("删除数据失败:指定删除的位置错误");
return false;
}
System.arraycopy(objData, nDestPos + 1, objData, nDestPos, nUsedLen
- nDestPos);
nUsedLen--;
return true;
}
/**
* 修改指定位置的数据
*
* @param eData
* 待修改的数据
* @param nDestPos
* 修改数据的位置
* @return
*/
public boolean set(E eData, int nDestPos) {
if ((nDestPos < 0) || (nDestPos > nUsedLen)) {
System.out.println("修改数据失败:指定修改的位置错误");
return false;
}
objData[nDestPos] = eData;
return true;
}
/**
* 查找指定位置的数据
*
* @param nDestPos
* 待查找的位置
* @return
*/
@SuppressWarnings("unchecked")
public E find(int nDestPos) {
if (isEmpty()) {
System.out.println("线性表为空,查找失败");
return null;
}
if ((nDestPos < 0) || (nDestPos > nUsedLen)) {
System.out.println("修改数据失败:指定修改的位置错误");
return null;
}
return (E) objData[nDestPos];
}
@SuppressWarnings("unchecked")
public E search(E eSearch) {
if (isEmpty()) {
System.out.println("线性表为空,查找失败");
return null;
}
if (eSearch.equals(null)) {
System.out.println("查找数据" + eSearch + "失败");
return null;
}
int nTmp = 0;
for (int i = 0; i < nUsedLen; i++) {
if (objData[i].equals(eSearch)) {
nTmp = i;
break;
} else {
nTmp = -1;
}
}
return (nTmp != -1) ? (E) objData[nTmp] : null;
}
/**
* 返回线性表已用长度
*
* @return
*/
public int getSize() {
return nUsedLen;
}
}
测试代码:
package ds.linerlist;
public class Simple {
public static void main(String[] args) {
LinerList<String> list = new LinerList<String>();
list.add("12");
list.add("34");
list.add("78");
list.add("90");
int len = list.getSize();
for (int i = 0; i < len; i++) {
System.out.println(i + "位置:" + list.find(i));
}
System.out.println("在2位置插入数据56");
list.insert("56", 2);
len = list.getSize();
for (int i = 0; i < len; i++) {
System.out.println(i + "位置:" + list.find(i));
}
System.out.println("修改10位置的数据为1a2");
list.set("1a2", 10);
System.out.println("修改0位置的数据为1a2");
list.set("1a2", 0);
len = list.getSize();
for (int i = 0; i < len; i++) {
System.out.println(i + "位置:" + list.find(i));
}
System.out.println("删除10位置的数据");
list.delete(10);
System.out.println("删除1位置数据");
list.delete(1);
len = list.getSize();
for (int i = 0; i < len; i++) {
System.out.println(i + "位置:" + list.find(i));
}
System.out.println("查找34");
System.out.println("结果:" + list.search("34"));
System.out.println("查找1a2");
System.out.println("结果:" + list.search("1a2"));
}
}
结果:
0位置:12
1位置:34
2位置:78
3位置:90
在2位置插入数据56
0位置:12
1位置:34
2位置:56
3位置:78
4位置:90
修改10位置的数据为1a2
修改数据失败:指定修改的位置错误
修改0位置的数据为1a2
0位置:1a2
1位置:34
2位置:56
3位置:78
4位置:90
删除10位置的数据
删除数据失败:指定删除的位置错误
删除1位置数据
0位置:1a2
1位置:56
2位置:78
3位置:90
查找34
结果:null
查找1a2
结果:1a2
这个只是简单的实现,还是会有很多的问题,只能下一步慢慢改善了。