线性表----顺序表(java实现)

本文介绍了线性表的逻辑结构及其在计算机中的两种存储方式——顺序表和链表。重点讲解了如何用Java实现顺序表,包括定义MyList接口和实现MyArrayList类,详细阐述了成员变量、构造方法、增删改查等基本操作,并提供了测试案例以验证实现的正确性。
摘要由CSDN通过智能技术生成

一,线性表

在数据结构中,数据与数据之间的关系可以抽象为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实现的还是比较成功的,满足了顺序表操作的最基本需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值