C++简单缓冲区类设计

news2024/11/16 13:36:34

目录

1.引言

2.静态缓冲区

3.动态缓冲区

4.数据引用类

5.自动数据引用类

6.几种缓冲区的类关系图

7.注意事项

8.完整代码


1.引言

        在C++中,设计静态和动态缓冲区类时,需要考虑的主要差异在于内存管理的方式。静态缓冲区类通常使用固定大小的内存区域(即栈分配或静态分配),而动态缓冲区类则根据需要动态地分配和释放内存(即堆分配)。下面将分别展示这几种缓冲区类的基本设计思路。

        不管是静态缓冲区还是动态缓冲区,都有统一的访问接口,于是提取共用方法,组成基础类:

template <class T>
class CSimpleDataBufferBase : public CNoncopyable
{
public:
	typedef T  DataType;
	typedef T* DataTypePointer;
	typedef T& DataTypeReference;
	typedef const T ConstDataType;
	typedef const T* ConstDataTypePointer;
	typedef const T& ConstDataTypeReference;
	
public:
	CSimpleDataBufferBase() {}
	virtual ~CSimpleDataBufferBase() {}

public:
	virtual  DWORD GetSize() const = 0;
	virtual  DataTypePointer GetData() = 0;
	virtual  ConstDataTypePointer GetData() const = 0;
	virtual  DWORD GetMaxSize() const = 0;
	operator DataTypePointer() {  return GetData(); } 
	DataTypeReference operator*() { return *GetData(); }
	DataTypeReference operator[](int nIndex);
	virtual  BOOL  SetData(ConstDataTypePointer pData, DWORD dwSize) = 0;
	virtual  void  Clear() = 0;
};

接口设计要点:

1)CSimpleDataBufferBase继承CNoncopyable,禁止构造拷贝和赋值拷贝。

2)访问缓冲区数据的接口,const和非const版本。

3)重载操作符*或[]访问缓冲区元素的数据

template <class T>
typename CSimpleDataBufferBase<T>::DataTypeReference CSimpleDataBufferBase<T>::operator[](int nIndex)
{
	if ( (nIndex >= 0) && (nIndex < (int)GetSize()))
	{
		DataTypePointer pData = GetData();
		return pData[nIndex];
	}
	else
	{
		throw std::out_of_range("invalid data<nIndex> position");
	}	
}

4)往缓冲区写数据接口,接收的是const T*和数据的长度。

5)获取缓冲区的上限。

5)清空缓冲区。

2.静态缓冲区

        静态缓冲区类通常包含一个固定大小的数组(或其他容器,但数组是最直接的例子),并提供一系列方法来操作这个数组。 静态缓冲区类CStaticSimpleDataBufferT实现代码如下:

//数据静态分配
template <class T>
class CStaticSimpleDataBufferT : public CSimpleDataBufferBase<T>
{
public:
	CStaticSimpleDataBufferT(DWORD dwMaxSize = MAX_STATIC_SIMPLE_BUFFER_SIZE);
	virtual ~CStaticSimpleDataBufferT() {  }

public:
	DWORD GetSize() const { return m_dwDataLen; }
	DataTypePointer GetData() { return m_sData ;}
	ConstDataTypePointer GetData() const { return m_sData ;}
	BOOL  SetData(ConstDataTypePointer pData, DWORD dwSize);
	DWORD GetMaxSize() const {  return m_dwMaxDataSize; }
	void  Clear() { m_dwDataLen = 0; }

private:
	DataType m_sData[MAX_STATIC_SIMPLE_BUFFER_SIZE];
	DWORD   m_dwDataLen;
	const DWORD m_dwMaxDataSize;		
};

        从实现的代码看,静态缓冲区就是在内存中事先分配好一段空间,这种分配一般是在栈中进行,分配速度特别快,但是不灵活,不能按照用户的大小需求分配空间。

3.动态缓冲区

        动态缓冲区类通常基于动态内存分配(如newdelete)来满足用户的需求。静态缓冲区的大小在编译时确定,而动态缓冲区的大小则根据需要动态变化。静态缓冲区适用于那些大小已知且不会改变的场景,而动态缓冲区则更灵活,适用于大小可能变化的场景。动态缓冲区类CDynamicSimpleDataBufferT实现代码如下:

//CSimpleDataBufferBase的默认适配器
template <class T>
class  CSimpleDataBufferAdapter : public CSimpleDataBufferBase<T>
{
public:
	CSimpleDataBufferAdapter() : m_pData(NULL),m_dwDataLen(0) { }
	virtual ~CSimpleDataBufferAdapter() { }

public:
	DWORD GetSize() const { return m_dwDataLen; }
	BOOL  SetData(ConstDataTypePointer pData, DWORD dwSize) {  assert(0); return FALSE; }
	void  SetSize(DWORD dwSize) { m_dwDataLen = dwSize; }
	DWORD GetMaxSize() const {  assert(0); return 0; }
	void  Clear() {  assert(0); }
	DataTypePointer GetData() { return m_pData ;}
	ConstDataTypePointer GetData() const { return m_pData ;}
	
protected:
	DataTypePointer  m_pData;
	DWORD   m_dwDataLen;	
};

/动态缓冲区
template <class T>
class  CDynamicSimpleDataBufferT : public CSimpleDataBufferAdapter<T>
{
public:
	CDynamicSimpleDataBufferT(DWORD dwMaxSize = MAX_DYNAMIC_SIMPLE_BUFFER_SIZE);
	virtual ~CDynamicSimpleDataBufferT() { ClearData(); }

public:
	void  Clear() {  m_dwDataLen = 0; }
	DWORD GetMaxSize() const { return m_dwMaxDataSize; }
	BOOL  SetData(ConstDataTypePointer pData, DWORD dwSize);

protected:
	void  ClearData();

private:
	const DWORD m_dwMaxDataSize;
};

构造函数、析构函数、赋值函数实现如下:

//构造函数
template <class T>
CDynamicSimpleDataBufferT<T>::CDynamicSimpleDataBufferT(DWORD dwMaxSize)
: m_dwMaxDataSize(dwMaxSize)
{
	m_pData = new T[dwMaxSize];
	if (m_pData == NULL)
		throw std::	bad_alloc("new T Array Failed");
	m_dwDataLen = 0;
	
	assert(m_pData != NULL);
	assert(m_dwDataLen >= 0);
}

//清空数据函数
template <class T>
void  CDynamicSimpleDataBufferT<T>::ClearData()
{
	if (m_pData)
		delete []m_pData;

	m_pData = NULL;
	m_dwDataLen = 0;
}

//赋值函数
template <class T>
BOOL CDynamicSimpleDataBufferT<T>::SetData(ConstDataTypePointer pData, DWORD dwSize)
{
	int  i;

	if (dwSize > m_dwMaxDataSize)
		return FALSE;

	for (i = 0; i < (int)dwSize; i++)
		m_pData[i] = pData[i];
	m_dwDataLen = dwSize;

	return TRUE;
}

        析构函数自动调用了Clear函数,释放了内存,这样就不怕退出的时候出现内存泄漏。

4.数据引用类

        在前面讲解的静态缓冲区和动态缓冲区内部都需要开辟空间,而数据引用类不需要开辟空间;CRefSimpleDataBufferT的具体实现如下:

template <class T>
class  CRefSimpleDataBufferT : public CSimpleDataBufferAdapter<T>
{
public:
	CRefSimpleDataBufferT() { }
	CRefSimpleDataBufferT(ConstDataTypePointer pBuffer, DWORD dwSize);
	virtual ~CRefSimpleDataBufferT()  {  }

public:
	BOOL  SetData(ConstDataTypePointer pBuffer, DWORD dwSize);
	void  Clear();
};

template <class T>
CRefSimpleDataBufferT<T>::CRefSimpleDataBufferT(ConstDataTypePointer pBuffer, DWORD dwSize)
{
	m_pData = const_cast<DataTypePointer>(pBuffer);
	m_dwDataLen = dwSize;
}

template <class T>
void CRefSimpleDataBufferT<T>::Clear()
{
	if (m_pData)
		delete []m_pData;
	
	m_pData = NULL;
	m_dwDataLen = 0;
}

template <class T>
BOOL  CRefSimpleDataBufferT<T>::SetData(typename CRefSimpleDataBufferT<T>::ConstDataTypePointer pBuffer, DWORD dwSize)
{
	Clear();

	m_pData = const_cast<DataTypePointer>(pBuffer);
	m_dwDataLen = dwSize;

	return TRUE;
}

从实现的代码来看,如果引用的数据是动态分配的,就可以调用Clear函数释放内存,反之,则不需要调用。

5.自动数据引用类

自动数据引用类就是引用外部的动态分配的数据源,并自动释放这个数据源的内存。CAutoRefSimpleDataBufferT的实现代码如下:

//自动释放动态分配的数据引用类
template <class T>
class  CAutoRefSimpleDataBufferT : public CRefSimpleDataBufferT<T>
{	
public:
	CAutoRefSimpleDataBufferT() { }
	CAutoRefSimpleDataBufferT(ConstDataTypePointer pBuffer, DWORD dwSize);
	CAutoRefSimpleDataBufferT(ConstDataTypePointer pBuffer);
	void  Clear();
	DataTypePointer   operator->() { return GetData(); }
	ConstDataTypePointer   operator->() const  { return GetData(); }
	virtual ~CAutoRefSimpleDataBufferT();
};

template <class T>
CAutoRefSimpleDataBufferT<T>::CAutoRefSimpleDataBufferT(typename CAutoRefSimpleDataBufferT<T>::ConstDataTypePointer pBuffer, DWORD dwSize)
: CRefSimpleDataBufferT<T>(pBuffer, dwSize)
{
}

template <class T>
CAutoRefSimpleDataBufferT<T>::CAutoRefSimpleDataBufferT(typename CAutoRefSimpleDataBufferT<T>::ConstDataTypePointer pBuffer)
: CRefSimpleDataBufferT<T>(pBuffer, 1)
{
}

template <class T>
void CAutoRefSimpleDataBufferT<T>::Clear()
{
	if (1 == m_dwDataLen)
		delete m_pData;
	else
		CRefSimpleDataBufferT<T>::Clear();
}

template <class T>
CAutoRefSimpleDataBufferT<T>::~CAutoRefSimpleDataBufferT()
{
	Clear();
}

CAutoRefSimpleDataBufferT和CRefSimpleDataBufferT的不同点就在于析构函数自动调用了Clear函数,释放了数据源的内存。

6.几种缓冲区的类关系图

7.注意事项

1)静态成员变量的初始化:静态成员变量需要在类外进行初始化,并且只能初始化一次。

2)线程安全:如果多个线程可能同时访问这个静态缓冲区,你需要实现适当的同步机制来避免数据竞争和不一致。

3)资源管理:静态缓冲区在程序结束时自动销毁,但如果你在其中存储了动态分配的资源(如指针指向的堆内存),你需要确保在程序结束前正确释放这些资源。

4)性能考虑:静态缓冲区大小固定,如果缓冲区大小设置不当,可能会导致频繁的内存溢出或内存浪费。

5)并发访问:在并发环境中,如果多个线程可能同时写入或读取缓冲区,需要考虑使用互斥锁(如std::mutex)来同步访问。

8.完整代码

Noncopyable.h

/*************************************************************************

// 功能: 防止拷贝类

// 备注: 

*************************************************************************/
#pragma once

class  CNoncopyable
{
public:
	CNoncopyable() {}
	~CNoncopyable() {}

protected:
	CNoncopyable(const CNoncopyable& src);  //拷贝构造函数
	const CNoncopyable& operator=(const CNoncopyable& src); //赋值函数
};

SimpleDataBuffer.h

#pragma once
#include "Noncopyable.h"
#include <assert.h>
#include <new>
#include <stdexcept>
using namespace std;

#define  MAX_STATIC_SIMPLE_BUFFER_SIZE  	  (4*1024)  //4K
#define  MAX_DYNAMIC_SIMPLE_BUFFER_SIZE       (800*1024) //800K

template <class T>
class CSimpleDataBufferBase : public CNoncopyable
{
public:
	typedef T  DataType;
	typedef T* DataTypePointer;
	typedef T& DataTypeReference;
	typedef const T ConstDataType;
	typedef const T* ConstDataTypePointer;
	typedef const T& ConstDataTypeReference;
	
public:
	CSimpleDataBufferBase() {}
	virtual ~CSimpleDataBufferBase() {}

public:
	virtual  DWORD GetSize() const = 0;
	virtual  DataTypePointer GetData() = 0;
	virtual  ConstDataTypePointer GetData() const = 0;
	virtual  DWORD GetMaxSize() const = 0;
	operator DataTypePointer() {  return GetData(); } 
	DataTypeReference operator*() { return *GetData(); }
	DataTypeReference operator[](int nIndex);
	virtual  BOOL  SetData(ConstDataTypePointer pData, DWORD dwSize) = 0;
	virtual  void  SetSize(DWORD dwSize) = 0;
	virtual  void  Clear() = 0;
};

template <class T>
typename CSimpleDataBufferBase<T>::DataTypeReference CSimpleDataBufferBase<T>::operator[](int nIndex)
{
	if ( (nIndex >= 0) && (nIndex < (int)GetSize()))
	{
		DataTypePointer pData = GetData();
		return pData[nIndex];
	}
	else
	{
		throw std::out_of_range("invalid data<nIndex> position");
	}	
}

//数据静态分配
template <class T>
class CStaticSimpleDataBufferT : public CSimpleDataBufferBase<T>
{
public:
	CStaticSimpleDataBufferT(DWORD dwMaxSize = MAX_STATIC_SIMPLE_BUFFER_SIZE);
	virtual ~CStaticSimpleDataBufferT() {  }

public:
	DWORD GetSize() const { return m_dwDataLen; }
	DataTypePointer GetData() { return m_sData ;}
	ConstDataTypePointer GetData() const { return m_sData ;}
	BOOL  SetData(ConstDataTypePointer pData, DWORD dwSize);
	void  SetSize(DWORD dwSize) { m_dwDataLen = dwSize; }
	DWORD GetMaxSize() const {  return m_dwMaxDataSize; }
	void  Clear() { m_dwDataLen = 0; }

private:
	DataType m_sData[MAX_STATIC_SIMPLE_BUFFER_SIZE];
	DWORD   m_dwDataLen;
	const DWORD m_dwMaxDataSize;		
};

template <class T>
CStaticSimpleDataBufferT<T>::CStaticSimpleDataBufferT(DWORD dwMaxSize)
:  m_dwDataLen(0),
   m_dwMaxDataSize(dwMaxSize)
{
}

template <class T>
BOOL  CStaticSimpleDataBufferT<T>::SetData(ConstDataTypePointer pData, DWORD dwSize)
{
	int  i;
	if (dwSize > m_dwMaxDataSize)
		return FALSE;

	for (i = 0; i < (int)dwSize; i++)
		m_sData[i] = pData[i];
	m_dwDataLen = dwSize;
	
	return TRUE;
}
///
template <class T>
class  CSimpleDataBufferAdapter : public CSimpleDataBufferBase<T>
{
public:
	CSimpleDataBufferAdapter() : m_pData(NULL),m_dwDataLen(0) { }
	virtual ~CSimpleDataBufferAdapter() { }

public:
	DWORD GetSize() const { return m_dwDataLen; }
	BOOL  SetData(ConstDataTypePointer pData, DWORD dwSize) {  assert(0); return FALSE; }
	void  SetSize(DWORD dwSize) { m_dwDataLen = dwSize; }
	DWORD GetMaxSize() const {  assert(0); return 0; }
	void  Clear() {  assert(0); }
	DataTypePointer GetData() { return m_pData ;}
	ConstDataTypePointer GetData() const { return m_pData ;}
	
protected:
	DataTypePointer  m_pData;
	DWORD   m_dwDataLen;	
};

/
template <class T>
class  CDynamicSimpleDataBufferT : public CSimpleDataBufferAdapter<T>
{
public:
	CDynamicSimpleDataBufferT(DWORD dwMaxSize = MAX_DYNAMIC_SIMPLE_BUFFER_SIZE);
	virtual ~CDynamicSimpleDataBufferT() { ClearData(); }

public:
	void  Clear() {  m_dwDataLen = 0; }
	DWORD GetMaxSize() const { return m_dwMaxDataSize; }
	BOOL  SetData(ConstDataTypePointer pData, DWORD dwSize);

protected:
	void  ClearData();

private:
	const DWORD m_dwMaxDataSize;
};

template <class T>
CDynamicSimpleDataBufferT<T>::CDynamicSimpleDataBufferT(DWORD dwMaxSize)
: m_dwMaxDataSize(dwMaxSize)
{
	m_pData = new T[dwMaxSize];
	if (m_pData == NULL)
		throw std::	bad_alloc("new T Array Failed");
	m_dwDataLen = 0;
	
	assert(m_pData != NULL);
	assert(m_dwDataLen >= 0);
}

template <class T>
void  CDynamicSimpleDataBufferT<T>::ClearData()
{
	if (m_pData)
		delete []m_pData;

	m_pData = NULL;
	m_dwDataLen = 0;
}

template <class T>
BOOL CDynamicSimpleDataBufferT<T>::SetData(ConstDataTypePointer pData, DWORD dwSize)
{
	int  i;

	if (dwSize > m_dwMaxDataSize)
		return FALSE;

	for (i = 0; i < (int)dwSize; i++)
		m_pData[i] = pData[i];
	m_dwDataLen = dwSize;

	return TRUE;
}
//
template <class T>
class  CRefSimpleDataBufferT : public CSimpleDataBufferAdapter<T>
{
public:
	CRefSimpleDataBufferT() { }
	CRefSimpleDataBufferT(ConstDataTypePointer pBuffer, DWORD dwSize);
	virtual ~CRefSimpleDataBufferT()  {  }

public:
	BOOL  SetData(ConstDataTypePointer pBuffer, DWORD dwSize);
	void  Clear();
};

template <class T>
CRefSimpleDataBufferT<T>::CRefSimpleDataBufferT(ConstDataTypePointer pBuffer, DWORD dwSize)
{
	m_pData = const_cast<DataTypePointer>(pBuffer);
	m_dwDataLen = dwSize;
}

template <class T>
void CRefSimpleDataBufferT<T>::Clear()
{
	if (m_pData)
		delete []m_pData;
	
	m_pData = NULL;
	m_dwDataLen = 0;
}

template <class T>
BOOL  CRefSimpleDataBufferT<T>::SetData(typename CRefSimpleDataBufferT<T>::ConstDataTypePointer pBuffer, DWORD dwSize)
{
	Clear();

	m_pData = const_cast<DataTypePointer>(pBuffer);
	m_dwDataLen = dwSize;

	return TRUE;
}

//自动释放动态分配的数据引用类
template <class T>
class  CAutoRefSimpleDataBufferT : public CRefSimpleDataBufferT<T>
{	
public:
	CAutoRefSimpleDataBufferT() { }
	CAutoRefSimpleDataBufferT(ConstDataTypePointer pBuffer, DWORD dwSize);
	CAutoRefSimpleDataBufferT(ConstDataTypePointer pBuffer);
	void  Clear();
	DataTypePointer   operator->() { return GetData(); }
	ConstDataTypePointer   operator->() const  { return GetData(); }
	virtual ~CAutoRefSimpleDataBufferT();
};

template <class T>
CAutoRefSimpleDataBufferT<T>::CAutoRefSimpleDataBufferT(typename CAutoRefSimpleDataBufferT<T>::ConstDataTypePointer pBuffer, DWORD dwSize)
: CRefSimpleDataBufferT<T>(pBuffer, dwSize)
{
}

template <class T>
CAutoRefSimpleDataBufferT<T>::CAutoRefSimpleDataBufferT(typename CAutoRefSimpleDataBufferT<T>::ConstDataTypePointer pBuffer)
: CRefSimpleDataBufferT<T>(pBuffer, 1)
{
}

template <class T>
void CAutoRefSimpleDataBufferT<T>::Clear()
{
	if (1 == m_dwDataLen)
		delete m_pData;
	else
		CRefSimpleDataBufferT<T>::Clear();
}

template <class T>
CAutoRefSimpleDataBufferT<T>::~CAutoRefSimpleDataBufferT()
{
	Clear();
}

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

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

相关文章

【机器学习案列】基于随机森林和xgboost的二手车价格回归预测

一、项目分析 1.1 项目任务 kaggle二手车价格回归预测项目&#xff0c;目的根据各种属性预测二手车的价格。 1.2 评估准则 评估的标准是均方根误差&#xff1a; 1.3 数据介绍 数据连接https://www.kaggle.com/competitions/playground-series-s4e9/data?selecttrain.csv 其…

基于 Java Swing 实现的超级玛丽游戏

一、项目概述 > 这是一个基于 Java Swing 的游戏项目&#xff0c;旨在实现一个支持自定义地图的超级玛丽游戏。 > 游戏画面精美&#xff0c;包含多种功能和亮点&#xff0c;如地图编辑器、不同状态的马里奥、多种怪物和道具等。 二、项目演示 > 地图编辑器 > …

Mac写入U盘文件如何跨平台使用 Mac电脑怎么把U盘文件传送到电脑 mac怎么用u盘拷贝文件

不知道你在使用Mac电脑拷贝文件的时候有没有遇到过无法写入U盘的问题&#xff0c;这通常是由于Mac和Windows之间的兼容问题引起的。下面我将为大家详细介绍Mac写入U盘文件如何跨平台使用以及Mac如何将U盘文件复制到电脑。 一、Mac写入U盘文件如何跨平台使用 在Mac电脑上将文件…

MySQL第11讲--多表查询的介绍

文章目录 前言多表关系多表查询概述多表查询的分类连接查询内链接外链接自连接 联合查询子查询标量子查询列子查询行子查询表子查询 前言 在MySQL第10讲–约束的介绍中讲了数据库的几种约束条件&#xff1a;非空约束、唯一约束、主键约束、外键约束、检查约束、默认约束。下图对…

数字人实战第六天——DH_live 训练自己的数字人

一、简介 数字人是一种基于人工智能和数字化技术构建的虚拟人物或代理&#xff0c;能够进行人类式的交互和沟通。这些技术主要包括&#xff1a; 人工智能&#xff08;AI&#xff09;&#xff1a;AI 是数字人的核心&#xff0c;包括自然语言处理&#xff08;NLP&#xff09;、机…

[深度学习]循环神经网络

1 自然语言处理概述 语料:一个样本,句子/文章语料库:由语料组成词表:分词之后的词语去重保存成为词表2 词嵌入层 import jieba import torch.nn as nn import torch # 文本数据 text=北京东奥的进度条已经过半,不少外国运动员在完成自己的比赛后踏上归途。 # 分词 words=j…

11.梯度下降法的思想——举足轻重的模型优化算法

引言 优化算法在机器学习和人工智能中扮演者至关重要的角色。机器学习模型的训练过程本质上是一个优化问题&#xff0c;即通过调整模型参数来最小化损失函数。梯度下降法(Gradient Descent)在优化算法中占据着重要的地位&#xff0c;因其简单、有效且易于实现。 通过阅读本篇…

阿里云服务器挖矿木马清除

这里写自定义目录标题 阿里云服务器挖矿木马清除清除步骤&#xff1a; 阿里云服务器挖矿木马清除 直接看图&#xff1a; 清除步骤&#xff1a; 是的&#xff0c;根据您提供的 systemctl 输出&#xff0c;c3pool_miner.service 看起来非常可疑&#xff0c;因为它的描述是 “…

langchain v0.3更新了什么?

版本改动 这是具体改动的链接 官方blog首先说明了&#xff1a; 所有软件包已在内部从 Pydantic 1 升级到 Pydantic 2。 所有软件包都完全支持在用户代码中使用 Pydantic 2&#xff0c;而无需使用 langchain_core.pydantic_v1 或 pydantic.v1 等桥接程序。 由于 Pydantic 1 已…

Django 配置邮箱服务,实现发送信息到指定邮箱

一、这里以qq邮箱为例&#xff0c;打开qq邮箱的SMTP服务 二、django项目目录设置setting.py 文件 setting.py 添加如下内容&#xff1a; # 发送邮件相关配置 EMAIL_BACKEND django.core.mail.backends.smtp.EmailBackend EMAIL_USE_TLS True EMAIL_HOST smtp.qq.com EMAIL…

18724 二叉树的遍历运算

### 思路 1. **递归构建树**&#xff1a; - 先序遍历的第一个节点是根节点。 - 在中序遍历中找到根节点的位置&#xff0c;左边部分是左子树&#xff0c;右边部分是右子树。 - 递归构建左子树和右子树。 2. **递归生成后序遍历**&#xff1a; - 递归生成左子树的…

《Python编程:从入门到实践》数据可视化

一、项目 数据可视化学习 二、库依赖 matplotlib&#xff0c;pygal&#xff0c; 三、生成数据 1.绘制简单的折线图 import matplotlib.pyplot as pltsquares [1, 4, 9, 16, 25] plt.plot(squares) plt.show() 模块pyplot包含很多用于生成图表的函数。 &#xff08;1&am…

Excel求和为什么是0?结果不对的来跟着步骤排查

大家好&#xff0c;这里是效率办公指南&#xff01; &#x1f522; Excel求和功能是日常工作中常用的工具&#xff0c;但有时我们可能会遇到求和结果意外地显示为0&#xff0c;这可能会让我们感到困惑。今天&#xff0c;我们就来具体分析一下可能导致Excel求和结果为0的原因&a…

100套顶刊配色方案!Matlab超绝配色包TheBestColor

两三年前&#xff0c;我刚开始研究制作Matlab配色包&#xff0c;那时Matlab几乎只能用自带的默认配色&#xff0c;选择极少。 时至今日&#xff0c;Matlab配色已不是问题。 实际体验下来&#xff0c;在某些层面&#xff0c;甚至比隔壁R、Python吃得还要好一些。 但吃得太好&…

TARA分析方法论——威胁分析和风险评估方法

一、什么是TARA分析方法论 威胁分析和风险评估&#xff08;Threat Analysis and Risk Assessment&#xff09; 通过识别整车/项目的网络安全资产&#xff0c;分析其中的潜在的安全威胁&#xff0c;综合考虑威胁攻击可行性、危害影响等因素&#xff0c;识别出整车/项目可能存在…

【技巧】移动云手机如何防止1小时自动关机

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 背景介绍 领的免费云手机&#xff0c;如果1或2小时内不登录&#xff0c;就会被自动关机&#xff0c;这非常影响使用。本方法可以实现自动刷新页面&…

西门子:觅最佳的生态伙伴,筑最好的数字平台|商业创新同行者

沧海桑田&#xff0c;时光变幻。 纵观全球&#xff0c;历经百年仍能保持基业长青的公司少之又少&#xff0c;而像西门子这样依旧矗立在顶峰的企业可谓凤毛麟角&#xff0c;成功的数字化转型更是为这家企业带来了持续不断的澎湃活力。 作为当代数字化时代的创新经济模式&#…

智能手机取证: 专家如何从被锁定设备中提取数据?

在数字取证领域&#xff0c;从被锁定的手机中检索数据的能力是决定调查成功与否的关键技能。由于智能手机往往是解决复杂案件的关键&#xff0c;智能手机取证已经成为打击犯罪和恐怖主义战争中的一个关键组成部分。通话记录、短信、电子邮件&#xff0c;甚至位置数据都可能被发…

【机器学习(十一)】机器学习分类案例之是否患糖尿病预测—XGBoost分类算法—Sentosa_DSML社区版

文章目录 一、XGBoost算法二、Python代码和Sentosa_DSML社区版算法实现对比(一) 数据读入和统计分析(二)数据预处理(三)模型训练与评估(四)模型可视化 三、总结 一、XGBoost算法 关于集成学习中的XGBoost算法原理&#xff0c;已经进行了介绍与总结&#xff0c;相关内容可参考【…

代理IP获取工具:轻松获取可靠的代理IP

在网络世界中&#xff0c;代理IP是一个非常有用的工具。无论是为了提升隐私保护&#xff0c;还是为了访问特定的网络资源&#xff0c;代理IP都能提供极大的帮助。本文将介绍几种常见的代理IP获取工具&#xff0c;帮助你轻松获取可靠的代理IP。 什么是代理IP获取工具&#xff1…