本文欢迎转载,转载前请联系作者,经允许后方可转载。转载后请注明出处,谢谢! http://blog.csdn.net/colton_null 作者:喝酒不骑马 Colton_Null from CSDN
本文分享一下自主实现简单ArrayList的代码,主要参考了《数据结构与算法分析》。
思路及方法都写在了注释中
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;
public class MyLinkedList<T> implements Iterable<T> {
private int theSize;
private int modCount;
private Node beginMarker;
private Node endMarker;
public MyLinkedList() {
clear();
}
/**
* 清空链表初始化
*/
private void clear() {
beginMarker = new Node(null, null, null);
endMarker = new Node(null, beginMarker, null);
beginMarker.next = endMarker;
theSize = 0;
modCount++;
}
/**
* 返回链表长度
*
* @return 链表长度
*/
public int size() {
return theSize;
}
/**
* 判断链表是否为空
*
* @return 空为true,非空为false
*/
public boolean isEmpty() {
return size() == 0;
}
/**
* 添加元素到末位
*
* @param t 要添加的节点
* @return
*/
public boolean add(T t) {
add(size(), t);
return true;
}
/**
* 添加节点到指定索引处
*
* @param index 索引值
* @param t 要添加的节点
*/
public void add(int index, T t) {
// 这里getNode第三个参数是size()的原因是,当添加节点到末位的时候,索引值为当前列表长度。
// 如果size() - 1的话,在getNode中开会的判断中会报IndexOutOfBoundsException
addBefore(getNode(index, 0, size()), t);
}
/**
* 在给定node之前插入新node
*
* @param p 当前node
* @param t 要插入的新node
*/
private void addBefore(Node p, T t) {
Node newNode = new Node<>(t, p.prev, p);
newNode.prev.next = newNode;
p.prev = newNode;
theSize++;
modCount++;
}
/**
* 获取指定索引的元素
*
* @param index 索引值
* @return 该索引下的元素
*/
public T get(int index) {
return getNode(index).data;
}
/**
* 替换指定索引的元素
*
* @param index 索引
* @param t 新元素
* @return 旧元素
*/
public T set(int index, T t) {
Node node = getNode(index);
T oldValue = node.data;
node.data = t;
return oldValue;
}
/**
* 删除索引所在位置的元素
*
* @param index 索引
* @return 被删除的元素
*/
public T remove(int index) {
return remove(getNode(index));
}
/**
* 删除节点
*
* @param p 要被删除的节点
* @return 被删除的节点的值
*/
private T remove(Node p) {
p.prev.next = p.next;
p.next.prev = p.prev;
modCount++;
theSize--;
return p.data;
}
/**
* 根据索引获得节点
*
* @param index 索引
* @return 该索引下的节点
*/
private Node getNode(int index) {
return getNode(index, 0, size() - 1);
}
/**
* 获取index索引对应的节点。根据索引位置选择从前或后开始遍历。
*
* @param index 索引值
* @param lower 首位索引
* @param upper 末位索引
* @return 返回该索引下的节点
*/
private Node getNode(int index, int lower, int upper) {
Node p;
if (index < lower || index > upper) {
throw new IndexOutOfBoundsException();
}
// 如果索引在链表前半部分,则从前开始遍历。否则从后向前遍历。
if (index < size() / 2) {
p = beginMarker.next;
for (int i = 0; i < index; i++) {
p = p.next;
}
} else {
p = endMarker;
for (int i = size(); i > index; i--) {
p = p.prev;
}
}
return p;
}
@Override
public String toString() {
String str = "";
Node p = beginMarker;
while (p.next != endMarker) {
str += p.next.data.toString() + "\n";
p = p.next;
}
return str;
}
@Override
public Iterator iterator() {
return new LinkedListIterator();
}
/**
* Node节点内部类
*
* @param
*/
private class Node<T> {
// 元素内容
public T data;
// 上一个元素
public Node prev;
// 下一个元素
public Node next;
public Node(T d, Node p, Node n) {
data = d;
prev = p;
next = n;
}
}
private class LinkedListIterator implements Iterator<T> {
// 当前节点。默认是beginMarker.next,即第一个节点
private Node current = beginMarker.next;
// 用于检测迭代期间集合被修改的情况。默认和modCount相等。
private int expectedModCount = modCount;
// 用于判断是否可以被删除
private boolean okToRemove = false;
/**
* 判断是否有下一节点。如果当前节点为endMarker,则说明没有下一节点了。
* @return
*/
@Override
public boolean hasNext() {
return current != endMarker;
}
/**
* 迭代到下一节点
* @return
*/
@Override
public T next() {
// 迭代过程中如果集合被修改,则抛出异常
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (!hasNext()) {
throw new NoSuchElementException();
}
T nextItem = current.data;
current = current.next;
// 置为true
okToRemove = true;
return nextItem;
}
/**
* 移除节点
*/
@Override
public void remove() {
// 迭代过程中如果集合被修改,则抛出异常
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
if (!okToRemove) {
throw new IllegalStateException();
}
MyLinkedList.this.remove(current.prev);
// modCount保持同步
expectedModCount++;
// 置为false
okToRemove = false;
}
}
}
思路和方法同样都写在了注释中。
import java.util.Iterator;
public class MyLinkedListTest {
public static void main(String[] args) {
// 初始化MyLinkedList
MyLinkedList list = new MyLinkedList<>();
System.out.println("list的长度为:" + list.size());
System.out.println("list的是否为空:" + list.isEmpty());
// 测试添加元素
list.add(1);
list.add(2);
System.out.println("list的长度为:" + list.size());
System.out.println("list的是否为空:" + list.isEmpty());
System.out.println("list内容为:");
System.out.println(list);
// 测试插入元素
list.add(0, 100);
System.out.println("list的首位为:" + list.get(0));
// 测试修改元素
list.set(0, 200);
System.out.println("list的首位为:" + list.get(0));
// 测试删除元素
list.remove(1);
System.out.println("list内容为:");
System.out.println(list);
// 测试迭代器
Iterator itr = list.iterator();
System.out.println("用迭代器遍历输出list:");
while (itr.hasNext()) {
System.out.println(itr.next());
}
// 测试迭代器删除元素
itr = list.iterator();
while (itr.hasNext()) {
itr.next();
itr.remove();
}
System.out.println("list是否为空:" + list.isEmpty());
}
}
输出:
list的长度为:0
list的是否为空:true
list的长度为:2
list的是否为空:false
list内容为:
1
2
list的首位为:100
list的首位为:200
list内容为:
200
2
用迭代器遍历输出list:
200
2
list是否为空:true
证明LinkedList的简单实现可用。
站在前人的肩膀上前行,感谢以下博客及文献的支持。