Day 09 List子接口LinkedList
List子接口LinkedList
LinkedList引入
ArrayList : 底层是数组,通过下标就能查询,它的查询比较快,但是删除比较慢 LinkedList:底层是双向链表,要一个一个的遍历,没有下标,所以数据比较多的时候查询比较 慢,但是它比较适合添加和删除操作。
对于频繁的插入或删除元素的操作,建议使用LinkedList类,效率较高
LinkedList:双向链表,内部没有声明数组,而是定义了Node类型的first和last,用于记录首末 元素。同时,定义内部类Node,作为LinkedList中保存数据的基本结构。
LinkeList前置基础知识
单项链表
element:用来存放元素
next:用来指向下一个节点 通过每个节点的指针指向下一个节点从而连接起来的结构,最后一个节点的next指向null
单向循环链表
在单向链表的最后一个节点的next会指向头节点,而不是指向null,这样存成一个环。
双向链表
element:用来存放元素
pre:用来指向上一个节点
next:用来指向下一个节点 双向链表包含两个指针,pre指向前一个节点, next 指向后一个指针,但是第一个节点head(头节点) 的pre指向null,最后一个节点的tail指向null。
双向循环链表
lement、pre、next 跟前面的一样
第一个节点的pre指向最后一个节点,最后一个节点的next指向第一个节点,也形成一个“环”。
LinkedList常用方法
方法名 | 说明 |
---|---|
void addFirst(Object o) | 在链表的头部添加元素 |
void addLast(Object o) | 在链表的尾部添加元素 |
Object getFirst() | 获取链表中的第一个元素 |
Object getLast() | 获取链表中的最后一个元素 |
Object removeFirst | 删除中的第一个元素 |
Object removeLast() | 删除链表中的最后一个元素 |
public static void main(String[] args) {LinkedList linkedList = new LinkedList();linkedList.add("aaa");//添加到数组linkedList.add("bbb");linkedList.add("ccc");linkedList.add("ddd");linkedList.add("eee");System.out.println(linkedList);//打印出添加后的数组//linkedList.clear();linkedList.offerFirst("eee");//在首位添加元素System.out.println(linkedList);linkedList.addFirst("qqq");//继续在首位添加元素System.out.println(linkedList);linkedList.removeFirst();//移除首位元素System.out.println(linkedList);linkedList.pollFirst();//方法检索并删除此列表的第一个元素,如果此列表为空,则返回 nullSystem.out.println(linkedList);}
链表的原理及实现
什么是链表?
链表是由n个子节点组合起来的一种线性数据结构 链表的特性:
- 链表是以节点(Node)的方式来存储,所以又叫链式存储
- 节点可以连续存储,也可以不连续存储
- 节点的逻辑顺序与物理顺序可以不一致
- 链表可以扩充
单链表
两个部分:
- data域:数据域,用来存储元素数据
- next域:用于指向下一节点
单链表的操作
单链表的所有操作都是从head开始,head本身不存储元素,其next指向第一个节点,然后顺着next链表 进行一步步操作。其尾部节点的next指向为空,这也是判断尾部节点的依据。
插入节点
向单链表中插入一个新节点,可以通过调整两次next指向来完成。
x为新节点,将其next指向A2,再将A1的next指向X即可。
如果是从尾节点插入,直接将尾节点的next指向新节点就可以了。
删除操作
从单链表中删除一节点,通过修改next指向来实现。
将A1的next 指向为A2,这样就能删除 X, X的内存空间会自动被垃圾回收。
代码实现
public class Node {public String data;public Node next;public Node(String data) {this.data = data;}public String getData() {return data;}public void setData(String data) {this.data = data;}public Node getNext() {return next;}public void setNext(Node next) {this.next = next;}@Overridepublic String toString() {return "Node{" +"data='" + data + '\'' +", next=" + next +'}';}
}
private Node head = new Node(null);//得有head节点,是单链表的开始
//添加节点
public void add(Node node){Node temp = head;//temp存储头节点while (true) {//判断node是否为空if (temp.next == null){temp.next = node;break;}temp = temp.next;}}
singleLinkedList.add(aaa);
singleLinkedList.add(bbb);
//指定节点插入元素public void addOfOrder(Node node, String name) {Node temp = head;while (true) {if (temp.next == null){temp.next = node;break;}else if (name == temp.getData()) {node.next = temp.next;temp.next = node;break;}temp = temp.next;}}
singleLinkedList.addOfOrder(eee,"bbb");
//查找获取数据
public Node get(String key) {if (head.next == null) {return null;}Node temp = head.next;while (temp != null){if (temp.data == key) {return temp;}temp = temp.next;}return null;
}
//移除数据public void remove(Node node) {Node temp = head.next;while (true) {if (temp.next == null) {break;}if (temp.next.data == node.data) {temp.next = temp.next.next;//断开连接break;}temp = temp.next;}}
//修改叫这个node节点的名字name
public void update(Node node, String name) {Node temp = head.next;//这句话一般都不变,都要用while (true) {if (temp == null) {break;}if (temp.data == name) {temp.data = node.data;break;}temp = temp.next;}}
//测试
public static void main(String[] args) {Node aaa = new Node("aaa");Node bbb = new Node("bbb");Node ccc = new Node("ccc");SingleLinkedList singleLinkedList = new SingleLinkedList();singleLinkedList.add(aaa);singleLinkedList.add(bbb);singleLinkedList.add(ccc);singleLinkedList.print();System.out.println("=====================");Node eee = new Node("eee");singleLinkedList.addOfOrder(eee,"bbb");singleLinkedList.print();System.out.println("=====================");System.out.println(singleLinkedList.get("eee"));System.out.println(singleLinkedList.get("qqq"));System.out.println("=====================");singleLinkedList.remove(ccc);singleLinkedList.print();System.out.println("=====================");singleLinkedList.update(new Node("www"), "eee");singleLinkedList.print();
双向链表
双向链表其节点由三部分构成:
prev域:用于指向上一节点
data域:数据域,用来存储元素数据
next域:用于指向下一节点
双向链表的操作
双向链表的操作可以从两端开始,从第一个节点通过next指向可以一步步操作到尾部,从最后一个节点 通过prev指向可以一步步操作到头部。
插入节点
像双向链表中插入一个节点,需要调整两次 pre指向 和 两次 next 指向。
X为新节点,将A1的next指向X,将x的next指向A2,将A2的pre指向X,将X 的pre指向A1。
删除节点
从双向链表中删除一个节点,需要调整一次 pre 指向 和 一次 next 指向就可以了。
将A1的 next指向 A2, 将A2的pre 指向 A1。
代码实现
public class DoubleNode {public final int key;public String value;public DoubleNode pre;public DoubleNode next;public DoubleNode(int key, String value) {this.key = key;this.value = value;}@Overridepublic String toString() {return "DoubleNode{" +"key=" + key +", value='" + value + '\'' +'}';}
}
public class DoubleLinkedList {public DoubleNode first = null; //双链表的头部,也就是第一个节点public DoubleNode last = null; //双链表的尾部,也就是最后一个节点/*** @Description //TODO 从尾部添加节点*/public DoubleLinkedList addToTail(DoubleNode node) {if (last == null) {first = node;} else {last.next = node;node.pre = last;}last = node;return this;}/*** @Description //TODO 从头部开始添加*/public DoubleLinkedList addToHead(DoubleNode node) {if (first == null) {last = node;} else {node.next = first;first.pre = node;}first = node;return this;}/*** @Description //TODO 按照key key顺序添加*/public DoubleLinkedList addOfOrder(DoubleNode node) {if (first == null) {first = node;last = node;return this;}
//node 比头节点小,将 node 设为头肩if (first.key > node.key) {first.pre = node;node.next = first;first = node;return this;}
//node 比尾节点大,将node变为 尾节点if (node.key > last.key) {last.next = node;node.pre = last;last = node;return this;}DoubleNode temp = first.next;while (true) {if (temp.key > node.key) {node.next = temp;node.pre = temp.pre;temp.pre.next = node;temp.pre = node;break;}temp = temp.next;}return this;}/*** @Description //TODO 获取节点*/public DoubleNode get(int key) {if (first == null) {return null;}DoubleNode temp = first;while (temp != null) {if (temp.key == key) {return temp;}temp = temp.next;}return null;}/*** @Description //TODO 删除*/public DoubleLinkedList remove(DoubleNode node) {if (first == null) {return this;}
//如果删除的是头节点if (first == node) {first.next.pre = null;first = first.next;return this;}
//如果删除的是为节点if (last == node) {last.pre.next = null;last = last.pre;return this;}DoubleNode temp = first.next;while (temp != null) {if (temp.key == node.key) {temp.pre.next = temp.next;temp.next.pre = temp.pre;break;}temp = temp.next;}return this;}/*** @Description //TODO*/public DoubleLinkedList update(DoubleNode node) {if (first == null) {return this;}DoubleNode temp = first;while (temp != null) {if (temp.key == node.key) {temp.value = node.value;break;}temp = temp.next;}return this;}public void print() {if (first == null) {return;}DoubleNode temp = first;while (temp != null) {System.out.println(temp);temp = temp.next;}}public static void main(String[] args) {DoubleNode aaa = new DoubleNode(1, "aaa");DoubleNode bbb = new DoubleNode(2, "bbb");DoubleNode ccc = new DoubleNode(6, "ccc");DoubleLinkedList doubleLinkedList = new DoubleLinkedList();doubleLinkedList.addToTail(aaa);doubleLinkedList.addToTail(bbb);doubleLinkedList.addToTail(ccc);doubleLinkedList.print();System.out.println("===================");DoubleNode ddd = new DoubleNode(4, "ddd");doubleLinkedList.addToHead(ddd);doubleLinkedList.print();System.out.println("===================");DoubleNode eee = new DoubleNode(3, "eee");doubleLinkedList.addOfOrder(eee);doubleLinkedList.print();System.out.println("===================");System.out.println(doubleLinkedList.get(7));System.out.println("===================");doubleLinkedList.remove(new DoubleNode(1, "aaa"));doubleLinkedList.print();System.out.println("===================");doubleLinkedList.update(new DoubleNode(2, "herb"));doubleLinkedList.print();}
}
源码分析
LinkedList特性
- LinkedList 集合底层实现的数据结构为双向链表
- LinkedList 集合中元素允许为 null
- LinkedList 允许存入重复的数据
- LinkedList 中元素存放顺序为存入顺序。
- LinkedList 是非线程安全的
- 如果在频繁的插入,或者删除数据时,就用linkedList性能会更好。
继承结果及层次关系
类的属性
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable{
//LinkedList 中的节点个数
transient int size = 0;
//LinkedList 链表的头节点
transient Node<E> first;
//LinkedList 链表的 尾节点
transient Node<E> last;
}
构造方法
- 空构造器
//空构造器生成一个空链表 ==> frist = last = null
public LinkedList() {
}
- 有参构造器
// 将集合 c 中的 各个元素构建成 LinkedList 链表
public LinkedList(Collection<? extends E> c) {
//调用无参构造器
this();
//添加集合中的所有元素
addAll(c);
}
内部类(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 就是实际的节点,用于存放实际元素的地方
add()
public boolean add(E e) {
//将元素添加到链表的末尾
linkLast(e);
return true;
}
说明:add函数用于向LinkedList中添加一个元素,并且添加到链表尾部。具体添加到尾部的逻辑是由 linkLast函数完成的。
void linkLast(E e) {//临时节点 l(L的小写)保存last,也就是 l 指向最后一个节点final Node<E> l = last;//将e(值)封装为节点,并且e.perv指向了最后一个节点final Node<E> newNode = new Node<>(l, e, null);//newNode 成为最后一个节点last = newNode;// 判断之前的链表是否为空,如果为空,那么 newNode 就成为了头节点if (l == null)first = newNode;else //否则将之前的尾节点 的 next 指向 newNode(新节点)l.next = newNode;size++;///添加了节点,size要自增modCount++;}
的末尾
linkLast(e);
return true;
}
说明:add函数用于向LinkedList中添加一个元素,并且添加到链表尾部。具体添加到尾部的逻辑是由 linkLast函数完成的。
void linkLast(E e) {//临时节点 l(L的小写)保存last,也就是 l 指向最后一个节点final Node<E> l = last;//将e(值)封装为节点,并且e.perv指向了最后一个节点final Node<E> newNode = new Node<>(l, e, null);//newNode 成为最后一个节点last = newNode;// 判断之前的链表是否为空,如果为空,那么 newNode 就成为了头节点if (l == null)first = newNode;else //否则将之前的尾节点 的 next 指向 newNode(新节点)l.next = newNode;size++;///添加了节点,size要自增modCount++;
}
Day 09 List子接口LinkedList相关推荐
- Collection集合接口及其子接口、实现类
1. Collection 接口简介 2. Collection的子接口 2.1 List接口 List接口的实现类 ① ArrayList ② Vector ③ Stack ④ LinkedList ...
- 【Java8】堆栈/队列/数组/链表/红黑树,List/set子接口,hashcode/hashset,Map/内部接口,/统计字符个数,debug,斗地主,Collections,TreeSet
文章目录 1.堆栈/队列/数组/链表:数据结构即计算机组织管理数据的方式,堆栈指的是内存图中的栈,不是堆 2.红黑树:二查,二查平,二查平1倍 3.List子接口:集合,IndexOutOfBound ...
- JavaSE进阶之(十)Map 子接口之 ConcurrentHashMap
十.Map 子接口之 ConcurrentHashMap 10.1 JDK 1.7 中的 ConcurrentHashMap 01.JDK 1.7 中 ConcurrentHashMap 底层结构 0 ...
- JavaSE入门学习34:Java集合框架之Collection接口、子接口及其实现类
一Collection接口 Collection接口定义了存取一组对象的方法,其子接口Set.List和Queen分别定义了存储方式. 使用Collection接口需要注意: 1Collection接 ...
- Java-Collection的子接口-List集合
文章目录 List集合 Demo1 List 实现类 ArrayList ArrayList源码分析 Vector LinkedList LinkedList源码分析 ArrayList和Linked ...
- 集合之Collection家族的 List接口+LinkedList+Vector+Stack及Set接口+HashSet+LinkedHashSet+TreeSet
集合之Collection家族的 List接口+LinkedList+Vector+Stack及Set接口+HashSet+LinkedHashSet+TreeSet 一.LinkedList 1.L ...
- Spring Boot——[JPA 无法注入 JpaRepository 子接口问题]解决方案
问题描述 Error starting ApplicationContext. To display the conditions report re-run your application wit ...
- 怎么把路由的#号去掉_VLAN应用篇系列:交换机VLAN间路由与传统单臂路由(子接口)方式...
1 说明 之前已经讲解过了思科交换机的VLAN间路由以及路由器与二层交换机组网的单播路由形式[子接口],这次主要讲解华为上面的VLAN间路由的配置,以及单臂路由的组网方式.华为的三层VLAN接口,就叫 ...
- linux系统子接口配置文件,Linux网卡绑定、子接口-IP别名
查看网卡线缆状态: mii-tool eth0 查看网卡底层信息: ethtool eth0 ethtool -i eth0 查看网卡驱动信息 ethtool -S eth0 查看网卡状态统计信 ...
最新文章
- 给热爱学习的同学们推荐一些顶级的c# Blogs链接
- Python 是怎么火起来的? 转载 2018年01月12日 00:00:00 133 图:Python 之父 Guido 正在设计 Python 语言,结果家里突然潜入一条大蟒蛇,一番激烈斗争,大
- hadoop启动报错:localhost: ssh: Could not resolve hostname localhost
- AndroidStudio部署项目时出现错误:Instant Run requires 'Tools | Android | Enable ADB integration' to be enabled
- 【LCT】网络(luogu 2173/ZJOI2011)
- mysql在哪里写代码_[译] 如何写好 Go 代码
- C++学习:第一章 开始
- 199.二叉树的右视图
- hplus java,HPlus(H+) 后台管理模板带文档V 4.1.1-完整版
- 一个简单的java程序
- 科技爱好者周刊(第 160 期):中年码农的困境
- 用无线路由器同步或备份PassXYZ数据,教你如何把无线路由器打造成网络存储
- 禁止所有搜索引擎蜘蛛的爬行收录
- 优步和滴滴激战中国市场
- Python 快速入门学习
- Mac Charles 抓包 iPhone Https(详细流程)
- Java数据结构03-------------链表
- hdu 1114Piggy-Bank(完全背包)
- js 保留两位小数的方法总结
- 使用爬虫实现代理IP池之放弃篇
热门文章
- 消费新品周报 | TCL发布中国首款可旋转智慧大屏;麦卢卡蜂蜜品牌BEE+登陆中国...
- Flink一站式平台 StreamX 1.2.2 正式发布, 迄今最稳定可用版本
- 效用最大化准则:离散选择模型的核心(Probit模型上篇)——离散选择模型之七
- 高数-不定积分--凑积分(第一类换元法)
- [NOIP2000]单词接龙(牛客)
- 模块化开发一个电子商务网站
- java的Intersect用法_intersect、minus的用法
- 黄淮学院计算机重点学科,黄淮学院专业排名 最好的专业有哪些
- 利用百度AI平台+pyqt5实现自动识别银行卡小工具
- 新型冠状病毒传播规律离散微观模型(结果与实际情况一致)-附源码