8.1 C++ STL 变易拷贝算法

C++ STL中的变易算法(Modifying Algorithms)是指那些能够修改容器内容的算法,主要用于修改容器中的数据,例如插入、删除、替换等操作。这些算法同样定义在头文件 <algorithm> 中,它们允许在容器之间进行元素的复制、拷贝、移动等操作,从而可以方便地对容器进行修改和重组。

主要包括以下几类变易算法:

  1. 复制算法:
    • copy():将一个容器的元素复制到另一个容器中。
    • copy_if():根据给定的条件(函数对象或谓词)复制满足条件的元素到另一个容器中。
    • copy_n():从指定位置开始,复制指定个数的元素到另一个容器中。
    • copy_backward():将一个容器的元素复制到另一个容器中,并保持原有的顺序。
  2. 拷贝算法:
    • fill():用指定值替换容器中的所有元素。
    • fill_n():用指定值替换容器中从指定位置开始的一定数量的元素。
    • generate():根据给定的生成函数,替换容器中的所有元素。
    • generate_n():根据给定的生成函数,替换容器中从指定位置开始的一定数量的元素。
  3. 移动算法:
    • move():将一个容器中的元素移动到另一个容器中,通常用于移动语义的场景。

这些变易算法允许我们在不创建新容器的情况下,对现有容器进行元素的复制、拷贝和重排。使用这些算法可以实现高效的数据操作,节省了内存开销和不必要的数据拷贝。同时,这些算法也是C++ STL中非常有用和常用的功能,为C++开发者提供了强大的工具来操作和修改容器中的元素。

8.1 元素复制算法

Copy 算法函数,用于将一个源序列的内容复制到另一个目标序列中。copy函数的用法如下:

template<class InputIterator, class OutputIterator>
OutputIterator copy(InputIterator first, InputIterator last, OutputIterator result);

其中,first、last是迭代器,表示源序列的范围;result是迭代器,表示目标序列的起始位置。调用copy函数后,将会将[first, last]区间内的元素复制到从result开始的目标序列中,并返回指向目标序列最后一个复制元素之后的位置的迭代器。

需要注意的是,copy函数只能复制对象,不能使用于复制C字符串(包括char*和char[])等字符数组。对于字符数组,可以使用strcpy函数进行复制。另外,如果源序列区间和目标序列区间有重叠部分,需要使用copy_backward函数。

如下案例中,实现容器之间元素的拷贝复制操作,将两个迭代器进行互相拷贝。

#include <iostream>
#include <vector>
#include <algorithm>using namespace std;void MyPrint(int x) { cout << x << " "; }int main(int argc, char* argv[])
{vector<int> var1 = { 1,3,5,7,9 };vector<int> var2 = { 2,4,6,8,10 };// 复制var1到var2 此时var2中的内容将被覆盖copy(var1.begin(), var1.end(), var2.begin());// var1 -> 覆盖到 --> var2for_each(var2.begin(), var2.end(), MyPrint);cout << endl;// 复制var1中的前3个元素,并输出copy_backward(var1.begin(), var1.begin() + 2, var1.end());for_each(var1.begin(), var1.end(), MyPrint);system("pause");return 0;
}

8.2 元素交换算法

Swap 算法函数,用于交换两个对象或是两个结构的值。swap函数的用法如下:

template <class T>
void swap (T& a, T& b);

其中,a、b是要交换值的两个对象。

swap函数使用时需要注意,swap并不像第一眼看到的那样简单粗暴地直接交换值,它实际上是通过移动指针进行的值交换,因此对于大规模的对象交换,使用swap会比暴力直接交换值更加高效。同时,swap函数还保证了异常安全性,即在对象交换时如果发生了异常,swap函数会确保原始状态恢复,不会产生未定义行为。

在C++11中,类也可以自定义swap成员函数,当使用了自定义的swap函数时,调用std::swap函数将使用类内定义的swap函数进行值交换。一般而言,自定义swap函数应该优先使用std::swap进行值交换,从而可以借助std::swap的优势提高交换效率。

#include <iostream>
#include <vector>
#include <algorithm>using namespace std;void MyPrint(int x) { cout << x << " "; }int main(int argc, char* argv[])
{vector<int> var1 = { 1,3,5,7,9 };vector<int> var2 = { 2,4,6,8,10 };// 两个容器之间数值互换swap(var1, var2);for_each(var1.begin(), var1.end(), MyPrint);// 通过迭代的方式实现数值互换iter_swap(&var1, &var2);for_each(var2.begin(), var2.end(), MyPrint);// 区间选择交换swap_ranges(var1.begin(), var1.end(), var2.begin());for_each(var2.begin(), var2.end(), MyPrint);system("pause");return 0;
}

8.3 元素搬运算法

Transform 算法函数,用于将给定源序列中的元素按照指定规则进行变换,并将结果存放到目标序列中。transform函数的用法如下:

template<class InputIterator, class OutputIterator, class UnaryOperation>
OutputIterator transform(InputIterator first1, InputIterator last1, OutputIterator result, UnaryOperation op);

其中,first1、last1是迭代器,表示源序列的范围;result是迭代器,表示目标序列的起始位置;op是一个一元函数对象,用于对源序列中的元素进行变换。调用transform函数后,将会对[first1, last1]区间内的每个元素执行一次op操作,并将结果存放到对应的result位置。

但读者需要注意,transform函数会根据op的返回值类型确定目标序列的元素类型,并自动调用构造函数生成目标序列中的元素。因此,如果op返回的类型是一个自定义的类型,需要确保该类型具有默认构造函数和赋值运算符函数。另外,如果源序列与目标序列重叠,需要使用另一种重载的transform函数来保证正确性。

transform函数的使用场景十分广泛,可以用于对任意类型的序列进行任意类型的变换,例如将数组中的每个元素加1,将vector中的每个字符串转换为大写形式等等。

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;void MyPrint(int x) { cout << x << " "; }class TransForm
{// 在搬运的过程中每次+10写入到vTarget;
public: int operator()(int val){ return val + 10;}
};
class New_TransForm
{// 使用仿函数,将两个数组中的值相加
public: int operator()(int val1, int val2){return val1 + val2;}
};int main(int argc, char* argv[])
{vector<int> var = { 1,2,3,4,5 };    // 原容器vector<int > vTarget;               // 目标容器// 第一种形式:将var中的数据每次+10后搬运到vTarget中vTarget.resize(5);    // transform 不会自动开辟内存,需要我们手动开辟transform(var.begin(), var.end(), vTarget.begin(), TransForm());// 循环输出 此处的 [](int val){cout << val << " ";  其实是 MyPrint 不过是匿名了for_each(vTarget.begin(), vTarget.end(), [](int val){cout << val << " "; });cout << endl;// 第二种形式:将var1,var2两个容器中的值相加,相加后搬运到new_vTarget容器中vector<int> var1 = { 1, 2, 3, 4, 5 };  // 原容器vector<int> var2 = { 6, 7, 8, 9, 10 }; // 原容器vector<int> new_vTarget;               // 目标容器new_vTarget.resize(5);transform(var1.begin(), var1.end(), var2.begin(), new_vTarget.begin(), New_TransForm());for_each(new_vTarget.begin(), new_vTarget.end(), MyPrint);system("pause");return 0;
}

8.4 元素替换算法

Replace 算法函数,用于将给定序列中的所有等于给定值的元素替换为指定的新值。replace函数的用法如下:

template <class ForwardIterator, class T>
void replace (ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value);

其中,first、last是迭代器,表示待替换的序列的范围;old_value表示要被替换的值;new_value表示替换后的新值。调用replace函数后,会将[first, last]区间内所有等于old_value的元素全部替换为new_value

但读者需要注意,replace函数只能替换对象,不能复制对象。例如,replace函数无法用来替换字符串或其他类似C风格字符串或STL字符串的对象。如果需要替换字符串或其他复杂对象,可以考虑使用其他函数,例如字符串的replace成员函数。另外,replace函数只能对相等的元素进行替换,无法按照某种规律进行替换。如果需要按照某种规律替换序列,可以考虑使用replace_if函数。

#include <iostream>
#include <vector>
#include <algorithm>using namespace std;void MyPrint(int x) { cout << x << " "; }
class MyCompart
{
public: bool operator()(int val){// 将大于5的数据替换return val > 5;}
};int main(int argc, char* argv[])
{vector<int> var = { 1,2,3,4,4,5,5,6,7,8,8,9,0,2,1,0 };// 全部替换: 将var中的4全部替换为4000replace(var.begin(), var.end(), 4, 4000);  for_each(var.begin(), var.end(), MyPrint);// 条件替换:将所有的大于5的数替换为0replace_if(var.begin(), var.end(), MyCompart(), 0);for_each(var.begin(), var.end(), MyPrint);system("pause");return 0;
}

8.5 容器初始化算法

Fill 算法函数,用于将给定序列中的所有元素全部填充为指定的值。fill函数的用法如下:

template <class ForwardIterator, class T>
void fill (ForwardIterator first, ForwardIterator last, const T& val);

其中,first、last是迭代器,表示待填充的序列的范围;val表示要填充的值。调用fill函数后,会将[first, last]区间内的所有元素全部填充为val

需要注意的是,fill函数只能填充对象,不能复制对象。例如,fill函数无法用来填充字符串或其他类似C风格字符串或STL字符串的对象。如果需要填充字符串或其他复杂对象,可以考虑使用其他函数,例如memset函数对于字符串数组的初始化。还需要注意的是,fill函数只能等量复制相同的值,无法按照某种规律变化,如果需要按照某种规律填充序列,可以使用generate函数。

#include <iostream>
#include <vector>
#include <algorithm>using namespace std;void MyPrint(int x) { cout << x << " "; }int main(int argc, char* argv[])
{vector<int> var = { 1,2,3,4,4,5,5,6,7,8,8,9,0,2,1,0 };// 将前3个元素填充为0fill_n(var.begin(), 3, 0);for_each(var.begin(), var.end(), MyPrint);// 全部填充为0fill_n(var.begin(), var.size(), 0);for_each(var.begin(), var.end(), MyPrint);// 全部填充为10fill(var.begin(), var.end(), 10);for_each(var.begin(), var.end(), MyPrint);system("pause");return 0;
}

8.6 普通条件移除

Remove_if 算法函数,用于从给定序列中删除满足某个条件的元素。remove_if函数的用法如下:

template <class ForwardIterator, class UnaryPredicate>
ForwardIterator remove_if (ForwardIterator first, ForwardIterator last, UnaryPredicate pred);

其中,first、last是迭代器,表示要进行操作的序列的范围;pred是一个一元谓词函数,用于指定需要删除的元素。调用remove_if函数后,将会删除[first, last]区间内满足pred条件的元素,并将其移到区间尾部,返回指向第一个被移动元素位置的迭代器。

remove_if函数并不会真正地删除被移动的元素,而是将它们移动到区间尾部,所以最终在[first, last]区间剩下的元素是不确定的。如果想要真正地删除被移动的元素,可以再调用容器类的erase函数删除尾部的元素。需要注意的是,erase函数只能对带有erase成员函数(例如vector、list)的容器使用,对于没有erase成员函数的容器(例如数组),需要手动调整数组的长度。

如下是一个使用案例,代码中实现了将容器中不等于某个值的元素移除出容器,代码如下所示;

#include <iostream>
#include <vector>
#include <algorithm>using namespace std;void MyPrint(int x) { cout << x << " "; }
bool even(int val) { return val % 2 ? 0 : 1; }int main(int argc, char* argv[])
{vector<int> var { 4,3,4,8,9,5,6,7,8,9,2,1,4 };// 移除var里面的所有的4vector<int>::iterator result;result = remove(var.begin(), var.end(), 4);for_each(var.begin(), var.end(), MyPrint);cout << endl;// 移除var里面所有的偶数vector<int>::iterator result1;result1 = remove_if(var.begin(), var.end(), even);for_each(var.begin(), var.end(), MyPrint);system("pause");return 0;
}

8.7 条件移除复制

Remove_copy 算法函数,用于将满足某个条件的元素从一个源序列复制到目标序列中,同时去除不满足条件的元素。remove_copy函数的用法如下:

template <class InputIterator, class OutputIterator, class T>
OutputIterator remove_copy (InputIterator first, InputIterator last, OutputIterator result, const T& value);

其中,first、last是迭代器,表示要进行操作的源序列的范围;result是迭代器,表示复制后的目标序列起始位置;value是需要去除的元素的值。调用remove_copy函数后,将会将原序列[first, last]中不等于value的元素复制到目标序列[result, result + (last - first))中,并返回目标序列最后一个复制元素的后继位置的迭代器。需要注意的是,remove_copy函数并不会真正地将值为value的元素从原序列中移除,而是将它们留在原序列中,因此返回的目标序列只包含不等于value的元素。

remove_copy函数的使用场景通常是,需要在不破坏原序列的情况下,复制其中一些元素到目标序列中,并去除一些元素。如下案例中所示,算法实现了将原容器中不等于某个给定值的元素复制到新容器中。

#include <iostream>
#include <vector>
#include <algorithm>using namespace std;void MyPrint(int x) { cout << x << " "; }bool even(int val){ return val % 2 ? 0 : 1; }int main(int argc, char* argv[])
{vector<int> var { 4,3,4,8,9,5 };int iarray[6] = { 0, 0, 0, 0, 0, 0, };// 移除复制,将var中的数据的前4个数据复制到iarray中,var中数据保持不变remove_copy(var.begin(), var.end(), iarray, 4);for_each(iarray, iarray+6, MyPrint);cout << endl;// 移除var中的偶数,剩余元素复制到iarray中remove_copy_if(var.begin(), var.end(), iarray, even);for_each(iarray, iarray + 6, MyPrint);system("pause");return 0;
}

8.8 容器元素去重算法

Unique 算法函数,用于删除给定序列中相邻的重复元素,只保留一个副本。unique函数的用法如下:

template <class ForwardIterator>
ForwardIterator unique (ForwardIterator first, ForwardIterator last);

其中,first、last是迭代器,表示要进行去重的序列的范围。调用unique函数后,将会去除[first, last]区间内相邻的重复元素,仅保留第一个元素,其余相同的元素都将被删除,剩下的元素会被移动到前面,返回指向最后一个未被删除元素之后的迭代器,通常与erase函数一起使用以删除多余的元素。

unique函数只删除相邻的重复元素,不删除中间隔着其他元素的重复元素,例如序列[a, b, b, c, b, d, d]经过unique去重后会变为[a, b, c, b, d],注意不会删除序列中间的b,因为它并不相邻。还需要注意的是,unique只对相邻元素进行去重,如果需要对无序序列进行去重,可以先对序列进行排序,然后再调用unique函数。

如下笔者提供两个案例,案例中函数unique_copy实现邻近元素去重,函数unique去除连续重复元素,如下所示;

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;void MyPrint(int x) { cout << x << " "; }int main(int argc, char* argv[])
{vector<int> var { 2,5,5,5,5,5,6,7,5,9,5};int iarray[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };// 实现邻近元素去重,只能去除相邻元素中重复的unique_copy(var.begin(), var.end(), iarray);for_each(iarray, iarray + 10, MyPrint);cout << endl;// 另一种邻近元素去重算法vector<int>::iterator result;result = unique(var.begin(), var.end());for_each(var.begin(),result,MyPrint);system("pause");return 0;
}

8.9 元素反向拷贝算法

Reverse 算法函数,用于将给定序列中的元素翻转,即将元素按逆序排列。reverse函数的用法如下:

template <class BidirectionalIterator>
void reverse (BidirectionalIterator first, BidirectionalIterator last);

其中,first、last是迭代器,表示要进行翻转的序列的范围。调用reverse函数后,将会把[first, last]中的元素按相对位置逆序排列,即对于[first, last]中的任意两个迭代器i、j,若 i小于j,则翻转后的序列中,i对应的元素会出现在j之后。

读者需要注意,reverse函数不会改变序列中各个元素的值,只会改变它们的位置,因此是一个非变易算法。与rotate函数类似,reverse函数一般只用于BidirectionalIterator迭代器类型的序列,即支持双向遍历的序列(例如双向链表),而不支持随机访问的序列(例如单向链表)。

简单总结来说,该算法实现了对容器中元素的反向排列,和反向复制容器中的数据,这个复制案例如下所示;

#include <iostream>
#include <vector>
#include <algorithm>using namespace std;void MyPrint(int x) { cout << x << " "; }int main(int argc, char* argv[])
{vector<int> var { 1,2,3,4,5,6,7,8,9,10 };// 将元素反向排列后输出reverse(var.begin(), var.end());for_each(var.begin(), var.end(), MyPrint);cout << endl;// 将元素反向复制到iarray数组中存储int iarray[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };reverse_copy(var.begin(), var.end(), iarray);for_each(iarray,iarray+10, MyPrint);system("pause");return 0;
}

8.10 容器旋转复制算法

Rotate是的一个算法函数,用于将给定序列中的元素向左循环移动若干个位移,即将序列中前面的元素移动到末尾,其最终的位置与原来位置的距离是一个定值。rotate函数的用法如下:

template <class ForwardIterator>
void rotate (ForwardIterator first, ForwardIterator middle, ForwardIterator last);

其中,first、middle、last是迭代器,表示要进行循环移动的序列的范围。调用rotate函数后,将会将序列[first, last]中的元素向左循环移动,使得中间区间[middle, last)的元素移动到前面,前面的区间[first, middle)的元素移动到后面,即做如下变换:

[ a b c d e f g ] -> [ d e f g a b c ]↑                  ↑middle              first

但读者需要注意,rotate函数不会改变序列中各个元素的值,只会改变它们的位置。另外,若中间区间[middle, last)为空,则整个序列不会发生变化;若其包含所有元素,则rotate等效于reverse函数。由于此函数的核心功能是反转数组,所以在使用时需要自行指定一个中心数。

#include <iostream>
#include <vector>
#include <algorithm>using namespace std;void MyPrint(int x) { cout << x << " "; }int main(int argc, char* argv[])
{vector<int> var { 1,2,3,4,5,6,7,8,9,10 };for_each(var.begin(), var.end(), MyPrint);// 以元素6为中心,将两边数据旋转后输出cout << "middle => " << *(var.begin() + 5) << endl;rotate(var.begin(), var.begin() + 5, var.end());for_each(var.begin(), var.end(), MyPrint);cout << endl;// 旋转后复制到iarray数组中存储int iarray[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };rotate_copy(var.begin(), var.begin() + 5, var.end(), iarray);for_each(iarray,iarray+10, MyPrint);system("pause");return 0;
}

8.11 随机数相关算法

Random 是C++11引入的标准库函数,用于生成随机数。该函数库提供了多个随机数引擎和分布函数,可以用于产生各种类型的随机数,例如在给定范围内生成整数或浮点数、生成布尔值等。以下是random库中的一些常用函数:

  • std::mt19937:是一种随机数引擎,使用梅森旋转算法产生高质量的伪随机数。
  • std::uniform_int_distribution:用于生成随机的整数分布,可以指定整数范围。
  • std::uniform_real_distribution:用于生成随机的浮点数分布,可以指定实数范围。
  • std::normal_distribution:用于生成随机的标准正态分布或自定义正态分布。
  • std::bernoulli_distribution:用于模拟一个伯努利分布,即二项分布的情况,可以生成布尔值。

使用random库时,通常先创建一个随机数引擎实例,然后再创建一个特定的分布函数实例,最后利用分布函数实例的调用运算符()来产生随机数。例如:

std::mt19937 gen{std::random_device{}()};
std::uniform_int_distribution<int> dist{1, 10};
int x = dist(gen);  // 在1到10之间生成一个均匀分布的整数

如下案例中实现了简单的生成随机数,以及对随机数进行初始化,其代码中的算法generate_n用于生成随机数,而random_shuffle算法则用于打乱数组。

#include <iostream>
#include <vector>
#include <ctime>
#include <algorithm>
using namespace std;void MyPrint(int x) { cout << x << " "; }int main(int argc, char* argv[])
{// 增加此方法,每次都可以随机打乱srand((unsigned int)time(NULL));vector<int> var(10);// 生成随机数:生成5个随机数,并存入vargenerate_n(var.begin(), 5, rand);for_each(var.begin(), var.end(), MyPrint);cout << endl;// 随机抖动: 随机的打乱一个数组int iarray[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };random_shuffle(iarray, iarray + 10);for_each(iarray, iarray + 10, MyPrint);system("pause");return 0;
}

8.12 容器元素分割算法

Partition 算法函数,用于将给定序列中的元素根据某个条件分为两组,使得满足条件的元素全部在一组,不满足条件的元素在另一组,最终返回第一个不满足条件的元素的位置。具体流程是,首先在序列中选定一个元素作为分界点,然后将序列中的其他元素依次与分界点比较,如果满足条件则移动到左边,否则移动到右边,最终左边的所有元素都满足条件,右边的所有元素都不满足条件。partition函数的用法如下:

template <class ForwardIterator, class UnaryPredicate>
ForwardIterator partition (ForwardIterator first, ForwardIterator last, UnaryPredicate pred);

其中,firstlast是一个前闭后开区间,表示待分割的序列的范围;pred是一个一元谓词函数,用于指定元素满足的条件。函数执行完毕后,返回指向第一个不满足条件的元素的迭代器。

该算法用于重新分割排列容器的元素,第一种无序分割,第二种为有序分割,如下代码是该函数的具体使用案例。

#include <iostream>
#include <vector>
#include <algorithm>using namespace std;void MyPrint(int x) { cout << x << " "; }// 判断是否小于10
bool Less(int y){ return y < 10 ? 1 : 0; }int main(int argc, char* argv[])
{int iarray[10] = { 12,45,2,6,8,-5,-12,-78,-4,3 };// 按照小于10对容器进行分割int * result = partition(iarray, iarray + 10, Less);// 输出小于10的元素for_each(iarray, result , MyPrint);cout << endl;// 按照小于10对容器分割,但保持原来的次序int * new_ret = stable_partition(iarray, iarray + 10, Less);for_each(iarray, iarray + 10, MyPrint);cout << " --> 分界元素 Mid:" << *new_ret << endl;system("pause");return 0;
}

本文作者: 王瑞
本文链接: https://www.lyshark.com/post/83787397.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

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

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

相关文章

CompletableFuture总结和实践

CompletableFuture被设计在Java中进行异步编程。异步编程意味着在主线程之外创建一个独立的线程&#xff0c;与主线程分隔开&#xff0c;并在上面运行一个非阻塞的任务&#xff0c;然后通知主线程进展&#xff0c;成功或者失败。 一、概述 1.CompletableFuture和Future的区别&…

Cesium之水流模型

关于Primitive。 Primitive和Entity&#xff0c;一般翻译成图元和实体&#xff0c;图元更接近底层&#xff0c;实体是封装后的高级对象&#xff0c;使用更加简便。一般来说&#xff0c;Primitive的使用相对繁琐&#xff0c;相比Entity需要使用者自己初始化更多对象&#xff0c…

day9 STM32 I2C总线通信

I2C总线简介 I2C总线介绍 I2C&#xff08;Inter-Integrated Circuit&#xff09;总线&#xff08;也称IIC或I2C&#xff09;是由PHILIPS公司开发的两线式串行总线&#xff0c;用于连接微控制器及其外围设备&#xff0c;是微电子通信控制领域广泛采用的一种总线标准。 它是同步通…

WebGPU应用开发快速入门

WebGPU 是一种全新的现代API,用于在 Web 应用程序中访问 GPU 的功能。在 WebGPU 之前,有 一种WebGL技术,它提供了 WebGPU 功能的子集。 而WebGPU启用了新一类丰富的网络内容,开发人员可以用它构建了令人惊叹的应用。其历史可以追溯到2007 年发布的 OpenGL ES 2.0 API,而该…

【Android】相对布局(RelativeLayout)最全解析

【Android】相对布局&#xff08;RelativeLayout&#xff09;最全解析 一、相对布局&#xff08;RelativeLayout&#xff09;概述二、根据父容器定位三、根据兄弟控件定位 一、相对布局&#xff08;RelativeLayout&#xff09;概述 相对布局&#xff08;RelativeLayout&#x…

【仿写框架之仿写Tomact】四、封装HttpRequest对象(属性映射http请求报文)、HttpResponse对象(属性映射http响应报文)

文章目录 1、创建HttpRequest对象2、创建HttpResponse对象 1、创建HttpRequest对象 HttpRequest对象中的属性与HTTP协议中的内容对应&#xff0c;用于后序servlet从request中获取请求中的参数。 参照http请求报文&#xff1a; import java.io.BufferedReader; import java…

(详解踩坑)GIT版本回滚git stash、git reset、git reset --hard、git revert

目录 背景 一、&#xff08;git log、git reflog&#xff09;查看git提交日志及命令历史 1.1 git log&#xff08;提交日志&#xff09; 1.2 git reflog&#xff08;命令历史&#xff09; 二、git reset&#xff08;回退到指定的版本&#xff0c;并且保留更改&#xff09; …

Vue-9.集成(.editorconfig、.eslintrc.js、.prettierrc)

介绍 同时使用 .editorconfig、.prettierrc 和 .eslintrc.js 是很常见的做法&#xff0c;因为它们可以在不同层面上帮助确保代码的格式一致性和质量。这种组合可以在开发过程中提供全面的代码维护和质量保证。然而&#xff0c;这也可能增加一些复杂性&#xff0c;需要谨慎配置…

Redis消息传递:发布订阅模式详解

目录 1.Redis发布订阅简介 2.发布/订阅使用 2.1 基于频道(Channel)的发布/订阅 2.2 基于模式(pattern)的发布/订阅 3.深入理解Redis的订阅发布机制 3.1 基于频道(Channel)的发布/订阅如何实现的&#xff1f; 3.2 基于模式(Pattern)的发布/订阅如何实现的&#xff1f; 3.3 Sp…

【深入探究人工智能】:常见机器学习算法总结

文章目录 1、前言1.1 机器学习算法的两步骤1.2 机器学习算法分类 2、逻辑回归算法2.1 逻辑函数2.2 逻辑回归可以用于多类分类2.3 逻辑回归中的系数 3、线性回归算法3.1 线性回归的假设3.2 确定线性回归模型的拟合优度3.3线性回归中的异常值处理 4、支持向量机&#xff08;SVM&a…

【SA8295P 源码分析】27 - QNX Ethernet MAC 驱动 之 emac_tx_thread_handler 数据发送线程 源码分析

【SA8295P 源码分析】27 - QNX Ethernet MAC 驱动 之 emac_tx_thread_handler 数据发送线程 源码分析 系列文章汇总见:《【SA8295P 源码分析】00 - 系列文章链接汇总》 本文链接:《【SA8295P 源码分析】27 - QNX Ethernet MAC 驱动 之 emac_tx_thread_handler() 数据发送线程…

如何使用Docker安装AWVS?

前言 还记得很早的时候使用AWVS&#xff0c;还需要找位置&#xff0c;贴补丁&#xff0c;放文件&#xff0c;现在慢慢掌握Docker后发现&#xff0c;使用Docker去部署一些东西就很方便&#xff0c;当然也包括AWVS。 我们今天带大家通过Docker部署AWVS&#xff08;有中文哦&…

React+Typescript 状态管理

好 本文 我们来说说状态管理 也就是我们的 state 我们直接顺便写一个组件 参考代码如下 import * as React from "react";interface IProps {title: string,age: number }interface IState {count:number }export default class hello extends React.Component<I…

python 自动化学习(四) pyppeteer 浏览器操作自动化

背景 之前我在工作中涉及到了很多地方都是重复性的页面点点点工作&#xff0c;又因为安全保密原则不开放接口和数据库&#xff0c;只有一个页面来提供点击进行操作&#xff0c;就想着用前面学的自动化来实现&#xff0c;但发现前面学的模拟操作对浏览器来说并没有那么友好&…

flink配置参数

flink-conf.yaml 基础配置 # jobManager 的IP地址jobmanager.rpc.address: localhost# JobManager 的端口号jobmanager.rpc.port: 6123# JobManager JVM heap 内存大小jobmanager.heap.size: 1024m# TaskManager JVM heap 内存大小taskmanager.heap.size: 1024m# 每个 TaskMan…

安装pyrender和OSMesa

1&#xff09;安装 pyrender Pyrender是一个基于OpenGL的库&#xff0c;可以加载和渲染三维网格、点云、相机等对象3。 pip install pyrender 2&#xff09;理解PyOpenGL和OSMesa的关系是: PyOpenGL是Python的OpenGL绑定库&#xff08;接口壳子&#xff09;,它提供了在Python中…

WPF DataGrid columns表头根据数据集动态动态生成Demo

思路是这样的&#xff0c;数组集合装表头的信息&#xff0c;遍历这个集合&#xff0c;遍历过程中处理一下数据&#xff0c;然后就把每表头信息添加到dataGrid2.Columns.Add(templateColumn); 1&#xff0c;页面Xaml代码&#xff1a; <DataGrid x:Name"dataGrid" …

代码部署到服务器

前言&#xff1a;相信看到这篇文章的小伙伴都或多或少有一些编程基础&#xff0c;懂得一些linux的基本命令了吧&#xff0c;本篇文章将带领大家服务器如何部署一个使用django框架开发的一个网站进行云服务器端的部署。 文章使用到的的工具 Python&#xff1a;一种编程语言&…

uniapp 企业微信侧边栏开发网页授权 注入企业权限 注入应用权限 获取userid(2)

1、网页授权&#xff0c;获取code 代码&#xff1a; oauthUrl() {const that thisuni.removeStorageSync(code)let REDIRECT_URI encodeURIComponent(window.location.href)let CORPID webConfig.appIdlet url https://open.weixin.qq.com/connect/oauth2/authorize?appi…

Flink-----Yarn应用模式作业提交流程

Yarn应用模式作业提交流程 在Yarn当中又分为Session&#xff0c;PerJob&#xff0c;Application&#xff0c;建议和推荐使用独立集群的&#xff0c;其中就包含PerJob 和Application&#xff0c;但是1.17版本的Flink已将PerJob标记为过时&#xff0c;并且Application可以解决Pe…