Java数据结构·顺序表ArrayList类的实现

本文详细介绍了如何实现一个顺序表,包括接口设计、成员变量、添加、查找、删除等方法,同时与Java内置的ArrayList类的功能进行了对比。
摘要由CSDN通过智能技术生成

一. 顺序表的定义

        顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。

       注:该数组实现的思想和  ArrayList  类  里的相应方法  在实现上类似, 有助于理解 ArrayList 类 的用法
 

 二. 接口的实现

        首先,我们需要认识到,一个顺表拥有哪些功能。比如:增删查改判定等,那这是我们可以借助接口来实现这些功能。

public interface IList {
    // 新增元素,默认在数组最后新增
    public void add(int data);

    // 在 pos 位置新增元素
    public void add(int pos, int data);

    // 判定是否包含某个元素
    public boolean contains(int toFind);

    // 查找某个元素对应的位置
    public int indexOf(int toFind);

    // 获取 pos 位置的元素
    public int get(int pos);

    // 给 pos 位置的元素设为 value
    public void set(int pos, int value);

    //删除第一次出现的关键字key
    public void remove(int toRemove);

    // 获取顺序表长度
    public int size();

    // 清空顺序表
    public void clear();

    // 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
    public void display();

    //判断顺序表是否满
    boolean isFull();

    //判断顺序表是否为空
    boolean isEmpty();
}

三. 成员变量

         我们还需要一些成员变量来助我们实现顺序表。

         比如:public int[] elem  数组作为顺序表的载体

                    public int usedSize  用于记录数组的有效数据

                    public static final int DEFAULT_CAPACITY  作为数组的默认大小

         以及  public MyArrayList()  构造方法来初始化elem数组

public class MyArrayList implements IList {
    public int[] elem;

    public int usedSize; //记录数组的有效数据

    public static final int DEFAULT_CAPACITY = 5;  //默认容量

    //初始化elem数组
    public MyArrayList() {
        elem = new int[DEFAULT_CAPACITY];
    }
}

四. 实现接口当中的方法

4.1  public void add(int data)方法

        该方法的作用即是在数组的尾部插入新元素,即所谓的尾插法。但需要注意的是,因为前面我们通过实现构造方法来初始化elem数组,使得该数组有一定的空间,所以我们需要在每次插入新元素之间线判断数组是否满,如若满了,则需扩容。

        那么  if(isFull())语句的所用则是判断是否满,如果满,则用  Arrays  的  copyof()  方法来进行2倍扩容。注:isFull()方法在后面会有介绍

        之后则将  data  赋值到  elem  数组的  usedSize  位置上, 然后  usedSize++  来增加数组的有效数据。 

 /**
     * 新增元素,默认在数组最后新增
     * @param data
     */
    @Override
    public void add(int data) {
        // 先判断是否满  满了要扩容
        if (isFull()) {
            elem = Arrays.copyOf(elem, 2 * elem.length );
        }
        elem[usedSize] = data;
        usedSize++;
    }

4.2  public boolean isFull() 方法

/**
     * 判断顺序表是否满
     * @return
     */
    @Override
    public boolean isFull() {
        return usedSize == elem.length;
    }

        该方法的类型是  boolean,  如果  usedSize  ==  elem.length, 则返回true , 否则为false。  

        用于给其他方法中的  if  语句 做判断。

4. public void add(int pos, int data) 方法

       注意:该方法与前面的  add  方法有些许不同, 该方法是在指定位置插入, 不一定是尾插。

       但在插入之间我们还需要判断插入的位置是否  越界  ,  则我们可以新写一个  private void CheckPosofAdd(int pos)  方法  来判断,  之所以为  private, 是因为该方法只为  add  方法用。

        如果  pos  位置越界,  则抛出异常。(我们还需要新创个类  public class EmptyException  来继承  RuntimeException  

public class EmptyException extends RuntimeException{
    public EmptyException() {

    }

    public EmptyException(String msg) {
        super(msg);
    }
}
 /**
     * 检查pos位置 只对上面的方法使用
     * @param pos
     */
    private void checkPosOfAdd(int pos){
        if (pos < 0 || pos > usedSize) {
            throw new PosException("pos位置为" + pos);
        }
    }

      还要判断是否需要扩容 (同理前面)

      最后, 用  for  循环来将  pos  位置之后的所有元素向后挪一位,  再将  data  赋值到  pos  位置,  然后  usedSiz ++  即可。

/**
     * 在 pos 位置新增元素
     * @param pos
     * @param data
     */
    @Override
    public void add(int pos, int data) {
        //判断pos位置
        checkPosOfAdd(pos);
        // 判断是否满 满需要扩容
        if (isFull()) {
            elem = Arrays.copyOf(elem, 2 * elem.length );
        }

        for (int i = usedSize - 1; i >= pos; i--) {
            elem[i + 1] = elem[i];
        }
        elem[pos] = data;
        usedSize++;
    }

4.4  public boolean contains(int toFind) 方法

      该方法用于判断是否包含某个元素。

      用  for  循环遍历数组,  如果找到  则返回   ture,  否则  false

/**
     * 判定是否包含某个元素
     * @param toFind
     * @return
     */
    @Override
    public boolean contains(int toFind) {
        for (int i = 0; i < elem.length; i++) {
            if (toFind == elem[i]) {
                return true;
            }
        }
        return false;
    }

4.5  public int indexOf(int toFind) 方法

        该方法用于查找某个元素的位置

        用  for  循环遍历数组,  如果所要查找的元素存在,  则返回此时的下标值,  即  i

/**
     * 查找某个元素对应的位置
     * @param toFind
     * @return
     */
    @Override
    public int indexOf(int toFind) {
        for (int i = 0; i < elem.length; i++) {
            if (toFind == elem[i]) {
                return i;
            }
        }
        return 0;
    }

4.6  public int get(int pos) 方法

      该方法的作用是   获取 pos 位置的元素。

      但在获取之前我们还需要检查数组是否为空

      即  新写一个  public boolean isEmpty()  方法

/**
     * 检查pos是否为空
     * @return
     */
    @Override
    public boolean isEmpty() {
        return usedSize == 0;
    }

       除此之外,  我们也需要检查  pos  是否合法, 不合法则抛出异常。(同理前面所提到的异常)

/**
     * //检查pos是否合法
     * @param pos
     */
    private void checkPosOfGet(int pos) {
        if (pos < 0 || pos >= this.usedSize) {
            throw new PosException("pos位置不合法:" + pos);
        }
    }

4.7  public void set(int pos, int value)  方法

      该方法用于将  pos  位置的值修改为  value

      同理,在修改之前, 需要检查  pos  是否合法 ,  以及顺序表是否为空。 没问题,则直接赋值。

 /**
     * 更新 pos 位置的值为 value
     * @param pos
     * @param value
     */
    @Override
    public void set(int pos, int value) {
        checkPosOfGet(pos);
        if (isEmpty()) {
            throw new EmptyException("顺序表为空");
        }
        this.elem[pos] = value;

    }

4.8  public void remove(int toRemove) 方法

      该方法用于删除第一次出现的值  toRemove

      首先,判断顺序表是否为空

      然后, 调用  indexof()  方法,  找出  toRemove  的位置,  然后遍历数组, 将  toRemove  后面的元素全部往前挪一位

       最后,  usedSize --  即可

 /**
     * 删除第一次出现的toRemove
     * @param toRemove
     */
    @Override
    public void remove(int toRemove) {
        if (isEmpty()) {
            throw new EmptyException("顺序表为空,不能删除");
        }

        int index = indexOf(toRemove);

        for (int i = index; i < usedSize - 1; i++) {
            elem[i] = elem[i + 1];
        }
        usedSize--;
    }

4.9  public int size()  方法

      该方法用于获取数组长度

 /**
     * 获取顺序表长度
     * @return
     */
    @Override
    public int size() {
        return this.usedSize;
    }

4.10  public void clear() 方法

    清空顺序表 防止内存泄漏
 /**
     * 清空顺序表 防止内存泄漏
     */
    @Override
    public void clear() {
        elem = null;
    }

4.11  public void display() 方法

        该方法用于打印顺序表

        注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的

/**
     * 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
     */
    @Override
    public void  display() {
        for (int i = 0; i < usedSize; i++) {
            System.out.println(elem[i] + " ");
        }
        System.out.println();
    }

五. 全部代码

import java.util.Arrays;

public class MyArrayList implements IList {
    public int[] elem;

    public int usedSize; //记录数组的有效数据

    public static final int DEFAULT_CAPACITY = 5;  //默认容量

    //初始化elem数组
    public MyArrayList() {
        elem = new int[DEFAULT_CAPACITY];
    }

    /**
     * 新增元素,默认在数组最后新增
     * @param data
     */
    @Override
    public void add(int data) {
        // 先判断是否满  满了要扩容
        if (isFull()) {
            elem = Arrays.copyOf(elem, 2 * elem.length );
        }
        elem[usedSize] = data;
        usedSize++;
    }

    /**
     * 判断顺序表是否满
     * @return
     */
    @Override
    public boolean isFull() {
        return usedSize == elem.length;
    }

    /**
     * 在 pos 位置新增元素
     * @param pos
     * @param data
     */
    @Override
    public void add(int pos, int data) {
        //判断pos位置
        checkPosOfAdd(pos);
        // 判断是否满 满需要扩容
        if (isFull()) {
            elem = Arrays.copyOf(elem, 2 * elem.length );
        }

        for (int i = usedSize - 1; i >= pos; i--) {
            elem[i + 1] = elem[i];
        }
        elem[pos] = data;
        usedSize++;
    }

    /**
     * 检查pos位置 只对上面的方法使用
     * @param pos
     */
    private void checkPosOfAdd(int pos){
        if (pos < 0 || pos > usedSize) {
            throw new PosException("pos位置为" + pos);
        }
    }

    /**
     * 判定是否包含某个元素
     * @param toFind
     * @return
     */
    @Override
    public boolean contains(int toFind) {
        for (int i = 0; i < elem.length; i++) {
            if (toFind == elem[i]) {
                return true;
            }
        }
        return false;
    }

    /**
     * 查找某个元素对应的位置
     * @param toFind
     * @return
     */
    @Override
    public int indexOf(int toFind) {
        for (int i = 0; i < elem.length; i++) {
            if (toFind == elem[i]) {
                return i;
            }
        }
        return 0;
    }

    /**
     * 获取 pos 位置的元素
     * @param pos
     * @return
     */
    @Override
    public int get(int pos) {
        //检查pos是否合法
        checkPosOfGet(pos);
        //检查pos是否为空
        if (isEmpty()) {
            throw new EmptyException("顺序表为空");
        }
        return elem[pos];
    }

    /**
     * 检查pos是否为空
     * @return
     */
    @Override
    public boolean isEmpty() {
        return usedSize == 0;
    }

    /**
     * //检查pos是否合法
     * @param pos
     */
    private void checkPosOfGet(int pos) {
        if (pos < 0 || pos >= this.usedSize) {
            throw new PosException("pos位置不合法:" + pos);
        }
    }

    /**
     * 更新 pos 位置的值为 value
     * @param pos
     * @param value
     */
    @Override
    public void set(int pos, int value) {
        checkPosOfGet(pos);
        if (isEmpty()) {
            throw new EmptyException("顺序表为空");
        }
        this.elem[pos] = value;

    }

    /**
     * 删除第一次出现的toRemove
     * @param toRemove
     */
    @Override
    public void remove(int toRemove) {
        if (isEmpty()) {
            throw new EmptyException("顺序表为空,不能删除");
        }

        int index = indexOf(toRemove);

        for (int i = index; i < usedSize - 1; i++) {
            elem[i] = elem[i + 1];
        }
        usedSize--;
    }

    /**
     * 获取顺序表长度
     * @return
     */
    @Override
    public int size() {
        return this.usedSize;
    }

    /**
     * 清空顺序表 防止内存泄漏
     */
    @Override
    public void clear() {
        elem = null;
    }

    /**
     * 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
     */
    @Override
    public void  display() {
        for (int i = 0; i < usedSize; i++) {
            System.out.println(elem[i] + " ");
        }
        System.out.println();
    }
}
public class EmptyException extends RuntimeException{
    public EmptyException() {

    }

    public EmptyException(String msg) {
        super(msg);
    }
}
public interface IList {
    // 新增元素,默认在数组最后新增
    public void add(int data);

    // 在 pos 位置新增元素
    public void add(int pos, int data);

    // 判定是否包含某个元素
    public boolean contains(int toFind);

    // 查找某个元素对应的位置
    public int indexOf(int toFind);

    // 获取 pos 位置的元素
    public int get(int pos);

    // 给 pos 位置的元素设为 value
    public void set(int pos, int value);

    //删除第一次出现的关键字key
    public void remove(int toRemove);

    // 获取顺序表长度
    public int size();

    // 清空顺序表
    public void clear();

    // 打印顺序表,注意:该方法并不是顺序表中的方法,为了方便看测试结果给出的
    public void display();

    //判断顺序表是否满
    boolean isFull();

    //判断顺序表是否为空
    boolean isEmpty();
}

六. ArrayList使用

6.1  ArrayList的构造

ArrayList()无参构造
ArrayList(Collection<? extends E> c)利用其他 Collection 构建 ArrayList
ArrayList(int initialCapacity)指定顺序表初始容量
public static void main(String[] args) {
// ArrayList创建,推荐写法
// 构造一个空的列表
List<Integer> list1 = new ArrayList<>();
// 构造一个具有10个容量的列表
List<Integer> list2 = new ArrayList<>(10);
list2.add(1);
list2.add(2);
list2.add(3);
// list2.add("hello"); // 编译失败,List<Integer>已经限定了,list2中只能存储整形元素
// list3构造好之后,与list中的元素一致
ArrayList<Integer> list3 = new ArrayList<>(list2);
// 避免省略类型,否则:任意类型的元素都可以存放,使用时将是一场灾难
List list4 = new ArrayList();
list4.add("111");
list4.add(100);
}

6.2   ArrayList 的  add(E  e)  方法

该方法的实现思想类似于我们前面的  public void add(int data)  方法, 尾插  e

import java.util.ArrayList;
public class Main {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(1);
        arrayList.add(2);
        arrayList.add(3);
        arrayList.add(4);
        System.out.println(arrayList);
    }
}

输出结果为:

6.3  ArrayList 的  add  (int index, E element)  方法

该方法的实现思想类似于我们前面的  public void add(int pos, int data) 方法,

将 element 插入到 index 位置

import java.util.ArrayList;
public class Main {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(1);
        arrayList.add(2);
        arrayList.add(3);
        arrayList.add(4);
        arrayList.add(2, 17);
        System.out.println(arrayList);
    }
}

输出结果为:

6.4  ArrayList 的  remove  (int  index) 方法

该方法的实现思想类似于我们前面的  public void remove(int toRemove) 方法,

删除 index 位置元素

import java.util.ArrayList;
public class Main {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(10);
        arrayList.add(20);
        arrayList.add(30);
        arrayList.add(40);
        arrayList.remove(2);
        System.out.println(arrayList);
    }
}

输出结果为:

6.5  ArrayList 的  contains  (Object  o)  方法

该方法的实现思想类似于我们前面的  public boolean contains(int toFind)  方法,

判断 o 是否在线性表中

import java.util.ArrayList;
public class Main {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(10);
        arrayList.add(20);
        arrayList.add(30);
        arrayList.add(40);
        System.out.println(arrayList.contains(40));
    }
}

输出结果:

6.6  ArrayList 的  indexof(Object  o)方法

该方法的实现思想类似于我们前面的   public int indexOf(int toFind) 方法,  返回第一个 o 所在下标

import java.util.ArrayList;
public class Main {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(10);
        arrayList.add(20);
        arrayList.add(30);
        arrayList.add(40);
        System.out.println(arrayList.indexOf(20));
    }
}

输出结果:

6.7  ArrayList 的 clear() 方法

该方法的实现思想类似于我们前面的  public void clear() 方法, 清空数组

import java.util.ArrayList;
public class Main {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(10);
        arrayList.add(20);
        arrayList.add(30);
        arrayList.add(40);
        System.out.println(arrayList);
        System.out.println("=================");
        arrayList.clear();
        System.out.println(arrayList);
    }
}

输出结果:

6.8   ArrayList 的  get(int index) 方法

该方法的实现思想类似于我们前面的  public int get(int pos)  方法,获取下标 index 位置元素

import java.util.ArrayList;
public class Main {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(10);
        arrayList.add(20);
        arrayList.add(30);
        arrayList.add(40);
        System.out.println(arrayList.get(2));
    }
}

输出结果:

6.9  ArrayList 的  set (int index, E element) 方法

该方法的实现思想类似于我们前面的  public void set(int pos, int value)  方法

将下标 index 位置元素设置为 element

import java.util.ArrayList;
public class Main {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(10);
        arrayList.add(20);
        arrayList.add(30);
        arrayList.add(40);
        System.out.println(arrayList);
        System.out.println("=====================");
        arrayList.set(2, 78);
        System.out.println(arrayList);
    }
}

输出结果:

七.  ArrayList 的 遍历

ArrayList 的 遍历  有三种方式, 分别为  for循环、foreach、使用迭代器

public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);

// 使用下标+for遍历
for (int i = 0; i < list.size(); i++) {
System.out.print(list.get(i) + " ");
} 
System.out.println();

// 借助foreach遍历
for (Integer integer : list) {
System.out.print(integer + " ");
} 
System.out.println();
//迭代器
Iterator<Integer> it = list.listIterator();
while(it.hasNext()){
System.out.print(it.next() + " ");
} S
ystem.out.println();
}


 

  • 15
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值