Linked List
- 用多少就申请多少内存。
- 链表是一种链式存储的线性表,所有元素的内存地址不一定连续的。
接口设计
代码实现
MyList.java(接口)
package com.cyb; public interface MyList<E> { /** * 元素未找到 */ static final int ELEMENT_NOT_FOUND = -1; /** * 清除所有元素 */ void clear(); /** * 元素的数量 * * @return */ int size(); /** * 是否为空 * * @return */ boolean isEmpty(); /** * 是否包含某个元素 * * @param element 元素 * @return */ boolean contains(E element); /** * 添加元素至尾部 * * @param element 元素 */ void add(E element); /** * 在指定索引下标处添加元素 * * @param index 下标索引 * @param element 元素 */ void add(int index, E element); /** * 获取元素 * * @param index 索引下标 * @return */ E get(int index); /** * 设置index位置的元素 * * @param index 索引下标 * @param element 元素 * @return 原来的元素 */ E set(int index, E element); /** * 移除指定索引处的元素 * * @param index 索引下标 * @return */ E remove(int index); /** * 查看元素的索引 * * @param element 元素 * @return */ int indexOf(E element); }
AbstractMyList.java(抽象类)
package com.cyb; public abstract class AbstractMyList<E> implements MyList<E> { /** * 元素的数量 */ protected int size; /** * /** 元素的个数 * * @return */ public int size() { return size; } /** * 是否为空 * * @return */ public boolean isEmpty() { return size == 0; } /** * 是否包含某个元素 * * @param element 元素 * @return */ public boolean contains(E element) { return indexOf(element) != ELEMENT_NOT_FOUND; } /** * 添加元素到最后面 * * @param element */ public void add(E element) { add(size, element); } protected void outOfBounds(int index) { throw new IndexOutOfBoundsException("Index:" + index + ",Size:" + size); } /** * 范围检测 * * @param index 索引下标 */ protected void rangeCheck(int index) { if (index < 0 || index >= size) { outOfBounds(index); } } /** * 范围检测 * * @param index 索引下标 */ protected void rangeCheckForAdd(int index) { if (index < 0 || index > size) { outOfBounds(index); } } }
MyArrayList.java
package com.cyb; /** * 自定义ArrayList数组 * * @author chenyanbin * */ public class MyArrayList<E> extends AbstractMyList<E> { /** * 所有元素 */ private E[] elements; private static final int DEFAULT_CAPACITY = 100; public MyArrayList() { this(DEFAULT_CAPACITY); } @SuppressWarnings("unchecked") public MyArrayList(int capacity) { capacity = (capacity < DEFAULT_CAPACITY) ? DEFAULT_CAPACITY : capacity; elements = (E[]) new Object[capacity]; } /** * 往index位置添加元素 * * @param index 索引下标 * @param element 元素 */ public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacity(size + 1); for (int i = size; i > index; i--) { elements[i] = elements[i - 1]; } elements[index] = element; size++; } /** * 返回index位置对应的元素 * * @param index 索引下标 * @return */ public E get(int index) { rangeCheck(index); return elements[index]; } /** * 设置index位置的元素 * * @param index 索引下标 * @param element 元素 * @return 原来的元素 */ public E set(int index, E element) { rangeCheck(index); E oldElement = elements[index]; elements[index] = element; return oldElement; } /** * 删除index位置对应的元素 * * @param index 索引下标 * @return 删除的元素值 */ public E remove(int index) { rangeCheck(index); E result = elements[index]; for (int i = index + 1; i < size; i++) { elements[i - 1] = elements[i]; } elements[--size] = null; return result; } /** * 删除对象 * * @param element 对象 */ public void remove(E element) { remove(indexOf(element)); } /** * 查看元素的位置 * * @param element 元素 * @return */ @SuppressWarnings("null") public int indexOf(E element) { if (element == null) { for (int i = 0; i < size; i++) { if (elements[i] == null) return i; } } else { for (int i = 0; i < size; i++) { if (element.equals(elements[i])) return i; } } return ELEMENT_NOT_FOUND; } /** * 清除所有元素 */ public void clear() { for (int i = 0; i < size; i++) { elements[i] = null; } size = 0; } @Override public String toString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("size=").append(size).append(",["); for (int i = 0; i < size; i++) { // 方式一(推荐) if (i > 0) { stringBuilder.append(","); } stringBuilder.append(elements[i]); // 方式二(不推荐) // if (i!=size-1) { // stringBuilder.append(","); // } } stringBuilder.append("]"); return stringBuilder.toString(); } /** * 保证要有capacity的容量 * * @param capacity 容量 */ private void ensureCapacity(int capacity) { int oldCapacity = elements.length; if (oldCapacity >= capacity) return; // 新容量为旧容量的1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); @SuppressWarnings("unchecked") E[] newElements = (E[]) new Object[newCapacity]; for (int i = 0; i < size; i++) { newElements[i] = elements[i]; } elements = newElements; System.out.print("容量从" + oldCapacity + "扩展为" + newCapacity + " "); } }
MyLinkedList.java
package com.cyb; public class MyLinkedList<E> extends AbstractMyList<E> { private Node<E> first; @Override public void clear() { size = 0; first = null; } @Override public void add(int index, E element) { if (index==0) { first=new Node<E>(element, first); } else { Node<E> prev = node(index-1); prev.next=new Node<E>(element, prev.next); } size++; } @Override public E get(int index) { // TODO Auto-generated method stub return node(index).element; } @Override public E set(int index, E element) { Node<E> node = node(index); E old = node.element; node.element = element; return old; } @Override public E remove(int index) { Node<E> node=first; if (index==0) { first=first.next; } else { Node<E> prev = node(index-1); node=prev.next; prev.next=node.next; } size--; return node.element; } @Override public int indexOf(E element) { if (element == null) { Node<E> node=first; for (int i = 0; i < size; i++) { if (node.element == null) return i; node=node.next; } } else { Node<E> node=first; for (int i = 0; i < size; i++) { if (element.equals(node.element)) return i; node=node.next; } } return ELEMENT_NOT_FOUND; } /** * 获取index位置对应的节点对象 * * @param index 索引下标 * @return */ private Node<E> node(int index) { rangeCheck(index); Node<E> node = first; for (int i = 0; i < index; i++) { node = node.next; } return node; } @Override public String toString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("size=").append(size).append(",["); Node<E> node=first; for (int i = 0; i < size; i++) { // 方式一(推荐) if (i > 0) { stringBuilder.append(","); } stringBuilder.append(node.element); // 方式二(不推荐) // if (i!=size-1) { // stringBuilder.append(","); // } node=node.next; } stringBuilder.append("]"); return stringBuilder.toString(); } private class Node<E> { E element; Node<E> next; public Node(E element, Node<E> next) { this.element = element; this.next = next; } } }
Test.java(测试类)
package com.cyb; public class Test { public static void main(String[] args) { MyList<Integer> list=new MyLinkedList<Integer>(); list.add(10); list.add(20); list.add(30); list.add(2, 21); list.add(list.size(),55); list.remove(0); System.out.println(list); } }
项目结构图
推荐一个学习算法的可视化网站:https://visualgo.net/zh
动态数组的缩容
如果内存使用比较紧张,动态数组有比较多的剩余空间,可以考虑进行缩容操作。
缩容规则
如:剩余空间占总容量的一半时,就进行缩容。
在remove方法中,添加一个缩容方法。
package com.cyb; /** * 自定义ArrayList数组,有动态缩容操作 * * @author chenyanbin * */ public class MyArrayList2<E> extends AbstractMyList<E> { /** * 所有元素 */ private E[] elements; private static final int DEFAULT_CAPACITY = 100; public MyArrayList2() { this(DEFAULT_CAPACITY); } @SuppressWarnings("unchecked") public MyArrayList2(int capacity) { capacity = (capacity < DEFAULT_CAPACITY) ? DEFAULT_CAPACITY : capacity; elements = (E[]) new Object[capacity]; } /** * 往index位置添加元素 * * @param index 索引下标 * @param element 元素 */ public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacity(size + 1); for (int i = size; i > index; i--) { elements[i] = elements[i - 1]; } elements[index] = element; size++; } /** * 返回index位置对应的元素 * * @param index 索引下标 * @return */ public E get(int index) { rangeCheck(index); return elements[index]; } /** * 设置index位置的元素 * * @param index 索引下标 * @param element 元素 * @return 原来的元素 */ public E set(int index, E element) { rangeCheck(index); E oldElement = elements[index]; elements[index] = element; return oldElement; } /** * 删除index位置对应的元素 * * @param index 索引下标 * @return 删除的元素值 */ public E remove(int index) { rangeCheck(index); E result = elements[index]; for (int i = index + 1; i < size; i++) { elements[i - 1] = elements[i]; } elements[--size] = null; trim(); return result; } /** * 删除对象 * * @param element 对象 */ public void remove(E element) { remove(indexOf(element)); } /** * 查看元素的位置 * * @param element 元素 * @return */ @SuppressWarnings("null") public int indexOf(E element) { if (element == null) { for (int i = 0; i < size; i++) { if (elements[i] == null) return i; } } else { for (int i = 0; i < size; i++) { if (element.equals(elements[i])) return i; } } return ELEMENT_NOT_FOUND; } /** * 清除所有元素 */ public void clear() { for (int i = 0; i < size; i++) { elements[i] = null; } size = 0; } @Override public String toString() { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("size=").append(size).append(",["); for (int i = 0; i < size; i++) { // 方式一(推荐) if (i > 0) { stringBuilder.append(","); } stringBuilder.append(elements[i]); // 方式二(不推荐) // if (i!=size-1) { // stringBuilder.append(","); // } } stringBuilder.append("]"); return stringBuilder.toString(); } /** * 保证要有capacity的容量 * * @param capacity 容量 */ private void ensureCapacity(int capacity) { int oldCapacity = elements.length; if (oldCapacity >= capacity) return; // 新容量为旧容量的1.5倍 int newCapacity = oldCapacity + (oldCapacity >> 1); @SuppressWarnings("unchecked") E[] newElements = (E[]) new Object[newCapacity]; for (int i = 0; i < size; i++) { newElements[i] = elements[i]; } elements = newElements; System.out.print("容量从" + oldCapacity + "扩展为" + newCapacity + " "); } /** * 缩容 */ private void trim() { int capacity = elements.length; int newCapacity = capacity >> 1; if (size > newCapacity || capacity <= DEFAULT_CAPACITY) return; E[] newElements = (E[]) new Object[newCapacity]; for (int i = 0; i < size; i++) { newElements[i] = elements[i]; } elements = newElements; } }