19.趣味算法
约 2772 字大约 9 分钟
2025-02-05
一、开场:算法世界的新探索
标题:解锁算法密码 - 字符串与矩阵算法探秘
副标题:用算法解决实际问题,提升编程实战能力
引入方式:展示一个聊天软件的界面,提问学生如何在程序中判断用户输入的密码是否符合规则,从而引出字符串处理算法;再展示一个建筑设计图纸,其中涉及到空间结构的计算,提问如何用程序计算建筑结构的力学参数,进而引入矩阵运算算法。让学生明白这些算法在生活和专业领域中的重要性。
配图:选择聊天软件界面和建筑设计图纸的图片,或者用简单的流程图展示算法在实际应用中的流程,激发学生对算法学习的兴趣。
二、字符串处理算法
字符串匹配算法 - BF 算法
原理讲解:BF(Brute-Force)算法,也叫暴力匹配算法,是最简单的字符串匹配算法。它的基本思想是从主串的第一个字符开始,依次与模式串的字符进行比较。如果在某一位置上主串和模式串的字符相等,则继续比较下一个字符;如果不相等,则主串从下一个字符开始,重新与模式串进行比较,直到找到匹配的子串或者遍历完主串。例如,在主串 “abcdef” 中查找模式串 “cde”,先比较主串的第一个字符 “a” 和模式串的第一个字符 “c”,不相等,主串从第二个字符 “b” 开始与模式串重新比较,以此类推,直到找到匹配的子串。
代码示例:
#include <iostream>
#include <string>
bool bruteForceSearch(const std::string& text, const std::string& pattern) {
int n = text.length();
int m = pattern.length();
for (int i = 0; i <= n - m; i++) {
int j;
for (j = 0; j < m; j++) {
if (text[i + j]!= pattern[j]) {
break;
}
}
if (j == m) {
return true;
}
}
return false;
}
int main() {
std::string text = "abcdef";
std::string pattern = "cde";
if (bruteForceSearch(text, pattern)) {
std::cout << "模式串在主串中找到。" << std::endl;
} else {
std::cout << "模式串在主串中未找到。" << std::endl;
}
return 0;
}
代码分析:外层循环控制主串的起始位置,内层循环用于逐个比较主串和模式串的字符。如果内层循环完整执行完毕,说明找到了匹配的子串,返回true
;否则返回false
。
字符串反转算法
原理讲解:字符串反转算法是将字符串中的字符顺序颠倒。可以使用双指针法,一个指针指向字符串的开头,另一个指针指向字符串的末尾,然后交换两个指针指向的字符,并逐渐向中间移动指针,直到两个指针相遇。例如,对于字符串 “hello”,先交换 “h” 和 “o”,再交换 “e” 和 “l”,得到反转后的字符串 “olleh”。
代码示例:
#include <iostream>
#include <string>
std::string reverseString(std::string str) {
int left = 0;
int right = str.length() - 1;
while (left < right) {
char temp = str[left];
str[left] = str[right];
str[right] = temp;
left++;
right--;
}
return str;
}
int main() {
std::string original = "hello";
std::string reversed = reverseString(original);
std::cout << "原字符串: " << original << std::endl;
std::cout << "反转后的字符串: " << reversed << std::endl;
return 0;
}
代码分析:通过while
循环,在每次循环中交换左右指针指向的字符,并更新指针位置,直到左指针大于等于右指针,完成字符串反转。
三、矩阵运算算法
矩阵加法
原理讲解:矩阵加法是将两个相同维度的矩阵对应位置的元素相加。例如,对于矩阵 A 和矩阵 B:$ A=\begin{bmatrix} 1 & 2 \ 3 & 4 \end{bmatrix} \quad B=\begin{bmatrix} 5 & 6 \ 7 & 8 \end{bmatrix} $
它们的和为:$ A + B=\begin{bmatrix} 1 + 5 & 2 + 6 \ 3 + 7 & 4 + 8 \end{bmatrix} =\begin{bmatrix} 6 & 8 \ 10 & 12 \end{bmatrix} $
代码示例:
#include <iostream>
void addMatrices(int matrix1[][100], int matrix2[][100], int result[][100], int rows, int cols) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
result[i][j] = matrix1[i][j] + matrix2[i][j];
}
}
}
int main() {
int matrix1[2][2] = {
{1, 2},
{3, 4}
};
int matrix2[2][2] = {
{5, 6},
{7, 8}
};
int result[2][2];
addMatrices(matrix1, matrix2, result, 2, 2);
std::cout << "矩阵相加结果:" << std::endl;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
std::cout << result[i][j] << " ";
}
std::cout << std::endl;
}
return 0;
}
代码分析:使用两层嵌套循环遍历矩阵的每一个元素,将对应位置的元素相加并存储到结果矩阵中。
矩阵乘法
原理讲解:矩阵乘法的规则是,若有矩阵 A(m x n)和矩阵 B(n x p),则它们的乘积矩阵 C(m x p)的元素Cij等于矩阵 A 的第 i 行元素与矩阵 B 的第 j 列对应元素乘积之和。例如,对于矩阵 A 和矩阵 B:$ A=\begin{bmatrix} 1 & 2 \ 3 & 4 \end{bmatrix} \quad B=\begin{bmatrix} 5 & 6 \ 7 & 8 \end{bmatrix} $
它们的乘积为:$ A\times B=\begin{bmatrix} 1\times5 + 2\times7 & 1\times6 + 2\times8 \ 3\times5 + 4\times7 & 3\times6 + 4\times8 \end{bmatrix} =\begin{bmatrix} 19 & 22 \ 43 & 50 \end{bmatrix} $
代码示例:
#include <iostream>
void multiplyMatrices(int matrix1[][100], int matrix2[][100], int result[][100], int rows1, int cols1, int cols2) {
for (int i = 0; i < rows1; i++) {
for (int j = 0; j < cols2; j++) {
result[i][j] = 0;
for (int k = 0; k < cols1; k++) {
result[i][j] += matrix1[i][k] * matrix2[k][j];
}
}
}
}
int main() {
int matrix1[2][2] = {
{1, 2},
{3, 4}
};
int matrix2[2][2] = {
{5, 6},
{7, 8}
};
int result[2][2];
multiplyMatrices(matrix1, matrix2, result, 2, 2, 2);
std::cout << "矩阵相乘结果:" << std::endl;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
std::cout << result[i][j] << " ";
}
std::cout << std::endl;
}
return 0;
}
代码分析:最外层循环控制结果矩阵的行,中间层循环控制结果矩阵的列,最内层循环用于计算结果矩阵中每个元素的值。
四、算法应用实战
实际问题 1:文本加密与解密
问题描述:实现一个简单的文本加密和解密程序。加密算法采用凯撒密码,即将每个字符按照一定的偏移量进行替换。例如,偏移量为 3 时,‘a’变为‘d’,‘b’变为‘e’,以此类推。解密则是加密的逆过程。
代码实现:
#include <iostream>
#include <string>
std::string encrypt(const std::string& text, int shift) {
std::string encryptedText = "";
for (char c : text) {
if (std::isalpha(c)) {
char base = std::isupper(c)? 'A' : 'a';
encryptedText += (c - base + shift) % 26 + base;
} else {
encryptedText += c;
}
}
return encryptedText;
}
std::string decrypt(const std::string& encryptedText, int shift) {
return encrypt(encryptedText, 26 - shift);
}
int main() {
std::string originalText = "hello world";
int shift = 3;
std::string encrypted = encrypt(originalText, shift);
std::string decrypted = decrypt(encrypted, shift);
std::cout << "原始文本: " << originalText << std::endl;
std::cout << "加密后的文本: " << encrypted << std::endl;
std::cout << "解密后的文本: " << decrypted << std::endl;
return 0;
}
分析与讲解:encrypt
函数通过遍历文本中的每个字符,对字母字符进行偏移替换,非字母字符保持不变。decrypt
函数利用加密的逆过程,通过调整偏移量实现解密。
实际问题 2:图像变换中的矩阵运算
问题描述:在简单的图像处理中,图像可以表示为一个像素矩阵。通过矩阵运算,可以实现图像的平移、旋转等变换。以图像平移为例,假设图像矩阵为 A,平移矩阵为 T,通过矩阵乘法A×T得到平移后的图像矩阵。
代码实现(简化概念性代码):
#include <iostream>
// 假设图像矩阵为二维数组,这里简化为3x3矩阵表示
void translateImage(int image[][3], int translation[][3], int result[][3]) {
// 这里简单模拟矩阵乘法实现图像平移,实际应用中需更复杂计算
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
result[i][j] = 0;
for (int k = 0; k < 3; k++) {
result[i][j] += image[i][k] * translation[k][j];
}
}
}
}
int main() {
int image[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
int translation[3][3] = {
{1, 0, 1},
{0, 1, 0},
{0, 0, 1}
};
int result[3][3];
translateImage(image, translation, result);
std::cout << "平移后的图像矩阵:" << std::endl;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
std::cout << result[i][j] << " ";
}
std::cout << std::endl;
}
return 0;
}
分析与讲解:translateImage
函数模拟了通过矩阵乘法实现图像平移的过程。实际的图像处理中,图像矩阵和变换矩阵会更复杂,这里仅作概念性展示,帮助学生理解矩阵运算在图像变换中的应用。
五、实践与巩固
练习题目
让学生编写一个程序,使用 KMP 算法(可先简单介绍其原理)实现字符串匹配,找出主串中所有模式串出现的位置,并输出位置信息。
给出一个包含矩阵运算的程序,其中存在矩阵维度不匹配、运算逻辑错误等问题,让学生找出并改正,同时添加注释解释修改原因。
互动环节
开展小组竞赛,将学生分成小组共同完成练习题目。完成后,每个小组推选一名代表进行代码展示和讲解,其他小组进行提问和评价,教师进行总结和点评,获胜小组可获得小奖品,如编程书籍、在线课程优惠券等。
进行情景模拟编程,教师给出一些生活中需要字符串处理和矩阵运算的场景,如密码强度检测、地理坐标变换等,让学生在规定时间内用所学算法编写代码实现,然后邀请学生上台分享自己的代码思路,增强学生的编程实践能力和表达能力。
六、回顾与总结
总结
回顾字符串处理算法(BF 算法、字符串反转算法)和矩阵运算算法(矩阵加法、矩阵乘法)的原理、代码实现和特点。
总结算法在实际问题(文本加密解密、图像变换)中的应用方法和技巧,强调根据具体问题选择合适算法的重要性。
对比不同算法的时间复杂度和空间复杂度,帮助学生理解算法效率的概念。
拓展
鼓励学生课后尝试优化所学算法,如对 BF 算法进行优化,减少不必要的比较次数;或者尝试实现更复杂的矩阵运算,如矩阵的求逆运算。
推荐一些算法学习资源,如在线算法学习平台(如 LeetCode、牛客网等)、算法书籍(如《算法导论》《数据结构与算法分析:C++ 描述》等),让学生在课后能进一步深入学习算法知识,提升算法设计和编程能力。
七、结束寄语
感谢语
感谢同学们在本节课的积极参与和认真学习,通过本节课的学习,大家对字符串处理和矩阵运算算法有了深入的理解和掌握。希望大家在今后的编程学习中,能够灵活运用这些算法解决各种实际问题,不断提升自己的编程水平和算法思维能力。