备注: 所有的星都表示易考指数。
成就:
- 提出了一种抽象的计算模型图灵机【★★★☆☆】
- 提出了关于机器思维的问题【★☆☆☆☆】
- 人工智能之父【★★★★☆】
影响:
设立图灵奖,专门奖励为计算机事业作出重要贡献的个人【★★★★★】
成就:
成功研制出世界上第一台同通用计算机【★★★☆☆】
成就:
- 起草了“存储程序通用电子计算机方案”(
EDVAC
)【★★☆☆☆】- 提出了冯 • 诺伊曼结构【★☆☆☆☆】
- 提出了利用存储程序运行计算机【★☆☆☆☆】
- 提出了采用二进制编码代替十进制【★★☆☆☆】
- 计算机之父【★★★★★】
影响:
成就中2.3.4这三大思想至今仍然为电子计算机设计者所遵循
目的:
奖励为计算机事业作出重要贡献的个人【★★☆☆☆】
特点:
- 计算机界的诺贝尔奖【★☆☆☆☆】
- 计算机界最负盛名、最崇高的奖项【★★★★☆】
目的:
奖励计算机领域的突出贡献者【★★☆☆☆】
获奖事例:
- 晶体管的发明【★★☆☆☆】
- 大容量存储硬盘的发明(巨磁电阻)【★☆☆☆☆】
- 光纤的发明【★☆☆☆☆】
- 集成电路的发明【★★☆☆☆】
目的:
奖励计算机科学家和技术上具有杰出成就的科学家【★★☆☆☆】
提出者:
戈登 • 摩尔【★☆☆☆☆】
提出时间:
1965年【★☆☆☆☆】
称为:
计算机第一定律【★★★☆☆】
定律内容:
- 集成电路芯片上所集成的电路的数目,每隔 18 18 18 个月就翻一番;【★★★☆☆】
- 微处理器的性能每隔 18 18 18 个月提高一倍,而价格下降一半;【★★★☆☆】
- 用 1 1 1 美元所能买到的计算机的性能,每隔 18 18 18 个月翻两番。【★★☆☆☆】
研制者:
谷歌【★☆☆☆☆】
研制(成功)时间:
2019 2019 2019 年 10 10 10 月【★☆☆☆☆】
研制结果:
研制出名为Sycamore
的 53 53 53 位量子芯片,芯片已成功实现“量子优越性”。【★★☆☆☆】
在编程中, ∨ ∨ ∨和 ∧ ∧ ∧分别代表逻辑或(
OR
)和逻辑与(AND
)操作符。它们是用来在布尔表达式中进行逻辑运算的。
逻辑或操作符( ∨ ∨ ∨)表示只要两个操作数中至少一个为true
,整个表达式的结果就为true
。例如,表达式 ( x ∨ y x ∨ y x∨y) 的结果在 x x x 或 y y y 中至少有一个为true
时为true
,否则为false
。
逻辑与操作符( ∧ ∧ ∧)表示只有两个操作数都为true
,整个表达式的结果才为true
。例如,表达式 ( x ∧ y x ∧ y x∧y) 的结果在 x x x 和 y y y 都为true
时为true
,否则为false
。
这些逻辑运算符通常用于控制流程中的条件判断和布尔表达式的求值。在编程语言中,常见的逻辑运算符是 “||
” 和 “&&
”,它们分别对应逻辑或和逻辑与操作符。
面向对象的概念是一种软件开发方法论,其核心思想是将系统中的数据和操作数据的方法封装在一起,通过对象之间的交互来实现程序的功能。【★★☆☆☆】面向对象的特点包括封装、继承和多态。【★★★★☆】
C++
是一种支持面向对象编程的编程语言,它在语言层面上提供了丰富的面向对象特性。下面是C++
的一些面向对象特性:
- 封装:通过类定义来实现封装,类将数据和操作封装在一起,通过访问修饰符(
public
、private
和protected
)控制对类成员的访问权限。封装提供了数据的隐藏和保护,使得对象的使用者只能通过类的公共接口访问和操作对象的数据。- 继承:
C++
支持单继承和多继承。继承允许一个类通过继承另一个类来获得其属性和方法,并且可以通过派生类对继承的成员进行覆盖或扩展。继承提供了代码的重用性,可以通过定义基类来实现通用的行为,然后通过派生类来扩展或定制特定的行为。- 多态:
C++
通过虚函数和运行时动态类型识别(RTTI
)实现多态性。多态允许不同类型的对象根据其具体类型调用相同的方法,实现方法的动态绑定。这提供了灵活性和可扩展性,可以处理具有不同行为的对象集合,并且可以在运行时根据对象的实际类型来决定调用哪个方法。
• 简介
除了C++
,还有一些专门面向对象的编程语言,如Java
、C#
(Csharp
)等。这些语言在语法和语义上更加贴近面向对象的概念,提供了更丰富的面向对象特性。比如,Java
和C#
都支持自动垃圾回收机制,简化了内存管理的工作;它们还提供接口(interface
)机制,允许定义规范和多继承等。
• 优点
面向对象的编程模型具有很多优点,例如可重用性、可扩展性和可维护性等。通过面向对象的方法,可以将系统分解为若干个相对独立的对象,每个对象都有自己的状态和行为,从而简化了系统的设计和实现过程。同时,面向对象的编程模型也使得代码更加易于理解和维护,有助于提高开发效率和软件质量。
栈是一种具有后进先出(LIFO)特性的数据结构。实现了两个基本操作:压栈(将元素放入栈顶)和出栈(将栈顶元素取出)。
在C++中,可以使用std::stack
作为栈的实现。
队列是一种具有先进先出(FIFO)特性的数据结构。实现了两个基本操作:入队(将元素放入队尾)和出队(将队头元素取出)。
在C++中,可以使用std::queue
作为队列的实现。
二叉树是一种每个节点最多有两个子节点的树状结构。其中一个子节点称为左子节点,另一个称为右子节点。
可以使用指针或者数组等方式来实现二叉树。常见的二叉树操作包括插入节点、删除节点、查找节点等。
链表是由节点按顺序连接而成的线性数据结构。每个节点包含一个数据元素和一个指向下一个节点的指针。
在C++中,可以使用指针或者标准库中的std::list
来实现链表。
堆是一种特殊的树形结构,常用于实现优先级队列。堆分为最大堆和最小堆两种。
C++标准库中的std::priority_queue
提供了堆的实现,可以根据自定义的比较函数来实现最大堆或最小堆。
散列表是根据关键字直接访问存储位置的数据结构,实现了键值对的映射。散列表通过哈希函数将关键字映射到存储位置。
C++标准库中的std::unordered_map
和std::unordered_set
提供了散列表的实现。
图是由节点和边构成的网络结构。图可以分为有向图和无向图,可以使用邻接矩阵或邻接表来表示。
常见的图算法包括深度优先搜索(DFS)、广度优先搜索(BFS)、最短路径算法等。
树是一种非线性的数据结构,以分层的方式存储数据。树的每个节点可以有多个子节点。
常见的树结构包括二叉树、二叉搜索树、平衡二叉树、红黑树等。
集合是一种无序且元素不重复的数据结构。集合中的元素没有顺序,可以进行插入、删除和查找操作。
C++标准库中的std::set
和std::unordered_set
提供了集合的实现。
哈希集合是基于散列表实现的集合数据结构。哈希集合利用哈希函数将元素存储在散列表中。
C++标准库中的std::unordered_set
提供了哈希集合的实现。
哈希映射是基于散列表实现的键值对映射数据结构。哈希映射利用哈希函数将键映射到散列表中的存储位置。
C++标准库中的std::unordered_map
提供了哈希映射的实现。
图的遍历算法用于访问图中的所有节点。常见的图的遍历算法包括深度优先搜索(DFS)和广度优先搜索(BFS)。
DFS从起始节点开始,沿着一条路径访问图的节点,直到无法继续前进,然后回退到上一个节点继续探索其他路径。
BFS从起始节点开始,先访问起始节点的所有邻接节点,然后逐层访问其他节点,直到访问完所有节点。
树的遍历算法用于访问树中的所有节点。常见的树的遍历算法包括前序遍历、中序遍历和后序遍历。
前序遍历先访问根节点,然后按照左子树、右子树的顺序遍历节点。
中序遍历按照左子树、根节点、右子树的顺序遍历节点。
后序遍历按照左子树、右子树、根节点的顺序遍历节点。
void bubbleSort(int arr[], int n)
{
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < n - i - 1; j++)
{
if (arr[j] > arr[j + 1])
{
swap(arr[j], arr[j + 1]);
}
}
}
}
时间复杂度: O ( n 2 ) O(n^2) O(n2)
空间复杂度: O ( 1 ) O(1) O(1)
void insertionSort(int arr[], int n)
{
for (int i = 1; i < n; i++)
{
int key = arr[i];
int j = i - 1;
while (j >= 0 && arr[j] > key)
{
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
}
时间复杂度: O ( n 2 ) O(n^2) O(n2)
空间复杂度: O ( 1 ) O(1) O(1)
void selectionSort(int arr[], int n)
{
for (int i = 0; i < n - 1; i++)
{
int minIndex = i;
for (int j = i + 1; j < n; j++)
{
if (arr[j] < arr[minIndex])
{
minIndex = j;
}
}
swap(arr[i], arr[minIndex]);
}
}
时间复杂度: O ( n 2 ) O(n^2) O(n2)
空间复杂度: O ( 1 ) O(1) O(1)
int partition(int arr[], int low, int high)
{
int pivot = arr[high];
int i = low - 1;
for (int j = low; j < high; j++)
{
if (arr[j] < pivot)
{
i++;
swap(arr[i], arr[j]);
}
}
swap(arr[i + 1], arr[high]);
return (i + 1);
}
void quickSort(int arr[], int low, int high) {
if (low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)(平均情况), O ( n 2 ) O(n^2) O(n2)(最坏情况)
空间复杂度: O ( l o g n ) O(logn) O(logn)(平均情况), O ( n ) O(n) O(n)(最坏情况)
void merge(int arr[], int left, int mid, int right)
{
int n1 = mid - left + 1;
int n2 = right - mid;
int L[n1], R[n2];
for (int i = 0; i < n1; i++)
{
L[i] = arr[left + i];
}
for (int j = 0; j < n2; j++)
{
R[j] = arr[mid + 1 + j];
}
int i = 0, j = 0, k = left;
while (i < n1 && j < n2)
{
if (L[i] <= R[j])
{
arr[k] = L[i];
i++;
}
else
{
arr[k] = R[j];
j++;
}
k++;
}
while (i < n1)
{
arr[k] = L[i];
i++;
k++;
}
while (j < n2)
{
arr[k] = R[j];
j++;
k++;
}
}
void mergeSort(int arr[], int left, int right)
{
if (left < right)
{
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
}
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
空间复杂度: O ( n ) O(n) O(n)
int sequentialSearch(int arr[], int n, int target)
{
for (int i = 0; i < n; i++)
{
if (arr[i] == target)
{
return i;
}
}
return -1;
}
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( 1 ) O(1) O(1)
int binarySearch(int arr[], int n, int target)
{
int left = 0, right = n - 1;
while (left <= right)
{
int mid = left + (right - left) / 2;
if (arr[mid] == target)
{
return mid;
}
else if (arr[mid] < target)
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
return -1;
}
时间复杂度: O ( l o g n ) O(logn) O(logn)
空间复杂度: O ( 1 ) O(1) O(1)
int interpolationSearch(int arr[], int n, int target)
{
int left = 0, right = n - 1;
while (left <= right && target >= arr[left] && target <= arr[right])
{
int pos = left + (target - arr[left]) * (right - left) / (arr[right] - arr[left]);
if (arr[pos] == target)
{
return pos;
}
else if (arr[pos] < target)
{
left = pos + 1;
}
else
{
right = pos - 1;
}
}
return -1;
}
时间复杂度:平均情况下 O ( l o g l o g n ) O(loglogn) O(loglogn),最坏情况下 O ( n ) O(n) O(n)
空间复杂度: O ( 1 ) O(1) O(1)
int hashSearch(int arr[], int n, int target)
{
unordered_map<int, int> hashTable;
for (int i = 0; i < n; i++)
{
hashTable[arr[i]] = i;
}
if (hashTable.find(target) != hashTable.end())
{
return hashTable[target];
}
return -1;
}
时间复杂度:平均情况下 O ( 1 ) O(1) O(1),最坏情况下 O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)
struct TreeNode
{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
TreeNode* insert(TreeNode* root, int val)
{
if (root == NULL)
{
return new TreeNode(val);
}
if (val < root->val)
{
root->left = insert(root->left, val);
}
else if (val > root->val)
{
root->right = insert(root->right, val);
}
return root;
}
bool search(TreeNode* root, int val)
{
if (root == NULL)
{
return false;
}
if (root->val == val)
{
return true;
}
else if (val < root->val)
{
return search(root->left, val);
}
else
{
return search(root->right, val);
}
}
时间复杂度:平均情况下 O ( l o g n ) O(logn) O(logn),最坏情况下 O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)
例如 2020 2020 2020 年 CSP-J
真题:
#include
#include
using namespace std;
char encoder[26]={'C','S','P',0};
char decoder[26];
string st;
int main(){
int k=0;
for(int i=0;i<26;++i)
if (encoder[i]!=0)++k;
for(char x='A';x<='Z';++x){
bool flag=true;
for(int i=0;i<26;++i)
if(encoder[i]==x){
flag=false;
break;
}
if(flag){
encoder[k]=x;
++k;
}
}
for(int i=0;i<26;++i)
decoder[encoder[i]-'A']=i+'A';
cin>>st;
for(int i=0;i<st.length();++i)
st[i]=decoder[st[i]-'A'];
cout<<st;
return 0;
}
问题: 如果输入UTP
, 则程序会输出什么?
通过表格列举所有变量、数组中改动的值这个方式:
循环变量的值 | k |
flag |
encoder[k] |
decoder |
st |
---|---|---|---|---|---|
0 | 1 | 0 | ‘\0’ | / | / |
1 | 2 | 0 | ‘\0’ | / | / |
2 | 3 | 0 | ‘\0’ | / | / |
‘A’, 0 | 4 | true | ‘A’ | / | / |
‘B’, 0 | 5 | true | ‘A’ | / | / |
‘C’, 0 | 6 | true | ‘A’ | / | / |
… | … | … | … | … | … |
‘Z’, 0 | 28 | true | ‘A’ | / | / |
‘A’, 1 | 29 | false | ‘C’ | / | / |
‘B’, 1 | 29 | true | ‘C’ | / | / |
‘C’, 1 | 29 | true | ‘C’ | / | / |
… | … | … | … | … | … |
‘Z’, 1 | 29 | true | ‘C’ | / | / |
‘A’, 2 | 29 | true | ‘C’ | / | / |
‘B’, 2 | 29 | true | ‘C’ | / | / |
‘C’, 2 | 29 | false | ‘C’ | / | / |
… | … | … | … | … | … |
‘Z’, 2 | 29 | true | ‘C’ | / | / |
… | … | … | … | … | … |
‘U’ | … | … | … | … | / |
‘T’ | … | … | … | … | / |
‘P’ | … | … | … | … | / |
程序将输出:CSP
。这个程序看似复杂,但是经过列举之后,我们就能发现它还是很容易的。
#include
using namespace std;
char encoder[26] = {'C','S','P',0};
char decoder[26];
string st;
int main() {
int k = 3; // k一定是3
for (char x = 'A'; x <= 'Z'; ++x) {
bool flag = true;
for (int i = 0; i < k; ++i) {
if (encoder[i] == x) {
flag = false;
break;
}
}
if (flag) {
encoder[k] = x;
++k;
}
}
for (int i = 0; i < 26; ++i) {
decoder[encoder[i] - 'A'] = i + 'A';
}
cin >> st;
for (int i = 0; i < st.length(); ++i) {
st[i] = decoder[st[i] - 'A'];
}
cout << st;
return 0;
#include
using namespace std;
string st;
char encoder[26] = {'C', 'S', 'P', 0};
char decoder[26];
int main() {
int k = 3;
for (char x = 'A'; x <= 'Z'; ++x) {
bool flag = true;
for (int i = 0; i < k; ++i) {
if (encoder[i] == x) {
flag = false;
break;
}
}
if (flag) encoder[k++] = x; // 合并程序,下标直接变成k自增
}
for (int i = 0; i < 26; ++i) decoder[encoder[i] - 'A'] = i + 'A';
cin >> st;
for (char &c : st) c = decoder[c - 'A'];
cout << st;
return 0;
}
如果输入TTT
:
因此,输入TTT
的解码结果为022。
编码器将会是:
{'C', 'S', 'P', 0, 'A', 'B', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'Q', 'R', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}
解码器将会是:
{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'}
如果输入是TTT
,输出应该是AAA
。
例如:
cnt[a[k]]++;
首先,先不看a[k]
。
cnt[***]++;
这样,我们就知道,程序的目的是将cnt[]
中某一个元素自增。然后再看a[k]
。
index = a[k];
cnt[index]++;
这样就清楚许多了。
例如:
int w[6] = {1, 1};
for (int n = 2; n <= 5; n++)
{
w[n]=w[n-1]+w[n-2];
}
通过列举:
n | w[n] | w[n-1] | w[n-2 |
---|---|---|---|
2 | 0 | 1 | 1 |
2 | 2 | 1 | 1 |
3 | 0 | 2 | 1 |
3 | 3 | 2 | 1 |
4 | 0 | 3 | 2 |
4 | 5 | 3 | 2 |
5 | 0 | 5 | 3 |
5 | 8 | 5 | 3 |
因此, w[]
数组应该为:
{1, 1, 2, 3, 5, 8}