前言
队列、堆栈与数组、链表的关系与区分
1.先要搞明白两个东西,数据结构,和数据存储结构
数据结构
:是指相互之间存在一种或多种特定关系的数据元素的 集合。听起来是不是很抽象,简单理解:数据结构就是描述对象间逻辑关系的学科。比如:队列就是一种先进先出的逻辑结构,栈是一种先进后出的逻辑结构,家谱 是一种树形的逻辑结构!(初学数据结构的时候很不理解为什么有“栈”这个东西;队列很容易理解—无论购物就餐都需要排队;栈可以认为就是个栈道— 只允许一个人通过的小道,而且只能从一端进入,然后再从这端返回,比如你推了个箱子进去啦,第二个人也推个箱子进去,此时只能等后进来的这个人拉着箱子出 去后,你才能退出。)
数据存储结构
:它是计算机的一个概念,简单讲,就是描述数据在计算机中存储方式的学科;常用的数据存储 方式就两种:顺序存储,非顺序存储!顺序存储就是把数据存储在一块连续的存储介质(比如硬盘或内存)上—-举个例子:从内存中拿出第100个字节到 1000个字节间的连续位置,存储数据;数组就是典型的顺序存储!非顺序存储就是各个数据不一定存在一个连续的位置上,只要每个数据知道它前面的数据和后 面的数据,就能把所有数据连续起来啦;链表就是典型的非顺序存储啦!
队列、栈是线性数据结构的典型代表,而数组、链表是常用的两种数据存储结构;队列和栈均可以用数组或链表的存储方式实现它的功能!
双向链表
LinkedList
它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。这种叫做双向链表也叫双链表
LinkedList
LinkedList
中定义了3个属性first
,last
,size
,如下:
1 | transient int size = 0; |
first
表示上一个节点的信息last
表示下一个节点的信息size
表示双向链表中节点实例的个数
节点
LinkedList
是采用节点Node
方式把前后两个节点关联起来,变成链表,在LinkedList
的源码中有个节点的内部类
1 | private static class Node<E> { |
LinkedList
之所以是双向链表就是因为Node
节点中的next
和prev
两个参数把链串联起来next
:保存下一个节点的信息prev
:保存上一个节点的信息element
:节点的具体内容(相当于业务数据)
LinkedList中的remove()方法分析
1 | /** |
removeFirst()
1 | /** |
unlinkFirst(f)
1 | /** |
LinkedList中的add(E e)方法分析
1 | /** |
- linkLast(e)
1 | /** |
- 内部类
class Node<E>
:
1 | private static class Node<E> { |
LinkedList中的get(int index)方法分析
1 | /** |
第一步检查下标越界情况
checkElementIndex(index)
方法,其中有个构造异常信息的方法1
2
3
4
5
6
7
8
9
10
11
12
13
14/**
* Constructs an IndexOutOfBoundsException detail message.
* Of the many possible refactorings of the error handling code,
* this "outlining" performs best with both server and client VMs.
*/
private String outOfBoundsMsg(int index) {
return "Index: "+index+", Size: "+size;
}
private void checkElementIndex(int index) {
//这里调用了isElementIndex(index)方法,判断下标是否越界,越界抛出异常
if (!isElementIndex(index))
throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
- `isElementIndex(index)`方法
1
2
3
4
5
6
7
/**
* 说明参数是否为现有元素的索引。
*/
private boolean isElementIndex(int index) {
//判断是否下标越界,返回true或者false
return index >= 0 && index < size;
}
第二步,确定元素位置
node(index)
方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21/**
* 返回指定元素索引中的(非空)节点。
*/
Node<E> node(int index) {
// assert isElementIndex(index);
//这里使用的是二分查找法,如果size右移1位,代表size的一半大小;这种情况下如果,元素的下标index小于的元素的一半说明,元素的位置在前半截,所以从firsy开始遍历
if (index < (size >> 1)) {
Node<E> x = first;
//这里遍历到指定元素的前一位停止,然后取出前一位的下一位,得到指定元素,节约性能
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
//这里同理,从最后一个开始遍历,遍历的下标i-1,如果i大于了,指定元素的下标说明,i这个节点的前一个就是指定的元素,所以用x.prev,就可以了
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
LinkedList中的set(int index, E element)方法分析
1 | /** |