1、编程需求
阿萌要开发一个程序,该程序可以从一组整数中,找出该组整数的中位数。

例如学生输入下面的一组整数:

程序对这一组整数按照从小到大的顺序排序:

程序从排序后的整数中找出中位数28,并输出28到shell窗口。
2、理解中位数
下面是一组学生投掷沙包的数据:

现在要统计一下这组学生投掷沙包的一般水平,该如何统计呢?

该组数的平均数为28.41,用28.41来表示这组学生投掷沙包的一般水平显然不太合适。因为我们可以看出,24.7更适合表示这组学生投掷沙包的一般水平。
使用该组数的平均数,不适合表示这组学生投掷沙包的一般水平,是因为该组数中有两个极端数值36.8和34.7。
当一组数中出现了极端数值时,用中位数作为这组数的一般水平会更合适。
中位数是按顺序排列的一组数据中居于中间位置的数,即在这组数据中,有一半的数据比它大,有一半的数据比它小
3、找出中位数的方法
要找出一组数的中位数,需要先对这组数按照大小排序,或从大到小排序,或从小到大排序。
如果这组数的个数是奇数,则中间那个数就是这组数的中位数;如果这组数的个数是偶数,则中间那2个数的平均值就是这组数的中位数。
用程序从一组数找出中位数的具体步骤如下:
(1)程序接收学生输入的一组数;
(2)程序对该组数按从小到大排序;
(3)如果该组数的个数是奇数,输出该组数中间的那个数;
(4)如果该组数的个数是偶数,求出中间那2个数的平均值,输出平均值。

4、冒泡排序算法
要从一组数中找出中位数,需要对这一组数进行大小排序,或者从小到大排序,或者从大到小排序。
对一组数进行排序,对人来说非常容易,通过眼睛的观察和数的比较,就可以完成一组数的排序。
要让计算机完成一组数的排序,就需要人来编写程序,将排序的算法编写为程序,计算机才能完成对一组数的排序。
排序有很多算法,让我们来看一个冒泡排序算法,该算法一次比较两个元素,如果他们的顺序错误就把他们交换过来,重复访问该组数所有的数并进行比较和交换,直到再没有数需要交换,说明该组数已经排序完成。
对下面的一组数用冒泡排序算法,并按照从小到大的顺序排序。

排序前的一组数,我们称为原始数列,每两个数进行一次比较,称为一轮比较。

第一轮比较:23与34比较,23小于34,两个数不用交换位置。

第二轮比较:34与5比较,因为34大于5,因此34和5交换位置。


第三轮比较:34与7比较,因为34大于7,因此34与7交换位置。


第四轮比较:比较34和56,因为34小于56,两个数不用交换位置。

在前面的四轮比较中,从数列左侧的第一个数开始,顺序两两比较两个数的大小,如果前面一个数比后面一个数大,就交换两数的位置,直到数列的最后一个数比较完毕。
这四轮比较下来,称为一趟比较。如果在该趟比较中,存在两个数交换位置的情况,就需要进行下一趟比较,直到再没有数字进行交换,算法结束。
因为在第一趟比较中,存在两数的位置交换,因此还需要进行第二趟的比较。
第二趟比较
第二趟比较也是从数列左侧的第一个数开始,顺序两两比较两个数的大小。不过第二趟比较就不需要再比较数列右侧的最后一个数了,因为在第一趟比较的过程中,该数列最大的数已经被交换到数列右侧最后的一个位置了。

第一轮比较:比较23和5,因为23大于5,因此23和5交换位置。


第二轮比较:比较23和7,因为23大于7,因此23和7交换位置。


第三轮比较:比较23和24,因为23小于24,两个数不用交换位置。

至此,第二趟比较完成。最后的一个数56就不用比较了,因为56在第一趟比较中就已经为自己找到了正确的位置。
从第三轮的比较结果来看,排序已经完成,每个数都自己找到了正确的位置。已经不需要再进行第三趟比较了。
5、for循环嵌套结构
冒泡排序算法需要对待排序的一组数,进行多趟数的比较,在每趟的比较过程中,需要按顺序两两比较该组数中相邻的两个数。
现在我们需要把冒泡排序算法编写为程序,算法的多趟比较可以用for循环来实现。但这里会存在一个问题,就是在每趟的循环中,还需要一个循环来完成每趟顺序两两比较该组数中相邻的两个数,这个循环是在每趟循环的循环体内。

要解决上面的问题,就需要用到for循环的嵌套结构。for循环的嵌套结构是在for循环体内再嵌套一个for循环,这样就会有两层循环,第一层循环称为外循环,第二层循环称为内循环。
for循环嵌套结构语法如下:

首先外循环的第一轮触发内循环,内循环将一直执行到完成为止,然后,外循环的第二轮再次触发内循环,此过程不断重复直到外循环结束,使用嵌套循环时,只有在内循环完全结束后,外循环才会执行下一趟循环。

案例01的代码演示了for循环嵌套结构的使用。
案例01输出九九乘法表,代码使用了两层循环,外层循环范围为1~10,控制九九乘法表行的输出,内层循环范围为1~i+1,控制乘法表列的输出。
在案例01代码中,调用print函数输出乘法表时,另外传入了一个参数“end= ""”,传入该参数是告诉print函数,在内容输出完成后,不要输出换行符。下次调用print函数输出内容时,还是在这一行输出,并不另起一行输出内容。
print函数的默认输出,是在输出内容后,再另外输出一个换行符,下次输出内容时会另起一行。如果在调用print函数时,传入参数“end= ""”,print函数就不会再另外输出一个换行符。
6、冒泡排序算法的代码实现
掌握了for循环嵌套结构的用法,就可以开始编写冒泡排序算法的代码了。冒泡排序算法用函数来实现,方便主程序的调用,冒泡排序算法函数代码保存到sort.py模块文件。
冒泡排序算法的流程图:

冒泡排序算法代码:
''' 程序文件:sort.py 功能描述:冒泡排序 代码编写时间:2020/04/20 作者:编程训练营 ''' # 定义冒泡排序函数 # 函数传入待排序的整数列表nums def bubble_sort(nums): ''' 外层循环控制比较趟数 需要比较nums列表长度减1趟 ''' for i in range(0,len(nums)-1): ''' 内层循环控制每一趟排序多少次 每一趟排序都会把较大的数值移动到列表后面 第i趟排序循环次数为列表长度减去已经排过序的i个元素 如果第j个元素大于第j+1个元素,则交换 ''' for j in range(0,len(nums)-i-1): if nums[j] > nums[j+1]: # 交换第j和第j+1个元素 temp = nums[j] nums[j] = nums[j+1] nums[j+1] = temp return nums
代码解读
函数传入列表nums,nums存储了待排序的一组整数。然后用外层for循环结构控制列表元素的比较趟数,比较趟数为待排序列表元素的个数减去1,在每趟比较中,用内层for循环遍历待排序列表元素,并进行比较和位置交换,循环范围介于0到列表元素的个数减去1,再减去外层循环当前执行的比较趟数,因为i趟排序过程中,已经把i个较大的数交换到列表length-i的列表序号范围,无需再比较和交换。
7、程序流程图

(1)程序输出提示信息,提示信息为“输入quit退出程序,输入begin开始找中位数”;
(2)获取学生输入的内容,赋值给option;
(3)判断option的值是否是quit,若是quit,程序结束;
(4)若不是quit,调用函数要求学生输入一组整数;
(5)调用排序算法函数对学生输入的一组整数排序;
(6)调用函数找出中位数,并输出中位数;
(7)再次等待学生的输入。

(1)创建一个空列表list,用于存储学生输入的一组整数;
(2)输出提示信息,提示信息内容为“请输入一个整数,输入end可结束输入”;
(3)接收学生的输入,输入内容赋值给num;
(4)判断num是否是整数,如果是整数将num加入list,再次进入输入状态。如果不是整数,判断num是否等于end,如果是end,返回list,函数执行结束。

(1)判断list元素的个数是否是奇数,如果是奇数,转第2个步骤,否则转第3个步骤;
(2)取出list中间的元素,函数返回该元素的值。取list中间元素的方法是:list元素的索引为list元素的个数除以2并取整;
(3)取出list中间两个元素。取中间两个元素的方法是:第一个元素的索引是list元素的个数除以2取整后减1,第二个元素的索引是第一个元素的索引加1;
(4)返回两个元素的平均值。
8、程序代码及解读
程序代码如下:
'''
程序文件:main.py
功能描述:找出一个数的中位数
代码编写时间:2020/04/22
作者:编程训练营
'''
# 导入sort模块
import sort as sort
# 定义getnums函数,获取一组整数
def getnums():
# 创建一个空的list
list = []
# 输出提示信息
print("请输入一个整数,输入end可结束输入")
# 循环输入整数
while(True):
# 获取输入
num = input("请输入:")
# 判断num是否全部是数字字符
if num.isdigit():
list.append(int(num))
elif num == "end":
break;
return list
# 定义find函数
# 从已排序的列表中找出中位数
def find(inlist):
# 获取列表元素的个数
length = len(inlist)
# 判断length是否是奇数
if length % 2 != 0:
# 如果是奇数
# 返回索引为列表元素个数除以2的列表元素
return inlist[len(inlist)//2]
else:
# 获取列表中间元素第一个元素
num1 = inlist[len(inlist)//2-1]
# 获取列表中间元素第二个元素
num2 = inlist[len(inlist)//2]
# 求两个元素的平均值
average = (num1+num2)//2
return average
# 程序入口
if __name__ == '__main__':
while(True):
# 输出提示信息
print("输入quit退出程序,输入begin开始找中位数")
# 等待学生输入
option = input("请输入:")
# 如果输入是quit,退出程序
if option == "quit":
break;
# 如果输入是begin,开始找中位数
if option == "begin":
# 调用函数getnums获取一组整数
nums = getnums()
# 调用sort模块的sort函数对列表元素排序
nums = sort.bubble_sort(nums)
# 调用find函数找出中位数
num = find(nums)
# 输出中位数
print("%s的中位数:%d" % (nums,num))代码解读
代码定义了两个函数,分别是getnums函数和find函数。
getnums函数实现获取学生输入一组整数的功能。函数首先创建一个空的list列表,用于存储学生输入的整数。然后使用while循环来获取学生输入的多个整数,在while循环体内,使用input函数获取学生输入的内容,并赋值给num,程序使用num的isdigit方法,判断num的内容是否全部是数字字符,如果全部是数字字符,使用int函数将num转换为整数添加到list。如果num的内容是end,说明整数序列已经输入完成,调用break语句退出循环,函数返回list。
find函数实现从已排序的列表中找出中位数的功能。函数首先判断列表元素个数的奇偶性,如果列表元素的个数是奇数,索引为列表元素个数除以2取整后的列表元素,就是该整数序列的中位数。如果列表元素的个数是偶数,该整数序列的中位数是中间两个数的平均值,函数求出两个数的平均值并返回。
代码使用了import语句导入了sort.py模块,该模块定义了bubble_sort函数,该函数实现了冒泡排序算法。
程序的主体代码建立一个while循环,让程序一直处于运行状态。在while循环体内,首先会要求学生输入“quit”或“begin”,并赋值给option。
如果option的内容为“quit”,则调用break语句退出循环,程序结束。
如果option的内容为“begin”,调用getnums函数要求学生输入一组整数,函数会返回已存储一组整数的列表,然后调用sort模块的bubble_sort函数对列表内的整型进行排序,最后调用find函数从已排序的列表中找出中位数。
