19、集合之LinkedList

 

LinkedList——链表

相比较于ArrayList的方法,除了Add(),get(),remove(),size()等,LinkedList多了addLast(),addFirst(),getFirst

1、一般将数据结构分为两大类:线性数据结构和非线性数据结构。线性数据结构有线性表、栈、队列、串、数组和文件;非线性数据结构有树和图。

线性表的逻辑结构是n个数据元素的有限序列: (a1, a2,a3,…an),n为线性表的长度(n≥0),n=0的表称为空表。数据元素呈线性关系。必存在唯一的称为“第一个”的数据元素;必存在唯一的称为“最后一个”的数据元素;除第一个元素外,每个元素都有且只有一个前驱元素;除最后一个元素外,每个元素都有且只有一个后继元素。所有数据元素在同一个线性表中必须是相同的数据类型。

线性表按其存储结构可分为顺序表和链表。用顺序存储结构存储的线性表称为顺序表;用链式存储结构存储的线性表称为链表。将线性表中的数据元素依次存放在某个存储区域中,所形成的表称为顺序表。一维数组就是用顺序方式存储的线性表。ArrayList就相当于顺序表。LinkedList就相当于链表。

2、单向链表

链表的操作

public class Node
{
	String data;
	Node next;
	
	public Node(String s)
	{
		data = s;
	}
}

public class NodeTest
{
	public static void main(String[] args)
	{
		Node node1 = new Node("node1");
		Node node2 = new Node("node2");
		Node node3 = new Node("node3");
		Node node4 = new Node("node4");
		
		node1.next =node2;
		node2.next =node3;
		
		node1.next = node4;
		node4.next = node2;
		
		System.out.println(node1.next.data);
		
		node1.next = node2;
		node4.next = null;
		
		System.out.println(node1.next.data);
	}
}


3、循环链表

双向循环列表

 

public class Node2
{
	Node2 previous;
	Node2 next;
	String data;
	
	public Node2(String s)
	{
		data = s;
	}
}

public class NodeTest2
{
	public static void main(String[] args)
	{
		Node2 node1 = new Node2("node1");
		Node2 node2 = new Node2("node2");
		Node2 node3 = new Node2("node3");
		
		node1.next =node2;
		node1.previous = node3;
		node2.next =node3;
		node2.previous = node1;
		node3.next = node1;
		node3.previous = node2;
		//在node1和node2之间插入node4
		Node2 node4 = new Node2("node4");
		
		node1.next = node4;
		node4.previous =node1;
		
		node2.previous =node4;
		node4.next =node2;
		
		System.out.println("--------------");
		//删除node4
		node1.next = node2;
		node2.previous =node1;
		
		node4.next =null;
		node3.previous =null;
		
		
	}
}


4、LinkedList源代码分析:LinkedList底层就是使用了双向循环链表实现

//先定义两个成员变量
private transient Entry<E> header = new Entry<E>(null, null, null);
private transient int size = 0;
//默认构造函数
public LinkedList() {
        header.next = header.previous = header;
    }

看一下Entry:

private static class Entry<E> {
	E element;
	Entry<E> next;
	Entry<E> previous;

	Entry(E element, Entry<E> next, Entry<E> previous) {
	    this.element = element;
	    this.next = next;
	    this.previous = previous;
	}
    }


它的定义就像Node2,有一个存放数据的成员变量element,还各有一个指向前驱和后继Entry的指针previous和next。

关于add()方法,参数是一个Object对象,作为Entry的element值

 public boolean add(E e) {
	addBefore(e, header);
        return true;
    }

private Entry<E> addBefore(E e, Entry<E> entry) {
	Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
	newEntry.previous.next = newEntry;
	newEntry.next.previous = newEntry;
	size++;
	modCount++;
	return newEntry;
    }

add()方法默认调用addBefore()方法插入一个新的节点,addBefore看其字面意思,就是在指定的节点之前插入,而其参数默认为e和header,e是要保存的数据,header是链表的头节点,按照上面的图,头节点的前驱就是链表的最后一个节点,所以插入默认是插入到链表最后。addBefore方法先构建一个新的Entry节点,根据其参数,这个新节点的element=e,next=entry,(也就是header),previous=entry.previous,(也就是header.previous)。然后修改原来最后一个节点的后继指向新节点:newEntry.previous.next = newEntry;然后在修改原来的头节点的前驱指向新节点:newEntry.next.previous = newEntry;

5、关于ArrayList与LinkedList的比较分析

1)ArrayList底层采用数组实现,LinkedList底层采用双向链表实现。

2)当执行插入或删除操作时,采用LinkedList比较好。

3)当执行搜索操作时,采用ArrayList比较好。

6、list的删除操作只删除找到匹配的第一个节点,如linkedlist.add("aaa");linkedlist.add("aaa");删除时,remove("aaa")只删除第一个找到的aaa节点。

在get()方法取第n个元素时,调用了entry()方法,这个方法使用了一个优化性能的算法,先判断n是否大于链表元素个数的二分之一,如果不大于,说明距离头节点比较近,从头开始先后遍历寻找,否则说明距离末节点比较近,从尾部开始向前遍历寻找。

 7、当向ArrayList添加一个对象时,实际上就是将该对象放置到了ArrayList底层所维护的数组当中;当向LinkedList中添加一个对象时,实际上LinkedList内部会生成一个Entry对象,该对象的结构为: 

Entry

{

Entry previous;

Object element;

Entry next;

}

其中的Object类型的元素element就是我们向LinkedList中所添加的元素,然后Entry又构造好了向前与向后的引用previous、next,最后将生成的这个Entry对象加入到了链表当中。换句话说,LinkedList中所维护的是一个个的Entry对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值