【数据结构】A、B为递减有序的单链表,编写函数,将它们合并成递增有序的单链表,相同元素值只保留一个结点

1.算法思路

  1. 将两单链表合并,常用的方法是归并排序。每次比较两个链表的当前结点值,选择较大的结点值进行插入操作。
  2. 由于是将递减有序的链表变为递增有序的链表,那么可以考虑使用头插法,每次归并排序比较完成后将更大值的结点插入到已排序链表中,然后移动排序链表的头指针指向该结点。

2.定义结构体

typedef struct LNode {
    int data;
    struct LNode *next;
} LNode, *LinkList;

3.定义函数

3.1 创建单链表

编写函数创建单链表。输入参数为:

  • LinkList A: 单链表的头结点
  • int a[]: 该单链表的元素值
  • length: 元素值的长度
    当i < length时,循环创建结点,并使用尾插法将结点插入到当前链表的最后面,然后将链表尾指针移动至尾部,即当前结点。
void CreateList(LinkList A, int a[], int length) {
    LNode *s = (LNode *)malloc(sizeof(LNode));
    LNode *tail = A;
    s->next = NULL;
    for(int i=0; i < length; i++) {
        s = (LNode *)malloc(sizeof(LNode));//创建新结点
        s->data = a[i];
        s->next = NULL;
        tail->next = s;
        tail = tail->next;
    }
}

3.2 合并单链表

  1. 首先创建链表头结点C,它将指向已排好序的链表头结点,每次使用头插法插入新结点后都将指向此时的头结点,即新结点。
  2. 创建工作指针p,q分别指向A和B的首个数据结点。判断p,q是否为空。如果有链表为空,则返回NULL。这里假定两个链表都不为空时才进行排序,否则结束程序。
  3. 当p,q都不为空时,遍历A,B链表,比较结点值,进行如下判断:
    • p->data == q->data: 说明两结点值重复,因此选择删除一个结点,头插另一个结点。这里选择插入p结点而删除q结点。首先使用指针s只想当前结点p,然后将p结点向后移动,之后修改相应指针实现p的头插。然后将s指向q,并让q向后移动,再释放s。
    • p->data > q->data: 此时选择更大的结点即p将其插入到排序链表中,然后p后移,比较新的p和q。
    • p->data < q->data: 此时选择更大的结点即q将其插入到排序链表中,然后q后移,比较新的p和q。
  4. 当A或B遍历完成时,上述循环退出。此时判断p,q哪个指针为空。使用头插法将未空指针后面的剩余结点插入到排序链表。
LinkList MergeList(LinkList A, LinkList B) {
    //C用于指向以合并链表的头结点
    LinkList C = (LinkList)malloc(sizeof(LNode));
    C->next = NULL;
    //p,q用于遍历两个链表,s用于指向当前结点更大的结点
    LNode *p = A->next, *q = B->next, *s = NULL;
    if(!p || !q) {
        printf("链表为空!\n");
        return NULL;
    }
    while(p && q) {//p,q都不为空,开始比较
        if(p->data == q->data) {//p,q相等,删除一个结点
            //首先将一个结点头插到当前链表中
            s = p;
            p = p->next;
            s->next = C->next;
            C->next = s;
            //删除另一个结点
            s = q;
            q = q->next;
            free(s);
        }
        else {
            if(p->data > q->data) {//p的结点值更大,将s移到p
                s = p;
                p = p->next;
            } else{//q的结点值更大,将s移到q
                s = q;
                q = q->next;
            }
            s->next = C->next;
            C->next = s;
        }
    }
    while(p) {//当q为空时,将q剩下的进行头插法
        s = p;
        p = p->next;
        s->next = C->next;
        C->next = s;
    }
    while(q) {//当p为空时,将p剩下的进行头插法
        s = q;
        q = q->next;
        s->next = C->next;
        C->next = s;
    }
    return C->next;
}

4.测试结果

给出两组测试结果:

LinkList A = (LinkList)malloc(sizeof(LNode));
LinkList B = (LinkList)malloc(sizeof(LNode));
int a[] = {7,6,5,4,3,2,1};
int b[] = {9,5,3,1};
CreateList(A, a, sizeof(a) / sizeof(a[0]));
CreateList(B, b, sizeof(b) / sizeof(b[0]));

在这里插入图片描述

LinkList A = (LinkList)malloc(sizeof(LNode));
LinkList B = (LinkList)malloc(sizeof(LNode));
int a[] = {7,5,3,1};
int b[] = {7,5,3,1};
CreateList(A, a, sizeof(a) / sizeof(a[0]));
CreateList(B, b, sizeof(b) / sizeof(b[0]));

在这里插入图片描述

5.完整代码

#include <iostream>
using namespace std;

//定义结构体
typedef struct LNode {
    int data;
    struct LNode *next;
} LNode, *LinkList;

//合并两个递减链表并实现递增有序
LinkList MergeList(LinkList A, LinkList B) {
    //C用于指向以合并链表的头结点
    LinkList C = (LinkList)malloc(sizeof(LNode));
    C->next = NULL;
    //p,q用于遍历两个链表,s用于指向当前结点更大的结点
    LNode *p = A->next, *q = B->next, *s = NULL;
    if(!p || !q) {
        printf("链表为空!\n");
        return NULL;
    }
    while(p && q) {//p,q都不为空,开始比较
        if(p->data == q->data) {//p,q相等,删除一个结点
            //首先将一个结点头插到当前链表中
            s = p;
            p = p->next;
            s->next = C->next;
            C->next = s;
            //删除另一个结点
            s = q;
            q = q->next;
            free(s);
        }
        else {
            if(p->data > q->data) {//p的结点值更大,将s移到p
                s = p;
                p = p->next;
            } else{//q的结点值更大,将s移到q
                s = q;
                q = q->next;
            }
            s->next = C->next;
            C->next = s;
        }
    }
    while(p) {//当q为空时,将q剩下的进行头插法
        s = p;
        p = p->next;
        s->next = C->next;
        C->next = s;
    }
    while(q) {//当p为空时,将p剩下的进行头插法
        s = q;
        q = q->next;
        s->next = C->next;
        C->next = s;
    }
    return C->next;
}

//创建单链表
void CreateList(LinkList A, int a[], int length) {
    LNode *s = (LNode *)malloc(sizeof(LNode));
    LNode *tail = A;
    s->next = NULL;
    for(int i=0; i < length; i++) {
        s = (LNode *)malloc(sizeof(LNode));//创建新结点
        s->data = a[i];
        s->next = NULL;
        tail->next = s;
        tail = tail->next;
    }
}

int main() {
    //创建单链表
    LinkList A = (LinkList)malloc(sizeof(LNode));
    LinkList B = (LinkList)malloc(sizeof(LNode));
    int a[] = {7,6,5,4,3,2,1};
    int b[] = {9,5,3,1};
    CreateList(A, a, sizeof(a) / sizeof(a[0]));
    CreateList(B, b, sizeof(b) / sizeof(b[0]));
    LinkList p = A->next;
    //打印查看原始数据
    printf("A链表的数据为:\n");
    while(p) {
        printf("%d\t", p->data);
        p = p->next;
    }
    printf("\n");
    p = B->next;
    printf("B链表的数据为:\n");
    while(p) {
        printf("%d\t", p->data);
        p = p->next;
    }
    printf("\n");
    //获取合并后的链表
    LinkList q = MergeList(A, B);
    //打印输出
    printf("修改后链表的数据为:\n");
    while(q) {
        printf("%d\t", q->data);
        q = q->next;
    }
    return 0;
}
  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

每天进步一点丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值