基本概念
链表和数组一样是线性表(Liner List)结构,它并不需要一块连续的内存空间, 他通过指针将一块零散的内存块串联起来使用。三种常见的链表结构,分别是:单链表、双向链表和循环链表。
链表的基本元素是结点,往往通过一个类实现一个结点,每个链表的结点需要存储数据和记录链上下一个结点的地址(data and next)。第一个结点叫做头结点,最后一个结点叫做尾结点,其中头结点记录链表的基地址,然后就可以遍历得到整条链表,而尾结点指向一个空地址NULL表示链表上最后一个结点。
NOTE:链表中涉及到指针的操作,切记一个地址可以被多个指针指向。注重指针指向断开的顺序。
特点
因为链表不需要连续的内存空间,所以简单的删除和插入操作时间复杂度是O(1),而随机访问需要遍历链表,时间复杂度为O(n)。
源码分析
/*******************************************************
*
* The Node class
*
********************************************************/
private static class Node<AnyType>
{
// "泛型data存储数据,next记录下一个结点的地址"
private AnyType data;
private Node<AnyType> next;
// "初始化方法"
public Node(AnyType data, Node<AnyType> next)
{
this.data = data;
this.next = next;
}
}
public class LinkedList<AnyType> implements Iterable<AnyType>
{
private Node<AnyType> head;
/**
* Constructs an empty list
* "一个空链表,头指针为空(基地址)即可"
*/
public LinkedList()
{
head = null;
}
/**
* Returns true if the list is empty
*
*/
public boolean isEmpty()
{
return head == null;
}
/**
* Inserts a new node at the beginning of this list.
* "插入一个新结点到表头"
*/
public void addFirst(AnyType item)
{
"新建一个结点,next指向上一个头结点,然后head指向此新头结点"
head = new Node<AnyType>(item, head);
}
/**
* Returns the first element in the list.
*
*/
public AnyType getFirst()
{
if(head == null) throw new NoSuchElementException();
return head.data;
}
/**
* Removes the first element in the list.
*
*/
public AnyType removeFirst()
{
AnyType tmp = getFirst();
"head指向下一个结点,相当于移除头结点"
head = head.next;
return tmp;
}
/**
* Inserts a new node to the end of this list.
*
*/
public void addLast(AnyType item)
{
"首先判断头结点是不是为空,相当于添加头结点"
if( head == null)
addFirst(item);
else
{
"如果链表不为空,需要根据头结点head遍历到尾结点"
Node<AnyType> tmp = head;
while(tmp.next != null) tmp = tmp.next;
"此前的尾结点指向一个指向null的结点,完成添加结点到尾部"
tmp.next = new Node<AnyType>(item, null);
}
}
/**
* Returns the last element in the list.
*
*/
public AnyType getLast()
{
if(head == null) throw new NoSuchElementException();
Node<AnyType> tmp = head;
while(tmp.next != null) tmp = tmp.next;
return tmp.data;
}
/**
* Removes all nodes from the list.
*
*/
public void clear()
{
"只需要头结点为空即可"
head = null;
}
/**
* Returns the data at the specified position in the list.
* "根据位置索引查看链表中的元素"
*/
public AnyType get(int pos)
{
if (head == null) throw new IndexOutOfBoundsException();
Node<AnyType> tmp = head;
"相当于执行遍历的次数"
for (int k = 0; k < pos; k++) tmp = tmp.next;
if( tmp == null) throw new IndexOutOfBoundsException();
return tmp.data;
}
/**
* Inserts a new node after a node containing the key.
* "在指定元素的后面插入新的结点"
*/
public void insertAfter(AnyType key, AnyType toInsert)
{
Node<AnyType> tmp = head;
while(tmp != null && !tmp.data.equals(key)) tmp = tmp.next;
if(tmp != null)
"先创建一个node结点(指向下一个结点tmp.next),然后再断开tmp原来的指向,指向新的节点node"
tmp.next = new Node<AnyType>(toInsert, tmp.next);
}
/**
* Inserts a new node before a node containing the key.
* "在指定元素的前面插入新的结点"
*/
public void insertBefore(AnyType key, AnyType toInsert)
{
if(head == null) return;
if(head.data.equals(key))
{
addFirst(toInsert);
return;
}
Node<AnyType> prev = null;
Node<AnyType> cur = head;
"在指定元素的前面插入新的结点,换一种思路就是,找到指点元素的前一个节点,然后在前一个节点后插入一个结点即可"
while(cur != null && !cur.data.equals(key))
{
prev = cur;
cur = cur.next;
}
//insert between cur and prev
if(cur != null)
prev.next = new Node<AnyType>(toInsert, cur);
}
/**
* Removes the first occurrence of the specified element in this list.
*
*/
public void remove(AnyType key)
{
if(head == null)
throw new RuntimeException("cannot delete");
if( head.data.equals(key) )
{
head = head.next;
return;
}
Node<AnyType> cur = head;
Node<AnyType> prev = null;
while(cur != null && !cur.data.equals(key) )
{
prev = cur;
cur = cur.next;
}
if(cur == null)
throw new RuntimeException("cannot delete");
//delete cur node
prev.next = cur.next;
}
/**
* Reverses the list
* Complewxity: O(n) "反转链表"
*/
public LinkedList<AnyType> reverse()
{
LinkedList<AnyType> list = new LinkedList<AnyType>();
Node<AnyType> tmp = head;
while(tmp != null)
{
list.addFirst( tmp.data );
tmp = tmp.next;
}
return list;
}