目录
3.2删除元素
1.链表环的问题
public boolean hasCycle(ListNode head) {
// 创建一个指针pos,初始指向头节点
ListNode pos = head;
// 创建一个集合visited,用于存储已经访问过的节点
Set<ListNode> visited = new HashSet<ListNode>();
// 遍历链表
while (pos != null) {
// 如果当前节点已经在visited集合中,则说明存在环,返回true
if (visited.contains(pos)) {
return true;
} else {
// 否则将当前节点加入visited集合中
visited.add(pos);
}
// 指针后移
pos = pos.next;
}
// 如果遍历完整个链表都没有发现环,则返回false
return false;
}
1.1链表环的问题——Leetcode141
https://leetcode.cn/problems/linked-list-cycle/description/
public boolean hasCycle(ListNode head) {
// 创建一个集合visited,用于存储已经访问过的节点
Set<ListNode> visited = new HashSet<ListNode>();
// 遍历链表
while (head != null) {
// 如果当前节点已经在visited集合中,则说明存在环,返回true
if (!visited.add(head)) {
return true;
} else {
// 否则将当前节点加入visited集合中
visited.add(head);
}
// 指针后移
head = head.next;
}
// 如果遍历完整个链表都没有发现环,则返回false
return false;
}
1.1链表环的问题——Leetcode142
https://leetcode.cn/problems/linked-list-cycle-ii/description/
public ListNode detectCycle(ListNode head) {
// 快慢指针初始指向头节点
ListNode fast = head, slow = head;
// 遍历链表,寻找环的起始节点
while (true) {
// 如果快指针或者快指针的下一个节点为空,说明不存在环,返回null
if (fast == null || fast.next == null) {
return null;
}
// 快指针每次移动两步,慢指针每次移动一步
fast = fast.next.next;
slow = slow.next;
// 如果快指针和慢指针相遇,说明存在环,跳出循环
if (fast == slow) {
break;
}
}
// 将快指针重新指向头节点
fast = head;
// 两个指针相遇的节点即为环的起始节点
while (slow != fast) {
slow = slow.next;
fast = fast.next;
}
// 返回环的起始节点
return fast;
}
2.双向链表的问题
//创建双链表结点
class DoubleNode {
public int data; // 数据域,用于存储结点的数据
public DoubleNode next; // 指向下一个结点的引用
public DoubleNode prev; // 指向上一个结点的引用
public DoubleNode(int data) {
this.data = data; // 构造方法,初始化结点的数据域
}
// 打印结点的数据域
public void displayNode() {
System.out.print("{" + data + "} "); // 输出结点的数据域内容
}
}
双向链表的结构和遍历
public class DoublyLinkList {
private DoubleNode first; // 链表的头节点
private DoubleNode last; // 链表的尾节点
public DoublyLinkList() {
first = null; // 初始化时,链表为空,头节点和尾节点均为null
last = first;
}
/**
* 从头部开始遍历并打印链表中的节点
*/
public void displayForward() {
System.out.print("List(first--->last): ");
DoubleNode current = first; // 从头节点开始遍历
while (current != null) {
current.displayNode(); // 调用节点的displayNode()方法打印节点信息
current = current.next; // 移动到下一个节点
}
System.out.println();
}
/**
* 从尾部开始遍历并打印链表中的节点
*/
public void displayBackward() {
System.out.print("List(last--->first): ");
DoubleNode current = last; // 从尾节点开始遍历
while (current != null) {
current.displayNode(); // 调用节点的displayNode()方法打印节点信息
current = current.prev; // 移动到上一个节点
}
System.out.println();
}
}
3.1插入状态
// 在链表头部插入一个节点
public void insertFirst(int data) {
DoubleNode newDoubleNode = new DoubleNode(data);
if (isEmpty()) { // 如果链表为空,新节点既是第一个节点,也是最后一个节点
last = newDoubleNode;
} else { // 如果链表不为空,则将原来的第一个节点的prev指针指向新节点
first.prev = newDoubleNode;
}
newDoubleNode.next = first; // 新节点的next指针指向原来的第一个节点
first = newDoubleNode; // 将新节点赋给first成为第一个节点
}
// 在链表尾部插入一个节点
public void insertLast(int data) {
DoubleNode newDoubleNode = new DoubleNode(data);
if (isEmpty()) { // 如果链表为空,新节点既是第一个节点,也是最后一个节点
first = newDoubleNode;
} else { // 如果链表不为空,则将原来的最后一个节点的next指针指向新节点
last.next = newDoubleNode;
newDoubleNode.prev = last; // 新节点的prev指针指向原来的最后一个节点
}
last = newDoubleNode; // 将新节点赋给last成为最后一个节点
}
// 在某个节点后面插入一个节点
public void insertAfter(int key, int data) {
DoubleNode newDoubleNode = new DoubleNode(data);
DoubleNode current = first;
// 遍历链表,找到要插入节点的位置
while ((current != null) && (current.data != key)) {
current = current.next;
}
if (current == null) { // 如果链表为空或未找到key值,则在链表末尾插入新节点
if (isEmpty()) { // 如果链表为空,则新节点既是第一个节点,也是最后一个节点
first = newDoubleNode;
last = newDoubleNode;
} else { // 如果链表不为空,则在链表末尾插入新节点
last.next = newDoubleNode;
newDoubleNode.prev = last;
last = newDoubleNode;
}
} else { // 如果找到了key值,则在该节点后面插入新节点
if (current == last) { // 如果key值是最后一个节点,则将新节点插入链表末尾
newDoubleNode.next = null;
last = newDoubleNode;
} else { // 如果key值不是最后一个节点,则将新节点插入当前节点和下一个节点之间
newDoubleNode.next = current.next;
current.next.prev = newDoubleNode;
}
current.next = newDoubleNode;
newDoubleNode.prev = current;
}
}
3.2删除元素
// 检查链表是否为空
public boolean isEmpty() {
return (first == null);
}
// 从头部删除结点
public DoubleNode deleteFirst() {
DoubleNode temp = first;
if (first.next == null) { // 如果链表只有一个节点,删除后链表为空,将last指向null
last = null;
} else { // 如果链表有两个(包括两个)以上的节点,则将第二个节点的prev指针指向null
first.next.prev = null;
}
first = first.next; // 将第二个节点赋给first成为第一个节点
return temp; // 返回删除的节点
}
// 从尾部删除结点
public DoubleNode deleteLast() {
DoubleNode temp = last;
if (first.next == null) { // 如果链表只有一个节点,则删除后为空链表,将first指向null
first = null;
} else { // 如果链表有两个(包括两个)以上的节点,则将倒数第二个节点的next指针指向null
last.prev.next = null;
}
last = last.prev; // 将倒数第二个节点赋给last成为最后一个节点
return temp; // 返回删除的节点
}
// 按值删除
public DoubleNode deleteKey(int key) {
DoubleNode current = first;
// 遍历链表,找到要删除节点的位置
while (current != null && current.data != key) {
current = current.next;
}
if (current == null) { // 如果当前节点为空,则返回null,说明链表中没有要删除的节点
return null;
} else {
if (current == first) { // 如果要删除的节点是第一个节点
first = current.next; // 将第二个节点赋给first成为第一个节点
current.next.prev = null; // 将第二个节点的prev指针指向null
} else if (current == last) { // 如果要删除的节点是最后一个节点
last = current.prev; // 将倒数第二个节点赋给last成为最后一个节点
current.prev.next = null; // 将倒数第二个节点的next指针指向null
} else { // 如果要删除的节点不是第一个节点也不是最后一个节点
current.prev.next = current.next; // 将当前节点的上一个节点的next指针指向当前节点的下一个节点
current.next.prev = current.prev; // 将当前节点的下一个节点的prev指针指向当前节点的上一个节点
}
}
return current; // 返回删除的节点
}