java算法:链表

链表是一种基本的数据结构,它是多个数据项的集合。链表相对于数组的主要优点在于给我们提供了重新有效地组织数据项的能力,这种便利牺牲快速访问链表中的数据项为代价,因为访问链表就是从开始指针往下查。

在一些编程环境中,链表是基本的数据结构,但是在java中不是。我们构建类,Node:

class Node{
	Object item;
	Node next;
}

要有效地使用链表,内存分配是需要考虑的主要因素。

Node x = new Node();

当我们使用链表结构时,对每个对象的所有成员都进行初始化。因为调用构造函数是实例化对象过程的一部分,所以我们可以在每个构造函数中给每个数据域赋值。 

class Node{
	Ojbect item;
	Node next;
	Node(Ojbect v){
		item = v;
		next = null;
	}
}

注意:

要移走节点x后的节点:

t = x.next; x.next = t.next;

在x后插入节点:

t.next = x.next; x.next = t;

插入和删除的简单性是链表存在的理由。要在数组中进行相应的操作就很不方便,因为它们要移动被影响的数据项之后的所有数据项。

链表并不适合有效访问第k项操作的查找。在数组中简单访问a[k]找到第k项。而在链表中,需要遍历k个指针。

当使用 x.next = x.next.next;语句从链表中移走节点时,可能再也不能访问到它了。在java中,这个不需要特别关心,因为java会自动把没有被引用的内存回收。

例一:循环链表例子(约瑟芬问题:N个人围成一圈,每隔M-1个人就去掉一人,然后剩下的人再靠拢,问题是谁是最后剩下的人):

public class Josephus {

	public static void main(String[] args) {
		int N = Integer.parseInt(args[0]);
		int M = Integer.parseInt(args[1]);
		Node t = new Node(1);
		Node x = t;
		for(int i = 2; i <= N; i++){
			x = (x.next = new Node(i));
		}
		x.next = t;
		while(x != x.next){
			for(int i = 1; i < M; i++){
				x = x.next;
			}
			x.next = x.next.next;
		}
		System.out.println("survivor is " + x.val);
	}
	public static class Node{
		int val;
		Node next;
		Node(int v){
			val = v;
		}
	}
}

当N=9,M=5,剩下的是8。

埃拉托色尼筛和约瑟芬问题明显说明了使用数组和链表来分别表示顺序组织的对象集合之间的差异。如果分别使用链表和数组来解决问题,开销会很大。

在java中,对象和对象的引用为链表这个概念提供了直接、便捷的具体实现手段。