C语言 用链表对学号进行排序,求解C语言中建立一个对链表按照学号进行排序的问题...

==========================

功能:选择排序(由小到大)

返回:指向链表表头的指针

==========================

*/

/*

选择排序的基本思想就是反复从还未排好序的那些节点中,

选出键值(就是用它排序的字段,我们取学号num为键值)最小的节点,

依次重新组合成一个链表。

我认为写链表这类程序,关键是理解:

head存储的是第一个节点的地址,head->next存储的是第二个节点的地址;

任意一个节点p的地址,只能通过它前一个节点的next来求得。

单向链表的选择排序图示:

---->[1]---->[3]---->[2]。

。。---->[n]---->[NULL](原链表)

head 1->next 3->next 2->next n->next

---->[NULL](空链表)

first

tail

---->[1]---->[2]---->[3]。

。。---->[n]---->[NULL](排序后链表)

first 1->next 2->next 3->next tail->next

图10:有N个节点的链表选择排序

1、先在原链表中找最小的,找到一个后就把它放到另一个空的链表中;

2、空链表中安放第一个进来的节点,产生一个有序链表,并且让它在原链表中分离出来(此时要注意原链表中出来的是第一个节点还是中间其它节点);

3、继续在原链表中找下一个最小的,找到后把它放入有序链表的尾指针的next,然后它变成其尾指针;

*/

struct student *SelectSort(struct student *head)

{

struct student *first; /*排列后有序链的表头指针*/

struct student *tail; /*排列后有序链的表尾指针*/

struct student *p_min; /*保留键值更小的节点的前驱节点的指针*/

struct student *min; /*存储最小节点*/

struct student *p; /*当前比较的节点*/

first = NULL;

while (head != NULL) /*在链表中找键值最小的节点。

*/

{

/*注意:这里for语句就是体现选择排序思想的地方*/

for (p=head,min=head; p->next!=NULL; p=p->next) /*循环遍历链表中的节点,找出此时最小的节点。*/

{

if (p->next->num num) /*找到一个比当前min小的节点。

*/

{

p_min = p; /*保存找到节点的前驱节点:显然p->next的前驱节点是p。*/

min = p->next; /*保存键值更小的节点。*/

}

}

/*上面for语句结束后,就要做两件事;一是把它放入有序链表中;二是根据相应的条件判断,安排它离开原来的链表。

*/

/*第一件事*/

if (first == NULL) /*如果有序链表目前还是一个空链表*/

{

first = min; /*第一次找到键值最小的节点。*/

tail = min; /*注意:尾指针让它指向最后的一个节点。

*/

}

else /*有序链表中已经有节点*/

{

tail->next = min; /*把刚找到的最小节点放到最后,即让尾指针的next指向它。*/

tail = min; /*尾指针也要指向它。*/

}

/*第二件事*/

if (min == head) /*如果找到的最小节点就是第一个节点*/

{

head = head->next; /*显然让head指向原head->next,即第二个节点,就OK*/

}

else /*如果不是第一个节点*/

{

p_min->next = min->next; /*前次最小节点的next指向当前min的next,这样就让min离开了原链表。

*/

}

}

if (first != NULL) /*循环结束得到有序链表first*/

{

tail->next = NULL; /*单向链表的最后一个节点的next应该指向NULL*/

}

head = first;

return head;

}

/*

==========================

功能:直接插入排序(由小到大)

返回:指向链表表头的指针

==========================

*/

/*

直接插入排序的基本思想就是假设链表的前面n-1个节点是已经按键值

(就是用它排序的字段,我们取学号num为键值)排好序的,对于节点n在

这个序列中找插入位置,使得n插入后新序列仍然有序。

按照这种思想,依次

对链表从头到尾执行一遍,就可以使无序链表变为有序链表。

单向链表的直接插入排序图示:

---->[1]---->[3]---->[2]。。。---->[n]---->[NULL](原链表)

head 1->next 3->next 2->next n->next

---->[1]---->[NULL](从原链表中取第1个节点作为只有一个节点的有序链表)

head

图11

---->[3]---->[2]。

。。---->[n]---->[NULL](原链表剩下用于直接插入排序的节点)

first 3->next 2->next n->next

图12

---->[1]---->[2]---->[3]。。。---->[n]---->[NULL](排序后链表)

head 1->next 2->next 3->next n->next

图13:有N个节点的链表直接插入排序

1、先在原链表中以第一个节点为一个有序链表,其余节点为待定节点。

2、从图12链表中取节点,到图11链表中定位插入。

3、上面图示虽说画了两条链表,其实只有一条链表。在排序中,实质只增加了一个用于指向剩下需要排序节点的头指针first罢了。

这一点请读者务必搞清楚,要不然就可能认为它和上面的选择排序法一样了。

*/

struct student *InsertSort(struct student *head)

{

struct student *first; /*为原链表剩下用于直接插入排序的节点头指针*/

struct student *t; /*临时指针变量:插入节点*/

struct student *p; /*临时指针变量*/

struct student *q; /*临时指针变量*/

first = head->next; /*原链表剩下用于直接插入排序的节点链表:可根据图12来理解。

*/

head->next = NULL; /*只含有一个节点的链表的有序链表:可根据图11来理解。*/

while (first != NULL) /*遍历剩下无序的链表*/

{

/*注意:这里for语句就是体现直接插入排序思想的地方*/

for (t=first, q=head; ((q!=NULL) && (q->num num)); p=q, q=q->next); /*无序节点在有序链表中找插入的位置*/

/*退出for循环,就是找到了插入的位置*/

/*注意:按道理来说,这句话可以放到下面注释了的那个位置也应该对的,但是就是不能。

原因:你若理解了上面的第3条,就知道了。*/

first = first->next; /*无序链表中的节点离开,以便它插入到有序链表中。*/

if (q == head) /*插在第一个节点之前*/

{

head = t;

}

else /*p是q的前驱*/

{

p->next = t;

}

t->next = q; /*完成插入动作*/

/*first = first->next;*/

}

return head;

}

/*

==========================

功能:冒泡排序(由小到大)

返回:指向链表表头的指针

==========================

*/

/*

直接插入排序的基本思想就是对当前还未排好序的范围内的全部节点,

自上而下对相邻的两个节点依次进行比较和调整,让键值(就是用它排

序的字段,我们取学号num为键值)较大的节点往下沉,键值较小的往

上冒。

即:每当两相邻的节点比较后发现它们的排序与排序要求相反时,

就将它们互换。

单向链表的冒泡排序图示:

---->[1]---->[3]---->[2]。。。---->[n]---->[NULL](原链表)

head 1->next 3->next 2->next n->next

---->[1]---->[2]---->[3]。

。。---->[n]---->[NULL](排序后链表)

head 1->next 2->next 3->next n->next

图14:有N个节点的链表冒泡排序

任意两个相邻节点p、q位置互换图示:

假设p1->next指向p,那么显然p1->next->next就指向q,

p1->next->next->next就指向q的后继节点,我们用p2保存

p1->next->next指针。

即:p2=p1->next->next,则有:

[ ]---->[p]---------->[q]---->[ ](排序前)

p1->next p1->next->next p2->next

图15

[ ]---->[q]---------->[p]---->[ ](排序后)

图16

1、排序后q节点指向p节点,在调整指向之前,我们要保存原p的指向节点地址,即:p2=p1->next->next;

2、顺着这一步一步往下推,排序后图16中p1->next->next要指的是p2->next,所以p1->next->next=p2->next;

3、在图15中p2->next原是q发出来的指向,排序后图16中q的指向要变为指向p的,而原来p1->next是指向p的,所以p2->next=p1->next;

4、在图15中p1->next原是指向p的,排序后图16中p1->next要指向q,原来p1->next->next(即p2)是指向q的,所以p1->next=p2;

5、至此,我们完成了相邻两节点的顺序交换。

6、下面的程序描述改进了一点就是记录了每次最后一次节点下沉的位置,这样我们不必每次都从头到尾的扫描,只需要扫描到记录点为止。

因为后面的都已经是排好序的了。

*/

struct student *BubbleSort(struct student *head)

{

struct student *endpt; /*控制循环比较*/

struct student *p; /*临时指针变量*/

struct student *p1;

struct student *p2;

p1 = (struct student *)malloc(LEN);

p1->next = head; /*注意理解:我们增加一个节点,放在第一个节点的前面,主要是为了便于比较。

因为第一个节点没有前驱,我们不能交换地址。*/

head = p1; /*让head指向p1节点,排序完成后,我们再把p1节点释放掉*/

for (endpt=NULL; endpt!=head; endpt=p) /*结合第6点理解*/

{

for (p=p1=head; p1->next->next!=endpt; p1=p1->next)

{

if (p1->next->num > p1->next->next->num) /*如果前面的节点键值比后面节点的键值大,则交换*/

{

p2 = p1->next->next; /*结合第1点理解*/

p1->next->next = p2->next; /*结合第2点理解*/

p2->next = p1->next; /*结合第3点理解*/

p1->next = p2; /*结合第4点理解*/

p = p1->next->next; /*结合第6点理解*/

}

}

}

p1 = head; /*把p1的信息去掉*/

head = head->next; /*让head指向排序后的第一个节点*/

free(p1); /*释放p1*/

p1 = NULL; /*p1置为NULL,保证不产生“野指针”,即地址不确定的指针变量*/

return head;

}

/*

==========================

功能:插入有序链表的某个节点的后面(从小到大)

返回:指向链表表头的指针

==========================

*/

/*

有序链表插入节点示意图:

---->[NULL](空有序链表)

head

图18:空有序链表(空有序链表好解决,直接让head指向它就是了。

)

以下讨论不为空的有序链表。

---->[1]---->[2]---->[3]。。。---->[n]---->[NULL](有序链表)

head 1->next 2->next 3->next n->next

图18:有N个节点的有序链表

插入node节点的位置有两种情况:一是第一个节点前,二是其它节点前或后。

---->[node]---->[1]---->[2]---->[3]。。。---->[n]---->[NULL]

head node->next 1->next 2->next 3->next n->next

图19:node节点插在第一个节点前

---->[1]---->[2]---->[3]。

。。---->[node]。。。---->[n]---->[NULL]

head 1->next 2->next 3->next node->next n->next

图20:node节点插在其它节点后

*/

struct student *SortInsert(struct student *head, struct student *node)

{

struct student *p; /*p保存当前需要检查的节点的地址*/

struct student *t; /*临时指针变量*/

if (head == NULL) /*处理空的有序链表*/

{

head = node;

node->next = NULL;

n += 1; /*插入完毕,节点总数加1*/

return head;

}

p = head; /*有序链表不为空*/

while (p->num num && p != NULL) /*p指向的节点的学号比插入节点的学号小,并且它不等于NULL*/

{

t = p; /*保存当前节点的前驱,以便后面判断后处理*/

p = p->next; /*后移一个节点*/

}

if (p == head) /*刚好插入第一个节点之前*/

{

node->next = p;

head = node;

}

else /*插入其它节点之后*/

{

t->next = node; /*把node节点加进去*/

node->next = p;

}

n += 1; /*插入完毕,节点总数加1*/

return head;

}

/*

测试代码如下:

*/

/*测试SelectSort():请编译时去掉注释块*/

/*

head = SelectSort(head);

Print(head);

*/

/*测试InsertSort():请编译时去掉注释块*/

/*

head = InsertSort(head);

Print(head);

*/

/*测试BubbleSort():请编译时去掉注释块*/

/*

head = BubbleSort(head);

Print(head);

*/

/*测试SortInsert():上面创建链表,输入节点时请注意学号num从小到大的顺序。

请编译时去掉注释块*/

/*

stu = (struct student *)malloc(LEN);

printf("/nPlease input insert node -- num,score: ");

scanf("%ld,%f",&stu->num,&stu->score);

head = SortInsert(head,stu);

free(stu);

stu = NULL;

Print(head);

*/

转载: 。

全部

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/395457.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

字符集(CHARACTER SET)和校对集(COLLATE)

http://blog.sina.com.cn/s/blog_9707fac301016wxm.html http://www.th7.cn/db/mysql/201412/84636.shtml 从上文中可以看出character_set_connection、character_set_client、 character_set_results三个字符集什么时候用到。从实际上可以看到,当客户端连接服务器的…

shell 本地接口自动化

一.基于http/https的接口 一般情况下,当前大多公司在做接口自动化的时候都会使用一些工具;比如:postman/jmeter/python自研开发接口平台。。。 以上的情况,都是在源码与测试使用分离的情况下实践的。也就是说:目前国内…

hitchhiker部署_《 Hitchhiker的Python机器学习指南》

hitchhiker部署by Conor Dewey由Conor Dewey 《 Hitchhiker的Python机器学习指南》 (The Hitchhiker’s Guide to Machine Learning in Python) 提供实施代码,教学视频等 (Featuring implementation code, instructional videos, and more) 趋势 (The Trend) Machi…

CAD库中列举所有航路点

select distinct f1.airway_point_name,f1.latitude,f1.longitude,upper(f1.airway_point_type_name)type,f2.code_fir from airway_ordered_point f1, v_airway_point f2where f2.significant_point_idf1.airway_point_idorder by code_fir, type,airway_point_name转载于:htt…

第50次二级c语言真题,2006年4月全国计算机等级考试二级C语言笔试试卷含答案

一、选择题((1)一(10)每题2分,(11)一(50)每题1分,共60分)下列各题A)、B)、C)、D)四个选项中,只有一个选项是正确的,请将正确选项涂写在答题卡相应位置上,答在试卷上不得分。(1)下列选项中不属于结构化程序设计方法的是…

python hashlib模块

摘要算法简介 Python的hashlib提供了常见的摘要算法,如MD5,SHA1等等。 什么是摘要算法呢?摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示&…

TZOJ 5101 A Game(区间DP)

描述 Consider the following two-player game played with a sequence of N positive integers (2 < N < 100) laid onto a 1 x N game board. Player 1 starts the game. The players move alternately by selecting a number from either the left or the right end o…

国家职业标准职业编码查询_为什么我学会编码而不是从事金融职业

国家职业标准职业编码查询by Amir Ghafouri通过阿米尔加富里(Amir Ghafouri) 为什么我学会编码而不是从事金融职业 (Why I learned to code instead of pursuing a career in finance) Last year I faced a major life and career decision: commit to pursuing a Chartered F…

go tool trace goalng调优工具

为什么80%的码农都做不了架构师&#xff1f;>>> 你想知道你的Go程序在做什么吗&#xff1f; go tool trace 可以向你揭示&#xff1a;Go程序运行中的所有的运行时事件。 这种工具是Go生态系统中用于诊断性能问题时&#xff08;如延迟&#xff0c;并行化和竞争异常…

程序员 文本编辑器 c语言,程序员必备的五款文本编辑器

原标题&#xff1a;程序员必备的五款文本编辑器程序员的工作离不开文本编辑器&#xff0c;有人说一个txt就能搞定&#xff0c;但txt面对如今复杂的要求&#xff0c;明显有些捉襟见肘&#xff0c;下面推荐五款超级好用的文本编辑器及搭配软件&#xff0c;绝对是程序员的大爱。程…

PCH文件的创建和配置

1.PCH文件的的创建 (1)CommandN (2)打开新建文件窗口:ios->other->PCH file&#xff0c;创建一个pch文件 2.PCH文件的配置 (1)在工程的TARGETS里边Building Setting中搜索Prefix Header (2)然后在Precompile Prefix Header下边的Prefix Header右边双击&#xff0c;添加刚…

ci 数据库异常捕获_系统地捕获错误:如何通过4个步骤构建GitLab CI测试管道

ci 数据库异常捕获by Joyz通过乔伊斯 系统地捕获错误&#xff1a;如何通过4个步骤构建GitLab CI测试管道 (Catch bugs systematically: how to build a GitLab CI testing pipeline in 4 steps) Your first app is a hit the day it’s launched. But one week later, you rea…

(小白)函数一: 声明函数的方法—语句定义法和表达式定义法的区别

一、函数的定义&#xff1a; 在说明什么是函数前先举一个小例子&#xff1a; 大家都知道印刷术是我国的四大发明&#xff08;科普一下&#xff1a;中国四大发明&#xff1a;造纸术、印刷术、火药、指南针&#xff09;之一&#xff0c;之所以有印刷术&#xff0c;是因为重复的抄…

android限制输入字符的范围,Android EditText 对输入字数和内容范围进行限制

在做定制机时&#xff0c;对光敏值进行范围控制时&#xff0c;以及对区号输入时遇到对输入字数以及输入内容的显示。找了好多方法&#xff0c;终于找到了几种方法其中EditText的addTextChangedListener功不可没。例如对光敏值要在0到61之间。大于61时要在输入框中自动变为61.代…

vue13过滤器 debounce延迟、limitBy、filterBy、orderBy

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>智能社——http://www.zhinengshe.com</title><meta name"viewport" content"widthdevice-width, initial-scale1.0, maximum…

Sass:一种CSS预处理器语言

http://sass-lang.com/ Sass是一种CSS预处理器语言&#xff0c;通过编程方式生成CSS代码。因为可编程&#xff0c;所以操控灵活性自由度高&#xff0c;方便实现一些直接编写CSS代码较困难的代码。 同时&#xff0c;因为Sass是生成CSS的语言&#xff0c;所以写出来的Sass文件是不…

Python学习(五)列表的简单操作

#!/usr/bin/env python#_*_coding:utf8_*_# 操作列表# for循环nbaStars [yaoming,kobe,manu,23,the klaw]for nbaStar in nbaStars: print(nbaStar)nbaStars [yaoming,kobe,manu,str(23),the klaw] # 这里有 int 对象&#xff0c;没有title方法的for nbaStar in nbaStars:…

node seneca_使用Node.js和Seneca编写国际象棋微服务,第3部分

node senecaFinishing up a three-part series on writing a rules engine with Seneca microservices.完成有关使用Seneca微服务编写规则引擎的三部分系列文章。 Parts 1 & 2 of this series covered:本系列的第1部分和第2部分涉及&#xff1a; The Seneca microservice…

Android开发画布销毁,Android DialogFragment 在页面销毁下的使用方式

今天看到了一篇文章,讲了DialogFragment的封装方式(Android&#xff1a;我为何要封装DialogFragment&#xff1f;),想到当初也为页面销毁后DialogFragment的回调方式头疼了好久,看到了po主的思路,与当初自己想的不太一样,就整理一下.如何在开发中遇到页面销毁的情况在android开…

视觉智能产品发布 阿里云这项世界第一的技术现在人人可用

用手机拍下朋友的相片&#xff0c;软件会自动识别进行分类并将照片发送给朋友。这不是空想&#xff0c;利用视觉智能对手机相册进行管理、分类和分享正逐步成为现实。在6月10日举行的云栖大会上海峰会上&#xff0c;阿里云正式发布了“图像识别”和“人脸识别”两款视觉智能服务…