单向链表

Node理解

链表

Node 对象内部有valuenext
img
与arraylist很多接口相同,add remove clear等;
但是不能用继承,它们两个没有什么可以抽取到父类的公共代码。
但是可以用接口,只声明公共接口,不实现。
Node为单独类,里面保存值和下一个node的引用。

  1. public class Test {
  2. public static void main(String[] args) {
  3. // 创建了三个Node
  4. ListNode list1 = new ListNode(1);
  5. ListNode list2 = new ListNode(2);
  6. ListNode list3 = new ListNode(3);
  7. // 将他们串起来
  8. list1.next = list2; // 就相当于在类里面的 ListNode next = new ListNode(2);
  9. list2.next = list3;
  10. // 输出一下
  11. System.out.println(list1.next.next.val); //3
  12. }
  13. }
  14. class ListNode{
  15. int val;
  16. ListNode next; // 声明next变量为ListNode 用的时候再给它赋值 这是一个引用 类似指针
  17. public ListNode(int val){
  18. this.val = val;
  19. }
  20. }

img

实现链表主要接口

  1. package com.ay.linkedlist;
  2. public interface List<E> {
  3. void clear();
  4. int size();
  5. boolean isEmpty();
  6. void add(int index,E element);
  7. boolean contains(E element);
  8. void add(E element);
  9. E get(int index);
  10. E remove(int index);
  11. E set(int index,E element);
  12. int indexOf(E element);
  13. }
  1. package com.ay.linkedlist;
  2. public class LinkedList<E> implements List<E>{
  3. private int size;
  4. //只用在Linkedlist 定义为内部类
  5. private Node<E> first;
  6. private int ELEMENT_NOT_FOUND=-1;
  7. @Override
  8. public void clear() {
  9. first=null;
  10. size = 0;
  11. }
  12. @Override
  13. public int size() {
  14. return size;
  15. }
  16. @Override
  17. public boolean isEmpty() {
  18. return size==0;
  19. }
  20. //
  21. @Override
  22. public void add(int index, E element) {
  23. Node<E> nodes = new Node<>(element);
  24. if(index == 0){
  25. first = new Node<>(element,first);
  26. }else{
  27. nodes.next = node(index-1).next;
  28. node(index-1).next = nodes;
  29. // Node<E> prev = node(index-1);
  30. // prev.next = new Node<>(element,prev.next);
  31. }
  32. size ++;
  33. }
  34. @Override
  35. public boolean contains(E element) {
  36. return indexOf(element)!=ELEMENT_NOT_FOUND;
  37. }
  38. @Override
  39. public void add(E element) {
  40. add(size,element);
  41. }
  42. @Override
  43. public E get(int index) {
  44. Node<E> nodes = first;
  45. for (int i = 0; i < index; i++) {
  46. nodes = nodes.next;
  47. }
  48. return nodes.element;
  49. }
  50. @Override
  51. public E remove(int index) {
  52. if(index==0){
  53. first = node(index+1);
  54. }else{
  55. node(index-1).next = node(index+1);
  56. }
  57. size--;
  58. return null;
  59. }
  60. // 相当于改动嘛
  61. @Override
  62. public E set(int index, E element) {
  63. E old = node(index).element;
  64. node(index).element = element;
  65. return old;
  66. }
  67. // 获取指定元素的index
  68. @Override
  69. public int indexOf(E element) {
  70. Node<E> nodes = first;
  71. for (int i = 0; i < size; i++) {
  72. nodes = nodes.next;
  73. if(nodes.element==element){
  74. return i;
  75. }
  76. }
  77. return ELEMENT_NOT_FOUND;
  78. }
  79. public String toString(){
  80. Node<E> nodes = first;
  81. StringBuilder string = new StringBuilder();
  82. string.append("Size: ").append(size).append(" [");
  83. while(nodes!=null){
  84. string.append(nodes.element).append(",");
  85. nodes = nodes.next;
  86. }
  87. string.append("]");
  88. return string.toString();
  89. }
  90. // 定义一个函数返回对应index的node对象
  91. private Node<E> node(int index){
  92. Node<E> nodes = first;
  93. for (int i = 0; i < index; i++) {
  94. nodes = nodes.next;
  95. }
  96. return nodes;
  97. }
  98. // 注意返回对象 跟返回对象元素
  99. private static class Node<E>{
  100. // 内部类可以省略public 或 private
  101. E element;
  102. Node<E> next;
  103. //构造方法
  104. public Node(E element){
  105. this.element = element;
  106. }
  107. public Node(E element,Node<E> next){
  108. this.element = element;
  109. this.next = next;
  110. }
  111. }
  112. }

测试类

  1. package com.ay.linkedlist;
  2. public class Main {
  3. public static void main(String[] args) {
  4. List<Integer> list1 = new LinkedList<Integer>();
  5. list1.add(10);
  6. list1.add(20);
  7. list1.add(30);
  8. list1.add(40);
  9. list1.remove(2);
  10. System.out.println(list1);
  11. list1.add(3,50);
  12. list1.set(2,70);
  13. System.out.println(list1);
  14. System.out.println(list1.get(3));
  15. }
  16. }

练习

237. 删除链表中的节点 - 力扣(LeetCode) (leetcode-cn.com)

  1. /**
  2. * Definition for singly-linked list.
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode(int x) { val = x; }
  7. * }
  8. */
  9. class Solution {
  10. public void deleteNode(ListNode node) {
  11. node.val = node.next.val;
  12. node.next = node.next.next;
  13. }
  14. }

用下一个节点的值覆盖此节点的值,然后就出现了两个相同值的节点,把此节点指向下下个节点就可以了。

141. 环形链表

快慢指针,快指针走两步,慢指针走一步,如果有环肯定是相遇的。

  1. /**
  2. * Definition for singly-linked list.
  3. * class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode(int x) {
  7. * val = x;
  8. * next = null;
  9. * }
  10. * }
  11. */
  12. public class Solution {
  13. public boolean hasCycle(ListNode head) {
  14. if (head.next==null) return false;
  15. ListNode fast = head.next;
  16. ListNode low = head;
  17. while(fast != null && fast.next!=null){
  18. fast = fast.next.next;
  19. low = low.next;
  20. if(low == fast){
  21. return true;
  22. }
  23. }
  24. return false;
  25. }
  26. }

双向链表