C语言:将两个非递减的有序链表合并为一个非递增的有序链表。结果链表仍使用原来两个链表的存储空间, 不另外占用其它的存储空间

将两个非递减的有序链表合并为一个非递增的有序链表。要求结果链表仍使用原来两个链表的存储空间, 不另外占用其它的存储空间。表中允许有重复的数据,并输出每一步从哪取下了什么元素


完整代码如下:

#include<stdio.h>
#include<stdlib.h>
typedef struct link{		//定义链表
        int data;
        struct link *next;
}link;
link * initLink(int n){         //初始化链表,确定长度,输入数据
        link *p,*q;
        printf("依次输入数据:");
        for(int i=1;i<=n;i++){
                link *temp=(link*)malloc(sizeof(link));         //动态分配内存
                scanf("%d",&temp->data);        //填充数据
                temp->next=NULL;      //最后一个节点指针NULL
                if(i==1){
                        q=temp;         //给q,p赋值第一个结点
                        p=temp;
                }
                else{           //形成一条p链
                        p->next=temp;   //p陆续指向后边的结点
                        p=p->next;      //p移动到最后
                }
        }
        return q;
}
link * mergeList(link *a,link *b){      //合并两条传入的链表
        link *o,*p,*q;      //这里p中转,o指向最后一个元素,q指向最新元素
        int i=1;                //第一次合并使用
        while (a||b){
                if(!a){         //a空了,直接指向b的结点
                        printf("从b取下%d\n",b->data);
                        p=b;
                        b=b->next;
                }               //b空了或者a的数据<=b的数据时,指向a的结点
                else if(!b||a->data<=b->data){
                        printf("从a取下%d\n",a->data);
                        p=a;
                        a=a->next;
                }               //此处可和上面的合并
                else {
                        printf("从b取下%d\n",b->data);
                        p=b;
                        b=b->next;
                }
                if(i==1){

                        o=q=p;          //初始化指针
                        i++;            //使用一次舍弃
                }
                else {
                        p->next=q;        //使取下的结点连上合并后的链
                        q=p;              //更新q的位置到最新结点
                }
        }
        o->next=NULL;   //使最后一个指向NULL输出结束条件
        free(b);        //a,b,q的空间可以释放
        free(a);
        return q;
}
int main(){
        int m,n;                //记录a,b的长度
        printf("第一个链表的长度:");
        scanf("%d",&m);
        link *a = initLink(m);  //初始化a
        printf("第二个链表的长度:");
        scanf("%d",&n);
        link *b = initLink(n);  //初始化b
        link *c = mergeList(a,b);//合并a,b
        printf("合并链(非递增):");
        while(c){
                printf("%d ",c->data);
                c=c->next;
        }
        return 0}

--------------------------------------------------分隔线------------------------------------------

由于最近数据结构课布置了这个作业,并且知识一知半解(练习少了),所以百度找了一些代码看,然后搞了七八个小时弄出来下面的代码

#include<stdio.h>
#include<stdlib.h>
typedef struct link{		//定义链表
        int data;
        struct link *next;
}link;
link * initLink(int n){         //初始化链表,确定长度,输入数据
        link *p,*q;
        printf("依次输入数据:");
        for(int i=1;i<=n;i++){
                link *temp=(link*)malloc(sizeof(link));         //动态分配内存
                scanf("%d",&temp->data);        //填充数据
                temp->next=NULL;      //最后一个节点指针NULL
                if(i==1){
                        q=temp;         //给q,p赋值第一个结点
                        p=temp;
                }
                else{           //形成一条p链
                        p->next=temp;   //p陆续指向后边的结点
                        p=p->next;      //p移动到最后
                }
        }
        return q;
}
link * mergeList(link *a,link *b){      //合并两条传入的链表
        link *p,*q;                     //p指向合并链表第一个元素
        q=(link*)malloc(sizeof(link));  //q:使合并链的最后一个元素为NULL
        q->next=NULL;
        int i=1;
        while (a||b){
                if(!a){         //a空了,直接指向b的结点
                        printf("从b取下%d\n",b->data);
                        p=b;
                        b=b->next;
                }               //b空了或者a的数据<=b的数据时,指向a的结点
                else if(!b||a->data<=b->data){
                        printf("从a取下%d\n",a->data);
                        p=a;
                        a=a->next;
                }
                else {
                        printf("从b取下%d\n",b->data);
                        p=b;
                        b=b->next;
                }
                p->next=q->next;        //使取下的结点连上合并后的链
                q->next=p;              //更新合并后的链
        }
        free(b);        //a,b,q的空间可以释放
        free(a);
        return p;
}
int main(){
        int m,n;                //记录a,b的长度
        printf("第一个链表的长度:");
        scanf("%d",&m);
        link *a = initLink(m);  //初始化a
        printf("第二个链表的长度:");
        scanf("%d",&n);
        link *b = initLink(n);  //初始化b
        link *c = mergeList(a,b);//合并a,b
        printf("合并链(非递增):");
        while(c){
                printf("%d ",c->data);
                c=c->next;
        }
        return 0}

可是有一个地方我一直觉得有问题(由于基础不扎实),合并链表中我觉得好像不符合题意:不另外占用其它的存储空间。

在这里插入图片描述

这里给q分配空间我也不太知道违背题意没,但不太放心,于是我把mergeList函数做了一些修改(可以对比上面的代码):

link * mergeList(link *a,link *b){      //合并两条传入的链表
        link *p,*q;                     //p指向合并链表第一个元素
        //q=(link*)malloc(sizeof(link));  //q:使合并链的最后一个元素为NULL
        //q->next=NULL;
        int i=1;                //第一次合并使用
        while (a||b){
                if(!a){         //a空了,直接指向b的结点
                        printf("从b取下%d\n",b->data);
                        p=b;
                        b=b->next;
                }               //b空了或者a的数据<=b的数据时,指向a的结点
                else if(!b||a->data<=b->data){
                        printf("从a取下%d\n",a->data);
                        p=a;
                        a=a->next;
                }               //此处可和上面的合并
/*              else if(a->data<=b->data){
                        printf("从a取下%d\n",a->data);
                        p=a;
                        a=a->next;
                }               //b的数据<a的数据时,指向b的结点(不可与!a合并
*/              else {
                        printf("从b取下%d\n",b->data);
                        p=b;
                        b=b->next;
                }
                if(i==1){
                        q=p;
                        q->next=p;
                        i++;            //使用一次舍弃
                }
                else {
                        p->next=q->next;        //使取下的结点连上合并后的链
                        q->next=p;              //更新合并后的链
                }
        }
        free(b);        //a,b,q的空间可以释放
        free(a);
        free(q);
        return p;
}

但是有问题,就是第一个元素的合并有一些问题,输出的是一些乱码
在这里插入图片描述
代码总体上不够完善,如果有大佬有好的建议或者可以解决后面这个问题欢迎指导。
(@ο@)
终于实现了不占用其他存储空间了,之前的代码确实不符合题意
所以更新代码为(只需要更换mergeList函数的代码)如下:

link * mergeList(link *a,link *b){      //合并两条传入的链表
        link *o,*p,*q;      //这里p中转,o指向最后一个元素,q指向最新元素
        int i=1;                //第一次合并使用
        while (a||b){
                if(!a){         //a空了,直接指向b的结点
                        printf("从b取下%d\n",b->data);
                        p=b;
                        b=b->next;
                }               //b空了或者a的数据<=b的数据时,指向a的结点
                else if(!b||a->data<=b->data){
                        printf("从a取下%d\n",a->data);
                        p=a;
                        a=a->next;
                }               //此处可和上面的合并
                else {
                        printf("从b取下%d\n",b->data);
                        p=b;
                        b=b->next;
                }
                if(i==1){

                        o=q=p;          //初始化指针
                        i++;            //使用一次舍弃
                }
                else {
                        p->next=q;        //使取下的结点连上合并后的链
                        q=p;              //更新q的位置到最新结点
                }
        }
        o->next=NULL;   //使最后一个指向NULL输出结束条件
        free(b);        //a,b,q的空间可以释放
        free(a);
        return q;
}

唉,一个题搞了可能有十多个小时,被指针的引用弄得晕头转向,逻辑思维不行,以后得训练训练。望各位学好数学(真心觉得数学不好太吃亏了),不然容易绕圈转,浪费太多时间。

假设两个递减有序链表分别为A和B,可以按照以下步骤合并它们: 1. 定义三个指针,分别指向A的当前节点、B的当前节点和A的前一个节点,初始时A和B的当前节点都指向链表头,A的前一个节点为NULL。 2. 从A和B中选择较小的节点,将其接到A的前一个节点后面。 3. 将A的前一个节点指向新加入的节点。 4. 将A的当前节点指向下一个节点,B的当前节点指向下一个节点。 5. 重复步骤2-4,直到A和B中任意一个链表为空。 6. 如果A链表已经为空,则将B链表剩余的节点全部接到A链表的前面。 7. 将A链表反转,得到一个递增有序链表。 下面是具体的C语言实现代码: ```c #include <stdio.h> #include <stdlib.h> // 定义链表节点结构体 typedef struct Node { int val; struct Node* next; } Node; // 将链表反转 Node* reverse(Node* head) { Node *p, *q, *r; p = head; q = NULL; while (p != NULL) { r = p->next; p->next = q; q = p; p = r; } return q; } // 将两个递减有序链表合并一个递增有序链表 void merge(Node* A, Node* B) { Node *pa, *pb, *prev; pa = A->next; pb = B->next; prev = A; while (pa != NULL && pb != NULL) { if (pa->val <= pb->val) { prev->next = pa; prev = pa; pa = pa->next; } else { prev->next = pb; prev = pb; pb = pb->next; } } if (pb != NULL) { prev->next = pb; } A->next = reverse(A->next); } int main() { // 构造两个递减有序链表 Node* A = (Node*)malloc(sizeof(Node)); A->next = NULL; Node* B = (Node*)malloc(sizeof(Node)); B->next = NULL; Node* p = A; Node* q = B; int a[] = {1, 3, 5, 7, 9}; int b[] = {2, 4, 6, 8, 10}; int i; for (i = 0; i < 5; i++) { p->next = (Node*)malloc(sizeof(Node)); p = p->next; p->val = a[i]; p->next = NULL; q->next = (Node*)malloc(sizeof(Node)); q = q->next; q->val = b[i]; q->next = NULL; } // 合并两个链表并输出结果 merge(A, B); Node* r = A->next; while (r != NULL) { printf("%d ", r->val); r = r->next; } printf("\n"); return 0; } ``` 上述代码中,我们首先定义了一个链表节点结构体,然后按照题目要求,构造了两个递减有序链表A和B,接着调用merge函数将它们合并为一个递增有序链表,并最终输出合并后的结果。在merge函数中,我们分别用pa和pb指向A和B的当前节点,prev指向A的前一个节点。从A和B中选择较小的节点,将其接到A的前一个节点后面,然后将A的前一个节点指向新加入的节点,将A的当前节点指向下一个节点,B的当前节点指向下一个节点。重复这个过程,直到A和B中任意一个链表为空。如果A链表已经为空,则将B链表剩余的节点全部接到A链表的前面。最后调用reverse函数将A链表反转,得到一个递增有序链表
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值