【数据结构】10道经典面试题目带你玩转链表

🦄个人主页:修修修也

🎏所属专栏:数据结构

⚙️操作环境:Visual Studio 2022


目录

一.移除链表元素

二.反转链表

三.链表的中间结点

四.链表中倒数第K个结点

五.合并两个有序链表

六.链表分割

七.链表的回文结构

八.相交链表

九.环形链表


一.移除链表元素

题目链接:

203. 移除链表元素icon-default.png?t=N7T8https://leetcode.cn/problems/remove-linked-list-elements/


题目描述:

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


题目详情:


解题思路:

思路一:双指针删除val法

如图,我们创建两个指针,分别是prev和cur,在初始时,它们一个指向空,一个指向链表的第一个结点(即head):

然后让两指针顺着链表向后移动,如果碰到cur不是val的值的结点就继续同时向后移动:

如果在移动的过程中碰到了cur是val的值的结点则将prev链上cur的下一个结点,并将cur结点释放:

删除后prev不动,cur继续向后移动:

如果cur指向的结点不是val的值,则两个指针继续向后移动:

直到cur再次碰到值等于val的结点:

继续将prev链上cur的下一个结点,并将cur结点释放:

删除后prev不动,cur继续向后移动:

这时发现cur已经走到NULL,则链表已经遍历到尾,即已删除完毕,向主函数返回此时链表的头指针head即可.


思路二:双链表遍历尾插法

如图,我们再创建一个单链表newhead,然后创建一个cur指针负责遍历待删链表,再创建一个tail指针负责记录新链表的尾结点:

当cur结点的值不为val时,我们将该结点尾插到新链表的后面:

然后cur指针继续向后移动遍历旧链表:

碰到cur结点的值不为val时,我们继续将该结点尾插到新链表的后面:

然后cur指针向后走,tail指针同样要重新指向新链表的尾结点:

当cur结点的值为val时,我们创建一个新指针next记录下cur的next结点,然后将cur结点free掉,再使cur指针指向刚刚记录的next结点.

然后cur继续向后遍历,遇到值为val的结点就删除,遇到非val的结点就尾插到新结点:

注意,当最后一个结点也是我们要删除的结点时,我们在删除结束后记得要将tail的指针域置为空,否则会导致新链表的尾结点末端连着一个非法空间!

如上,删除结束后返回新链表的头指针newhead即可.


解题代码:

思路一解题代码:

//双指针删val法
struct ListNode* removeElements(struct ListNode* head, int val)
{
    struct ListNode*cur=head;
    struct ListNode*prev=NULL;
    while(cur)
    {
        if(cur->val != val)
        {
            prev=cur;
            cur=cur->next;
        }
        else
        {
            if(prev == NULL) //如果是头删,则更新头指针,然后删除头结点
                             //否则会造成prev空指针解引用问题
            {
                head=cur->next;
                free(cur);
                cur=head;
            }
            else
            {
                prev->next=cur->next;
                free(cur);
                cur=prev->next;
            }
        }
    }
    return 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(newhead==NULL)//头插是赋值
            {
                newhead=tail=cur;
            }
            else
            {
                tail->next=cur;
                tail=tail->next;
            }
            cur=cur->next;
        }
        else
        {
            struct ListNode*next=cur->next;
            free(cur);
            cur=next;
        }
    }
    if(tail!=NULL)//防止最后一个位置是待删元素,free后新链表的尾结点的指针域是野指针问题.
    {
        tail->next=NULL;
    }
    return newhead;
}

提交运行:


二.反转链表

题目链接:

206. 反转链表icon-default.png?t=N7T8https://leetcode.cn/problems/reverse-linked-list/


题目描述:

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


题目详情:


解题思路:

思路一:三指针逆连链表法

如图,我们创建三个指针分别是p1,p2,p3.使它们分别指向首结点,第二结点,第三结点:

然后将p2指针的next指向p1:

然后使p1,p2,p3向前挪动:

再将p2指针的next指向p1:

然后p1,p2,p3继续向前挪动:

再将p2指针的next指向p1:

再将p1,p2,p3继续向前挪动:

再将p2指针的next指向p1:

再将p1,p2,p3继续向前挪动:

可以看到,当p2指针为空时,链表已经全部逆链完毕,这时返回p1指针即为逆转后的链表头.


思路二:双链表取结点头插法

如图,我们创建一个新链表newhead,以及一个用来遍历待逆置链表的指针cur:

然后使cur向后遍历,每找到一个结点就将其头插到newnode链表中:

继续向后移动然后头插到newnode中:

直到将待逆置链表全部尾插到newhead链表中:

这时链表就逆置完毕了,这时返回newhead,即新链表的头即可.


解题代码:

思路一解题代码:

//三指针逆链表法
struct ListNode* reverseList(struct ListNode* head)
{
    if(head==NULL)
    {
        return NULL;
    }
    struct ListNode*p1=NULL;
    struct ListNode*p2=head;
    struct ListNode*p3=head->next;
    if(p3==NULL)
    {
        return head;
    }
    else if(p3->next==NULL)
    {
        p3->next=p2;
        p2->next=p1;
        return p3;
    }
    else
    {
        p1=p2;
        p2=p2->next;
        p1->next=NULL;
        while(p2)
        {
            p3=p3->next;
            p2->next=p1;
            p1=p2;
            p2=p3;
        }
        return p1;
    }
}

提交运行:


思路二解题代码:

//取结点头插法
struct ListNode* reverseList(struct ListNode* head)
{
    struct ListNode*newnode=NULL;
    struct ListNode*cur=head;
    while(cur)
    {
        if(newnode==NULL)//当newnode为NULL时单独赋值处理,并把尾结点置空
        {
            newnode=cur;
            cur=cur->next;
            newnode->next=NULL;
        }
        else
        {
            struct ListNode*prev=newnode;
            newnode=cur;
            cur=cur->next;
            newnode->next=prev;
        }
    }
    return newnode;
}

提交运行:


三.链表的中间结点

 题目链接:

876. 链表的中间结点icon-default.png?t=N7T8https://leetcode.cn/problems/middle-of-the-linked-list/


题目描述:

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

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


题目详情:


解题思路:

快慢指针解题法:

如图,我们分别创建两个指针,一个快指针,一个慢指针,开始时它们都指向链表的头结点:

然后我们让两指针循环向后遍历链表,但我们每次让fast指针向后走两步,而slow指针只向后走一步,如下是两个指针前进一次的样子:

如此循环前进,直到fast走到链表的最后一个结点,即fast->next=NULL时:

可以看到,当fast走到尾时,slow指针恰好指向链表的中间结点.

当然,当链表的结点数为偶数时,则当fast走到NULL时,slow指针恰好指向链表的中间结点,如:


解题代码:

//快慢指针解题法
struct ListNode* middleNode(struct ListNode* head)
{
    struct ListNode*fast=head;
    struct ListNode*slow=head;
    while(fast&&fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
    }

    return slow;    
}

提交运行:


四.链表中倒数第K个结点

 题目链接:

链表中倒数第K个结点icon-default.png?t=N7T8https://www.nowcoder.com/share/jump/1020746871700211094739


题目描述:

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


题目详情:


解题思路:

快慢指针法:

如图,我们设置两个指针,一个是fast,一个是slow,开始时它们分别指向链表的头结点:

在开始时,我们求链表中的倒数第k个结点,就先让fast向前走k步,如我们要求上图链表中的倒数第2个结点,则我们先让fast指针向前走2步:

当fast走完k步后,fast开始和slow一起向后挪动,直到fast走到NULL为止:

一起向后走一步:

一起向后再走一步:

当fast走到NULL时,slow恰好指向链表的倒数第二个结点:

这时我们在函数中返回slow指针即可.


解题代码:

struct ListNode* FindKthToTail(struct ListNode* pListHead, int k )
{
    //快慢指针法
    struct ListNode*fast=pListHead;
    struct ListNode*slow=pListHead;
    while(k)
    {
        if(fast==NULL)//防止k的长度比链表的长度长
        {
            return NULL;
        }
        fast=fast->next;
        k--;
    }
    while(fast)
    {
        fast=fast->next;
        slow=slow->next;
    }
    return slow;
}

提交运行:


五.合并两个有序链表

 题目链接:

21. 合并两个有序链表icon-default.png?t=N7T8https://leetcode.cn/problems/merge-two-sorted-lists/


题目描述:

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


题目详情:


解题思路:

双指针尾插新链表法:

如图,我们创建一个新链表,以及三个指针,分别是cur1,cur2,tail,分别用来遍历链表1,遍历链表2,记录新链表的尾结点:

然后我们比较cur1和cur2的值,将其中的较小者尾插到newhead链表中(假设两个值相同时我们默认将cur1插入到链表中):

然后分别更新cur1指针和tail指针,使它们分别指向下一个结点和新链表的尾结点:

然后再比较cur1和cur2的值,将它们的较小者插入到新链表中:

再更新cur2指针和tail指针:

直到某一链表的结点全部插入到newhead中,如:

这时将不为空的链表剩下的全部结点直接链接在tail指针后面即可:

这时得到的新链表就是两个链表合并为升序链表的结果,我们返回newhead即可.


解题代码:

//双指针比较尾插新链表法
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
    struct ListNode*cur1=list1;
    struct ListNode*cur2=list2;
    struct ListNode*newhead=NULL;
    struct ListNode*tail=newhead;
    while(cur1&&cur2)
    {
        if(cur1->val<=cur2->val)
        {
            if(newhead==NULL)//首结点是赋值
            {
                newhead=cur1;
                tail=newhead;
            }
            else
            {
                tail->next=cur1;
                tail=tail->next;
            }
            cur1=cur1->next;
        }
        else
        {
            if(newhead==NULL)//首结点是赋值
            {
                newhead=cur2;
                tail=newhead;
            }
            else
            {
                tail->next=cur2;
                tail=tail->next;
            }
            cur2=cur2->next;
        }
    }
    if(cur1==NULL)
    {
        if(tail)//防止tail为NULL时的空指针解引用问题
        {
            tail->next=cur2;
        }
        else
        {
            return cur2;
        }
        
    }
    else
    {
        if(tail)
        {
            tail->next=cur1;
        }
        else
        {
            return cur1;
        }
    }
    return newhead;
}

提交运行:


六.链表分割

 题目链接:

链表分割icon-default.png?t=N7T8https://www.nowcoder.com/share/jump/1020746871700135186269


题目描述:

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


题目详情:


解题思路:

双链表分类再合并法:

如图,我们创建一个cur指针用来遍历链表,然后创建一个新链表newhead1来存放比x小的结点,同时创建一个tail1指针记录这个链表的尾结点.

再创建一个新链表newhead2来存放比x大的结点,同时创建一个tail2指针记录这个链表的尾结点:

我们以x等于3为例,如果cur指向的结点的val值小于3,就将该结点尾插到newhead1链表中,反之,如果cur指向的结点的val值大于等于3,就将该结点尾插到newhead2链表中:

我们将cur指向的'1'结点尾插到newhead1中,并用tail1记录下newhead1的尾结点,然后cur向后遍历:

再将'2'结点尾插到newhead1链表中,更新tail1和cur的指向:

这时cur指向的结点的val值为6,大于x,我们把它尾插到newhead2中,更新cur和tail2的值:

将后续结点依次判断后尾插到newhead1或newhead2中去,直到cur为NULL:

当将原链表中的结点全部分到两个新链表中后,将newhead1和newhead2链表重新链接在一起,即tail1的指针域连接上newhead2,就可以得到一个新的按题目要求排序好的新链表了:

这时返回新链表的头,即newhead1给函数即可.


解题代码:

//双链表分类再合并法
class Partition {
public:
    ListNode* partition(ListNode* pHead, int x)
    {
        struct ListNode*cur=pHead;
        struct ListNode*newhead1=NULL;
        struct ListNode*tail1=NULL;
        struct ListNode*newhead2=NULL;
        struct ListNode*tail2=NULL;
        while(cur)
        {
            if(cur->val<x)
            {
                if(newhead1==NULL)
                {
                    newhead1=cur;
                    tail1=newhead1;
                }
                else 
                {
                    tail1->next=cur;
                    tail1=tail1->next;
                }
            }
            else
            {
                if(newhead2==NULL)
                {
                    newhead2=cur;
                    tail2=newhead2;
                }
                else 
                {
                    tail2->next=cur;
                    tail2=tail2->next;
                }
            
            }
            cur=cur->next;
        }
        if(tail2!=NULL)//防止tail2尾结点的指针域不为空造成新链表带环
        {
            tail2->next=NULL;//所以要将tail2的指针域置为空
            if(tail1!=NULL)
            {
                tail1->next=newhead2;//置空之后链接两个链表
                return newhead1;    //链接成功返回newhead1
            }
            else
            {
                return newhead2;   //tail1==NULL意味newhead1没有元素,则可以直接返回newhead2
            }
        }
        else     //tail2==NULL意味newhead2没有元素,则可以直接返回newhead1
        {
            return newhead1;
        }
        
        return newhead1;
    }
};

提交运行:


七.链表的回文结构

 题目链接:

链表的回文结构icon-default.png?t=N7T8https://www.nowcoder.com/share/jump/1020746871700305446248


题目描述:

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

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

如:

1->2->2->1

返回:

true

题目详情:


解题思路:

先逆置后对比对法:

思路为:我们先将原链表的后半段逆置,然后再将其和原链表的前半段作对比,如果相同,则是回文结构.

实现该思路我们需要先找中间结点,再逆置中间结点后的链表部分,再将逆置后的链表和原链表的前半部分做对比:

图示如下,找中间结点:

逆置中间结点后的链表得到newhead:

逐一对比head链表和newhead链表的结点,如果有不一样的,则不是回文结构,如果都一样,则是回文结构:

注:查找中间结点以及逆转链表的代码思路我们在前面几道题中已经实现过了,在这里直接套用即可.


解题代码:

//先逆转再对比法
ListNode*midnode(ListNode*head)//找中间结点函数
{
    struct ListNode*fast=head;
    struct ListNode*slow=head;
    while(fast&&fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
    }
    return slow;
}

ListNode* reverseList(struct ListNode* head)//逆转函数
{
    struct ListNode*newnode=NULL;
    struct ListNode*cur=head;
    while(cur)
    {
        if(newnode==NULL)//当newnode为NULL时单独赋值处理,并把尾结点置空
        {
            newnode=cur;
            cur=cur->next;
            newnode->next=NULL;
        }
        else
        {
            struct ListNode*prev=newnode;
            newnode=cur;
            cur=cur->next;
            newnode->next=prev;
        }
    }
    return newnode;
}


class PalindromeList {
public:
    bool chkPalindrome(ListNode* A) {
        //找中间结点   slow
    struct ListNode*mid=midnode(A);

        //逆置尾链表
    struct ListNode*newhead=reverseList(mid);

        //对比新链表
    struct ListNode*cur1=A;
    struct ListNode*cur2=newhead;
    while(cur1&&cur2)
    {
        if(cur1->val!=cur2->val)
        {
            return false;
        }
        cur1=cur1->next;
        cur2=cur2->next;
    }
    return true;
    }
};

提交运行:


八.相交链表

 题目链接:

160. 相交链表icon-default.png?t=N7T8https://leetcode.cn/problems/intersection-of-two-linked-lists/


题目描述:

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

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

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构


题目详情:


解题思路:

对于这道题,我们首先要理解:假设两个链表短的长度为x,长的长度为y,则他们的交点一定位于长链表的后x结点中,而不会位于后x之外的结点:

因为交点之后的结点就是两个链表共用的了,即相交后的链表元素如果A有那么B也一定有,因此不可能出现两链表的交集比某一链表的长度还长的情况.

所以我们在找交点时应该从长链表的第y-x个结点和短链表的第一个结点开始一起向后找有没有相同的结点:

如果有,则为两链表的交点,如果没有,则两链表没有交点:

因此我们本题的思路是,先分别求出A,B链表的长度,然后让长链表向后走到后面只有x个结点的地方,开始和短链表一起向后移动,在移动的过程中找有没有交点,如果找到了,返回交点,如果走到尾还没有找到,则返回0.


解题代码:

//同长后移找交点法
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{
    //先遍历A,B链表求出长度
    struct ListNode*cur1=headA;
    struct ListNode*cur2=headB;
    int len1=0;
    int len2=0;
    while(cur1)
    {
        cur1=cur1->next;
        len1++;
    }
    while(cur2)
    {
        cur2=cur2->next;
        len2++;
    }
    int k=abs(len1-len2);

    //让长的先走到和短的长度一样的地方,然后开始同时向后走
    cur1=headA;
    cur2=headB;
    if(len1>len2)
    {
        while(k--)
        {
            cur1=cur1->next;
        }
        while(cur1&&cur2)
        {
            if(cur1==cur2)
            {
                return cur1;
            }
            cur1=cur1->next;
            cur2=cur2->next;
        }
        return 0;
    }
    else
    {
        while(k--)
        {
            cur2=cur2->next;
        }
        while(cur1&&cur2)
        {
            if(cur1==cur2)
            {
                return cur2;
            }
            cur1=cur1->next;
            cur2=cur2->next;
        }
        return 0;
    }
}

提交运行:


九.环形链表

 题目链接:

141. 环形链表icon-default.png?t=N7T8https://leetcode.cn/problems/linked-list-cycle/


题目描述:

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

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。

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


题目详情:


解题思路:

快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表起始位置开始运行,如果链表带环则一定会在环中相遇,否则快指针率先走到链表的末尾.

现实中参考陪女朋友在操场跑步减肥时套圈的情景.


解题代码:

//双指针循环追逐法
bool hasCycle(struct ListNode *head)
{
    if(head==NULL||head->next==NULL)
    {
        return false;
    }
    struct ListNode*fast=head;
    struct ListNode*slow=head;
    while(fast&&fast->next&&slow)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow)
        {
            return true;
        }
    }
    return false;
}

提交运行:


结语

希望通过上面的题目能使大家对链表的理解更上一层楼,欢迎大佬们留言或私信与我交流.学海漫浩浩,我亦苦作舟!关注我,大家一起学习,一起进步!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

国内优质企业网盘推荐:满足您的文件存储与共享需求

企业网盘是主要用于企业工作过程中给的文件存储、共享以及协作。很多用户在挑选文件协作工具时更偏爱国内的工具&#xff0c;原因是使用上可能更贴合国人的使用习惯&#xff01; 那么现在国内做的比较好的企业网盘有什么&#xff1f; Zoho Workdrive企业网盘&#xff0c;ZOHO…

.NET 8 正式 GA 遥遥领先

.NET 8 一正式 已正式 GA。 微软称 .NET 8 提供了数以千计的性能、稳定性和安全性改进&#xff0c;以及平台和工具增强功能&#xff0c;有助于提高开发者的工作效率和创新速度。 比如 .NET 8 为 Android 和 WASM 引入了全新的 AOT 模式、改进 System.Text.Json&#xff0c;以…

谈谈如何写作(二)

序言 没有什么比一套好理论更有用了。——库尔特勒温 谈谈如何写作系列今天进入第二篇&#xff0c;第一篇请速戳&#xff1a;谈谈如何写作&#xff08;一&#xff09; 今天&#xff0c;博主从如何写报告讲起。 Q&#xff1a;如何写报告 如何写报告呢&#xff1f; 当每位盆友接到…

MAXScript实现简单的碰撞检测教程

在本教程中&#xff0c;我们将创建一个使轮子在地形上跟随的脚本。此脚本将没有任何UI。并且仅适用于特定对象。 因此&#xff0c;第一步是创建一个新的脚本。打开侦听器窗口&#xff0c;然后在文件菜单下选择“新建脚本…”。 我们首先需要创建与场景中的对象相对应的3个变量…

实战提升(六)

前言&#xff1a;Practice makes perfect&#xff01;今天实战Leetcode链表分割还有回文结构。今天的题全都来自于牛客网。 实战一&#xff1a; 思路&#xff1a;我们一这个链表为例&#xff0c;小于5的链表尾插到第一个链表&#xff0c;大于5的链表尾插到第二个链表&#xf…

【开源】基于Vue.js的开放实验室管理系统的设计和实现

项目编号&#xff1a; S 013 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S013&#xff0c;文末获取源码。} 项目编号&#xff1a;S013&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 实验室类型模块2.2 实验室模块2.3 实…

vim指令

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;熟练掌握vim&#xff0c;并且能用vim敲出简单的代…

【计算机组成原理】知识点巩固 - 存储器概述

目录 1、存储器分类 1.1、按存储介质分类 1.2、按存取方式分类 1.3、按信息的可改写性分类 1.4、按信息的可保存性分类 1.5、按功能和存取速度分类 2、存储器技术指标 2.1、存储容量 2.2、存取速度 3、存储系统层次结构 4、主存的基本结构 5、主存中数据的存放 5…

麒麟 ZYJ 服务器软件适配 参考示例

一、zyj 环境简介 1. ZYJ 概述 国产化 SMZYJ 是由国家 BM 主管部门鉴定并批准生产使用的国内自主开发的 整机 JM 国标设备&#xff0c;设备采用了自主设备基础硬件&#xff08;飞腾、国科微等&#xff09;、安全硬 件自主固件&#xff08;昆仑等&#xff09;自主 SM 专用操作…

7、传统CV之高斯滤波

这一节在上一节均值滤波的基础上,再进阶一下,了解一下什么是高斯滤波。 首先,如上一节所说,均值滤波是利用一个窗口在图片上滑动,每次都计算窗口内能看到的像素的平均值,然后将平均值作为滤波的输出,从而可以起到平滑图像、去噪点的作用。 有没有发现,此时并没有特别…

栈的实现及OJ练习(c语言)

目录 前言 栈 栈的实现&#xff08;数组栈&#xff09; 初始化栈 入栈 出栈 获取栈顶元素 获取栈中有效元素个数 检测栈是否为空 销毁栈 最终代码&#xff1a; 选择练习 栈的OJ题 前言 我们在之前已经学习了顺序表和链表的概念&#xff0c;它们有这样的优缺点&a…

4.2 Windows驱动开发:内核中进程线程与模块

内核进程线程和模块是操作系统内核中非常重要的概念。它们是操作系统的核心部分&#xff0c;用于管理系统资源和处理系统请求。在驱动安全开发中&#xff0c;理解内核进程线程和模块的概念对于编写安全的内核驱动程序至关重要。 内核进程是在操作系统内核中运行的程序。每个进…

键鼠自动化2.0展示

软件介绍&#xff1a;桌面键鼠自动化工具 Qtc 编写&#xff1a; 本软件采用Qt C编写&#xff0c;旨在提供高效、跨平台的桌面键鼠自动化解决方案。Qt C框架的选择确保了软件的稳定性、可靠性&#xff0c;并通过其图形用户界面实现了用户友好的操作体验。 鼠标移动与点击&#…

MySQL 的执行原理(一)

5.1 单表访问之索引合并 我们前边说过 MySQL 在一般情况下执行一个查询时最多只会用到单个二级 索引&#xff0c;但存在有特殊情况&#xff0c;在这些特殊情况下也可能在一个查询中使用到多个二 级索引&#xff0c;MySQL 中这种使用到多个索引来完成一次查询的执行方法称之为&…

物联网AI MicroPython学习之语法 SPI串行外设通信

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; SPI 介绍 模块功能: SPI串行外设驱动 接口说明 SPI - 构建SPI对象 函数原型&#xff1a;SPI(id, baudrate&#xff0c;polarity, phase&#xff0c;sck, mosi, miso)参数说明&#xff1a; 参数类型必选参…

webAPP基础学习

###视觉基础 part-I ####1.面试中常见的像素问题 >什么是像素? *1.什么是px? px-虚拟像素,css像素的单位 px是一个相对单位,相对于设备像素而言 >相对性 a.相对于同一个设备,css像素的可变的 css像素物理像素>会受到缩放的影响 css像素缩放倍数*单个物理像…

django理解02 前后端分离中的问题

前后端分离相对于传统方式的问题 前后端数据交换的问题跨域问题 页面js往自身程序&#xff08;django服务&#xff09;发送请求&#xff0c;这是浏览器默认接受响应 而请求其它地方是浏览器认为存在潜在危险。自动隔离请求&#xff01;&#xff01;&#xff01; 跨域问题的解决…

蓝桥杯 枚举

例题讲解 特别数的和 #include<iostream> using namespace std; bool ifspecial(int n){while(n){if(n%100||n%101||n%102||n%109){return true;} n/10;}return false; } int main(){int n;cin>>n;int sum0;for(int i1;i<n;i){if(ifspecial(i)){sumi;}}cout&l…

K-Means算法进行分类

已知数据集D中有9个数据点&#xff0c;分别是&#xff08;1,2&#xff09;&#xff0c;(2,3), (2,1), (3,1),(2,4),(3,5),(4,3),(1,5),(4,2)。采用K-Means算法进行聚类&#xff0c;k2&#xff0c;设初始中心点为&#xff08;1.1,2.2&#xff09;&#xff0c;&#xff08;2.3,3.…

LitCTF2023 - Reverse方向 全WP

文章目录 [LitCTF 2023]世界上最棒的程序员[LitCTF 2023]ez_XOR[LitCTF 2023]enbase64[LitCTF 2023]snake[LitCTF 2023]程序和人有一个能跑就行了[LitCTF 2023]debase64[LitCTF 2023]For AiurLitCTF{Pylon_OverCharge!!_We_Must_construc7_addition4l_pylons} [LitCTF 2023]世界…