当前位置:   article > 正文

五分钟“手撕”链表

五分钟“手撕”链表

为了提高大家的学习效率,我把代码放开头,供查阅。 

目录

一、链表的实现代码

二、什么是链表

三、链表的分类

四、链表的常见操作

插入

删除 

五、Java自带的LinkedList 

 两个构造方法

 一些常用方法

六、LinkedList的遍历

七、ArrayList和LinkedList的区别  


一、链表的实现代码

  1. //无头单向链表
  2. package demo1;
  3. public class MySingleLinkedList{
  4. class ListNode{
  5. public int var;
  6. public ListNode next;
  7. public int val;
  8. public ListNode(int var) {
  9. this.var = var;
  10. }
  11. }
  12. ListNode head;
  13. public void creat(){
  14. ListNode node1=new ListNode(1);
  15. ListNode node2=new ListNode(1);
  16. ListNode node3=new ListNode(1);
  17. ListNode node4=new ListNode(1);
  18. node1.next=node2;
  19. node2.next=node3;
  20. node3.next=node4;
  21. head=node1;
  22. }
  23. //头插法
  24. public void addFirst(int data) {
  25. ListNode node=new ListNode(data);
  26. node.next=head;
  27. head=node;
  28. }
  29. //尾插法
  30. public void addLast(int data) {
  31. ListNode node=new ListNode(data);
  32. if(head==null){
  33. head=node;
  34. return;
  35. }
  36. ListNode cur=head;
  37. while (cur.next!=null){
  38. cur=cur.next;
  39. }cur.next=node;
  40. }
  41. private void IndexCheck(int index)throws IndexNotLegal {
  42. if(index<0||index>size()){
  43. throw new IndexNotLegal("index位置不合法");
  44. }
  45. }
  46. //任意位置插入,第一个数据节点为0号下标
  47. public void addIndex(int index, int data){
  48. try {
  49. IndexCheck(index);
  50. }catch (IndexNotLegal e){
  51. e.printStackTrace();
  52. return;
  53. }
  54. ListNode node=new ListNode(data);
  55. ListNode cur=head;
  56. if(index==0){
  57. addFirst(data);
  58. return;
  59. }if(index==size()){
  60. addLast(data);
  61. return;
  62. }
  63. //注意这里是index-1
  64. for (int i = 0; i < index-1; i++) {
  65. cur= cur.next;
  66. }
  67. node.next=cur.next;
  68. cur.next=node;
  69. }
  70. //查找是否包含关键字key是否在单链表当中
  71. public boolean contains(int key) {
  72. ListNode cur=head;
  73. while (cur!=null){
  74. if(cur.var==key){
  75. return true;
  76. }cur=cur.next;
  77. }return false;
  78. }
  79. //删除第一次出现关键字为key的节点
  80. public void remove(int key) {
  81. if(head.var==key){
  82. head=head.next;
  83. return;
  84. }if(head==null){
  85. return;
  86. }
  87. ListNode cur=head;
  88. while (cur.next!=null){
  89. if(cur.next.var==key){
  90. cur.next=cur.next.next;
  91. return;
  92. }cur=cur.next;
  93. }
  94. }
  95. //删除所有出现的key节点
  96. public void removeAllKey(int key) {
  97. if(head==null){
  98. return;
  99. }ListNode prev=head;
  100. ListNode cur=head.next;
  101. while (cur!=null){
  102. if(cur.var==key){
  103. prev.next= cur.next;
  104. //这里不能写prev=cur
  105. cur= cur.next;
  106. }else {
  107. prev=cur;
  108. cur= cur.next;
  109. }
  110. if(head.var==key){
  111. head=head.next;
  112. }
  113. }
  114. }
  115. //得到单链表的长度
  116. public int size() {
  117. ListNode cur=head;
  118. int count=0;
  119. while (cur!=null){
  120. count++;
  121. cur=cur.next;
  122. }return count;
  123. }
  124. //打印链表
  125. public void display() {
  126. ListNode cur=head;
  127. for (int i = 0; i < size(); i++) {
  128. System.out.print(cur.var+" ");
  129. cur=cur.next;
  130. }
  131. System.out.println();
  132. }
  133. //清除链表
  134. public void clear() {
  135. head=null;
  136. }
  137. }
  138. public class IndexNotLegal extends RuntimeException {
  139. public IndexNotLegal(){
  140. }public IndexNotLegal(String s){
  141. super(s);
  142. }
  143. }
  144. package demo2;
  145. // 无头双向链表
  146. public class MyLinkedList {
  147. class ListNode {
  148. public int var;
  149. ListNode prev;
  150. ListNode next;
  151. public ListNode(int var) {
  152. this.var = var;
  153. }
  154. }
  155. ListNode head;
  156. ListNode last;
  157. //头插法
  158. public void addFirst(int data) {
  159. ListNode node = new ListNode(data);
  160. if (head == null) {
  161. head = last = node;
  162. return;
  163. }
  164. node.next = head;
  165. head.prev = node;
  166. head = node;
  167. }
  168. //尾插法
  169. public void addLast(int data) {
  170. ListNode node = new ListNode(data);
  171. if (head == null) {
  172. head = last = node;
  173. return;
  174. }
  175. last.next = node;
  176. node.prev = last;
  177. last = node;
  178. }
  179. private void indexCheck(int index) throws IndexNotLegal {
  180. if (index < 0 || index > size()) {
  181. throw new IndexNotLegal("index位置不合法");
  182. }
  183. }
  184. private ListNode findIndexCur(int index) {
  185. ListNode cur = head;
  186. while (index != 0) {
  187. cur = cur.next;
  188. index--;
  189. }
  190. return cur;
  191. }
  192. //任意位置插入,第一个数据节点为0号下标
  193. public void addIndex(int index, int data) {
  194. try {
  195. indexCheck(index);
  196. } catch (IndexNotLegal e) {
  197. e.printStackTrace();
  198. }
  199. if (index == 0) {
  200. addFirst(data);
  201. return;
  202. }
  203. if (index == size()) {
  204. addLast(data);
  205. return;
  206. }
  207. ListNode node = new ListNode(data);
  208. ListNode cur = findIndexCur(index);
  209. //先把node插进去,再调整node的前一个,最后再调cur,因为需要cur来调整
  210. node.next=cur;
  211. cur.prev.next=node;
  212. node.prev=cur.prev;
  213. cur.prev=node;
  214. }
  215. //查找是否包含关键字key是否在单链表当中
  216. public boolean contains(int key) {
  217. ListNode cur = head;
  218. while (cur != null) {
  219. if (cur.var == key) {
  220. return true;
  221. }
  222. cur = cur.next;
  223. }
  224. return false;
  225. }
  226. //删除第一次出现关键字为key的节点
  227. public void remove(int key) {
  228. ListNode cur = head;
  229. while (cur != null) {
  230. if (cur.var == key) {
  231. //头节点
  232. if (head.var == key) {
  233. head.next.prev = null;
  234. head = head.next;
  235. return;
  236. }
  237. //尾巴节点
  238. if (last.var == key) {
  239. last.prev.next = null;
  240. last = last.prev;
  241. return;
  242. }
  243. cur.next.prev = cur.prev;
  244. cur.prev.next = cur.next;
  245. return;
  246. }
  247. cur = cur.next;
  248. }
  249. }
  250. //删除所有值为key的节点
  251. public void removeAllKey(int key) {
  252. ListNode cur = head;
  253. while (cur != null) {
  254. if (cur.var == key) {
  255. //头节点
  256. if (head.var == key) {
  257. head.next.prev = null;
  258. head = head.next;
  259. return;
  260. }
  261. //尾巴节点
  262. if (last.var == key) {
  263. last.prev.next = null;
  264. last = last.prev;
  265. return;
  266. }
  267. cur.next.prev = cur.prev;
  268. cur.prev.next = cur.next;
  269. }
  270. cur = cur.next;
  271. }
  272. }
  273. //得到单链表的长度
  274. public int size() {
  275. int count = 0;
  276. ListNode cur = head;
  277. while (cur != null) {
  278. cur = cur.next;
  279. count++;
  280. }
  281. return count;
  282. }
  283. public void display() {
  284. ListNode cur = head;
  285. for (int i = 0; i < size(); i++) {
  286. System.out.print(cur.var + " ");
  287. cur = cur.next;
  288. }
  289. System.out.println();
  290. }
  291. public void clear() {
  292. head = last = null;
  293. }
  294. }
  295. package demo2;
  296. public class IndexNotLegal extends RuntimeException{
  297. public IndexNotLegal(){
  298. }public IndexNotLegal(String s){
  299. super(s);
  300. }
  301. }

二、什么是链表

简单来说,像链子一样的数据结构。像火车一节一节车厢一样,每个元素是独立的个体(内部类)。 并且他们在空间里是分散的 

 

为什么分散的还可以找到下一个呢?

答:一个节点里面装着两种东西,一个是值,一个的下一个的地址,这样根据下一个的地址就可以找到下一个了。 

三、链表的分类

常见的链表有三种,但是我这里只介绍两种:无头单链,无头双链。剩下的一种之后再补充。

单链和双链的区别?

答: 一个节点都是一个类。单链装的是值和下个节点双链装的是值和上个节点和下个节点

四、链表的常见操作

插入

怎么插入元素?在链表中很简单! 

单链p下个节点改成n1,n0下个节点改为p。

双链 p下个节点改为n1,n0下个节点改为p(先把p插进去,成一个逆时针),p上个节点改为n0,n1的上个节点改为p(修改原来的两点节点)

注意!还需要考虑一些特殊情况,具体请看代码的实现!

删除 

在链表中删除节点也非常方便,只需改变一个节点的引用(指针)即可。 

单链:n0的下个节点指向n1。

双链:n0下个节点改为n1,n1上个节点改为n0 。

问题来了:为什么p的指向n1可以不删?

答;原因是以及没人指向p了, 如果没人引用(指向)的东西,就会被系统自动回收。 像clear()方法,head不指向首个节点,那么首个节点被回收,同理下面也如此。

五、Java自带的LinkedList 

 两个构造方法

方法解释
LinkedList()无参构造
public LinkedList(Collection c)使用其他集合容器中元素构造List
  1. public static void main(String[] args) {
  2. // 构造一个空的LinkedList
  3. List<Integer> list1 = new LinkedList<>();
  4. List<String> list2 = new java.util.ArrayList<>();
  5. list2.add("JavaSE");
  6. list2.add("JavaWeb");
  7. list2.add("JavaEE");
  8. // 使用ArrayList构造LinkedList
  9. List<String> list3 = new LinkedList<>(list2);
  10. }

 一些常用方法

方法解释
boolean add(E e)尾插 e
void add(int index, E element)将 e 插入到 index 位置
boolean addAll(Collection c)尾插 c 中的元素
E remove(int index)删除 index 位置元素
boolean remove(Object o)删除遇到的第一个 o
E get(int index)获取下标 index 位置元素
E set(int index, E element)将下标 index 位置元素设置为 element
void clear()清空
boolean contains(Object o)判断 o 是否在线性表中
int indexOf(Object o)返回第一个 o 所在下标
int lastIndexOf(Object o)返回最后一个 o 的下标
List subList(int fromIndex, int toIndex)截取部分 list
  1. public static void main(String[] args) {
  2. LinkedList<Integer> list = new LinkedList<>();
  3. list.add(1); // add(elem): 表示尾插
  4. list.add(2);
  5. list.add(3);
  6. list.add(4);
  7. list.add(5);
  8. list.add(6);
  9. list.add(7);
  10. System.out.println(list.size());
  11. System.out.println(list);
  12. // 在起始位置插入0
  13. list.add(0, 0); // add(index, elem): 在index位置插入元素elem
  14. System.out.println(list);
  15. list.remove(); // remove(): 删除第一个元素,内部调用的是removeFirst()
  16. list.removeFirst(); // removeFirst(): 删除第一个元素
  17. list.removeLast(); // removeLast(): 删除最后元素
  18. list.remove(1); // remove(index): 删除index位置的元素
  19. System.out.println(list);
  20. // contains(elem): 检测elem元素是否存在,如果存在返回true,否则返回false
  21. if(!list.contains(1)){
  22. list.add(0, 1);
  23. }
  24. list.add(1);
  25. System.out.println(list);
  26. System.out.println(list.indexOf(1)); // indexOf(elem): 从前往后找到第一个elem的位置
  27. System.out.println(list.lastIndexOf(1)); // lastIndexOf(elem): 从后往前找第一个1的位置
  28. int elem = list.get(0); // get(index): 获取指定位置元素
  29. list.set(0, 100); // set(index, elem): 将index位置的元素设置为elem
  30. System.out.println(list);
  31. // subList(from, to): 用list中[from, to)之间的元素构造一个新的LinkedList返回
  32. List<Integer> copy = list.subList(0, 3);
  33. System.out.println(list);
  34. System.out.println(copy);
  35. list.clear(); // 将list中元素清空
  36. System.out.println(list.size());
  37. }

六、LinkedList的遍历

  1. public static void main(String[] args) {
  2. LinkedList<Integer> list = new LinkedList<>();
  3. list.add(1); // add(elem): 表示尾插
  4. list.add(2);
  5. list.add(3);
  6. list.add(4);
  7. list.add(5);
  8. list.add(6);
  9. list.add(7);
  10. System.out.println(list.size());
  11. //for循环遍历
  12. for (int i = 0; i < list.size(); i++) {
  13. System.out.print(list.get(i)+" ");
  14. }
  15. // foreach遍历
  16. for (int e:list) {
  17. System.out.print(e + " ");
  18. }
  19. System.out.println();
  20. // 使用迭代器遍历---正向遍历
  21. ListIterator<Integer> it = list.listIterator();
  22. while(it.hasNext()){
  23. System.out.print(it.next()+ " ");
  24. }
  25. System.out.println();
  26. // 使用反向迭代器---反向遍历
  27. ListIterator<Integer> rit = list.listIterator(list.size());
  28. while (rit.hasPrevious()){
  29. System.out.print(rit.previous() +" ");
  30. }
  31. System.out.println();
  32. }

七、ArrayList和LinkedList的区别  

不同点数组链表
存储方式连续内存空间分散内存空间
容量扩展长度不可变可灵活扩展
内存效率元素占用内存少、但可能浪费空间元素占用内存多
访问元素O(1)O(N)
添加元素O(N)O(1)
删除元素O(N)O(1)

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

闽ICP备14008679号