前言
欢迎大家阅读小奥奇的新作,听说上一篇我们留下了一点点 “ 简单的题目 ” ,我们在本篇要干什么呢,请看本篇任务!
本篇任务概述:
1、解决 “ 简单的遗留题目 ”
2、 LInkedList(双向)的使用
3、简单的自我模拟 LinkedList 的实现
4、ArrayList 和 LinkedList 的区别
一、解决 “ 简单的遗留题目 ”
1.1 反转一个单链表
public ListNode reverseList(ListNode head) {
if(head==null){
return null;
}
ListNode cur=head;
while(cur.next!=null){
ListNode lim=cur.next;
cur.next=lim.next;
lim.next=head;
head=lim;
}
return head;
}
解题思路如下:
主要使用头插法(前篇讲到过),从第二个节点开始,先判断 head 是否为空,若为空则返回 null,否则令 cur = head,使用 while 遍历链表,当 cur.next 不为空时,初始化下一个节点,使 lim = cur.next,接着使当前节点的下一个结点 cur.next 设置为下一个节点的下一个节点 lim.next,再使下一个节点的下一个节点 lim.next 指向头节点 head,将头节点设置为 lim 即可
1.2 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点
class Solution {
public ListNode middleNode(ListNode head) {
if(head==null||head.next==null){
return head;
}
ListNode fast=head;
ListNode slow=head;
while(fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
}
return slow;
}
}
解题思路如下:
先判断头节点是否为空或是否只含一个节点,定义两个指针:快指针 fast 和慢指针 slow,使用 while( fast!= null && fast.next != null )遍历链表,使快指针 fast 一次走两个节点,慢指针 slow 一次走一个节点,当快指针 fast 为空或其下一节点为空时,结束循环,此时 slow 所在位置即为中间节点
1.3 链表的回文结构
class Solution {
public boolean isPalindrome(ListNode head) {
if(head==null){
return true;
}
ListNode fast=head;
ListNode slow=head;
while(fast!=null&&fast.next!=null){
fast=fast.next.next;
slow=slow.next;
}
ListNode cur=slow;
while(cur.next!=null){
ListNode lim=cur.next;
cur.next=lim.next;
lim.next=slow;
slow=lim;
}
while(head!=slow){
if(head.val!=slow.val){
return false;
}
if(head.next==slow){
return true;
}
head=head.next;
slow=slow.next;
}
return true;
}
}
解题思路如下:
判断链表是否为空,如何和上题一样,找到中间节点,接着从中间节点出进行逆置,然后用while 遍历链表,当遍历的过程有不相等之处,即该链表不存在回文结构,否则存在回文结构
题目都解决完毕,若有不明白或错误之处,请大家在评论区提出,相信大家做完收获满满,第三题难道相对大啦点,但是和前两题联系紧密,接下来我们将介绍 LinkedList 的使用
二、LinkedList(双向)的使用
2.1 什么是LinkedList?
LinkedList 的官方文档https://docs.oracle.com/javase/8/docs/api/java/util/LinkedList.html LinkedList的底层是双向链表结构,由于链表没有将元素储存在连续的空间,而是储存在单独的节点中,用引用将各个节点连接起来,所以在任意位置插入或删除元素都比较方便。
2.2 LinkedList的使用
2.3 LinkedList的构造
三、简单的自我模拟 LinkedList 的实现
代码如下:(大家自行观看,我就不解释啦)
public class LinkedList implements IList{
static class ListNode{
private int val;
private ListNode prev;
private ListNode next;
public ListNode(int val) {
this.val = val;
}
}
private ListNode head;
private ListNode last;
public void addFirst(int data) {
ListNode node=new ListNode(data);
if(head==null){
head=last=node;
}else {
node.prev = null;
node.next = head;
head.prev = node;
head = node;
}
}
public void addLast(int data) {
ListNode node = new ListNode(data);
if (head == null) {
head = last = node;
}else {
last.next = node;
node.prev = last;
last=last.next;
}
}
private void checki(int index) throws Illegalindex{
if(index<0||index>size()){
throw new Illegalindex("输入的索引不合法!!!");
}
}
public void addIndex(int index, int data) throws Illegalindex{
try{
checki(index);
ListNode node=new ListNode(data);
if(index==0){
addFirst(data);
return;
}
if(index==size()){
addLast(data);
return;
}
ListNode cur=head;
while(index!=0){
cur=cur.next;
index--;
}
node.next=cur;
node.prev=cur.prev;
cur.prev.next=node;
cur.prev=node;
}catch(Illegalindex e){
System.out.println("增加的位置不合法!!!");
e.printStackTrace();;
}
}
public void remove(int key) {
ListNode cur = head;
while (cur != null) {
if (cur.val == key) {
if (cur == head) {
head = head.next;
if (head != null) {
head.prev = null;
}
} else {
cur.prev.next = cur.next;
if (cur.next == null) {
last = last.prev;
} else {
cur.next.prev = cur.prev;
}
}
return;
}
cur = cur.next;
}
}
public void removeAllKey(int key) {
ListNode cur = head;
while (cur != null) {
if (cur.val == key) {
if (cur == head) {
head = head.next;
if (head != null) {
head.prev = null;
}
} else {
cur.prev.next = cur.next;
if (cur.next == null) {
last = last.prev;
} else {
cur.next.prev = cur.prev;
}
}
}
cur = cur.next;
}
}
public int size() {
ListNode cur=head;
int len=0;
while(cur!=null){
len++;
cur=cur.next;
}
return len;
}
public void clear() {
ListNode cur=head;
while(cur!=null){
ListNode curn=cur.next;
cur.next=null;
cur.prev=null;
cur=curn;
}
head=last=null;
}
public boolean contains(int toFind) {
ListNode cur=head;
while(cur!=null){
if(cur.val==toFind){
return true;
}
}
return false;
}
public void display() {
ListNode cur=head;
for (int i = 0; i < size(); i++) {
System.out.print(cur.val+" ");
cur=cur.next;
}
System.out.println();
}
}
上述代码实现了 IList 接口,以及抛出了自定义异常,前面文章都有涉及并讲解。
四、ArrayList 和 LinkedList 的区别
ArrayList 和 LinkedList 是Java中的两种不同的集合实现方式。下面是它们之间的区别:
1. 内部实现:
ArrayList 是基于数组实现的,LinkedList是基于双向链表实现的。
2. 插入和删除操作的效率:
ArrayList 在尾部插入和删除元素的效率较高,时间复杂度为O(1),而在中间插入和删除元素的效率较低,因为需要移动其他元素,时间复杂度为O(n)。而 LinkedList 在任意位置插入和删除元素的效率都较高,时间复杂度为O(1)。
3. 随机访问的效率:
ArrayList 支持随机访问操作,即可以通过索引快速访问任意位置的元素,时间复杂度为O(1)。而 LinkedList 则不支持随机访问,需要从头或尾开始遍历链表,时间复杂度为O(n)。
4. 内存消耗:
ArrayList需要连续的内存空间来存储元素,所以在元素较多时可能会占用较大的内存空间。而LinkedList不需要连续的内存空间,它只需要为每个元素存储指向前后节点的引用,所以在元素较多时可能会占用较小的内存空间。
根据具体的使用场景,选择 ArrayList 还是 LinkedList 会有不同的优劣势。如果需要频繁的随机访问和对尾部的增删操作较多,可以选择 ArrayList;如果需要频繁的在任意位置插入和删除操作,可以选择 LinkedList。