c/c++开发,无可避免的模板编程实践(篇六)

news2024/9/22 21:26:39

一、泛型算法

        1.1 泛型算法概述

        c++标准库不仅包含数据结构(容器、容器适配器等),还有很多算法。数据结构可以帮助存放特定情况下需要保存的数据,而算法则会将数据结构中存储的数据进行变换。标准库没有给容器添加大量的功能函数,而是选择提供一组算法,这些算法大都不依赖特定的容器类型,是通过泛型编程(模板)实现的,可作用在不同类型的容器和不同类型的元素上。

        为了快速了解泛型算法,来看下面一个简要案例,第三参数0是累加初始化值:

    vector<int> v{100, 400, 200, 300, 200, 500, 100, 400, 600, 300 };
    int sum = 0;
    for (auto &&i : v)
    {
        sum += i;
    }
    cout << "sum = " << sum << endl;                            //sum = 3100
    //调用泛型算法计算    
    cout << "sum = " << accumulate(begin(v), end(v), 0) << endl;//sum = 3100,第三参数0是累加初始化值

        两者都能得到同样的结果,例子中循环变量也不是很长,不过其可读性比 accumulate 差很多。标准库泛型算法的思想就是提供丰富的算法(通用为主)供开发者使用,避免耗费大量的时间在重复制造轮子上面。

        一方面就是,即便开发者会自己去实现相应标准库中的算法,也要进行大量的测试来确保自己实现的算法是否正确,标准库提供的算法都是经过了严格的测试。所以没有必要做重复的工作,这样也能节省代码审阅者的时间,否则他们还要确定算法实现中是否有Bug。
        另一方面是STL算法非常的高效。很多标准库算法提供了多种特化实现,这样足以应对依赖迭代器类型的使用方式。例如,将 vector 中的所有元素都填充0时,就可以使用 std::fill 。因为 vector 使用的是一段连续的内存,对于这种使用连续内存存放数据的结构都可以使用 std::fill 进行填充,这个函数类似于C中的 memset 函数。

        标准容器定义了很少的操作。大部分容器主要是支持到元素增删、访问、遍历,获取容器大小等功能。用户若希望对容器元素进行更多其他有用的操作:例如给顺序容器排序,或者查找某个特定的元素,或者查找最大或最小的元素,等等。标准库并没有为每种容器类型都定义实现这些操作的成员函数,而是定义了一组泛型算法:因为它们实现共同的操作,所以称之为“算法”;而“泛型”指的是通过模板支持,它们可以操作在多种容器类型上,即不但可作用于 vector 或 list 这些标准库类型,还可用在内置数组类型、甚至其他类型的序列上。

        1.2 泛型算法应用示例

        例如,针对排序,标准库提供了 sort算法,为需要排序的各个容器提供服务,对于list 这种不支持到sort泛型算法的,还提供了功能函数sort来实现。而对于关联容器,本身是已排序的。下面针对sort算法在相关容器的一些应用,看看都是如何达成排序目的的。

//创建一个大数组vector
	vector<int> v_sort;
	const int v_size = 10000;    //数组大小
	const int read_size = 20;    //输出数量
	for(int i=0; i<v_size;i++)
	{
		v_sort.push_back(rand()%v_size);    //随机赋值
	}
	//构造一个新的vertor,为了公平测试后面容器,调用sort算法排序vector
	vector<int> v_sort_new(v_sort.begin(),v_sort.end());
	cout << "clock()1 = " << clock() <<endl;
	sort(v_sort_new.begin(),v_sort_new.end());
	cout << "clock()2 = " << clock() <<endl;
	//输出已排序的vector前一段数据
	for(int i=0; i<read_size;i++)
	{
		cout << v_sort_new[i] << " ";
	}
	cout << "\n";
	//将vector拷贝构造list,调用list的sort函数排序
	list<int> l_sort(v_sort.begin(),v_sort.end());
	cout << "clock()3 = " << clock() <<endl;
	l_sort.sort();
	cout << "clock()4 = " << clock() <<endl;
	//输出已排序的list前一段数据
	list<int>::iterator it_list=l_sort.begin();
	for (int i=0; i<read_size;i++)
	{
		/* code */
		cout << *(it_list++) << " ";
	}
	cout << "\n";
	//将vector拷贝构造multiset,multiset在构造时就自动排序
	cout << "clock()5 = " << clock() <<endl;
	multiset<int> set_sort(v_sort.begin(),v_sort.end());
	cout << "clock()6 = " << clock() <<endl;
	//输出已排序的multiset前一段数据
	multiset<int>::iterator it_mset = set_sort.begin();
	for (int i=0; i<read_size;i++)
	{
		/* code */
		cout << *(it_mset++) << " ";
	}
	cout << "\n";
	//将multiset拷贝回vector,multiset在构造时就自动排序,vector同样得到已排序结构
	cout << "clock()7 = " << clock() <<endl;
	v_sort.clear();
	v_sort.assign(set_sort.begin(),set_sort.end());
	cout << "clock()8 = " << clock() <<endl;
	//重新输出已排序的vector前一段数据
	for(int i=0; i<read_size;i++)
	{
		cout << v_sort[i] << " ";
	}
	cout << "\n";
//out log
clock()1 = 3
clock()2 = 10
0 0 2 3 3 3 4 4 6 8 8 9 12 12 12 12 14 16 16 17
clock()3 = 19
clock()4 = 34
0 0 2 3 3 3 4 4 6 8 8 9 12 12 12 12 14 16 16 17
clock()5 = 38
clock()6 = 53
0 0 2 3 3 3 4 4 6 8 8 9 12 12 12 12 14 16 16 17
clock()7 = 62
clock()8 = 65
0 0 2 3 3 3 4 4 6 8 8 9 12 12 12 12 14 16 16 17

        上述这段代码,构建了一个大随机数组,然后将数据复制构造到vector、list、mulset看看其排序功能及排序耗时,由于mulset插入数据就已排序,把数据重新拷贝会vector,也能同样获得已排序结构。

        而is_sorted 函数会告诉我们,容器内部的值是否已经经过排序:

//创建一个大数组vector
	vector<int> v_sort;
	const int v_size = 10000;
	const int read_size = 20;
	for(int i=0; i<v_size;i++)
	{
		v_sort.push_back(rand()%v_size);
	}
	cout << "v_sort is_sorted = "<< is_sorted(v_sort.begin(), v_sort.end()) << endl;
    ...见前代码...
    cout << "clock()7 = " << clock() <<endl;
	v_sort.clear();
	v_sort.assign(set_sort.begin(),set_sort.end());
	cout << "clock()8 = " << clock() <<endl;
	...见前代码...
	cout << "v_sort is_sorted = "<< is_sorted(v_sort.begin(), v_sort.end()) << endl;
//out log
v_sort is_sorted = 0
...省略...
clock()7 = 49
clock()8 = 51
0 0 2 3 3 3 4 4 6 8 8 9 12 12 12 12 14 16 16 17
v_sort is_sorted = 1

        shuffle 将打乱 vector 中的内容,前两个参数是容器的首尾迭代器,第三个参数是一个随机数生成器:

random_device rd;
mt19937 g {rd()};
//
	shuffle(v_sort.begin(),v_sort.end(),g);    //g是随机数生成器
	cout << "v_sort is_sorted = "<< is_sorted(v_sort.begin(), v_sort.end()) << endl; //=0

        有时候,并不需要对列表完全进行排序,只需要比它前面的某些值小就可以。所以,让使用 partition 将数值小于20的元素放到前面:

//
	partition(v_sort.begin(),v_sort.end(), [] (int i) { return i < 20; });
	//重新输出已排序的vector前一段数据
	for(int i=0; i<read_size;i++)
	{
		cout << v_sort[i] << " ";
	}
	cout << "\n";
//out log
0 17 16 16 4 12 0 2 9 14 6 12 3 3 3 4 8 8 12 12

        或者只想对部分元素排序,可以调用partial_sort 。这个函数对容器的内容在某种程度上的排序。其会将 vector 中最小的N个数,放在容器的前半部分。其余的留在 vector 的后半部分,不进行排序:

//
	shuffle(v_sort.begin(),v_sort.end(),g);
	auto middle (next(begin(v_sort), 100));//[0,100)
	partial_sort(begin(v_sort), middle, end(v_sort));//将小的数放置前面,并排序
	//重新输出已排序的vector前一段数据
	for(int i=0; i<read_size;i++)
	{
		cout << v_sort[i] << " ";
	}
	cout << "\n";
//out log
0 0 2 3 3 3 4 4 6 8 8 9 12 12 12 12 14 16 16 17

        sort 函数还支持使用者将自行定义的比较函数作为第三个参数进行传入,按实际场景意愿排序,例如上述vector降序排序。

bool compare(int a,int b){ return a>b;};    //降序排序
//
	shuffle(v_sort.begin(),v_sort.end(),g);
	sort(v_sort.begin(),v_sort.end(),compare);
	//重新输出已排序的vector前一段数据
	for(int i=0; i<read_size;i++)
	{
		cout << v_sort[i] << " ";
	}
	cout << "\n";
//out log
9997 9996 9995 9994 9993 9991 9990 9989 9988 9986 9984 9984 9984 9984 9983 9982 9982 9981 9981 9981

        1.3 泛型算法与容器

        可以看出,标准库提供的泛型算法一般与容器的类型无关,不依赖于容器类型。但会隐式地依赖元素类型(算法函数的模板参数类型):必须能够对元素做比较等运算。然后,泛型算法用迭代器来实现算法与容器的绑定,例如sort(begin(v),end(v)),通过遍历容器及排序。所有迭代器都支持自增操作符,从一个元素定位下一个元素,并提供解引用操作符访问元素的值,迭代器还支持相等和不等操作符,用于判断两个迭代是否相等。

        大多数情况下,每个算法都需要使用(至少)两个迭代器指出该算法操纵的元素范围。第一个迭代器指向第一个元素,而第二个迭代器则指向最后一个元素的下一位置。第二个迭代器所指向的元素[有时被称为超出末端迭代器]本身不是要操作的元素,而被用作终止遍历的哨兵(sentinel)。
        使用超出末端迭代器还可以很方便地处理第四个要求,只要以此迭代器为返回值,即可表示没有找到要查找的元素。如果要查找的值未找到,则返回超出末端迭代器;否则,返回的迭代器指向匹配的元素。
        第三个要求——元素值的比较,有两种解决方法。默认情况下,sort操作要元素类型定义了比较<、>等操作符,算法使用这个操作符比较元素。如果元素类型不支持这些操作符,或者打算用不同的测试方法来比较元素,则可使用一个额外的参数:实现元素比较的函数名字。

        使用泛型算法必须包含 algorithm 头文件:

        #include <algorithm>,

        标准库还定义了一组泛化的算术算法(generalized numeric algorithm),其命名习惯与泛型算法相同。使用这些算法则必须包含 numeric 头文件:

        #include <numeric>,

        除了少数例外情况,所有算法都在一段范围内的元素上操作,我们将这段范围称为“输出范围(input range)”。带有输入范围参数的算法总是使用头两个形参标记该范围。

        算法对算法对输入范围的操作是类似的,但在该范围内如何操纵元素却有所不同:有些操作只读取数据(accumulat、find...),有些操作会修改数据(replace、fill...),有些操作会移动数据(sort、stable_sort 、move...)。

        标准库算法与容器关系要点:
        1)泛型算法本身从不执行容器操作,只是单独依赖迭代器和迭代器操作实现,因而其实现与容器类型无关。实际的容器类型未知(甚至所处理的元素是否存储在容器中也是未知的)。

//算法与容器类型无关
vector<int>::const_iterator result_vec = find(v_sort.begin(),v_sort.end(),99);//vector查找
list<int>::const_iterator result_list = find(l_sort.begin(),l_sort.end(),99);  //list查找
multiset<int>::iterator result_mset = find(set_sort.begin(),set_sort.end(),99);//multiset 查找
int vg[12] = {71,73,29,34,40,23,84,99,21,78,18,58};
int *result_vg = find(vg,vg+12,99);	//数组查找

        这个事实也许比较意外,但本质上暗示了:使用“普通”的迭代器时,算法从不修改基础容器的大小。正如我们所看到的,算法也许会改变存储在容器中的元素的值,也许会在容器内移动元素,但是,算法从不直接添加或删除元素。

//算法修改容器值
fill(v_sort.begin(),v_sort.begin()+2, 0);	//前两个值设为0
fill(vg,vg+2, 0);							//前两个值设为0
//算法会移动容器内的数据位置
sort(vg,vg+12,compare);

        2)泛型算法都是在标记容器(或其他序列)内的元素范围的迭代器上操作的。标记范围的两个实参类型必须精确匹配,而迭代器本身必须标记一个范围:它们必须指向同一个容器中的元素(或者超出容器末端的下一位置),并且如果两者不相等,则第一个迭代器通过不断地自增,必须可以到达第二个迭代器。

fill(vg,vg+2, 0);							//前两个值设为0
fill(vg,vg+10, 10);							//前10个值设为10
fill(vg,vg+sizeof(vg), 10);					//前每个值设为10

        3)标准库为所有泛型和算术算法的每一个迭代器形参指定了范围最小的迭代器种类(迭代器分类见下一小节)。

        例如,find(以只读方式单步遍历容器)至少需要一个输入迭代器。replace 函数至少需要一对前向迭代器。replace_copy 函数的头两个迭代器必须至少是前向迭代器,第三个参数代表输出目标,必须至少是输出迭代器。对于每一个形参,迭代器必须保证最低功能。将支持更少功能的迭代器传递给函数是错误的;而传递更强功能的迭代器则没问题。向算法传递无效的迭代器类别所引起的错误,无法保证会在编译时被捕获到。

        1.4 泛型算法与迭代器

        可以看出,标准库的算法是通过迭代器间接来操作容器的,迭代器作为算法与容器之间的桥梁。标准库除了提供平时使用最多的迭代器-iterator迭代器,标准库还提供了其他特殊用途的迭代器:

  • 插入迭代器(inserter、back_inserter 、front_inserter):这类迭代器与容器绑定在一起,实现在容器中插入元素的功能。

        • back_inserter,创建使用 push_back 实现插入的迭代器。
        • front_inserter,使用 push_front 实现插入。
        • inserter,使用 insert 实现插入操作。除了所关联的容器外,inserter还带有第二实参:指向插入起始位置的迭代器。

//
list<int> ilst, ilst2, ilst3, ilst4; // empty lists
for (list<int>::size_type i = 0; i != 4; ++i){ ilst.push_front(i);	}
copy (ilst.begin(), ilst.end(), front_inserter(ilst2));	// after copy ilst2 contains: 0 1 2 3
copy (ilst.begin(), ilst.end(), back_inserter(ilst3));	// after copy, ilst3 contains: 3 2 1 0
copy (ilst.begin(), ilst.end(),	inserter (ilst4, ilst4.begin()));// after copy, ilst4 contains: 3 2 1 0
  •  流迭代器(istream_iterator、 ostream_iterator):这类迭代器可与输入或输出流绑定在一起,用于迭代遍历所关联的 IO 流。

        •istream_iterator 用于读取输入流

        •ostream_iterator 则用于写输出流

istream_iterator<T> in(strm);//创建从输入流 strm 中读取 T 类型对象的istream_iterator 对象

istream_iterator<T> in; //istream_iterator 对象的超出末端迭代器

ostream_iterator<T> in(strm);//创建将 T 类型的对象写到输出流 strm 的ostream_iterator 对象

ostream_iterator<T> in(strm, delim);//创建将 T 类型的对象写到输出流 strm 的ostream_iterator 对象,在写入过程中使用 delim作为元素的分隔符。delim 是以空字符结束的字符数组

        流迭代器除了最基本的迭代器操作:自增、解引用和赋值外,还提供了可比较两个 istream 迭代器是否相等(或不等)的操作,而 ostream 迭代器则不提供比较运算 。

        流迭代器都是类模板:任何已定义输入操作符(>> 操作符)的类型都可以定义 istream_iterator。类似地,任何已定义输出操作符(<< 操作符)的类型也可定义 ostream_iterator。

#include <iterator>
#include <fstream>
//从输入流cin读取数据,并将读取内容刷新到cout屏幕输出和文件中,输入quit标识退出命名行输入读取
//
istream_iterator<string> cin_it(cin),eof; // reads int from cin,
ofstream outfile("test.txt");
ostream_iterator<string> outputf(outfile, " ");// writes string from the ofstream named outfile
ostream_iterator<string> output(cout, "\n");
string end_str = "quit";
while (cin_it != eof)
{
    if(0==strcmp((*cin_it).c_str(),end_str.c_str()))
	{
		break;
	}
    *outputf++ = *cin_it;
	*output++=*cin_it++;
	flush(cout);
}
flush(outfile);
  • reverse_iterator (反向迭代器):这类迭代器实现向后遍历,而不是向前遍历。所有容器类型都定义了自己的 reverse_iterator 类型,由 rbegin 和 rend 成员函数返回。

        反向迭代器是一种反向遍历容器的迭代器。也就是,从最后一个元素到第一个元素遍历容器。反向迭代器将自增(和自减)的含义反过来了:对于反向迭代器,++ 运算将访问前一个元素,而 -- 运算则访问下一个元素。

//
	cout << "ilst.size() = " << ilst.size() << endl;
	list<int>::reverse_iterator it_rvec = ilst.rbegin();
	for (size_t i = 0; i < ilst.size(); i++)
	{
		cout << *it_rvec << " ";
		/* code */
		it_rvec++;
	}
	cout << "\n";
    it_rvec = ilst.rend();
	it_rvec--;
	for (size_t i = 0; i < ilst.size(); i++)
	{
		cout << *it_rvec << " ";
		/* code */
		it_rvec--;
	}
	cout << "\n";
  • const_iterator(常量迭代器):相当于常量指针,迭代器指向内容无法修改。
//
	list<int>::const_iterator it_const = ilst.begin();
	it_const++;         //OK
	//*it_const = 10;	//error
    list<int>::iterator it_val= ilst.begin();
	*it_val = 10;       //OK

        对于迭代器,容器类在其定义时,会依据自身特点来明确其支持的迭代器类型;而对于泛型算法,根据算法要求它的迭代器提供什么类型的操作,对算法分类。因此迭代器是算法与容器沟通的桥梁。

        算法要求的迭代器操作分为五个类别:

Input iterator//(输入迭代器) 读,不能写;只支持自增运算
Output iterator//(输出迭代器) 写,不能读;只支持自增运算
Forward iterator//(前向迭代器) 读和写;只支持自增运算
Bidirectional iterator//(双向迭代器) 读和写;支持自增和自减运算
Random access iterator//(随机访问迭代器) 读和写;支持完整的迭代器算术运算

        例如,map、set 和 list 类型提供双向迭代器,而 string、vector 和 deque 容器上定义的迭代器都是随机访问迭代器,用作访问内置数组元素的指针也是随机访问迭代器。istream_iterator 是输入迭代器,而ostream_iterator 则是输出迭代器。

二 、标准库算法阐述

        1.1 算法形参结构

        大多数算法采用下面四种形式形参结构:

alg (beg, end, other parms);
alg (beg, end, dest, other parms);
alg (beg, end, beg2, other parms);
alg (beg, end, beg2, end2, other parms);

       其中,alg 是算法的名字,beg 和 end 指定算法操作的元素范围。通常将该范围称为算法的“输入范围”。尽管几乎所有算法都有输入范围,但算法是否使用其他形参取决于它所执行的操作。这里列出了比较常用的其他形参:dest、beg2 和 end2,它们都是迭代器。这些迭代器在使用时,充当类似的角色。除了这些迭代器形参之外,有些算法还带有其他的菲迭代器形参,它们是这些算法特有的。

  •  dest 形参是一个迭代器,用于指定存储输出数据的目标对象。算法假定无论需要写入多少个元素都是安全的。
  •  类似beg 和 end,beg2 和 end2 则标记第二个输入范围,是有些算法所需要的。
  • 很多算法通过检查其输入范围内的元素实现其功能。这些算法通常要用到标准关系操作符:== 或 <。其中的大部分算法会提供第二个版本的函数parms,允许程序员提供比较或测试函数parms取代操作符的使用。
sort (beg, end);        //采用默认比较
sort (beg, end, comp);  //采用自定义的parms-comp函数来比较

        1.2 算法命名规范

        标准库使用一组相同的命名和重载规范来定义算法名称。

        1)很多算法通过检查其输入范围内的元素实现其功能。这些算法通常要用到标准关系操作符:== 或 <。其中的大部分算法会提供第二个版本的函数,允许程序员提供比较或测试函数取代操作符的使用。

sort(beg, end); 
stable_sort(beg, end); //保证排序后元素的原始顺序
sort(beg, end, comp);
//
find(beg, end, val); 
find_if(beg, end, pred); 

        2)实现复制的算法版本,标准库会在这些算法在名字中添加了_copy 后缀区分。

reverse(beg, end);
reverse_copy(beg, end, dest
replace_copy_if(beg, end, dest, pred, new_val);

        1.3 容器特有算法

        泛型算法具有通用性,但算法是否其作用归根还是和数据结构关联的,有些容器其特有结构,对一些算法是无法支持到的。但标准库也相应地为这些容器提供了功能函数支持,使得获得容器一致性。

        在我们前面的sort应用例子就看到,list容器是采用了list内置的sort函数,而非公用的sort算法。list 容器上的迭代器是双向的,而不是随机访问类型。由于 list 容器不支持随机访问,因此,在此容器上不能使用需要随机访问迭代器的算法, 例如sort 算法及其相关的算法。还有一些其他的泛型算法,如 merge、remove、reverse 和 unique,虽然可以用在 list 上,但却付出了性能上的代价。如果这些算法利用 list 容器实现的特点,则可以更高效地执行。
        如果可以结合利用 list 容器的内部结构,则可能编写出更快的算法。与其他顺序容器所支持的操作相比,标准库为 list 容器定义了更精细的操作集合,使它不必只依赖于泛型操作。表 11.4 列出了 list 容器特有的操作,其中不包括要求支持双向或更弱的迭代器类型的泛型算法,这类泛型算法无论是用在list 容器上,还是用在其他容器上,都具有相同的效果。

/*
*将 lst2 的元素合并到 lst 中。这两个 list 容器对象都必须排序。
*lst2 中的元素将被删除。合并后,lst2 为空。返回 void 类型。
*/
lst.merge(lst2)      //第一个版本使用 < 操作符
lst.merge(lst2, comp)//第二个版本则使用 comp 指定的比较运算

/*调用 lst.erase 删除所有等于指定值或使指定的谓词函数返回非零值的元素。返回 void 类型*/
lst.remove(val) 
lst.remove_if(unaryPred)

/*反向排列 lst 中的元素*/
lst.reverse() 

/*对 lst 中的元素排序*/
lst.sort 

/*将 lst2 的元素移到 lst 中迭代器 iter 指向的元素前面。在 lst2 中删除移出的元素。*/
lst.splice(iter, lst2)       //第一个版本将 lst2 的所有元素移到 lst 中;合并后,lst2 为空。lst 和 lst2 不能是同一个 list 对象
lst.splice(iter, lst2, iter2)//
第二个版本只移动 iter2 所指向的元素,这个元素必须是 lst2 中的元素。在这种情况中,lst 和lst2 可以是同一个 list 对象。也就是说,可在一个 list对象中使用 splice 运算移动一个元素
lst.splice(iter, beg, end)   //第三个版本移动迭代器 beg 和 end 标记的范围内的元素。beg 和 end 照例必须指定一个有效的范围。这两个迭代器可标记任意 list 对象内的范围,包括 lst。当它们指定 lst 的一段范围时,如果 iter 也指向这个范围的一个元素,则该运算未定义。

/*调用 erase 删除同一个值的集合副本。*/
lst.unique()          //第一个版本使用 ==操作符判断元素是否相等
lst.unique(binaryPred)//第二个版本则使用指定的谓词函数实现判断

        1.4 标准算法库简述

        标准库提供了超过 100 种算法。与容器一样,算法有着一致的结构。下面就将这些算法分类归纳一下,来看看算法对容器提供了那些常用操作。

        1)容器排序

std::sort(beg, end)//接受一定范围的元素,并对元素进行排序
std::stable_sort(beg, end)//接受一定范围的元素,并对元素进行排序,其能保证排序后元素的原始顺序
std::sort(beg, end, comp)
std::stable_sort(beg, end, comp)//

std::is_sorted(beg, end) //接受一定范围的元素,并判断该范围的元素是否经过排序。
std::shuffle(beg, end,gen) //类似于反排序函数;其接受一定范围的元素,并打乱这些元素。
std::random_shuffle(beg, end)//按随机次序重新安排元素,要求随机访问迭代器支持
std::random_shuffle(beg, end, rand)

std::partial_sort(beg, mid, end)//接受一定范围的元素和另一个迭代器,前两个参数决定排序的范围,后两个参数决定不排序的范围。
std::partial_sort(beg, mid, end, comp)

std::partial_sort_copy(beg, end, destBeg, destEnd)
std::partial_sort_copy(beg, end, destBeg, destEnd, comp)

std::reverse(beg, end)    //向后处理输入序列排序,要求双向迭代器支持
std::reverse_copy(beg, end, dest)

std::partition(beg, end, unaryPred)//能够接受谓词函数。所有元素都会在谓词函数返回true时,被移动到范围的前端。剩下的将放在范围的后方。
std::stable_partition(beg, end, unaryPred)//类似std::partition,不同的是能保证排序后元素的原始顺序

std::nth_element(beg, nth, end)//实参 nth 是一个迭代器,定位输入序列中的一个元素。
std::nth_element(beg, nth, end, comp)

std::next_permutation(beg, end)//对序列进行前向和后向处理,要求双向迭代器
std::next_permutation(beg, end, comp)

std::prev_permutation(beg, end)//与 next_permutation 很像,但变换序列以形成前一个排列
std::prev_permutation(beg, end, comp)
...

        2)在容器中查找元素

std::find(beg, end, val) //可将一个搜索范围和一个值作为参数。函数将返回找到的第一个值的迭代器。线性查找。
std::find_if(beg, end, unaryPred) //在 unaryPred 为真的输入范围中查找。
std::count(beg, end, val) //count 算法返回元素在输入序列中出现次数的计数
std::count_if(beg, end, unaryPred) //在 unaryPred 为真的输入范围中查找。
std::find_first_of(beg1, end1, beg2, end2)//返回第二个范围的任意元素在第一个范围的首次出现的迭代器,如果找不到匹配就返回 end1。
std::find_first_of(beg1, end1, beg2, end2, binaryPred)//使用 binaryPred 比较来自两个序列的元素,返回第一个范围中第一个这种元素的迭代器
std::find_end(beg1, end1, beg2, end2)    //返回第二个范围的任意元素在第一个范围的最后出现的迭代器
std::find_end(beg1, end1, beg2, end2, binaryPred)//
std::adjacent_find(beg, end)//返回重复元素的第一个相邻对。如果没有相邻的重复元素。就返回 end。
std::adjacent_find(beg, end, binaryPred)

std::search(beg1, end1, beg2, end2)//返回输入范围中第二个范围作为子序列出现的第一个位置。
std::search(beg1, end1, beg2, end2, binaryPred)
std::search_n(beg, end, count, val)
std::search_n(beg, end, count, val, binaryPred)
std::binary_search(beg, end, val)//可将一个搜索范围和一个值作为参数。执行二分查找,当找到对应元素时,返回true;否则,返回false。
std::binary_search(beg, end, val, comp)

std::lower_bound(beg, end, val)//可将一个查找返回和一个值作为参数,并且执行二分查找,返回第一个不小于给定值元素的迭代器。
std::lower_bound(beg, end, val, comp)
std::upper_bound(beg, end, val)//与 std::lower_bound 类似,不过会返回第一个大于给定值元素的迭代器。
std::upper_bound(beg, end, val, comp)

std::equal_range(beg, end, val)//可将一个搜索范围和一个值作为参数,并且返回一对迭代器。其第一个迭代器和返回结果一样,第二个迭代器和 std::upper_bound 返回结果一样。
std::equal_range(beg, end, val, comp)
std::equal(beg1, end1, beg2)//确定两个序列是否相等。
std::equal(beg1, end1, beg2, binaryPred) //

std::mismatch(beg1, end1, beg2)//比较两个序列中的元素,返回一对表示第一个不匹配元素的迭代器。
std::mismatch(beg1, end1, beg2, binaryPred) //

for_each(beg, end, f)//对其输入范围中的每个元素应用函数f。
...

        3)从容器中删除指定元素

std::remove(beg, end, val)//接受一个容器范围和一个具体的值作为参数,并且移除对应的值。返回一个新的end迭代器,用于修改容器的范围。
std::remove_if(beg, end, unaryPred)
std::remove_copy(beg, end, dest, val)//接受一个容器范围,一个输出迭代器和一个值作为参数。并且将所有不满足条件的元素拷贝到输出迭代器的容器中。
std::remove_copy_if(beg, end, dest, unaryPred)//用 new_val 代替每个匹配元素,对每个元素执行unaryPred,代替使 unaryPred 为真的那些元素

std::replace(beg, end, old_val, new_val)//接受一个容器范围和两个值作为参数,将使用第二个数值替换所有与第一个数值相同的值。
std::replace_if(beg, end, unaryPred, new_val)
std::replace_copy(beg, end, dest, old_val, new_val)//与 std::replace 功能类似,将每个元素复制到 dest,用 new_val 代替指定元素。
std::replace_copy_if(beg, end, dest, unaryPred, new_val)

//
std::unique(beg, end)//清楚非唯一性的元素,只保留一个
std::unique(beg, end, binaryPred)
std::unique_copy(beg, end, dest)//将唯一元素复制到 dest
std::unique_copy(beg, end, dest, binaryPred)

std::rotate(beg, mid, end)//围绕由 mid 表示的元素旋转元素。mid 处的元素成为第一个元素,从 mid +1 到 end 的元素其次,后面是从 beg 到 mid 的范围。返回 void
std::rotate_copy(beg, mid, end, dest)//除了保持输入序列不变并将旋转后的序列写至 dest 之外,与 rotated 很像。返回 void

std::copy_if //与 std::copy 功能相同,可以多接受一个谓词函数作为是否进行拷贝的依据。
...

        4)修改内容

std::copy(beg, end, dest)    //将一个容器的数据拷贝到另一个容器
std::copy_n  //
std::copy_backward(beg, end, dest)//按逆序将元素复制到输出迭代器 dest。返回 dest

std::move    //
std::fill(beg, end, val)//范围内写入val
std::fill_n(dest, cnt, val)//将 cnt 个值写到 dest。fill_n 函数写 val 值的 cnt 个副本

std::generate(beg, end, Gen)//将新值赋给输入序列中的每个元素,执行 Gen()来创建新值
std::generate_n(dest, cnt, Gen)//对发生器 Gen() 进行 cnt 次计算

std::transform(beg, end, dest, unaryOp)//将容器某一范围的元素放置到其他容器中,在拷贝的同时,修改容器中的元素
std::transform(beg, end, beg2, dest, binaryOp)

std::merge(beg1, end1, beg2, end2, dest)//合并序列,两个输入序列都必须是已排序的。将合并后的序列写至 dest
std::merge(beg1, end1, beg2, end2, dest, comp)
std::inplace_merge(beg, mid, end)//将同一序列中的两个相邻子序列合并为一个有序序列:将从 beg 到 mid 和从 mid 到 end 的子序列合并为从 beg 到 end 的序列
std::inplace_merge(beg, mid, end, comp)

std::swap(elem1, elem2)//算法要求前向迭代器,因为修改输入序列中的元素,交换指定元素或由给定迭代器表示的元素
std::swap_ranges(beg1, end1, beg2)//用开始于 beg2 的第二个序列中的元素交换输入范围中的元素。
std::iter_swap(iter1, iter2)

...

        5)输入迭代器特有算法

includes(beg, end, beg2, end2)//如果输入序列包含第二个序列中的每个元素,就返回 true;否则,返回 false
includes(beg, end, beg2, end2, comp)

set_union(beg, end, beg2, end2, dest)//创建在任一序列中存在的元素的有序序列。两个序列中都存在的元素在输出序列中只出现一次。将序列存储在 dest 中
set_union(beg, end, beg2, end2, dest, comp)

set_intersection(beg, end, beg2, end2, dest)//创建在两个序列中都存在的元素的有序序列。将序列存储在 dest 中。
set_intersection(beg, end, beg2, end2, dest, comp)

set_difference(beg, end, beg2, end2, dest)//创建在第一个容器中但不在第二个容器中的元素的有序序列。
set_difference(beg, end, beg2, end2, dest, comp)

set_symmetric_difference(beg, end, beg2, end2, dest)//创建在任一容器中存在但不在两个容器中同时存在的元素的有序序列。
set_symmetric_difference(beg, end, beg2, end2, dest, comp)

        6)最大最小值

min(val1, val2)
min(val1, val2, comp)
max(val1, val2)
max(val1, val2, comp)

min_element(beg, end)
min_element(beg, end, comp)
max_element(beg, end)
max_element(beg, end, comp)

        7)简单数学计算

accumulate(beg, end, init)//返回输入范围中所有值的总和
accumulate(beg, end, init, BinaryOp)

inner_product(beg1, end1, beg2, init)//返回作为两个序列乘积而生成的元素的总和。
inner_product(beg1, end1, beg2, init, BinOp1, BinOp2)

partial_sum(beg, end, dest)//将新序列写至 dest,其中每个新元素的值表示输入范围中在它的位置之前(不包括它的位置)的所有元素的总和。
partial_sum(beg, end, dest, BinaryOp)

adjacent_difference(beg, end, dest)//将新序列写至 dest,其中除了第一个元素之外每个新元素表示当前元素和前一元素的差。
adjacent_difference(beg, end, dest, BinaryOp)

        8)更多算法相关操作如下

头文件	名字
algorithm	lower_bound 
algorithm	max 
algorithm	min 
algorithm	nth_element 
algorithm	partial_sort 
algorithm	stable_sort 
algorithm	unique 
algorithm	unique_copy 
algorithm	upper_bound 
algorithm	copy 
algorithm	count 
algorithm	count_if 
algorithm	equal_range 
algorithm	fill 
algorithm	fill_n 
algorithm	find 
algorithm	find_end 
algorithm	find_first_of 
algorithm	for_each 
algorithm	replace 
algorithm	replace_copy 
algorithm	set_difference 
algorithm	set_intersection 
algorithm	set_union 
algorithm	sort 
cstdlib	    abort
functional	bind2nd 
bitset	    bitset 
deque	    deque 
exception	exception 
fstream	    fstream 
fstream	    ifstream 
cstddef	    ptrdiff_t 
iomanip	    setfill 
iomanip	    setprecision 
iomanip	    setw 
cstddef	    size_t 
ios_base	ios_base
cctype	    isalpha
cctype	    islower
cctype	     ispunct 
cctype	     isspace 
cctype	     isupper 
functional	 less_equal 
functional	 negate 
functional	 not1 
fstream	     of stream 
functional	 plus 
cmath	     sqrt 
cstring	     strcmp 
cstring	     strcpy 
cstring	     strlen 
cstring	     strncpy 
exception	 terminate 
cctype	     tolower 
cctype	     toupper 
exception	 unexpected 
头文件	名字
iostream	boolalpha 
iostream	cerr 
iostream	cin 
iostream	cout 
iostream	dec 
iostream	endl 
iostream	ends 
iostream	fixed 
iostream	flush 
iostream	hex 
iostream	internal 
iostream	right 
iostream	scientific 
iostream	showbase 
iostream	showpoint 
iostream	skipws 
iostream	 istream 
iostream	 left 
iostream	 noboolalpha 
iostream	 noshowbase 
iostream	 noshowpoint 
iostream	 noskipws 
iostream	 nounitbuf 
iostream	 nouppercase 
iostream	 oct 
iostream	 ostream 
iostream	 unitbuf 
iostream	 uppercase 
头文件	    名字
numeric	    accumulate    
memory	    allocator
memory	    auto_ptr 
iterator	back_inserter 
new	        bad_alloc 
typeinfo	bad_cast 
iterator	front_inserter 
string	    getline 
numeric	    inner_product 
iterator	inserter 
queue	    priority_queue 
queue	    queue 
stdexcept	range_error 
iterator	reverse_iterator 
stdexcept	runtime_error 
set	        set 
iterator	 istream_iterator 
sstream	     istringstream 
list	     list 
stdexcept	 logic_error 
utility	     make_pair 
map	         map 
map	         multimap 
set	         multiset 
iterator	 ostream_iterator 
sstream	     ostringstream 
stdexcept	 out_of_range 
utility	     pair 
stack	     stack 
string	     string 
sstream	     stringstream 
typeinfo	 type_info 
memory	     uninitialized_copy 
vector	     vector 

三、源码案例及测试

        3.1 编译测试

        创建test.h/cpp源文件,通过g++ test.cpp -o test.exe编译指令生成程序,运行测试:

         3.2 源代码

        test.h

#ifndef _TEST_H_
#define _TEST_H_
#include <iostream>
#include <vector>
#include <list>
#include <set>
#include <numeric>
#include <algorithm> 
#include <time.h>
#include <random>	
#include <iterator>
#include <fstream>
#include <cstring>
#endif //_TEST_H_

        test.cpp

#include "test.h"

using namespace std;

bool compare(int a,int b)
{
    return a>b;
};
//
random_device rd;
mt19937 g {rd()};

int main(int argc, char* argv[])
{
    vector<int> v{100, 400, 200, 300, 200, 500, 100, 400, 600, 300 };
    int sum = 0;
    for (auto &&i : v)
    {
        sum += i;
    }
    cout << "sum = " << sum << endl;
    //
    cout << "sum = " << accumulate(begin(v), end(v), 0) << endl;
	//创建一个大数组vector
	vector<int> v_sort;
	const int v_size = 10000;
	const int read_size = 20;
	for(int i=0; i<v_size;i++)
	{
		v_sort.push_back(rand()%v_size);
	}
	cout << "v_sort is_sorted = "<< is_sorted(v_sort.begin(), v_sort.end()) << endl;
	//构造一个新的vertor,为了公平测试后面容器,调用sort算法排序vector
	vector<int> v_sort_new(v_sort.begin(),v_sort.end());
	cout << "clock()1 = " << clock() <<endl;
	sort(v_sort_new.begin(),v_sort_new.end());
	cout << "clock()2 = " << clock() <<endl;
	//输出已排序的vector前一段数据
	for(int i=0; i<read_size;i++)
	{
		cout << v_sort_new[i] << " ";
	}
	cout << "\n";
	//将vector拷贝构造list,调用list的sort函数排序
	list<int> l_sort(v_sort.begin(),v_sort.end());
	cout << "clock()3 = " << clock() <<endl;
	l_sort.sort();
	cout << "clock()4 = " << clock() <<endl;
	//输出已排序的list前一段数据
	list<int>::iterator it_list=l_sort.begin();
	for (int i=0; i<read_size;i++)
	{
		/* code */
		cout << *(it_list++) << " ";
	}
	cout << "\n";
	//将vector拷贝构造multiset,multiset在构造时就自动排序
	cout << "clock()5 = " << clock() <<endl;
	multiset<int> set_sort(v_sort.begin(),v_sort.end());
	cout << "clock()6 = " << clock() <<endl;
	//输出已排序的multiset前一段数据
	multiset<int>::iterator it_mset = set_sort.begin();
	for (int i=0; i<read_size;i++)
	{
		/* code */
		cout << *(it_mset++) << " ";
	}
	cout << "\n";
	//将multiset拷贝回vector,multiset在构造时就自动排序,vector同样得到已排序结构
	cout << "clock()7 = " << clock() <<endl;
	v_sort.clear();
	v_sort.assign(set_sort.begin(),set_sort.end());
	cout << "clock()8 = " << clock() <<endl;
	//重新输出已排序的vector前一段数据
	for(int i=0; i<read_size;i++)
	{
		cout << v_sort[i] << " ";
	}
	cout << "\n";
	cout << "v_sort is_sorted = "<< is_sorted(v_sort.begin(), v_sort.end()) << endl;
	//
	shuffle(v_sort.begin(),v_sort.end(),g);
	cout << "v_sort is_sorted = "<< is_sorted(v_sort.begin(), v_sort.end()) << endl; //=0
	//
	partition(v_sort.begin(),v_sort.end(), [] (int i) { return i < 20; });
	//重新输出已排序的vector前一段数据
	for(int i=0; i<read_size;i++)
	{
		cout << v_sort[i] << " ";
	}
	cout << "\n";
	//
	shuffle(v_sort.begin(),v_sort.end(),g);
	auto middle (next(begin(v_sort), 100));
	partial_sort(begin(v_sort), middle, end(v_sort));
	//重新输出已排序的vector前一段数据
	for(int i=0; i<read_size;i++)
	{
		cout << v_sort[i] << " ";
	}
	cout << "\n";
	//
	shuffle(v_sort.begin(),v_sort.end(),g);
	sort(v_sort.begin(),v_sort.end(),compare);
	//重新输出已排序的vector前一段数据
	for(int i=0; i<read_size;i++)
	{
		cout << v_sort[i] << " ";
	}
	cout << "\n";
	//算法与容器类型无关
	vector<int>::const_iterator result_vec = find(v_sort.begin(),v_sort.end(),99);//vector查找
	list<int>::const_iterator result_list = find(l_sort.begin(),l_sort.end(),99);  //list查找
	multiset<int>::iterator result_mset = find(set_sort.begin(),set_sort.end(),99);//multiset 查找
	int vg[12] = {71,73,29,34,40,23,84,99,21,78,18,58};
	int *result_vg = find(vg,vg+12,99);	//数组查找
	//算法修改容器值
	fill(v_sort.begin(),v_sort.begin()+2, 0);	//前两个值设为0
	fill(vg,vg+2, 0);							//前两个值设为0
	//算法会移动容器内的数据位置
	sort(vg,vg+12,compare);
	fill(vg,vg+sizeof(vg), 10);					//前每个值设为10
	//
	list<int> ilst, ilst2, ilst3, ilst4; // empty lists
	for (list<int>::size_type i = 0; i != 4; ++i)
		ilst.push_front(i);	
	copy (ilst.begin(), ilst.end(), front_inserter(ilst2));	// after copy ilst2 contains: 0 1 2 3
	copy (ilst.begin(), ilst.end(), back_inserter(ilst3));	// after copy, ilst3 contains: 3 2 1 0
	copy (ilst.begin(), ilst.end(),	inserter (ilst4, ilst4.begin()));// after copy, ilst4 contains: 3 2 1 0
	//
	/*//注释,编译后面代码测试
	istream_iterator<string> cin_it(cin),eof; // reads int from cin,
	ofstream outfile("test.txt");
	ostream_iterator<string> outputf(outfile, " ");// writes string from the ofstream named outfile
	ostream_iterator<string> output(cout, "\n");
	string end_str = "quit";
	while (cin_it != eof)
	{
		if(0==strcmp((*cin_it).c_str(),end_str.c_str()))
		{
			break;
		}
		*outputf++ = *cin_it;
		*output++ = *cin_it++;
		flush(cout);
	}
	flush(outfile);
	*/
	//
	cout << "ilst.size() = " << ilst.size() << endl;
	list<int>::reverse_iterator it_rvec = ilst.rbegin();
	for (size_t i = 0; i < ilst.size(); i++)
	{
		cout << *it_rvec << " ";
		/* code */
		it_rvec++;
	}
	cout << "\n";
	it_rvec = ilst.rend();
	it_rvec--;
	for (size_t i = 0; i < ilst.size(); i++)
	{
		cout << *it_rvec << " ";
		/* code */
		it_rvec--;
	}
	cout << "\n";
	//
	list<int>::const_iterator it_const = ilst.begin();
	it_const++;
	//*it_const = 10;	//error
	list<int>::iterator it_val= ilst.begin();
	*it_val = 10;
    return 0;
};

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

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

相关文章

基于springboot+vue的校园社团管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

9.循环神经网络

9.循环神经网络 目录 序列模型 统计工具 自回归模型 马尔可夫模型 训练 预测 文本预处理 读取数据集 词元化 词表 整合所有功能 总结 语言模型和数据集 学习语言模型 马尔可夫模型与m元语法 自然语言统计 读取长序列数据 随机采样 顺序分区 总结 循环神经…

树状数组(高级数据结构)-蓝桥杯

一、简介树状数组 (Binary Indexed Tree,BIT)&#xff0c;利用数的二进制特征进行检索的一种树状结构。一种真正的高级数据结构&#xff1a; 二分思想、二叉树、位运算、前缀和。高效!代码极其简洁!二、基本应用数列a1,a2,....,an&#xff0c;操作&#xff1a;单点修改&#xf…

微服务架构是什么?微服务架构与SOA的区别

微服务架构定义微服务架构是一种架构风格和架构思想&#xff0c;它倡导我们在传统软件应用架构的基础上&#xff0c;将系统业务按照功能拆分为更加细粒度的服务&#xff0c;所拆分的每一个服务都是一个独立的应用&#xff0c;这些应用对外提供公共的API&#xff0c;可以独立承担…

Python3 operator 模块

Python3 operator 模块 Python2.x 版本中&#xff0c;使用 cmp() 函数来比较两个列表、数字或字符串等的大小关系。 Python 3.X 的版本中已经没有 cmp() 函数&#xff0c;如果你需要实现比较功能&#xff0c;需要引入 operator 模块&#xff0c;适合任何对象&#xff0c;包含…

从防御者视角来看APT攻击

前言 APT防御的重要性毋庸讳言&#xff0c;为了帮助各位师傅在防御方面建立一个总体认识&#xff0c;本文会将APT防御方法分为三类&#xff0c;分别是&#xff1a;监控、检测和缓解技术&#xff0c;并分别进行梳理&#xff0c;介绍分析代表性技术。这一篇分析现有的监控技术。…

多重继承的虚函数表

同一个类,不同对象使用同一张虚函数表 不同类使用不同的虚函数表 子类自己添加的虚函数(非重写),在VS中是将此放在第一个继承类的虚函数表里. #include <iostream> using namespace std;class Father { public:virtual void func1() { cout << "Father::f…

3款强大到离谱电脑软件,都是效率神器,从此远离加班

闲话少说&#xff0c;直接上狠货。 1、ImageGlass ImageGlass是一款值得吹爆的电脑图片浏览工具&#xff0c;使用极其方便&#xff0c;体积50M左右&#xff0c;非常小巧&#xff0c;功能却强大到离谱&#xff0c;ImageGlass打开图片的速度极快&#xff0c;实现快速不同图像间切…

Flink-状态编程(Keyed State、Operator State、Broadcast State、状态持久化和状态后端)

文章目录状态编程Flink 中的状态有状态算子状态的分类按键分区状态&#xff08;Keyed State&#xff09;基本概念支持的结构类型使用基本代码实例-值状态&#xff08;ValueState&#xff09;实例-列表状态&#xff08;ListState&#xff09;实例-映射状态&#xff08;MapState&…

2023年湖北中级职称(工程类建筑类)报名条件和要求是什么?

2023年湖北中级职称&#xff08;工程类建筑类&#xff09;报名条件和要求是什么&#xff1f; 中级职称分为计算机类、医药类、卫生类、教师类、工程类、经济类等各大类&#xff0c;今天主要就是跟大家说一下工程类中级职称评审的一个条件和要求&#xff0c;这也是评职称人员应该…

ASEMI低压MOS管50N06S,50N06S图片,50N06S尺寸

编辑-Z ASEMI低压MOS管50N06S参数&#xff1a; 型号&#xff1a;50N06S 漏极-源极电压&#xff08;VDS&#xff09;&#xff1a;60V 栅源电压&#xff08;VGS&#xff09;&#xff1a;25V 漏极电流&#xff08;ID&#xff09;&#xff1a;50A 功耗&#xff08;PD&#xf…

面试一位软件测试6年工作者:一年经验掰成六年来用....

在众多面试中&#xff0c;对于那个工作了6年的面试者&#xff0c;我印象很深刻&#xff0c;因为最开始拿到简历的时候&#xff0c;我一摸:"这简历&#xff0c;好厚啊&#xff01;"再一看&#xff0c;工作6年。 于是我去找了我的领导&#xff0c;我说:“这人我应该没…

linux-rockchip-音频相关

一、查看当前配置声卡状态 cat /proc/asound/cards二、查看当前声卡工作状态 声卡分两种通道&#xff0c;一种是Capture、一种是Playback。Capture是输入通道&#xff0c;Playback是输出通道。例如pcm0p属于声卡输出通道&#xff0c;pcm0c属于声卡输入通道。 ls /proc/asoun…

分析现货黄金价格一般有什么方法

分析现货黄金价格一般有什么方法呢&#xff1f;我相信很多投资者都会说&#xff0c;是技术分析。很多人并不知道技术分析是什么&#xff0c;并且技术分析是如何去分析现货黄金价格的&#xff0c;那么本文就介绍一下技术分析的主要分类。可以说&#xff0c;小编的其他文章都是以…

ASE20N60-ASEMI的MOS管ASE20N60

编辑-Z ASE20N60在TO-247封装里的静态漏极源导通电阻&#xff08;RDS(ON)&#xff09;为0.4Ω&#xff0c;是一款N沟道高压MOS管。ASE20N60的最大脉冲正向电流ISM为80A&#xff0c;零栅极电压漏极电流(IDSS)为10uA&#xff0c;其工作时耐温度范围为-55~150摄氏度。ASE20N60功耗…

Linux知识之主机状态

1、查看系统资源占用 •可以通过top命令查看CPU、内存使用情况&#xff0c;类似Windows的任务管理器默认每5秒刷新一次&#xff0c;语法&#xff1a;直接输入top即可&#xff0c;按q或ctrl c退出 2、 top命令内容详解 •第一行&#xff1a;top&#xff1a;命令名称&#xff0…

群晖-第2章-设置HTTPS访问

群晖-第2章-设置HTTPS访问 本章介绍如何通过HTTPS访问群晖&#xff0c;前置要求是完成群晖-第1章-IPV6的DDNS中的内容&#xff0c;可以是IPV4也可以是IPV6&#xff0c;或者你有公网IP&#xff0c;直接添加DNS解析也可以。只要能通过域名访问到nas就行。 本文参考自群晖添加SS…

【汽车电子】A核与M核异构通信过程解析

一、 硬件层通信实现原理二、驱动层Virtio下RPMsg通信实现三、应用层双核通信实现方式 现在越来越多的产品具有M core和A core的异构架构&#xff0c;既能达到M核的实时要求&#xff0c;又能满足A核的生态和算力。比如NXP的i.MX8系列、瑞萨的RZ/G2L系列以及TI的AM62x系列等等。…

CSS基础教程

目录 css背景 1.background-color 2.透明度和不透明度 3.使用RGBA的透明度 css背景图片 css背景重复 ​编辑 1.background-repeat 2. background-repeat:no-repeat 3.background-position css背景附着 css边框 1.border-style 边框样式 2.border-width 边框宽度 4…

生物识别技术—景联文科技提供课堂行为采集、reID行为采集、驾驶员行为采集等全类型采集服务!

“随着生物识别技术逐步成熟&#xff0c;其识别准确率大幅提高&#xff0c;应用场景趋向复杂化、多样化&#xff0c;市场规模保持高速增长。据报道&#xff0c;市场研究机构Emergen Research最新发布的一份报告预测&#xff0c;到2027年&#xff0c;全球生物识别市场规模将接近…