2018年物联网学生科协软件第二次培训总结
文章目录
一、数组----多数据存储
1. 数组的定义
数组是c语言中的一种复合数据类型,是相同数据类型的有序集合。
2. 数组的声明
数据类型 数组名[下标个数];
int array[100];
double d_array[30];
3. 数组的初始化
(1).
int arr1[3] = {1, 2, 3};
int arr2[] = {1, 2, 3}; //在这里,我们arr[3]里边的数字可以不用写
(2).
int arr2[3] = {1, 2}; //也是可以的,注意最后一个数初始化为0
(3).
int arr3[3] = {1, 2, 3, 4}; //错误,不能超过数组长度
4. 数组中元素的访问
通过数组下标来访问每个元素
int a[5]={1,2,3,4,5};
a[0]=1; //a[0]为数组中的首个元素
a[1]=2;
a[2]=3;
a[3]=4;
a[4]=5;
小代码示例:
int score[10]; //存储10个整型值的数组
int count = 10; //学生人数
printf("Enter the 10 scores: \n");
for(int i=0; i< count; i++)
{
scanf(“%d”, &score[i]); //从键盘读入一个分数并存到数组里
}
5.数组的内存分配
int a[100];
double b[30];
printf("%d\n",sizeof(a)); //400
printf("%d",sizeof(b)); //240
当编译器对以上代码进行编译时,就会为数组分配内存单元。 假设计算机指定数组score中的元素从地址为1000的地方开始存放。
具体分配原理如下图所示:
二、数值交换问题
1. 最常用的方法----建立临时变量
小代码示例:
int a=10,b=20,temp;
temp = a;
a = b;
b = temp;
printf("%d%d", a,b);
2. 数学计算的方法
小代码示例:
int a =10, b = 20;
a = a - b;
b = a + b;
a = b - a;
printf("%d%d", a, b);
缺点:两个数的和可能会越界,适用于两个比较小的数
3. 异或运算的方法
小代码示例:
int a =10, b = 20;
a = a^b;
b = a^b;
a = a^b;
printf("%d%d", a, b);
思路:将a,b转换为二进制数(10 = 01010,20 = 10010)
按位异或(两个值相同为0,不同为1)
4. 数组换标不换值的方法
小代码示例:
int a=10,b=20;
int array1[2] = {10,20}; //存a、b
int array2[2] = {0,1}; //存下标
b = array1[array2[0]];
a = array1[array2[1]];
printf("%d%d",a,b);
思路:用数组元素作为数组的下标,这种方法换逻辑不换存储
三、 基本的排序算法
1. 冒泡排序(升序)
基本操作:比较数组中相邻的元素。如果这个数比它后一个大,就交换它们两个。
第一步:从数组第一和第二个元素(第一对)开始,执行基本操作,直到数组末尾的两个元素(最后一对)。这样执行一遍后,最后的元素会是数组中最大的数。
第二步:重复基本操作,但每次操作的元素会少一个(因为执行完n次操作后,前n个最大的元素会被排好序),直到没有任何一对数字需要比较。冒泡排序完成。
小代码示例:
#include<stdio.h>
int main(){
int a[5] = {2,3,4,1,6};
int i, j, temp;
for (j = 0; j < 4; j++)
for (i = 0; i < 4 - j; i++){
if(a[i] > a[i + 1]){
temp = a[i];
a[i] = a[i + 1];
a[i + 1] = temp;
}
}
for(j = 0; j < 5; j++){
printf("%d ",a[j]);
}
return 0;
}
2. 选择排序(升序)
基本操作:每次找出操作序列中最小的数放到最前面。
第一步:第一次操作遍历整个序列,将最小的元素放到首位。
第二步:重复基本操作,第n次操作从序列第n个元素开始遍历序列,将最小的元素放到序列第n个位置。直到某次操作序列中没有元素可以遍历。选择排序完成。
图解如下:
小代码示例:
#include<stdio.h>
int main(){
int a[5] = {2,3,4,1,6};
int i, j, temp;
//每一次都找出最小的放到前面
for(i = 0; i < 4; i++)
{
min = i; //查找最小值的下标
for(j = i+1; j < 5; j++)
if(a[min] > a[j])
min = j; //交换最小值的下标
//判断一下最小的是不是自身,如果不是则交换位置
if(min != i)
{
temp = a[min];
a[min] = a[i];
a[i] = temp;
}
}
for(i=0;i<5;i++){
printf("%d",a[i]);
}
}
3. 插入排序(升序)
基本操作:将有序序列的后一个元素插入到序列当中,使其依然有序。
第一步:假设初始时有序序列中只有第一个元素,此时执行基本操作,会将第二个元素排好序。此时有序序列中有两个元素。
第二步:重复基本操作,有序序列的长度不断增加。当有序序列中的元素个数和原序列相等时,即所有元素均有序排列时,插入排序完成。
图解如下:
小代码示例:
#include<stdio.h>
int main(){
int i, j, temp;
int a[5] = {2,3,4,1,6};
for(i = 1 ;i < 5 ; i++){
temp = a[i];
for(j = i ; j>0 && a[j-1]>temp ; j--)
a[j] = a[j-1];
a[j]=temp;
}
for(i=0;i<5;i++){
printf("%d",a[i]);
}
return 0;
}
四、 字符与字符串
1. 字符的概念
字符型数据包括 字符常量 和 字符变量。
(1). 字符常量:
- 概念 :
是单引号括起来的一个字符。例如:‘a’、‘b’、‘=’、‘?’都是合法的字符常量。 - 特点 :
①字符常量只能用单引号括起来,不能用双引号或者其他字符;
②字符常量只能是单个字符,不能是字符串;
③字符可以是字符集中的任意字符,但数字被定义为字符型之后不能参与数值的运算。(比如:‘3’和3) - 特殊的字符常量:
在上次培训我们提到的转义字符是一种特殊的字符常量,其具有特定的含义不同于字符原有的意义即为”转义”。
(2). 字符变量:
- 字符型变量用来存储字符数据,即单个字符。
- 字符变量的类型说明符是char。
注意: ①每个字符变量被分配一个字节的内存空间,因此只能存放一个字符;
代码小示例:
char a='h';
printf("%d",sizeof(a)); //1
字符值是以ASCII码的形式存放在变量的内存单元之中的。
2. 字符的输入与输出
char ch;
scanf(“%c”,&ch);
printf(“%c”,ch);
小练习: 输入一个字母,将其大写转小写,小写转大写。
小代码示例:
#include<stdio.h>
int main(){
char a;
scanf("%c",&a);
if(a>=65&&a<=90)
a += 32;
else if(a>=97&&a<=122)
a -= 32;
printf("%c",a);
return 0;
}
3. 字符串的概念
从形式上看,一个字符串就是用一对双引号括起来的一串字符,其双引号是该字符串的起,止标志符,它不属于字符串本身的字符。
例:
“string”
“物联网院学生科协”
4. 字符串的初始化
字符型数组表示字符串
char[]=“iotesta”
char b[20]=“I love esta”
Char str[6]={‘H’, ‘e’, ‘l’, ‘l’, ‘o’, ‘\0’}
注意: 在进行逐个元素初始化时,必须明确写出字符串结束符’\0’
5. 字符串的输入与输出
scanf(“%s”,str); //(注意!不用写&)
printf(“%s”,str);
小练习:输入一个字符串,将其大写转小写,小写转大写。
小代码示例:
#include<stdio.h>
int main(){
int i;
char a[12]="iLoVEesTA";
for(i=0;i<12;i++){
if(a[i]>=65&&a[i]<=90)
a[i] += 32;
else if(a[i]>=97&&a[i]<=122)
a[i] -= 32;
}
printf("%s",a);
return 0;
}
6. 关于字符串的常用函数
函数:函数是一个封装一个功能的代码块,便于重复使用。主要是传入参数,获得返回值,或者在函数内对参数进行操作。其中关于字符串的常用函数都在<string.h>头文件里,即在使用时要在最上面加上 #include<string.h>
(1). 求字符串长度----strlen函数
int strlen (const char s[ ]);
①功能:计算字符串的长度
②返回值:返回字符串的实际长度,不包括‘\0’在内
③注意:在求字符串长度的过程中,遇到字符串‘\0’就结束,只计算起始位置到‘\0’前面的字符个数,例如:strlen(“AB\0CD\0EF”)的结果是2
sizeof()与strlen()函数的区别:
sizeof()计算的是系统为变量分配的内存空间的大小,会加上隐藏结束符的长度。
(2). 字符串拷贝
- strcpy函数
char* strcpy (char *s1, const char *s2);
①功能:将字符串s2复制到s1指定的地址(即将字符串s2拷贝到s1中去)
②返回值:字符串s1的首地址。
③注意:字符串s1必须是数组或者已经分配空间的字符型指针,并且空间足够大,该函数不分配空间;拷贝时‘\0’一同被拷贝;不能使用赋值语句给一个字符数组赋值;
- strncpy函数
char* strncpy (char *s1, const char *s2, int n);
功能:将s2的前n个字符复制到s1中对应的地址, 并在末尾加‘\0’ ;
(3). 字符串连接----strcat函数
char* strcat (char *s1, const char *s2);
①功能:将字符数组s2连接到字符数组s1尾部
②说明:字符数组s1必须空间足够大(s1的存储空间≥strlen(s1)+strlen(s2)+1),连接前,两串均以‘\0’结束,连接后,串s1原来的‘\0’被覆盖,新得到的字符串最后加‘\0’;调用此函数后,s1的长度等于s1、s2两个字符串长度之和。
小代码示例:
char a[20]="Hello"; //字符串长度为5
char b[ ]="World"; //字符串长度为5
strcat(a," "); //连接一个空格到a串之后
strcat(a,b); //把b串连接到a串之后
printf("%s %d",a,strlen(a));
//执行该程序的输出结果是: Hello World 11
(4). 字符串比较----strcmp函数
int strcmp (const char *s1, const char *s2);
①功能:比较字符串s1和s2。
②比较规则:对两个串从左向右逐个字符比较(ASCII码),直到遇到不同的字符或者‘\0’为止;
③返回值:返回int型整数。
(1)若s1 < s2,返回负整数;
(2)若s1 > s2,返回正整数;
(3)若s1 = s2,返回零;
注意: 字符串比较不能用“==”,必须用strcmp;
以上函数的综合使用
小代码示例:
char str1[10];
char str2[10];
scanf("%s%s",str1,str2);
//求字符串的长度
printf("%d %d\n",strlen(str1),strlen(str2));
//字符串连接
strcat(str1,str2);
printf("%s\n",str1);
//字符串拷贝
strcpy(str1,str2);
printf("%s\n",str1);
//字符串比较
printf("%d\n",strcmp(str1,str2));
五、有趣的小算法
贪心算法
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来最好的选择。也就是说,将整体最优问题分解为局部来考虑,做出的是在某种意义上的局部最优解。
贪心选择 — 第一个基本要素
贪心选择是指,所求问题的整体最优解可以通过一系列局部最优的选择来达到。
对于一个具体问题,要确定它是否具有贪心选择的性质,我们必须证明每一步所作的贪心选择最终能得到问题的最优解。通常可以首先证明问题的一个整体最优解,是从贪心选择开始的,而且作了贪心选择后,原问题简化为一个规模更小的类似子问题。
- 贪心算法相关经典问题:
货币选择问题、背包问题、区间调度问题、字典序最小问题
小练习: 双11已经不远了,但一橙小萌新很苦恼,因为他每个月的15号才能收到生活费。为了解决这个问题,他决定提前向妈妈索要11月份的生活费,但他的妈妈却没有那么容易将钱给他。妈妈说:你不是在学编程吗?那你告诉我,如果接下来几个月的生活费我都不用移动支付的方式,而是以纸币的形式给你,我最少要准备多少张人民币呢?你回答出来就提前给你11月份的生活费,否则你双11就别买东西了!
一橙小萌新想买的罗技鼠标在购物车里很久了,要是错过双11就太悲伤了,你们快帮帮他吧!(假设每个月的生活费是整数。人民币一共有100元、50元、10元、5元、2元和1元六种)。
Input
输入数据第1行是一个整数n(n<100),表示接下来的n个月,第2到第n+1行每行一个数,表示每个月一橙小萌新的生活费。
Output
输出一个整数x,表示至少需要准备的人民币张数。每个输出占一行。
Sample Input
3 1 2 3
Sample Output
4
小代码示例:
while(scanf("%d",&n)!=EOF&&n!=0)
{
sum=0;
for(i=0; i<n; i++)
{
scanf("%d",&m);
sum+=m/100;
m%=100;
sum+=m/50;
m%=50;
sum+=m/10;
m%=10;
sum+=m/5;
m%=5;
sum+=m/2;
m%=2;
sum+=m;
}
printf("%d\n",sum);
}
思路:从大面值钞票往下选,便是最少的张数。
贪心算法不是对所有问题都能得到整体最优解,关键是贪心策略的选择,选择的贪心策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。