根据Java中ArrayList模仿实现线性表
1. 线性表概念
- 具有n个相同类型元素的有限序列
2. 成员变量和接口设计
2.1 成员变量
因为线性表是根据数组来实现的,所以需要一个数组来存储元素,并且一个size方法来记录表中数据数量。
/**
* 元素的数量
*/
private int size;
/**
* 所有的元素
*/
private E[] elements;
2.2 接口设计
int size()
:返回线性表长度;boolean isEmpty()
:判断线性表是否为空;boolean contains(E element)
:判断线性表中是否存在某元素;void add(E element)
:添加元素;E get(int index)
:返回index位置的元素;E set(int index, E elemnt)
:设置index位置的元素为element;void add(int index, E element)
:向index位置添加元素element;E remove(int index)
:删除index位置的元素;int indexOf(E element)
:查看元素的位置;void clean()
:清空线性表。
3. 接口实现
3.1 构造方法
如果没有调用无参构造方法就直接指定表的长度为默认值,否则就根据指定长度来。
// 默认容量
private static final int DEFAULT_CAPACITY = 10;
// 最大数组长度
private static final int MAX_LENGTH = Integer.MAX_VALUE - 1;
/**
* 有参构造函数
* @param capacity 容量
*/
public ArrayList(int capacity) {
capacity = Math.max(capacity, DEFAULT_CAPACITY);
capacity = Math.min(capacity,MAX_LENGTH);
elements = (E[]) new Object[capacity];
}
/**
* 无参构造函数,根据默认长度设置
*/
public ArrayList() {
this(DEFAULT_CAPACITY);
}
3.2 简单方法实现
void clear()
/**
* 清除所有元素
*/
public void clear() {
// 如果添加的元素是对象,需要把实例化的对象赋值为null,关闭它的引用。
for (int i = 0; i < size; i++) {
elements[i] = null;
}
size = 0;
}
int size()
/**
* 元素的数量
* @return size
*/
public int size() {
return size;
}
boolean isEmpty()
/**
* 是否为空
* @return true / false
*/
public boolean isEmpty() {
return size == 0;
}
int indexOf(E element)
/**
* 查看元素的索引
* @param element
* @return
*/
public int indexOf(E element) {
for (int i = 0; i < elements.length;i++) {
if (elements[i].equals(element)){
return i;
}
}
return ELEMENT_NOT_FOUND;
}
boolean contains(E element)
/**
* 是否包含某个元素
* @param element 元素
* @return true / false
*/
public boolean contains(E element) {
return indexOf(element) != ELEMENT_NOT_FOUND;
}
E get(int index)
/**
* 获取index位置的元素
* @param index
* @return
*/
public E get(int index) {
rangeCheck(index);
return elements[index];
}
E set(int index, E element)
/**
* 设置index位置的元素
* @param index
* @param element
* @return 原来的元素ֵ
*/
public E set(int index, E element) {
E oldE = elements[index];
elements[index] = element;
return oldE;
}
- 重写
toString()
@Override
public String toString() {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("list = { [")
for (int i = 0; i < size; i++) {
stringBuffer.append(elements[i]);
if (i != size - 1){
stringBuffer.append(",");
}
}
stringBuffer.append("],");
stringBuffer.append("size =").append(size).append("}");
return stringBuffer.toString();
}
- 私有方法
/**
* 抛出异常方法
* @param index
*/
private void outOfBounds(int index) {
throw new IndexOutOfBoundsException("Index:" + index + ", Size:" + size);
}
/**
* inde限制
* @param index
*/
private void rangeCheck(int index) {
if (index < 0 || index >= size) {
outOfBounds(index);
}
}
/**
* 添加时针对index限制
* @param index
*/
private void rangeCheckForAdd(int index) {
if (index < 0 || index > size) {
outOfBounds(index);
}
}
3.3 remove
删除线性表中的某个节点,不能影响到其它的节点顺序,就需要从后往前移动
/**
* 查看元素的索引
* @param element
* @return
*/
public int indexOf(E element) {
if (element == null) {
for (int i = 0; i < size; i++) {
if (elements[i]==null) {
return i;
}
}
for (int i = 0; i < elements.length;i++) {
if (element.equals(elements[i])){
return i;
}
}
return ELEMENT_NOT_FOUND;
}
3.4 add
如果在某个位置添加元素,为了保证线性表中其它元素顺序不会发生变化,就需要从最后一个开始向后挪动其它元素。
/**
* 在index位置插入一个元素
* @param index
* @param element
*/
public void add(int index, E element) {
rangeCheckForAdd(index);
for (int i = size - 1; i >= index; i--) {
elements[i + 1] = elements[i];
}
elements[index] = element;
size++;
}
/**
* 添加元素到尾部
* @param element
*/
public void add(E element) {
add(size,element);
}
3.5 扩容方法
由于是基于数组实现的,无法直接再申请一片刚刚好跟当前数组连续的内存,因此只能开辟一个更大内存的数组,然后将原有的数据复制到新数组中。
/**
* 保证要有capacity的容量
* @param capacity
*/
private void ensureCapacity(int capacity) {
int oldCapacity = elements.length;
if (oldCapacity >= capacity){
return;
}
// 变成原先容量的 1.5 倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity > MAX_LENGTH){
newCapacity = MAX_LENGTH;
}
E[] newElelemtns = (E[]) new Object[capacity];
for (int i = 0; i < size; i++) {
newElelemtns[i] = elements[i];
}
elements = newElelemtns;
}
4. 测试类实现
由于后面代码需要进行很多测试,与其自己查看对错,不如直接编写测试类来比较
/**
* @Description 测试工具类
* @date 2022/4/5 10:07
*/
public class AssertUtils {
public static void test(boolean v){
try {
if (!v) {
throw new Exception("测试未通过");
}
}catch (Exception e){
e.printStackTrace();
}
}
}