篇章五 数据结构——链表(一)

目录

1.ArrayList的缺陷

2. 链表

2.1 链表的概念及结构

2.2 链表结构

1. 单向或者双向

2.带头或者不带头

3.循环或者非循环

2.3 链表的实现

1.完整代码

2.图解

 3.显示方法

4.链表大小

5. 链表是否存在 key 值

6.头插法

7.尾插法

8.中间插入

9.删除key值节点

 10.删除所有key值节点

11.clear

3.练习

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

3.2 反转一个单链表

3.3 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点

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

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

3.6 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前

​编辑

3.7 链表的回文结构

3.8 输入两个链表,找出它们的第一个公共结点

3.9 给定一个链表,判断链表中是否有环

3.10 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL


1.ArrayList的缺陷

通过篇章四,我们已经熟悉了ArrayList的使用,并且进行了简单模拟实现。通过源码知道,ArrayList底层使用数组来存储元素。

那这样会出现什么问题呢?

        由于其底层是一段连续空间,当在ArrayList任意位置插入或者删除元素时,就需要将后序元素整体往前或者往后搬移,时间复杂度为O(n),效率比较低。因此ArrayList不适合做任意位置插入和删除比较多的场景。因此:java集合中又引入了LinkedList,即链表结构。

2. 链表

2.1 链表的概念及结构

链表是一种 物理存储结构上非连续 存储结构,数据元素的 逻辑顺序 是通过链表中的 引用链接 次序实现的。

注意:
1.从上图可看出,链式结构在逻辑上是连续的,但是在物理上不一定连续
2.现实中的结点一般都是从堆上申请出来的
3.从堆上申请的空间,是按照一定的策略来分配的,两次申请的空间可能连续,也可能不连续

2.2 链表结构

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

1. 单向或者双向

什么是双向?

2.带头或者不带头

什么是带头?

什么是不带头?

3.循环或者非循环

什么是循环?

组合成的 8种链表结构

虽然有这么多的链表的结构,但是我们重点掌握两种:

1. 无头单向非循环链表结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结构的子结构,如哈希桶、图的邻接表等等。

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

2.3 链表的实现

1.完整代码


/*** Created with IntelliJ IDEA* Description  无头单向非循环链表实现* User: 王杰* Date: 2025-05-26* Time: 20:33*/
public class MySingleList implements IList{static class ListNode {public int val;public ListNode next;public ListNode(int val) {this.val = val;}}public ListNode head;// 创建链表public void createList() {ListNode node1 = new ListNode(12);ListNode node2 = new ListNode(23);ListNode node3 = new ListNode(34);ListNode node4 = new ListNode(45);ListNode node5 = new ListNode(56);node1.next = node2;node2.next = node3;node3.next = node4;node4.next = node5;this.head = node1;}// 显示方法@Overridepublic void display() {ListNode cur = head;while (cur != null) {System.out.print(cur.val + " ");cur = cur.next;}}// 链表大小@Overridepublic int size() {int len = 0;ListNode cur = head;while (cur != null) {len++;cur = cur.next;}return len;}// 链表是否存在 key 值@Overridepublic boolean contains(int key) {ListNode cur = head;while (cur != null) {if (cur.val == key) {return true;}cur = cur.next;}return false;}// 头插法@Overridepublic void addFirst(int data) {ListNode node = new ListNode(data);node.next = head;head = node;}// 尾插法@Overridepublic void addLast(int data) {ListNode node = new ListNode(data);// 一个节点都没有if (head == null) {head = node;return;}// 找尾巴ListNode cur = head;while (cur != null) {if (cur.next == null) {cur.next = node;return;}cur = cur.next;}}//中间插入@Overridepublic void addIndex(int index, int data) {int len = size();if (index < 0 || index > len) {System.out.println("index位置不存在");return;}if (index == 0) {addFirst(data);return;}if (index == len) {addLast(data);return;}// 中间插入ListNode cur = head;if (index - 1 != 0) {cur = cur.next;index--;}ListNode node = new ListNode(data);// 所有的插入 优先 绑定后边node.next = cur.next;cur.next = node;}// 删除 key值 节点@Overridepublic void remove(int key) {if (head == null) {return;}// 删除头节点if (head.val == key) {head = head.next;return;}ListNode cur = findNodeOfKey(key);if (cur == null) {return;}ListNode del = cur.next;cur.next = del.next;}private ListNode findNodeOfKey(int key) {ListNode cur = head;while (cur.next != null) {if (cur.next.val == key) {return cur;}cur = cur.next;}return null;}// 删除 所有key值 节点@Overridepublic 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;}}@Overridepublic void clear() {ListNode cur = head;while (cur != null) {ListNode curNext = cur.next;cur.next = null;cur = curNext;}head = null;}}

2.图解

单向不带头非循环链表:

 3.显示方法

// 显示方法
@Override
public void display() {ListNode cur = head;while (cur != null) {System.out.print(cur.val + " ");cur = cur.next;}
}

4.链表大小

	// 链表大小@Overridepublic int size() {int len = 0;ListNode cur = head;while (cur != null) {len++;cur = cur.next;}return len;}

实现到这里,我们需要掌握的是:

1.ListNode cur = head; 

        此处申请了临时变量,因为数据存储在堆空间,而且 cur 也指向链表,所以改变有效。同时 此处也是为了不改变 head 的位置,因为后续要用head找到该链表,如果head位置变动了,就找不到该链表了。

2.cur != null;

        此处最后一个节点,是会运算的。最后,cur指向的是最后一个节点的下一个节点,也就是 null;

3.cur.next != null;

        此处最后一个节点,是不会运算的。最后,cur指向的是最后一个节点。

5. 链表是否存在 key 值

    // 链表是否存在 key 值@Overridepublic boolean contains(int key) {ListNode cur = head;while (cur != null) {if (cur.val == key) {return true;}cur = cur.next;}return false;}

6.头插法

    // 头插法@Overridepublic void addFirst(int data) {ListNode node = new ListNode(data);node.next = head;head = node;}

7.尾插法

	// 尾插法@Overridepublic void addLast(int data) {ListNode node = new ListNode(data);// 一个节点都没有if (head == null) {head = node;return;}// 找尾巴ListNode cur = head;while (cur != null) {if (cur.next == null) {cur.next = node;return;}cur = cur.next;}}

8.中间插入

	//中间插入@Overridepublic void addIndex(int index, int data) {int len = size();if (index < 0 || index > len) {System.out.println("index位置不存在");return;}if (index == 0) {addFirst(data);return;}if (index == len) {addLast(data);}// 中间插入ListNode cur = head;if (index - 1 != 0) {cur = cur.next;index--;}ListNode node = new ListNode(data);// 所有的插入 优先 绑定后边node.next = cur.next;cur.next = node;}

注意:

1.此处中间插入,关键是找到 要 插入的位置前一个位置

2.要牢记 所有的插入 优先 绑定后边

9.删除key值节点

	// 删除 key值 节点@Overridepublic void remove(int key) {if (head == null) {return;}// 删除头节点if (head.val == key) {head = head.next;return;}ListNode cur = findNodeOfKey(key);if (cur == null) {return;}ListNode del = cur.next;cur.next = del.next;}private ListNode findNodeOfKey(int key) {ListNode cur = head;while (cur.next != null) {if (cur.next.val == key) {return cur;}cur = cur.next;}return null;}

注意:

        找到 要删除的节点 的前一个节点

这一思路在单链表中很关键

 10.删除所有key值节点

	// 删除 所有key值 节点@Overridepublic 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;}}

11.clear

    @Overridepublic void clear() {ListNode cur = head;while (cur != null) {ListNode curNext = cur.next;cur.next = null;cur = curNext;}head = null;}

注意:

         此处最后 head 也要置空

3.练习

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

203. 移除链表元素 - 力扣(LeetCode)

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {public ListNode removeElements(ListNode head, int val) {if (head == null) {return head;}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;}
}

203. 移除链表元素 - 力扣(LeetCode) 此处和 2.3 中的 10.删除所有key节点 一样

3.2 反转一个单链表

OJ链接

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {public ListNode reverseList(ListNode head) {if(head == 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;}
}

3.3 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点

OJ链接

  /*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/class Solution {public ListNode middleNode(ListNode head) {if(head == null) {return null;}ListNode fast = head;ListNode slow = head;while(fast != null && fast.next != null) {slow = slow.next;fast = fast.next.next;}     return slow;  }}

注意:

        做这些练习的时候,要考虑 空链表 的情况,也就是 head == null 

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

OJ链接

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {public int kthToLast(ListNode head, int k) {if(head == null) {return -1;}ListNode fast = head;ListNode slow = head;// fast 走 k - 1 步int count = 0;        while(count != k - 1) {fast = fast.next;count++;}while(fast.next != null) {slow = slow.next;fast = fast.next;}return slow.val;}
}

注意:

1. fast.next != null;

        此处 fast 走到最后一个节点即可,不必走到 null

2.此处 k 值,不确定是否合法,一般题目中会设置范围,但是没设置的话就需要补充上k值合法性的校验

补充:验证 k 的合法性

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {public int kthToLast(ListNode head, int k) {if(head == null) {return -1;}if(k <= 0) {return -1;}ListNode fast = head;ListNode slow = head;// fast 走 k - 1 步int count = 0;        while(count != k - 1) {fast = fast.next;if(fast == null) {return -1;}count++;}while(fast.next != null) {slow = slow.next;fast = fast.next;}return slow.val;}
}

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

OJ链接

  /*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/class Solution {public ListNode mergeTwoLists(ListNode list1, ListNode list2) {ListNode newHead = new ListNode();ListNode cur = newHead;while(list1 != null && list2 != null) {if(list1.val > list2.val) {cur.next = list2;list2 = list2.next;cur = cur.next;}else {cur.next = list1;list1 = list1.next;cur = cur.next;}}if(list1 != null) {cur.next = list1;}if(list2 != null) {cur.next = list2;}return newHead.next;}}

3.6 编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前

OJ链接

import java.util.*;/*
public class ListNode {int val;ListNode next = null;ListNode(int val) {this.val = val;}
}*/
public class Partition {public ListNode partition(ListNode pHead, int x) {ListNode cur = pHead;ListNode beforStart = null;ListNode beforEnd = null;ListNode afterStart = null;ListNode afterEnd = null;while(cur != null) {if(cur.val < x) {if(beforStart == null) {beforStart = cur;beforEnd = cur;}else {beforEnd.next = cur;beforEnd = beforEnd.next;}cur = cur.next;}else {if(afterStart == null) {afterStart = cur;afterEnd = cur;}else {afterEnd.next = cur;afterEnd = afterEnd.next;}cur = cur.next;}  }if(beforStart == null) {return afterStart;}// 置空 afterEnd.nextif(afterStart != null) {afterEnd.next = null;}beforEnd.next = afterStart;return beforStart;}
}

注意:

此处思路:是把 大于x 和 小于x 的值分为两个链表。

但是:注意特殊情况,比如大于x的链表为空 和 小于x的链表为空。

而且:要注意,在 小于x的链表不为空时, 置空 afterEnd.next

3.7 链表的回文结构

OJ链接

import java.util.*;/*
public class ListNode {int val;ListNode next = null;ListNode(int val) {this.val = val;}
}*/
public class PalindromeList {public boolean chkPalindrome(ListNode A) {if(A == null) {return true;}ListNode fast = A;ListNode slow = A;while(fast != null && fast.next != null) {fast = fast.next.next;slow = slow.next;}ListNode cur = slow.next;while(cur != null) {ListNode curNext = cur.next;cur.next = slow;slow = cur;cur =curNext;} while(A != slow) {if(A.val != slow.val) {return false;}// 偶数情况if(A.next == slow) {return true;}A = A.next;slow = slow.next;}return true;}
}

注意:

1.  三步走:找中间节点,反转中间节点后的链表,比较前半部分和后半部分链表的val值

2. 偶数情况:
            if(A.next == slow) {
                return true;
            }

3.8 输入两个链表,找出它们的第一个公共结点

OJ链接

/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode(int x) {*         val = x;*         next = null;*     }* }*/
public class Solution {public ListNode getIntersectionNode(ListNode headA, ListNode headB) {ListNode pLong = headA;ListNode pShort = headB;// 先求两个链表的长度int lenA = 0;int lenB = 0;while(pLong != null) {lenA++;pLong = pLong.next;}while(pShort != null) {lenB++;pShort = pShort.next;}pLong = headApShort = headB// 求差值int len = lenA - lenB;if(len < 0) {pLong = lenB;pShort = lenA;len = lenB - lenA;}// 走完上述两步 pLong 一定指向最长的链表  pShort 一定指向最短的链表// 接下来的操作 只需要操作 pLong 和 pShort 就行了// 让最长的链表走 len 步while(len != 0) {pLong = pLong.next;len--;}// 两个引用同时走 直到他们相遇while(pLong != pShort) {pLong = pLong.next;pShort = pShort.next;}if(pLong == null) {return null; // 不相交}return pLong;}
}

注意:

1.主要思路就是:走两个链表长度的差值步

2. 此处注意还原 pLong 和 pShort ,因为算长度,他们的位置发生了改变,要还原,否则影响下面代码

        pLong = headA
        pShort = headB

3.注意不相交的情况:

        if(pLong == null) {
            return null; // 不相交
        }

3.9 给定一个链表,判断链表中是否有环

OJ链接

/*** Definition for singly-linked list.* class ListNode {*     int val;*     ListNode next;*     ListNode(int x) {*         val = x;*         next = null;*     }* }*/
public class Solution {public boolean hasCycle(ListNode head) {if(head == null) {return false;}if(head.next == null) {return false;}ListNode fast = head;ListNode slow = head;while(fast != null && fast.next != null) {fast = fast.next.next;slow = slow.next;if(fast == slow) {return true;}}return false;}
}

【思路】

        快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表起始位置开始运行,如果链表带环则一定会在环中相遇,否则快指针率先走到链表的末尾。比如:陪女朋友到操作跑步减肥。

【扩展问题】

  • 为什么快指针每次走两步,慢指针走一步可以?

    假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。当慢指针刚进环时,可能就和快

    指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。此时,两个指针每移动一次,之间的距离就缩小一步,不会出现每次刚好是套圈的情况,因此:在慢指针走到一圈之前,快指针肯定是可以追上慢指针的,即相遇。

  • 快指针一次走3步,走4步,...n步行吗?

 注意:

1.链表为空,和只有一个节点的情况是不存在环的

        if(head == null) {
            return false;
        }

        if(head.next == null) {
            return false;
        }

2.快慢指针的步数问题:

        快 2 慢 2:会相遇

        快3 慢 1 :永不相遇

可见:并不是快指针比慢指针快就行,还得注意步数问题。

3.10 给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL

OJ链接

/*** Definition for singly-linked list.* class ListNode {*     int val;*     ListNode next;*     ListNode(int x) {*         val = x;*         next = null;*     }* }*/
public class Solution {public ListNode detectCycle(ListNode head) {ListNode fast = head;ListNode slow = head;if(head == null) {return null;}if(head.next == null) {return null;}while(fast != null && fast.next != null) {fast = fast.next.next;slow = slow.next;if(fast == slow) {break;}}if(fast == null || fast.next == null) {return null; // 没有环}slow = head;while(slow != fast) {fast = fast.next;slow = slow.next;}return slow;}
}

【结论】

        让一个指针从链表起始位置开始遍历链表,同时让一个指针从判环时相遇点的位置开始绕环运行,两个指针都是每次均走一步,最终肯定会在入口点的位置相遇。

【证明】

 注意:

1.链表为空,和只有一个节点的情况是不存在环的

        if(head == null) {
            return false;
        }

        if(head.next == null) {
            return false;
        }

2.相遇时出循环:

        while(fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow) {
                break;
            }
        }

3.去除没有环的情况:

        if(fast == null || fast.next == null) {
            return null; // 没有环
        }

4.关键:让慢指针回到链表开头,然后慢指针与快指针以相同的速度走

        slow = head;
        while(slow != fast) {
            fast = fast.next;
            slow = slow.next;
        }

5.证明:此处最关键的是,fast的路程是slow路程的二倍,建立等式,计算,取极端情况 得出关系,写代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/news/907273.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据库相关面试

数据库相关面试 Mysql MySQL中的事务隔离级别及其特点 参考&#xff1a;事务的隔离级别&#xff1a;可重复读 未提交读(Read Uncommitted)&#xff1a;允许脏读&#xff0c;也就是可能读取到其他会话中未提交事务修改的数据 已提交读(Read Committed)&#xff1a;只能读取到…

基于Scrapy的天猫商品数据爬取与分析实战(含API签名破解与可视化)

基于Scrapy的天猫商品数据爬取与分析实战&#xff08;含API签名破解与可视化&#xff09; 本文以华为Mate 60 Pro为例&#xff0c;详细介绍如何使用Scrapy框架爬取天猫商品数据&#xff0c;涵盖API签名破解、反爬应对、数据存储及可视化全流程&#xff0c;适合爬虫进阶学习者实…

【C++进阶篇】哈希表的模拟实现(赋源码)

这里写目录标题 前言一. 开放地址法实现哈希表1.1 闭散列结构定义1.2 构造函数1.3 插入&#xff08;线性探测&#xff09;1.3.1 传统写法1.3.2 现代写法 1.4 查找1.5 删除 二. 链地址法实现哈希表&#xff08;哈希桶&#xff09;2.1 开散列结构定义2.2 构造函数2.3 插入2.4 查找…

07-后端Web实战(部门管理)

5. 修改部门 对于任何业务的修改功能来说&#xff0c;一般都会分为两步进行&#xff1a;查询回显、修改数据。 5.1 查询回显 5.1.1 需求 当我们点击 "编辑" 的时候&#xff0c;需要根据ID查询部门数据&#xff0c;然后用于页面回显展示。 5.1.2 接口描述 参照参照…

深度解析项目集方向或目标根本性转变的应对策略 —— 项目集管理实战指南

在复杂多变的商业环境中&#xff0c;项目集管理面临着重重挑战&#xff0c;而项目集方向或目标的根本性转变无疑是其中最具冲击力的问题之一。本文将深度剖析这一难题&#xff0c;为项目集管理从业者提供实用、新颖且富有价值的应对策略&#xff0c;助力大家在项目集管理的复杂…

JAVA面试复习知识点

面试中遇到的题目&#xff0c;记录复习&#xff08;持续更新&#xff09; Java基础 1.String的最大长度 https://www.cnblogs.com/wupeixuan/p/12187756.html 2.集合 Collection接口的实现&#xff1a; List接口&#xff1a;ArraryList、LinkedList、Vector Set接口&#xff1a…

【烧脑算法】定长滑动窗口:算法题中的“窗口”智慧

目录 引言 定长滑动窗口习题剖析 3439. 重新安排会议得到最多空余时间 I 2134. 最少交换次数来组合所有的 1 II 1297. 子串的最大出现次数 2653. 滑动子数组的美丽值 567. 字符串的排列 438. 找到字符串中所有字母异位词 30. 串联所有单词的子串 220. 存在重复元素 II…

JWT安全:接收无签名令牌.【签名算法设置为none绕过验证】

JWT安全&#xff1a;假密钥【签名随便写实现越权绕过.】 JSON Web 令牌 (JWT)是一种在系统之间发送加密签名 JSON 数据的标准化格式。理论上&#xff0c;它们可以包含任何类型的数据&#xff0c;但最常用于在身份验证、会话处理和访问控制机制中发送有关用户的信息(“声明”)。…

XGBoost与SHAP深度解析:从算法原理到实战价值

在机器学习领域&#xff0c;XGBoost以其卓越的性能长期占据Kaggle竞赛和工业界的主流地位&#xff0c;而SHAP&#xff08;SHapley Additive exPlanations&#xff09;则成为模型可解释性的标杆工具。本文将深度解析两者的技术内核&#xff0c;并通过实战案例揭示其结合应用的实…

Java SE Cloneable接口和深/浅拷贝

Java为我们提供了各种各样功能的接口&#xff0c;Clonable接口就是其中之一。 它通常配合Object类的 clone方法使用。这个方法可以为我们创建一个对象的拷贝&#xff0c;即复制一个对象。在进入本文的主要内容之前&#xff0c;先来对访问限定符 protected进行一个解剖。 1.再…

Python学习(3) ----- Python的函数定义及其使用

Python 中函数是组织好的、可重复使用的代码块&#xff0c;用于实现单一或相关联的功能。下面是函数定义和使用的完整说明&#xff1a; &#x1f4cc; 一、函数定义语法 def 函数名(参数1, 参数2默认值, *args, **kwargs):"""函数说明文档"""函…

vue2使用el-tree实现两棵树间节点的拖拽复制

原文链接&#xff1a;两棵el-tree的节点跨树拖拽实现 参照这篇文章&#xff0c;把它做成组件&#xff0c;新增左侧树&#xff08;可拖出&#xff09;被拖节点变灰提示&#xff1b; 拖拽中&#xff1a; 拖拽后&#xff1a; TreeDragComponent.vue <template><!-- …

智变与重构:AI 赋能基础教育教学的范式转型研究报告

一、研究背景与核心价值 &#xff08;一&#xff09;技术驱动下的教育转型浪潮 在全球数字化转型加速的背景下&#xff0c;人工智能作为核心技术力量&#xff0c;正重塑基础教育生态。据《人工智能赋能未来教育研究报告》指出&#xff0c;我国教育数字化战略行动已推动超 70…

Go语言中Print、Printf和Println的区别及使用场景详解

在Go语言的fmt包中&#xff0c;Print、Printf和Println是三个基础但功能各异的输出函数。本文将从多个维度进行详细对比分析&#xff0c;并给出具体的使用建议。 1. 核心区别深度解析 1.1. 函数签名与基本行为 func Print(a ...interface{}) (n int, err error) func Printf…

高端制造行业 VMware 替代案例合集:10+ 头部新能源、汽车、半导体制造商以国产虚拟化支持 MES、PLM 等核心应用系统

在“中国制造 2025”政策的推动下&#xff0c;国内的新能源、汽车制造、半导体、高端装备等高端制造产业迎来了蓬勃发展&#xff0c;成为全球制造业版图中举足轻重的力量。订单数量的激增与国产化转型的趋势&#xff0c;也为高端制造企业的 IT 基础设施带来了新的挑战&#xff…

Spring Ai | 从零带你一起走进AI项目(中英)

目录 Thinking Study question pox.xml Maven Gradle Configure API Key Use the AI Client Question Thinking 让数据变得更加贴近用户的想法 Study question null pox.xml 添加依赖 Maven <dependencies><dependency><groupId>org.springfram…

LiveGBS作为下级平台GB28181国标级联2016|2022对接海康大华宇视华为政务公安内网等GB28181国标平台查看级联状态及会话

LiveGBS作为下级平台GB28181国标级联2016|2022对接海康大华宇视华为政务公安内网等GB28181国标平台查看级联状态及会话 1、GB/T28181级联概述2、搭建GB28181国标流媒体平台3、获取上级平台接入信息3.1、向下级提供信息3.2、上级国标平台添加下级域3.3、接入LiveGBS示例 4、配置…

卸载 Office PLUS

Office PLUS作为微软官方推出的智能办公提效工具&#xff0c;自2015年问世以来&#xff0c;凭借其丰富的模板资源和便捷的智能功能&#xff0c;迅速赢得了广大职场人士和学生的青睐。本文将全面介绍Office PLUS的发展历程、核心功能、可能带来的使用问题&#xff0c;以及如何彻…

影响沉金价格的因素如何体现在多层电路板制造上?

随着科技的不断发展&#xff0c;电子产品越来越普及&#xff0c;对电路板的需求也越来越大。多层电路板作为电子产品的核心部件&#xff0c;其性能和质量直接影响到整个产品的稳定性和可靠性。在多层电路板的生产过程中&#xff0c;沉金工艺是一种常用的表面处理方法&#xff0…

扩展摩尔投票法:找出出现次数超过 n/3 的元素

文章目录 问题描述关键洞察算法原理Java 实现算法演示投票阶段验证阶段 复杂度分析算法关键点通用化公式实际应用场景边界情况处理总结 标签&#xff1a;LeetCode 169, 摩尔投票法, 多数元素, 算法扩展, 数组处理 在解决多数元素问题时&#xff0c;我们学习了经典的摩尔投票法处…