合并两个有序链表[C++版]

合并两个有序链表[C++版]

    • 问题描述
    • 解决思想
    • 我的代码
    • 代码理解
      • 角度1
      • 角度2
    • 我的总结

问题描述

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
举个栗子:
链表1:1->3->5->7
链表2:2->4->8
合并之后的链表:1->2->3->4->5->7->8

解决思想

对于这个题,我想我们可以这样做:
类似于排序的方式,并且两个子链表都已经排好了顺序。
以上述为例,我们很容易发现链表1的第一个元素小于链表2的第一个元素,也就是1 < 2,毫无疑问,1肯定是两条链表里的最小值节点。好,我们不再看关注1。
那么此时我们的链表1变为了3->5->7,链表2变为了2->4->8,
同理执行上述操作(即比较两个链表的第一个元素的大小),我们发现2 < 3,这说明2是次小的,我们不再关注2。
此时链表1变为了3->5->7,链表2变为了4->8。
我们继续重复执行上述操作,到最好我们发现链表1为空了,这个时候链表2仅有一个节点,节点值为8。
该例中,链表2仅存的最后一个节点就是两个链表中的最大值节点
这个时候我们选择返回这个不为空的链表(因为没有比较的意义了啊~ 这个链表本身就是排好的,也没有和它比的链表了)。

通过上述操作,我们可以依次把排好序的整体链表的值依次输出。我们发现:
1.每次操作都是类似的,即都比较了抛弃该节点之后的新链表与下个列表的第一个值进行比较。
2.当某个链表为空时,我们只需要返回剩余不为空的链表即可
我们用递归进行实现

我的代码

在贴代码之前,我们不妨先看看C++语言中链表实现的这种方式。

struct ListNode {
	// 节点的值
	int val;
	// 节点的next指针,指向下一个节点
	struct ListNode *next;
	// 有参构造函数(初始化)
	ListNode(int x){
		val = x;
		next = nullptr;
	}
};

使用结构体来定义了这样的一个链表中的节点,这点很关键。一个链表其实就是指针指向了这个节点,这个节点又指向了下一个节点

class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
    	// 递归出口1:链表1为空,返回链表2
        if(pHead1 == nullptr){
            return pHead2;
        // 递归出口2:链表2为空,返回链表1
        }else if(pHead2 == nullptr){
            return pHead1;
        }
        // 若链表1的第一个元素小于链表2的第一个元素 那么保留链表1的第一个元素并使它的指针指向后续链表合并的结果
        if(pHead1->val <= pHead2->val){
            pHead1->next = Merge(pHead1->next, pHead2);
            // 返回这个链表
            return pHead1;
        // 若链表2的第一个元素小于链表1的第一个元素 那么保留链表2的第一个元素并使它的指针指向后续链表合并的结果
        }else{
            pHead2->next = Merge(pHead1, pHead2->next);
            // 返回这个链表
            return pHead2;
        }
    }
};

代码理解

我想很多人看这个代码都是有点懵的。
我想从两个角度来讲一下我是如何理解的。

角度1

递归的习惯。
我们在上面的内容中已经分析了,递归的出口是什么?——自然是当有个链表为空时,返回另一个链表。
递归的状态转移方程是什么?——比较当前阶段下的链表1和链表2的首元素。若链表1的首元素小,我们就留下它,并使它的next指针指向新的链表1(去掉了首元素)和链表2合并的结果,反之链表2也一样
这样代码便好写了。

角度2

分析代码到底是怎么实现的。
这里用到了一种工具——
合并两个有序链表[C++版]_第1张图片
我来解释一下我画的这个图。重点在右侧的栈区
我们第一次对链表1的首元素和链表2的首元素进行比较时候,我们发现1 < 2。那么计算机如何做呢?
我们留下1,并将next指向下一个入栈的东西(就是后续操作)。为什么呢?
我们传过来的链表1是完整的链表1,那么链表本身的节点不变吧,就是1,我们只能对next指针进行操作,令它指向后续链表的合并结果
第二次,我们发现2 < 3,同理吧,我们肯定留下2,令它的指针指向后续链表合并的结果。
如此,直到最后,仅有一个节点(节点值为8)的链表入栈了。
根据我们递归出口设定,这个时候要返回这个仅有一个节点(节点值为8)的链表。
那么节点值为7的节点指向这个仅有一个节点(节点值为8)的链表,5又指向7,4又指向5.。。。每次都会把完整指向的链表返回,直到最后就返回了节点值为1的链表,即1->2->3->4->5->7->8。
此时所有元素均出栈完毕了

我的总结

递归分析还是比较困难的。培养递归的思想还是很重要。

你可能感兴趣的:(Leecode,C++)