一.什么是松散链表?
松散链表中的每个节点存储多个元素,每一块中的所有节点由循环链表连接在一起。
下面是用java实现的代码(大约700行直接翻译自国外某大神的代码):
1.先创建一个类,里面定义了松散链表的块和操作:
package lianbiaostudy;
/*
* This source code is placed in the public domain. This means you can use it
* without any restrictions.
*/
import java.util.AbstractList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.io.Serializable;
import java.util.ConcurrentModificationException;
public class songsanlianbiao<E> extends AbstractList<E> implements List<E>, Serializable {
private int nodeCapacity;//定义每个块最多能装多少元素
private int size = 0;//存储链表的大小的变量
private Node firstNode;//块的第一个节点
private Node lastNode;//块的最后一个节点
//定义块
private class Node {
Node next;//下一个块
Node previous;//前一个块
int numElements = 0;//存储在此块的元素数
Object[] elements;//存储元素的数组
//构造新块
Node() {
elements = new Object[nodeCapacity];
}
}
//带参构造方法,设置每个块装多少元素
public songsanlianbiao(int nodeCapacity) throws IllegalArgumentException {
if (nodeCapacity < 8) {
throw new IllegalArgumentException("nodeCapacity < 8");
}
this.nodeCapacity = nodeCapacity;
firstNode = new Node();
lastNode = firstNode;
}
//默认构造方法,默认每个块装16个元素
public songsanlianbiao() {
this(16);
}
//返回链表的大小
public int size() {
return size;
}
//判断链表是否为空
@Override
public boolean isEmpty() {
return (size == 0);
}
//查询链表是否包含指定元素,如果包含返回true
@Override
public boolean contains(Object o) {
return (indexOf(o) != -1);
}
//遍历迭代器
@Override
public Iterator<E> iterator() {
return new ULLIterator(firstNode, 0, 0);
}
//返回包含此列表中所有元素的数组按适当的顺序
@Override
public Object[] toArray() {
Object[] array = new Object[size];
int p = 0;
for (Node node = firstNode; node != null; node = node.next) {
for (int i = 0; i < node.numElements; i++) {
array[p] = node.elements[i];
p++;
}
}
return array;
}
// 返回包含此列表中所有元素的数组按适当的顺序
@Override
public <T> T[] toArray(T[] a) {
if (a.length < size) {
a = (T[]) java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), size);
}
Object[] result = a;
int p = 0;
for (Node node = firstNode; node != null; node = node.next) {
for (int i = 0; i < node.numElements; i++) {
result[p] = node.elements[i];
p++;
}
}
return a;
}
//将指定的元素追加到此列表的末尾。成功返回true
@Override
public boolean add(E e) {
insertIntoNode(lastNode, lastNode.numElements, e);
return true;
}
//删除
@Override
public boolean remove(Object o) {
int index = 0;
Node node = firstNode;
if (o == null) {
while (node != null) {
for (int ptr = 0; ptr < node.numElements; ptr++) {
if (node.elements[ptr] == null) {
removeFromNode(node, ptr);
return true;
}
}
index += node.numElements;
node = node.next;
}
} else {
while (node != null) {
for (int ptr = 0; ptr < node.numElements; ptr++) {
if (o.equals(node.elements[ptr])) {
removeFromNode(node, ptr);
return true;
}
}
index += node.numElements;
node = node.next;
}
}
return false;
}
//要检查是否包含在此列表中如果此列表包含返回true
@Override
public boolean containsAll(Collection<?> c) {
if (c == null) {
throw new NullPointerException();
}
Iterator<?> it = c.iterator();
while (it.hasNext()) {
if (!contains(it.next())) {
return false;
}
}
return true;
}
@Override
public boolean addAll(Collection<? extends E> c) {
if (c == null) {
throw new NullPointerException();
}
boolean changed = false;
Iterator<? extends E> it = c.iterator();
while (it.hasNext()) {
add(it.next());
changed = true;
}
return changed;
}
@Override
public boolean removeAll(Collection<?> c) {
if (c == null) {
throw new NullPointerException();
}
Iterator<?> it = c.iterator();
boolean changed = false;
while (it.hasNext()) {
if (remove(it.next())) {
changed = true;
}
}
return changed;
}
@Override
public boolean retainAll(Collection<?> c) {
if (c == null) {
throw new NullPointerException();
}
boolean changed = false;
for (Node node = firstNode; node != null; node = node.next) {
for (int i = 0; i < node.numElements; i++) {
if (!c.contains(node.elements[i])) {
removeFromNode(node, i);
i--;
changed = true;
}
}
}
return changed;
}
//
@Override
public void clear() {
Node node = firstNode.next;
while (node != null) {
Node next = node.next;
node.next = null;
node.previous = null;
node.elements = null;
node = next;
}
lastNode = firstNode;
for (int ptr = 0; ptr < firstNode.numElements; ptr++) {
firstNode.elements[ptr] = null;
}
firstNode.numElements = 0;
firstNode.next = null;
size = 0;
}
//得到指定位置的数
public E get(int index) throws IndexOutOfBoundsException {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException();
}
Node node;
int p = 0;
if (size - index > index) {
node = firstNode;
while (p <= index - node.numElements) {
p += node.numElements;
node = node.next;
}
} else {
node = lastNode;
p = size;
while ((p -= node.numElements) > index) {
node = node.previous;
}
}
return (E) node.elements[index - p];
}
//设置指定位置的元素
@Override
public E set(int index, E element) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException();
}
E el = null;
Node node;
int p = 0;
if (size - index > index) {
node = firstNode;
while (p <= index - node.numElements) {
p += node.numElements;
node = node.next;
}
} else {
node = lastNode;
p = size;
while ((p -= node.numElements) > index) {
node = node.previous;
}
}
el = (E) node.elements[index - p];
node.elements[index - p] = element;
return el;
}
//在指定位置添加元素
@Override
public void add(int index, E element) throws IndexOutOfBoundsException {
if (index < 0 || index > size) {
throw new IndexOutOfBoundsException();
}
Node node;
int p = 0;
if (size - index > index) {
node = firstNode;
while (p <= index - node.numElements) {
p += node.numElements;
node = node.next;
}
} else {
node = lastNode;
p = size;
while ((p -= node.numElements) > index) {
node = node.previous;
}
}
insertIntoNode(node, index - p, element);
}
//删除指定位置的元素
@Override
public E remove(int index) throws IndexOutOfBoundsException {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException();
}
E element = null;
Node node;
int p = 0;
if (size - index > index) {
node = firstNode;
while (p <= index - node.numElements) {
p += node.numElements;
node = node.next;
}
} else {
node = lastNode;
p = size;
while ((p -= node.numElements) > index) {
node = node.previous;
}
}
element = (E) node.elements[index - p];
removeFromNode(node, index - p);
return element;
}
//
@Override
public int indexOf(Object o) {
int index = 0;
Node node = firstNode;
if (o == null) {
while (node != null) {
for (int ptr = 0; ptr < node.numElements; ptr++) {
if (node.elements[ptr] == null) {
return index + ptr;
}
}
index += node.numElements;
node = node.next;
}
} else {
while (node != null) {
for (int ptr = 0; ptr < node.numElements; ptr++) {
if (o.equals(node.elements[ptr])) {
return index + ptr;
}
}
index += node.numElements;
node = node.next;
}
}
return -1;
}
@Override
public int lastIndexOf(Object o) {
int index = size;
Node node = lastNode;
if (o == null) {
while (node != null) {
index -= node.numElements;
for (int i = node.numElements - 1; i >= 0; i--) {
if (node.elements[i] == null) {
return (index + i);
}
}
node = node.previous;
}
} else {
while (node != null) {
index -= node.numElements;
for (int i = node.numElements - 1; i >= 0; i--) {
if (o.equals(node.elements[i])) {
return (index + i);
}
}
node = node.previous;
}
}
return -1;
}
/**
* Returns a list iterator over the elements in this list (in proper
* sequence).
*
* @return a list iterator over the elements in this list (in proper
* sequence)
*/
@Override
public ListIterator<E> listIterator() {
return new ULLIterator(firstNode, 0, 0);
}
@Override
public ListIterator<E> listIterator(int index) {
if (index < 0 || index > size) {
throw new IndexOutOfBoundsException();
}
Node node;
int p = 0;
if (size - index > index) {
node = firstNode;
while (p <= index - node.numElements) {
p += node.numElements;
node = node.next;
}
} else {
node = lastNode;
p = size;
while ((p -= node.numElements) > index) {
node = node.previous;
}
}
return new ULLIterator(node, index - p, index);
}
private static final long serialVersionUID = -674052309103045211L;
//松散链表迭代器
private class ULLIterator implements ListIterator<E> {
Node currentNode;
int ptr;
int index;
private int expectedModCount = modCount;
ULLIterator(Node node, int ptr, int index) {
this.currentNode = node;
this.ptr = ptr;
this.index = index;
}
//下一个位置
@Override
public boolean hasNext() {
return (index < size - 1);
}
@Override
public E next() {
ptr++;
if (ptr >= currentNode.numElements) {
if (currentNode.next != null) {
currentNode = currentNode.next;
ptr = 0;
} else {
throw new NoSuchElementException();
}
}
index++;
checkForModification();
return (E) currentNode.elements[ptr];
}
//判断
@Override
public boolean hasPrevious() {
return (index > 0);
}
@Override
public E previous() {
ptr--;
if (ptr < 0) {
if (currentNode.previous != null) {
currentNode = currentNode.previous;
ptr = currentNode.numElements - 1;
} else {
throw new NoSuchElementException();
}
}
index--;
checkForModification();
return (E) currentNode.elements[ptr];
}
@Override
public int nextIndex() {
return (index + 1);
}
@Override
public int previousIndex() {
return (index - 1);
}
@Override
public void remove() {
checkForModification();
removeFromNode(currentNode, ptr);
}
@Override
public void set(E e) {
checkForModification();
currentNode.elements[ptr] = e;
}
@Override
public void add(E e) {
checkForModification();
insertIntoNode(currentNode, ptr + 1, e);
}
private void checkForModification() {
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
}
/**
* Insert an element into the specified node. If the node is already full,
* a new node will be created and inserted into the list after
* the specified node.
*
* @param node
* @param ptr the position at which the element should be inserted
* into the <tt>node.elements<tt> array
* @param element the element to be inserted
*/
private void insertIntoNode(Node node, int ptr, E element) {
//如果这个块满了
if (node.numElements == nodeCapacity) {
// 创建一个新块
Node newNode = new Node();
// 将一半的元素移到新块中
int elementsToMove = nodeCapacity / 2;
int startIndex = nodeCapacity - elementsToMove;
int i;
for (i = 0; i < elementsToMove; i++) {
newNode.elements[i] = node.elements[startIndex + i];
node.elements[startIndex + i] = null;
}
node.numElements -= elementsToMove;
newNode.numElements = elementsToMove;
// 将新块插入到链表中
newNode.next = node.next;
newNode.previous = node;
if (node.next != null) {
node.next.previous = newNode;
}
node.next = newNode;
if (node == lastNode) {
lastNode = newNode;
}
// 检查是否这个元素应该被插入
// 原始块或进入新块
if (ptr > node.numElements) {
node = newNode;
ptr -= node.numElements;
}
}
for (int i = node.numElements; i > ptr; i--) {
node.elements[i] = node.elements[i - 1];
}
node.elements[ptr] = element;
node.numElements++;
size++;
modCount++;
}
/**
* Removes an element from the specified node.
*
* @param node the node from which an element should be removed
* @param ptr the index of the element to be removed within
* the <tt>node.elements<tt> array
*/
//从指定节点中删除元素
private void removeFromNode(Node node, int ptr) {
node.numElements--;
for (int i = ptr; i < node.numElements; i++) {
node.elements[i] = node.elements[i + 1];
}
node.elements[node.numElements] = null;
if (node.next != null && node.next.numElements + node.numElements <= nodeCapacity) {
mergeWithNextNode(node);
} else if (node.previous != null && node.previous.numElements + node.numElements <= nodeCapacity) {
mergeWithNextNode(node.previous);
}
size--;
modCount++;
}
/**
* This method does merge the specified node with the next node.
*
* @param node the node which should be merged with the next node
*/
//将指定块和下一个块合并
private void mergeWithNextNode(Node node) {
Node next = node.next;
for (int i = 0; i < next.numElements; i++) {
node.elements[node.numElements + i] = next.elements[i];
next.elements[i] = null;
}
node.numElements += next.numElements;
if (next.next != null) {
next.next.previous = node;
}
node.next = next.next;
if (next == lastNode) {
lastNode = node;
}
}
}
2.测试代码:
里面对比了松散链表和java自带的链表的效率:
public class ceshi {
public static void main(String[] args) {
LinkedList<Integer> ll = new LinkedList<Integer>();
long endTime;
// Láncolt lista - feltöltés
long startTime = System.currentTimeMillis();
for (int i = 0; i < 5000000; i++) {
ll.add(i);
}
endTime = System.currentTimeMillis();
System.out.println("普通链表:LL: FILL -> " + (endTime - startTime));
// Lánsolt lista - törlés
startTime = System.currentTimeMillis();
ll.remove(2500000);
endTime = System.currentTimeMillis();
System.out.println("LL: REMOVE -> " + (endTime - startTime));
ll = null;
System.gc();
// ULL - feltöltés
songsanlianbiao<Integer> ull = new songsanlianbiao<>(8);
startTime = System.currentTimeMillis();
for (int i = 0; i < 5000000; i++) {
ull.add(i);
}
System.out.println(ull.size());
endTime = System.currentTimeMillis();
System.out.println("松散链表:ULL: FILL -> " + (endTime - startTime));
// ull - törlés
startTime = System.currentTimeMillis();
System.out.println(ull.remove(20));
endTime = System.currentTimeMillis();
System.out.println("ULL: REMOVE -> " + (endTime - startTime));
System.out.println(ull.lastIndexOf(4999999));
}
}
结果: