#include<stdio.h>
#include<malloc.h>
#define LEN sizeof(struct Student)
struct Student //结构体声明
{
long num;
int score;
struct Student* next;
};
int n;
struct Student* creat() //创建单向链表
{
struct Student *head=NULL, *p_before, *p_later;
p_before = p_later = (struct Student*) malloc(LEN);
scanf_s("%ld%d", &p_before->num, &p_before->score);
while (p_before->num!=0)
{
n++;
if (n == 1)
head = p_before;
else
p_later->next = p_before;
p_later = p_before;
p_before = (struct Student*) malloc(LEN);
scanf_s("%ld%d", &p_before->num, &p_before->score);
}
p_later->next = NULL;
free(p_before);
return head;
}
struct Student* sort(struct Student* list) //冒泡排序,
{
struct Student *p, *q;
int temp1,i;
long temp2;
for (p = list, i =1; i < n;i++,p=p->next)
for (q = p->next;q!= NULL;q=q->next)
if (p->score < q->score)
{
temp1 = p->score;
p->score = q->score;
q->score = temp1;
temp2 = p->num;
p->num = q->num;
q->num = temp2;
}
return list;
}
struct Student* sort1(struct Student* h) //插入排序
{
struct Student *f, *t, *p=NULL, *q;
f = h->next;
h->next = NULL;
while (f!=NULL)
{
for (t = f, q = h; (q != NULL && (q->score > t->score)); p = q, q = q->next);
f = f->next; //在进行插入操作前,先使f后移
if (q == h) h = t; //如果当前新链的头节点关键值比f(即t)所指节点关键值小,需要将f(即t)所指节点插在该头节点前,先让新链头节点指针指向
//f(即t)所指节点,作为新链的新的头节点
else p->next = t; //否则,将f(即t)所指节点连在p所指节点后
t->next = q; //不管if还是else,都需要将f(即t)所指节点连在q所指节点前,如果q=NULL,就是让f(即t)所指节点的next域指向NULL,这显然也是正确的
}
return h; //返回新链(排好序的链)的头节点指针
}
struct Student* sort2(struct Student* h) //选择排序
{
struct Student *f=NULL,*t=NULL, *max, *maxbf=NULL, *p;
while (h!=NULL)
{
for (p = h, max = h; p->next != NULL; p = p->next)
{
if (p->next->score > max->score)
{
maxbf = p;
max = p->next;
}
}
if (f==NULL)
{
f = max;
t = max;
}
else
{
t->next = max;
t = max;
}
if (max==h)
{
h = h->next;
}
else
{
maxbf->next = max->next;
}
}
t->next = NULL;
return f;
}
struct Student* sort3(struct Student* h) //这是什么排序呢?我也说不好。这是我自己想出来的算
{ //法……大体思想是:先从链表第一个结点开始遍历链表,找出关键值(这里是成绩score)最大的(因为
struct Student *p, *q, *pt=NULL, *pbf=NULL, *qbf=NULL; //是从大到小排序)结点和链表中第一个结点交换(利用指针实现);然后,从链表中第二个结点开始遍历链
for (p = h ; p->next!=NULL; pbf = p, p = p->next) //表,找出关键值最大的结点和链表中第二个结点交换……如此操作,直到从链表中最后一个结点开始的那趟
{ //遍历和操作结束
for (q = p; q->next != NULL;q=q->next) //代码格式很不好,写这段代码时在下还很渣很渣……粘贴到这里时,就更不好看了……对不起大家了
{
if (p->score < q->next->score)
{
qbf = q; q = q->next;
if (p==h && p->next==q)
{
h = q; p->next = q->next; q->next = p; p = q;
}
else
{
if (p == h&&p->next != q)
{
h = q; pt = q->next; q->next = p->next, qbf->next = p; p->next = pt; p = q; q = qbf;
}
else
{
if (p != h && p->next == q)
{
pt = q->next; pbf->next = q; q->next = p; p->next = pt; p = q;
}
else
{
if (p != h && p->next != q)
{
pt = q->next; pbf->next = q; q->next = p->next; qbf->next = p; p->next = pt; p = q; q = qbf;
}
}
}
}
}
}
}
return h;
}
//快排 这里在下也参考了网上的代码,但在下也着实进行了一番改进才编译通过,这里使用了指针的指针,不详细讲了,大家自己分析吧
struct Student* Link_Quick_Sort(struct Student ** head, struct Student ** end) // 注意这里函数返回值可以写成void,同时将return语句去掉,
{ //同时,将main函数中(1)(2)两句改为:
struct Student * big_head=NULL, *big_end=NULL, *small_head=NULL, *small_end=NULL; //Link_Quick_Sort(&pt, NULL);
struct Student * big_tail=NULL, *small_tail = NULL; //for (p=pt, i = 1; i <= n; i++, p = p->next)
int key = (*head)->score; //也是可以的。原因是递归是先进后出,后进先出,二第一次调用时传的是&pt(见main函数中
struct Student * traversal = (*head)->next; //第(1)句),故当整个函数结束后,pt的值已修改,且指向排好序的链表的头结点。
(*head)->next = NULL;
struct Student *p = NULL;
while (traversal != NULL)
{
if (traversal->score > key)
{
if (big_head == NULL) { big_head = traversal; big_tail = traversal; }
else{ big_tail->next = traversal; big_tail = traversal; }
traversal = traversal->next;
big_tail->next = NULL;
}
else
{
if (small_head == NULL) { small_head = traversal; small_tail = traversal; }
else{ small_tail->next = traversal; small_tail = traversal; }
traversal = traversal->next;
small_tail->next = NULL;
}
}
big_end = big_tail; small_end = small_tail;
if (big_head != NULL && big_head->next != NULL){ Link_Quick_Sort(&big_head, &big_end); }
if (small_head != NULL && small_head->next != NULL){ Link_Quick_Sort(&small_head, &small_end); }
if (big_end != NULL&&small_head != NULL)
{
big_end->next = (*head);
(*head)->next = small_head;
(*head) = big_head;
if (end == NULL){ end = &p; }
(*end) = small_end;
}
else if (big_end!=NULL)
{
big_end->next = (*head);
if (end == NULL){ end = &p; }
(*end) = (*head);
(*head) = big_head;
}
else if (small_head!=NULL)
{
(*head)->next = small_head;
if (end == NULL){ end = &p; }
(*end) = small_end;
}
return (*head);
}
void main() //用main函数来测试
{
printf("请依次输入学生的学和姓名\n");
printf("学号和姓名间以空格隔开\n");
printf("输入0 0结束\n");
struct Student* pt,*p;
struct Student* creat();
struct Student* sort(); //这里调用的是冒泡排序,要想调用其它排序,在这里改一下函数调用就可以了
pt=creat();
int i;
for ( p=pt,i = 1; i <=n; i++,p=p->next)
printf("num=%ld score=%d\n", p->num, p->score);
printf("排序后:\n");
p=Link_Quick_Sort(&pt, NULL); //(1)
for ( i = 1; i <= n; i++, p = p->next)//(2)
printf("第%d名: num=%ld score=%d\n",i, p->num, p->score);
}
C语言 单向链表 及其排序
最新推荐文章于 2025-08-04 22:09:49 发布
