剑指offer_面试题17_合并两个排序的链表(两种思维)

题目:输入两个递增排序的链表,合并这两个链表,并使新链表中的结点仍然是按照递增排序的。

第一种思维:合并两个排序的链表,类似于合并两个排序数组,所不同的仅是一个用链表保存数据,一个用数组保存数据。

算法如下:(下面的算法前提是:头结点 不是 链表的第一个数据节点。)

/**方法一:合并两个排序链表,使用了新创建的链表来保存,没有改动两个原始链表*/
ListNode *merge_tow_list(ListNode *pHead1,ListNode *pHead2)
{
    if(NULL == pHead1 && NULL == pHead2)
        return pHead1;
    if(NULL == pHead1 && NULL != pHead2)
        return pHead2;
    if(NULL != pHead1 && NULL == pHead2)
        return pHead1;

    ListNode *temp1, *temp2;
    temp1 = pHead1->m_pNext;        /*指向第一个数据结点*/
    temp2 = pHead2->m_pNext;

    ListNode *pHead_new = new ListNode;    /*新建了一个链表用来存放合并后的结点*/
    pHead_new->m_nValue = 0;
    pHead_new->m_pNext = NULL;

    ListNode *curr, *temp;
    curr = pHead_new;

    while(temp1 != NULL && temp2 != NULL)
    {
        if(temp1->m_nValue < temp2->m_nValue)
        {
            temp = new ListNode;
            temp->m_nValue = temp1->m_nValue;  /*将数据赋值个新节点*/
            temp->m_pNext = NULL;              /*新链表增加的结点,接在链表尾*/
            curr->m_pNext = temp;

            pHead_new->m_nValue++;

            curr = curr->m_pNext;
            temp1 = temp1->m_pNext;
        }
        else
        {
            temp = new ListNode;
            temp->m_nValue = temp2->m_nValue;
            temp->m_pNext = NULL;
            curr->m_pNext = temp;

            pHead_new->m_nValue++;

            curr = curr->m_pNext;
            temp2 = temp2->m_pNext;
        }
    }
    while(NULL != temp1)
    {
        temp = new ListNode;
        temp->m_nValue = temp1->m_nValue;
        temp->m_pNext = NULL;
        curr->m_pNext = temp;

        pHead_new->m_nValue++;              /*头结点数据保存结点总数,每增加一个数据结点,该值加1*/

        curr = curr->m_pNext;
        temp1 = temp1->m_pNext;
    }
    while(NULL != temp2)
    {
        temp = new ListNode;
        temp->m_nValue = temp2->m_nValue;
        temp->m_pNext = NULL;
        curr->m_pNext = temp;

        pHead_new->m_nValue++;

        curr = curr->m_pNext;
        temp2 = temp2->m_pNext;
    }

    return pHead_new;
}

以下是合并两个排序数组的算法,可以对比如上算法来看:

void Merge_array(int a[], n, int b[], m, int c[])
{
    int i, j, k;

    i = j = k = 0;
    while (i < n && j < m)
    {
        if (a[i] < b[j])
            c[k++] = a[i++]; //c[k] = a[i];k++;i++;这里j不变
        else
            c[k++] = b[j++]; //c[k] = b[i];k++;j++;这里i不变
    }
    //到这里总会有一个数组会先结束,将剩下的数组的剩余数据依次补充进c[]就可以了
    while (i < n)
        c[k++] = a[i++];

    while (j < m)
        c[k++] = b[j++];
}

第二种思维:来源于书本,使用了递归:

1、从两个链表中找第一个节点,即比较两个链表头结点的数据值,假如链表 1 的第一个结点数据值小,那就把它作为新链表的头街点;

2、找第二个节点时,也是两个链表的头结点比较,此时链表 1 的头结点为上一步被取走结点的下一结点,链表 2 的头结点则还是原来链表的头结点。比较这两个 头结点,谁小 则取出并接在 新链表头结点后。

3、其他结点,依次类推。。。

其中第 2 步,我们可以发现,这里可以很方便的用 递归 的原理来解决。

以这种方法解决问题,需要有这样的前提:链表的第一个数据结点,即为头结点。(这与第一种思维的前提不同)

算法如下

/**第二种方法:使用递归,适合头结点就是第一个数据结点的链表表示方法*/
/**代码非常简洁,巧妙*/
ListNode * merge_tow_list2(ListNode *pHead1,ListNode *pHead2)
{
    if(NULL == pHead1)
        return pHead2;
    else if(NULL == pHead2)
        return pHead1;

    ListNode *pMergedHead = NULL;

    if(pHead1->m_nValue < pHead1->m_nValue)
    {
        pMergedHead = pHead1;
        pMergedHead->m_pNext = merge_tow_list2(pHead1->m_pNext,pHead2);
    }
    else
    {
        pMergedHead = pHead2;
        pMergedHead->m_pNext = merge_tow_list2(pHead1,pHead2->m_pNext);
    }

    return pMergedHead;
}

主函数如下:(这里只测试了,第一种方法的代码)

int main()
{
    int n_of_list1 = 6;
    int n_of_list2 = 3;
    int i = 1,j = 2;
    ListNode *pHead1,*pHead2,*pHead;
    pHead1 = creat_List();
    while(n_of_list1 > 0)
    {
        insert_Node_behind(pHead1,i);
        i += 2;
        n_of_list1--;
    }
    pHead2 = creat_List();
    while(n_of_list2 > 0)
    {
        insert_Node_behind(pHead2,j);
        j += 2;
        n_of_list2--;
    }
    show_List(pHead1);
    show_List(pHead2);

    pHead = merge_tow_list(pHead1,pHead2);
    show_List(pHead);

    return 0;
}

结果如下:(其他测试用例,可以改变主函数中的数据得到)

/*点滴积累,我的一小步O(∩_∩)O~*/

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-29 02:00:56

剑指offer_面试题17_合并两个排序的链表(两种思维)的相关文章

剑指offer面试题17——合并两个排序的链表

题目1519:合并两个排序的链表 题目描述: 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则.(hint: 请务必使用链表.) 输入: 输入可能包含多个测试样例,输入以EOF结束.对于每个测试案例,输入的第一行为两个整数n和m(0<=n<=1000, 0<=m<=1000):n代表将要输入的第一个链表的元素的个数,m代表将要输入的第二个链表的元素的个数.下面一行包括n个数t(1<=t<=1000000):代表链表一中的元素.接

剑指offer之面试题17合并两个排序的链表

问题描述: 输入两个递增的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的. 实现代码如下: #include <stdio.h> #include <stdlib.h> #include <stdbool.h> struct List{ int date; struct List *next; }; struct List* doMergeList(struct List *P1head,struct List *P2head){ if(P1head==NU

剑指offer 面试题17—合并两个排序的链表

题目: 输入两个递增排序的链表,合并这两个链表并使得新链表中的节点仍然是按照递增排序的. 基本思想: 当我们得到两个链表中值较小的头结点并把它连接到已经合并的链表之后,两个链表剩余的节点依然是排序的,因此合并的步骤和之前的而不周是一样的.这就是典型的递归的过程. #include <iostream> using namespace std; typedef int ElemType;//数据类型模板 typedef struct Node//结点 { ElemType data; struc

剑指Offer面试题15(Java版):链表中倒数第K个结点

题目: 输入一个链表,输出该链表中倒数第k哥结点. 为了符合大多数人的习惯,本题从1开始计数,即链表的尾结点是倒数第1个结点. 例如一个链表有6个结点,从头结点开始它们的值依次是1,2,3,4,5,6.这个链表的倒数第3个结点是值为4的结点 为了得到第K个结点,很自然的想法是先走到链表的尾端,再从尾端回溯K步.可是我们从链表结点的定义可疑看出本题中的链表 是单向链表,单向链表的结点只有从前往后的指针而没有从后往前的指针,因此这种思路行不通. 既然不能从尾节点开始遍历这个链表,我们还是把思路回到头

剑指offer_面试题14_调整数组顺序使奇数位于偶数前面(函数指针用法)

题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分. 1.一般想法,不考虑时间复杂度: 每次遍历数组,碰到一个偶数就拿出来,将后面所有数字向前挪动一位,在将该偶数放到最后. 2.利用冒泡排序的思想,两个指针,一前以后,如果前为偶数,后为奇数,就交换. 算法如下: void Reorder_array(int p[],int length) { if(NULL == p || length <= 0) return; int i

剑指Offer面试题7(Java版):用两个栈实现队列与用两个队列实现栈

题目:用两个栈实现一个队列.队列的声明如下,请实现它的两个函数appendTail和deletedHead,分别完成在队列尾部插入节点和在队列头部删除节点的功能. 我们通过一个具体的例子来分析该队列插入和删除元素的过程.首先插入一个元素a,不妨先把它插入到stack1,此时stack1 中的元素有{a},stack2为空.再压入两个元素b和c,还是插入到stack1中,此时stack1中的元素有{a,b,c},其中c位于栈顶,而stack2仍然为空. 这个时候,我们试着删除从队列中删除一个元素.

剑指offer_面试题3_二维数组中的查找(简单问题亦不能忽视)

题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样一个二维数组和一个整数,判断数组中是否含有该整数. 数组如下: 在该数组中查找一个整数隐含的几个规律: 1.在数组中选取一个数,如果与所查目标相等,那么查找结束 2.若所选数字,小于,要查找的目标,则要查找的目标应该在当前选取的位置的右边或者下边 3.若所选数字,大于,要查找的目标,则要查找的目标应该在当前选取的位置的左边或者上边 问题关键如何在该数组中选取整数? 答:在一行中,

剑指offer面试题38:数字在排序数组中出现的次数

题目描述: 统计一个数字在排序数组中出现的次数. 输入: 每个测试案例包括两行: 第一行有1个整数n,表示数组的大小.1<=n <= 10^6. 第二行有n个整数,表示数组元素,每个元素均为int. 第三行有1个整数m,表示接下来有m次查询.1<=m<=10^3. 下面有m行,每行有一个整数k,表示要查询的数. 输出: 对应每个测试案例,有m行输出,每行1整数,表示数组中该数字出现的次数. 样例输入: 81 2 3 3 3 3 4 513 样例输出: 4 //source:http

剑指offer——面试题38:数字在排序数组中出现的次数(利用二分查找来找第一次和最后一次的位置)

题目: 统计一个数字在排序数组中出现的次数. 思路: 因为是排好序的数组,所以可以采用二分查找的算法. 一般最容易想到的思路是采用二分查找先找到一个,然后往他左右两边遍历,但是这个方法由于在n个数组中还可能有n个k,所以 查找的复杂度还是O(n) 可以先用二分查找算法找到第一个出现的位置,即当找到一个时,看它前面一个是否也是k或者是否已经是查找这段的第一个了 然后同样用二分查找找最后一个出现的位置. 1 #include<iostream> 2 #include<vector> 3