一,线性表
在数据结构中,数据与数据之间的关系可以抽象为4种逻辑结构:
1,集合结构:数据元素间除“同属于一个集合”外,没有其他的任何关系。
2,线性结构:数据可以按照某种规则排列成线性表的形式。
3,树形结构:数据之间呈现倒立的树形结构,每个元素有一个双亲,有0个或多个孩子,数据之间是一对多的关系。
4,网状结构:每个数据元素都有可能有多个相邻的数据元素,数据元素之间呈现一种多对多的关系。
线性表:一种逻辑结构,相同数据类型的n个数据元素的有限序列,除第一个元素外,每个元素有且仅有一个直接前驱,除最后一个元素外,每个元素有且仅有一个直接后继。
二,顺序表
线性表其实指的是一种逻辑结构,而这种逻辑结构在计算机中的表示可以有两种,即存储结构:
1,线性存储,这样的线性表叫做顺序表,顺序表一般通过高级语言的数组来实现,数组本质上其实就是一个线性表。
2,链式存储,这样的线性表叫做链表,链表通常是通过定义结点的方式,以指针将各个元素及元素之间的关系体现出来。
三,顺序表的实现
一,定义MyList接口
定义一个MyList接口,该接口定义了线性表实现的规范,即定义线性表需要实现的基本操作,这些操作包括增删改查,判断表是否为空,查询表的长度。
//自定义接口MyList,是所有list集合实现的父接口,
public interface MyList<T>
{
boolean add(T data); //在顺序表末尾插入元素
boolean add(int index,T data); //在指定位置插入元素
T remove(int index); //根据下标删除元素
T remove(T data); //删除指定的元素
boolean set(int index,T data); //在修改指定位置的元素的值
T get(int index); //查找下表为index的元素
int indexOf(T data); //返回元素data所在位置
int size(); //返回列表长度
boolean isEmpty(); //判断列表是否为空
}
因为只是为了简单实现线性表,而不是追求一个大而全的目标,因此MyList接口并没有向java提供的类库那样实现Iterator接口和Comparable接口,不过在上面的代码中可以看到MyList接口是支持泛型的。
二,定义MyArrayList类,实现顺序表
定义MyArrayList类,实现MyList接口,并根据顺序表的特点实现接口的方法,和拓展自己的方法
//列表需要存放不同数据类型的元素,使用java泛型实现
public class MyArrayList<T> implements MyList<T> {}
1,成员变量
private int size; //列表的容量
private int length; //列表实际长度,即列表中最后一个元素的下标加一
private Object[] list; //java不支持泛型数组,所有创建一个Object类型数组来存放数据
private int increment; //当数组已满时,数组的增长量
2,构造方法,无参构造方法,带初始化长度的构造方法,以数组初始化表的构造方法
public MyArrayList()
{
this(10); //列表容量默认为10
}
public MyArrayList(int size)
{
if(size<=0) //当要求创建的列表长度小于等于0时,抛异常
throw new RuntimeException("要创建的列表大小不符合要求");
else
this.size = size;
length = 0;
list = new Object[size];
increment = this.size; //列表大小增量为当前列表容量
}
public MyArrayList(T[] list) //以数组初始化列表
{
size = list.length;
length = list.length;
increment = size;
this.list = Arrays.copyOf(list, size); //将传入的参数数组复制到list中
}
3,add方法,在表末尾插入元素和在指定位置插入元素
@Override
public boolean add(T data) //在列表末尾插入元素
{
return add(length,data);
}
@Override
public boolean add(int index, T data) //在指定位置插入元素
{
if(length==size)//先判断表是否已满,满了则需要调用grow方法进行增长
grow();
if(index>length)
index=length; //下标超出表长,默认在末尾插入
if(index < 0)
return false; //下标为负数,插入失败
for(int i=length-1;i>=index;i--)
list[i+1] = list[i]; //指定位置后的所有元素整体后移一个位置
list[index] = data;
length++; //更新列表长度
return true;
}
4,grow方法,当顺序表满时,实现顺序表的自动增长
private void grow()
{
size = size + increment; //新数组长度为原长度加上增量
increment = size; //数组增长策略采用倍数增长,即每次增长量为原长度的一倍
list = Arrays.copyOf(list, size);//将原来的数组复制到新数组中
}
5,remove方法,根据下标或者元素删除对应的数据
@Override
public T remove(int index)
{
if(index<0 || index>=length)
throw new RuntimeException("删除操作失败,下标不符合规范!");
@SuppressWarnings("unchecked")
T data = (T) list[index];
for(int i=index;i<length-1;i++)
list[i] = list[i+1]; //指定位置后的所有元素整体前移一个位置,则需要删除的元素被覆盖,即实现了删除
list[--length] = null; //最后的元素置为null,表长减一
return data;
}
@Override
public T remove(T data)
{
int index = indexOf(data); //先查需要删除元素所在下标,然后在进行删除操作
return remove(index);
}
6,set方法,修改指定位置的元素
@Override
public boolean set(int index, T data)
{
if(index<0 || index>=length)
throw new RuntimeException("更新操作失败,下标不符合规范");
list[index] = data;
return true;
}
7,get方法,返回具体下标所在元素
@SuppressWarnings("unchecked")
@Override
public T get(int index)
{
if(index<0 || index>=length)
throw new RuntimeException("查询操作失败,下标不符合规范");
return (T) list[index];
}
8,indexOf方法,查询该元素所在的位置
@Override
public int indexOf(T data)
{
for(int i=0;i<length;i++) //遍历数组,找到需要查找元素的位置
if(list[i] == data)
return i;
return -1; //没有则返回-1
}
9,size方法,返回顺序表中元素的实际个数
@Override
public int size()
{
return length; //元素的实际个数,而并非数组(表)的长度
}
10,isEmpty方法,判断表是否为空
@Override
public boolean isEmpty()
{
return length==0;
}
11,toString方法,为方便查看表中的所有元素重写了toString方法
//以()的形式输出表中所有元素
public String toString()
{
StringBuilder strb = new StringBuilder();
strb = strb.append("(");
for(int i=0;i<length-1;i++)
{
strb = strb.append(list[i].toString()+",");
}
strb=strb.append(list[length-1]+")");
String s = new String(strb);
strb=null;
return s;
}
四,测试
实现了顺序表以后,对该顺序表进行测试:
import static java.lang.System.*;//静态引入
public class TestMyArrayList {
public static void main(String[] args)
{
//测试自定义的顺序表
MyArrayList<String> list = new MyArrayList<String>(2);
list.add("北京");
list.add("上海");
list.add("广东");
list.add(6,"常州");//并不存在下标6,所有默认在末尾插入
out.println("list.size="+list.size());
for(int i=0;i<list.size();i++)
{
out.println(list.get(i));
}
String s = list.remove(2);
out.println("删除的元素为:"+s);
out.println(list.toString());
list.set(1, "大连");
out.println(list.toString());
}
}
程序运行结果:
list.size=4
北京
上海
广东
常州
删除的元素为:广东
(北京,上海,常州)
(北京,大连,常州)
从上面的测试程序和其运行结果可以看出来,MyArrayList实现的还是比较成功的,满足了顺序表操作的最基本需求。