Linkedlist是一个集合容器,具有增删改查基本功能,本例中模拟增删查,对于修改,只需要将原节点处的val更新为新值即可,增加和删除在链表中速度是比较快的,查找,修改慢,因为要从头或者从尾开始遍历。自定义的linkedList名称为yLinkedList。

类似于ArrayList中需要有一个数组来存储元素,在Linkedlist中也需要一个容器来存储元素,这个容器叫什么名字自己随意取,这里使用Node。该容器理论上可以放在任意处,只要在Mylinkedlist中可以调用即可,但考虑到外部类不会直接使用Node,所以将Node作为Mylinkedlist的内部私有类比较合适。

链表有长度,所以具有属性size,链表通过索引查找元素时,从头部或者尾部开始遍历,链表中需要存在头部(head)和尾部(tail)节点,LinkedList是双链表,在每个Node节点中都需要存在一个指向前一个节点指针和指向后一个节点指针,且Node节点也必须保存当前节点的值,这样MyLinkedList的大致结构就有了,由于是简单模拟增删查,List接口中的方法挺多的,故未实现List

  1. package com.demo.langdemo.jdk;
  2.  
  3. public class MyLinkedList {
  4. int size;
  5. // 当前集合的首节点
  6. private Node head;
  7. // 当前集合的尾节点
  8. private Node tail;
  9.  
  10. /*
  11. * 存储元素的容器
  12. */
  13. private class Node {
  14. // 当前节点的值
  15. Object val;
  16. // 当前节点的前一个节点
  17. Node pre;
  18. // 当前节点的后一个节点
  19. Node next;
  20.  
  21. Node(Node pre, Object val, Node next) {
  22. this.pre = pre;
  23. this.val = val;
  24. this.next = next;
  25. }
  26. }
  27. }

在首部添加元素

当前添加的元素的前一个节点是null,后一个节点就是之前的head节点,若当前的首节点为null,则表明整个集合元素个数为0,,将当前元素添加后,首尾节点相同,都为当前节点。当首节点不为null,则将当前首节点的的pre指向新添加节点,并且将首节点指向新添加节点

  1. public void addFirst(Object val) {
  2. // 定位新添加的节点的位置,添加到首节点,则其前驱节点为null
  3. Node newNode = new Node(null, val, head);
  4. // 修改其他节点位置
  5. if (head == null) {
  6. // 首节点为空,则说明当前集合中还不存在数据,尾节点为空,也说明为空,但两个判断条件同样效果,使用一个判断即可
  7. tail = newNode;
  8. } else {
  9. head.pre = newNode;
  10. }
  11. // 更新head为当前节点
  12. head = newNode;
  13. size++;
  14. }

在尾部添加元素

在尾部添加元素时,前一个节点即为尾节点,后一个节点为null,当尾节点为null时,则表明整个集合元素个数为0,此时首尾节点相同,都为当前节点。当尾节点不为null时,将当前尾节点的的next指向新添加节点,并且将tail节点指向新添加元素

  1. public void addLast(Object val) {
  2. // 定位新添加的节点的位置,添加到尾节点,则其后继节点为null
  3. Node newNode = new Node(head, val, null);
  4. if (tail == null) {
  5. // 尾节点为空
  6. head = newNode;
  7. } else {
  8. tail.next = newNode;
  9. }
  10.  
  11. tail = newNode;
  12. size++;
  13. }

直接调用add方法时,从头插入或者从尾插入可根据具体情况选择

在指定位置添加元素

首先确定索引是否超出了当前集合的size,超出则抛出异常,如果index==size,则在尾部插入,如果index==0,则在头部插入,否则即是在中间部位插入。中间部位插入时,首先要获取到查入位置已存在的节点(查询方法在后面介绍),获取其pre节点,新添加节点的pre指向已存在节点的pre节点,新添加节点的next节点指向已经存在的已存在的节点。已存在的节点的pre节点的next节点指向新添加节点,已存在的节点的pre节点指向新添加节点

  1. public void add(int index, Object val) {
  2. // 需要找到当前索引的节点
  3. try {
  4. if (index < 0 || index > size) {
  5. throw new Exception("error");
  6. }
  7. } catch (Exception e) {
  8. e.printStackTrace();
  9. }
  10. if (index == size) {
  11. addLast(val);
  12. } else if (index == 0) {
  13. addFirst(val);
  14. } else {
  15. Node currNode = getNode(index);
  16. Node pre = currNode.pre;
  17. Node newNode = new Node(pre, val, currNode);
  18. pre.next = newNode;
  19. currNode.pre = newNode;
    size ++;
  20. }
  21. }

查找指定位置的节点

从中间开始查找无从下手,但每次添加元素时,size都会做对应的自增,所以每个索引也是唯一对应一个元素的,这里不考虑性能,直接就从head开始遍历查找,找index对应元素,那么index-1的next节点即为当前要找的index对应的元素

  1. public Object get(int index) {
  2. return getNode(index).val;
  3. }
  4.  
  5. private Node getNode(int index) {
  6. Node node = head;
  7. for (int i = 0; i < index; i++) {
  8. // 将head的next节点重新赋值给node,继续查询下一个head的next节点,这样,index-1的next节点即为我们所需要的节点
  9. node = head.next;
  10. }
  11. return node;
  12. }

根据指定索引删除

获取索引对应的元素,找到其pre和next节点,并将pre和next节点之间建立联系,将当前被删除元素的pre和next节点置为null,解除与集合中元素的联系

  1. public Object remove(int index) {
  2. // 找到索引对应的节点
  3. Node node = getNode(index);
  4. // 获取该节点的pre和next节点
  5. Node pre = node.pre;
  6. Node next = node.next;
  7.  
  8. // 设置该节点的pre和next对应关系
  9. pre.next = next;
  10. next.pre = pre;
  11.  
  12. node.next=null;
  13. node.pre = null;
  14.  
  15. size--;
  16. return node.val;
  17. }

根据元素值删除

从头或者从尾或者两头开始遍历等,扎到每个node节点的值与要删除的对比,若一致,则删除,将当前要删除的节点的pre和next节点删除,解除与集合中元素的关系,注意要删除的元素必须是重写了equals方法,否则删除的结果可能与预期不一致。

  1. public Object remove(Object val) {
  2. Node node = head;
  3. for (int i = 0; i < size; i++) {
  4. if (node.val.equals(val)) {
  5. Node pre = node.pre;
  6. Node next = node.next;
  7.  
  8. pre.next = next;
  9. next.pre = pre;
  10. break;
  11. }
  12. node = node.next;
  13. }
  14.  
  15. node.pre = null;
  16. node.next = null;
  17. size--;
  18. return node.val;
  19. }

完整实现类

MyLinkedList.java

  1. package com.demo.langdemo.jdk;
  2.  
  3. public class MyLinkedList {
  4. int size;
  5. // 当前集合的首节点
  6. private Node head;
  7. // 当前集合的尾节点
  8. private Node tail;
  9.  
  10. /*
  11. * 存储元素的容器
  12. */
  13. private class Node {
  14. // 当前节点的值
  15. Object val;
  16. // 当前节点的前一个节点
  17. Node pre;
  18. // 当前节点的后一个节点
  19. Node next;
  20.  
  21. Node(Node pre, Object val, Node next) {
  22. this.pre = pre;
  23. this.val = val;
  24. this.next = next;
  25. }
  26. }
  27.  
  28. public void addLast(Object val) {
  29. // 定位新添加的节点的位置,添加到尾节点,则其后继节点为null
  30. Node newNode = new Node(head, val, null);
  31. if (tail == null) {
  32. // 尾节点为空
  33. head = newNode;
  34. } else {
  35. tail.next = newNode;
  36. }
  37.  
  38. tail = newNode;
  39. size++;
  40. }
  41.  
  42. public void addFirst(Object val) {
  43. // 定位新添加的节点的位置,添加到首节点,则其前驱节点为null
  44. Node newNode = new Node(null, val, head);
  45. // 修改其他节点位置
  46. if (head == null) {
  47. // 首节点为空,则说明当前集合中还不存在数据,尾节点为空,也说明为空,但两个判断条件同样效果,使用一个判断即可
  48. tail = newNode;
  49. } else {
  50. head.pre = newNode;
  51. }
  52. // 更新head为当前节点
  53. head = newNode;
  54. size++;
  55. }
  56.  
  57. public void add(Object val) {
  58. // addFirst(val);
  59. addLast(val);
  60. }
  61.  
  62. public Object get(int index) {
  63. return getNode(index).val;
  64. }
  65.  
  66. private Node getNode(int index) {
  67. Node node = head;
  68. for (int i = 0; i < index; i++) {
  69. // 将head的next节点重新赋值给node,继续查询下一个head的next节点,这样,index-1的next节点即为我们所需要的节点
  70. node = head.next;
  71. }
  72. return node;
  73. }
  74.  
  75. public String toString() {
  76. StringBuilder str = new StringBuilder();
  77.  
  78. Node node = head;
  79. while (node != null) {
  80. str.append(node.val).append(",");
  81. node = node.next;
  82. }
  83.  
  84. return str.deleteCharAt(str.length() - 1).toString();
  85. }
  86.  
  87. public void add(int index, Object val) {
  88. // 需要找到当前索引的节点
  89. try {
  90. if (index < 0 || index > size) {
  91. throw new Exception("error");
  92. }
  93. } catch (Exception e) {
  94. e.printStackTrace();
  95. }
  96. if (index == size) {
  97. addLast(val);
  98. } else if (index == 0) {
  99. addFirst(val);
  100. } else {
  101. Node currNode = getNode(index);
  102. Node pre = currNode.pre;
  103. Node newNode = new Node(pre, val, currNode);
  104. pre.next = newNode;
  105. currNode.pre = newNode;
  106. size++;
  107. }
  108. }
  109.  
  110. public Object remove(int index) {
  111. // 找到索引对应的节点
  112. Node node = getNode(index);
  113. // 获取该节点的pre和next节点
  114. Node pre = node.pre;
  115. Node next = node.next;
  116.  
  117. // 设置该节点的pre和next对应关系
  118. pre.next = next;
  119. next.pre = pre;
  120.  
  121. node.next = null;
  122. node.pre = null;
  123.  
  124. size--;
  125. return node.val;
  126. }
  127.  
  128. public Object remove(Object val) {
  129. Node node = head;
  130. for (int i = 0; i < size; i++) {
  131. if (node.val.equals(val)) {
  132. Node pre = node.pre;
  133. Node next = node.next;
  134.  
  135. pre.next = next;
  136. next.pre = pre;
  137. break;
  138. }
  139. node = node.next;
  140. }
  141.  
  142. node.pre = null;
  143. node.next = null;
  144. size--;
  145. return node.val;
  146. }
  147.  
  148. public int getSize() {
  149. return size;
  150. }
  151.  
  152. }

在本次模拟中,未考虑性能等问题,只是实现了简单的功能,了解下链表的结构及实现思路。还需要查看大神写的LinkedList源码,了解其实现精髓。

ArrayList和LinkedList,前者查询和修改快,添加和删除慢,后者是查询,修改慢,添加删除快。

模拟LinkedList的更多相关文章

  1. JAVA容器-模拟LinkedList实现(双链表)

    概述 LinkedList实质上就是双向链表的拓展的实现,我们将关注一下问题.LinkedList 1.双向链表怎么来实现插入.删除.查询? 2.利用二分法提高查询效率. 3.不同步,线程不安全,需要 ...

  2. 单元测试(Spring)

    单元测试是指对软件中的最小可测试单元进行的检查和验证,是软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试. 单元测试好处:提高代码质量(实现功能.逻辑 ...

  3. 框架Mockito

    一.什么是mock测试,什么是mock对象? 先来看看下面这个示例: 从上图可以看出如果我们要对A进行测试,那么就要先把整个依赖树构建出来,也就是BCDE的实例. 一种替代方案就是使用mocks 从图 ...

  4. 大数据之路week02 List集合的子类

    1:List集合的子类(掌握) (1)List的子类特点 ArrayList: 底层数据结构是数组,查询快,增删慢. 线程不安全,效率高. Vector: 底层数据结构是数组,查询快,增删慢. 线程安 ...

  5. C++模拟实现JDK中的ArrayList和LinkedList

    Java实现ArrayList和LinkedList的方式采用的是数组和链表.以下是用C++代码的模拟: 声明Collection接口: #ifndef COLLECTION_H_ #define C ...

  6. 使用LinkedList模拟一个堆栈或者队列数据结构

    使用LinkedList模拟一个堆栈或者队列数据结构. 堆栈:先进后出  如同一个杯子. 队列:先进先出  如同一个水管. import java.util.LinkedList; public cl ...

  7. java 16 - 5 LinkedList模拟栈数据结构的集合

    请用LinkedList模拟栈数据结构的集合,并测试 题目的意思是: 你自己的定义一个集合类,在这个集合类内部可以使用LinkedList模拟. package cn_LinkedList; impo ...

  8. Java LinkedList特有方法程序小解 && 使用LinkedList 模拟一个堆栈或者队列数据结构。

    package Collection; import java.util.LinkedList; /* LinkedList:特有的方法 addFirst()/addLast(); getFirst( ...

  9. 面试题:使用LinkedList来模拟一个堆栈或者队列数据结构

    请使用LinkedList来模拟一个堆栈或者队列数据结构. 堆栈:先进后出 First In Last Out  (FILO) 队列:先进先出 First In First Out  (FIFO) 我 ...

随机推荐

  1. linux 删除文件空间未释放问题

    现象:我们测试环境上,导出数据文件时,由于作业报错,重复导出,空间使用到达100%,按理说,导出的文件时在相同的路径下,文件名也是一致的,会自动替换. 那么之前导出的文件会被删除,问题就出现在删除这一 ...

  2. Matplotlib 随机漫步图

    import matplotlib.pyplot as plt from random import choice class Randomwalk(): def __init__(self,num_ ...

  3. 【异常】postman能够请求成功获取到参数,前端请求的却请求不到

    1 前端联调的时候,反馈自己的参数没有生效,无论传递任何参数都是一样的结果 盯了一下日志发现 postman请求的是   :{"getParameter":{"provi ...

  4. 0、CentOS7系统root密码丢失找回方法

    第一步 1.重新启动或开启CentOS7.6系统,在选择进入系统的Grub菜单界面如下图1-1,根据提示按"e"小写字母进入编辑界面,如下图1-2所示: 图1-1 CentOS7. ...

  5. deep_learning_Function_ Matplotlib 3D 绘图函数 plot_surface 的 rstride 和 cstride 参数

    今晚开始接触 Matplotlib 的 3D 绘图函数 plot_surface,真的非常强大,图片质量可以达到出版级别,而且 3D 图像可以旋转 ,可以从不同角度来看某个 3D 立体图,但是我发现各 ...

  6. Galera Cluster 实现mysql的高可用 (Percona XtraDB Cluster)

    Galera Cluster 实现mysql的高可用 (Percona XtraDB Cluster) # 基础搭建 # 设备:三台主机 192.168.47.101 192.168.47.102 1 ...

  7. python中的apply(),applymap(),map() 的用法和区别

    平时在处理df series格式的时候并没有注意 map和apply的差异 总感觉没啥却别.不过还是有区别的.下面总结一下: import pandas as pd df1= pd.DataFrame ...

  8. hive的事物性 transaction manager

    create table lk3 (id string,nname string,grade int,goldUser int); insert into lk3 values (,, ), (,, ...

  9. 小猿圈-IT自学人的小圈子 https://book.apeland.cn/details/54/

    笔记链接   https://book.apeland.cn/details/54/ 学习视频   https://www.apeland.cn/python

  10. BZOJ 1758 / Luogu P4292 [WC2010]重建计划 (分数规划(二分/迭代) + 长链剖分/点分治)

    题意 自己看. 分析 求这个平均值的最大值就是分数规划,二分一下就变成了求一条长度在[L,R]内路径的权值和最大.有淀粉质的做法但是我没写,感觉常数会很大.这道题可以用长链剖分做. 先对树长链剖分. ...