Data structures and algorithms (ii) a linear table - sequential storage structure

Linear table

Linear table (list): a finite sequence of zero or more data elements.
For example: a class of children, line up one after another, each of them knows who the children in front of him is, who is behind, like a wire them in series. It can be called a linear table.

To the definition of the linear form, linear form analyze what what write operations, attributes and behaviors from two aspects:

Property aspects:

  • Int size effective number of elements in the linear form
  • int capacity the maximum capacity of the linear form
  • E [] data data storage containers

Behavior

  • increase()
  • delete()
  • change()
  • check()
  • other()

Define a linear sequence table storage structure refers to the use of addresses are successively stored data elements in the linear form. Sequential storage structure based on dynamic array may be implemented to achieve the linear form sequential storage structure in the Java language, abstract data types we define the linear form for the interface List, which substantially follows :( methods are abstract, there are public abstract, where we omitted)

/*
定义线性表的接口List
List支持泛型E
该List线性表中所存储的具体数据类型由外界决定
 */
public interface List<E> extends Iterable<E>{	//接口继承Iterable为实现迭代器
    //获取线性表中元素的有效个数
    public abstract int getSize();  
    //判断线性表是否为空
    boolean isEmpty();
    //在线性表指定index角标处出入元素e
    void add(int index,E e);
    //在线性表的表头插入元素e
    void addFirst(E e);
    //在线性表的表尾插入元素e
    void addLast(E e);
    //获取线性表中指定角标index处元素
    E get(int index);
	//获取表头元素
    E getFirst();
	//获取表尾元素
    E getLast();
	//修改线性表中指定角标index处的元素为新元素e
    void set(int index,E e);
	//判断线性表中是否包含元素e
    boolean contains(E e);
    //查找元素e的角标(从左到又默认第一个出现的元素角标)
    int find(E e);
    //删除并返回线性表中指定角标index处的元素
    E remove(int index);
    //删除并返回表头元素
    E removeFist();
    //删除并返回表尾元素
    E removeLast();
    //删除指定元素e
    void removeElement(E e);
    //清空线性表
    void clear();
}

Next, write a linear sequence table storage structure ArrayList, it implements the interface List

import java.util.Iterator;
/*
创建线性表的顺序存储结构实现类ArrayList
 */
public class ArrayList<E> implements List<E>{
    //创建E类型的一维数组
    private E[] data;
    //维护元素的个数
    private int size;
    //默认最大容量为10
    private static int DEAFULT_CAOACITY=10;
    //创建一个默认大小的顺序表
    public ArrayList(){
        //data =(E[]) (new Objects[DEAFULT_CAOACITY]);
        //调用一个参数的构造函数传参
        this(DEAFULT_CAOACITY);
    }
    //创建一个容量由用户指定的顺序表
    public ArrayList(int capacity){
        if(capacity<=0){
            //没捕获没声明,运行异常,创建异常对象,抛出
            throw new IllegalArgumentException("容量必须>0"+capacity);
        }
        //对一维数组data进行初始化,类型给Object再强转为E泛型
        data=(E[])(new Object[capacity]);
        //有效元素个数初始为0
        size=0;
    }

    //用户传入一个数组,将该数组封装成一个顺序表
    public ArrayList(E[] data){
        if(data==null){
            throw new IllegalArgumentException("数组不能为空");
        }
        this.data=(E[])(new Object[data.length]);
        //读取传入数组元素,放入data
        for(int i=0;i<data.length;i++){
            this.data[i]=data[i];
        }
        //并更新有效元素个数
        size=data.length;
    }

    //重写接口中的获取有效元素个数
    @Override
    public int getSize() {
        //直接返回成员变量size
        return size;
    }

    //重写判空方法
    @Override
    public boolean isEmpty() {
        return size==0;
    }

    @Override
    public void add(int index,E e) {
        if(index<0||index>size){   //角标index越界的情况
            throw new IllegalArgumentException("角标越界");
        }
        //如果线性表满了就扩容
        if(size==data.length){
            //扩容(扩二倍)
            resize(data.length*2);
        }
        //插入元素
        for(int i=size;i>index;i--){    //后移元素
            data[i]=data[i-1];
        }
        data[index]=e;      //把元素插到index位置
        //有效元素个数更新
        size++;
    }
    //扩缩容函数
    private void resize(int newLength) {
        //创建新数组
        E[] newData=(E[])(new Object[newLength]);
        for(int i=0;i<size;i++){ //循环继续条件 data.length 和size都一样
            newData[i] = data[i];  //元素放入新数组
        }
        //偷梁换柱
        data = newData;
    }

    @Override
    public void addFirst(E e) {
        //表头插入元素,调用add,角标传0即可
        add(0,e);
    }

    @Override
    public void addLast(E e) {
        //表尾插入元素,调用add,角标传size即可
        add(size,e);
    }


    //重写获取线性表中指定角标index处的元素的方法
    @Override
    public E get(int index) {
        if(isEmpty()){  //判空,为空时不能获取元素
            throw new IllegalArgumentException("线性表为空");
        }
        if(index<0||index>=size){    //输入角标越界情况,抛异常
            throw new IllegalArgumentException("角标越界");
        }
        return data[index];
    }

    @Override
    public E getFirst() {
        //获取表头,调用get方法,index给0
        return get(0);
    }

    @Override
    public E getLast() {
        //获取表头,调用get方法,index给size-1
        return get(size-1);
    }

    //重写修改线性表中指定角标index处的元素为新元素e的方法
    @Override
    public void set(int index, E e) {
        if(isEmpty()){
            throw new IllegalArgumentException("线性表为空");
        }
        if(index<0||index>=size){
            throw new IllegalArgumentException("角标越界");
        }
        data[index]=e;  //把元素e给角标index对应位置
    }

    //重写 判断线性表中是否包含元素e
    @Override
    public boolean contains(E e) {
        //调用find方法,能找到就包含
        return find(e)!=-1;
    }

    //重写 查找元素e的角标
    @Override
    public int find(E e) {
        if(isEmpty()){  //判空 抛异常
            throw new IllegalArgumentException("线性表为空");
        }
        //遍历表中元素,与e对比,比的是内容
        for(int i=0;i<size;i++){
            if(data[i].equals(e)){  //data里面都是对象   ==比的是地址  equals比的是内容
                return i;
            }
        }
        return -1;
    }

    //重写 删除并返回线性表中指定角标index处的元素
    @Override
    public E remove(int index) {
        if(isEmpty()){  //表为空时,不可删除
            throw new IllegalArgumentException("线性表为空");
        }
        if(index<0||index>=size){
            throw new IllegalArgumentException("角标越界");
        }
        //把index处元素给变量ret,用于返回
        E ret = data[index];
        //把后面的元素前移
        for(int i=index+1;i<size;i++){
            data[i-1]=data[i];
        }
        //并将有效元素个数递减
        size--;
        //缩容的情况,条件是自定义
        if(size<=data.length/4&&data.length/2>=10){  //如果有效长度小于等于现在长度的1/4,同时缩容之后的长度大于等于10,才可以缩容
            resize(data.length/2);
        }
        //返回被删除元素
        return ret;
    }

    @Override
    public E removeFirst() {
        //删表头,调用remove方法
        return remove(0);
    }

    @Override
    public E removeLast() {
        //删表尾
        return remove(size-1);
    }

    //重写 删除指定元素e
    @Override
    public void removeElement(E e) {   //从左到右删第一个
        //先找到e,拿到角标
        int index = find(e);
        //如果角标存在
        if(index!=-1){
            //调用remove方法删除元素
            remove(index);
        }else{  //否则抛出异常
            throw new IllegalArgumentException("元素不存在");
        }
    }
    //重写 清空线性表方法
    @Override
    public void clear() {
        //把构造函数内容拿来用
        size=0;
        data=(E[])(new Object[DEAFULT_CAOACITY]);
    }

    //ArrayLis特有的方法 获取线性表容量
    public int getCapacity(){
        return data.length;
    }
    //toString方法
    /*打印这样的格式
        ArrayList:10/20
        []
    */
    public String toString(){
        //创建StringBuilder对象,不需要额外创字符串,在原来的上加字符
        StringBuilder sb = new StringBuilder();
        sb.append(String.format("ArrayList: %d/%d \n",size,data.length));
        //用数组的形式输出
        sb.append('[');
        if(isEmpty()){  //若为空,打印 []
            sb.append(']');
        }else{      //不为空,遍历线性表元素
            for(int i=0;i<size;i++){
                //在原来上加字符
                sb.append(data[i]);
                if(i==size-1){  //遍历到最后一个元素打印']'
                    sb.append(']');
                }else{          //不然在每个元素中间打','
                    sb.append(',');
                }
            }
        }
        //调用对象的tostring方法返回对象
        return sb.toString();
    }

    //返回当前数据结构的一个迭代器对象
    //迭代器用于在没有角标支持的环境下遍历元素
    @Override
    public Iterator<E> iterator() {
        return new ArrayListIterator();  //创建并返回内部类对象
    }
    //迭代器 内部类
    private class ArrayListIterator implements Iterator{ //
        //index初始为-1
        private int index=-1;

        @Override
        public boolean hasNext() {
            return index<size-1;
        }

        @Override
        public E next() {
            index++;
            return data[index];
        }
    }
}

Finish can write a test class to test the accuracy of each method.

Published 70 original articles · won praise 56 · views 1988

Guess you like

Origin blog.csdn.net/qq_43624033/article/details/103524948