本专栏👉CSP-J/S初赛内容主要讲解信息学奥赛的初赛内容,包含计算机基础、初赛常考的C++程序和算法以及数据结构,并收集了近年真题以作参考。
如果你想参加信息学奥赛,但之前没有太多C++基础,请点击👉专栏:C++语法入门,如果你C++语法基础已经炉火纯青,则可以进阶算法👉专栏:算法知识和数据结构👉专栏:数据结构啦
目录
1 算法的定义
2 算法的特征
3 算法复杂度
空间复杂度
时间复杂度
4 计算简单程序的时间复杂度
5 计算复杂程序的时间复杂度
6 时间复杂度的计算规则
1 算法的定义
算法是一组有序的、确定的、可执行的操作步骤,用于解决特定问题或完成特定任务。它可以被看做是一种计算机处理的过程,将一些输入数据转换为需要的输出结果。
算法通常包含了输入、输出、处理流程、控制结构等要素,通过精心设计可以高效地实现各种计算、搜索、排序、优化、数据挖掘等任务。
算法是计算机科学和信息技术领域中重要的基础知识之一,对于软件开发、数据分析、人工智能等方面都有着广泛的应用。
2 算法的特征
算法有以下几个特征:
1. 有限性(有穷性):算法必须是有限的,也就是说,它必须在有限的时间内完成。
2. 确定性(确切性):算法中每一步骤必须是明确的,无歧义的。同样的输入,必须得到同样的输出。
3. 可行性:算法中的每个步骤必须是可行的,也就是说,可以通过计算机或其他工具来实现。
4. 输入:算法应该明确其输入,也就是待处理的数据。
5. 输出:算法应该明确其输出,也就是处理完输入数据后的结果。
3 算法复杂度
同一个问题可以用不同的算法来解决,而一个算法质量的优劣将影响到程序的效率。算法分析的目的在于选择合适的算法和改进算法。对于算法的评价主要从时间复杂度和空间复杂度来考虑。
空间复杂度
空间复杂度指的是一个算法在运行过程中所需的内存空间大小,通常用空间复杂度来衡量算法对计算机资源的利用程度。
算法在时间的高效性和空间的高效性之间通常是矛盾的,所以一般会取一个平衡点。通常会假设程序运行在足够大的内存空间中,来研究算法的时间复杂度。
时间复杂度
时间复杂度指的是一个算法在运行过程中所需的计算时间大小,通常用时间复杂度来衡量算法对计算机资源的利用程度。时间复杂度表示的是算法执行时间与输入数据规模之间的关系。
时间复杂度通常用大O符号表示,表示算法所需最长时间与输入数据规模之间的关系。例如,一个时间复杂度为O(n)的算法表示在最坏情况下,随着输入数据规模的增加,算法所需的执行时间也会以线性的方式增长。
常见的时间复杂度从低到高依次为:O(1)、O(log n)、O(n)、O(n log n)、O(n²)、O(n³)。当然还有更高阶的时间复杂度,但它们往往不太常见。
在实际应用中,我们通常希望选择时间复杂度越小的算法来解决问题,这样可以提高程序的效率,节省计算机资源。
(常见的时间复杂度对比图)
4 计算简单程序的时间复杂度
计算一个简单程序的时间复杂度,需要分析程序中循环语句、条件判断语句、函数调用等代码块的执行次数。下面以一个简单的C++程序为例,来演示时间复杂度的计算过程:
以上程序中,用于计算时间复杂度的是for循环语句。根据循环语句的定义,可以得到程序的时间复杂度为O(n),其中n为输入的数值。
#include <iostream>
using namespace std;
int main()
{int n;cin >> n;int sum = 0;for (int i = 0; i < n; i++){sum += i;}cout << "sum = " << sum << endl;return 0;
}
具体分析过程如下:
1. 第1行的cin >> n;语句顺序执行一次,时间复杂度为O(1);
2. 第2行的int sum = 0;语句顺序执行一次,时间复杂度为O(1);
3. 第3~6行的for循环语句执行次数为n次,时间复杂度为O(n);
4. 第7行的cout << "sum = " << sum << endl;语句顺序执行一次,时间复杂度为O(1);
5. 第8行的return 0;语句顺序执行一次,时间复杂度为O(1)。
因此,以上程序的时间复杂度为O(n)。
5 计算复杂程序的时间复杂度
计算稍微复杂的C++程序时间复杂度,首先需要了解各个代码块(如循环语句、条件判断语句、函数调用等)的执行次数,然后根据执行次数的总和来计算时间复杂度。下面以一个稍微复杂的C++程序为例,来演示时间复杂度的计算过程:
#include <iostream>
using namespace std;
int func(int n)
{int sum = 0;for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){sum += i * j;}}return sum;
}int main()
{int n;cin >> n;cout << "sum = " << func(n) << endl;return 0;
}
以上程序包含了一个计算二重循环中每项乘积之和的函数`func`,以及在主函数中调用`func`计算并输出答案。其中,用于计算时间复杂度的是`func`函数中的二重循环语句。
具体分析过程如下:
1. 在`func`函数中,第2行的`int sum = 0;`语句顺序执行一次,时间复杂度为O(1);
2. 在`func`函数中,第3~6行的二重循环语句执行次数为n²次,时间复杂度为O(n²);
3. 在`func`函数中,第7行的`return sum;`语句顺序执行一次,时间复杂度为O(1);
4. 在主函数中,第2行的`cin >> n;`语句顺序执行一次,时间复杂度为O(1);
5. 在主函数中,第3行的`cout << "sum = " << func(n) << endl;`语句顺序执行一次,时间复杂度为O(n²);
6. 在主函数中,第4行的`return 0;`语句顺序执行一次,时间复杂度为O(1)。
因此,以上程序的时间复杂度为O(n²)。
6 时间复杂度的计算规则
时间复杂度的计算规则有以下几点:
1. 对于最好、最坏和平均情况,时间复杂度分别使用最好、最坏和平均情况的执行时间来衡量。一般来说,我们关注的是最坏情况下的时间复杂度,因为这可以保证算法在任何情况下都不会超时。
2. 由于时间复杂度只关注算法的数量级而不关注常数项和低阶项,因此在计算时间复杂度时可以省略常数项和低阶项。例如,O(2n)可以简化为O(n),O(n²+n+1)可以简化为O(n²)。
3. 在计算带有循环语句的程序的时间复杂度时,可以根据循环体中代码的执行次数来计算总的执行次数。例如,在一个for循环中嵌套了一个for循环,内层循环执行了n次,外层循环执行了m次,那么这个程序的时间复杂度就是O(m*n)。
4. 在计算带有递归调用的程序的时间复杂度时,需要考虑递归调用的深度和每层递归调用的时间复杂度。例如,在斐波那契数列的递归实现中,递归深度为n,而每次递归调用都需要计算两个斐波那契数,因此时间复杂度为O(2ⁿ)。
5. 在计算带有多个不同代码段的程序的时间复杂度时,可以把每个代码段的时间复杂度相加来得到总的时间复杂度。例如,在一个函数中同时执行了一个循环和一个递归调用,那么程序的时间复杂度就是循环的时间复杂度加上递归调用的时间复杂度。
总之,计算时间复杂度需要对程序中各个代码段的执行时间进行分析,并把它们的时间复杂度相加或相乘,得到总的时间复杂度。