当前位置: 首页 > news >正文

专门 做鞋子团购的网站江北关键词优化排名seo

专门 做鞋子团购的网站,江北关键词优化排名seo,哪个网站专门做高清壁纸,自己做的网站用别的电脑怎么访问LinkedList的本质是双向链表。(01) LinkedList继承于AbstractSequentialList,并且实现了Dequeue接口。 (02) LinkedList包含两个重要的成员:header 和 size。  header是双向链表的表头,它是双向链表节点所对应的类Entry的实例。Entry中包含…

 

LinkedList的本质是双向链表。
(01) LinkedList继承于AbstractSequentialList,并且实现了Dequeue接口。 
(02) LinkedList包含两个重要的成员:header 和 size
  header是双向链表的表头,它是双向链表节点所对应的类Entry的实例。Entry中包含成员变量: previous, next, element。其中,previous是该节点的上一个节点,next是该节点的下一个节点,element是该节点所包含的值。 
  size是双向链表中节点的个数。

(前面照旧是复制粘贴的图和文字,大家大概理解一下,下面进入正题)

为了理解上面的概念,首先我们来看一下核心类Node

 

//节点,有前驱,后继和值三个字端,其中前驱和后继也是节点
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}

Node表示的是结点,结点里面有三个元素:

数据,前驱和后继。

其中数据可是任意类型,前驱和后继同样是结点。

我们可以想象一个双向链表依次一共有A,B,C三个结点,他们的数据分别为a,b,c。那么:

A的前驱为null,后继为B,数据为a。

B的前驱为A,后继为C,数据为b。

C的前驱为B,后继为null,数据为c。

 

接下来我们来看一下构造函数和类变量

    //集合元素个数transient int size = 0;//第一个节点transient Node<E> first;//最后一个节点transient Node<E> last;//输入为空的构造函数public LinkedList() {}//直接传入一个Collection放入LinkedList中的构造器,public LinkedList(Collection<? extends E> c) {//调用无参的构造期this();addAll(c);}

 

类变量分别是List中数据的个数,第一个结点和最后一个结点。

构造函数有两个:一个是空的构造函数,一个是传入一个Collection来生成LinkedList。

我们来具体看一下这个addAll方法

 //将指定集合c中所有的元素,按照其迭代器返回的顺序全部追加到集合的结尾。public boolean addAll(Collection<? extends E> c) {return addAll(size, c);}//将指定集合c中所有的元素,按照其迭代器返回的顺序全部追加到集合的特定位置。public boolean addAll(int index, Collection<? extends E> c) {checkPositionIndex(index);Object[] a = c.toArray();int numNew = a.length;if (numNew == 0)return false;//pred是predecessor前置节点,succ是succeed 后置节点,请大家学好英语(笑)Node<E> pred, succ;if (index == size) {//新增节点在最后一个succ = null;pred = last;} else {//新增结点在index处succ = node(index);pred = succ.prev;}//前驱节点不为null的情况下,循环生成新节点,把前任节点作为新节点的前驱,数组里的数作为节点的值,后继置为空//然后把新节点作为前驱的后继,之后把新节点作为前驱,继续循环执行//可能你这个时候会有疑问,那不是没有制定后继?并不是的,后继是在你的新节点变为前驱后,由 pred.next = newNode;这一句指定的。for (Object o : a) {@SuppressWarnings("unchecked") E e = (E) o;Node<E> newNode = new Node<>(pred, e, null);if (pred == null)first = newNode;elsepred.next = newNode;pred = newNode;}//后继为空,则最后一个就是前驱(也就是前面最后一句指定为前驱的newNode)//后继不为空的话,则把后继作为前驱(就是前面最后一句指定为前驱的newNode)的后继,前驱作为后继的前驱if (succ == null) {last = pred;} else {pred.next = succ;succ.prev = pred;}//列表里的数增加size += numNew;//这个用来判断迭代器的fast-fail的,具体见我的前一篇ArrayList的那篇博文modCount++;return true;}

整个把Collection变为LinkedList的过程写的比较详细了,不再赘述。

 

现在我们随便看一些常用的方法,比如说获取第一个结点的值,我们发现会有getFirst()和peekFirst()这样两个方法;同样的获取最后一个结点的值,我们发现会有getLast()和peekLast()两个方法。那么为何会有两种呢?

我们看一下源码:

//获取第一个结点的值public E getFirst() {final Node<E> f = first;if (f == null)throw new NoSuchElementException();return f.item;}//获取的第一个结点的值public E peekFirst() {final Node<E> f = first;return (f == null) ? null : f.item;}

我们可以看出来,前者如果结点为空会报错,后者如果结点为空则会返回null。

以下对第一个结点和最后一个结点的操作:

 

        第一个结点(头部)                 最后一个结点(尾部)抛出异常        特殊值            抛出异常        特殊值
插入    addFirst(e)    offerFirst(e)    addLast(e)      offerLast(e)
移除    removeFirst()  pollFirst()      removeLast()    pollLast()
检查    getFirst()     peekFirst()      getLast()        peekLast()

 

左边的操作遇到异常会抛出异常,右边的操作遇到异常会返回特殊值。

 

由于LinkedLIst分别实现了队列和栈的接口,以下也是对第一个结点和最后一个结点的操作

当作为队列时,下表的方法等价:

队列方法       等效方法
add(e)        addLast(e)
offer(e)      offerLast(e)
remove()      removeFirst()
poll()        pollFirst()
element()     getFirst()
peek()        peekFirst()

当作为栈时下表的方法等价:

栈方法        等效方法
push(e)      addFirst(e)
pop()        removeFirst()
peek()       peekFirst()

 

以上说的都是对第一个结点和最后一个结点的操作,接下来写一下对中间结点的操作:

 //返回特定位置的结点的值public E get(int index) {checkElementIndex(index);return node(index).item;}//替换特定位置的结点的值,返回旧的值public E set(int index, E element) {checkElementIndex(index);Node<E> x = node(index);E oldVal = x.item;x.item = element;return oldVal;}//替换特定位置的结点,原结点向后移public void add(int index, E element) {checkPositionIndex(index);if (index == size)linkLast(element);elselinkBefore(element, node(index));}//删除特定位置的结点public E remove(int index) {checkElementIndex(index);return unlink(node(index));}

 

里面的具体操作如下:

 

   //获取某个index的结点Node<E> node(int index) {// assert isElementIndex(index);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;for (int i = size - 1; i > index; i--)x = x.prev;return x;}}//把输入的数e作为新增在最前面的结点的值private void linkFirst(E e) {final Node<E> f = first;final Node<E> newNode = new Node<>(null, e, f);first = newNode;if (f == null)last = newNode;elsef.prev = newNode;size++;modCount++;}//把输入的数e作为新增在最后面的结点的值void linkLast(E e) {final Node<E> l = last;final Node<E> newNode = new Node<>(l, e, null);last = newNode;if (l == null)first = newNode;elsel.next = newNode;size++;modCount++;}//把输入的数e作为新增在结点succ的前面的结点的值void linkBefore(E e, Node<E> succ) {// assert succ != null;final Node<E> pred = succ.prev;final Node<E> newNode = new Node<>(pred, e, succ);succ.prev = newNode;if (pred == null)first = newNode;elsepred.next = newNode;size++;modCount++;}//把非空的LinkedList的第一个节点unlinked(删除)private E unlinkFirst(Node<E> f) {// assert f == first && f != null;final E element = f.item;final Node<E> next = f.next;f.item = null;f.next = null; // help GCfirst = next;if (next == null)last = null;elsenext.prev = null;size--;modCount++;return element;}//把非空的LinkedList的最后一个节点unlinked(删除)private E unlinkLast(Node<E> l) {// assert l == last && l != null;final E element = l.item;final Node<E> prev = l.prev;l.item = null;l.prev = null; // help GClast = prev;if (prev == null)first = null;elseprev.next = null;size--;modCount++;return element;}///把非空的LinkedList的某个节点unlinked(删除)E unlink(Node<E> x) {// assert x != null;final E element = x.item;final Node<E> next = x.next;final Node<E> prev = x.prev;if (prev == null) {first = next;} else {prev.next = next;x.prev = null;}if (next == null) {last = prev;} else {next.prev = prev;x.next = null;}x.item = null;size--;modCount++;return element;}

 可以从上面看出来新增和删除元素都是比较方便的。

 

还有两个比较特殊的删除方法:

    //删除第一个出现的特定值public boolean removeFirstOccurrence(Object o) {return remove(o);}//删除最后一个出现的特定值public boolean removeLastOccurrence(Object o) {if (o == null) {for (Node<E> x = last; x != null; x = x.prev) {if (x.item == null) {unlink(x);return true;}}} else {for (Node<E> x = last; x != null; x = x.prev) {if (o.equals(x.item)) {unlink(x);return true;}}}return false;}

它们的特殊之处在于,它们想要删除的结点的数值也许有很多个,但是它们只会删除第一个出现的或者是最后一个出现的。

 

 

 

然后我们看一下搜索元素的方法:

   //判断是否包含某个特定的结点的值public boolean contains(Object o) {return indexOf(o) != -1;}//查找LinkedList中是否包含某个值,并返回第一个出现这个值的索引值,否则返回-1public int indexOf(Object o) {int index = 0;if (o == null) {for (Node<E> x = first; x != null; x = x.next) {if (x.item == null)return index;index++;}} else {for (Node<E> x = first; x != null; x = x.next) {if (o.equals(x.item))return index;index++;}}return -1;}//反向查找LinkedList中是否包含某个值,并返回第一个出现这个值的索引值,否则返回-1public int lastIndexOf(Object o) {int index = size;if (o == null) {for (Node<E> x = last; x != null; x = x.prev) {index--;if (x.item == null)return index;}} else {for (Node<E> x = last; x != null; x = x.prev) {index--;if (o.equals(x.item))return index;}}return -1;}

可以看出来,搜索元素是比较麻烦的,必须要全部遍历一遍。

 

 最后我们看一下一些边界值判断的方法:

    //判断某个索引值是否存在private boolean isElementIndex(int index) {return index >= 0 && index < size;}//判断这个索引是否超出了位置的边界,这个和上面的有何区别?为何index是<=而不是<
private boolean isPositionIndex(int index) {return index >= 0 && index <= size;}//多种边界异常的判断private String outOfBoundsMsg(int index) {return "Index: "+index+", Size: "+size;}private void checkElementIndex(int index) {if (!isElementIndex(index))throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}private void checkPositionIndex(int index) {if (!isPositionIndex(index))throw new IndexOutOfBoundsException(outOfBoundsMsg(index));}

 

限于篇幅(Lan),其他方法就不一一介绍了。

 

总结

1.LinkedList的本质基于双向链表实。

2.LinkedList在查找元素时,必须遍历链表;在新增和删除元素时,只要调整前后的引用就可以了。

3.LinkedList不是线程安全的,同样拥有fast-fail机制。

 

转载于:https://www.cnblogs.com/jing-daye/p/7242576.html

http://www.wooajung.com/news/34672.html

相关文章:

  • 建筑设计方案大全抖音关键词优化
  • ps图做ppt模板下载网站有哪些seo宣传网站
  • 那个网站推作者自己搭建网站
  • 域名查询备案查询武汉官网优化公司
  • 广告网站搭建seo优化按天扣费
  • 陕西服装网站建设seo排名优化怎么样
  • 机械加工外发订单平台北京seo专员
  • wordpress 布局插件系统优化助手
  • 网站注册空间百度推广排名代发
  • 做网站销售是干什么的2022国内外重大新闻事件10条
  • 珠海模板网站建设360站长工具seo
  • 手机网站怎么开发南宁优化网站网络服务
  • 外国网站dns招聘网站排名
  • 淘宝做网站费用抖音视频排名优化
  • 如何做网站滚动条网络营销策划包括哪些内容
  • ui设计的网站有哪些俄罗斯搜索引擎推广
  • 在百度做网站需要什么资料国外域名注册网站
  • 凡科做网站友情链接怎么做百度旗下13个app
  • 网站建设标准流程及外包注意事项一个产品的营销方案
  • 企业平台有哪些搜索引擎优化的基本原理
  • 阿里云服务器做网站多少钱正规网站优化推广
  • q a wordpress插件下载地址广州seo关键词优化是什么
  • 松原手机网站开发郑州专业seo哪家好
  • 深圳市网站开发公司今日新闻头条新闻最新
  • 深圳网站建设的服务怎么样搜索引擎营销的优缺点
  • 做网站是不是就能上传东西网站alexa排名
  • 转运网站建设百度关键词关键词大全
  • 网站建设收费价格北京seo网站设计
  • 哈尔滨seo推广汕头seo网络推广
  • 南昌定制网站公司大连企业网站建站模板