C++笔记之表驱动法
code review!
文章目录
- C++笔记之表驱动法
- 0.数组小技巧
- 1.std::map实现
- 2.结构体实现
- 3.数组和结构体结合实现表驱动法-存储函数指针
- 4.表驱动法概念-ChatGPT
- 5. 直接访问表(Direct Access Table)的示例
- 6. 索引访问表(Indexed Access Table)的示例
- 7. 阶梯访问表(Look-Up Table)的示例
- 8.《代码大全(第二版)》——表驱动法
- 表驱动法经典应用:作为状态转移数组
参考博文:
一个计算器的程序—表驱动法
0.数组小技巧
代码
int monthDays[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int getDays(int month){
return monthDays[--month];
}
1.std::map实现
代码
#include <iostream>
#include <map>
// 定义一个映射表,将输入值映射到输出值
std::map<int, std::string> table = {
{1, "One"},
{2, "Two"},
{3, "Three"},
{4, "Four"},
{5, "Five"}
};
int main() {
int input;
std::cout << "请输入一个数字 (1-5): ";
std::cin >> input;
// 使用映射表查找输入值对应的输出值
auto it = table.find(input);
if (it != table.end()) {
std::cout << "对应的字符串为: " << it->second << std::endl;
} else {
std::cout << "找不到对应的字符串" << std::endl;
}
return 0;
}
2.结构体实现
代码
#include <iostream>
#include <vector>
// 定义一个结构体,包含输入和输出字段
struct Mapping {
int input;
std::string output;
};
// 定义一个表格,将输入值映射到输出值
std::vector<Mapping> table = {
{1, "One"},
{2, "Two"},
{3, "Three"},
{4, "Four"},
{5, "Five"}
};
int main() {
int input;
std::cout << "请输入一个数字 (1-5): ";
std::cin >> input;
// 使用表格查找输入值对应的输出值
for (const Mapping& entry : table) {
if (entry.input == input) {
std::cout << "对应的字符串为: " << entry.output << std::endl;
return 0; // 找到匹配项后退出
}
}
std::cout << "找不到对应的字符串" << std::endl;
return 0;
}
3.数组和结构体结合实现表驱动法-存储函数指针
运行
代码
#include <iostream>
#include <functional>
// 定义一个结构体来存储操作符和对应的函数指针
struct Operator {
char op;
std::function<double(double, double)> func;
};
// 定义一些操作函数
double Add(double a, double b) {
return a + b;
}
double Subtract(double a, double b) {
return a - b;
}
double Multiply(double a, double b) {
return a * b;
}
double Divide(double a, double b) {
if (b != 0) {
return a / b;
} else {
std::cerr << "Error: Division by zero" << std::endl;
return 0.0;
}
}
int main() {
// 创建操作符数组
Operator operators[] = {
{'+', Add},
{'-', Subtract},
{'*', Multiply},
{'/', Divide}
};
char userOperator;
double operand1, operand2;
std::cout << "Enter an operator (+, -, *, /): ";
std::cin >> userOperator;
// 查找用户输入的操作符,并执行相应的函数
for (const Operator& op : operators) {
if (op.op == userOperator) {
std::cout << "Enter two operands: ";
std::cin >> operand1 >> operand2;
double result = op.func(operand1, operand2);
std::cout << "Result: " << result << std::endl;
break;
}
}
return 0;
}
4.表驱动法概念-ChatGPT
表驱动法是一种编程技巧,用于将输入值与输出值之间的关系存储在数据结构中,以减少大量的条件语句或计算逻辑。表驱动法可以采用不同的实现方式,包括直接访问表、索引访问表和阶梯访问表。
-
直接访问表(Direct Access Table):
直接访问表是最简单的表,其中每个输入对应一个唯一的输出。这通常用于快速查找信息,例如字典或电话簿。以下是一个示例,显示如何通过人名查找其电话号码:直接访问表(姓名对应电话号码): ----------------------------------------- | 姓名 | 电话号码 | ----------------------------------------- | 小明 | 123-456-7890 | | 小红 | 234-567-8901 | | 小李 | 345-678-9012 | | ... | ... | -----------------------------------------
-
索引访问表(Indexed Access Table):
索引访问表使用一个索引来引导到正确的数据记录。索引通常是关键字或标识符,它们指向数据表的特定行。以下是一个示例,显示如何通过学生ID查找学生信息:索引访问表(学生ID对应学生信息): ---------------------------------------------- | 学生ID | 姓名 | 年龄 | 课程 | ---------------------------------------------- | 1001 | 小明 | 18 | 数学 | | 1002 | 小红 | 19 | 英语 | | 1003 | 小李 | 20 | 物理 | | ... | ... | ... | ... | ----------------------------------------------
-
阶梯访问表(LUT - Look-Up Table):
阶梯访问表包含多个级别的数据,通常按照某种特定的条件进行分组。查找数据需要根据条件跳转到正确的级别,然后在该级别中查找所需信息。以下是一个示例,显示如何通过年龄范围查找不同年龄组的人数:阶梯访问表(年龄范围对应人数): ---------------------------------------------- | 年龄范围 | 人数 | ---------------------------------------------- | 0-10岁 | 100 | | 11-20岁 | 200 | | 21-30岁 | 150 | | ... | ... | ----------------------------------------------
这些示例展示了不同类型的表驱动法,它们在不同的应用中有不同的用途。直接访问表用于单一映射关系,索引访问表用于标识符到数据的映射,而阶梯访问表用于范围或条件相关的数据检索。以下是这些不同实现方式的详细解释:
-
直接访问表(Direct Lookup Table):
- 直接访问表是一种最简单的表驱动法实现方式。
- 在直接访问表中,输入值(通常作为键)与对应的输出值直接存储在一个数据结构中,通常是数组或散列表(哈希表)。
- 通过直接查找输入值,你可以立即找到对应的输出值,而无需进行复杂的计算或搜索。
- 这种方式适用于输入值的范围有限且已知的情况,例如将字母映射到其ASCII码值的情况。
-
索引访问表(Indexed Lookup Table):
- 索引访问表是一种使用索引(通常是整数)来查找输出值的表驱动法实现方式。
- 输入值与索引之间建立了一对一或一对多的映射关系,这个索引用于在表中查找对应的输出值。
- 通常,表会以数组或向量的形式存储,索引用作数组的索引,从而找到输出值。
- 这种方式适用于输入值不需要连续的情况,例如在游戏编程中,将不同类型的敌人映射到其属性和行为的情况。
-
阶梯访问表(Stepwise Lookup Table):
- 阶梯访问表是一种将输入值划分为范围或阶段,并为每个范围分配一个输出值的表驱动法实现方式。
- 输入值被划分为离散的阶梯(也称为阶段或区间),然后为每个阶梯分配一个输出值。
- 输入值根据其所属的阶梯来查找对应的输出值,通常使用条件语句或查找表来实现。
- 这种方式适用于将连续的输入值映射到离散的输出值范围,例如在温度范围内确定天气状况的情况,将分数映射到等级的情况等。
5. 直接访问表(Direct Access Table)的示例
#include <iostream>
#include <map>
#include <string>
int main() {
// 创建并初始化直接访问表(姓名对应电话号码)
std::map<std::string, std::string> directAccessTable = {
{"小明", "123-456-7890"},
{"小红", "234-567-8901"},
{"小李", "345-678-9012"}
};
// 通过姓名查找电话号码
std::string name = "小明";
if (directAccessTable.find(name) != directAccessTable.end()) {
std::cout << name << "的电话号码是:" << directAccessTable[name] << std::endl;
} else {
std::cout << "找不到姓名为" << name << "的记录。" << std::endl;
}
return 0;
}
6. 索引访问表(Indexed Access Table)的示例
#include <iostream>
#include <map>
#include <string>
int main() {
// 创建并初始化索引访问表(学生ID对应学生信息)
std::map<int, std::map<std::string, std::string>> indexedAccessTable = {
{1001, {{"姓名", "小明"}, {"年龄", "18"}, {"课程", "数学"}}},
{1002, {{"姓名", "小红"}, {"年龄", "19"}, {"课程", "英语"}}},
{1003, {{"姓名", "小李"}, {"年龄", "20"}, {"课程", "物理"}}}
};
// 通过学生ID查找学生信息
int studentId = 1001;
if (indexedAccessTable.find(studentId) != indexedAccessTable.end()) {
std::cout << "学生ID为" << studentId << "的学生信息:" << std::endl;
for (const auto& pair : indexedAccessTable[studentId]) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
} else {
std::cout << "找不到学生ID为" << studentId << "的学生记录。" << std::endl;
}
return 0;
}
7. 阶梯访问表(Look-Up Table)的示例
#include <iostream>
#include <map>
#include <string>
int main() {
// 创建并初始化阶梯访问表(年龄范围对应人数)
std::map<std::string, int> lookupTable = {
{"0-10岁", 100},
{"11-20岁", 200},
{"21-30岁", 150}
};
// 通过年龄范围查找人数
std::string ageRange = "11-20岁";
if (lookupTable.find(ageRange) != lookupTable.end()) {
std::cout << ageRange << "的人数为:" << lookupTable[ageRange] << std::endl;
} else {
std::cout << "找不到" << ageRange << "的人数记录。" << std::endl;
}
return 0;
}
8.《代码大全(第二版)》——表驱动法
表驱动法经典应用:作为状态转移数组
表驱动最常见在状态机设计模式里作为状态转移数组,在命令设计模式里作为命令码数组。