当前位置: 首页 > news >正文

【C++】模拟实现string

 

目录

🌞专栏导读

🌛定义string类

 🌛构造函数

🌛拷贝构造函数

🌛赋值函数

🌛析构函数 

🌛[]操作符重载 

🌛c_str、size、capacity函数 

🌛比较运算符重载 

 🌛resize与reserve函数

🌛push_back、append函数 

🌛insert函数 

🌛erase函数

🌛find函数

 🌛swap函数

🌛clean函数

 🌛迭代器

🌛>> 与 << 重载


🌞专栏导读

🌟作者简介:日出等日落,在读本科生一枚,致力于 C/C++、Linux 学习。

🌟本文收录于 C++系列,本专栏主要内容为 C++ 初阶、C++ 进阶、STL 详解等,持续更新!

🌟相关专栏推荐:C语言系列 、Linux系列 、数据结构与算法

本章我们将模拟实现string,但不一定非要与库中完全相同。我们将其中重要的、常用的接口进行模拟实现,旨在加深string类的学习与记忆。 

🌛定义string类

为了区别于标准库中的string,这里使用自己的命名空间,在自己的命名空间模拟实现string

string包含这三个基本成员

  • char* _str 字符数组;
  • size_t _size 有效字符大小;
  • size_t _capacity 容量;

 此外还需声明一个static成员nposnpos为将来实现的某些成员函数的缺省值,值位-1

namespace yxb
{class string{public:private:char* _str;size_t _capacity;size_t _size;//类中声明static const size_t npos;};//类外定义const size_t string::npos = -1;
}

 🌛构造函数

//构造函数string(const char* str = "")  //使用缺省值:_size(strlen(str)){_capacity = _size == 0 ? 3 : _size;  //_capacity初始值不能为0_str = new char[_capacity + 1];  //为'\0'预留位置strcpy(_str, str);}

注意

  • _capacity的值不能初始化为0,因为扩容时可能出现0*n=0的情况。

🌛拷贝构造函数

拷贝构造虽然编译器会自动实现,但是自动实现的拷贝构造为浅拷贝,对于string类中,成员变量会申请资源的情况,浅拷贝是行不通的,所以需要我们自己实现。

//拷贝构造s3(s2)string(const string& s):_size(s._size),_capacity(s._capacity){_str = new char[s._capacity + 1];strcpy(_str, s._str);}

🌛赋值函数

	//s1 = s3   s1 = s1string& operator=(const string& s){if (this != &s){char* tmp = new char[s._capacity + 1];strcpy(tmp,s._str);delete[] _str;_str = tmp;_size = s._size;_capacity = s._capacity;}return *this;}

🌛析构函数 

~string(){delete[] _str;_str = nullptr;_capacity = _size = 0; }

🌛[]操作符重载 

注意应对const对象与非const对象须实现不同的重载函数。

        char& operator[](size_t pos){assert(pos < _size);return _str[pos];}const char& operator[](size_t pos)const{assert(pos < _size);return _str[pos];}

🌛c_str、size、capacity函数 

  • c_str:返回C风格的字符串。
  • size:返回_size;
  • capacity:返回_capacity;
	const char* c_str(){return _str;}size_t size() const{return _size;}size_t capacity() const{return _capacity;}

🌛比较运算符重载 

	//比较运算符重载bool operator>(const string& s) const{return strcmp(_str, s._str) > 0;}bool operator==(const string& s) const{return strcmp(_str, s._str) == 0;}bool operator>=(const string& s) const{return *this > s && *this == s;}bool operator<(const string& s) const{return !(*this >= s);}bool operator<=(const string& s) const{return !(*this > s);}bool operator!=(const string& s) const{return !(*this == s);}

 🌛resize与reserve函数

  • resize:扩容并初始化;
  • reserve:只扩容;
//扩容void reverse(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}//扩容+初始化void resize(size_t n, char ch = '\0'){if (n <= _size){//删除数据,保留前n个_size = n;_str[_size] = '\0';}else{if (n > _capacity){reverse(n);}size_t i = _size;while (i < n){_str[i++] = ch;}_size = n;_str[_size] = '\0';}}

🌛push_back、append函数 

  • push_back:尾插一个字符;
  • append:尾插一个字符串;
  • +=:尾插一个字符或字符串;
void push_back(char ch){if (_size + 1 > _capacity){reverse(_capacity * 2);}_str[_size] = ch;_size++;_str[_size] = '\0';}void append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){reverse(_size + len);}strcpy(_str + _size, str);_size += len;}string& operator+=(char ch){push_back(ch);return *this;}string& operator+=(const char* str){append(str);return *this;}

🌛insert函数 

  • insert:在pos位置插入一个字符或字符串;
	void insert(size_t pos, char ch){assert(pos <= _size);if (_size + 1 > _capacity){reverse(2 * _capacity);}size_t end = _size + 1;while (pos < end){_str[end] = _str[end - 1];end--;}_str[pos] = ch;_size++;}void insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);if (_size + len > _capacity){reverse(_size + len);}//挪动数据size_t end = _size + len;while ( end > pos +len-1 ){_str[end] = _str[end-len];end--;}//拷贝插入 strncpy(_str + pos, str, len);_size += len;}

🌛erase函数

  • erase:删除pos位置向后的n个字符;
	void erase(size_t pos, size_t len = npos){if (len == npos || pos + len >= _size){_str[pos] = '\0';_size = pos;}//0123456789else{strcpy(_str + pos, _str + pos + len);_size -= pos;}}

🌛find函数

  • find:从pos位置开始向后查找指定字符或字符串,并返回起始位置的下标。
	size_t find(char ch, size_t pos = npos){assert(pos < _size);for (size_t i = pos; i < _size; ++i){if (_str[i] == ch){return i;}}return npos;}size_t find(const char* str, size_t pos = npos){assert(pos < _size);char* p = strstr(_str, str);if (p == nullptr){return npos;}else{return p - str;}}

 🌛swap函数

	void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}

🌛clean函数

  • clean:清理数据;
	void clean(){_str[0] = '\0';_size = 0;}

 🌛迭代器

	//迭代器typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin() const{return _str;}const_iterator end()const{return _str + _size;}

🌛>> 与 << 重载

注意这两个函数须定义在类外

    ostream& operator<<(ostream& out, const string& str){for (auto ch : str){out << ch;}return out;}istream& operator>>(istream& in, string& str){str.clean();char ch = in.get();char buff[128]; //避免因频繁扩容导致效率过低size_t i = 0;while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 127){buff[127] = '\0';str += buff;i = 0;}ch = in.get();}if (i != 0){buff[i] = '\0';str += buff;}return in;}

🌛完整代码

#pragma once
#include<assert.h>namespace yxb
{class string{public:typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin()const{return _str;}const_iterator end()const{return _str + _size;}/*string():_str(new char[1]), _size(0),_capacity(0){_str[0] = '\0';}*/string(const char* str = ""):_size(strlen(str)){_capacity = _size == 0 ? 3 : _size;_str = new char[_capacity + 1];strcpy(_str, str);}//拷贝构造s3(s2)string(const string& s):_size(s._size),_capacity(s._capacity){_str = new char[s._capacity + 1];strcpy(_str, s._str);}//s1 = s3   s1 = s1string& operator=(const string& s){if (this != &s){char* tmp = new char[s._capacity + 1];strcpy(tmp,s._str);delete[] _str;_str = tmp;_size = s._size;_capacity = s._capacity;}return *this;}~string(){delete[] _str;_str = nullptr;_capacity = _size = 0; }const char* c_str(){return _str;}char& operator[](size_t pos){assert(pos < _size);return _str[pos];}const char& operator[](size_t pos)const{assert(pos < _size);return _str[pos];}size_t size()const{return _size;}size_t capacity()const{return _capacity;}bool operator>(const string& s)const{return strcmp(_str, s._str) > 0;}bool operator==(const string& s)const{return strcmp(_str, s._str) == 0;}bool operator>=(const string& s)const{return (*this == s || *this > s);}bool operator<(const string& s)const{return !(*this >= s);}bool operator<=(const string& s)const{return !(*this > s);}bool operator!=(const string& s)const{return !(*this == s);}//扩容void reverse(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}//扩容+初始化void resize(size_t n, char ch = '\0'){if (n <= _size){//删除数据,保留前n个_size = n;_str[_size] = '\0';}else{if (n > _capacity){reverse(n);}size_t i = _size;while (i < n){_str[i++] = ch;}_size = n;_str[_size] = '\0';}}void push_back(char ch){if (_size + 1 > _capacity){reverse(_capacity * 2);}_str[_size] = ch;_size++;_str[_size] = '\0';}void append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){reverse(_size + len);}strcpy(_str + _size, str);_size += len;}string& operator+=(char ch){push_back(ch);return *this;}string& operator+=(const char* str){append(str);return *this;}void insert(size_t pos, char ch){assert(pos <= _size);if (_size + 1 > _capacity){reverse(2 * _capacity);}size_t end = _size + 1;while (pos < end){_str[end] = _str[end - 1];end--;}_str[pos] = ch;_size++;}void insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);if (_size + len > _capacity){reverse(_size + len);}//挪动数据size_t end = _size + len;while ( end > pos +len-1 ){_str[end] = _str[end-len];end--;}//拷贝插入 strncpy(_str + pos, str, len);_size += len;}void erase(size_t pos, size_t len = npos){if (len == npos || pos + len >= _size){_str[pos] = '\0';_size = pos;}//0123456789else{strcpy(_str + pos, _str + pos + len);_size -= pos;}}size_t find(char ch, size_t pos = npos){assert(pos < _size);for (size_t i = pos; i < _size; ++i){if (_str[i] == ch){return i;}}return npos;}size_t find(const char* str, size_t pos = npos){assert(pos < _size);char* p = strstr(_str, str);if (p == nullptr){return npos;}else{return p - str;}}void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}void clean(){_str[0] = '\0';_size = 0;}private:char* _str;size_t _capacity;size_t _size;static const size_t npos;};const size_t string::npos = -1;ostream& operator<<(ostream& out, const string& str){for (auto ch : str){out << ch;}return out;}istream& operator>>(istream& in, string& str){str.clean();char ch = in.get();char buff[128]; //避免因频繁扩容导致效率过低size_t i = 0;while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 127){buff[127] = '\0';str += buff;i = 0;}ch = in.get();}if (i != 0){buff[i] = '\0';str += buff;}return in;}void test_string1(){	string s1;string s2("hello world");cout << s1.c_str() << endl;cout << s2.c_str() << endl;s2[0]++;cout << s2.c_str() << endl;}void test_string2(){string s1;string s2("hello world");cout << s1.c_str() << endl;cout << s2.c_str() << endl;s1 = s2;cout << s1.c_str() << endl;cout << s2.c_str() << endl;}void test_string3(){string s1;string s2("hello world");cout << s1.c_str() << endl;cout << s2.c_str() << endl;string::iterator it = s2.begin();while (it != s2.end()){cout << *it << endl;++it;}}void test_string4(){string s1;string s2("hello world");string s3("hello");cout << s1.c_str() << endl;cout << s2.c_str() << endl;cout << (s3 >= s2) << endl;}void test_string5(){string s1;string s2("hello world");s2.append("yyyyyy");cout << s2.c_str() << endl;}void test_string6(){string s1("hhh ");cout << s1.c_str() << endl;s1.resize(10, 'x');cout << s1.c_str() << endl;s1.resize(100, 'y');cout << s1.c_str() << endl;}void test_string7(){string s1("123456789");cout << s1.c_str() << endl;s1.insert(2, "wwww");cout << s1.c_str() << endl;s1.insert(0, "ss");cout << s1.c_str() << endl;}void test_string8(){string s1("123456789");cout << s1.c_str() << endl;s1.erase(4, 2);cout << s1.c_str() << endl;}void test_string9(){string s1;cin >> s1;cout << s1 << endl;}
}

相关文章:

【C++】模拟实现string

目录 &#x1f31e;专栏导读 &#x1f31b;定义string类 &#x1f31b;构造函数 &#x1f31b;拷贝构造函数 &#x1f31b;赋值函数 &#x1f31b;析构函数 &#x1f31b;[]操作符重载 &#x1f31b;c_str、size、capacity函数 &#x1f31b;比较运算符重载 &#…...

AI智慧安监视频监控汇聚平台EasyCVR调用接口出现跨域现象该如何解决?

视频监控汇聚EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有GB28181、RTSP/Onvif、RTMP等&#xff0c;以及厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等&#xff0c;能对外分发RTSP、RTMP、FLV、HLS、WebRTC等格式的视…...

无人机机巢有哪些,无人机机场/机场的主要分类

随着无人机技术的飞速发展&#xff0c;无人机已经渗透到了物流、农业、救援、公共安全等多个领域。而为了使这些无人机能更加高效、灵活地运行&#xff0c;一个新的概念应运而生&#xff0c;那就是无人机机巢&#xff08;UAV Nest&#xff09;。复亚智能无人机机巢是一种供无人…...

联想存储 HH0305_DE4000H 划分卷组、卷、主机

创建卷组 可使用卷组来创建可供主机访问的一个或多个卷。卷组是具有共同特性&#xff08;如 RAID 级别和容量&#xff09;的卷的容器。 关于本任务 如果拥有容量较大的驱动器且可以在控制器之间分发卷&#xff0c;则为每个卷组创建多个卷可以很好地利用存储容量和保护数据。…...

【Python机器学习】实验08 决策树

文章目录 决策树1 创建数据2 定义香农信息熵3 条件熵4 信息增益5 计算所有特征的信息增益&#xff0c;选择最优最大信息增益的特征返回6 利用ID3算法生成决策树7 利用数据构造一颗决策树Scikit-learn实例决策树分类决策树回归Scikit-learn 的决策树参数决策树调参 实验1 通过sk…...

MySQL的innoDB存储引擎如何解决幻读的问题?

MySQL的innoDB存储引擎如何解决幻读的问题 基本情况 MySQL有四种事务隔离级别&#xff0c;这四种隔离级别代表当存在多个事务并发冲突时&#xff0c;可能出现的脏读、不可重复读、幻读的问题InnoDB 在 RR 的隔离级别下 &#xff0c;解决了幻读的问题幻读是指在同一个事务中&a…...

Web3.0:重新定义互联网的未来

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; Web3.0&#xff1a;重新定义互联网的未来 Web3.0是指下一代互联网&#xff0c;也称为“分布式互联网”。相比于Web1.0和Web2.0&#xff0c;Web3.0具有更强的去中心化、…...

2023年还能选择前端吗?

前言 在Github2022的 Octoverse年度报告上&#xff0c;稳居最多使用榜首的语言可以看到是JavaScript&#xff0c;作为前端中最为关键的一部分&#xff0c;这说明即使现在&#xff0c;前端这一块仍然是大量的人涌进来&#xff0c;依然是火热&#xff0c;但是&#xff0c;一门语…...

sheetJs / xlsx-js-style 纯前端实现导出 excel 表格及自定义单元格样式

文章目录 一、安装二、创建基础工作表三、设置单元格宽度/高度/隐藏单元格四、分配数字格式五、超链接六、单元格注释七、公式八、合并单元格九、自定义单元格样式十、项目地址 一、安装 xlsx 地址&#xff1a;https://www.npmjs.com/package/xlsxSheetJs 地址&#xff1a;htt…...

Redis 报错 RedisConnectionException: Unable to connect to x.x.x.x:6379

文章目录 Redis报错类型可能解决方案 Redis报错类型 org.springframework.data.redis.connection. spingboot调用redis出错 PoolException: Could not get a resource from the pool; 连接池异常:无法从池中获取资源; nested exception is io.lettuce.core. 嵌套异常 RedisConn…...

Stable Diffusion - 真人照片的高清修复 (StableSR + GFPGAN) 最佳实践

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132032216 GFPGAN (Generative Facial Prior GAN) 算法&#xff0c;用于实现真实世界的盲脸恢复的算法&#xff0c;利用预训练的面部 GAN&#xf…...

细讲一个 TCP 连接能发多少个 HTTP 请求(一)

一道经典的面试题是从 URL 在浏览器被被输入到页面展现的过程中发生了什么&#xff0c;大多数回答都是说请求响应之后 DOM 怎么被构建&#xff0c;被绘制出来。但是你有没有想过&#xff0c;收到的 HTML 如果包含几十个图片标签&#xff0c;这些图片是以什么方式、什么顺序、建…...

了解 CVSS:通用漏洞评分系统的应用

漏洞威胁管理至关重要&#xff0c;因为网络犯罪是一种持续存在的全球风险。网络犯罪分子愿意利用软件中的任何漏洞来访问网络和设备。对使用该软件的软件开发人员和组织的影响可能很严重。用户必须处理攻击的结果&#xff0c;例如赎金或数据盗窃&#xff0c;并且还可能面临法律…...

Xilinx FPGA电源设计与注意事项

1 引言 随着半导体和芯片技术的飞速发展&#xff0c;现在的FPGA集成了越来越多的可配置逻辑资源、各种各样的外部总线接口以及丰富的内部RAM资源&#xff0c;使其在国防、医疗、消费电子等领域得到了越来越广泛的应用。当采用FPGA进行设计电路时&#xff0c;大多数FPGA对上电的…...

前端:地图篇(一)

1、前言 在很多的出行程序中&#xff0c;都会使用到地图这一个功能&#xff0c;在实际的开发中我们也不会去开发一个自己的地图模型。如果自己开发一个地图模型&#xff0c;那么需要投入的成本、人力都是非常巨大的。所以我们很多网站和APP中使用的都是第三方的接口和JS&#…...

刷题笔记 day6

力扣 57 和为s的两个整数 class Solution { public:vector<int> twoSum(vector<int>& nums, int target) {vector<int> v;int i 0 , j nums.size()-1;while(i < j){if(nums[i] nums[j] > target){--j;}else if(nums[i] nums[j] < target){i…...

Drools用户手册翻译——第四章 Drools规则引擎(十一)复杂事件处理(CEP)的属性更改设置和监听器

甩锅声明&#xff1a;本人英语一般&#xff0c;翻译只是为了做个笔记&#xff0c;所以有翻译错误的地方&#xff0c;错就错了&#xff0c;如果你想给我纠正&#xff0c;就给我留言&#xff0c;我会改过来&#xff0c;如果懒得理我&#xff0c;就直接划过即可。 事实类型的属性…...

[数据分析与可视化] Python绘制数据地图4-MovingPandas入门指北

MovingPandas是一个基于Python和GeoPandas的开源地理时空数据处理库&#xff0c;用于处理移动物体的轨迹数据。它提供了一组强大的工具&#xff0c;可以轻松地加载、分析和可视化移动物体的轨迹。通过使用MovingPandas&#xff0c;用户可以轻松地处理和分析移动对象数据&#x…...

基于SpringBoot+Vue的MOBA类游戏攻略分享平台设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…...

Linux sed 命令详解

Linux sed&#xff08;Stream Editor&#xff09;是一种强大的文本处理工具&#xff0c;它在命令行中执行对文本进行搜索、替换和编辑等操作。sed的设计理念是按行处理文本&#xff0c;可以将输入文本逐行读取并应用指定的操作&#xff0c;然后输出结果。 sed命令有多种选项和…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

postgresql|数据库|只读用户的创建和删除(备忘)

CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成

厌倦手动写WordPress文章&#xff1f;AI自动生成&#xff0c;效率提升10倍&#xff01; 支持多语言、自动配图、定时发布&#xff0c;让内容创作更轻松&#xff01; AI内容生成 → 不想每天写文章&#xff1f;AI一键生成高质量内容&#xff01;多语言支持 → 跨境电商必备&am…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...