高级语言程序设计(一) (C Programming),第四讲:程序设计方法-模块化与算法设计,本章目标,进一步掌握模块化设计思想 掌握常用的数据查找及排序方法 了解全局变量 了解递归程序设计思想,问题4.1,【问题描述】 从文件中查找包含给定字符串的行。 【输入形式】 从标准输入中分两行分别输入被查找的文件及要查找的字符串(中间不含空格)。 【输出形式】 在屏幕上输出文件中包含给定字符串的行。 【样例输入】 在键盘输入如下文件名及字符串: test.txt the 文件test.txt内容如下: Now is the time for all good men to come to the aid of their party 【样例输出】 屏幕输出为: this is the time men to come to the aid of their party,问题4.1:算法设计,设 int index ( char s[ ], char t[ ] )函数用来在字符串s中查找字符串t。若找到则反回t在s中出现的位置,否则返回-1。其主要查找算法如下:,主要算法分析,在字符串s中查找字符串t : for(i=0; s[i] != ‘\0’; i++) for(j=i,k=0; t[k] != ‘\0; j++,k++) s[j]和t[k]进行比较,遍历输入字符串中每个字符,依次与给定串中每个字符比较。 j为s中每次开始比较的位置。,不同时break;找到的条件是:t[k]==‘\0’,问题4.1:算法设计(续),主要算法如下: 设变量filename,s,line分别用于存储文件名、查找串及文件中一行; 从标准输入中读入文件名和要查找的串到filename和s中; 以读方式打开文件filename; while 文件中还有内容时读一行到line中 如果 index(line, s) = 0 输出line;,如何从文件中读入一行? char *fgets(char *s, int n, FILE *fp) 从fp上最多读入n-1个字符,放入s 字符数组中。返回s,到达文件尾部返回NULL。,利用fgets从标准输入读取 一行字符串放在字符数组s 中,s的大小是101: fgets( s , 101 , stdin );,问题4.1:代码实现,#include #define MAXLINE 1000 int index(char s[ ], char t[ ]); int main( ) { char filename[64], s[81], line[MAXLINE]; FILE *fp; scanf(“%s“, filename); scanf(“%s“, s); if((fp = fopen(filename, “r“)) == NULL){ printf(“Can't open file %s!\n“, filename); return 1; } while(fgets(line, 81, fp) != NULL) if(index(line, s) = 0) printf(“%s“, line); return 0; },int index(char s[ ], char t[ ]) { int i, j, k; for(i =0; s[i] != ‘\0’; i++){ for(j=i,k=0;t[k]!=‘\0’ },使用scanf的缺点是不能输入带空格的字符串。可换成 gets(s); 来实现查找带空格的字符串。,由于打开一个文件操作可能失败,因此,好的风格应判断fopen函数的返回值,进行错误处理。,注意:由于上述循环当没有相应匹配字符时也退出。因此,要依据t中所有字符都匹配(即t[k]==‘\0’)来判断查找是否成功。,问题4.1:测试,当要查找的文件为“test.txt”,要查找的串为”the”,且文件test.txt中内容为: Now is the time for all good men to come to the aid of their party 则屏幕输出: this is the time men to come to the aid of their party,问题4.1:测试(续),其它考虑点: 要查找的串在一行的头、尾 要查找的串在文件中不存在,问题4.1:思考1,问题4.1实现了大小写相关的字符串查找,即字符串“the”和“The”是不同字符串。请实现大小写无关的字符串查找。 算法分析: 在比较字符时,可将比较字符均转换为小写或大写既可实现大小写无关查找。 设函数char tolower(char c)用于将字符c转换为相应小写字符,则上面index可改为:,int index(char s[ ], char t[ ]) { int i, j, k; for(i =0; s[i] != ‘\0’; i++){ for(j=i,k=0;t[k]!=‘\0’ },问题4.1:函数tolower实现,方法一: char tolower(char c) { if( c =‘A’ } 方法二:对于象tolower这样功能简单的函数,可以用宏函数来实现。 #define tolower(c) (c=‘A’&&c=‘Z’ ? ‘a’-’A’+c:c),预处理程序:define,定义函数 宏定义还可带变元(参数): #define 标识符(标识符, 标识符,…) 单词串 如: #define max(A, B) ((A) (B) ?(A) : (B)) 于是语句x = max(p+q, r+s); 可替换为: x = ((p+q) (r+s) ? (p+q) : (r+s)); 注意: 宏定义名与参数间不能有空格,如max(A,B); 参数应用括号括起来,如(A)(B)?(A) : (B),#define isupper(c ) (c =‘A’ && c=‘Z’)?1:0,反例: #define prod(x,y) x*y 则: a=prod(b+c,d+e);被替换为: a=b+c*d+e;,问题4.1:思考1(代码实现),#include #define MAXLINE 1000 #define tolower(c) (c=‘A’ },int index(char s[ ], char t[ ]) { int i, j, k; for(i =0; s[i] != ‘\0’; i++){ for(j=i,k=0;t[k]!=‘\0’ },问题4.1:思考2,其它实现方法? 问题4.1中index只能查找的是子字符串的首次出现。请考虑如何查找子字符串的最后一次出现? 如果要查找一个字符串在一个文件中的出现次数,或查找一个字符串在一个文件中的所有出现行列位置,如何实现?(注意,index只能查找子字符串首次出现,如果一行中有多个子字符串怎样办?),问题4.2,【问题描述】 某班有不超过200名的学生,从文件中输入某班学生成绩,对输入成绩按由高到低进行排序,并输出到另一个文件中。 【输入形式】 从文件scorelist.in中读入学生成绩,学生成绩以整数形式按行存放。注意,学生成绩数目不确定。 【输出形式】 将排序结果按行写到文件sorelist.out中。 【样例输入】 若文件scorelist.in中有如下成绩: 58 75 62 86 98 【样例输出】 程序运行结束后文件scorelist.out中内容为: 98 86 75 62 58,问题4.2:算法分析,问题可分解为如下几个部分:,算法: int socrelist[NUM],n=0; while(!feof(in)) fscanf(in, “%d”, 函数feof用来测试是否已读写到文件尾,若到文件尾,则返回1,否则返回0。 函数fscanf用来从文件中读数据。与标准输入scanf不同的是第一个参数为文件指针。,算法: for(i=0; in; i++) fprintf(out,“%d “,scorelist[i]); 函数fprintf用来从文件中读数据。与标准输入printf不同的是第一个参数为文件指针。,算法: 设一个函数专门用来对学生成绩进行排序,函数原型为: void sortScore(int list[], int len ),算法: FILE *in, *out; in = fopen(“scorelist.in”, “r”); out = fopen(“scorelist.out”,”w”);,问题 4.2:算法分析- 选择排序(续),有许多经典的算法用来对数据进行排序,如选择排序(selection sort)、插入排序(insertion sort)和快速排序(quick sort)等。有关排序算法及分析主要在《数据结构》课程中讲授。 在问题4.2中将使用选择排序算法对学生成绩进行排序。,问题 4.2:算法分析- 选择排序(续),选择排序的核心思想是先通过找到数组中未排序部分的最大元素,然后将其移到未排序部分的最前端来排序一个数组(从大至小排序)。即首先在整个数组中查找最大元素,将其换到第一个位置;然后从数组中第二个元素开始查找最大元素,以此类推。下面以图示来说明:,问题 4.2:算法分析- 选择排序(续),最大元素,最大元素,问题 4.2:算法分析- 选择排序(续),选择排序包括以下步骤: 找到最大元素 将最大元素移到未排序部分的第一个位置上,index = 0; for(i=1; iN; i++) if(array[index] array[i]) index = i;,通过交换两个元素即可。如: int tmp; tmp = array[i]; array[i] = array[index]; array[index] = tmp;,问题 4.2:代码实现(排序函数),void sortArray(int array[], int n) { int i,j,tmp, index; for(i=0; in; i++) { index = i; for (j=i; jn; j++) if(array[index] array[j]) index = j; tmp = array[i]; array[i] = array[index]; array[index] = tmp; } },问题 4.2:代码实现(主函数),#include #define NUM 200 void sortArray(int array[], int n); int main() { int scorelist[NUM], i, n=0; FILE *in, *out; if((in = fopen(“scorelist.in“,“r“)) == NULL){ printf(“Cann't open file scorelist.in!\n“); return 1; } if((out = fopen(“scorelist.out“,“w“)) == NULL){ printf(“Cann't open file scorelist.out!\n“); return 1; } while(!feof(in)) fscanf(in,“%d“, },,,C程序设计基础,22,问题 4.2:一种模块化更好的实现,#include #define NUM 200 int readList(int array[ ]); void sortArray(int array[ ], int n); void writeList(int array[ ], int n); int main() { int scorelist[NUM], n; n = readList(scorelist); sortArray(scorelist, n); writeList(scorelist, n); return 0; },int readList(int array[ ]) { FILE *in; int n=0; if((in = fopen(“scorelist.in“,“r“)) == NULL){ printf(“Cann't open file scorelist.in!\n“); exit(1); } while(!feof(in)) fscanf(in,“%d“, },问题 4.2:测试及常见问题,若文件scorelist.in文件尾有一个回车,则会发生什么现象?如何调试?,若文件scorelist.in内容为: 58 75 62 86 98,程序运行后文件scorelist.out内容为: 98 86 75 62 58,问题 4.2:修改主函数,#include #define NUM 200 void sortArray(int array[], int n); int main() { int scorelist[NUM], i, n=0; FILE *in, *out; if((in = fopen(“scorelist.in“,“r“)) == NULL){ printf(“Cann't open file scorelist.in!\n“); return 1; } if((out = fopen(“scorelist.out“,“w“)) == NULL){ printf(“Cann't open file scorelist.out!\n“); return 1; } while(fscanf(in,“%d“, },问题 4.2:另一个常用排序方法(冒泡排序)*,void sortArray(int array[], int n) { int i, j, tmp; for(i=0; in; i++) for(j=i; jn; j++){ if(array[i] array[j]){ tmp = array[i]; array[i] = array[j]; array[j] = tmp; } } },问题 4.2:另一个常用排序方法(冒泡排序)*,//从后往前,即最先排好的是头部 void sortArray(int array[], int n) { int i, j, tmp; for(i=1;i=i;j--){ if(array[j]array[j-1]){ tmp = array[j-1]; array[j-1] = array[j]; array[j] = tmp; } } } },//从前往后,即最先排好的是尾部 void sortArray(int array[], int n) { int i, j, tmp; for(i=0;in-1;i++){ for (j=0;jn-1-i;j++){ if(array[j]array[j+1]){ tmp = array[j+1]; array[j+1] = array[j]; array[j] = tmp; } } } },问题 4.2:另一种方法,在上述方法中,学生成绩一次全部读入,然后再排序后输出。 还有一种方法为每读入一个数据,就将其加到一个有序数据集中的相应位置上,无需最后排序。其具体算法如下:,问题 4.2:另一种算法,1.设整型数组scorelist存放排序后成绩,n为其中学生成绩个数,初始n为0; 2.分别以读和写方式打开文件scorelist.in和scorelist.out; 3.while 读文件中还有成绩时,读入一个成绩到score 将score插入到有序数组scorelist中相应位置; 4.输出数组scorelist到写文件中; 5.关闭读写文件;,设函数 void insertData(int array[ ],int data); 将一个变量插入到有序(从大到小)数组array中,插入后数组仍有序。,问题 4.2:函数insertData算法,找到数组array中第一个比data小的数组元素,设其下标为i; 将下标大于等于i的所有数组元素向后移动一个位置; array[i]=data; 数组元素个数n加1;,数组实际元素个数需要在insertData和main函数中都用到,如何在程序中函数间共享数据? 1)通过函数参数传递。但函数参数方式为传值,若要通过函数调用改变实参的值,要用到指针。 2)通过return语句返回值。注意只能返回一个值。 3)使用全局变量。,问题 4.2:另一种代码实现,//c4_2b.c #include #define NUM 200 int N = 0; void insertData(int array[], int data); int main() { int scorelist[NUM],score, i; FILE *in, *out; if((in = fopen(“scorelist.in“,“r“)) == NULL){ printf(“Cann't open file scorelist.in!\n“); return 1; } if((out = fopen(“scorelist.out“,“w“)) == NULL){ printf(“Cann't open file scorelist.out!\n“); return 1; } while(fscanf(in,“%d“, },void insertData( int array[ ], int data ) { int i, j; for( i=0; iarray[i]) break; for( j=N; ji; j-- ) array[j] = array[j-1]; array[i]=data; N++; },查找要插入的位置,从插入位置开始所有元素向后移动一个元素。,N为一个全局变量 。,全局变量访问,外部变量*,外部变量(global variable ):在函数外面定义的变量。 作用域(scope)为整个程序,即可在程序的所有函数中使用。 外部变量有隐含初值0。 生存期(life cycle):外部变量(存储空间)在程序执行过程中始终存在。,外部变量说明(extern)*,C程序可以分别放在几个文件上,每个文件可作为一个编译单位分别编译。外部变量只需在某个文件上定义一次,其它文件若要引用此变量时,应用extern加以说明。(外部变量定义时不必加extern关键字)。 在同一文件中,若前面的函数要引用后面定义的外部(在函数之外)变量时,也应在函数里加以extern说明。,外部变量说明(extern)(续)*,例如,对问题4.2的代码实现中,如果外部变量N不在程序头部定义,则需要用extern加以说明。 … extern int N; int main() { … } int N = 0; void insertData(int array[], int data) { … },外部变量定义,外部变量说明,外部变量说明(extern)(续)*,使用外部变量的原因: 解决函数单独编译的协调; 与变量初始化有关; 外部变量的值是永久的; 解决数据共享; 外部变量的副作用: 使用外部变量的函数独立性差,通常不能使用在其他的程序中。而且,如果多个函数都使用到某个外部变量,一旦出现差错,就很难发现问题是由哪个函数引起的。在程序中的某个部分引起外部变量的错误,很容易误以为是由另一部分引起的。,递归(Recursion)*,通过调用自身解决问题的过程称为递归。递归是解决某些复杂问题的有效方法。如:,,,递归(续)*,例:求n! #include int fact(int n); main( ) { printf(“3!=%d, 5!=%d\n”, fact(3), fact(5)); } int fact(int n) { int res=0; if( n = 1) res = 1; else res = n * fact(n-1)); return res; },在C语言中,一个函数直接或间接调用自已称为递归。,1,fact(3),3*fact(2),2*fact(1),,,,递归(续)*,递归算法十分简洁,编译后得到的目标代码也很短,但它并不节省(实际上还要增加)运行时所需的时间和空间,因为它必须维持一个要处理的值的栈。 此外,递归算法并不是语言必须的,不用它同样可以实现相应功能,如上例中,递归函数fact可用非递归方法 实现: int fact(int n) { int f = 1; while(n){ f *= n; n--; } return ( f); },例:汉诺塔(hanoi tower)游戏 void hanoi( int n, char a, char b, char c) { if( n 0 ) { hanoi(n-1, a, c, b); printf(“MOVE %d: %c  %c\n”, n, a, c); hanoi(n-1, b, a, c); } } main( ) { int n; printf(“Please input the number of hanoi tower:”); scanf(“%d”, },,,,问题4.3: 一个经典递归程序示例*,,,,,,,,问题4.4:生成全排列数*,【问题描述】输入整数N( 1 = N = 10 ),生成从1~N所有整数的全排列。 【输入形式】输入整数N。 【输出形式】输出有N!行,每行都是从1~N所有整数的一个全排列,各整数之间以空格分隔。各行上的全排列不重复。输出各行遵循“小数优先”原则, 在各全排列中,较小的数尽量靠前输出。如果将每行上的输出看成一个数字,则所有输出构成升序数列。具体格式见输出样例。 【样例输入1】3 【样例输出1】 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1 【样例说明1】输入整数N=3,要求整数1、2、3的所有全排列, 共有N!=6行。且先输出1开头的所有排列数,再输出2开头的所有排列数,最后输出3开头的所有排列数。在以1开头的所有全排列中同样遵循此原则。 【样例输入2】10 【样例输出2】 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 10 9 1 2 3 4 5 6 7 9 8 10 1 2 3 4 5 6 7 9 10 8 1 2 3 4 5 6 7 10 8 9 1 2 3 4 5 6 7 10 9 8 …………………… 【样例说明2】输入整数N=10,要求整数1、2、3、……、10的所有全排列。上例显示了输出的前10行。,问题4.4:算法分析*,对于N的全排列: MNMN-1…Mn…M1 其中Mn的值应为1,2,…,N数字中不为MNMN-1…Mn+1的数字,并且应从小到大取值。因此,可设一个数组int Mark[N]用来分别标识一个数字是否已被使用。因此,对于生成Mn数字的算法如下: If(n==0) /*当前排列已生成*/ 输出数字串MNMN-1…Mn…M1; 结束; for(i=1; i=N; i++) If(Mark[i] == 0) /*表示该数字i未使用*/ Mark[i] = 1; /*数字i将被使用*/ 将数字i放到全排列位置n上(即MNMN-1…Mn的Mn ) 生成Mn-1 数字; Mark[i] = 0; /*数字i将被释放*/,使用递归方法!,问题4.4:代码实现*,#include #define MAX 10 int Mark[MAX] = {0}; /*标记数组,用来标记某个数字是否已被使用成为*/ char Stack[MAX+1]; /*全排列数字串*/ void rank(int m, int n); /* m记录下一个要生成的全排列数字应放在Stack中的位置,n表示还剩几个数字需要 生成*/ int N; int main () { scanf (“%d“, /*释放该数字*/ } },递归(续):递归问题总结*,通常包含如下特性的问题适合应用递归方法解决: 问题包含一个(或多个)基本实例,如 0! = 1 问题的解可以简化为包含比当前问题更简单一步的问题的解,并且最终问题解可归结到基本实例,如 n! = n*(n-1)!, 0!=1。,

展开阅读全文

c语言中分不分大小写,C语言高级语言程序设计(一)-第四章 程序设计方法-模块化与算法设计.ppt...相关推荐

  1. c语言中申请内存并初始化,c语言中结构体的定义、初始化及内存分配

    #include struct person { char *name; int age; }; int main() { //结构体可以定义在函数内,也可以定义到函数外 //相当于全局变量与局部变量 ...

  2. c语言textout字体大小,《WINDOWS程序设计》第四章关于TEXTOUT的小问题

    <WINDOWS程序设计>第四章关于TEXTOUT的小问题 文章原文是这样说的: 您会发现常常需要显示格式化的数字跟简单的字符串.我在第二章讲到过,您不能使惯用的工具(可 爱的printf ...

  3. c语言中字母大写转小写,C语言中字母大小写转换的简单操作

    大写字母要转换小写字母,要怎么操作呢?而在C语言开发中,我们经常会遇到这样或者那样的问题,别着急,爱站技术频道为你细细道来C语言中字母大小写转换的简单操作. C语言tolower()函数:将大写字母转 ...

  4. A13在c语言中是合法变量吗,C语言中局部变量和全局变量等在内存中的存放位置.doc-资源下载在线文库www.lddoc.cn...

    C语言中局部变量和全局变量_等在内存中的存放位置.doc C 语言中局部变量和全局变量 变量的存储类别static,extern,auto,register 8.8 局部变量和全局变量在讨论函数的形参 ...

  5. c语言中只能逐个引用6,C语言前面六个练习.doc

    C语言前面六个练习 第一章 C语言基础知识 4.一个函数的函数体可以没有变量定义和执行部分,函数可以是空函数 2.一个函数由两部分组成,它们是 函数体 和 函数的说明部分. 3.函数体的范围是 大括号 ...

  6. 指针在c语言中的运用,怎么理解C语言中的指针,如何运用?

    恰好我之前写了一系列介绍 C 语言的文章,介绍了什么是指针,以及为什么要使用指针,下面摘录一部分,感兴趣的话,可以点我了解更多. 什么是 C语言指针? 不同的数据类型的主要区别在于占用的存储空间不同. ...

  7. c语言中栈堆,全程剖析C语言中堆和栈的区别

    C语言中堆和栈的区别 1.申请方式 (1)栈(satck):由系统自动分配.例如,声明在函数中一个局部变量int b;系统自动在栈中为b开辟空间. (2)堆(heap):需程序员自己申请(调用mall ...

  8. c语言中占位符,Java C# C语言中的占位符

    一般拼接一段字符串在编程中是很常见的事,下面简单做个总结: 什么是占位符?占位符就是先占住一个固定的位置,等着你再往里面添加内容的符号. 1.Java中处理方法: package com.amos; ...

  9. c语言中时间类型的变量,C语言变量的类型

    C语言变量的类型 变量要有变量名,在内存中占据一定的存储单元,存储单元里存放的是该变量的值.不同类型的变量其存储单元的大小不同,变量在使用前必须定义.那么C语言变量的类型有哪些呢,一起来看看! (一) ...

最新文章

  1. 可疑文件_如何识别文件的真假
  2. Python爬虫之reuqests实现简单网页采集--网页采集教程
  3. 强化学习笔记2:序列决策(Sequential Decision Making)过程
  4. 360安全卫士 导致MySQL 5.0.24 自动关闭
  5. Acticity切换时ScrollView不停留原位置,自动滚动其他位置
  6. 官宣!张小龙史上最长演讲 4小时3万字完整版回应微信的一切
  7. python内置的数据结构_Python内置数据结构
  8. 前端笔记-thymeleaf发送数据给JavaScript变量(普通变量和List)
  9. python 文件服务器
  10. NumPy Essentials 带注释源码 五、NumPy 中的线性代数
  11. 判断是否是质数 c++java
  12. Linux系统war包解压目录,linux系统下解压war包
  13. 基于simhash的短文本去重
  14. GIS软件——arcgis10.2制作符号并链接符号库
  15. xp系统下载U盘安装教程,u盘安装xp系统方法
  16. C++统计正数数目和负数的数目,并计算平均值
  17. 蒙特卡罗算法是什么?
  18. Nexus 私服搭建及配置
  19. 访问网站只有文字,没有图片
  20. 量子计算 21 量子算法 6 (Shor Part III: QFT+PF)

热门文章

  1. 2014中国信用卡报告
  2. 图书信息管理系统(数据结构顺序表,c语言版)
  3. c 语言字体怎么改,Notepad++设置字体语言格式方法介绍
  4. twrp双清勾选哪两个_浅谈TWRP的作用
  5. 统计一下项目中的代码有多少行是你贡献的
  6. AOT(超前编译)实例分析
  7. [渣翻]从零开始写一个时序数据库
  8. 洛谷P3354 Riv河流 [IOI2005] 树型dp
  9. 阿里云服务器上面关闭tomcat报错
  10. 如何在微信复制链接直接可以用浏览器打开 微信调用手机浏览器打开指定链接