• Java实现单链表


    目录

    一.单链表

    二.单链表基本操作的实现

    1.单链表类、属性的定义

    2.求链表长度

    3.链表是否包含值为key的节点

    4.添加元素

    5.删除节点

    6.清空链表

    三、完整代码


    一.单链表

    链表是一种在物理存储结构非连续存储结构,数据元素的逻辑顺序通过链表中的引用链接次序实现。链表的结构多样,我们通过实现无头单向非循环链表,来进一步理解链表。

    从图中可以看出,链表在逻辑上连续的,但在物理存储结构上不一定是连续的

    由于链表是单向的,可以通过前一个节点访问后一个节点,不能通过后一个节点访问前一个结点

    二.单链表基本操作的实现

    1.单链表类、属性的定义

    要创建链表首先要有节点,我们可以将节点定义为内部类

    1. public class MySingleList{
    2. static class ListNode{
    3. //存放当前结点的值
    4. private int val;
    5. //存放下一节点的地址
    6. private ListNode next;
    7. public ListNode(){}
    8. public ListNode(int val){
    9. this.val = val;
    10. }
    11. }
    12. }

    由于链表是通过前一个节点访问下一个节点的,因此我们需要知道链表的第一个节点,因此我们需要定义一个头节点

    private ListNode head;//第一个节点
    

    2.求链表长度

     定义变量count用以计算,遍历链表,统计链表节点个数

    1. //求链表长度
    2. public int size() {
    3. int count = 0;
    4. //定义节点cur,用于遍历链表
    5. ListNode cur = head;
    6. while(cur != null){
    7. count++;
    8. //指向下一节点
    9. cur = cur.next;
    10. }
    11. return count;
    12. }

    3.链表是否包含值为key的节点

    遍历链表,判断节点的值是否等于key

    1. public boolean contains(int key) {
    2. ListNode cur = head;
    3. while(cur != null){
    4. if(cur.val == key){
    5. return true;
    6. }
    7. cur = cur.next;
    8. }
    9. return false;
    10. }

    4.添加元素

    链表添加元素的方式通常有三种,头插、尾插和在指定位置添加元素。

    头插:在链表的第一个节点前插入元素

     实现头插,就是让要插入的节点node指向原本链表的头节点head,再更新链表的第一个节点,让head指向新插入的节点

    1. //头插
    2. public void addFirst(int data) {
    3. //创建新节点
    4. ListNode listNode = new ListNode(data);
    5. listNode.next = head;
    6. head = listNode;
    7. }

    尾插:在链表的最后插入元素

    实现尾插,首先要找到链表的最后一个节点,再将最后一个节点的next更新为新节点即可

    1. //尾插
    2. public void addLast(int data) {
    3. ListNode newNode = new ListNode(data);
    4. //若链表为空,直接将head更新为插入节点
    5. if(head == null){
    6. head = newNode;
    7. }else{
    8. //通过遍历找到最后一个节点
    9. ListNode cur = head;
    10. while(cur.next != null){
    11. cur = cur.next;
    12. }
    13. cur.next = newNode;
    14. }
    15. }

    在指定位置添加元素

     在指定位置添加元素,首先要判断指定位置index是否合法,若index < 0 或 index > size,则不能添加元素,然后通过遍历找到节点插入的位置,由于链表为单链表,不能通过后一节点找到前一节点,因此,我们需要找到插入位置的前驱节点,然后通过前驱节点实现链表在index位置的插入

    1. //在任意位置添加元素
    2. public void addIndex(int index, int data) {
    3. //index不正确,无法添加元素
    4. if(index < 0 || index > size()){
    5. throw new RuntimeException("输入位置不正确,无法添加元素!");
    6. }else if(index == 0){//在0位置插入,即为头插
    7. addFirst(data);
    8. }else{
    9. ListNode cur = head;//用cur遍历链表,找到前驱节点
    10. ListNode listNode = new ListNode(data);
    11. int count = 0;
    12. while(count != index-1){
    13. count++;
    14. cur = cur.next;
    15. }
    16. //添加元素
    17. listNode.next = cur.next;
    18. cur.next = listNode;
    19. }
    20. }

    5.删除节点

    删除第一个值为key的节点:与在指定位置添加元素相同,我们需要找到第一个值为key的节点node的前驱节点,然后才能删除值为key的节点。由于JVM会将未被任何引用指向的对象回收掉,我们只需让node的前驱节点指向node的下一节点,即可实现删除

    1. //删除第一个值为key的节点
    2. public boolean remove(int key) {
    3. ListNode cur = head;
    4. //链表第一个节点的值即为key,头删
    5. if(head.val == key){
    6. head = head.next;
    7. return true;
    8. }//通过遍历找到第一个值为key的节点的前驱节点
    9. while(cur.next != null){
    10. if(cur.next.val == key){//找到了,删除节点
    11. cur.next = cur.next.next;
    12. return true;
    13. }
    14. cur = cur.next;
    15. }
    16. return false;//未找到值未key的节点,返回false
    17. }

    删除所有值为key的节点:首先要找到值为key的节点node,将node的上一节点指向node的下一节点,即可删除值为key的节点,注意考虑头节点值为key的情况,要删除链表中所有值为key的节点,利用while循环即可实现。

    1. //删除所有值为key的节点
    2. public void removeAllKey(int key) {
    3. //若链表为空,则直接返回null
    4. if(head == null){
    5. return;
    6. }
    7. ListNode cur = head;
    8. while(cur.next != null){
    9. if(cur.next.val == key){
    10. cur.next = cur.next.next;
    11. }else{
    12. cur = cur.next;
    13. }
    14. }
    15. //单独考虑头节点的值是否等于val
    16. if(head.val == key){
    17. head = head.next;
    18. }
    19. }

    6.清空链表

    由于JVM会将未被任何引用指向的对象回收掉,清空链表可以将每个节点的指向都置为null,即切断节点之间的链接,也可以直接将head置为null

    将每个节点的指向都置为null

    1. //清空链表
    2. public void clear() {
    3. if(head == null){//链表本身为空
    4. return;
    5. }
    6. ListNode cur = head;
    7. while(cur != null){
    8. ListNode next = cur.next;//记录下一节点
    9. cur.next = null;
    10. cur = next;
    11. }
    12. }

    直接将head置为null

    1. //清空链表
    2. public void clear() {
    3. head = null;
    4. }

    三、完整代码

    1. public class MySingleList {
    2. static class ListNode{
    3. //存放当前结点的值
    4. private int val;
    5. //存放下一节点的地址
    6. private ListNode next;
    7. public ListNode(){}
    8. public ListNode(int val){
    9. this.val = val;
    10. }
    11. }
    12. private ListNode head;//第一个节点
    13. //求链表长度
    14. public int size() {
    15. int count = 0;
    16. //定义节点cur,用于遍历链表
    17. ListNode cur = head;
    18. while(cur != null){
    19. count++;
    20. //指向下一节点
    21. cur = cur.next;
    22. }
    23. return count;
    24. }
    25. //链表是否包含值为key的节点
    26. public boolean contains(int key) {
    27. ListNode cur = head;
    28. while(cur != null){
    29. if(cur.val == key){
    30. return true;
    31. }
    32. cur = cur.next;
    33. }
    34. return false;
    35. }
    36. //头插
    37. public void addFirst(int data) {
    38. //创建新节点
    39. ListNode listNode = new ListNode(data);
    40. listNode.next = head;
    41. head = listNode;
    42. }
    43. //尾插
    44. public void addLast(int data) {
    45. ListNode newNode = new ListNode(data);
    46. //若链表为空,直接将head更新为插入节点
    47. if(head == null){
    48. head = newNode;
    49. }else{
    50. //通过遍历找到最后一个节点
    51. ListNode cur = head;
    52. while(cur.next != null){
    53. cur = cur.next;
    54. }
    55. cur.next = newNode;
    56. }
    57. }
    58. //在任意位置添加元素
    59. public void addIndex(int index, int data) {
    60. //index不正确,无法添加元素
    61. if(index < 0 || index > size()){
    62. throw new RuntimeException("输入位置不正确,无法添加元素!");
    63. }else if(index == 0){//在0位置插入,即为头插
    64. addFirst(data);
    65. }else{
    66. ListNode cur = head;//用cur遍历链表,找到前驱节点
    67. ListNode listNode = new ListNode(data);
    68. int count = 0;
    69. while(count != index-1){
    70. count++;
    71. cur = cur.next;
    72. }
    73. //添加元素
    74. listNode.next = cur.next;
    75. cur.next = listNode;
    76. }
    77. }
    78. //删除第一个值为key的节点
    79. public boolean remove(int key) {
    80. ListNode cur = head;
    81. //链表第一个节点的值即为key,头删
    82. if(head.val == key){
    83. head = head.next;
    84. return true;
    85. }//通过遍历找到第一个值为key的节点的前驱节点
    86. while(cur.next != null){
    87. if(cur.next.val == key){//找到了,删除节点
    88. cur.next = cur.next.next;
    89. return true;
    90. }
    91. cur = cur.next;
    92. }
    93. return false;//未找到值未key的节点,返回false
    94. }
    95. //删除所有值为key的节点
    96. public void removeAllKey(int key) {
    97. //若链表为空,则直接返回null
    98. if(head == null){
    99. return;
    100. }
    101. ListNode cur = head;
    102. while(cur.next != null){
    103. if(cur.next.val == key){
    104. cur.next = cur.next.next;
    105. }else{
    106. cur = cur.next;
    107. }
    108. }
    109. //单独考虑头节点的值是否等于val
    110. if(head.val == key){
    111. head = head.next;
    112. }
    113. }
    114. //清空链表
    115. public void clear() {
    116. if(head == null){//链表本身为空
    117. return;
    118. }
    119. ListNode cur = head;
    120. while(cur != null){
    121. ListNode next = cur.next;//记录下一节点
    122. cur.next = null;
    123. cur = next;
    124. }
    125. //或直接将head置为null
    126. //head = null;
    127. }
    128. }
  • 相关阅读:
    Day16:冒泡排序详解
    two point(双指针)
    Github每日精选(第30期):javascript 日期时间选择器flatpickr
    【网络编程】网络原来这么简单(更新中)
    Linux知识点总结(文件,进程,进程间通信)
    使用U盘安装openSUSE-Leap-15.4-DVD-x86_64
    31. 下一个排列
    Linux中防火墙相关操作
    selenium元素定位 —— 提高篇 CSS定位元素
    QT 自定义信号
  • 原文地址:https://blog.csdn.net/2301_76161469/article/details/133145847