第三章学习小结—-转

【学习目标】

01掌握一维数组的声明和使用方法(OK)

02掌握二维数组的声明和使用方法(OK)

03掌握字符串的声明、赋值、比较和连接方法(连接很少用)

04熟悉字符的ASCII码和ctype.h中的字符函数

05正确认识++、+=等能修改变量的运算符(OK)

06学会用编译选项-Wall获得更多的警告信息(OK)

07了解不同操作系统中换行符的表示方法(嗯)

08掌握fgetc和getchar的使用方法(fgetc基本没用过)

09掌握预处理和迭代开发的技巧(嗯)

程序3-1 逆序输出

输入元素个数n,n<100,接着是n个的元素(大小不超过10^9),然后逆序输出

view plaincopy

#include <stdio.h>

  • #define N 110
  • int a[N];
  • int
  • main(void)
  • {
  • int n, i;
  • scanf("%d", &n);
  • for (i = 0; i != n; i++)
  • scanf("%d", &a[i]);
  • for (i = n-1; i != -1; i--)
  • printf(i != 0 ? "%d " : "%d\n", a[i]);
  • return 0;
  • }

附带:数组的复制

输入元素个数n,n<100,接着是n个的元素(大小不超过10^9),复制前m(m <= n)个元素后逆序输出,再复制全部元素后输出

view plaincopy

#include <stdio.h>

  • #include <string.h>
  • #define N 110
  • int a[N];
  • int b[N];
  • int
  • main(void)
  • {
  • int n, m, i;
  • scanf("%d %d", &n, &m);
  • for (i = 0; i != n; i++)
  • scanf("%d", &a[i]);
  • memcpy(b, a, sizeof (int)*m);
  • for (i = m-1; i != -1; i--)
  • printf(i != 0 ? "%d " : "%d\n", b[i]);
  • memcpy(b, a, sizeof (a));
  • for (i = n-1; i != -1; i--)
  • printf(i != 0 ? "%d " : "%d\n", b[i]);
  • return 0;
  • }

例题3-1开灯问题

view plaincopy

#include <stdio.h>

  • #include <string.h>
  • #define false -1
  • #define ture 1
  • #define N 1010
  • int a[N];
  • int
  • main(void)
  • {
  • int n, k, i, j;
  • int first = 1;
  • scanf("%d%d", &n, &k);
  • memset(a, false, sizeof(a));
  • for (i = 1; i != k+1; i++) {
  • for (j = i-1; j < n; j += i) {
  • a[j] = -a[j];
  • }
  • }
  • for (i = 0; i != n; i++) {
  • if (ture == a[i])
  • printf(1 == first ? first = 0, "%d" :" %d", i+1);
  • }
  • printf("\n");
  • return 0;
  • }

思路:简单模拟,这里我数组下标还是从0开始,所以最后输出下标时要+1;另外,用first标志变量更具通用性!

书上的方法是利用!0 == 1,而且利用(j%i == 0)来判断,就清晰简明来讲比上面的程序要好一点。

例题3-2 蛇形填数

view plaincopy

#include <stdio.h>

  • #include <string.h>
  • #define N 10
  • #define empty 0
  • int a[N][N];
  • int
  • main(void)
  • {
  • int n, i, j, m;
  • int count = 1;
  • scanf("%d",&n);
  • memset(a, empty, sizeof (a));
  • i = 0;
  • j = n-1;
  • a[i][j] = count++;
  • m = n*n;
  • while (m--) {
  • while (i+1 != n && a[i+1][j] == empty) a[++i][j] = count++;
  • while (j-1 != -1 && a[i][j-1] == empty) a[i][--j] = count++;
  • while (i-1 != -1 && a[i-1][j] == empty) a[--i][j] = count++;
  • while (j+1 != n && a[i][j+1] == empty) a[i][++j] = count++;
  • }
  • for (i = 0; i != n; i++) {
  • for (j = 0; j != n; j++)
  • printf(j != n-1 ? "%d " : "%d\n", a[i][j]);
  • }
  • return 0;
  • }

最后一个问题为什么是++tot而不是tot++;其实应当是针对起点从0开始而问的。我们只需要保证第一个while循环能执行n*n次,里面的第一个循环第一次执行确保count ==  2即可。

3.2字符数组

竖式问题——

view plaincopy

#include <stdio.h>

  • #include <string.h>
  • char base[11];
  • char tmp[20];
  • /*
  • *compare tmp[] with instr[]
  • *if all the elements of tmp[] belongs to instr[] return 1, else return 0;
  • */
  • int
  • cmp(char *t)
  • {
  • char *p, *q;
  • int count;
  • int len = strlen(base);
  • for (p = t; *p != ‘\0‘; p++) {
  • count = 0;
  • for (q = base; *q != ‘\0‘; q++) {
  • if (*p != *q)
  • count++;
  • }
  • if (count == len)
  • return 0;
  • }
  • return 1;
  • }
  • int
  • main(void)
  • {
  • int abc, de;
  • int count = 1;
  • scanf("%s", base);
  • for (abc = 100; abc != 1000; abc++)
  • for (de = 10; de != 100; de++) {
  • sprintf(tmp, "%d", abc);
  • if (cmp(tmp) == 0)
  • continue;
  • sprintf(tmp, "%d", de);
  • if (cmp(tmp) == 0)
  • continue;
  • sprintf(tmp, "%d", abc*(de%10));
  • if (cmp(tmp) == 0)
  • continue;
  • sprintf(tmp, "%d", abc*(de/10));
  • if (cmp(tmp) == 0)
  • continue;
  • sprintf(tmp, "%d", abc*de);
  • if (cmp(tmp) == 0)
  • continue;
  • printf("<%d>\n", count++);
  • printf("  %d\nX  %d\n-----\n", abc, de);
  • printf("%5d\n%4d\n-----\n%5d\n\n", abc*(de%10), abc*(de/10), abc*de);
  • }
  • printf("The number of solutions = %d\n", count-1);
  • return 0;
  • }

显然我写的这个程序简洁性不如书本上的,最大的区别在于书本用了一个我从没用过的函数strchr()

另外我的程序也可以设置一个buf[99],使用一个sprintf()把4个相关数字串存入buf[99],一次性检查。

谷歌一下strchr()的一个BSD版本实现如下:

view plaincopy

#include <stddef.h>

  • #include <string.h>
  • char *
  • strchr(const char *p, int ch)
  • {
  • char c;
  • c = ch;
  • for (;; ++p) {
  • if (*p == c)
  • return ((char *)p);
  • if (*p == ‘\0‘)
  • return (NULL);
  • }
  • /* NOTREACHED */
  • }

这个函数的功能就是返回ch在字符串的位置,如果字符串中没有ch,则返回NULL
因此LRJ老师的版本非常清晰简明~我还是敲一遍吧!

view plaincopy

#include <stdio.h>

  • #include <string.h>
  • int
  • main(void)
  • {
  • int i, abc, de, x, y, z, ok, count = 0;
  • char s[20], buf[90];
  • scanf("%s", s);
  • for (abc = 111; abc <= 999; abc++)
  • for (de = 11; de <= 99; de++) {
  • x = abc*(de%10);
  • y = abc*(de/10);
  • z = abc*de;
  • sprintf(buf, "%d%d%d%d%d", abc, de, x, y, z);
  • ok = 1;
  • for (i = 0; i < strlen(buf); i++)
  • if (strchr(s, buf[i]) == NULL)
  • ok = 0;
  • if (ok) {
  • printf("<%d>\n", ++count);
  • printf("%5d\nX%4d\n-----\n%5d\n%4d\n-----\n%5d\n\n", abc, de, x, y, z);
  • }
  • }
  • printf("The number of solutions = %d\n", count);
  • return 0;
  • }

看来用好C标准函数,可以提高不少效率和大大减少错误的可能性。

3.3最长回文字串

首先阅读了书本前面的分析——

第一步采用比较通用的方案:预处理。就是存入源串,再按约束构造一个新串。这个新串为处理后续问题提供了方便,相当于简化了问题,如果源串有用处则要保存好。

处理字符的函数一般定义在 ctype.h中,包括:

isalpha(),isdigit(),isprint()(判断是不是可打印的字符,回车符就是不可打印的?),toupper(),tolower()

有了仅仅保存大写字母的新串,可以暴力枚举所有子串,假定一般情况:子串不是回文的情况远远多于是回文。

可以得到如下代码——

view plaincopy

#include <stdio.h>

  • #include <string.h>
  • #include <ctype.h>
  • #define N 5010
  • char input[N];
  • char new[N];
  • int srcpt[N];
  • int
  • main(void)
  • {
  • int i, j;
  • int len = 0;
  • int max = 1;
  • int curlen = 0, savei = 0, savej = 0;
  • int tmp, p, q, ok;
  • fgets(input, sizeof(input), stdin);
  • for (i = 0; i != strlen(input); i++)
  • if (1 == isalpha(input[i])) {
  • new[len] = toupper(input[i]);
  • srcpt[len++] = i;
  • }
  • for (i = 0; i != len; i++) {
  • for (j = i; j != len; j++) {
  • curlen = j-i+1;
  • ok = 1;
  • p = i + curlen/2-1; /*Notice!!!*/
  • if (0 == curlen%2) {
  • q = p+1;
  • tmp = curlen;
  • }
  • else {
  • q = p+2;
  • tmp = curlen-1;
  • }
  • while (tmp > 0) {
  • if (new[p--] != new[q++])
  • break;
  • tmp -= 2;
  • }
  • if (tmp > 0)
  • ok = 0;
  • if (1 == ok && curlen > max) {
  • max = curlen;
  • savei = i;
  • savej = j;
  • }
  • }
  • }
  • for (i = srcpt[savei]; i <= srcpt[savej]; i++)
  • printf("%c", input[i]);
  • printf("\n");
  • return 0;
  • }

正如LRJ所言,这个版本处理5000个a时显得非常吃力,上面代码一般情况下效率可能还可以接受,但对于全是a这种极端情况则所有枚举情况都是以最坏的效率进行的!

书上的版本——

书上的思路是一次遍历新串,设i为新串当前位置

当前位置i对应的单个字符必定已经是回文串,以i为中心,向两边扩展,是回文串则记录信息(此时判断得到的回文串长度大小必定是奇数);

当前位置i对应的字符和i+1对应的字符(两个字符)若是回文串,或者以 i和i+1 为中心,向两边扩展,是回文串则记录信息(此时判断得到的回文串长度大小必定是偶数);

这样子就能充分利用当前已知的回文串,其实这个思想是动态规划的思想!

以ababbbb为例,循环过程如下:

i == 0;s[0] == a;a是回文,max更新为1,无法继续扩展;

对于s[0~1],ab不是回文,break;

i == 1;  s[1] == b;b是回文,扩展一步,aba是回文,max更新为3,无法继续扩展;

对于s[1~2],ba不是回文,break;

i == 2;s[2] == a;a是回文,扩展一步,bab是回文,再扩展一步,ababb不是回文,break;

对于s[2~3],ab不是回文,break;

i == 3;s[3] == b;b是回文,扩展一步,abb不是回文,break;

对于s[3~4],bb是回文,扩展一步,abbb不是回文,break;

i == 4;s[4] == b;b是回文,扩展一步,bbb是回文,再扩展一步,abbbb不是回文,break;

对于s[4~5],bb是回文,扩展一步,bbbb是回文,更新max为4,无法继续扩展;

i == 5;s[5] == b;  b是回文,扩展一步,bbb是回文,无法继续扩展(右边会越界);

对于s[5~6],bb是回文,但无法继续扩展(同样右边会越界);

i == 6;s[6] == b;b是回文,无法继续拓展;

不存在s[6~7],i+1 == 7会越界;

结束;

代码是相当地清晰有力——

view plaincopy

#include <stdio.h>

  • #include <string.h>
  • #include <ctype.h>
  • #define N 5000+10
  • char buf[N];
  • char s[N];
  • int p[N];
  • int
  • main(void)
  • {
  • int m = 0, max = 0;
  • int x, y, i, j;
  • fgets(buf, sizeof (buf), stdin);
  • for (i = 0; i < strlen(buf); i++)
  • if (isalpha(buf[i])) {
  • p[m] = i;
  • s[m++] = toupper(buf[i]);
  • }
  • for (i = 0; i < m; i++) {
  • /* 对于当前位置i,以回文s[i]为中心不断扩展,得到奇数长度的最长回文串 */
  • for (j = 0; i -j >= 0 && i +j < m; j++) {
  • if (s[i -j] != s[i +j])
  • break;
  • if (j*2+1 > max) {
  • max = j*2+1;
  • x = p[i -j];
  • y = p[i +j];
  • }
  • }
  • /* 对于当前位置i,若s[i~i+1]是回文,则以其为中心不断扩展,得到偶数长度的最长回文串 */
  • for (j = 0; i -j >= 0 && i+1 +j < m; j++) {
  • if (s[i -j] != s[i+1 +j])
  • break;
  • if (j*2+2 > max) {
  • max = j*2+2;
  • x = p[i -j];
  • y = p[i+1 +j];
  • }
  • }
  • }
  • for (i = x; i <= y; i++)
  • printf("%c", buf[i]);
  • printf("\n");
  • return 0;
  • }

总结

这章首先学到了strchr()函数,用于查找一个字符在一个字符串中的位置;

对于求最长子回文,书上给出了动态规划的思想,显得相当优美。对于每一个当前i,充分利用子问题的解(单个字符就是回文,作为奇数串的“最小”解;若s[i~i+1]也是回文则是偶数串的“最小”解,其实也可以把空串理解回文,即偶数串的“最小”解,这样理解甚至更加自然),从而快速地得到当前i对应的最大子回文(设置当前max就微不足道了),碉堡了

原博客地址:http://blog.csdn.net/architect19/article/details/8567507

第三章学习小结—-转

时间: 2024-08-02 09:35:56

第三章学习小结—-转的相关文章

第三章学习小结

第三章主要学习了关于栈和队列的知识,知道了有关栈和队列的初始化和基本操作.栈是只在一头进行插入与删除操作的数据结构,而队列是可以在两头进行插入与删除操作的数据结构.此外栈和队列分别可以分为链栈与顺序栈,链队与顺序队列.栈的特点是先进后出,队列的特点是先进先出. 在这里分享有关栈的函数: #include <stack> //头文件 stack <elemtype> L //定义栈 push():L.push(x) 将数据x放在栈顶 top():L.top()返回栈顶元素 pop()

数据结构 第一章学习小结

数据结构   第一章学习小结 1.数据结构第1章的心得体会: 这周学习了数据结构的绪论及第一章.初步了解了数据结构与算法的相关概念,一开始看书看视频时觉得还挺抽象的,不能够完全理解.但是反复多看了几遍之后,结合例题,自己去操作去跑代码,慢慢觉得容易理解接受起来了.由于现在以网课形式进行教学,老师上课的同时基本还是靠自己去理解学习.当然老师也发挥很大的作用,比如让我们更深入的了解递归的空间复杂度为什么与问题规模有关,又怎样去找到该函数的临界值等等.既锻炼了我们深入思考的能力,也让我们更加清楚了解不

第三章内容小结

1.内容小结:在第三章的学习中我们学习到了两种特殊的线性表:栈和队列. (1)特殊性:栈:限定仅在表尾(栈顶)进行插入或者删除的线性表,后进先出. 队列:只允许在表的一端进行插入(队尾),而在另一端(队头)进行删除的线性表.先进先出. (2)存储方式:顺序存储(顺序栈:循环队列)和链式存储(链栈:链队). (3)主要操作: 栈:入栈和出栈.对于顺序栈的入栈和出栈操作前要判断栈满或栈空. 队列:入队和出队.对于顺序队的循环队列进队和出队操作要判断队满或队空.涉及队头或队尾指针的修改都要将其对MAX

《构建之法》第三章学习心得

这周我学习了<构建之法>第三章,讲述了软件工程师的成长.软件系统的绝大部分模块都是由个人开发或维护的.在软件工程的术语中,这些单个的成员叫做Individ-ual Contributor(IC).IC在团队中的流程是怎么样的呢?以开发人员为例,流程如下. 1.通过交流.实验.快速原型等方法,理解问题.需求或任务 2.提出多种解决办法并估计工作量 3.其中包括寻找以前的解决方案,因为很多工作是重复性的 与相关角色交流解决问题的提案,决定一个可行的方案 执行,把想法变成实际中能工作的代码,同时验证

201671010105 2016-2017-2《Java程序设计》第三章学习心得

通过学习第三章,我的总结有以下几点: 先说内容,第三章我们主要学习的是java的基本程序设计结构,学习了与之相关的一些内容,注释,数据类型,变量,运算符,字符串,输入输出语句,数组等等,在这些内容中,有些是在C语言中同样可以学到的,我们上学期已经学过,但也有很多是与c不一样的,是首次接触,比如注释,无论是java还是c语言,对于编程者而言,给自己编写的程序注释是一种良好的习惯,不止自己看懂,别人也能看懂,又比如数据类型,java中多了byte(字节型)和boolean(布尔型).在后面内容中也有

ch3第三章的小结——杨智雯

第四周c++学习情况. 学习情况:周一在实验室上了第三章的输入输出流,上课状态良好,老师讲的都明白了.周三老师讲解了师兄给我解释过的数组问题,但是还是不是很懂,了解了直接用c1之类的字符型直接加减数字来使输出发生变化,并学习了如何使字符型变量变成表格中的数字号码. 遇到的困难:可是ch3中的编程作业统计和保留小数的问题,老师应该是没有讲到的,我并不会啊!!/(ㄒoㄒ)/~~咨询了师兄,可是按照师兄的解法还是输出不了啊!!!实验二的内容经过老师的讲解基本上都解决了问题,再acm培训课程中也了解了具

20165233 Java第二、三章学习总结

2017-2018-2 <Java程序设计>第二周学习总结 教材学习内容总结 第二.三章 ch2 标识符与关键字 基本数据类型: 逻辑类型:boolean 整数类型:int.byte.short.long(注意:long型常量用后缀L来表示:且Java中没有无符号声明) 字符类型:char 浮点类型:float.double(float常量后面必须有后缀f或F ) 类型转换运算 输入.输出数据 数组 ch3 运算符与表达式 if条件分支语句 switch开关语句 循环语句(包括for语句.wh

第三章学习总结

第三章 栈和队列 本章我们学习了线性结构的另外两种表现形式:栈和队列. 栈:只限定仅在表尾进行插入或删除的线性表.表尾段称作栈顶,表头端称作栈底,它的修改原则是后进先出,用于按照保存数据时的相反顺序来使用数据.类似于我们生活中放书拿书,最后叠上去的最早被抽出来. 队列:是一种先进先出的线性表,它只允许在表的一段进行插入,而在另一端删除元素.允许插入的一段称为队尾,允许删除的一段称为队头.它类似于我们生活中排队买东西,先来的先买,先输入的数据先输出. 接下来谈谈我在做作业时所遇到的问题. 括号匹配

数据结构第四章学习小结

第四章主要是串和数组的学习,之前对串和数组的应用仅限于对其单独处理,本章学习着重于对具体题目的实际操作,实践了串的模式匹配算法,对其有了更深入的了解,数组的应用拓展到了稀疏矩阵的存储的实现. 一.串 串的模式匹配 BF算法 首先未匹配到串尾时,将两个字符串一一匹配,可用C++自带的length()函数实现 while(i<=S.length()&&j<=T.length()) 接下来就是匹配的过程 if(S[i]==T[j]){ i++;j++; }//若匹配则继续比较下一位