已有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);/*排序完成,输出链表*/
}