C++学习笔记(11)

四、学习要领
1)如果容器有成员函数,则使用成员函数,如果没有才考虑用 STL 的算法函数。
2)把全部的 STL 算法函数过一遍,知道大概有些什么东西。
3)如果打算采用某算法函数,一定要搞清楚它的原理,关注它的效率。
4)不要太看重这些算法函数,自己写一个也就那么回事。
5)不是因为简单,而是因为不常用。 五、常用函数
1)for_each()遍历
2)find()遍历
3)find_if()遍历
4)find_not_if()遍历
5)sort()排序
STL 的 sort 算法,数据量大时采用 QuickSort(快速排序),分段归并排序。一旦分段后的数据量小于
某个门槛(16),为避免 QuickSort 的递归调用带来过大的额外负荷,就改用 InsertSort(插入排序)。
如果递归层次过深,还会改用 HeapSort(堆排序)。
适用于数组容器 vector、string、deque(list 容器有 sort 成员函数,红黑树和哈希表没有排序的说
法)。
6)二分查找
示例(foreach):
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
template<typename T>
void zsshow(const T& no) // 张三的个性化表白函数。
{
cout << "亲爱的" << no << "号:我是一只傻傻鸟。\n";
}
template<typename T>
class czs // 张三的个性化表白仿函数。
{
public:
void operator()(const T& no) {
cout << "亲爱的" << no << "号:我是一只傻傻鸟。\n";
}
};
template<typename T1, typename T2>
void foreach(const T1 first, const T1 last, T2 pfun)
{
for (auto it = first; it != last; it++)
pfun(*it); // 以超女编号为实参调用类的 operator()函数。
}
int main()
{
vector<int> bh = { 5,8,2,6,9,3,1,7 }; // 存放超女编号的容器。
//list<string> bh = { "05","08","02","06","09","03","01","07" }; // 存放超女编号的容器。
// 写一个函数,在函数中遍历容器,向超女表白,表白的方法可自定义。
foreach(bh.begin(), bh.end(), zsshow<int>); // 第三个参数是模板函数。
foreach(bh.begin(), bh.end(), czs<int>()); // 第三个参数是仿函数。
}
示例(findif):
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
template<typename T>
bool zsshow(const T& no,const T & in_no) // 张三的个性化表白函数。
{
if (no != in_no) return false;
cout << "亲爱的" << no << "号:我是一只傻傻鸟。\n";
return true;
}
template<typename T>
class czs // 张三的个性化表白仿函数。
{
public:
bool operator()(const T& no, const T& in_no) {
if (no != in_no) return false;
cout << "亲爱的" << no << "号:我是一只傻傻鸟。\n";
return true;
}
};
template<typename T1, typename T2, typename T3>
T1 findif(const T1 first, const T1 last, T2 pfun,T3 in_no)
{
for (auto it = first; it != last; it++)
if (pfun(*it, in_no) ==true) return it; // 用迭代器调用函数对象。
return last;
}
int main()
{
vector<int> bh = { 5,8,2,6,9,33,1,7 }; // 存放超女编号的容器。
//list<string> bh = { "05","08","02","06","09","03","01","07" }; // 存放超女编号的容器。
auto it1=findif(bh.begin(), bh.end(), zsshow<int>,2); // 第三个参数是模板函数。
if (it1 == bh.end()) cout << "查找失败。\n";
else cout << "查找成功:" << *it1 << endl;
auto it2=findif(bh.begin(), bh.end(), czs<int>(),33); // 第三个参数是仿函数。
if (it2 == bh.end()) cout << "查找失败。\n";
else cout << "查找成功:" << *it2 << endl;
}
示例(findif 仿函数):
#include <iostream>
#include <vector>
#include <list>
#include <algorithm> // STL 算法函数头文件。
using namespace std;
template<typename T>
bool zsshow(const T& no) // 张三的个性化表白函数。
{
if (no != 3) return false;
cout << "亲爱的" << no << "号:我是一只傻傻鸟。\n";
return true;
}
template<typename T>
class czs // 张三的个性化表白仿函数。
{
public:
T m_no; // 存放张三喜欢的超女编号。
czs(const T& no) : m_no(no) {} // 构造函数的参数是张三喜欢的超女编号。
bool operator()(const T& no) {
if (no != m_no) return false;
cout << "亲爱的" << no << "号:我是一只傻傻鸟。\n";
return true;
}
};
template<typename T1, typename T2>
T1 findif(const T1 first, const T1 last, T2 pfun)
{
for (auto it = first; it != last; it++)
if (pfun(*it) ==true) return it; // 用迭代器调用函数对象。
return last;
}
int main()
{
vector<int> bh = { 5,8,2,6,9,33,1,7 }; // 存放超女编号的容器。
//list<string> bh = { "05","08","02","06","09","03","01","07" }; // 存放超女编号的容器。
auto it1=find_if(bh.begin(), bh.end(), zsshow<int>); // 第三个参数是模板函数。
if (it1 == bh.end()) cout << "查找失败。\n";
else cout << "查找成功:" << *it1 << endl;
auto it2=find_if(bh.begin(), bh.end(), czs<int>(8)); // 第三个参数是仿函数。
if (it2 == bh.end()) cout << "查找失败。\n";
else cout << "查找成功:" << *it2 << endl;
}
示例(bsort):
#include <iostream>
#include <vector>
#include <list>
#include <algorithm> // STL 算法函数。
#include <functional> // STL 仿函数。
using namespace std;
template<typename T>
bool compasc(const T& left, const T& right) { // 普通函数,用于升序。
return left < right;
}
template<typename T>
struct _less
{
bool operator()(const T& left, const T& right) { // 仿函数,用于升序。
return left < right;
}
};
template<typename T>
bool compdesc(const T& left, const T& right) { // 普通函数,用于降序。
return left > right;
}
template<typename T>
class _greater
{
public:
bool operator()(const T& left, const T& right) { // 仿函数,用于降序。
return left > right;
}
};
template<typename T, typename compare>
void bsort(const T first, const T last, compare comp) // 冒泡排序。
{
while(true)
{
bool bswap = false; // 本轮遍历已交换过元素的标识,true-交换过,false-未交
换过。
for (auto it = first; ; )
{
auto left = it; // 左边的元素。
it++;
auto right = it; // 右边的元素。
if (right == last) break; // 表示 it1 已经是最后一个元素了。
//if (*left > *right) // 如果左边的元素比右边大,交换它们的值。
//if (*left < *right) // 如果左边的元素比右边小,交换它们的值。
// 排序规则:如果 comp()返回 true,left 排在前面(升序),否则 right 排在前面(降
序)。
if (comp(*left, *right) == true) continue;
// 交换两个元素的值。
auto tmp = *right; *right = *left; *left = tmp;
bswap = true; // 一轮遍历已交换过元素的标识。
}
if (bswap == false) break; // 如果在 for 循环中不曾交换过元素,说明全部的元素已有序。
}
}
int main()
{
vector<int> bh = { 5,8,2,6,9,33,1,7 }; // 存放超女编号的容器。
//list<string> bh = { "05","08","02","06","09","03","01","07" }; // 存放超女编号的容器。
//bsort(bh.begin(), bh.end(),compasc<int>); // 普通函数(升序)。
//bsort(bh.begin(), bh.end(), compdesc<int>); // 普通函数(降序)。
//bsort(bh.begin(), bh.end(),_less<int>()); // 仿函数(升序)。
//bsort(bh.begin(), bh.end(), _greater<int>()); // 仿函数(降序)。
//bsort(bh.begin(), bh.end(), less<int>()); // STL 提供的仿函数(升序)。
//bsort(bh.begin(), bh.end(), greater<int>()); // STL 提供的仿函数(降序)。
//sort(bh.begin(), bh.end(),_less<int>()); // 仿函数(升序)。
sort(bh.begin(), bh.end(), _greater<int>()); // 仿函数(降序)。
for (auto val : bh)
cout << val << " ";
cout << endl;
}
示例(for_each):
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
template<typename T>
struct girl {
T m_yz; // 统计的颜值。
int m_count; // 符合条件的元素个数。
girl(const T yz) : m_yz(yz), m_count(0) {}
void operator()(const T& yz) {
if (yz==m_yz) m_count++;
}
};
int main()
{
vector<int> vv = { 1,3,2,4,1,2,3,1,4,3 }; // 1-极漂亮;2-漂亮;3-普通;4-歪瓜裂枣
girl<int> g=for_each(vv.begin(), vv.end(), girl<int>(1)); // 按颜值统计超女人数。
cout << "g.m_count=" << g.m_count << endl;
}
193、智能指针 unique_ptr
unique_ptr 独享它指向的对象,也就是说,同时只有一个 unique_ptr 指向同一个对象,当这个
unique_ptr 被销毁时,指向的对象也随即被销毁。
包含头文件:#include <memory>
template <typename T, typename D = default_delete<T>>
class unique_ptr
{
public:
explicit unique_ptr(pointer p) noexcept; // 不可用于转换函数。
~unique_ptr() noexcept;
T& operator*() const; // 重载*操作符。
T* operator->() const noexcept; // 重载->操作符。
unique_ptr(const unique_ptr &) = delete; // 禁用拷贝构造函数。
unique_ptr& operator=(const unique_ptr &) = delete; // 禁用赋值函数。
unique_ptr(unique_ptr &&) noexcept; // 右值引用。
unique_ptr& operator=(unique_ptr &&) noexcept; // 右值引用。
// ... private:
pointer ptr; // 内置的指针。
};
第一个模板参数 T:指针指向的数据类型。
第二个模板参数 D:指定删除器,缺省用 delete 释放资源。
测试类 AA 的定义:
class AA
{
public:
string m_name;
AA() { cout << m_name << "调用构造函数 AA()。\n"; }
AA(const string & name) : m_name(name) { cout << "调用构造函数 AA("<< m_name <<
")。\n"; }~AA() { cout << m_name << "调用了析构函数~AA(" << m_name << ")。\n"; }
}; 一、基本用法
1)初始化
方法一:
unique_ptr<AA> p0(new AA("西施")); // 分配内存并初始化。
方法二:
unique_ptr<AA> p0 = make_unique<AA>("西施"); // C++14 标准。
unique_ptr<int> pp1=make_unique<int>(); // 数据类型为 int。
unique_ptr<AA> pp2 = make_unique<AA>(); // 数据类型为 AA,默认构造函数。
unique_ptr<AA> pp3 = make_unique<AA>("西施"); // 数据类型为 AA,一个参数的构造函数。
unique_ptr<AA> pp4 = make_unique<AA>("西施",8); // 数据类型为 AA,两个参数的构造函数。
方法三(不推荐):
AA* p = new AA("西施");
unique_ptr<AA> p0(p); // 用已存在的地址初始化。
2)使用方法
 智能指针重载了*和->操作符,可以像使用指针一样使用 unique_ptr。
 不支持普通的拷贝和赋值。
AA* p = new AA("西施");
unique_ptr<AA> pu2 = p; // 错误,不能把普通指针直接赋给智能指针。
unique_ptr<AA> pu3 = new AA("西施"); // 错误,不能把普通指针直接赋给智能指针。
unique_ptr<AA> pu2 = pu1; // 错误,不能用其它 unique_ptr 拷贝构造。
unique_ptr<AA> pu3;
pu3 = pu1; // 错误,不能用=对 unique_ptr 进行赋值。
 不要用同一个裸指针初始化多个 unique_ptr 对象。
 get()方法返回裸指针。
 不要用 unique_ptr 管理不是 new 分配的内存。
3)用于函数的参数
 传引用(不能传值,因为 unique_ptr 没有拷贝构造函数)。
 裸指针。
4)不支持指针的运算(+、-、++、--)
二、更多技巧
1)将一个 unique_ptr 赋给另一个时,如果源 unique_ptr 是一个临时右值,编译器允许这样做;如
果源 unique_ptr 将存在一段时间,编译器禁止这样做。一般用于函数的返回值。
unique_ptr<AA> p0;
p0 = unique_ptr<AA>(new AA ("西瓜"));
2)用 nullptr 给 unique_ptr 赋值将释放对象,空的 unique_ptr==nullptr。
3)release()释放对原始指针的控制权,将 unique_ptr 置为空,返回裸指针。(可用于把 unique_ptr
传递给子函数,子函数将负责释放对象)
4)std::move()可以转移对原始指针的控制权。(可用于把 unique_ptr 传递给子函数,子函数形参
也是 unique_ptr)
5)reset()释放对象。
void reset(T * _ptr= (T *) nullptr);
pp.reset(); // 释放 pp 对象指向的资源对象。
pp.reset(nullptr); // 释放 pp 对象指向的资源对象
pp.reset(new AA("bbb")); // 释放 pp 指向的资源对象,同时指向新的对象。
6)swap()交换两个 unique_ptr 的控制权。
void swap(unique_ptr<T> &_Right);
7)unique_ptr 也可象普通指针那样,当指向一个类继承体系的基类对象时,也具有多态性质,如同
使用裸指针管理基类对象和派生类对象那样。
8)unique_ptr 不是绝对安全,如果程序中调用 exit()退出,全局的 unique_ptr 可以自动释放,但
局部的 unique_ptr 无法释放。
9)unique_ptr 提供了支持数组的具体化版本。
数组版本的 unique_ptr,重载了操作符[],操作符[]返回的是引用,可以作为左值使用。
// unique_ptr<int[]> parr1(new int[3]); // 不指定初始值。
unique_ptr<int[]> parr1(new int[3]{ 33,22,11 }); // 指定初始值。
cout << "parr1[0]=" << parr1[0] << endl;
cout << "parr1[1]=" << parr1[1] << endl;
cout << "parr1[2]=" << parr1[2] << endl;
unique_ptr<AA[]> parr2(new AA[3]{string("西施"), string("冰冰"), string("幂幂")});
cout << "parr2[0].m_name=" << parr2[0].m_name << endl;
cout << "parr2[1].m_name=" << parr2[1].m_name << endl;
cout << "parr2[2].m_name=" << parr2[2].m_name << endl;
示例 1:
#include <iostream>
#include <memory>
using namespace std;
class AA
{
public:
string m_name;
AA() { cout << m_name << "调用构造函数 AA()。\n"; }
AA(const string & name) : m_name(name) { cout << "调用构造函数 AA("<< m_name <<
")。\n"; }~AA() { cout << "调用了析构函数~AA(" << m_name << ")。\n"; }
};
// 函数 func1()需要一个指针,但不对这个指针负责。
void func1(const AA* a) {
cout << a->m_name << endl;
}
// 函数 func2()需要一个指针,并且会对这个指针负责。
void func2(AA* a) {
cout << a->m_name << endl;
delete a;
}
// 函数 func3()需要一个 unique_ptr,不会对这个 unique_ptr 负责。
void func3(const unique_ptr<AA> &a) {
cout << a->m_name << endl;
}
// 函数 func4()需要一个 unique_ptr,并且会对这个 unique_ptr 负责。
void func4(unique_ptr<AA> a) {
cout << a->m_name << endl;
}
int main()
{
unique_ptr<AA> pu(new AA("西施"));
cout << "开始调用函数。\n";
//func1(pu.get()); // 函数 func1()需要一个指针,但不对这个指针负责。
//func2(pu.release()); // 函数 func2()需要一个指针,并且会对这个指针负责。
//func3(pu); // 函数 func3()需要一个 unique_ptr,不会对这个 unique_ptr
负责。
func4(move(pu)); // 函数 func4()需要一个 unique_ptr,并且会对这个 unique_ptr 负责。
cout << "调用函数完成。\n";
if (pu == nullptr) cout << "pu 是空指针。\n";
}
示例 2:
#include <iostream>
#include <memory>
using namespace std;
class AA
{
public:
string m_name;
AA() { cout << m_name << "调用构造函数 AA()。\n"; }
AA(const string & name) : m_name(name) { cout << "调用构造函数 AA("<< m_name <<
")。\n"; }~AA() { cout << "调用了析构函数~AA(" << m_name << ")。\n"; }
};
int main()
{
//AA* parr1 = new AA[2]; // 普通指针数组。
AA* parr1 = new AA[2]{ string("西施"), string("冰冰") };
//parr1[0].m_name = "西施 1";
//cout << "parr1[0].m_name=" << parr1[0].m_name << endl;
//parr1[1].m_name = "西施 2";
//cout << "parr1[1].m_name=" << parr1[1].m_name << endl;
//delete [] parr1;
unique_ptr<AA[]> parr2(new AA[2]); // unique_ptr 数组。
//unique_ptr<AA[]> parr2(new AA[2]{ string("西施"), string("冰冰") });
parr2[0].m_name = "西施 1";
cout << "parr2[0].m_name=" << parr2[0].m_name << endl;
parr2[1].m_name = "西施 2";
cout << "parr2[1].m_name=" << parr2[1].m_name << endl;
}
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/53414.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

kubernetes微服务之ingress-nginx

目录 1 ingress-nginx 介绍 2 Ingress-nginx 的工作原理 3 使用 Ingress-nginx 的步骤 4 部署 ingress &#xff1a; 4.1 开启ipvs 模式 4.2 下载部署文件 4.3 上传镜像到harbor 4.4 修改文件中镜像地址,与harbor仓库路径保持一致 4.5 检查是否running 4.6 将ingress的命名…

轻松上手,高效产出:音频剪辑工具年度精选

不知道你有没有拍vlog记录生活的习惯&#xff0c;有时候视频里穿插进自己的声音能让视频更加丰富贴上自己的标签。这次我们一起探讨当下有哪些好用的在线音频剪辑工具。 1.FOXIT音频剪辑 链接直达>>https://www.foxitsoftware.cn/audio-clip/ 这个工具是一款专业的音…

Java 数据类型详解:基本数据类型与引用数据类型

在 Java 编程语言中&#xff0c;数据类型主要分为两大类&#xff1a;基本数据类型和引用数据类型。理解这两种类型的区别、使用场景及其转换方式是学习 Java 的基础。本文将深入探讨这两类数据类型的特点&#xff0c;并展示自动类型转换、强制类型转换以及自动拆箱和封箱的使用…

虚拟现实辅助工程技术助力多学科协同评估

在当今高速发展的经济环境中&#xff0c;制造业面临着多重挑战&#xff0c;包括提高产品性能、压缩设计周期、实现轻量化设计和降低成本。为了有效应对这些挑战&#xff0c;多学科协同评估成为缩短研发周期和提升研制质量的关键手段。 传统的多学科评估面临着数据孤立与融合困难…

《‌黑神话:‌悟空》‌游戏攻略‌

时光荏苒&#xff0c;岁月如梭&#xff0c;不知不觉已经来到了2024年的9月份了。 ‌突然想写一篇关于《‌黑神话&#xff1a;‌悟空》‌的游戏攻略‌。 在《‌黑神话&#xff1a;‌悟空》‌这款以中国古代名著《‌西游记》‌为背景的动作角色扮演游戏中&#xff0c;‌玩家将扮…

LeetCode 热题 100 回顾9

干货分享&#xff0c;感谢您的阅读&#xff01;原文见&#xff1a;LeetCode 热题 100 回顾_力code热题100-CSDN博客 一、哈希部分 1.两数之和 &#xff08;简单&#xff09; 题目描述 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标…

前端页面加载由模糊到清晰的实现方案

要实现图片加载时由模糊逐渐变得清晰的效果,可以使用 CSS 和 JavaScript 的结合。这里的思路是:先让图片在加载时模糊显示,等图片完全加载完后,再去掉模糊效果。 1. 使用 CSS 实现模糊效果 我们可以使用 filter: blur() 来为图片添加模糊效果,结合 transition 属性在加载…

MongoDB Limit 与 Skip 方法

MongoDB Limit 与 Skip 方法 MongoDB 是一个流行的 NoSQL 数据库&#xff0c;它提供了灵活的数据存储和强大的查询功能。在处理大量数据时&#xff0c;我们常常需要限制返回的结果数量或者跳过一部分结果&#xff0c;这时就可以使用 MongoDB 的 limit 和 skip 方法。 Limit 方…

Python中差分进化differential_evolution的调用及参数说明

在场景应用中&#xff0c;要求我们的函数计算结果尽可能的逼近实际测量结果&#xff0c;可转化计算结果与测量结果的残差&#xff0c;通过最小化残差&#xff0c;便可求出最优的结果。但使用最小二乘等方法来计算时&#xff0c;常常会使迭代的结果显然局部最优点而导致结算错误…

【redis】redis的特性和主要应用场景

文章目录 redis 的特性在内存中存储数据可编程的扩展能力持久化集群高可用快 redis 的应用场景实时数据存储缓存消息队列 redis 的特性 redis 的一些特性&#xff08;优点&#xff09;成就了它 在内存中存储数据 In-memory data structures MySQL 主要是通过“表”的方式来…

JavaEE-HTTPHTTPS

目录 HTTP协议 一、概念 二、http协议格式 http请求报文 http响应报文 URL格式 三、认识方法 四、认识报头 HTTP响应中的信息 HTTPS协议 对称加密 非对称加密 中间人攻击 解决中间人攻击 HTTP协议 一、概念 HTTP (全称为 "超⽂本传输协议") 是⼀种应⽤…

WEB项目解决CORS 跨域问题

为了安全&#xff0c;web默认是不允许跨域访问的。不过实际项目中&#xff0c;会遇到不同模块之间来回跳转的情况。所以&#xff0c;项目内部一般会修改配置或者代码来解决CORS跨域问题。 我的后端使用的是 Jetty 服务器&#xff0c;所以下面就拿jetty来举例。Jetty 提供了一个…

14.2 k8s中我们都需要监控哪些组件

本节重点介绍 : k8s中关注四大块指标总结 容器基础资源指标k8s资源指标k8s服务组件指标部署在pod中业务埋点指标 k8s关注指标分析 k8s中组件复杂&#xff0c;我们主要专注的无外乎四大块指标&#xff1a; 容器基础资源指标 为何关注这些指标 我们的应用从独享一台机器上…

springboot组件使用-mybatis组件使用

文章目录 springboot使用mybatis组件1. 添加依赖2. 配置数据源3. 创建实体类4. 创建Mapper接口5. 创建Mapper XML文件6. 使用Mapper7. 启动类配置 mybtis 动态SQL1. Mapper 注解2. Select 注解3. Insert 注解4. Update 注解5. Delete 注解6. Results 注解7. Param 注解8. Cache…

Mysql中的锁机制详解

一、概述 锁是计算机协调多个进程或线程并发访问某一资源的机制。 在数据库中&#xff0c;除了传统的计算资源&#xff08;如CPU、RAM、I/O等&#xff09;的争用以外&#xff0c;数据也是一种供需要用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决…

一文讲懂Spring Event事件通知机制

目录 一 什么是spring event 二 怎么实现spring event 一 什么是spring event 我不会按照官方的解释来说什么是spring event&#xff0c;我只是按照自己的理解来解释&#xff0c;可能原理上会和官方有偏差&#xff0c;但是它的作用和功能就是这个&#xff0c;我更加偏向于从他…

Rust:Restful API 服务程序开发详述

0. 关于异步程序设计 0.1 对异步机制的理解 运行效率对于后端程序来讲很重要。我曾经以为&#xff0c;多线程机制是后端设计的终极方法&#xff0c;后来才发现&#xff0c;异步机制才是榨干 CPU 运行效率资源的关键所在。 我最初对于异步程序设计有误解&#xff0c;以为多线…

详解React setState调用原理和批量更新的过程

1. React setState 调用的原理 setState目录 1. React setState 调用的原理2. React setState 调用之后发生了什么&#xff1f;是同步还是异步&#xff1f;3. React中的setState批量更新的过程是什么&#xff1f; 具体的执行过程如下&#xff08;源码级解析&#xff09;&#x…

安卓13带有系统签名的应用不能正常使用webview 调用webview失败 系统应用app apk

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改5.彩蛋1.前言 android版本高一些的平台,经常会遇到一些权限安全问题,像客户的应用如果带有系统签名,会导致不能正常使用webview问题。 2.问题分析 我们log信息,可以发现下面的提示: Fo…

网络层ip协议

一.概念 ip协议主要是为了在复杂的网络环境中确定一个合适的路径来传输主机间的数据。简单来说就是用来确定主机的位置。 ip协议中的一些设备如下&#xff1a; 主机: 配有 IP 地址, 但是不进行路由控制的设备;路由器: 即配有 IP 地址, 又能进行路由控制;节点: 主机和路由器的统…