Java数据结构LinkedList单链表和双链表模拟实现及相关OJ题秒AC总结知识点
创始人
2024-05-27 13:43:00
0

本篇文章主要讲述LinkedList链表中从初识到深入相关总结,常见OJ题秒AC,望各位大佬喜欢


一、单链表

1.1链表的概念及结构

1.2无头单向非循环链表模拟实现

1.3测试模拟代码

 1.4链表相关面试OJ题

1.4.1 删除链表中等于给定值 val 的所有节点

1.4.2 反转一个单链表

1.4.3 给你单链表的头结点 head ,请你找出并返回链表的中间结点

1.4.4 输入一个链表,输出该链表中倒数第k个结点

1.4.5 合并俩个有序链表

二、双链表

2.1双向链表模拟实现

2.2LinkedList其他常用方法介绍

2.3ArrayList和LinkedList的区别


1.1链表的概念及结构

由于顺序表ArrayList不适合从任意位置插入或者删除元素,因此引入了LinkedList链表,链表是一种物理存储结构上非连续存储结构,也称链式存储,数据元素的逻辑顺序是通过链表中的引用链接次序实现的。

实际中链表的结构非常多样,以下情况组合起来就有8种链表结构:

1. 单向或者双向

 2. 带头或者不带头

 

 3. 循环或者非循环

 4.无头单向非循环链表或者无头双向链表

 在Java的集合框架库中LinkedList底层实现就是无头双向循环链表。

1.2无头单向非循环链表模拟实现

public class MySingleList {static class ListNode {public int val;public ListNode next;public ListNode(int val) {this.val = val;}}public ListNode head;public void createLink() {ListNode node1 = new ListNode(12);ListNode node2 = new ListNode(13);ListNode node3 = new ListNode(14);ListNode node4 = new ListNode(16);node1.next = node2;node2.next = node3;node3.next = node4;head = node1;}/*** @author 徐延焜xyk* @Description://遍历链表*/public void display() {ListNode cur = head;while (cur != null) {System.out.println(cur.val + " ");cur = cur.next;}System.out.println();}/*** @author 徐延焜xyk* @Description://查找是否包含关键字key是否在单链表当中*/public boolean contains(int key) {ListNode cur = head;while (cur != null) {if (cur.val == key) {return true;}cur = cur.next;}return false;}/*** @author 徐延焜xyk* @Description://得到单链表的长度 O(N)*/public int size() {int count = 0;ListNode cur = head;while (cur != null) {count++;cur = cur.next;}return count;}/*** @author 徐延焜xyk* @Description://头插法 O(1)*/public void addFirst(int data) {ListNode node = new ListNode(data);node.next = head;head = node;}/*** @author 徐延焜xyk* @Description://尾插法 O(N)    找尾巴的过程*/public void addLast(int data) {ListNode node = new ListNode(data);if (head == null) {head = node;return;}ListNode cur = head;while (cur.next != null) {cur = cur.next;}cur.next = node;}/*** @author 徐延焜xyk* @Description: //任意位置插入,第一个数据节点为0号下标*/public void addIndex(int index, int data) throws ListIndexOutofException {checkIndex(index);if (index == 0) {addFirst(data);return;}if (index == size()) {addFirst(data);return;}ListNode cur = findIndexSubOne(index);ListNode node = new ListNode(data);node.next = cur.next;cur.next = node;}/*** @author 徐延焜xyk* @Description:找到 index-1位置的节点的地址*/private ListNode findIndexSubOne(int index) {ListNode cur = head;int count = 0;while (count != index - 1) {cur = cur.next;count++;}return cur;}private void checkIndex(int index) throws ListIndexOutofException {if (index < 0 || index > size()) {throw new ListIndexOutofException("index位置不合法!");}}/*** @author 徐延焜xyk* @Description://删除第一次出现关键字为key的节点 O(N)*/public void remove(int key) {if (head == null) {return;}if (head.val == key) {head = head.next;return;}ListNode cur = searchPrev(key);if (cur == null) {return;}ListNode del = cur.next;cur.next = del.next;}/*** @author 徐延焜xyk* @Description:找到关键字key的前一个节点*/private ListNode searchPrev(int key) {ListNode cur = head;while (cur.next != null) {if (cur.next.val == key) {return cur;}cur = cur.next;}return null;}/*** @author 徐延焜xyk* @Description://删除所有值为key的节点*/public void removeAllKey(int key) {if (head == null) {return;}ListNode prev = head;ListNode cur = head.next;while (cur != null) {if (cur.val == key) {prev.next = cur.next;cur = cur.next;} else {prev = cur;cur = cur.next;}if (head.val == key) {head = head.next;}}}/*** @author 徐延焜xyk* @Description:保证链表当中 所有的节点 都可以被回收*/public void clear() {head = null;}
}

1.3测试模拟代码

public static void main(String[] args) {MySingleList mySingleList = new MySingleList();//LinkedList stack = new LinkedList();//Queue queue = new ArrayDeque<>();mySingleList.display();System.out.println("=======");System.out.println(mySingleList.contains(90));System.out.println(mySingleList.size());System.out.println("====测试插入===");mySingleList.addLast(1);mySingleList.addLast(2);mySingleList.addLast(3);mySingleList.addLast(4);try {mySingleList.addIndex(0,1);}catch (ListIndexOutofException e) {e.printStackTrace();}mySingleList.display();System.out.println("=============");mySingleList.removeAllKey(1);mySingleList.display();}

 1.4链表相关面试OJ题

1.4.1 删除链表中等于给定值 val 的所有节点

1. 删除链表中等于给定值 val 的所有节点。
203. 移除链表元素 - 力扣(LeetCode)

class Solution {public ListNode removeElements(ListNode head, int val) {if (head == null){return null;}ListNode prev = head;ListNode cur = head.next;while (cur != null){if (cur.val == val){prev.next = cur.next;cur = cur.next;}else{prev = cur;cur = cur.next;}}if (head.val == val){head = head.next;}return head;}
}

1.4.2 反转一个单链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

206. 反转链表 - 力扣(LeetCode)

class Solution {public ListNode reverseList(ListNode head) {if(head == null){return null;}if(head.next == null){return head;}ListNode cur = head.next;head.next = null;while(cur != null){ListNode curNext = cur.next;cur.next = head;head = cur;cur = curNext;}return head;}
}

1.4.3 给你单链表的头结点 head ,请你找出并返回链表的中间结点

给你单链表的头结点 head ,请你找出并返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

876. 链表的中间结点 - 力扣(LeetCode)

class Solution {public ListNode middleNode(ListNode head) {ListNode fast = head;ListNode slow = head;while (fast != null && fast.next != null){fast = fast.next.next;slow = slow.next;}return slow;}
}

1.4.4 输入一个链表,输出该链表中倒数第k个结点

链表中倒数第k个结点_牛客题霸_牛客网 (nowcoder.com)

仅仅用一个指针进行遍历注定是没有办法很优美地实现此问题解答的,所以要用两个指针,这两个指针的位置相差k-1个距离,当快指针走到最后一个节点的时候,慢指针指向的位置就是我们要的倒数第k个节点了。思想就是这么简单了,很多链表类的题目都是活用指针就可以解决的,一个指针不可以的时候就两个指针来完成。

public class Solution {public ListNode FindKthToTail(ListNode head, int k) {if (k <= 0 || head == null) {return null;}ListNode fast = head;ListNode slow = head;while (k - 1 != 0) {fast = fast.next;if (fast == null) {return null;}k--;}while (fast.next != null) {fast = fast.next;slow = slow.next;}return slow;}
}

1.4.5 合并俩个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

21. 合并两个有序链表 - 力扣(LeetCode)

class Solution {public ListNode mergeTwoLists(ListNode head1, ListNode head2) {ListNode newHead = new ListNode(0);ListNode tmp = newHead;while (head1 != null && head2 != null){if (head1.val < head2.val){tmp.next = head1;head1 = head1.next;tmp = tmp.next;}else {tmp.next = head2;head2 = head2.next;tmp = tmp.next;}}if (head1 != null){tmp.next = head1;}if (head2 != null){tmp.next = head2;}return newHead.next;}
}

上述这些oj题都是最基本的题目,请关注后续播客会有难度题上线!!

二、双链表

2.1双向链表模拟实现

public class MyLinkedList {static class ListNode {public int val;public ListNode prev;//前驱public ListNode next;//后继public ListNode(int val) {this.val = val;}}public ListNode head;public ListNode last;//头插法O(1)public void addFirst(int data) {ListNode node = new ListNode(data);if (head == null) {head = node;last = node;} else {node.next = head;head.prev = node;head = node;}}//尾插法O(1)public void addLast(int data) {ListNode node = new ListNode(data);if (head == null) {head = node;last = node;} else {last.next = node;node.prev = last;last = node;}}//任意位置插入,第一个数据节点为0号下标public void addIndex(int index, int data) {if (index < 0 || index > size()) {throw new ListIndexOutOfException();}if (index == 0) {addFirst(data);return;}if (index == size()) {addLast(data);return;}ListNode cur = findIndex(index);ListNode node = new ListNode(data);node.next = cur;cur.prev.next = node;node.prev = cur.prev;cur.prev = node;}public ListNode findIndex(int index) {ListNode cur = head;while (index != 0) {cur = cur.next;index--;}return cur;}//查找是否包含关键字key是否在单链表当中public boolean contains(int key) {ListNode cur = head;while (cur != null) {if (cur.val == key) {return true;}cur = cur.next;}return false;}//删除第一次出现关键字为key的节点public void remove(int key) {ListNode cur = head;while (cur != null) {if (cur.val == key) {//1. 删除的是头节点if (cur == head) {head = head.next;//只有一个节点if (head != null) {head.prev = null;}} else {//中间  尾巴cur.prev.next = cur.next;//不是尾巴节点if (cur.next != null) {cur.next.prev = cur.prev;} else {//是尾巴节点last = last.prev;}}return;}cur = cur.next;}}//删除所有值为key的节点public void removeAllKey(int key) {ListNode cur = head;while (cur != null) {if (cur.val == key) {//1. 删除的是头节点if (cur == head) {head = head.next;//只有一个节点if (head != null) {head.prev = null;}} else {//中间  尾巴cur.prev.next = cur.next;//不是尾巴节点if (cur.next != null) {cur.next.prev = cur.prev;} else {//是尾巴节点last = last.prev;}}}cur = cur.next;}}public int size() {int len = 0;ListNode cur = head;while (cur != null) {len++;cur = cur.next;}return len;}public void display() {ListNode cur = head;while (cur != null) {System.out.println(cur.val + " ");cur = cur.next;}System.out.println();}public void clear() {ListNode cur = head;while (cur != head) {ListNode curNext = cur.next;cur.prev = null;cur.next = null;cur = curNext;}head = null;last = null;}
测试代码:
public static void main(String[] args) {MyLinkedList linkedList = new MyLinkedList();linkedList.addLast(1);linkedList.display();}

1. LinkedList实现了List接口
2. LinkedList的底层使用了双向链表
3. LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问
4. LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)
5. LinkedList比较适合任意位置插入的场景

2.2LinkedList其他常用方法介绍

方法解释
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
LinkedList list = new LinkedList<>();
list.add(1); // add(elem): 表示尾插
list.add(2);
list.add(3);
list.add(4);
list.add(5);
list.add(6);
list.add(7);
System.out.println(list.size());
System.out.println(list);
// 在起始位置插入0
list.add(0, 0); // add(index, elem): 在index位置插入元素elem
System.out.println(list);
list.remove(); // remove(): 删除第一个元素,内部调用的是removeFirst()
list.removeFirst(); // removeFirst(): 删除第一个元素
list.removeLast(); // removeLast(): 删除最后元素
list.remove(1); // remove(index): 删除index位置的元素
System.out.println(list);

2.3ArrayList和LinkedList的区别

不同点ArrayListLinkedList
存储空间上物理上一定连续逻辑上连续,但物理上不一定连续
随机访问支持O(1)不支持:O(N)
头插需要搬移元素,效率低O(N)只需修改引用的指向,时间复杂度为O(1)
插入空间不够时需要扩容没有容量的概念
应用场景元素高效存储+频繁访问任意位置插入和删除频繁

相关内容

热门资讯

结婚典礼感谢致辞 结婚典礼感谢致辞(通用15篇)  在平平淡淡的学习、工作、生活中,要用到致辞的情况还是蛮多的,致辞要...
大鱼海棠配音台词 大鱼海棠配音台词  蛰伏十二年的动画《大鱼海棠》,终于上映了。虽然剧情被很多人吐槽,但美得不像话的画...
小学毕业典礼主持词 小学毕业典礼主持词实用范文  活动对象的不同,主持词的写作风格也会大不一样。在当今中国社会,司仪等是...
篮球赛闭幕词 篮球赛闭幕词(精选15篇)篮球赛闭幕词1各位来宾、同志们:  为期xx天的xxx第二届职工篮球赛,在...
元旦联欢晚会主持词 元旦联欢晚会主持词范文(精选9篇)  主持词分为会议主持词、晚会主持词、活动主持词、婚庆主持词等。在...
大型文艺演出主持词 大型文艺演出主持词  主持词可以采用和历史文化有关的表述方法去写作以提升活动的文化内涵。在当今中国社...
开学典礼致辞 开学典礼致辞15篇  在日常生活或是工作学习中,大家都经常接触到致辞吧,致辞具有“礼仪性”或“仪式化...
农村婚礼司仪主持词 农村婚礼司仪主持词15篇  主持词需要富有情感,充满热情,才能有效地吸引到观众。在当今不断发展的世界...
如何主持会议参考 如何主持会议范文参考  1.宣布会议开始。会议时间到后,若全体与会人员都已到位(至少重要的与会人员已...
韩剧漂亮男人经典台词 韩剧漂亮男人经典台词  1、答案都是在当事人手里的,不知道人们为什么,明明是自己非常了解的问题,但是...
外公七十大寿祝寿词 外公七十大寿祝寿词  外公七十大寿祝寿词  尊敬的外公、外婆、各位长辈、各位来宾:    大家好!今...
《香瓜七兄弟》经典台词 《香瓜七兄弟》经典台词  1. 阿丽呀,我哪好,我改还不行吗  2. 记不记得上回你尿炕 阿姨来了你...
孙子满月酒爷爷致辞 孙子满月酒爷爷致辞(通用6篇)  无论是身处学校还是步入社会,大家都不可避免地会接触到致辞吧,致辞具...
国庆文艺汇演主持词 国庆文艺汇演主持词  主持词要注意活动对象,针对活动对象写相应的主持词。在当今社会中,主持人在活动中...
中秋晚会主持词开场 中秋晚会主持词开场  主持词是主持人在台上表演的灵魂之所在。在现在的社会生活中,主持人的需求越来越高...
婚礼现场新郎致辞 婚礼现场新郎致辞各位亲朋好友:  大家好!  人生能有几次最难忘、最幸福的时刻,今天我才真正从内心里...
班会主持稿 班会主持稿(15篇)  在生活中,我们越来越需要主持稿,主持稿是主持人于节目进行过程中串联节目的稿件...
幼儿园开学典礼的主持词 幼儿园开学典礼的主持词范文(精选6篇)  根据活动对象的不同,需要设置不同的主持词。在当下这个社会中...
教师节晚会活动主持词 教师节晚会活动主持词(精选10篇)  主持词是主持人在台上表演的灵魂之所在。在当下的中国社会,很多场...
同学聚会的主持词 同学聚会的主持词3篇  中学时代,是一个人一生中最美好的时光。小编为大家整理了同学聚会的主持词3篇,...