C++ 线性表、内存操作、 迭代器,数据与算法分离。

线性表:

线性表是最基本、最简单、也是最常用的一种数据结构。线性表(linear list)是数据结构的

一种,一个线性表是n个具有相同特性的数据元素的有限序列。

线性表中数据元素之间的关系是一对一的关系,即除了第一个和最后一个数据元素之外,其它数据元素都是首尾相接的(注意,这句话只适用大部分线性表,而不是全部。比如,循环链表逻辑层次上也是一种线性表(存储层次上属于链式存储,但是把最后一个数据元素的尾指针指向了首位结点)。

线性表_百度百科 (baidu.com)

C++中的数组,vector,string是线性表,大家对线性表操作非常熟悉,感觉非常方便,比如:

std::string s = "Hello World!";

在字符串 s 中的第二个字符是 * (s.c_str() + 1), 或者 *(s.begin() + 1), 是字符 e;

为什么还要设计迭代器,是因为要数据与算法分离,这是C++标准库的核心,如果

不理解这个,你会感觉标准库非常难用,明明很简单的事,为什么搞得那么复杂。

看下面的例子:

cpp 复制代码
int main() {	

	std::string s = "Hello World!";
	std::list<char> slist1 = { 'H','e','l','l','o', ' ', 'W','o','r','l','d','!'};
	std::list<char> slist2(s.begin(), s.end());

	for (auto c : slist1) {
		std::cout << c;
	}

	std::cout << "\n";

	for (auto c : slist2) {
		std::cout << c;
	}

	std::cout << "\n";

	return 0;
}

输出结果都是:

因此,设计迭代器的核心目标数据与算法分离。

再看一个例,关于内存操作的例子,看下面的函数:

针对线性表:

cpp 复制代码
/// <summary>
/// 不改变原有数据,把内存段区间 [begin,pend) 向后移动nCount位,后面的
/// 数据pend后面会覆盖nCount-1个,包括pend就是nCount个,如果bFilling
/// 为True,则用相应的pFilling所指的数据填充空出来的内存。
/// 例:
///		_string s = "sss123   www";
///		MoveBack(s.begin(), s.begin() + 6, 3, true, s.end() - 3);
///     结果:s=wwwsss123www
/// 
/// 注意:pFilling 与 pbegin,pend,不能在同一区域的内存块中。
/// 
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="pbegin"></param>
/// <param name="pend"></param>
/// <param name="nCount"></param>
/// <param name="bFilling"></param>
/// <returns></returns>
/// 创建时间:2024-10-03    最后一次修改时间:2024-10-03 (已测试)
template<class T>
T* MoveBack(T* pbegin, T* pend, const size_t& nCount, const bool& bFilling = false,
const T* pFilling = null)
{
	assert(pend >= pbegin);

	for (size_t n = 0; n < pend - pbegin; ++n) {

		*(pend + nCount - 1 - n ) = *(pend - 1 - n);
	}

	if (bFilling && pFilling) { //检查bFilling不能在区间[pbegin,pend + nCount)中

		assert(pFilling < pbegin || pFilling >= pend + nCount);

		for (size_t n = 0; n < nCount; ++n) {

			*(pbegin + n) = *(pFilling + n);
		}
	}

	return pbegin;
}
cpp 复制代码
int main() {	

	std::string s = "Hello World!";

	//线性表
	_Array<char> arr;
	arr.SetBuffer(20,true);	
	arr.Add(s.begin(), s.end());
	for (auto c : arr) {std::cout << c;}
	std::cout << "\n";
	 
	//在线性表中"Hello World!########" => (后移7位)"####Hello World!####
	//前面####用"中国"填空

	std::cout << MoveBack(arr.Begin(), arr.End(), 7, true, "中国 : ") << "\n";



}

运行结果:

下面我们来设计可以针对迭代器进行移动的MoveBack_new函数

例子后面的???????,是为容器预留下的内存空间。

cpp 复制代码
template<class IterClass, class ValueType = IterClass::value_type>
const IterClass MoveBackIter(const IterClass& itbegin, const IterClass& itend,
	const size_t& nCount,const bool& bFilling = false,
	const ValueType* pFilling = null){

	//assert(itend >= itbegin);  //可能很多迭代器不支持

	for (size_t n = 0; n < itend - itbegin; ++n) {

		*(itend + nCount - 1 - n) = *(itend - 1 - n);
	}

	if (bFilling && pFilling) { //检查bFilling不能在区间[pbegin,pend + nCount)中

		//可能很多迭代器不支持
		//assert(pFilling < itbegin || pFilling > itend + nCount);

		for (size_t n = 0; n < nCount; ++n) {

			*(itbegin + n) = *(pFilling + n);
		}
	}

	return itbegin;
}

执行程序:

cpp 复制代码
int main() {	

	std::string s = "Hello World!???????";

	//线性表
	_Array<char> arr;
	arr.SetBuffer(30,true);	
	arr.Add(s.begin(), s.end());
	for (auto c : arr) {std::cout << c;}
	std::cout << "\n";
	 
	//在线性表中"Hello World!########" => (后移7位)"####Hello World!####
	//前面####用"中国"填空

	MoveBack_new(arr.begin(), arr.end(), 7, true, "中国 : ");
	cout << "线性表移动后内容:";
	for (auto c : arr) { std::cout << c; }
	std::cout << "\n";

 
	//链表
	_list<char> li;
	li.Add(s.begin(), s.end());
	for (auto c : li) { std::cout << c; }
	std::cout << "\n";



	MoveBack_new(li.begin(), li.begin() + 12, 7, true, "中国 : ");
	cout << "链表移动后内容::";
	for (auto c : li){	std::cout << c;	}
}

执行结果:

结论:

迭代器设计的目的就是把算法和数据剥离出来,比如上面的MoveBack_new,

即可以对线性表操作,又可以对链表操作,缺点是,在这后面,你要做太多的工作

和优化,但是这对你熟悉和使用,甚至设计标准库,非常有用。

相关推荐
PhyliciaFelicia1 小时前
基于R语言机器学习遥感数据处理与模型空间预测
开发语言·深度学习·随机森林·机器学习·数据分析·r语言
2401_857297911 小时前
秋招内推--招联金融2025
java·前端·算法·金融·求职招聘
小帅吖1 小时前
浅析Golang的Context
开发语言·后端·golang
Eiceblue1 小时前
Python保留数据删除Excel单元格的函数和公式
开发语言·python·excel
闲人编程1 小时前
使用Python实现图形学的阴影贴图算法
python·算法·图形学·贴图·阴影贴图
MarisTang1 小时前
Go语言实现随机森林 (Random Forest)算法
算法·随机森林·golang
丢掉幻想准备斗争1 小时前
C++(string类的实现)
开发语言·c++
育种数据分析之放飞自我2 小时前
GWAS分析中显著位点如何注释基因:excel???
linux·算法·excel
Grayson_Zheng2 小时前
【解决方案】关于 UART 接收数据时丢失数据的解决办法——环形缓冲存储区
c语言·数据结构·stm32·单片机
写bug如流水2 小时前
【Python】使用 Pydantic + SQLAlchemy + MySQL 实现自动记录创建时间和更新时间
开发语言·python·mysql