题目 1052: [编程入门]链表合并

文章描述了一个编程问题,涉及两个链表的合并与排序。链表中的节点包含学号和成绩,目标是将两个链表按学号升序合并。程序通过创建链表、排序链表(使用选择排序)和输出链表数据来实现这一功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

已有a、b两个链表,每个链表中的结点包括学号、成绩。要求把两个链表合并,按学号升序排列。

输入格式
第一行,a、b两个链表元素的数量N、M,用空格隔开。 接下来N行是a的数据 然后M行是b的数据 每行数据由学号和成绩两部分组成

输出格式
按照学号升序排列的数据

样例输入
2 3
5 100
6 89
3 82
4 95
2 10
样例输出
2 10
3 82
4 95
5 100
6 89

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

/*typedef 本质就是重命名函数*/
/* struct student 是一个结构体类型*/
typedef struct student{
    double number;
    double grade;
    struct student *next;/*指向下一个struct student类型的指针变量next*/
}*node, Node; 
/*其中,node是一个指向struct student类型的指针,而Node是一个结构体类型,它与struct student等价。
  因此,可以用node定义一个指针变量,如node p=NULL;或者用Node定义一个结构体变量。如Node s = {1,90,NULL}*/ 

/* typedef struct student *node,Node的意思是:
   把struct student*这个指针类型重命名为node和Node两个新的名字,
   也即是说,node和Node都是指向struct student类型的指针————node类型的变量
   可以指向一个包含number,grade和next成员的结构体。*/

node create(int n); /*创建链表函数*/

void output(node l);/*输出函数*/

void order(node l1, node l2);/*排序函数*/

// 本质上还挺简单的,就是一个初始化,一个排序,一个输出。
int main(){
    int n,m; /*a,b,前n行是a的,后m行是b的*/
    scanf("%d%d",&n,&m);
    node head1,head2;
    head1 = create(n); /*创建链表a*/
    head2 = create(m); /*创建链表a*/
    order(head1,head2);
    return 0;
}

// 节点是数据结构中的基本单元,用于存储元素数据以及与其他节点的链接关系。
/*创建链表函数*/
node create(int n){
    node h; /*头节点指针*/
    h = (node)malloc(sizeof(Node)); /*创建头节点*/
    h->next = NULL; /*next指针域赋空*/
    node q = h; /*定义指针q,q和h都指向同一个struct student对象*/
    node p;
    /*p是一个指针,指向struct student类型。
    p相较*p而言:
    1. p是一个指针,它存储的是一个地址,也就是指向的对象的地址;
    2. *p是一个结构体,它是p所指向的对象,也就是一个struct student对象。
    3. *p包含三个成员:number,grade和next。*/

    /*创建n个节点*/
    for(int i=0;i<n;i++){
        p = (node)malloc(sizeof(Node));
        scanf("%lf%lf",&(*p).number,&(*p).grade);/*输入学号、成绩*/
        /*采用后差法插入节点*/
        p->next = q->next; /*将p的next指向q的next,也就是将p插入到q和q->next之间*/
        q->next = p;/*将q的next指针设为p,也是在说明p插入到q和q-next之间*/
        q = p;/*将q指向p,也就是让q指向新插入的节点p,最后一次声明"关系"*/
    }
    return h; /*返回头节点,头节点不存储任何信息,他的作用是标识链表的起始位置*/
}
/*输出函数:实现对链表所有节点的输出,并释放表中所有节点的内存空间*/
// 链表是一种数据结构,由一系列的节点组成,每个节点都有指向下一个节点的指针。
void output(node l){
    // 将链表的起始节点l的next指针赋值给l,即跳过头节点,从第一个存储学生数据的节点开始遍历链表
    l = l->next; /*让l指向它的下一个节点,通常用于遍历链表*/
    node q; /*用于释放节点。声明了一个node类型的变量q,用于暂存当前节点*/
    // 从头节点之后的第一个节点开始遍历链表
    while(l!=NULL){
        printf("%0.0f %0.0f\n",l->number,l->grade);
        q = l; /*q指向l*/
        l = l->next; /*l指向下一个节点*/
        free(q); /*释放q所指向的内存空间*/
    }
    // 循环结束后,链表中所有的节点都已经被释放,链表不在存在。
}
/*排序函数
接受两个参数:待排序的两个链表l1和l2;*/
void order(node l1,node l2){
    node q; /*定义指针q*/
    q = l1; /*将l1的起始节点赋给了q,即q指向l1(表a)的头节点*/
    l2 = l2->next; /*表b的头节点下移*/
    
    /*让q指向表a的最后一个节点,用于将链表l2插入到链表l1的末尾*/
    while(q->next != NULL){
        q = q->next;
    }

    q->next=l2; /*表a的最后一个节点的指针域指向l2(表b)的起始节点(即跳过头节点,从第一个储存学生数据的节点开始),完成连接*/ 
    q = l1->next; /*再次把q指向表a的第一个节点,即跳过头节点,从第一存储学生数据的节点开始*/
    node min; /*定义指向最小学号节点的指针*/

    int t; /*保存最小学号的变量*/
    int n,g; /*交换学号、成绩的中间变量*/
    node p; /*定义指针p,用于中间遍历求最小学号*/

    /*开始遍历,选择排序最外层
    从节点q开始遍历链表l1,每次找到链表中学号最小的节点,并将其与当前节点进行交换
    ps:选择排序的基本思想是选择未排序部分的最小(或最大)元素,并将其与未排序部分的第一个元素进行交换。
    在这个函数中,选择排序的实现是对链表中的每个元素进行扫描,找到最小的元素并将其与当前元素交换。*/
    while(q!=NULL){
        p = q; /*p等于查找的第一个节点q*/
        // t是值,用于比较;min是指针,指向节点。
        t = p->number; /*让t等于开始查找的第一个节点的学号*/
        min = p; /*最小学号节点指针指向p*/
        /*从节点p向后遍历*/
        while(p!=NULL){
            if(p->number<t){
                t = p->number; /*记录最小学号*/
                min = p; /*记录最小学号节点*/
            }
            p = p->next; /*遍历p的下一个节点*/
        }

        /*最小学号节点的学号与第一个节点的学号交换*/
        n = q->number; /*n等于第一个节点的学号*/ 
        q->number = min->number; 
        min->number = n;

        /*同理,把成绩也交换了,排序思路为选择排序*/
        g = q->grade;
        q->grade = min->grade;
        min->grade = g;

        /*第一遍排序完后,q后移,也就是选择排序开始排第二遍时的第一个数*/
        q = q->next;
    }
    output(l1);/*排序完成,输出链表*/
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值