马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
x
1.链表
1.1为什么要引入链表
上一篇文章中我们先容了ArrayList,ArrayList的底层是通过数组实现的,具有随机访问服从高等特点,那么我们为什么还需要引入链表呢?
这是因为ArrayList底层通过数组实现,当在ArrayList任意位置(除了末了一位)举行插入和删除操作时,就需要将后续的元素整体向前大概向后举行搬移,时间复杂度为O(n),服从比较低,由此可见ArrayList很不适合在一些插入大概删除操作较多的场景,而java聚集中引入了链表,可以很好改善这个问题
1.2链表的概念和结构
链表是一种物理存储上非连续的存储结构,数据元素上的逻辑顺序是通过链表中的引用实现的。差别于数组,链表的物理存储单元可以分散在内存中的任意位置,通过节点(每个节点包含两部门:数据域和指针域。数据域用于存储数据元素,指针域则存储指向下一个节点的引用)之间的引用将它们连接起来形成一个线性序列
在Java中用对象引用代替指针
链表的结构多种多样,主要分为以下6种结构:
1.单向链表或双向链表
2.带头链表大概不带头链表
3.循环链表大概非循环链表
1.3实现一个单链表
- public class SingleLinkedList{
- //头插法
- public void addFirst(int data){}
- //尾插法
- public void addLast(int data){}
- //任意位置插入
- public void addIndex(int index,int data){}
- //查询链表中是否含有关键字key
- public boolean contains(int key){}
- //删除第一次出现关键字key的节点
- public void remove(int key){}
- //删除所有值为key的节点
- public void removeAllKey(int data){}
- //得到单链表的长度
- public int size(){}
- //清空所有节点,清空单链表
- public void clear(){}
- //打印单链表
- public void display(){}
- }
复制代码 实现思路:
1.addFirst(int data)在单链表头部举行插入操作,只需要创建一个新的节点将新节点的value属性赋值为data,并将新节点的next指向原来链表的头部节点即可
2.addLast(int data)在单链表尾部举行插入操作,只需要创建一个新的节点将新节点的value属性赋值为data,并将原链表尾部的节点的next指向新的节点即可
3.addIndex(int pos,int data)在链表指定位置插入元素,起首要判断插入的位置是否正当,如果正当则分别需要修改要将原来插入位置的元素的next指向新节点,而且新节点的next要指向插入位置背面的那个节点
4.contains(int key)判断链表是否包含元素key,只需要依次遍历链表,获取到每个节点的元素并举行判断
5.remove(int key)删除元素key,遍历链表,找到key所在的位置,将key前一个元素的next指向key背面的元素即可
6.removeAllKey(int key)删除元素值为key的全部元素,每找到一个值为key的元素要举行判断key是否有前后节点,再举行相应的删除操作
7.size()返回链表中的节点个数,可以通过遍历链表并设置计数器,通过计数器统计链表中结点的个数
8.display()打印链表,遍历并依次打印每个节点的元素
2.LinkedList
2.1什么是LinkedList
LinkedList是Java聚集框架中的链表,LinkedList是基于双向链表实现的,由于链表中没有将元素存储在连续的空间内,元素存储在单独的节点中,然后通过引用将节点连接起来,因此在任意位置插入大概删除元素,不需要搬移元素,服从比较高。
LinkedList中的节点结构:
说明:
1.LinkedList实现了List接口
2.LinkedList的底层使用了双向链表
3.LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问
4.LinkedList的任意位置插入和删除操作服从比较高,时间复杂度为O(1)
5.LinkedList比较适合插入删除比较多的场景
6.LinkedList的访问服从比较低,时间复杂度为O(n)
2.2LinkedList的构造方法
方法 | 表明 | LinkedList() | 无参构造 | public LinkedList(Collection<? extends E> c) | 使用其他聚集容器种的元素构造List | 代码演示:
- public class Test {
- public static void main(String[] args) {
- //构造一个空的LinkedList
- List<Integer> list1=new LinkedList<>();
- System.out.println(list1);
- List<String> list=new java.util.ArrayList<>();
- list.add("hajimi");
- list.add("hahaha");
- list.add("lalala");
- //使用ArrayList构造LinkedList
- List<String> list2=new LinkedList<>(list);
- System.out.println(list2);
- }
- }
复制代码
2.3LinkedList的常用方法
方法 | 表明 | boolean add(E,e) | 在尾部插入元素e | void add(int index,E e) | 将元素e插入到index的位置 | boolean addAll(Collection<? extends E> c) | 在尾部插入c中的全部元素 | E remove(int index) | 删除index位置的元素 | boolean remove(Object o)
| 删除第一个o元素 | E get(int index) | 获取下标为index位置元素 | E set(int index,E e) | 将下标为index位置的元素设置为e | void clear() | 清空链表中的全部元素 | boolean contains(Object o) | 判断o是否在线性表中 | int indexOf(Object o) | 返回第一个o所在的下标 | int lastIndexOf(Object o) | 返回末了一个o所在的下标 | List<E> subList(int fromIndex,int toIndex) | 截取部门list | 代码演示:
- import java.util.*;
- public class Test {
- public static void main(String[] args) {
- List<String> list=new LinkedList<>();
- //在链表末尾插入元素
- list.add("My");
- list.add("name");
- list.add("hajimi");
- System.out.println(list);
- //在指定位置插入元素
- list.add(2,"is");
- System.out.println(list);
- list.add(4,"king");
- System.out.println(list);
- //删除指定位置的元素
- list.remove(4);
- System.out.println("进行删除操作后的链表"+list);
- //删除指定元素
- list.remove("My");
- System.out.println("进行删除操作后的链表"+list);
- //获取指定位置的元素
- System.out.println(list.get(2));
- //将指定位置下标的元素设置为e
- System.out.println(list.set(0,"Your name"));
- System.out.println(list);
- //判断线性表中是否包含某元素
- System.out.println(list.contains("hajimi"));
- list.add("hajimi");
- //返回指定元素第一个出现的下标
- System.out.println(list.indexOf("hajimi"));
- //返回指定元素最后一次出现的下标
- System.out.println(list.lastIndexOf("hajimi"));
- //截取部分链表内容
- List<String> partList;
- partList=list.subList(0,3);
- System.out.println("截取的部分:"+partList);
- //在链表尾部插入其他容器的所有元素
- list.addAll(partList);
- System.out.println(list);
- //清空链表中的所有元素
- list.clear();
- System.out.println(list);
- }
- }
复制代码
2.4LinkedList的遍历
LinkedList遍历主要有3中方式:
1.使用for循环搭配链表长度举行遍历
2.使用foreach循环
3.使用迭代器举行遍历
代码演示:
- import java.util.*;
- public class Test {
- public static void main(String[] args) {
- List<String> list=new LinkedList<>();
- list.add("My");
- list.add("name");
- list.add("is");
- list.add("hajimi");
- list.add("king");
- list.add("!");
- //使用for循环搭配链表长度进行遍历链表
- for (int i=0;i<list.size();i++){
- System.out.print(list.get(i)+" ");
- }
- System.out.println();
- //使用foreach循环遍历链表
- for(String s:list){
- System.out.print(s+" ");
- }
- System.out.println();
- //使用迭代器遍历链表
- //正向遍历
- ListIterator<String> it= list.listIterator();
- while(it.hasNext()){
- System.out.print(it.next()+" ");
- }
- System.out.println();
- //反向遍历
- ListIterator<String> rit= list.listIterator(list.size());
- while (rit.hasPrevious()){
- System.out.print(rit.previous()+" ");
- }
- }
- }
复制代码 2.5实现一个LinkedList
LinkedList原码中节点的结构如下:
实现一个泛型为Integer的链表,代码演示:
对上述代码举行运行测试:
- public class Test {
- public static void main(String[] args) {
- MyLinkedList2 myLinkedList2=new MyLinkedList2();
- myLinkedList2.addLast(1);
- myLinkedList2.addLast(2);
- myLinkedList2.addFirst(3);
- myLinkedList2.addIndex(2,6);
- myLinkedList2.addIndex(0,5);
- myLinkedList2.addIndex(1,4);
- myLinkedList2.display();
- System.out.println(myLinkedList2.contains(6));
- myLinkedList2.remove(6);
- myLinkedList2.display();
- myLinkedList2.addFirst(1);
- myLinkedList2.display();
- myLinkedList2.removeAllKey(1);
- myLinkedList2.display();
- System.out.println(myLinkedList2.size());
- myLinkedList2.clear();
- myLinkedList2.display();
- }
- }
复制代码
3.LinkedList的特点
LinkedList的特点主要体如今以下几个方面:
1.数据存储的方式
LinkedList是通过一系列节点组成的,每个节点都包含三个部门,数据元素,指向前一个节点的引用和指向后一个节点的引用,链表的内存是动态分配的,每个节点的内存空间是独立分配的,使得链表的巨细灵活可调
2.操作服从
在链表头部大概尾部插入和删除元素操作的时间复杂度为O(1),如果已经得到目标节点的引用,举行插入和删除操作的时间复杂度为O(1),但如果没有则需要从头遍历找到目标位置,时间复杂度为O(n)
链表不支持随机访问,方位任意元素都需要从头开始举行遍历,时间复杂度为O(n)
3.内存使用
每个节点除了存取数据元素外,还需要存储引用,有额外的内存开销。链表的内存分配时动态的,不会像数组那样分配固定的巨细
4.适用场景
适合插入和删除频仍的场景,不适合随机访问的场景,适合数据量不确定的场景(动态扩展,不外多浪费空间)
4.LinkedList和ArrayList的区别
差别点 | ArrayList | LinkedList | 存储空间上 | 物理上连续的 | 逻辑上连续,物理上不肯定连续 | 随机访问 | 支持,时间复杂度O(1) | 不支持,时间复杂度O(n) | 插入/删除 | 需要搬运元素,服从低,时间复杂度O(n) | 只需要修改引用的指向,时间复杂度O(1) | 扩容机制 | 当数组空间不敷时,会创建一个更大的数组并复制原数据 | 动态分配内存,每次插入时动态分配新节点 | 内存使用 | 内存分配连续,大概有空间浪费(预留空间),但内存使用服从较高。 | 每个节点需要额外存储指针,内存使用相对较高。 | 适用场景 | 元素频仍访问的场景 | 插入删除频仍的场景 |
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |