当前位置:   article > 正文

数据结构——链表的实现(Java版)_java链表结构的实现

java链表结构的实现

目录

一、链表

二、代码实现

1.创建结点

2.构造函数

3.链表的相关属性

4.添加虚拟节点

5.判断链表是否为空

6.添加方法

(1)在头部添加

(2)在尾部添加

(3)在索引位置添加

(4)对头插法和尾插法代码进行简化(调用任意位置添加的方法)

7.打印链表(遍历,重写toString方法)

8.获取链表元素个数(链表长度)

9.获取链表结点

(1)获取头结点

(2)获取尾结点

(3)获取指定位置结点

10.判断结点是否存在

11.删除结点

(1)删除头结点

(2)删除尾节点

(3)在指定位置删除结点

(4)删除元素

(5)不使用虚拟节点删除


一、链表

链表是真正的动态数据结构,也是最简单的动态数据结构。

动态数据结构还有:二叉树,trie等

优点:不需要处理固定容量的问题,真正的动态

缺点:丧失了随机访问的能力

学习链表有助于更深理解引用和递归

二、代码实现

1.创建结点

使用内部类来创建结点

  1. //使用内部类——创建结点
  2. class Node<T>{
  3. T data;//节点本身
  4. Node next;//指向下个节点

2.构造函数

两个构造函数(传入的参数不同)

  1. public Node(T data){
  2. this.data=data;
  3. this.next=null;
  4. }
  5. public Node(T data,Node next){
  6. this.data=data;
  7. this.next=null;
  8. }
  9. }

3.链表的相关属性

头结点和结点个数(链表长度)

  1. private Node head;//头结点
  2. private int size;//表示链表中有多少个结点

4.添加虚拟节点

  1. public SelfLinkedList(){
  2. //创建一个虚拟头结点
  3. Node dummyHead=new Node(Integer.MIN_VALUE);
  4. this.head=dummyHead;
  5. this.size=0;
  6. dummyHead.next=head;
  7. }

5.判断链表是否为空

  1. public boolean isEmpty(){
  2. return this.size==0;
  3. }

6.添加方法

(1)在头部添加

  1. public void addHead(T data){
  2. //创建一个节点
  3. Node node= new Node(data);
  4. //挂接
  5. node.next=this.head;
  6. this.head=node;
  7. //更新size
  8. this.size++;
  9. }

(2)在尾部添加

  1. public void addTail(T data){
  2. Node node=new Node(data);
  3. //针对空链表做处理
  4. if(this.head==null){
  5. this.head=node;
  6. this.size++;
  7. return;
  8. }
  9. Node curNode=this.head;
  10. while(curNode.next!=null){
  11. curNode=curNode.next;
  12. }
  13. curNode.next=node;
  14. this.size++;
  15. }

(3)在索引位置添加

  1. //在任意位置添加
  2. public void add(int index,T data){
  3. //判断index是否有效
  4. if(index<0||index>this.size){
  5. throw new IllegalArgumentException("index is invalid");
  6. }
  7. //创建一个节点
  8. Node node= new Node(data);
  9. //特殊处理1:如果索引为0,
  10. if(index==0){
  11. this.head=new Node(data,this.head);
  12. this.size++;
  13. return;
  14. }
  15. //特殊处理2:链表为空(异常已抛出)
  16. //找前驱结点,从头开始找,让索引移动index-1次
  17. Node pre=this.head;
  18. for(int i=1;i<=index;i++){
  19. pre=pre.next;
  20. }
  21. //开始进行结点的挂接
  22. node.next=pre.next;
  23. pre.next=node;
  24. this.size++;
  25. }

(4)对头插法和尾插法代码进行简化(调用任意位置添加的方法)

  1. //在头部添加
  2. public void addHead(T data){
  3. add(0,data);
  4. }
  5. //在尾部添加
  6. public void addTail(T data){
  7. add(this.size,data);
  8. }

7.打印链表(遍历,重写toString方法)

  1. //打印整个链表
  2. @Override
  3. public String toString() {
  4. //从this。head开始一直向后
  5. Node curNode=this.head.next;
  6. StringBuilder sb=new StringBuilder();
  7. while(curNode!=null){
  8. sb.append(curNode.data+"-->");
  9. curNode=curNode.next;
  10. }
  11. sb.append("null");
  12. return sb.toString();
  13. }

8.获取链表元素个数(链表长度)

  1. //获取链表中元素的个数
  2. public int getSize(){
  3. return this.size;
  4. }

9.获取链表结点

(1)获取头结点

  1. //获取链表的头结点
  2. public Optional getFirst(){
  3. if(this.head.next==null){
  4. return Optional.empty();
  5. }
  6. return Optional.ofNullable(this.head.next.data);
  7. }

(2)获取尾结点

  1. //获取链表的尾结点
  2. public Optional getLast(){
  3. if(this.head.next==null){
  4. return Optional.empty();
  5. }
  6. Node<T> curNode=this.head;
  7. while(curNode.next!=null){
  8. curNode=curNode.next;
  9. }
  10. return Optional.of(curNode.data);
  11. }

(3)获取指定位置结点

  1. //从链表中获取任意位置的结点
  2. public T get(int index) {
  3. if (index < 0 || index >= this.size) {
  4. throw new IllegalArgumentException("index is invalid");
  5. }
  6. Node<T> curNode = this.head.next;
  7. int i = 0;
  8. while (i < index) {
  9. curNode = curNode.next;
  10. i++;
  11. }
  12. return curNode.data;
  13. }

10.判断结点是否存在

  1. //从链表中查找指定位置元素是否存在
  2. public boolean contains(T data) {
  3. Node curNode = this.head.next;
  4. while (curNode != null) {
  5. if (curNode.data.equals(data)) {
  6. return true;
  7. }
  8. }
  9. return false;
  10. }

11.删除结点

(1)删除头结点

  1. //从链表的头部删除元素
  2. public T removeHead() {
  3. if (this.isEmpty()) {
  4. return null;
  5. }
  6. Node<T> delNode = this.head.next;
  7. this.head.next = delNode.next;
  8. delNode.next = null;
  9. //更新size;
  10. this.size--;
  11. return delNode.data;
  12. }

(2)删除尾节点

  1. //链表的尾部删除元素
  2. public T removeTail() {
  3. if (this.isEmpty()) {
  4. return null;
  5. }
  6. Node<T> pre = this.head;
  7. while (pre.next.next != null) {
  8. pre = pre.next;
  9. }
  10. Node<T> delNode = pre.next;
  11. pre.next = delNode.next;
  12. delNode.next = null;
  13. //更新size;
  14. this.size--;
  15. return delNode.data;
  16. }

(3)在指定位置删除结点

  1. //删除任意位置的结点
  2. public T remove(int index){
  3. if(index<0||index>=this.size){
  4. throw new IllegalArgumentException("index is invalid");
  5. }
  6. //找删除结点的前驱
  7. Node<T>pre=this.head;
  8. int i=0;
  9. while(i<index){
  10. pre=pre.next;
  11. i++;
  12. }
  13. Node<T>delNode=pre.next;
  14. pre.next=delNode.next;
  15. delNode.next=null;
  16. this.size--;
  17. return delNode.data;
  18. }

(4)删除元素

  1. //根据值从链表中删除元素
  2. public int removeByValue(T value){
  3. int count=0;
  4. //定义前驱结点
  5. Node<T>pre=this.head;
  6. while(pre.next!=null){
  7. Node curNode=pre.next;
  8. if(curNode.data.equals(value)){
  9. pre.next=pre.next.next;
  10. curNode.next=null;
  11. this.size--;
  12. count++;
  13. }else{
  14. pre=pre.next;
  15. }
  16. }
  17. return count;
  18. }

(5)不使用虚拟节点删除

  1. //不使用虚拟头结点
  2. public int removeByValue2(T val){
  3. int count = 0;
  4. Node<T> realHead = this .head.next;
  5. while(realHead!=null&&realHead.data.equals(val)){
  6. realHead=realHead.next;
  7. this.size--;
  8. count++;
  9. }
  10. //判断链表是否为空
  11. if(realHead==null){
  12. return count;
  13. }
  14. //头结点不是删除的点
  15. Node pre = realHead;
  16. while(pre.next!=null){
  17. Node<T> delNode = pre.next;
  18. if(delNode.equals(val)){
  19. pre.next = delNode .next;
  20. delNode.next = null;
  21. this.size--;
  22. count++;
  23. }else{
  24. pre = pre .next;
  25. }
  26. }
  27. return count;
  28. }

三、完整代码

  1. package com.algo.lesson.lesson03;
  2. import java.util.Optional;
  3. import java.util.Random;
  4. public class SelfLinkedList<T> {
  5. //使用内部类——创建结点
  6. class Node<T> {
  7. T data;//节点本身
  8. Node next;//指向下个节点
  9. public Node(T data) {
  10. this.data = data;
  11. this.next = null;
  12. }
  13. public Node(T data, Node next) {
  14. this.data = data;
  15. this.next = null;
  16. }
  17. }
  18. //链表相关的属性和方法
  19. private Node head;//头结点
  20. private int size;//表示链表中有多少个结点
  21. public SelfLinkedList() {
  22. //创建一个虚拟头结点
  23. Node dummyHead = new Node(Integer.MIN_VALUE);
  24. this.head = dummyHead;
  25. this.size = 0;
  26. dummyHead.next = head;
  27. }
  28. //判断链表是否为空
  29. public boolean isEmpty() {
  30. return this.size == 0;
  31. }
  32. //向链表中添加结点
  33. //在头部添加
  34. public void addHead(T data) {
  35. /*//创建一个节点
  36. Node node= new Node(data);
  37. //挂接
  38. node.next=this.head;
  39. this.head=node;
  40. //更新size
  41. this.size++;*/
  42. add(0, data);
  43. }
  44. //在尾部添加
  45. public void addTail(T data) {
  46. /*Node node=new Node(data);
  47. //针对空链表做处理
  48. if(this.head==null){
  49. this.head=node;
  50. this.size++;
  51. return;
  52. }
  53. Node curNode=this.head;
  54. while(curNode.next!=null){
  55. curNode=curNode.next;
  56. }
  57. curNode.next=node;
  58. this.size++;*/
  59. add(this.size, data);
  60. }
  61. //在任意位置添加
  62. public void add(int index, T data) {
  63. //判断index是否有效
  64. if (index < 0 || index > this.size) {
  65. throw new IllegalArgumentException("index is invalid");
  66. }
  67. //创建一个节点
  68. Node node = new Node(data);
  69. //特殊处理1:如果索引为0,
  70. if (index == 0) {
  71. this.head = new Node(data, this.head);
  72. this.size++;
  73. return;
  74. }
  75. //特殊处理2:链表为空(异常已抛出)
  76. //找前驱结点,从头开始找,让索引移动index-1次
  77. Node pre = this.head;
  78. for (int i = 1; i <= index; i++) {
  79. pre = pre.next;
  80. }
  81. //开始进行结点的挂接
  82. node.next = pre.next;
  83. pre.next = node;
  84. this.size++;
  85. }
  86. //打印整个链表
  87. @Override
  88. public String toString() {
  89. //从this。head开始一直向后
  90. Node curNode = this.head.next;
  91. StringBuilder sb = new StringBuilder();
  92. while (curNode != null) {
  93. sb.append(curNode.data + "-->");
  94. curNode = curNode.next;
  95. }
  96. sb.append("null");
  97. return sb.toString();
  98. }
  99. //从链表中查找指定位置元素是否存在
  100. public boolean contains(T data) {
  101. Node curNode = this.head.next;
  102. while (curNode != null) {
  103. if (curNode.data.equals(data)) {
  104. return true;
  105. }
  106. }
  107. return false;
  108. }
  109. //获取链表中元素的个数
  110. public int getSize() {
  111. return this.size;
  112. }
  113. //获取链表的头结点
  114. public Optional getFirst() {
  115. if (this.head.next == null) {
  116. return Optional.empty();
  117. }
  118. return Optional.ofNullable(this.head.next.data);
  119. }
  120. //获取链表的尾结点
  121. public Optional getLast() {
  122. if (this.head.next == null) {
  123. return Optional.empty();
  124. }
  125. Node<T> curNode = this.head;
  126. while (curNode.next != null) {
  127. curNode = curNode.next;
  128. }
  129. return Optional.of(curNode.data);
  130. }
  131. //从链表中获取任意位置的结点
  132. public T get(int index) {
  133. if (index < 0 || index >= this.size) {
  134. throw new IllegalArgumentException("index is invalid");
  135. }
  136. Node<T> curNode = this.head.next;
  137. int i = 0;
  138. while (i < index) {
  139. curNode = curNode.next;
  140. i++;
  141. }
  142. return curNode.data;
  143. }
  144. //从链表的头部删除元素
  145. public T removeHead() {
  146. if (this.isEmpty()) {
  147. return null;
  148. }
  149. Node<T> delNode = this.head.next;
  150. this.head.next = delNode.next;
  151. delNode.next = null;
  152. //更新size;
  153. this.size--;
  154. return delNode.data;
  155. }
  156. //链表的尾部删除元素
  157. public T removeTail() {
  158. if (this.isEmpty()) {
  159. return null;
  160. }
  161. Node<T> pre = this.head;
  162. while (pre.next.next != null) {
  163. pre = pre.next;
  164. }
  165. Node<T> delNode = pre.next;
  166. pre.next = delNode.next;
  167. delNode.next = null;
  168. //更新size;
  169. this.size--;
  170. return delNode.data;
  171. }
  172. //删除任意位置的结点
  173. public T remove(int index){
  174. if(index<0||index>=this.size){
  175. throw new IllegalArgumentException("index is invalid");
  176. }
  177. //找删除结点的前驱
  178. Node<T>pre=this.head;
  179. int i=0;
  180. while(i<index){
  181. pre=pre.next;
  182. i++;
  183. }
  184. Node<T>delNode=pre.next;
  185. pre.next=delNode.next;
  186. delNode.next=null;
  187. this.size--;
  188. return delNode.data;
  189. }
  190. //根据值从链表中删除元素
  191. public int removeByValue(T value){
  192. int count=0;
  193. //定义前驱结点
  194. Node<T>pre=this.head;
  195. while(pre.next!=null){
  196. Node curNode=pre.next;
  197. if(curNode.data.equals(value)){
  198. pre.next=pre.next.next;
  199. curNode.next=null;
  200. this.size--;
  201. count++;
  202. }else{
  203. pre=pre.next;
  204. }
  205. }
  206. return count;
  207. }
  208. //不使用虚拟头结点
  209. public int removeByValue2(T val){
  210. int count = 0;
  211. Node<T> realHead = this .head.next;
  212. while(realHead!=null&&realHead.data.equals(val)){
  213. realHead=realHead.next;
  214. this.size--;
  215. count++;
  216. }
  217. //判断链表是否为空
  218. if(realHead==null){
  219. return count;
  220. }
  221. //头结点不是删除的点
  222. Node pre = realHead;
  223. while(pre.next!=null){
  224. Node<T> delNode = pre.next;
  225. if(delNode.equals(val)){
  226. pre.next = delNode .next;
  227. delNode.next = null;
  228. this.size--;
  229. count++;
  230. }else{
  231. pre = pre .next;
  232. }
  233. }
  234. return count;
  235. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/777346
推荐阅读
相关标签
  

闽ICP备14008679号