将两个非递减的有序链表合并为一个非递减的有序链表(利用原来两个链表的存储空间,表中不允许有重复数据)

题目

将两个非递减的有序链表合并为一个非递减的有序链表。
(要求利用原来两个链表的存储空间,不另外占用其他空间,表中不允许有重复数据)

这是福宝第一次写数据结构的作业(只学了一个月),部分注释可能不准确,还烦请大家指出来!另外,初版代码写完后,我发现要实现无重复,最好在排序结束后就把单个链表中重复的结点删掉。否则分情况讨论复杂到了一定境界,真的让人崩溃。后面还会有逆序版的解答,大家也可以参考一下。


代码

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <ctime>

/*****自定义结构*****/
struct Node // 单链表的结点
{
    int data;          // 存放在结点中数据的类型,在本题中为整型
    struct Node *next; // 存放后继结点的内存地址
};
typedef struct Node Node;      // 【自己的理解】重命名struct Node为Node
typedef struct Node *LinkList; // 【自己的理解】重命名struct Node *为LinkList
/*****自定义结构*****/

/*****随机生成一个长度为l的单链表(未排序并且有头结点)*****/
LinkList List_TailInsert(int l, LinkList &L)
{
    int k = 1;
    int x = 0;
    L = (LinkList)malloc(sizeof(Node)); // 创建头结点
    LinkList s;
    LinkList r = L; // r为表尾指针
    // srand(time(0));//放在这一行会导致两组随机数差不多
    while (k <= l)
    {
        x = rand() % 101;
        s = (LinkList)malloc(sizeof(Node)); // 由系统生成一个Node型的结点,同时将该结点的起始位置赋值给指针变量s
        s->data = x;
        r->next = s;
        r = s;
        k = k + 1;
        printf("%d ", x);
    }
    r->next = NULL;
    printf("\n");
    return L;
}
/*****随机生成一个长度为l的单链表(未排序并且有头结点)*****/

/*****对单链表进行冒泡排序(结合了输出功能)*****/
LinkList BubbleSort(LinkList &L)
{
    LinkList pa, pb, pc;
    int c = 0;
    pa = L->next;
    pb = L->next->next;
    pc = L->next;
    int j = 1;

    /***求链表长度***/
    int l = 0;
    while (pc != NULL)
    {
        l = l + 1;
        pc = pc->next;
    }
    /***求链表长度***/

    while (j < l)
    {
        if (pa->data > pb->data)
        {
            c = pb->data;
            pb->data = (int)pa->data;
            pa->data = c;
            j = 1;
        }
        else
        {
            j = j + 1;
        }
        pb = pb->next;
        pa = pa->next;
        if (pa->next == NULL && j != l)
        {
            j = 1;
            pa = L->next;
            pb = L->next->next;
        }
    }
    pc = L->next;
    while (pc != NULL)
    {
        printf("%d ", pc->data);
        pc = pc->next;
    }
    printf("\n");
    return L;
}
/*****对单链表进行冒泡排序(结合了输出功能)*****/

/*****核心功能函数1:排序后单链表删重函数optimize*****/
LinkList opt(LinkList &L)
{
    LinkList p0, p1;
    p0 = L->next;
    p1 = p0->next;
    while (p1 != NULL)
    {
        if (p0->data != p1->data)
        {
            p0 = p0->next;
            p1 = p1->next;
        }
        else
        {
            p1 = p1->next;
            p0->next = p1;
        }
    }
    return L;
}
/*****核心功能函数1:排序后单链表删重函数optimize*****/

/*****核心功能函数2:归并链表*****/
LinkList MergeList(LinkList &La, LinkList &Lb) // 【自己的理解】LinkList &La就是La头结点的内存地址,也就是头指针
                                               // 通常用头指针来标识一个单链表
{
    LinkList pa, pb, pc, q; // LinkList是自定义的指针类型
    pa = La->next;          // 把单链表A头结点的指针【域】赋给pa
    pb = Lb->next;          // 把单链表B头结点的指针【域】赋给pb
    pc = La;                // 初始化pc,防止pc变成野指针,同时将pc作为链表合并后新的头节点
                            // 此时新头节点pc在La,pc作为pa的前驱节点链接pa
                            // pc作为pa的前驱节点,意义在于游标

    while (pa != NULL && pb != NULL) // La和Lb任意一条链表为空时跳出while循环
    {
        if (pa->data < pb->data) // 如果pa的值小于pb,则pb不插入,pb不动,pa前进
        {
            pc->next = pa;
            pc = pa;
            pa = pa->next; // 插入pa以后,pa前进,剩下的结点和La看作整体进行比较
        }
        else if (pa->data > pb->data) // 若pa的值大于pb,则需要把pb插在pa的前边
        {
            pc->next = pb;
            pc = pb;
            pb = pb->next; // 插入pb以后,pb前进,剩下的结点和Lb看作整体进行比较
        }
        else // 如果pa的值小于pb,则pb不插入,pb前进,pa前进
        {
            pc->next = pa;
            pc = pa;
            pa = pa->next;
            q = pb;
            pb = pb->next;
            free(q);
        }
    }

    pc->next = pa ? pa : pb; // 插入剩余结点,由于之前删重了,所以不会有重复的元素

    free(Lb);
    return La;
}
/*****核心功能函数2:归并链表*****/

/*****主函数*****/
int main()
{
    /*生成两个乱序的单链表,这里规定了第一个长度为12,第二个长度为8*/
    LinkList La = NULL;
    LinkList Lb = NULL;
    srand(time(0));
    printf("  生成的第一个单链表:");
    List_TailInsert(12, La);
    printf("  生成的第二个单链表:");
    List_TailInsert(8, Lb);

    /*对两个链表进行排序(结合了输出功能)*/
    printf("排序后的第一个单链表:");
    La = BubbleSort(La);
    printf("排序后的第二个单链表:");
    Lb = BubbleSort(Lb);

    /*对排序后的单链表进行优化(删除单链表中的重复数据)*/
    La = opt(La);
    Lb = opt(Lb);

    /*执行功能函数*/
    La = MergeList(La, Lb);

    /*输出符合题意的单链表*/
    printf("按题意处理后的单链表:");
    LinkList pp = La->next;
    while (pp != NULL)
    {
        printf("%d ", pp->data);
        pp = pp->next;
    }
    printf("\n");

    system("pause"); // 防止运行后自动退出,需头文件【stdlib.h】
}
/*****主函数*****/

感想

功能函数初稿写完的时候,我以为已经很完善了。但在强迫自己写了生成随机链表和冒泡排序的代码,并经过了大量测试以后,我发现功能函数初稿实在有很多问题,比如重复的去不干净、死循环、临界点顺序错误、非法内存地址空间、结果漏结点……

经过了好几个小时的打磨之后,这份代码终于算是差强人意了!

建议大家解这道题的时候一定要写好生成随机链表和排序的函数,只有大量的测试才能击溃你的骄傲找到代码的问题。

  • 5
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值