线性表-双向链表(LinkedList)

时间:2022-12-29 07:32:07

双向链表:如图1-3 所示,会把当前header拆分开,重新插入一个Entry<E>。

LinkedList源码

0.首先这个类中的两个变量

private transient Entry<E> header = new Entry<E>(null, null, null);
private transient int size = 0;

下面的这个size就不用说了,是大小,现在先着重看看 Entry<E> header,

Entry是一个内部类。

  1. private static class Entry<E> {
  2. E element;
  3. Entry<E> next;
  4. Entry<E> previous;
  5. Entry(E element, Entry<E> next, Entry<E> previous) {
  6. this.element = element;
  7. this.next = next;
  8. this.previous = previous;
  9. }
  10. }

线性表-双向链表(LinkedList)
 
线性表-双向链表(LinkedList)

就是一个链表,有父节点和子节点,父子节点都是一个对象的引用。

还有就是这个类是LinkedList的内部类,所以变量自然能再外部直接调用了。

1.构造函数

这个对象在声明的时候已经new了一个对象,所以这里可以直接使用里面的方法
    节点的子节点和父节点都自己。

  1. //无参构造
  2. public LinkedList() {
  3. header.next = header.previous = header;
  4. }

线性表-双向链表(LinkedList)

这里是无参构造后header的示意图,父子节点都指向自己。只是最初的header对象。
线性表-双向链表(LinkedList)

这里所指向的“一个对象”在初始化中为null 。并且没有改变过。

  1. //有参构造
  2. public LinkedList(Collection<? extends E> c) {
  3. //这一句可不能忘,对头节点的初始化很重要。
  4. this();
  5. addAll(c);
  6. }

在有了添加元素的操作后,entry的指针会指向不同地方。

2.add方法

这个方法主要是讲原来

返回是否成功

  1. public boolean add(E e) {
  2. addBefore(e, header);
  3. return true;
  4. }
  5. private Entry<E> addBefore(E e, Entry<E> entry) {
  6. //新建一个节点,子节点是头结点,这样看来它是环形链表。
  7. //它的父节点在第一次添加的时候是头结点,以后会得到最后一次添加的节点,并且在下面会断开后重连。
  8. Entry<E> newEntry = new Entry<E>(e, entry, entry.previous);
  9. //新节点的上一个节点的子节点设置为新的节点
  10. newEntry.previous.next = newEntry;
  11. //新节点的下一个节点的父节点设置为新的节点
  12. newEntry.next.previous = newEntry;
  13. //大小++
  14. size++;
  15. //这个不知道
  16. modCount++;
  17. //返回新的节点。
  18. return newEntry;
  19. }
  1. //在第几个位置添加
  2. public void add(int index, E element) {
  3. //如果在最后的位置添加,直接和上面的添加一样,如果不是,则
  4. addBefore(element, (index==size ? header : entry(index)));
  5. }
  6. private Entry<E> entry(int index) {
  7. if (index < 0 || index >= size)
  8. throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);
  9. //取得头结点
  10. Entry<E> e = header;
  11. <span style="color: #ff0000;"> //循环节点,从头节点开始循环,这个处理很聪明,先计算index的大小,小于一半的话正向遍历,大于一半的话反向遍历。</span>
  12. if (index < (size >> 1)) {
  13. for (int i = 0; i <= index; i++)
  14. e = e.next;
  15. } else {
  16. for (int i = size; i > index; i--)
  17. e = e.previous;
  18. }
  19. //最后返回节点。
  20. return e;
  21. }
  1. //添加到第一个位置
  2. public void addFirst(E e) {
  3. //只是在header的下一个开始添加,不多看了。
  4. addBefore(e, header.next);
  5. }
  1. public void addLast(E e) {
  2. //这个和add方法一样,所以普通的添加方法也是添加到最后的位置。
  3. addBefore(e, header);
  4. }

线性表-双向链表(LinkedList)

图1-3

这个是完整的情况,添加,删除都会断开相应的next和previous。同时注意header内部的element不会存储元素。他所指向的对象是null ,在前面也说过。

3.remove

主要是讲要删除元素的Entry调整父子节点就可实现删除。

  1. public E remove() {
  2. return removeFirst();
  3. }
  4. public E removeFirst() {
  5. return remove(header.next);
  6. }
  7. private E remove(Entry<E> e) {
  8. //不能删除头节点
  9. if (e == header)
  10. throw new NoSuchElementException();
  11. //这个是用来返回的
  12. E result = e.element;
  13. //父节点的子节点指向e的子节点。
  14. e.previous.next = e.next;
  15. //子节点的父节点指向e的父节点
  16. e.next.previous = e.previous;
  17. //将e设为空。
  18. e.next = e.previous = null;
  19. e.element = null;
  20. //大小--
  21. size--;
  22. modCount++;
  23. return result;
  24. }

删除元素。这里面的匹配和indexof方法很像。在indexof里面讲。

  1. public boolean remove(Object o) {
  2. if (o==null) {
  3. for (Entry<E> e = header.next; e != header; e = e.next) {
  4. if (e.element==null) {
  5. remove(e);
  6. return true;
  7. }
  8. }
  9. } else {
  10. for (Entry<E> e = header.next; e != header; e = e.next) {
  11. if (o.equals(e.element)) {
  12. remove(e);
  13. return true;
  14. }
  15. }
  16. }
  17. return false;
  18. }

4.indexOf

  1. //还<span style="color: #ff0000;">是对equals比较</span>
  2. ,都是正向循环。没什么新意,循环到头指针后结束。
  3. public int indexOf(Object o) {
  4. int index = 0;
  5. if (o==null) {
  6. for (Entry e = header.next; e != header; e = e.next) {
  7. if (e.element==null)
  8. return index;
  9. index++;
  10. }
  11. } else {
  12. for (Entry e = header.next; e != header; e = e.next) {
  13. if (o.equals(e.element))
  14. return index;
  15. index++;
  16. }
  17. }
  18. return -1;
  19. }

还有一些找第几个元素,返回元素数量,找到头元素,找都最后元素。

此文转载至:http://wdhdmx.iteye.com/blog/1161972

线性表-双向链表(LinkedList)的更多相关文章

  1. 数据结构与算法分析java——线性表3 &lpar;LinkedList&rpar;

    1. LinkedList简介 LinkedList 是一个继承于AbstractSequentialList的双向链表.它也可以被当作堆栈.队列或双端队列进行操作.LinkedList 实现 Lis ...

  2. 【Java数据结构学习笔记之一】线性表的存储结构及其代码实现

    应用程序后在那个的数据大致有四种基本的逻辑结构: 集合:数据元素之间只有"同属于一个集合"的关系 线性结构:数据元素之间存在一个对一个的关系 树形结构:数据元素之间存在一个对多个关 ...

  3. 数据结构与算法分析java——线性表1

    说到线性结构的话,我们可以根据其实现方式分为三类: 1)顺序结构的线性表 2)链式结构的线性表 3)栈和队列的线性表   应用程序后在那个的数据大致有四种基本的逻辑结构: 集合:数据元素之间只有&qu ...

  4. C语言 线性表 双向链式结构 实现

    一个双向链式结构实现的线性表 duList (GCC编译). /** * @brief 线性表双向链表结构 * @author wid * @date 2013-10-28 * * @note 若代码 ...

  5. Java 线性表、栈、队列和优先队列

    1.集合 2.迭代器 例子: 3.线性表 List接口继承自Collection接口,有两个具体的类ArrayList或者LinkedList来创建一个线性表 数组线性表ArrayList Linke ...

  6. 玩转C线性表和单向链表之Linux双向链表优化

    前言: 这次介绍基本数据结构的线性表和链表,并用C语言进行编写:建议最开始学数据结构时,用C语言:像栈和队列都可以用这两种数据结构来实现. 一.线性表基本介绍 1 概念: 线性表也就是关系户中最简单的 ...

  7. &lbrack;从今天开始修炼数据结构&rsqb;线性表及其实现以及实现有Itertor的ArrayList和LinkedList

    一.线性表 1,什么是线性表 线性表就是零个或多个数据元素的有限序列.线性表中的每个元素只能有零个或一个前驱元素,零个或一个后继元素.在较复杂的线性表中,一个数据元素可以由若干个数据项组成.比如牵手排 ...

  8. JAVA中的数据结构——集合类(线性表:Vector、Stack、LinkedList、set接口;键值对:Hashtable、Map接口&lt&semi;HashMap类、TreeMap类&gt&semi;)

    Java的集合可以分为两种,第一种是以数组为代表的线性表,基类是Collection:第二种是以Hashtable为代表的键值对. ... 线性表,基类是Collection: 数组类: person ...

  9. 线性表之何时使用ArrayList、LinkedList&quest;

    前言 线性表不仅可以存储重复的元素,而且可以指定元素存储的位置并根据下表访问元素. List接口的两个具体实现:数组线性表类ArrayList.链表类LinkedList. ArrayList Arr ...

随机推荐

  1. StackGAN&colon; Text to Photo-realistic Image Synthesis with Stacked Generative Adversarial Networks 论文笔记

    StackGAN: Text to Photo-realistic Image Synthesis with Stacked Generative Adversarial Networks  本文将利 ...

  2. Emacs简易教程

    Emacs简易教程阅读: 命令: $emacs 进入之后,输入: C-h t 这里,C-h表示按住[Ctrl]键的同时按h ####### 20090620 *退出: 输入“C-x C-c” *撤销: ...

  3. QT IP输入框正则表达式(使用QLineEdit的setValidator函数)

    /* ip输入框正则表达式 */ // IP 前3段 QRegExp regExp("[0-9][0-9.][0-9.][.]"); ui->lineEdit_1->s ...

  4. Java 程序员技能导图 1&period;0

    做Java开发已经一年,并非科班出身,在毕业工作三年后毅然决然辞职,参加培训机构从零开始.在这期间迷茫.失望.绝望时常伴我左右,但是在不断自我提高与努力中渐渐看到一些小小的成果使我不断坚信自己的选择并 ...

  5. 手把手教你树莓派实现简易室内监控系统(A)

    第一次写博文,有很多疏漏之处,然后受逼乎影响较深,希望大家多多包涵! _______________________________________________分割线是这样画的吧_________ ...

  6. 程序员如何面试才能拿到offer

    一.概述 面试,难还是不难?取决于面试者的底蕴(气场+技能).心态和认知及沟通技巧.面试其实可以理解为一场聊天和谈判,在这过程中有心理.思想上的碰撞和博弈.其实你只需要搞清楚一个逻辑:“面试官为什么会 ...

  7. scrapy爬虫学习系列二:scrapy简单爬虫样例学习

    系列文章列表: scrapy爬虫学习系列一:scrapy爬虫环境的准备:      http://www.cnblogs.com/zhaojiedi1992/p/zhaojiedi_python_00 ...

  8. 《剑指offer&lpar;第二版&rpar;》面试题60——n个骰子的点数

    一.题目描述 把n个骰子仍在地上,所有的骰子朝上的一面的点数之和为s,输入n,打印出s所有可能的值出现的概率. 二.题解 <剑指offer>上给出的两种方法,尤其是代码,晦涩难懂且没有注释 ...

  9. python爬虫——多线程&plus;协程(threading&plus;gevent)

    上一篇博客中我介绍了如何将爬虫改造为多进程爬虫,但是这种方法对爬虫效率的提升不是非常明显,而且占用电脑cpu较高,不是非常适用于爬虫.这篇博客中,我将介绍在爬虫中广泛运用的多线程+协程的解决方案,亲测 ...

  10. 2017-10-6 清北刷题冲刺班p&period;m

    1.数组异或 #include<iostream> #include<cstdio> #define maxn 100010 #define mod 1000000007 us ...