解剖—单链表相关OJ练习题

news2024/11/16 15:40:59

目录

一、移除链表元素

二、找出链表的中间节点 

三、合并两个有序链表

四、反转链表

五、求链表中倒数第k个结点

六、链表分割

七、链表的回文结构

八、判断链表是否相交  

九、判断链表中是否有环(一)

十、 判断链表中是否有环(二)


注:第六题和第七题牛客没有C环境,我在C++环境下用C语言写这道题(目前还没学C++,请大佬们理解一下,理解万岁!!) 

一、移除链表元素

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

  • 给你一个链表的头节点 head 和一个整数 val 
  • 请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

示例 1:

输入:head = [1, 2, 6, 3, 4, 5, 6], val = 6
输出:[1, 2, 3, 4, 5]
struct ListNode* removeElements(struct ListNode* head, int val) {
    struct ListNode* prev = NULL, * cur = head;
    while (cur) {        
        if (cur->val == val) {
            if (prev) {
                prev->next = cur->next;
                free(cur);
                cur = prev->next;
            }
            else {
                cur = head->next;
                free(head);
                head = cur;
            }
        }
        else {
            prev = cur;
            cur = cur->next;
        }
    }
    return head;
}

思路:链表常规删除,注意删除头节点的情况。

1、创建指向当前节点的前一个节点的指针prev=NULL(头节点的前一个节点为空),指针cur指向链表头节点。

2、以当前节点cur不为空为循环执行条件,判断当前节点的值是否等于val,等于则进行删除,不等于则prev更新为当前节点cur,当前节点cur指向下一个节点。

3、当前节点的值等于val时:

  • 如果值为 val 的节点不在头节点(prev 不为 NULL),将 prev 的 next 指针指向当前节点的下一个节点,然后释放当前节点并更新。
  • 如果值为 val 的节点在链表头节点(prev 为 NULL),则释放原来的头节点,将 head 更新为当前节点的下一个节点。

下面是第二种方法,创建新的链表,把不删除的节点链接到新链表 :

struct ListNode* removeElements(struct ListNode* head, int val) {
    struct ListNode* cur = head;        // 当前遍历节点
    struct ListNode* newhead = NULL;    // 新链表的头节点
    struct ListNode* tail = NULL;      // 新链表的尾节点

    while (cur) {
        if (cur->val != val) { // 当前节点的值不等于要删除的值
            if (tail == NULL) { // 第一次插入
                newhead = tail = cur; // 设置新链表的头和尾
            }
            else {
                tail->next = cur; // 将当前节点连接到新链表的尾部
                tail = tail->next; // 更新新链表的尾节点
            }
            cur = cur->next;     // 移动到下一个节点
            tail->next = NULL;  // 断开新链表的尾节点连接
        }
        else {
            struct ListNode* del = cur; // 保存需要删除的节点
            cur = cur->next;           // 移动到下一个节点
            free(del);                // 释放需要删除的节点的内存
        }
    }

    return newhead; // 返回新链表的头节点,已移除所有值为 val 的节点
}

二、找出链表的中间节点 

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

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

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

示例 1:

输入:head = [1,2,3,4,5]
输出:[3,4,5]
解释:链表只有一个中间结点,值为 3 。

struct ListNode* middleNode(struct ListNode* head) {
    struct ListNode* fast = head, * slow = head;
    while (fast && fast->next) {
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow;
}

 思路:快慢双指针

1、采用速度为1步的slow和速度为2步的fast,这样设置二者速度比较合理。

2、循环结束的条件需要考虑一下,分为链表节点个数为奇数和偶数,当fast走到最后的结果如下:

3、 所以循环结束的条件为 fast && fast->next 二者有一个为空。

三、合并两个有序链表

21. 合并两个有序链表

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

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    if (list1 == NULL)
        return list2;
    if (list2 == NULL)
        return list1;

    struct ListNode* tail = NULL, * head = NULL;

    while (list1 && list2) {
        if (list1->val < list2->val) {
            if (tail == NULL) {
                head = tail = list1;
            }
            else {
                tail->next = list1;
                tail = tail->next;
            }
            list1 = list1->next;
        }

        else {
            if (tail == NULL) {
                head = tail = list2;
            }
            else {
                tail->next = list2;
                tail = tail->next;
            }
            list2 = list2->next;
        }
    }
    if (list1)
        tail->next = list1;
    if (list2)
        tail->next = list2;
    return head;
}

思路:创建新链表,较小的进行链接。

好像跟顺序表的题相像合并两个有序数组

不过,这次是单链表,所以我们可以创建新链表,从前向后将较小的链接到链表中,不需要从后先前了。

1、首先判断是否有链表为空,一个链表为空,则直接返回合并后的结果:另一个不为空的链表,都为空则返回任意一个链表。

2、创建新链表的尾节点tail和头节点head,初始化为空。

3、比较 list1 和 list2 当前节点的值。

  • 如果 list1 的当前节点值小于 list2 的当前节点值,将 list1 的节点添加到合并后的链表中。
  • 如果 list2 的当前节点值小于等于 list1 的当前节点值,将 list2 的节点添加到合并后的链表中。

4、在向合并链表中添加节点时,需要检查 tail 是否为 NULL,

  • 如果是,说明这是第一个节点,因此同时更新 head 和 tail。
  • 否则,只需将新节点连接到 tail 的 next 并将 tail 更新为新节点。

5、每次添加节点后,对应的链表list需要向后移动一位。

6、最终循环结束时,如果有链表不为空,证明该链表剩余节点的值均大于另一个链表的最大值,则将该链表其余的节点依次插入新链表。

7、返回新链表头节点head。

四、反转链表

206. 反转链表

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

示例 1:

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
struct ListNode* reverseList(struct ListNode* head) {
    struct ListNode* cur = head;
    struct ListNode* rhead = NULL;
    while (cur) {
        struct ListNode* next = cur->next;
        cur->next = rhead;
        rhead = cur;
        cur = next;
    }
    return rhead;
}

思路(一): 创建新链表,从前向后取出原链表的节点进行头插。

1. 开始时,定义两个指针 `cur` 和 `rhead`。

  • `cur` 指向原始链表的头部 `head`
  • `rhead` 用来构建反转后的链表,初始为空,表示反转后链表的尾部。

2. 进入循环,这个循环将遍历整个链表并进行反转操作。循环的条件是 `cur` 不为 NULL,表示还有节点需要处理。

3. 在循环内部,首先创建一个临时指针 `next` 来保存 `cur` 的下一个节点,因为在修改 `cur->next` 指针之前,需要先保存下一个节点的信息,否则会丢失对它的引用。

4. 接着,将 `cur->next` 指向 `rhead`,这一步实际上是将 `cur` 的下一个节点指向反转后链表的头部,从而将 `cur` 从原链表中分离出来。

5. 更新 `rhead` 为 `cur`,这一步将 `cur` 成为反转后链表的新头部。

6. 更新 `cur` 为 `next`,这一步将 `cur` 移动到原链表中的下一个节点,准备处理下一个节点。

7. 循环继续执行,直到 `cur` 变为 NULL,表示已经遍历完整个链表。此时,`rhead` 指向反转后链表的头部。

8. 返回 `rhead`,它现在指向反转后的链表的头部,完成链表的反转。

struct ListNode* reverseList(struct ListNode* head) {
    if (head == NULL)
        return NULL;
    struct ListNode* n1 = NULL;
    struct ListNode* n2 = head;
    struct ListNode* n3 = n2->next;
    while (n2) {
        n2->next = n1;
        n1 = n2;
        n2 = n3;
        if (n3)
            n3 = n3->next;
    }
    return n1;
}

 思路(二):调转链表方向(三指针)

  • n1 初始化为 NULL,表示反转后的链表的尾部。
  • n2 初始化为链表的头部节点 head
  • n3 初始化为 n2 的下一个节点,即 n2->next

1、进入循环,这个循环将遍历整个链表并反转节点。

2、在循环内部,首先将 n2 的 next 指针指向 n1,这是为了将 n2 的指针方向反转,将其指向前一个节点 n1,而不是原来的下一个节点。

3、接着更新 n1 和 n2,将它们分别向前移动一个节点。n1 移动到 n2 的位置,n2 移动到 n3 的位置。

4、继续检查 n3 是否为 NULL。如果 n3 不为 NULL,将 n3 移动到它的下一个节点,以便在下一轮循环中使用。

5、循环继续执行,直到 n2 为 NULL,表示已经遍历完整个链表。此时,n1 指向原链表的最后一个节点,它成为了反转后链表的头部。

6、返回 n1,它现在指向反转后的链表的头部,完成了链表的反转。

五、求链表中倒数第k个结点

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

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

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
    struct ListNode* slow=pListHead,*fast=pListHead;
    int n=0;
    while(k){
        if(fast==NULL)
            return 0;
        fast=fast->next;
        k--;
    }

    while(fast){
        slow=slow->next;
        fast=fast->next;
    }
    return slow;
}

思路: 快慢指针

快慢指针的速度都为1步,快指针先走k步,然后慢指针开始与快指针同时走,快指针走到最后为空时,慢指针则为倒数第k个节点。

1、通过while循环先让fast走k步,如果fast为空则无法求出倒数第k个节点(k大于链表长度)返回值为0。

2、第二个while循环slow和fast开始同时向后走,fast为空时,slow指向的节点即为所求倒数第k个节点。

六、链表分割

链表的回文结构_牛客题霸_牛客网 (nowcoder.com)

现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。

class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        struct ListNode* lesshead, * lesstail, * greaterhead, * greatertail;

        lesshead = lesstail = (struct ListNode*)malloc(sizeof(struct ListNode));
        greaterhead = greatertail = (struct ListNode*)malloc(sizeof(struct ListNode));

        struct ListNode* cur = pHead;
        while (cur) {
            if (cur->val < x) {
                lesstail->next = cur;
                lesstail = lesstail->next;
            }
            else {
                greatertail->next = cur;
                greatertail = greatertail->next;
            }
            cur = cur->next;
        }

        lesstail->next = greaterhead->next;
        greatertail->next = NULL;
        pHead = lesshead->next;

        free(lesshead);
        free(greaterhead);

        return pHead;
    }
};

 思路:假设x=5,链表各节点值为如下图:

1、创建变量* lesshead, * lesstail为小于x的链表的头节点和尾节点,

         * greaterhead, * greatertail 为大于x的链表的头节点和尾节点。

  •     为两个新链表头节点开辟空间,储存值val和指向下一个节点next。

2、在循环中判断cur的值是否小于x,小于则将cur链接到less链表,不小于则链接到grearter链表。

3、两个新链表需要链接合并成完整链表。

4、greatertail->next = NULL;

  • 这一步一定不能少,否则可以会出现循环链表:

七、链表的回文结构

链表的回文结构_牛客题霸_牛客网 (nowcoder.com)

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。

给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。

测试样例:

  • 1->2->2->1
  • 返回:true
    
class PalindromeList {
public:
    struct ListNode* middleNode(struct ListNode* head){
        struct ListNode* slow=head;
        struct ListNode* fast=head;
        while(fast&&fast->next){
            fast=fast->next->next;
            slow=slow->next;
        }
        return slow;
    }
    struct ListNode* reverseList(struct ListNode* head){
        struct ListNode* cur=head,*rhead=NULL;
        while(cur){
            struct ListNode* next=cur->next;
            cur->next=rhead;
            rhead=cur;
            cur=next;
        }
        return rhead;
    }
    bool chkPalindrome(ListNode* head) {
        struct ListNode* mid=middleNode(head);
        struct ListNode* rmid=reverseList(mid);
        while(rmid){
            if(rmid->val==head->val){
                rmid=rmid->next;
                head=head->next;
            }
            else{
                return false;
            }
        }
        return true;
    }
};

思路:从中间点开始逆置, 

八、判断链表是否相交  

160. 相交链表

给你两个单链表的头节点 headA 和 headB 

  • 请你找出并返回两个单链表相交的节点。
  • 如果两个链表不存在相交节点,返回 null 。

图示两个链表在节点 c1 开始相交

  • 题目数据 保证 整个链式结构中不存在环。
  • 注意,函数返回结果后,链表必须 保持其原始结构 。
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode * tailA=headA;
    struct ListNode * tailB=headB;
    int lenA=1,lenB=1;
    while(tailA->next){
        tailA=tailA->next;
        lenA++;
    }
    while(tailB->next){
        tailB=tailB->next;
        lenB++;
    }
    if(tailA!=tailB){
        return NULL;
    }
    int gap=abs(lenA-lenB);
    struct ListNode * longList=headA;
    struct ListNode * shortList=headB;
    if(lenA<lenB){
        longList=headB;
        shortList=headA;
    }
    while(gap--){
        longList=longList->next;
    }
    while(longList!=shortList){
        longList=longList->next;
        shortList=shortList->next;
    }
    return longList;
}

 思路:长的链表走相差长度步数,然后短的开始和长的同时走,节点地址相等则相交。

1、定义变量 tailA 和 tailB 分别指向链表A和B的头节点,分别遍历对应链表获得链表长度lenA和lenB,因为while循环结束条件是tail->next为空,所以len的值初始化为1。

2、通过比较 tailA 和 tailB 是否相等来判断两个链表的尾节点是否一致。如果不相等,说明两个链表不可能有公共节点,直接返回 NULL。

 

3、使用abs函数求出链表A与B长度差值,差值赋值给变量gap。 

4、 创建两个指针longlist和shortlist分别指向链表A和B的头节点,然后判断链表大小,如果lenA大于lenB,则 longList=headB,否则 shortList=headA。

5、 longlist先向后走gap步,为了保持和shortlist同步遍历。

​ 

6、longlist和shortlist同时向后遍历,当二者相等时,停止遍历返回二者任意一个即为两个单链表相交的起始节点。

 

九、判断链表中是否有环(一)

141. 环形链表

给你一个链表的头节点 head ,判断链表中是否有环。

注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

  • 如果链表中存在环 ,则返回 true 。 否则,返回 false 。

  • 示例 1:

    输入:head = [3,2,0,-4], pos = 1
    输出:true
    解释:链表中有一个环,其尾部连接到第二个节点。

bool hasCycle(struct ListNode *head) {
    struct ListNode *fast=head;
    struct ListNode *slow=head;
    while(fast&&fast->next){
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow)
            return true;
    }
    return false;
}

思路:快慢指针 

指针slow一次走一步,指针fast一次走两步,这样在链表中走,如果有环存在则二者一定会相遇,因为fast是slow速度的两倍。如果fast走到最后为空,证明该链表没有环存在。

当fast步数

十、 判断链表中是否有环(二)

142. 环形链表 II

给定一个链表的头节点  head 

  • 返回链表开始入环的第一个节点。 

  • 如果链表无环,则返回 null

  • 不允许修改 链表。

  • 示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

struct ListNode* detectCycle(struct ListNode* head) {
    struct ListNode* fast = head;
    struct ListNode* slow = head;
    while (fast && fast->next) {
        slow = slow->next;
        fast = fast->next->next;
        if (fast == slow) {
            struct ListNode* meet = slow;
            while (head != meet) {
                head = head->next;
                meet = meet->next;
            }
            return meet;
        }
    }
    return NULL;
}

思路:快慢指针

  • slow一次走一步,fast一次走两步,他们都从头节点head位置开始移动。

  • 设head到入环节点的距离为L,假设第一次相遇位置为meet,入环节点到meet的距离为X,相遇位置到入环节点的距离为环的周长C减去X。

  • slow走的路程:L+X

  • fast走的路程: L+X+n*C(slow进环前,fast走了n圈,比如:环很小则fast可能走了好几圈slow才进环)。

  • 因为fast的速度是slow的两倍,所以fast走的路程是slow的两倍,一圈之内fast一定追上slow!!

  • 由此可以得到以下关系式:2(L+X)=L+X+n*C

  • 化简得到:L=n*C-X 即 L=(n-1)C+C-X,

  • 这样就知道了 L=C-X,即一个指针从相遇点开始走,一个指针从头节点开始走,他们会在入环点相遇。

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

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

相关文章

三网话费余额查询的API系统 基于thinkphp6.0框架

本套系统是用thinkphp6.0框架开发的&#xff0c;PHP需大于8.2&#xff0c;系统支持用户中心在线查询和通过API接口对接发起查询&#xff0c;用户余额充值是对接usdt接口&#xff0c;源码全开源&#xff0c;支持懂技术的人二次开发~搭建教程1、源码上传后&#xff0c;吧运行目录…

异常数据检测 | Python基于Hampel的离群点检测

文章目录 文章概述模型描述源码分享文章概述 在时间序列数据分析领域,识别和处理异常点是至关重要的任务。异常点或离群点是明显偏离预期模式的数据点,可能表明存在错误、欺诈或有价值的见解。 应对这一挑战的一种有效技术是汉普尔过滤器(Hampel Filter)。 模型描述 汉…

Manacher学习笔记

Manacher 算法&#xff0c;俗称马拉车算法&#xff0c;是一种解决最长回文子串问题的算法。 在 Ybt 的哈希章节中出现了这个&#xff1a; 数据范围 1 0 6 10^6 106&#xff0c;数据相对于马拉车模板较弱。 对于一个普通的字符串&#xff0c;我们要想求出它的回文子串需要考虑它…

聊天机器人语料在开发中的重要性

语料在聊天机器人的开发中起着至关重要的作用&#xff0c;使其能够有效理解和回应用户的查询。语料是聊天机器人的训练数据&#xff0c;通过分析和学习这个语料&#xff0c;聊天机器人可以提高对用户意图的准确理解&#xff0c;并生成恰当的回应。 | 一、聊天机器人语料好在哪&…

Unity 单例-接口模式

单例-接口模式 使用接口方式实现的单例可以继承其它类&#xff0c;更加方便 using System.Collections; using System.Collections.Generic; using UniRx; using UniRx.Triggers; using UnityEngine; namespace ZYF {public interface ISingleton<TMono> where TMono : M…

Redis-Sentinel高可用架构学习

Redis-Sentinel高可用架构 Redis主从复制过程&#xff1a; 主从同步原理 Redis Sentinel&#xff08;哨兵&#xff09;高可用集群方案&#xff1a;Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案。 当用Redis做Master-slave的高可用方案时&#xff0c;假如master宕机了…

微信小程序之后台首页交互

目录 一.与后台数据进行交互&request封装 后台准备 测试结果 ​编辑 前端 测试结果 二.wxs的介绍以及入门 测试结果 一.与后台数据进行交互&request封装 后台准备 pom.xml文件编写 <?xml version"1.0" encoding"UTF-8"?> <proj…

【JavaEE】常见的锁策略 -- 多线程篇(4)

文章目录 乐观锁 vs 悲观锁读写锁重量级锁 vs 轻量级锁自旋锁&#xff08;Spin Lock&#xff09;公平锁 vs 非公平锁可重入锁 vs 不可重入锁 乐观锁 vs 悲观锁 悲观锁: 总是假设最坏的情况&#xff0c;每次去拿数据的时候都认为别人会修改&#xff0c;所以每次在拿数据的时候都…

全连接网络参数Xavier初始化

1.梯度消失 考虑下图的神经网络&#xff0c;在使用梯度下降法迭代更新W_ki和W_ij时&#xff0c;它们的梯度方向间有什么关系&#xff1f; 它们的梯度关系如下&#xff1a; 从上述两个式子我们大致可以看出&#xff0c;损失函数L关于第h层参数的梯度由两部分组成&#xff1a;…

sql server2014如何添加多个实例 | 以及如何删除多个实例中的单个实例

标题sql server2014如何添加多个实例 前提&#xff08;已安装sql server2014 且已有默认实例MSSQLSERVER&#xff09; 添加新的实例 其实就是根据安装步骤再安装一次&#xff08;区别在过程中说明&#xff09; 双击安装 选择“全新独立安装或添加现有功能” 然后下一步下一…

微信小程序开发之后台数据交互及wxs应用

目录 一、后端准备 1. 应用配置 2. 数据源配置 二、数据库 1. 创建 2. 数据表 3. 数据测试 三、前端 1. 请求方法整合 2. 数据请求 3. WXS的使用 4. 样式美化 5. 页面 一、后端准备 通过SpringMVC及mybatis的技术学习&#xff0c;还有前后端分离的技术应用&…

Linux程序地址

目录 一、定义 二、问题引出 三、虚拟地址和物理地址 &#xff08;一&#xff09;问题解释 &#xff08;二&#xff09;什么是进程地址空间 &#xff08;三&#xff09;为什么要有进程地址空间 一、定义 #include <stdio.h> #include <stdlib.h>//geten…

运维监控Zabbix部署

目录 运维监控Zabbix部署 1. 简介 2. 安装 ​编辑 2.1 安装前准备 - Mysql 2.2 安装Zabbix Server 和 Zabbix Agent 2.2.1 安装Zabbix yum库 2.2.2 安装Zabbix Server、前端、Agent 2.2.3 初始化Mysql数据库 2.2.4 为Zabbix Server配置数据库 2.2.5 配置Zab…

【目标检测】Co-DETR:ATSS+Faster RCNN+DETR协作的先进检测器(ICCV 2023)

论文&#xff1a;DETRs with Collaborative Hybrid Assignments Training 代码**&#xff1a;https://github.com/Sense-X/Co-DETR 文章目录 摘要一、简介二、本文方法2.1.概述2.2.协同混合分配训练2.3. 定制的正 Query 生成2.4. Co-DETR为何有效1、丰富编码器的监督2、通过减少…

QEMU DirtyLimit特性介绍

文章目录 背景基本原理PMLDirty-RingDirty-Limit 具体实现数据结构vcpu_dirty_rate_statdirtylimit_state 算法实现接口逻辑qmp_set_vcpu_dirty_limitqmp_cancel_vcpu_dirty_limit 限制算法算法框架理想效果具体实现 测试验证QEMULibvirt 一个广子 背景 热迁移实现逻辑中&…

---图的遍历和最小生成树

广度优先遍历 --- 针对的是顶点遍历 深度优先遍历 如果给的图不是连通图&#xff1f;以某个点为起点就没有遍历完成。那么怎么保证遍历完剩下的点呢&#xff1f;&#xff1f; 在标记数组当中找没有遍历过的点&#xff0c;在进行遍历 最小生成树 生成树&#xff1a;一个连通…

使用TypeScript和jsdom库实现自动化数据抓取

目录 环境准备 使用TypeScript和jsdom抓取数据 总结 随着网络技术的发展&#xff0c;数据抓取已成为获取信息的重要手段。然而&#xff0c;手动进行数据抓取既耗时又容易出错。因此&#xff0c;本文将介绍如何使用TypeScript和jsdom库实现自动化数据抓取。我们将通过创建一个…

iMazing苹果用户手机备份工具 兼容最新的iOS16操作系统

现在距离苹果秋季新品发布会已过去月余&#xff0c;新iPhone 14系列和新版的iOS 16操作系统也如约与我们见面了&#xff0c;相信大家在9月初抢购的iPhone 14也基本到手了&#xff0c;但随之到来的数据资料备份迁移却是一件令人头大的事情&#xff0c;使用官方提供的iTunes软件卡…

计算机网络,网络(OSI)七层模型,三次握手四次挥手,get与post请求区别,网络IO(BIO\NIO\AIO),TCP与UDP区别

1.OSI模型&#xff1f; 开放式系统互联通信参考模型(Open System Interconnection Reference Model) OSI网络七层模型&#xff1a;应用层、表示层、会话层、传输层、网络层、数据链路层、物理层 TCP/IP协议群简化了OSI七层模型&#xff1a;应用层、传输层、网络层、数据链路…

java-各种成员变量初始化过程-待完善

前置条件 一、本文章讨论的成员变量 public static final String aa "aa";public static final Integer bb 1;public static final Students cc new Students();public static String aa1 "aa";public static Integer bb1 1;public static String bb2…