迭代器的使用之List和Map的遍历

本文介绍了如何使用不同的方法遍历Java集合框架中的ArrayList和Map,包括使用foreach循环、迭代器及ListIterator等,并对比不同遍历方式的特点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

迭代器的使用

  很多情况下,我们会希望遍历一个集合中的元素。例如,显示一个集合中的所有元素。

​ 一般遍历数组都会选择for或者增强for,这两个方法其实也可以用在集合框架之中;还有一种方法是可以采用迭代器遍历集合框架,它是一个对象,实现了 Iterator 接口或者是 ListIterator 接口。使用迭代器,你可以通过循环来删除或者得到集合的元素。ListIterator 继承了 Iterator ,以允许双向遍历列表和修改元素。

遍历 ArrayList
package com.lichee.date;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

/**
 * Created by lichee Yang on 2017-03-02.
 */
public class ArraryList {
    public static void main(String[] args) {

        List<String> list = new ArrayList<String>();
        list.add("lichee");
        list.add("yang");

       // 使用 foreach 遍历 list
        for (String str:list){
            System.out.println(str);
        }

       // 使用迭代器进行相关的遍历
        ListIterator<String> ite = list.listIterator();
        while (ite.hasNext()){
            System.out.println(ite.next());
        }


    }
}

遍历Map

package com.lichee.date;


import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * Created by lichee Yang on 2017-03-02.
 */
public class MapErgodic {
    public static void main(String[] args) {
        Map<String,String> map = new HashMap<>();
        map.put("1","lichee");
        map.put("2","yang");

        System.out.println("通过 map.values() 获得 value,但是不能获得 key");
        for (String val : map.values()){
            System.out.println(val);
        }

        System.out.println("通过 map.keyset() 遍历得到 key 和value");
        for (String key : map.keySet()){
            System.out.println("key = " + key + " ; value ="+ map.get(key));
        }

        System.out.println("通过 map.entrySet() 遍历得到 key 和 value,容量大时适用");
        for (Map.Entry<String,String> mapentry : map.entrySet()){
            System.out.println(mapentry);
        }

        System.out.println("通过 map.entrySet() 使用 iterator 遍历 key 和 value");
        Iterator<Map.Entry<String , String>> it = map.entrySet().iterator();
        while (it.hasNext()){
            Map.Entry<String , String> entry = it.next();
            System.out.println("key = " + entry.getKey() + " ; value ="+ entry.getValue());
        }
    }
}
解析
  1. HashMap 是一个散列表,它存储的内容是键值对(key–value)映射。该类实现了 Map 接口,根据键的 HashCode 值存储数据,具有很快的访问速度,最多运行一条记录的键为 null, 不支持同步线程。
  2. List 接口是一个有序的 collection ,使用此接口能够精准的控制每个元素的插入的位置,能够通过索引(元素在 list 中的位置,类似于数组的小标)来访问 list 中的元素,而且运行有相同的元素。
<think>好的,用户问的是“使用迭代器的时候如何完全遍历容器”。首先,我需要确定用户对迭代器的理解程度。可能他们刚接触C++,或者在使用容器时遇到了遍历的问题。用户之前的问题是关于修改std::map的排序为降序,现在转到迭代器遍历,可能是在实际编码中遇到了遍历不完整的情况,或者想确保自己正确使用迭代器。 接下来,我要考虑不同容器的迭代器类型。比如,顺序容器(vector、list关联容器(map、set)的迭代器使用方式有所不同,但基本遍历方法是类似的。用户可能想知道通用的方法,也可能需要针对特定容器的注意事项。 然后,我需要覆盖不同的遍历方法:正向迭代器、const迭代器、反向迭代器,以及C++11引入的基于范围的for循环。这些都是常见的遍历方式,用户可能不完全清楚它们的区别使用场景。 另外,用户提到的“完全遍历”可能包括遍历过程中不遗漏元素,或者在修改容器时如何避免迭代器失效的问题。比如,在遍历时删除元素可能会导致迭代器失效,需要特别注意。这时候可能需要提到erase方法返回下一个有效的迭代器,或者使用C++11后的erase_if方法。 还要考虑示例代码的正确性,确保语法正确,比如使用正确的迭代器类型,正确的循环结构,以及正确的元素访问方式。比如,对于map迭代器指向的是pair,需要访问firstsecond成员。 用户可能存在的误区包括:在遍历时修改容器结构导致迭代器失效,或者错误地使用迭代器范围(比如end()的位置)。需要指出这些常见错误并提供解决方法。 最后,需要总结最佳实践,比如推荐使用基于范围的for循环简化代码,或者在需要修改容器时使用特定的方法避免失效。同时,强调不同容器的特性,比如关联容器的有序性无序容器的不同遍历行为。</think>在 C++ 中通过迭代器完全遍历容器,需要根据 **容器类型** **遍历需求** 选择正确的迭代器使用方式。以下是详细指南: --- ### 一、基础遍历方法(通用) #### 1️⃣ **正向迭代器**(所有标准容器通用) ```cpp std::vector<int> vec = {1, 2, 3}; // 标准写法(推荐) for (auto it = vec.begin(); it != vec.end(); ++it) { std::cout << *it << " "; // 输出: 1 2 3 } // 显式指定迭代器类型 for (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) { // 操作逻辑 } ``` #### 2️⃣ **基于范围的 for 循环**(C++11 起) ```cpp for (const auto& element : vec) { // 自动推导容器元素 std::cout << element << " "; // 输出: 1 2 3 } ``` --- ### 二、特殊场景处理 #### 1️⃣ **反向遍历**(支持双向迭代器的容器) ```cpp std::list<std::string> lst = {"A", "B", "C"}; // 使用反向迭代器 for (auto rit = lst.rbegin(); rit != lst.rend(); ++rit) { std::cout << *rit << " "; // 输出: C B A } ``` #### 2️⃣ **带条件遍历时修改元素** ```cpp std::deque<double> dq = {1.1, 2.2, 3.3}; for (auto it = dq.begin(); it != dq.end(); ++it) { *it *= 2; // 修改元素值 // 注意:不要在此处增删元素(可能使迭代器失效) } // 修改后输出:2.2 4.4 6.6 ``` --- ### 三、不同容器的特性 #### 1️⃣ **关联容器**(`map`, `set` 等) ```cpp std::map<int, char> m = {{1, 'a'}, {3, 'c'}, {2, 'b'}}; for (auto it = m.begin(); it != m.end(); ++it) { // 访问键值对 std::cout << it->first << ":" << it->second << " "; // 输出(按键升序): 1:a 2:b 3:c } ``` #### 2️⃣ **无序容器**(`unordered_map`, `unordered_set` 等) ```cpp std::unordered_set<std::string> us = {"apple", "banana", "cherry"}; // 遍历顺序不确定(取决于哈希桶分布) for (auto it = us.begin(); it != us.end(); ++it) { std::cout << *it << " "; // 可能输出 banana apple cherry 等任意顺序 } ``` --- ### 四、避免迭代器失效的陷阱 #### 1️⃣ **顺序容器删除元素** ```cpp std::vector<int> v = {1, 2, 3, 4, 5}; // 正确做法(利用 erase 返回值) for (auto it = v.begin(); it != v.end(); ) { if (*it % 2 == 0) { it = v.erase(it); // erase 返回下一个有效迭代器 } else { ++it; } } // 最终结果:1, 3, 5 ``` #### 2️⃣ **关联容器删除元素** ```cpp std::set<int> s = {1, 2, 3, 4, 5}; for (auto it = s.begin(); it != s.end(); ) { if (*it > 3) { s.erase(it++); // 后置递增保证迭代器有效性 } else { ++it; } } // 最终结果:1, 2, 3 ``` --- ### 五、最佳实践总结 | 场景 | 推荐方法 | 注意事项 | |-----------------------|----------------------------------------|----------------------------| | 简单遍历 | 基于范围的 for 循环 | 无需显式操作迭代器 | | 需要索引或复杂条件 | 传统迭代器循环 | 注意 end() 的判断 | | 反向遍历 | `rbegin()` + `rend()` | 需要容器支持双向迭代器 | | 遍历时删除元素 | 利用 `erase()` 的返回值或后置递增 | 避免迭代器失效 | | 遍历关联容器 | 使用 `const_iterator` 避免意外修改键 | 键值不可修改 | --- ### 六、性能对比(以 vector 为例) ```cpp std::vector<int> big_vec(1000000); // 方法 1:传统迭代器 auto t1 = std::chrono::high_resolution_clock::now(); for (auto it = big_vec.begin(); it != big_vec.end(); ++it) { /* 操作 */ } // 方法 2:基于范围的循环 auto t2 = std::chrono::high_resolution_clock::now(); for (const auto& num : big_vec) { /* 操作 */ } // 结果:两种方法性能几乎相同(编译器优化后) ``` --- ### 常见错误示例 ```cpp // ❌ 错误 1:遍历时增删元素导致迭代器失效 std::vector<int> v = {1, 2, 3}; for (auto it = v.begin(); it != v.end(); ++it) { if (*it == 2) v.push_back(4); // 可能导致迭代器失效 } // ❌ 错误 2:错误判断结束条件 std::list<int> lst = {1, 2, 3}; auto it = lst.begin(); while (it != nullptr) { // 错误!end() 不是 nullptr // ... } ``` 掌握这些方法后,你可以安全高效地遍历所有标准容器!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值