传统查找方法解析
首先讨论了一个经典的查找场景:在100个箱子中查找一张目标数字的纸条。
查找流程
从第1号箱子开始,打开查看纸条上的数字。
如果数字等于目标值,则查找结束。
如果未找到,检查箱子编号是否大于100:
- 若大于100,查找失败,结束流程。
- 若不大于100,则继续查找下一个箱子。
存在的问题
在该方法中,每轮循环都需要进行 两次条件判断:
- 判断数字是否匹配。
- 判断编号是否超过范围。
对于小规模数据,这样的效率问题不明显,但在大规模数据查找中,这种额外的判断会显著影响性能。
哨兵思想优化
核心思想
通过额外添加一个“哨兵箱子”(第101号箱子),可以减少循环内的判断次数。
优化步骤
在第101号箱子中预先放置目标数字,确保查找过程中一定会命中。
查找时:
- 只需要判断当前箱子数字是否等于目标值。
- 一旦命中,再判断箱子编号是否小于等于100,从而判断是否为有效结果。
优势
- 判断次数减少:循环中只需进行一次数字匹配判断。
- 效率提升:特别是在数据规模较大、目标元素稀少的情况下,性能优势明显。
代码示例:哨兵查找法
#include <iostream>
using namespace std;
int main() {
int box[102]; // 100个箱子 + 1个哨兵箱子
int target = 42; // 目标数字
int n = 100; // 箱子数量
// 模拟初始化(这里只是示例,实际应从输入读取)
for (int i = 1; i <= n; i++) {
box[i] = i; // 假设每个箱子里是自己的编号
}
box[n+1] = target; // 哨兵箱子放目标值
int i = 1;
while (box[i] != target) {
i++;
}
if (i <= n) {
cout << "找到目标值,位置:" << i << endl;
} else {
cout << "未找到目标值" << endl;
}
return 0;
}
结构体成员偏移量计算
在C/C++开发中,常常需要获取结构体成员的内存偏移量。
宏定义实现
#define OFFSET_OF(type, member) ((size_t)&(((type*)0)->member))
(type*)0
将0
转换为type*
类型的指针(空指针)。->member
获取成员的地址(相对于0地址的偏移)。&
取地址,size_t
转换为整数,即为偏移量。
示例
#include <iostream>
using namespace std;
struct MyStruct {
int a;
double b;
char c;
};
int main() {
cout << "a 偏移量: " << OFFSET_OF(MyStruct, a) << endl;
cout << "b 偏移量: " << OFFSET_OF(MyStruct, b) << endl;
cout << "c 偏移量: " << OFFSET_OF(MyStruct, c) << endl;
return 0;
}
系统字节对齐差异
在不同系统中,结构体和联合体的成员排列会受到字节对齐规则影响。
系统环境 | 默认对齐字节 | 示例联合体占用 |
---|---|---|
64位 Linux | 8 字节对齐 | 16 字节(即使理论上只需10字节) |
32位 Linux | 4 字节对齐 | 12 字节 |
修改对齐方式
可使用 #pragma pack(n)
修改对齐规则,例如:
#pragma pack(2)
struct MyStruct {
char a;
int b;
};
#pragma pack()
这样可以减少内存浪费,但需要权衡访问性能。