实现简单的List功能
简单的实现javaArrayList(可扩容)功能,实现新增,删除,取数据。
package algorithm.data_structure; /** * 模拟ArrayList类的功能 * @author fangsh * */ public class SimpleList<T> { private Object[] elements ; private int size = 0 ;//记录元素数组的长度 private int elementsNum = 0 ;//记录元素的个数 private final static int ADD_NUMBER = 10 ;//扩容数量 private final static int RELEASE_CACHE = 5 ;//释放内存的大小 /** * 添加元素 * @param e * @return */ public void add(T e){ if(elements == null) elements = new Object[10] ; // 初始化元素数组,初始化长度为10 if(elements.length <= elementsNum){//判断是否有空间添加元素 addNumberCache() ; } elements[elementsNum] = e ; elementsNum++ ; } /** * 删除元素的方法,删除元素时,列表的长度不应该有所改变 * @param e * @return * 第一次写方法时犯的错误:对象比较的时候,使用了==,应该使用equals; * 需要优化的地方,在删除元素的时候,是否把元素占用的内存释放(涉及长度不够增加的情况) */ public boolean remove(T e){ if(elements != null){ if(elements.length > 0){ int removeIndex = 0 ; for(int i=0; i<elements.length; i++){ Object obj = elements[i] ; if(obj.equals(e)){ removeIndex = i ; break ; } } Object[] newObject = new Object[elements.length - 1] ; for(int begin=0; begin<removeIndex; begin++){ newObject[begin] = elements[begin] ; } for(int continueIndex= removeIndex+1; continueIndex<elements.length; continueIndex++){ newObject[continueIndex - 1] = elements[continueIndex] ; } elements = newObject ; elementsNum -- ; return true ; } } return false ; } /** * 改进的删除方法,返回删除的元素,并且删除时不修改列表的长度 * @param t * @return */ public T remove2(T t) throws Throwable{ if(elements == null || isEmpty()) throw new Throwable("列表为空,或者列表中没有数据") ; int removeIndex = -1 ; for(int i=0; i<elements.length; i++){ Object obj = elements[i] ; if(obj.equals(t)){ removeIndex = i ; } if(removeIndex != -1){ Object nextElement = null ; if(i != elements.length-1) nextElement = elements[i+1] ; elements[i] = nextElement ; } } elementsNum -- ; if(removeIndex < 0) throw new Throwable("删除的元素不在列表内!") ; return t ; } public boolean isEmpty(){ if(elementsNum == 0){ return true ; } return false ; } @SuppressWarnings("unchecked") public T get(int index) throws Throwable{ if(elements == null) throw new NullPointerException("列表为空!") ; if(index < 0) throw new Throwable("请输入有效的列表下标!") ; if(index > elements.length) throw new Throwable("您输入的下标超过列表元素的个数!") ; return (T)elements[index-1] ; } /** * 扩容的方法,默认扩容的长度为10 */ private void addNumberCache(){ if(elements == null) return ; if(elements.length == elementsNum){ Object[] newElements = new Object[elementsNum + ADD_NUMBER] ; for(int i=0; i<elements.length; i++){ newElements[i] = elements[i] ; } elements = newElements ; } } /** * 当SimpleList中的空余内存达到一定数量时,释放SimpleList中的内存 */ private void releaseNumberCache(){ if(elements == null) return ; if(elements.length > (elementsNum + 10)){//达到释放标准 Object[] newElements = new Object[elements.length - RELEASE_CACHE] ; for(int i=0; i<(elements.length - RELEASE_CACHE); i++){ newElements[i] = elements[i] ; } elements = newElements ; } } /** * 查询列表元素的个数 * @return */ public int getElementNum(){ return elementsNum; } /** * 查询元素列表的长度 * 注意这个方法一定不能用来判断列表元素的个数,因为列表可能存在多余空间 * @return */ public int getSize() throws Throwable{ if(elements == null) throw new Throwable("列表为空!") ; return elements.length ; } }
总结一下,做这个时出现的一些问题,日后注意:
1、在对比对象的时候,一开始脑残的使用了“==” ,导致删除方法不成功,对象比较注意一定使用equals方法。
2、做删除元素的时候,将元素数组的长度减少了,没有更新size这个字段,这个字段可以不用,需要这个值的时候,直接调用数组的length方法,减少bug出现的可能性(要随时同步size这个值,增加了出bug的可能性)
3、一开始的删除方法,会新建一个数组,并且还要重新遍历原素组,将元素重新加入到新数组中,这样造成资源的浪费,可以直接将被删除元素之后的元素依次往前移,最后一个数组位置补null。这样避免了新建数组造成的资源开销。