c++自学迭代器startup!
通俗解释:迭代器是什么?
想象一下迭代器就像图书馆的智能导航员 📚:
🎯 核心比喻
数组/容器 = 图书馆的书架
数据元素 = 书架上的书
迭代器 = 智能导航员(知道每本书的位置,能带你找到下一本)
🆚 迭代器 vs 普通指针
| 特性 | 普通指针 | 迭代器 |
|---|---|---|
| 适用范围 | 数组 | 所有容器(vector、list、map等) |
| 功能 | 基础访问 | 智能遍历,带安全检查 |
| 灵活性 | 固定 | 适配不同容器结构 |
💡 实际例子
数组用指针:
int 数组[3] = {10, 20, 30};
int *指针 = 数组; // 指针指向第一个元素
cout << *指针; // 输出10
指针++; // 移动到下一个
cout << *指针; // 输出20
vector用迭代器:
vector<int> 容器 = {10, 20, 30};
auto 迭代器 = 容器.begin(); // 迭代器指向第一个元素
cout << *迭代器; // 输出10
++迭代器; // 移动到下一个
cout << *迭代器; // 输出20
*iter 就是 获取迭代器当前指向的那个对象的引用。你可以读取它,也可以修改它。
std::vector<int> v = {10, 20, 30, 40};
std::vector<int>::iterator it = v.begin(); // it 这个“激光笔”指向10
// 使用 *it 来获取它指向的元素
int value = *it;
std::cout << value; // 输出:10
// 你甚至可以修改它指向的元素
*it = 100;
// 现在vector变成了:{100, 20, 30, 40}
iter->mem (箭头运算符)
-
字面意思:访问所指元素的成员。
-
通俗理解:“激光笔正指着一本通讯录,请直接告诉我‘张三’的电话号码是多少?”
这个操作是上一个操作的“快捷方式”,专门用于当容器里的元素是对象或结构体,并且你想访问这个对象内部的某个成员(变量或函数)时。
它完全等价于:(*iter).mem
我们来拆解一下:
-
(*iter):先解引用,拿到迭代器指向的那个对象本身。 -
.mem:然后使用点运算符(.)来访问这个对象的名为mem的成员。// 定义一个结构体 struct Person { std::string name; int age; }; // 创建一个容器,里面放了两个Person对象 std::vector<Person> people = {{"Alice", 25}, {"Bob", 30}}; // 迭代器it指向第一个Person对象(即{"Alice", 25}) std::vector<Person>::iterator it = people.begin(); // 现在,我们想获取Alice的名字 // 方法一:分两步走,先用 * 解引用,再用 . 访问成员 std::string name1 = (*it).name; // 等价于:(“拿到Alice这个人”).名字 // 方法二(更简洁):使用 -> 运算符一步到位 std::string name2 = it->name; // 输出:Alice int age = it->age; // 输出:25 // 它本质上就是 (*it).age 的简写形式,因为写起来更方便。迭代器的其他运算符
同样:
具体例子:
这样每次都能排除一半的可能性,很快就能找到答案!
- ++iter
- --iter
- iter1 == iter2
- iter1 != iter2
-
改为大写
-
string s("some string"); auto it = s.begin(); // 错误写法:s 仍然是 "some string" toupper(*it); cout << s << endl; // 输出: some string // 正确写法:s 变成 "Some string" *it = toupper(*it); cout << s << endl; // 输出: Some string这行代码实际上做了两件事:
-
toupper(*it):取出*it指向的字符(比如 's'),生成一个大写版本('S'),但不会改变原来的 's' -
*it = ...:把生成的大写字符 'S' 赋值回*it指向的位置 -
*it = toupper(*it);中的*it =部分是必不可少的,因为它把转换后的大写字符保存回字符串中对应的位置。没有这个赋值操作,转换就白做了! -
为什么必须加
::::是作用域解析运算符,它表示我们要访问的是某个类或命名空间内部的类型。类比理解:
想象一下公司里的职位:
-
不加
:::只说"经理" - 不知道是哪个部门的经理 -
加
:::说"销售部::经理" - 明确知道是销售部的经理 -
iterator本身没有意义 -
vector<int>::iterator明确表示是vector<int>这个"部门"的迭代器 -
更简单的写法:使用
auto如果你觉得这种写法太繁琐,C++11 引入了
auto关键字,可以自动推断类型: -
vector<int> v = {1, 2, 3}; string s = "hello"; // 使用 auto 让编译器自动推断类型 auto it = v.begin(); // 等价于 vector<int>::iterator auto it2 = s.begin(); // 等价于 string::iterator // 对于只读迭代器,使用 cbegin() auto it3 = v.cbegin(); // 等价于 vector<int>::const_iterator auto it4 = s.cbegin(); // 等价于 string::const_iterator通俗理解二分搜索
比喻:想象你在玩"猜数字"游戏,我心中想一个1-100的数字,你每次猜一个数,我会告诉你"大了"或"小了"。
笨方法:从1开始一个个猜 → 1, 2, 3, 4...(太慢了!)
聪明方法(二分搜索):
-
先猜50
-
如果我说"大了",你就知道数字在1-49之间
-
再猜25(1-49的中间)
-
如果我说"小了",你就知道数字在26-49之间
-
继续猜中间值...
#include <iostream> #include <vector> using namespace std; int main() { vector<int> text = {10, 20, 30, 40, 50, 60, 70}; int sought = 30; auto beg = text.begin(); auto end = text.end(); auto mid = text.begin() + (end - beg) / 2; while (mid != end && *mid != sought) { if (sought < *mid) { end = mid; } else { beg = mid + 1; } mid = beg + (end - beg) / 2; } if (mid != end) { cout << "Found: " << *mid << " at position " << (mid - text.begin()) << endl; } else { cout << "Not found" << endl; } return 0; }
更多推荐

所有评论(0)