一、抽象数据类型
抽象数据类型(abstract data type,ADT)是带有一组操作的一些对象的集合。
二、ArrayList 的实现
自定义ArrayList 实现代码如下:
package com.caitang.mjq;
import java.util.Iterator;
/**
* 自定义实现链表 问题:
* 1.何时使用theSize,何时使用size();
* 2.为何要扩容至两倍;
* @author Administrator
*
* @param <AnyType>
*/
public class MyArrayList <AnyType>implements Iterable<AnyType>
{
/**
* 自定义链表的默认容量 10
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 链表的大小——当前链表中的 元素的个数
*/
private int theSize;
/**
* 用于链表实现的数组
*/
private AnyType [] theItems;
/**
* 构造方法
*/
public MyArrayList()
{
doClear();
}
/**
* 清空链表
*/
public void clear()
{
doClear();
}
/**
* 清空链表
*/
private void doClear()
{
//设置链表元素个数为 0
theSize = 0;
//链表初始化方法,确保不发生异常
ensureCapacity(DEFAULT_CAPACITY);
}
/**
* 返回当前链表的元素个数
* @return
*/
public int size()
{
return theSize;
}
/**
* 返回当前链表是不是空表(元素个数是否为0)
* @return
*/
public boolean isEmpty()
{
return theSize == 0;
}
/**
* 将链表数组大小修改为元素个数大小,以避免空间资源浪费
*/
public void trimToSize()
{
ensureCapacity(size());
}
/**
* 获取某个指定索引位置上的元素
* @param idx 索引参数
* @return
*/
public AnyType get(int idx)
{
//如果索引参数小于0或者大于链表元素最大索引(size()-1,从零开始,等于链表元素个数-1);则抛出数组越界异常
if(idx<0||idx>=size())
{
throw new ArrayIndexOutOfBoundsException();
}
return theItems[idx];
}
/**
* 修改链表中指定索引位置处的元素的值为指定的值
* @param idx 索引参数
* @param newVal 新的元素值
* @return 原来的元素值
*/
public AnyType set(int idx,AnyType newVal)
{
if(idx<0||idx>=size())
{
throw new ArrayIndexOutOfBoundsException();
}
AnyType old = theItems[idx];
theItems [idx] = newVal;
return old;
}
/**
* 对链表容量进行扩充,以保证不会发生数组越界。
* @param newCapacity 扩充后的容量
*/
@SuppressWarnings("unchecked")
public void ensureCapacity(int newCapacity)
{
//如果需要扩增的容量小于当前链表的元素个数,则表明预期链表容量完全够用,不用扩容,直接返回。
if(newCapacity<theSize)
{
return;
}
//否则,就需要对现在的链表扩容至新容量大小,以保证后续操作不会使数组越界。
AnyType [] old = theItems;
theItems = (AnyType[]) new Object[newCapacity];
for(int i =0;i<size();i++)
{
theItems[i] = old[i];
}
}
/**
* 在指定索引位置新增元素
* @param idx 索引参数
* @param x 新增元素
*/
public void add(int idx,AnyType x)
{
//如果链表数组还剩下一个元素的空位,则将链表容量扩容至两倍
if(theItems.length==size())
{
ensureCapacity(size()*2+1);
}
//从索引位置开始,其后每个元素都向后移动一个位置
for(int i = theSize;i>idx;i--)
{
theItems[i]=theItems[i-1];
}
//设置 位置索引为 idx处的元素的值为x
theItems[idx] = x;
//链表大小(元素个数)+1
theSize++;
}
/**
* 向链表最后端添加元素
* @param x 添加的新元素
* @return 是否添加成功
*/
public boolean add(AnyType x)
{
add(size(),x);
return true;
}
/**
* 删除指定索引处的元素
* @param idx 位置索引参数
* @return 被删除的元素值
*/
public AnyType remove(int idx)
{
if(idx<0||idx>=size())
{
throw new ArrayIndexOutOfBoundsException();
}
AnyType removedItem = theItems[idx];
for(int i=idx;i<size()-1;i++)
{
theItems[i]=theItems[i+1];
}
theSize --;
return removedItem;
}
/**
* 链表 迭代器 返回自定义迭代器
*/
@Override
public Iterator<AnyType> iterator()
{
return new ArrayListIterator();
}
/**
* 内部类 实现Iterator
* @author Administrator
*
*/
private class ArrayListIterator implements java.util.Iterator<AnyType>
{
/**
* 迭代器当前指针位置——与链表数组的索引对应
*/
private int current = 0;
/**
* 是否有下一个元素
*/
@Override
public boolean hasNext()
{
return current < size();
}
/**
* 返回下一个元素(当前索引+1 处)
*/
@Override
public AnyType next()
{
if(!hasNext())
{
throw new java.util.NoSuchElementException();
}
return theItems[current++];
}
/**
* 迭代器 删除链表元素;循环中直接使用链表方法进行元素删除会抛出异常,需要使用迭代器的删除方法
* 问题:迭代器删除方法同样是调用链表删除元素的方法,为什么使用迭代器删除方法就不会报错,而使用链表删除方法就会报错?
*/
public void remove()
{
MyArrayList.this.remove(--current);
}
}
}
单元测试代码如下:
package com.caitang.mjq.test;
import org.junit.Before;
import org.junit.Test;
import com.caitang.mjq.MyArrayList;
public class TestMyArrayList
{
/**
* 自定义链表测试对象
*/
private MyArrayList<Integer> list = new MyArrayList<Integer>();
@Before
public void add()
{
list.add(1);
list.add(2);
list.add(3);
list.add(4);
assert list.size() == 3 :"链表新增元素,大小异常";
}
@Test
public void create()
{
assert list.size() == 0:"链表初始化大小异常";
}
/**
*
*/
@Test
public void isEmpty()
{
boolean b = list.isEmpty();
assert b == true : "是否是空链表异常";
}
@Test
public void get()
{
assert list.get(2)==3 : "链表获取元素,元素值异常";
}
@Test
public void remove()
{
list.remove(0);
assert list.get(0) == 2;
assert list.get(1) == 3;
assert list.size() == 3;
list.remove(2);
assert list.get(1) == 3;
assert list.size() == 2;
}
@Test
public void set()
{
list.set(1, 1);
assert list.get(1) == 1;
}
/**
*
*/@Test
public void clear()
{
list.clear();
assert list.size() == 0;
}
}
单元测试运行结果如下: