1 / 109

5 数据组织、筛法与排序问题 的解题思路

5 数据组织、筛法与排序问题 的解题思路. 教学内容: 1 数组的概念 2 筛法求素数 3 冒泡排序. 教学方法:任务驱动. 课时安排: 2节课. 学 习 目 标. 数组的概念、定义和初始化 筛法的解题思路 冒泡排序的思路. 内 容 要 点. 数组:定义、初始化、操作与应用 筛法:do_while循环、 while循环、求质数 排序:冒泡排序的算法. 问题:哪只羊最重?.

ping
Download Presentation

5 数据组织、筛法与排序问题 的解题思路

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 5数据组织、筛法与排序问题的解题思路 • 教学内容: • 1 数组的概念 • 2 筛法求素数 • 3 冒泡排序 教学方法:任务驱动 课时安排:2节课

  2. 学 习 目 标 • 数组的概念、定义和初始化 • 筛法的解题思路 • 冒泡排序的思路

  3. 内 容 要 点 • 数组:定义、初始化、操作与应用 • 筛法:do_while循环、 while循环、求质数 • 排序:冒泡排序的算法

  4. 问题:哪只羊最重? 中秋佳节,有贵客来到草原,主人要从羊群中选一只肥羊宴请宾客,当然要选最重者。这样就要记录每只羊的重量,如果有成千上万只羊,不可能用一般变量来记录。可以用带有下标的变量,也就是这里要讲的数组。 我们先看例子:用键盘输入10只羊的重量存放到一个名为sheep的数组中

  5. //************************************ //* 程序名:5_1.cpp(数组示例) * //* 作 者:wuwh * //* 编制时间:2002年9月20日 * //* 主要功能:找出最重的羊 * //************************************ #include <iostream> // 预编译命令 #include <memory> // 预编译命令 using namespace std; int main() // 主函数 { float sheep[10]; // 数组,有10个浮点类型元素, // 用于存10只羊每一只的重量 memset ( sheep, 0 , sizeof (sheep) );// 初始化数组元素为0 float bigsheep=0.0; // 浮点类型变量,存放最肥羊的重量 int i=0, bigsheepNo=0; // 整型变量,i 用于计数循环, // bigsheepNo用于记录最肥羊的号

  6. for ( i=0; i<10; i=i+1 ) // 计数循环 { // 循环,开始 cout<<"请输入羊的重量sheep["<< i << "]="; // 提示用 cin >> sheep[i]; // 输入第i只羊的重量 if ( bigsheep < sheep[i] ) // 如果第i只羊比当前最肥羊大 { bigsheep = sheep[i]; // 让第i只羊为当前最肥羊 bigsheepNo = i; // 纪录第i只羊的编号 } } // 循环结束 // 输出最肥羊的重量 cout<< "最肥羊的重量为"<<bigsheep<<endl; // 输出该羊的编号 cout<< "最肥羊的编号为"<<bigsheepNo<<endl; return 0; }

  7. 程 序 框 图

  8. 数组的定义 类型说明符 数组名 [ 常量表达式 ] 例: float sheep[10]; int a2001[1000]; 说明 • 1. 数组名的第一个字符应为英文字母; • 2. 用方括号将常量表达式括起; • 3. 常量表达式定义了数组元素的个数;

  9. 4. 数组下标从 0 开始。如果定义 5 个元素,是从第 0 个元素至第 4 个元素; 例如 int a[5] 定义了5个数组元素如下: a[0], a[1], a[2], a[3], a[4] 这是 5 个带下标的变量,这5个变量的类型是相同的

  10. 5.常量表达式中不允许包含变量 例如 int n; n = 5; int a[n]; 不合法! 因为 n 是变量,不是常量

  11. #define N 100 //宏定义,N为常数100 #define M 200 //宏定义,M为常数200 int a[ N ] ; //定义有100个元素的整型数组a long b[ N+M ] ; //定义有300个元素的长整型数组b double g[ M+6 ] ; //定义有206个元素的双精度实 //型数组g 以上定义是合法的 #define N 100 为命令行,不是语句,程序在 编译时遇到N 就用100替换。在命令行中定义的符号名N,也被称为符号常量N。

  12. 数组初始化 第一种方法 直接在定义时初始化 例如 int a[5] = { 3, 5, 4, 1, 2 }; a[0] = 3; a[1] = 5; a[2] = 4; a[3] = 1; a[4] = 2;

  13. 第二种方法 使用 memset 函数 格式为 memset(数组名, 初始化值, sizeof(数组名)) 举例: memset(sheep, 0, sizeof( sheep )); 含义是将名为 sheep 的数组中的全部元素均初始化为 0 。更深一层是说让系统为 sheep[10] 所分配的内存单元从 sheep[0] 为标志的地址单元到该数组的全部地址单元都赋以 0 。调用此库函数需要加入头文件 <memory.h> 。

  14. 请自己上机做7个实验 • 1.#include <iostream> using namespace std; int main() { int a[4]; // 声明项 cout << a[0] << endl; cout << a[1] << endl; cout << a[2] << endl; cout << a[3] << endl; return 0; } • 2.其他不变,改变声明项为 int a[4] = { 0, 1, 2, 3 };

  15. 3.其他不变,改变声明项为 int a[4] = { 3, 8 }; • 4.其他不变,改变声明项为 int a[4] = { 2, 4, 6, 8, 10 }; • 5.其他不变,改变声明项为 int a[4] = { 2, 4, 6, d }; • 6.其他不变,改变声明项为 int d; int a[4] = { 2, 4, 6, d }; • 7.其他不变,改变声明项为 int n=4; int a[n] = { 0, 1, 2, 3 };

  16. 讨 论 问 题 使用筛法求100以内的所有素数

  17. 5.2 筛 法

  18. 思路 想象将100个数看作沙子和小石头子,让小石头子权称素数;让沙子当作非素数。弄一个筛子,只要将沙子筛走,剩下的就是素数了。 非素数一定是 2、3、4 ……的倍数。 使用数组,让下标就是100以内的数,让数组元素的值作为筛去与否的标志。比如筛去以后让元素值为1。

  19. 方法的依据: 1至100这些自然数可以分为三类: • 单位数:仅有一个数1。 • 素数: 是这样一个数,它大于1,且只有1 和它自身这样两个正因数。 • 合数: 除了1和自身以外,还有其他正因数。 1不是素数,除1以外的自然数,当然只有素数与合数。筛法实际上是筛去合数,留下素数。

  20. 为了提高筛法效率,注意到: 令 n 为合数(这里是100), c 为 n 的最小正因数, 据初等数论,只要找到 c 就可以确认 n 为合数,将其筛去。 一定注意:要进行“筛”的1—100的数字是与数组prime[101]的下标相对应的,而每个数组元素的取值只有2个:是0或1,分别代表(标志)与下标相对应的数字是素数或不是素数。

  21. 程序框图如下: 请同学来分析左边程序的结构 从而了解算法的设计思路 为程序代码的实现创造条件

  22. 上述框图很清晰地描述了筛法的思路: • 1.第一块是一个计数型的循环语句,功能是将prime数组清零。 prime[c] = 0; c = 2, 3,… ,100 • 2.第二块是正因数d 初始化为 d = 2。 • 3.第三块是循环筛数。这里用了一个 do while语句,属于一种直到型循环,其一般形式为: do { 循环体语句块 } while ( 表达式 )

  23. do { 循环体语句块; } while ( 表达式 )

  24. 直到型循环框图如下: 直到表达式为假 时才退出循环,所以循环体至少执行一次。

  25. 举 例 求 π 的近似值

  26. 例.求π的近似值 用变量pi表示π的值。 令 表示括号中的每个项 当最后一项的绝对值小于等于 时,忽略掉以后的项

  27. //************************************ //* 程 序 名:5_2.cpp * //* 作 者:wuwh * //* 编制时间:2002年9月20日 * //* 主要功能:求pi的近似值 * //************************************ #include <iostream> #include <cmath> using namespace std; int main() // 主函数 { int sum=0; // 整型变量,总项数 float pi=0.0, a=1.0, b=1.0, c=1.0; // 浮点变量,a为分母,b为分子,c为b除以a

  28. do // 直到型循环 { // 循环体,开始 pi = pi + c; // 累加每一项 sum = sum + 1; a = a + 2.0f; // 计算每一项的分母;强制将2.0转换成float型 b = -b; // 分子变正负号 c = b / a; // 计算每一项 } // 循环体结束 while ( fabs(c) > 1e-6 ); // 当c的绝对值大于10的-6次方时,继续 // 执行循环体,否则退出 pi = 4.0f * pi; // 得到最终结果;将4.0作为float类型 cout << “pi= ” << pi << endl; // 输出pi值 cout << “sum=” << sum << endl; // 输出总项数 return 0; }

  29. do // 直到型循环 { // 循环体,开始 pi = pi + c; // 累加每一项 sum = sum + 1; a = a + 2.0f; // 计算每一项的分母 b = -b; // 分子变正负号 c = b / a; // 计算每一项 } // 循环体结束 while ( fabs(c) > 1e-6 );

  30. 运行结果pi = 3.14159, sum = 500000 提问:这种循环当表达式的值永远为真时, 会如何? 答:会构成死循环,即无休止地执行循环体 请实验: • 1. 将 b 定义为 int 型看看执行结果并分析为什么 • 2. 将 1e-6 变为 1e-7 或 1e-4 看看结果

  31. 下面还要介绍另一种循环“当循环” 一般形式: while ( 表达式 ) { 语句块;(循环体) }

  32. while( 表达式 ) { 语句块 ( 循环体 ); }

  33. 思考 #define N 1 while ( N ) { cout<<“ welcome to Tsinghua \n“; } 程序运行后会出现什么情况?

  34. 思考 #define N 1 while ( N - 1 ) { cout<<“ welcome to Tsinghua \n“; } 程序运行后会出现什么情况?

  35. 举 例 求两个整数的最小公倍数

  36. 分析:假定有x ,y 且 x > y,设最小公倍数为 z • 1. z 一定会 >= x • 2. z = k x , k= 1, 2, … • 3. z 一定会被 y 整除 用两个最简单的数试一下就可以找到算法. 比如 x=5, y=3.

  37. 第一步 z = x // x=5 5 % 3 != 0 // z % y 不能整除 • 第二步 z = z + x 10 % 3 != 0 // z % y不能整除 • 第三步 z = z + x 15 % 3 == 0 // z % y 能整除 找到了 z ,15就是5和3的最小公倍数

  38. //************************************ //* 程 序 名:5_3.cpp * //* 作 者:wuwh * //* 编制时间:2002年9月20日 * //* 主要功能:求两个数的最小公倍数 * //************************************ #include <iostream> #include <cmath> using namespace std; int main() // 主函数 { int x=0, y=0, z=0, w=0; // 整型变量 cout << “请输入两个整数,用空格隔开:”; // 提示信息 cin >> x; // 键盘输入整数 x cin >> y; // 键盘输入整数 y if ( x < y ) // 让 x 表示两者中的大数 { w = x; x = y; y = w; // “倒油瓶”方法 } z = x; // 将一个大数赋给 z while ( z % y != 0 ) // 当z不能被y整除时,就让z累加x {z = z + x; } cout << “最小公倍数为” << z << endl; // 输出最小公倍数 return 0; }

  39. cout << “请输入两个整数,用空格隔开:”; // 提示信息 cin >> x; // 键盘输入整数 x cin >> y; // 键盘输入整数 y if ( x < y ) // 让 x 表示两者中的 大数 { w = x; x = y; y = w; }

  40. z = x; // 将一个大数赋给 z // 当z不能被y整除时,就让z累加x while ( z % y != 0 ) { z = z + x; } cout << "最小公倍数为" << z << endl;

  41. 自学与比较 请同学们去比较三种循环的异同之处 • 1. for 循环(计数型循环) • 2. 当型循环(while循环) • 3. 直到型循环(do while 循环) 上机将筛出素数的程序完成

  42. 练习: 题目:某选手 10000m 跑的每 400m 用时记录在名为 RUN 的数组中,请你计算平均用时(每400 m 的平均用时),要求使用 3 种循环语句来编程。 1. for 2. do … while 3. while

  43. 数组中已有25圈的每一圈的时间 run 0 70 71 73 72 . . . 69 0 1 2 3 4 . . . 25

  44. int main() { int run[26]={ 70,71,… }; int sum=0 ,average=0; for( int i=1;i<=25;i++) { sum=sum+run[i]; } average=sum/25; cout<<average; system("pause"); return 0; } 初值 终值 增值

  45. i=1; 初值 while( i <= 25 ) { 终值 sum=sum+ run[ i ]; i = i +1; 增值 }

  46. i=1;初值 do { sum=sum+ run[ i ]; i = i +1; } while( i <= 25 );

  47. 结论 初值,终值,增值 循环中的3个表达式 一个也不能少!

  48. 排 序 问 题

  49. 5.3 冒泡排序法

  50. a 1 8 3 2 4 9 下标 1 2 3 4 5 6 希望排成: a 9 8 4 3 2 1 下标 1 2 3 4 5 6

More Related