Java学习分享-->集合-->链表

链表是一个有序集合,它将每个对象存放在独立的结点中,每个结点还存放着下一个结点的引用。在Java中由于链表是双向链接的,每个结点还存放着前一个结点的引用。

(图片引自Java核心技术 卷1 基础知识)

删除链表中间的一个元素,只需要更新被删除元素附近的结点。假设我们有三个结点,删除第二个结点后,第一个结点将原本存放第二个结点的引用更新为第三个结点的引用(这里对应我们前面提到的“每个结点还存放着下一个结点的引用”),而第三个结点将原本存放第二个结点的引用更新为第一个结点的引用(这里对应我们前面提到的“每个结点还存放着前一个结点的引用”)。

(图片引自Java核心技术 卷1 基础知识)

正常调用add()方法是将元素添加进链表的尾部,但可能会出现把元素添加进链表中间的情况。这时就需要使用ListIterator来实现,从名称上来我们知道这也是一种迭代器,不过这个迭代器中提供了一个add()方法(注意要和链表本身的add()方法分开理解)。调用迭代器的add()方法会在迭代器位置之前添加一个元素。而在另外一种Set类型中,由于其中的元素是无序的,其Iterator接口中就没有add()方法。因此我们得出一个结论:“只有对自然有序的集合使用迭代器添加元素才有实际意义”。

那这一实现过程是怎样的呢?首先我们需要明确要将新元素添加到链表中哪个已存在的元素之后,确定了位置之后利用迭代器的next()方法越过到已存在的元素之后,再通过调用迭代器的add()方法就可以把新元素添加到链表的指定位置。

在明确了上面的操作步骤后,有以下几个问题可以来思考下?

①需要向链表的表头添加元素

1)我们可以在拿到刚刚返回的ListIterator对象后就调用迭代器的add()方法,以下为example

        List<String> list = new LinkedList<String>();
        list.add("Andy");

        ListIterator<String> iterator = list.listIterator();
        iterator.add("Amy");

        while (iterator.hasNext()) {
            //这里输出的结果是Andy
            System.out.println(iterator.next());
        }

        iterator = list.listIterator();

        while (iterator.hasNext()) {
            //这里会输出两次,一次是Amy,一次是Andy
            System.out.println(iterator.next());
        }

为什么第一个while循环中的println只输出一次,而且输出的还是Andy?

根据我们前面提到的“调用迭代器的add()方法会在迭代器位置之前添加一个元素”,在我们第一次拿到这个迭代器对象的引用时,迭代器的位置在Andy这个元素前面,通过调用迭代器的add()方法,Amy这个元素被添加到了迭代器所在位置的前面,这样在执行hasNext()方法时,迭代器对象中还有可供访问的元素Andy,返回true。再调用next()就返回了元素Andy的引用。

而在执行第二个while之前,重新拿到了迭代器对象的引用,此时迭代器的位置就位于Amy之前,由于迭代器对象中有两个可供访问的元素,因此println分别打印出了Amy和Andy。

②需要向链表的表尾添加元素

1)直接调用链表本身的add()方法

2)当迭代器的hasNext()方法返回false时,这说明迭代器已经越过链表的最后一个元素,再调用迭代器的add()方法

        List<String> list = new LinkedList<String>();
        list.add("Andy");

        ListIterator<String> iterator = list.listIterator();

        while (iterator.hasNext()) {
            iterator.next();
        }

        iterator.add("Amy");

        iterator = list.listIterator();

        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

③链表中有多少个位置是可以添加元素的

如果链表中有n个元素,那么就会有n+1个位置可以添加元素。例如链表中有AB两个元素,那么A的前面、AB的中间、B的后面都是可以添加元素的。

我们前面提到的add()方法(这里指链表本身的add()方法),是向链表的尾部添加元素。链表中还有一个set()方法,它是做什么用的呢?set()方法会将传入的新元素取代调用next()或previous()方法返回的元素,此时这个链表就被修改了。需要额外说明的是add()、remove()方法是对链表结构性的修改,而set()方法不被视为结构性修改。

链表不支持快速随机访问,如果要查看链表中的第n个元素,就必须从头开始,越过n-1个元素。这意味着如果你使用get(2)来访问链表中的第三个元素,就必须越过前两个元素。如果要访问链表中第四个元素呢?get(3)这种方式好像可行,虽然它确实也访问到了第四个元素,但这一过程付出了越过前三个元素的代价。

想一想如果使用迭代器呢?当我们用迭代器访问到链表中第三个元素后,再去访问第四个元素会这么麻烦吗?

不会,因为此时迭代器只需要再向后移动,越过第四个元素,就能返回刚刚所越过的这个元素的引用。

鉴于此如果你需要通过整数索引来访问元素,那么就不应该选用链表。

那么说了这么多,我们在什么场景下选择链表呢,唯一理由就是想要尽量减少在列表中间插入或删除元素所付出的代价。

最后附几个与链表有关的笔试题:

一、请写出println打印的结果

        LinkedList<String> list = new LinkedList<String>();
        list.add("one");
        list.add("two");
        list.add("three");
        list.add("four");
        list.add("five");
        ListIterator<String> iteratorOne = list.listIterator(2);
        ListIterator<String> iteratorTwo = list.listIterator(iteratorOne.nextIndex());
        if (iteratorTwo.hasNext()) {
            System.out.println(iteratorTwo.next());
        }

二、请写出各println打印的结果

        List<String> a = new LinkedList<>();
        a.add("Amy");
        a.add("Carl");
        a.add("Erica");

        List<String> b = new LinkedList<>();
        b.add("Bob");
        b.add("Doug");
        b.add("Frances");
        b.add("Gloria");

        ListIterator<String> aIter = a.listIterator();
        Iterator<String> bIter = b.iterator();

        while (bIter.hasNext()) {
            if (aIter.hasNext()) aIter.next();
            aIter.add(bIter.next());
        }

        System.out.println(a);
        bIter = b.iterator();

        while (bIter.hasNext()) {
            bIter.next();

            if (bIter.hasNext()) {
                bIter.next();
                bIter.remove();
            }
        }

        System.out.println(b);

        a.removeAll(b);

        System.out.println(a);
时间: 2024-07-30 08:20:05

Java学习分享-->集合-->链表的相关文章

java学习笔记—集合之Map集合

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; text-align: center; font: 12.0px Times } p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px "Songti SC" } p.p3 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Times } p.p4 { margin: 0.0px 0.0px 0.0px 0.0

java学习之集合家族2

集合体系 一.数据结构 List集合储存数据结构 <1>堆栈结构 特点:先进后出 <2>队列结构 特点:先进先出 <3>数组结构 特点:查询快,增删慢 <4>链表结构 特点:增删快,查询慢 二.List接口 Java.util.List 接口(集合)extends Collection 接口 List接口的特点: 允许存储重复元素 是一个有序集合(存储元素的顺序和取出元素的顺序一致)存123 取出123 有索引,包含一些带索引的特有方法(有三种遍历方式:迭代

Java学习:集合双列Map

数据结构 数据结构: 数据结构_栈:先进后出 入口和出口在同一侧 数据结构_队列:先进先出 入口和出口在集合的两侧 数据结构_数组: 查询快:数组的地址是连续的,我们通过数组的首地址可以找到数组,通过数组的索引可以快速的查找某一个元素. 增删慢:数组的长度是固定的,我们想要增加/删除一个元素,必须创建一个新数组,把原数组的数据复制过来 例: int[] arr = new int[]{1,2,3,4}; 要把数组索引是3的元素删除 必须创建一个新的数组,长度是原数组的长度-1 把原数组的其它元素

java学习总结-集合(collection)

本人正在学习java基础知识,非常感恩能够看到毕向东老师的java视频,他引领了我去思考问题,而不是生硬的去记一些知识点,下面是我对集合学习的总结和思考. 01-常用对象API(集合框架-概述).avi 问题1:什么是集合框架? 首先要理解集合这个词,它有另一个更加形象的名词:容器,所谓容器就是装载事物的器皿,而在java中最大的特征就是面向对象,所以可以推断出其实它就是用来装载对象的,便于我们去遍历和处理这些对象,关于框架的含义,其实就是它不是一个单独对象,而是有很多对象,并且相互存在区别和关

java学习日记 集合框架

集合框架 有两大接口  一个是 Collection (类集 )与Map (映射): collection 下有两大接口  一个是List (列表) 另一个是Set(集合) List (列表):ArrayList 基于数组实现的动态列表    动态数组 : LinkedList 基于链表实现的列表      双向循环链表 Vector 向量   ------>stack栈           与线程相关: Set (集合) :TreeSet       通过树实现的集合  有序集合 HashSe

Java学习笔记----------集合Set

Java集合-----Set集合:就像一种容器,可以把多个对象放进该容器中.Java集合分为:Set.List.Map三种体系. Set:无序的,不可重复的: List:有序的,可重复的: Map:代表有映射关系的集合,Map保存的每一项数据都是key-value对.注意:Java 5后添加了Queue体系,代表一种队列集合实现. 集合和数组对比:1.数组一旦初始化,长度不可变:2.数组无法保存具有映射关系的数据,例如成绩表:语文---79:3.数组的元素可以是基本类型的值,也可以是对象,而集合

Java学习关于集合框架的基础接口--Collection接口

 集合框架(Collection  Framework)是Java最强大的子系统之一,位于java.util 包中.集合框架是一个复杂的接口与和类层次,提供了管理对象组的最新技术.Java集合框架标准化了程序处理对象组的方式. 集合框架在设计上需要满足几个目标.首先,框架必须是高性能的.基本集合(动态数组.链表.树以及哈希表)的实现是高效率的.很少需要手动编写这些数据引擎中的某一个.其次,框架必须允许不同类型的集合以类似的方式进行工作,并且具有高度的互操作性.再次,扩展或改造必须易于实现.为了满

java中的集合链表

java中的集合类有很多种,每个都有自己的一些特点,推荐你专门在这方面研究一下,比方Vector,ArrayList,,LinkedList,Hashtable等,其中你问到的链表,是不是指LinkedList呢?LinkedList是集合类的一种,和其它集合类一样都用于存放未知内容和未知长度的数据或者说对象.由于LinkedList的内部实现是采用链表结构,所以它就取名为LinkedList当然ArrayList的内部实现是采用数组结构,所以它就取名为ArrayList,呵呵,很好理解吧. 它

Java学习 ( 集合框架)

集合框架 概述:数组长度是固定的,当添加的元素超过了数组的长度时需要对数组重新定义,太麻烦,Java内部给我们提供了集合类,能存储任意对象,长度是可以改变的,随元素的增加而增加,随元素的减少而减少. 数组和集合的区别: 数组既可以存储基本数据类型,又可以存储引用数据类型.(基本数据类型存储的是值,引用数据类型存储的是地址值) 集合只能存储引用数据类型(对象) *集合中也可以存储基本数据类型,但是在存储的时候会自动装箱变成对象. 数组和集合的使用 : 如果元素个数是固定的推荐用数组. 如果元素个数