用数组计算Fibonacci数列的前10个数,并按每行打印5个数的格式输出。
输入样例
无
输出样例
1 1 2 3 5
8 13 21 34 55
注意:
① 只需打印Fibonacci数列的前10个数
② 每行最多只能打印5个数
在解答本题前,我们需要明白什么是Fibonacci数列。
Fibonacci数列(以下简称fi数列),即斐波那契数列,这个数列有一个特点:从数列的第三项开始*(包括第三项)*,每个项都等于它前两个项的和。
fi数列的第一、第二项的值分别为:1、1,由此可往后递推出后面项的值。
① 利用fi数列的特性,我们可以借助循环或递归来进行推算第n个项的值(n ≥ 3, n∈Z),这里我们使用循环的方法进行解答;
② 每推算一个项,就将其储存到数组中*(即对数组的元素逐个赋值)*;
③ 赋值结束之后,再利用循环逐个将数组里的值打印输出,并结合取模运算,按照题目要求,每打印5个数字就进行一次分行。
#include
#define N 10//利用宏定义,定义一个值为10的常量N int main() { int fi[N];//定义一个有10个int型元素的数组,储存fi数列 fi[0] = fi[1] = 1; /*<数组赋值>*/ for (int i = 0; i < N; i++) { if (i < 2) { fi[i] = 1; }//第一、第二项的值均为1 else { fi[i] = fi[i - 1] + fi[i - 2]; }//从第三项(i=2)开始推算,第i项的值等于第i-1项与第i-2项(即前两项)之和 } for (int i = 0; i < N; i++) { printf("%d ", fi[i]); if (i % 5 == 4) { printf("\n"); }//每输出五个数之后,进行换行操作 } return 0; }
*注: 黄 绿 色 数 字 是 \textcolor{YellowGreen}{黄绿色数字}是 黄绿色数字是 红 色 数 字 的 和 \textcolor{Red}{红色数字}的和 红色数字的和
本题的关键在于,如何运用数组和循环来推算Fibonacci数列
一般来说,在定义数组时,其方括号中只能使用常量或常量表达式 (严格地说,应该是一个有限正整数或有限正整数的表达式)
在定义数组时,数组方括号中的数字m,表示长度,表明该数组有m个元素;而在调用数组的元素时,数组方括号中的数字n(即下标),表示第n+1个元素
-例如:
定义时,int arr[m]; (m = 10) 那么调用时,arr[n]; (0 ≤ n < m, n ∈ N)
输入正整数**n
和整数x
,再输入n个整数并存入一个数组a
中,然后在数组a
中查找x
**,如果找到,输出相应元素的最小下标,否则,输出"Not Found"。
输入样例1
5 9
2 9 8 1 9
输出样例1
1
输入样例2
4 101
9 8 -101 10
输出样例2
Not Found
注意:
① 对于这类无法确定数组长度的题目,在定义的数组时长度要足够大,避免出现数组越界的情况
② 只需要输出一次下标,且该下标是所有符合条件的下标中最小的一个
③ 输出“Not Found”时的拼写和字母大小写是否正确
① 定义一个整型变量**index
**,并赋值一个负数,用于记录下标;
② 使用一次循环,将所输入n个整数全部储存到数组中;
③ 再使用一次循环,检测数组中有无符合条件的元素,并通过变量**index
**记录符合条件的元素的下标;
④ 根据记录的变量分辨情况,输出对应的结果。
#include
int main() { int n, x; int index = -1;//记录下标的变量,初始赋值一个负数 int a[1000];//定义一个较大的长度,防止出现异常 scanf("%d %d", &n, &x); for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } /*<遍历查找>*/ for (int i = 0; i < n; i++) { if (a[i] == x)//发现符合条件(等于x)的数 { index = i;//记录下标,使得index≥0 break;//跳出循环,不再往后检测 } } if (index < 0) { printf("Not Found"); }//index<0,表示没能在数组范围内找到x else { printf("%d", index); }//index≥0,表示在数组范围内找到了x return 0; }
break
关键字,减少不必要的循环,在一定程度上能提高程序的运行效率输入正整数**n
**(1 < n ≤ 10),再输入n个整数,输出最小值和它对应的下标,并与第一个数交换,再输出交换后的n个数。
输入样例1
5
5 9 8 2 15
输出样例1
2 3
2 9 8 5 15
输入样例2
6
-1 9 2 8 1 6
输出样例2
-1 0
-1 9 2 8 1 6
注意:
① 只有最小值需要与第一个数交换
② 先输出最小值,再输出最小值的下标,最后再输出经过交换处理的所有数
① 定义两个整型变量**min
、index
,分别用于记录最小值**、最小值的下标;
② 使用一次循环,将所输入n个整数全部储存到数组中;
③ 再使用一次循环,查找数组中值最小的元素,并通过变量**min
和index
,分别记录该元素的值和下标**;
④ 令最小值和第一个元素交换;
⑤ 输出结果。
#include
int main() { int n; int min;//最小值 int index;//最小值下标 int a[10]; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } /*<遍历查找>*/ for (int i = 0; i < n; i++) { if (i == 0 || a[i] < min) {//附加一个条件(i == 0),表示假设最小值min是第一个元素的值 min = a[i];//记录最小值 index = i;//记录最小值的下标 } } /*<元素互换>*/ //这里了一个类似的骚操作:用一个空杯子将一瓶可口可乐和一瓶百事可乐调包 int temp = a[0]; a[0] = a[index]; a[index] = temp; printf("%d %d\n", min, index); for (int i = 0; i < n; i++) { printf("%d ", a[i]); } return 0; }
以输入样例2为准,对于<元素互换>部分,各变量的变化流程如下图所示:
*注: 绿 色 数 据 将 会 取 代 \textcolor{ForestGreen}{绿色数据}将会取代 绿色数据将会取代 红 色 数 据 或 与 之 互 换 \textcolor{Red}{红色数据}或与之互换 红色数据或与之互换
a[0] = a[index];
a[index] = a[0];
逻辑上好像没啥毛病,但是在程序中,代码会严格按照各自的顺序运行处理,因此这样的写法是不可取的
输入一个整数**n
**(1 < n ≤ 10),再任意输入n个整数,用选择法将它们从小到大排序后输出。
输入样例1
5
3 5 2 8 1
输出样例1
1 2 3 5 8
输入样例2
8
5 -1 7 4 -6 0 4 1
输出样例2
-6 -1 0 1 4 4 5 7
注意:
① 按照从左到右的顺序,数字由小到大排列
选择排序(Selection sort),是数组的基础排序法的一种,和冒泡排序(Bubble Sort)相比,它的优点在于每次循环只需执行一次元素交换,因此运行效率也会更高一些,但它的主要缺点是不稳定,感兴趣的童鞋可以问度娘,这里不做过多的解释。
工作原理:每次从未排序的元素中找出这些元素的最值,并将这个最值与每次查找的第一个元素的值交换,如此循环,直至范围内的元素不足2个时,即意味着排序结束 。
① 定义一个变量**index
,用于记录每次排序时查找到的最小值的下标;
② 先利用一层循环,对每个元素进行排列;
③ 在上一层循环中,再嵌入一层循环,用于查找未排序范围内的最小值;
④ 每次查找到最小值后,根据index
记录,使其下标与index
相同的元素(arr[index]
)与未排序范围内的最左端的数(arr[i]
**)交换;
⑤ 嵌套循环结束后,表明排序完成,此时输出结果即可。
#include
#define N 10 int main() { int n; int index;//最小值的下标 int arr[N]; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d", &arr[i]); } /*<选择排序>*/ for (int i = 0; i < n; i++) {//第一层循环 index = i;//假设最小值是第i个元素 for (int j = i; j < n; j++) {//第二层循环,每次查找的第一个元素是arr[i] if (arr[index] > arr[j]) {//检测到比当前最小值更小的数 index = j;//原最小值的下标替换为当前最小值的下标 } } int temp = arr[i];//元素互换 arr[i] = arr[index]; arr[index] = temp; } for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } return 0; }
以输入样例1为准,数组各个元素的值在n次排列中的变化如下表所示:
arr[0] | arr[1] | arr[2] | arr[3] | arr[4] | 查找结束后 | |
---|---|---|---|---|---|---|
i = 0 | (3) | 5 | 2 | 8 | (1) | arr[0]与arr[4]的值互换 |
i = 1 | 1 | (5) | (2) | 8 | 3 | arr[1]与arr[2]的值互换 |
i = 2 | 1 | 2 | (5) | 8 | (3) | arr[2]与arr[4]的值互换 |
i = 3 | 1 | 2 | 3 | (8) | (5) | arr[3]与arr[4]的值互换 |
i = 4 | 1 | 2 | 3 | 5 | 8 | 排序完成,循环结束 |
以输入样例1为准,对于<选择排序>部分,查找最小值和交换的部分流程如下图所示:
*注: 两 个 不 同 的 绿 色 数 字 在 查 找 结 束 后 相 互 交 换 , 两个\textcolor{ForestGreen}{不同的绿色数字}在查找结束后相互交换, 两个不同的绿色数字在查找结束后相互交换, 红 色 方 框 为 未 进 行 排 序 的 数 组 范 围 \textcolor{Red}{红色方框}为未进行排序的数组范围 红色方框为未进行排序的数组范围
该题的难点在于查找和交换最值的部分,如何用循环进行查找和交换位置的确定是解决该题的关键
如何用循环进行查找和交换位置的确定是关键
某电视台要对该台的8个电视栏目的受欢迎程度进行一次调查,共调查了n
位观众(1 ≤ n ≤ 1000),现要求编写程序,输入观众的投票,统计输出各个栏目的得票情况。
输入样例
6
3 1 6 9 8 1
输出样例
1 2
3 1
6 1
8 1
注意:
① 可能会有观众投出无效票
② 只输出得票数不为0的栏目编号
① 定义一个整型变量**n
**,表示调查了几位观众;
② 使用一次循环,对每个观众的投票进行判断和统计;
③ 筛选出得票数不为0的栏目,并输出对应的结果。
#include
#include //memset函数的头文件 #define N 9//根据电视栏目数定义的宏定义常量,这里定义为9有一定的好处 int main() { int n; int program[N];//各电视栏目票数 //for (int i = 0; i < N; i++) program[i] = 0;//利用循环,数组元素全部赋值为0 memset(program, 0, sizeof(program));//利用memset函数,将数组元素全部赋值为0 scanf("%d", &n); for (int i = 0; i < n; i++) { int vote;//观众给对应栏目投的票 scanf("%d", &vote); if (vote >= 1 && vote <= 8) {//有效票 program[vote]++;//栏目票数加一 } } for (int i = 1; i < N; i++) {//这里i初值为1,跳过program[0] //因为在该数组中,program[8]是第8个栏目 //加上program[0],一共九个元素,所以才将N定义为9 if (program[i] > 0) { printf("%d %d\n", i, program[i]);//输出栏目对应的编号和票数 } } return 0; }
遇到这类题目时,数组的长度不一定要根据题目给出的一些数来决定,可以依情况稍稍调整,使编写过程更简洁*(以本题为例,为电视栏目所定义的数组长度N是9而不是8,不然在编写时就需要为某些变量进行±1等操作,比如program[i - 1],vote -= 1等)*
在编写时,多多考虑可能出现的特殊情况,最好作出相应的对策
输入正整数**n
(1 < n ≤ 10)和整数x
,再输入n个从小到大有序排列且不重复的整数,并存入一个数组a
中,然后在数组a
中查找x
**,如果找到,输出相应元素的下标,否则,输出"Not Found"。
输入样例1
10 7
1 2 3 4 5 6 7 8 9 10
输出样例1
6
输入样例2
6 1
-3 -1 0 2 4 6
输出样例2
Not Found
注意:
① 查找到目标值后,输出的是目标值的在数组中的下标
② 输出“Not Found”时的拼写和字母大小写是否正确
二分查找,又称折半查找(Binary search),是一种比遍历要高效的查找方法,但只有查找目标有序排列且无重复的目标时可用,因此这种查找方法主要适用于有序的顺序表。
工作原理:获取一个区间,然后取其中间值,将整个区间一分为二(每个区间是整个区间的½),再根据目标值可能出现的情况选择其中一个区间,再继续将这个区间一分为二(每个区间是整个区间的¼),如此循环,直至找到目标值或区间不可再分。
① 二分查找的查找方式具有规律性,因此可以借助循环或递归来查找目标值,这里我们使用递归的方法进行解答;
② 定义一个函数方法**binarySearch
,对一个区间进行判断,取其中间值,将区间划分成两个半区间,确定目标值可能会在的哪一半区间;
③ 确定目标值可能所在的那半区间后,立即再调用这个binarySearch
**,对这半个区间再进行一次判断,如此递归,直到找到目标值或区间不可再分;
④ 根据查找结束后返回的下标,输出对应的结果。
#include
int binarySearch(int l, int r, int x, int a[]) { int mid = (l + r) >> 1;//闭区间[l,r]的中间值 int idx = -1;//记录下标的变量,初值为负数,表示还没找到x if(x == arr[mid]) idx = mid;//发现中间值a[mid]等于x,则记录其下标 else if(arr[l] <= x && x < a[mid])//x在前半区间:a[l] ≤ x < a[mid] idx = binarySearch(l , mid - 1, x, arr);//在数组[l,mid-1]范围中继续二分查找 else if(arr[r] >= x && x > arr[mid])//x在后半区间:a[mid] < x ≤ a[r] idx = binarySearch(mid + 1 , r, x, arr);//在数组[mid+1,r]范围中继续二分查找 return idx;//返回下标变量idx的值 } int main() { int n, x, index; int a[10]; scanf("%d %d", &n, &x); for(int i = 0; i < n; i++) { scanf("%d", &arr[i]); } index = binarySearch(0, n-1, x, arr);//第一次二分查找开始 if(index < 0) { printf("Not Found"); }//没找到x,index是负数 else { printf("%d", index); }//找到x,index是非负数 return 0; }
以输入样例1为准,binarySearch函数查找流程如下图所示:
*注: 红 色 方 框 表 示 本 次 查 找 的 区 间 范 围 \textcolor{Red}{红色方框}表示本次查找的区间范围 红色方框表示本次查找的区间范围
本题的关键在于如何理解和实现二分查找的方法
递归和循环都各有千秋。相比于循环,递归更难以理解,但对于某些复杂的问题,使用递归的方法能将程序的编写过程简单化
所谓的数组(Array),是一种有序的元素序列,即是在程序设计中,为了处理方便, 把具有相同类型的若干元素按有序的形式组织起来的一种形式,它不仅是与**指针(Pointer)**相关的一部分内容,更是绝大多数编程语言的一种重要工具。
数组的出现带给我们方便,其中也包含了许多的算法(Algorithm),这些算法对我们处理数组非常有用,因此在掌握各种算法之前,了解数组的逻辑和结构是非常重要的。
数组主要用于统计(Statistic)和大量的数据处理,当然,数组的用途并不仅局限于此,如果肯下功夫去学的话,甚至能用它玩出各种花样来。
int a[] = { 0,1,2 };
表示定义一个长度为3的整型数组;char 标识符[]
或char *标识符
来表示定义一个字符串,需要注意的是,字符串最后一个元素都以**'\0'
**作为字符串的结尾;*注: 上 述 内 容 基 于 c 语 言 编 写 上述内容基于\textcolor{Red}{c语言}编写 上述内容基于c语言编写
主编:佚名