【链表】链表的合并【经典面试OJ详解】【力扣21,力扣23】超详细的算法教程

链表的合并

说在前面

那么这里博主先安利一下一些干货满满的专栏啦!

数据结构专栏:数据结构 这里包含了博主很多的数据结构学习上的总结,每一篇都是超级用心编写的,有兴趣的伙伴们都支持一下吧!
算法专栏:算法 这里可以说是博主的刷题历程,里面总结了一些经典的力扣上的题目,和算法实现的总结,对考试和竞赛都是很有帮助的!
力扣刷题专栏:Leetcode 想要冲击ACM、蓝桥杯或者大学生程序设计竞赛的伙伴,这里面都是博主的刷题记录,希望对你们有帮助!
C的深度解剖专栏:C语言的深度解剖 想要深度学习C语言里面所蕴含的各种智慧,各种功能的底层实现的初学者们,相信这个专栏对你们会有帮助的!

题目链接

  • 博主在这里想告诉大家,合并有序链表反转链表 这两个题,是面试笔试超级超级超级无敌经典的题目,百考不厌那种,也是链表中的经典题了。
    当然,博主还有很多数据结构和算法的经典力扣刷题笔记,都在 Leetcode 专栏里,欢迎大家订阅支持!

21. 合并两个有序链表
23. 合并K个升序链表

链表结构

struct ListNode {
    int val;
    ListNode* next;
    ListNode() : val(0), next(nullptr) {}
    ListNode(int x) : val(x), next(nullptr) {}
    ListNode(int x, ListNode* next) : val(x), next(next) {}
};

其实没那么复杂,我们只需要知道就是一个val一个next指针就行了,单链表还没有很好掌握的伙伴可以看这里哦~
【链表】单链表的介绍和基本操作(C语言实现)【保姆级别详细教学】

OJ21.合并两个有序链表

题目描述和算法分析

在这里插入图片描述

算法分析:
看到这道题,因为链表是有序的,我们可以用双指针来控制链表的遍历。 我们用两个指针分别指向两个链表,定义一个newhead作为新的链表头,然后两个指针所指向节点数字较小的,那些来尾插到newhead上,然后那个指针往后迭代一个节点,以此类推。
当最后有一个指针遍历到NULL之后,说明另外一条链表还没有遍历完,我们直接将剩下的尾插到刚刚的新链表上,因为它们肯定是数字最大的那几个节点

  • 数据结构题的共同特点,很多细节要注意,否则OJ肯定过不了。
  • 至于实现的细节,博主在实现代码的注释给大家解释清楚!

接口的完整实现代码

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
//如果其中一条表未空,直接返回另一条链表即可
    if(list1==NULL){
        return list2;
    }
    if(list2==NULL){
        return list1;
    }
    struct ListNode*newhead=NULL;//定义新的头
    struct ListNode*tail=newhead;//定义新链表的尾,
    //因为我们等下要尾插,所以定义一个尾节点跟着走,
    //我们可以不用每次都遍历链表找尾,降低时间复杂度

	//因为我们要做尾插,所以,我们先拿一个节点下来先,这样后面我们在循环里好控制
	//否则我们在循环里,还要判断,newhead是不是空的情况,比较麻烦,所以先拿一个下来,后面就好办了。
    if(list1->val>list2->val){
        tail=newhead=list2;
        list2=list2->next;
    }
    else{
        tail=newhead=list1;
        list1=list1->next;
    }
    
    //两个指针分别遍历两条链表
    struct ListNode*cur1=list1;
    struct ListNode*cur2=list2;
    while(cur1&&cur2){
    //小的放下来,迭代
        if(cur1->val<cur2->val){
            tail->next=cur1;
            cur1=cur1->next;
            tail=tail->next;
        }
        else{
            tail->next=cur2;
            cur2=cur2->next;
            tail=tail->next;
        }
    }
    //如果还有一条链表没有遍历完,直接整个尾插上去
    if(cur2==NULL){
        tail->next=cur1;
    }
    else if(cur1==NULL){
        tail->next=cur2;
    }
    return newhead;
}

OJ23.合并K个升序链表

题目描述和算法分析

在这里插入图片描述
这个题目博主放在这里其实就是让大家好好利用上一题的那个函数的,其实这一题还有效率更高的方法,但是我们承接上一题,就用上一题写好的函数做。
用那个函数,一条一条链在一起。

接口的完整实现代码

class Solution {
private:
    struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
    if(list1==NULL){
        return list2;
    }
    if(list2==NULL){
        return list1;
    }
    struct ListNode*newhead=NULL;
    struct ListNode*tail=newhead;
    if(list1->val>list2->val){
        tail=newhead=list2;
        list2=list2->next;
    }
    else{
        tail=newhead=list1;
        list1=list1->next;
    }
    struct ListNode*cur1=list1;
    struct ListNode*cur2=list2;
    while(cur1&&cur2){
        if(cur1->val<cur2->val){
            tail->next=cur1;
            cur1=cur1->next;
            tail=tail->next;
        }
        else{
            tail->next=cur2;
            cur2=cur2->next;
            tail=tail->next;
        }
    }
    if(cur2==NULL){
        tail->next=cur1;
    }
    else if(cur1==NULL){
        tail->next=cur2;
    }
    return newhead;
}
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        ListNode*ret=NULL;//最后的结果链表
        for(int i=0;i<lists.size();i++){//一条一条链接起来
            ret=mergeTwoLists(ret,lists[i]);
        }
        return ret;
    }
};

尾声

其实单链表在以后的学习工作中,并不是特别的实用,因为单链表也有很多缺陷。但是,掌握单链表是我们以后学习复杂数据结构的必须要的。
如果看到这里的你感觉这篇博客对你有帮助,不要忘了收藏,点赞,转发,关注哦。

posted @ 2022-05-09 23:59  背包Yu  阅读(24)  评论(0编辑  收藏  举报  来源