std与命名空间
- 首先我看到这个:
std::vector<int> v;
如果你在代码的开始部分使用了 using namespace std; 语句,那么在这个文件中你就不需要在每个标准库类型或函数前加上 std:: 前缀了
new不new
- java中新建一个对象,常常要用new
-
关于对象的创建和内存分配,C++与Java在这方面确实有些不同:
- C++ 中的对象创建:
- 栈上创建:在C++中,你可以直接在栈上创建对象,不需要使用 new 关键字。例如:std::vector v; 这里 v 是在栈上创建的,当离开声明它的作用域时会自动被销毁。
- 堆上创建:如果你需要在堆上创建对象,那么你需要使用 new 关键字。例如:std::vector* v = new std::vector(); 这样创建的对象在堆上,需要你手动删除,使用 delete v; 来避免内存泄漏。
Java 中的对象创建:
-
在Java中,所有的对象都是通过 new 关键字在堆上创建的。例如:Vector v = new Vector(); 在Java中没有类似C++中栈上分配的对象的概念。
-
iterato迭代器
- 迭代器的使用 示例代码:
//迭代器
vector<int>::iterator pStart = v.begin(); //vector 容器提供了 begin()方法 返回指向第一个元素的迭代器
vector<int>::iterator pEnd = v.end(); //vector 容器提供了 end()方法 返回指向最后一个元素下一个位置的迭代器
//通过迭代器遍历
while (pStart != pEnd){
cout << *pStart << " ";
pStart++;
}
- vector<int>::iterator 是一种特定类型的迭代器,专门用于遍历 std::vector<int> 类型的容器
- 迭代器的工作方式类似于指针。使用迭代器,你可以通过增加(++)、减少(--)、解引用(*)等操作来访问和遍历容器中的元素。例如:
vector<int> v = {10, 20, 30, 40, 50};
// 创建一个迭代器指向vector的开始
vector<int>::iterator it = v.begin();
// 解引用迭代器以访问它指向的当前元素
int firstValue = *it; // 10
// 移动迭代器到下一个元素
++it;
int secondValue = *it; // 20
迭代器和指针的区别:
迭代器通常被认为是一种广义的“指针”,用于访问和遍历容器中的元素,但它们并不局限于模板类,也不总是表现得像传统的指针。迭代器的设计和实现可以非常复杂,具体取决于它们所遍历的容器的类型。让我们来探讨一下这个话题:
- 迭代器与指针的相似性
迭代器在概念上类似于指针,因为它们:
提供了访问元素的能力,通常通过解引用操作符(*)。
支持移动操作,例如通过递增(++)和递减(–)操作符来前进或后退。 - 迭代器与指针的差异
虽然迭代器表现得类似于指针,但它们在设计和功能上通常比指针更为复杂:
容器特异性:迭代器是为特定类型的容器设计的,例如 vector、list 或 map。每种容器的迭代器都根据该容器的内部结构进行了优化。
支持的操作级别:不是所有迭代器都支持所有类型的操作。例如,std::list 的迭代器支持双向移动(++ 和 --),而 std::forward_list 的迭代器只支持向前移动(++)。std::vector 的迭代器支持随机访问(即可以跳跃访问,如 it + 5),而其他许多类型的迭代器则不支持。 - 不限于模板类
虽然STL(标准模板库)容器如 vector、list 和 map 都是模板类,并且它们的迭代器广泛应用于各种编程情景中,迭代器的概念并不仅限于模板类。任何容器,无论是否使用模板,只要它提供了一种方法来连续访问其元素,理论上都可以实现迭代器接口。实际上,你可以为自定义的容器类设计迭代器,无论这些类是否是模板类。
vector的begin()与end()
vector(v.begin(), v.end());//将v[begin(), end())区间中的元素拷贝给本身
- v.begin()到v.end()不会漏掉最后一项,因为v.end()本来就是指向最后一个元素之后的位置
c++中的参数类型
- 在C++中,决定函数参数是否使用引用主要取决于参数的类型、大小以及是否需要在函数中修改该参数。以下是一些一般的指导原则:
- 大对象或复杂对象(如类实例):
- 使用常量引用 (const T&) 传递,不需要修改参数的情况。
使用非常量引用 (T&) 传递,需要在函数中修改参数的情况。
- 使用常量引用 (const T&) 传递,不需要修改参数的情况。
- 小对象或基础类型(如 int, char, float):
- 直接传值 (T),通常这些类型传值的开销很小。
- 指针类型:
- 如果需要修改指针指向的内容,使用指针或指针引用。
- 如果不需要修改指针指向的内容,使用常量指针。
- 大对象或复杂对象(如类实例):
C++ 和 Java 中的 map
对比
1. 引用和导入
C++:
#include <map>
using namespace std;
java:
import java.util.Map;
import java.util.HashMap;
2. 声明与初始化
C++:
map<int, string> myMap;//直接声明没有new
myMap[1] = "One";//直接赋值,似乎python的dict有这个用法
myMap[2] = "Two";//如果这个pair已经存在就会直接覆盖
Java:
Map<Integer, String> myMap = new HashMap<>();
myMap.put(1, "One");//经典的put~
myMap.put(2, "Two");
3. 插入元素
C++:
myMap.insert(make_pair(3, "Three"));//也可以用下面的方法
result=myMap.insert(make_pair(3, "Three"));
//安全性:insert 方法不会覆盖已经存在的键值对。如果键已经存在,insert 不会做任何修改。
//返回值:insert 方法返回一个 pair,其中包含迭代器和一个布尔值,可以用来判断插入是否成功。
myMap[3]="Three";
Java:
myMap.put(3, "Three");
4. 访问元素
C++:
复制代码
string value = myMap[1]; // 使用下标操作符访问
// 或者
string value = myMap.at(1); // 使用 at 方法访问,带边界检查
Java:
String value = myMap.get(1);
5. 检查元素是否存在
C++:
if (myMap.find(2) != myMap.end()) {
// 元素存在,要知道
//find函数,如果找不到就返回end()(最后一个元素的后面一个元素)
}
- 注意,find函数返回的是一个迭代器,如果要拿到map里的key或value的话还要进一步操作:
//这个地方之类用auto是最好的,不用写那么多iterator之类的
auto it=myMap.find(target-nums[i]);
int x=it->first;//还需要这样一步!
另一种办法:count()函数在容器中其实是计数的作用,但是介于map里的元素不会重复,可以count()函数可以充当检查是否存在的作用
bool exists=myMap.count(key);
Java:
if (myMap.containsKey(2)) {
// 元素存在
}
6. 删除元素
C++:
myMap.erase(1);
Java:
myMap.remove(1);
7. 迭代
C++:
for (auto it = myMap.begin(); it != myMap.end(); ++it) {
cout << it->first << " -> " << it->second << endl;
}
//auto 不是一种数据类型,而是一个类型推导关键字,确保咱不出错
//注意 迭代器指针指向map的时候,取key和value的时候,用
->first以及->second
Java:
for (Map.Entry<Integer, String> entry : myMap.entrySet()) {
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
- 注意 如果不需要有序map直接用 unordered_map,在判题的时候可以时间复杂度更小
初始化
cpp中表示bool的vector一定要初始化,方法:
vector<bool> used(len, false);//长度+每个都初始化为false
- vector初始化的方法,长度+存储内容
vector<vector<int>> g(n, vector<int>(n, inf));