主頁 > 軟體設計 > B站黑馬c++學習筆記 —— 提高編程篇

B站黑馬c++學習筆記 —— 提高編程篇

2021-12-19 14:44:23 軟體設計

大綱

  • 1 模板
    • 1.1 模板的概念
    • 1.2 函式的模板
      • 1.2.1 函式的模板語法
      • 1.2.2 函式模板注意事項
      • 1.2.3 函式模板案例
      • 1.2.4 普通函式與函式模板的區別
      • 1.2.5 普通函式與函式模板的呼叫規則
      • 1.2.6 模板的局限性
    • 1.3 類模板
      • 1.3.1 類模板語法
      • 1.3.2 類模板與函式模板區別
      • 1.3.3 類模板中成員函式創建時機
      • 1.3.4 類模板物件做函式引數
      • 1.3.5 類模板與繼承
      • 1.3.6 類模板成員函式類外實作
      • 1.3.7 類模板分檔案撰寫
      • 1.3.8 類模板與友元
      • 1.3.9 類模板案例 — 通用陣列
  • 2 STL初識
    • 2.1 STL的誕生
    • 2.2 STL基本概念
    • 2.3 STL六大組件
    • 2.4 STL中容器、演算法、迭代器
    • 2.5 容器、演算法、迭代器初識
      • 2.5.1 vector存放內置資料型別
      • 2.5.2 vector存放自定義資料型別
      • 2.5.3 vector容器嵌套容器
  • 3 STL-常用容器
    • 3.1 string容器
      • 3.1.1 string基本概念
      • 3.1.2 string建構式
      • 3.1.3 string賦值操作
      • 3.1.4 string字串拼接
      • 3.1.5 string查找與替換
      • 3.1.6 string字串比較
      • 3.1.7 string字符存取
      • 3.1.8 string插入與洗掉
      • 3.1.9 string子串
    • 3.2 vector容器
      • 3.2.1 vector基本概念
      • 3.2.2 vector建構式
      • 3.2.3 vector賦值操作
      • 3.2.4 vector容量和大小
      • 3.2.5 vector插入與洗掉
      • 3.2.6 vector資料存取
      • 3.2.7 vector互換容器
      • 3.2.8 vector預留空間
    • 3.3 deque容器
      • 3.3.1 deque容器基本概念
      • 3.3.2 deque建構式
      • 3.3.3 deque賦值操作
      • 3.3.4 deque大小操作
      • 3.3.5 deque插入與洗掉
      • 3.3.6 deque資料存取
      • 3.3.7 deque排序
    • 3.4 案例 -- 評委打分
    • 3.4.1 案例描述
    • 3.4.2 實作步驟
    • 3.4.3 案例實作
    • 3.5 stack容器
      • 3.5.1 stack基本概念
      • 3.5.2 stack常用介面
    • 3.6 queue容器
      • 3.6.1 queue基本概念
      • 3.6.2 queue常用介面
    • 3.7 list容器
      • 3.7.1 list基本概念
      • 3.7.2 list建構式
      • 3.7.3 list賦值與交換
      • 3.7.4 list大小操作
      • 3.7.5 list插入與洗掉
      • 3.7.6 list資料存取
      • 3.7.7 list反轉與排序
      • 3.7.8 list排序案例
    • 3.8 set/multiset容器
      • 3.8.1 set基本概念
      • 3.8.2 set構造和賦值
      • 3.8.3 set大小和交換
      • 3.8.4 set插入與洗掉
      • 3.8.5 set查找和統計
      • 3.8.6 set和multiset區別
      • 3.8.7 pair對組創建
      • 3.8.8 set容器排序
    • 3.9 map/multimap容器
      • 3.9.1 map基本概念
      • 3.9.2 map構造和賦值
      • 3.9.3 map大小和交換
      • 3.9.4 map插入與洗掉
      • 3.9.5 map查找和統計
      • 3.9.6 map容器排序
    • 3.10 案例 -- 員工分組
      • 3.10.1 案例描述
      • 3.10.2 實作步驟
      • 3.10.3 案例實作
  • 4 STL-函式物件
    • 4.1 函式物件
      • 4.1.1 函式物件概念
      • 4.1.2 函式物件使用
    • 4.2 謂詞
      • 4.2.1 謂詞概念
      • 4.2.1 一元謂詞
      • 4.2.1 二元謂詞
    • 4.3 內建函式物件
    • 4.3.1 內建函式物件意義
    • 4.3.2 算術仿函式
    • 4.3.3 關系仿函式
    • 4.3.4 邏輯仿函式
  • 5 STL-常用演算法
    • 5.1 常用遍歷演算法
    • 5.1.1 for_each
    • 5.1.2 transform
    • 5.2 常用查找演算法
      • 5.2.1 find
      • 5.2.2 find_if
      • 5.2.3 adjacent_find
      • 5.2.4 binary_search
      • 5.2.5 count
      • 5.2.6 count_find
    • 5.3 常用排序演算法
      • 5.3.1 sort
      • 5.3.2 random_shuffle
      • 5.3.3 merge
      • 5.3.4 reverse
    • 5.4 常用拷貝和替換演算法
      • 5.4.1 copy
      • 5.4.2 replace
      • 5.4.3 replace_if
      • 5.4.4 swap
    • 5.5 常用算術生成演算法
      • 5.5.1 accumulate
      • 5.5.2 fill
    • 5.6 常用集合演算法
      • 5.6.1 set_intersection
      • 5.6.2 set_union
      • 5.6.3 set_difference

1 模板

1.1 模板的概念

在這里插入圖片描述

1.2 函式的模板

在這里插入圖片描述

1.2.1 函式的模板語法

在這里插入圖片描述

//函式模板
template<typename T>
void mySwap(T &a, T &b) {
	T temp = a;
	a = b;
	b = temp;
}
void test() {
	int a = 1;
	int b = 2;
	string c = "c";
	string d = "d";
	mySwap(a, b);
	//mySwap<int>(a, b); //顯示指定型別
	mySwap(c, d);
	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
	cout << "c = " << c << endl;
	cout << "d = " << d << endl;
}

int main() {	
	test();
	return 0;
}

1.2.2 函式模板注意事項

在這里插入圖片描述

1.2.3 函式模板案例

在這里插入圖片描述

//排序

//交換模板
template<class T>
void mySwap(T &a, T &b) {
	T temp = a;
	a = b;
	b = temp;
}
//排序模板
template<class T>
void mySort(T arr,int len) {
	for (int i = 0; i < len; i++) {
		int max = i;
		for (int j = i + 1; j < len; j++) {
			if (arr[j] > arr[max]) {
				max = j;
			}
		}
		if (max != i) {
			mySwap(arr[max], arr[i]);
		}
	}
}
//列印模板
template<class T>
void myPrint(T arr,int len) {
	for (int i = 0; i < len; i++) {
		cout << arr[i] ;
	}
	cout << endl;
}
void test() {
	int arr1[] = { 1,5,9,0,2,8,4 };
	char arr2[] = "asdwfg";
	int len1;
	int len2;
	len1 = sizeof(arr1) / sizeof(arr1[0]);
	len2 = sizeof(arr2) / sizeof(arr2[0]);
	mySort(arr1, len1);
	myPrint(arr1, len1);
	mySort(arr2,len2);
	myPrint(arr2, len2);
}

int main() {
	test();
	return 0;
}

1.2.4 普通函式與函式模板的區別

在這里插入圖片描述

  • 建議使用顯示指定型別的方式呼叫函式模板
//mySwap(a,b);
mySwap<int>(a, b);

1.2.5 普通函式與函式模板的呼叫規則

在這里插入圖片描述

//強制呼叫函式模板
mySwap<>(a, b);

1.2.6 模板的局限性

//類定義
class person {
public:
	int m_age;
	string m_name;

	person(int age, string name) {
		this->m_age = age;
		this->m_name = name;
	}
};
//普通函式模板
template<class T>
bool myCompare(T &a, T &b) {
	if (a == b) {
		return true;
	}
	else {
		return false;
	}
}
//具體化模板
template<> bool myCompare(person &p1, person &p2) {
	if (p1.m_age == p2.m_age&&p1.m_name == p2.m_name) {
		return true;
	}
	else {
		return false;
	}
}
//列印
void myPrint(bool &ret) {
	if (ret) {
		cout << "相同" << endl;
	}
	else {
		cout << "不同" << endl;
	}
}
void test() {
	person p1 = { 18,"Tom" };
	person p2 = { 28,"Tom" };

	bool ret1 = myCompare(p1, p2);
	myPrint(ret1);
	bool ret2 = myCompare(p1.m_name, p2.m_name);
	myPrint(ret2);
}

int main() {
	test();
	return 0;
}

1.3 類模板

1.3.1 類模板語法

在這里插入圖片描述

template<class nameType, class ageType>
class person{
public:
	nameType m_name;
	ageType m_age;
}

void test(){
	person<string,int> p1("Tom",18);
}

1.3.2 類模板與函式模板區別

在這里插入圖片描述

template<class nameType, class ageType = int>
class person{
public:
	nameType m_name;
	ageType m_age;
}

void test(){
	person<string> p1("Tom",18);
}

1.3.3 類模板中成員函式創建時機

在這里插入圖片描述

1.3.4 類模板物件做函式引數

在這里插入圖片描述

//查看模板引數型別名
cout << typeid(T).name() << endl;
template<class T1, class T2>
class person {
public:
	T1 m_age;
	T2 m_name;

	person(T1 age, T2 name) {
		this->m_age = age;
		this->m_name = name;
	}

	void person_print() {
		cout << this->m_age << endl;
		cout << this->m_name << endl;
	}
};
//指定傳入型別
void myPrint01(person<int, string> &p1) {
	p1.person_print();
}
void test01() {
	person<int, string> p1(18, "Tom");
	myPrint01(p1);
}
//引數模板化
template<class T1,class T2>
void myPrint02(person<T1, T2> &p2) {
	p2.person_print();
	cout << typeid(T1).name() << endl;
}
void test02() {
	person<int, string> p2(28, "Jack");
	myPrint02(p2);
}
//整個類模板化
template<class T>
void myPrint03(T &p3) {
	p3.person_print();
	cout << typeid(T).name() << endl;
}
void test03() {
	person<int, string> p3(38, "John");
	myPrint03(p3);
}

int main() {
	test01();
	test02();
	test03();
	return 0;
}

1.3.5 類模板與繼承

在這里插入圖片描述

//父類
template<class T>
class Base {
public:
	T m;
};
//子類
template<class T1,class T2>
class Son :public Base<T1> {
public:
	T2 n;
	Son() {
		cout << typeid(T1).name() << endl;
		cout << typeid(T2).name() << endl;
	}
};
void test() {
	Son<int, string> s1;
}

int main() {
	test();
	return 0;
}

1.3.6 類模板成員函式類外實作

template<class T1, class T2>
class person {
public:
	T1 m_age;
	T2 m_name;

	person(T1 age, T2 name);
	void person_print();
};
//建構式的類外實作
template<class T1, class T2>
person<T1, T2>::person(T1 age, T2 name) {
	this->m_age = age;
	this->m_name = name;
}
//成員函式的類外實作
template<class T1, class T2>
void person<T1, T2>::person_print() {
	cout << this->m_age << endl;
	cout << this->m_name << endl;
}
void test() {
	person<int, string> p1(18,"Tom");
	p1.person_print();
}

int main() {
	test();
	return 0;
}

1.3.7 類模板分檔案撰寫

在這里插入圖片描述

  • tree.hpp
#pragma once
#include<iostream>
#include<string>

using namespace std;

template<class T1, class T2>
class tree {
public:
	T1 m_age;
	T2 m_name;

	tree(T1 age, T2 name);
	void tree_print();
};

//建構式的類外實作
template<class T1, class T2>
tree<T1, T2>::tree(T1 age, T2 name) {
	this->m_age = age;
	this->m_name = name;
}
//成員函式的類外實作

template<class T1, class T2>
void tree<T1, T2>::tree_print() {
	cout << this->m_age << endl;
	cout << this->m_name << endl;
}
  • main.cpp
#include"tree.hpp"

void test() {
	tree<int, string> t1(180,"銀杏");
	t1.tree_print();
}

int main() {
	test();
	return 0;
}

1.3.8 類模板與友元

在這里插入圖片描述

template<class T1, class T2>
class person;
//提前宣告全域函式
template<class T1, class T2>
void person_print2(person<T1, T2> p) {
	cout << " 類外實作 " << p.m_name << endl;
}

template<class T1, class T2>
class person {
	//全域函式類內實作
	friend void person_print1(person<T1,T2> p) {
		cout << " 類內實作 " << p.m_name << endl;
	}
	//全域函式類外實作
	friend void person_print2<>(person<T1, T2> p);
public:
	person(T1 age, T2 name) {
		this->m_age = age;
		this->m_name = name;
	}
private:
	T1 m_age;
	T2 m_name;
};

void test() {
	//類內
	person<int, string> p1(18,"Tom");
	person_print1(p1);
	//類外
	person<int, string> p2(28, "Rose");
	person_print2(p2);
}

int main() {
	test();
	return 0;
}

1.3.9 類模板案例 — 通用陣列

在這里插入圖片描述

  • main.cpp
class person {
public:
	string m_name;
	int m_age;
	person() {};
	person(string name, int age) {
		this->m_name = name;
		this->m_age = age;
	}
};

void printArray(myArray<person> & arr) {
	for (int i = 0; i < arr.get_size(); i++) {
		cout << arr[i].m_name << "\n" << arr[i].m_age << endl;
	}
}

void test() {
	myArray<person> arr1(3);
	person p1("A", 18);
	person p2("B", 28);
	person p3("C", 38);

	arr1.push_back(p1);
	arr1.push_back(p2);
	arr1.push_back(p3);

	printArray(arr1);
}

int main() {
	test();
	return 0;
}
  • myArray.hpp
#pragma once
#include<iostream>
#include<string>
using namespace std;

template<class T>
class myArray {
public:
	myArray(int capacity) {
		//cout << "有參構造" << endl;
		this->m_Capacity = capacity;
		this->m_size = 0;
		this->pAddress = new T[this->m_Capacity];
	}

	myArray(const myArray & arr) {
		//cout << "拷貝構造" << endl;
		this->m_Capacity = arr.m_Capacity;
		this->m_size = arr.m_size;
		//this->pAddress = arr.pAddress; //淺拷貝 堆區資料會重復釋放
		this->pAddress = new T[arr.m_Capacity];	//深拷貝
		for (int i = 0; i < this->m_size; i++) {
			this->pAddress[i] = arr.pAddress[i];
		}
	}

	myArray & operator=(const myArray & arr) {
		//cout << "operator=構造" << endl;
		if (this->pAddress != NULL) {
			delete[] this->pAddress;
			this->pAddress = NULL;
			this->m_Capacity = 0;
			this->m_size = 0;
		}
		this->m_Capacity = arr.m_Capacity;
		this->m_size = arr.m_size;
		this->pAddress = new T[arr.m_Capacity];
		for (int i = 0; i < this->m_size; i++) {
			this->pAddress[i] = arr.pAddress[i];
		}
		return *this;
	}
	//尾插法
	void push_back(const T & val) {
		//判斷是否有容量
		if (this->m_size == this->m_Capacity) {
			return;
		}
		//插入資料
		this->pAddress[this->m_size] = val;
		//更新陣列大小
		this->m_size++;
	}
	//尾刪法
	void pop_back() {
		//判斷是否有資料
		if (this->m_size == 0) {
			return;
		}
		//讓用戶訪問不到該元素,邏輯洗掉
		this->m_size--;
	}
	//下標訪問資料
	T& operator[](int index) {
		return this->pAddress[index];
	}
	//獲取陣列容量
	int get_Capacity() {
		return this->m_Capacity;
	}
	//獲取陣列大小
	int get_size() {
		return this->m_size;
	}

	~myArray() {
		//cout << "解構式" << endl;
		if (this->pAddress != NULL) {
			delete[] this->pAddress;
			this->pAddress = NULL;
		}
	}
private:
	//堆區陣列指標
	T * pAddress;
	//陣列容量
	int m_Capacity;
	//陣列大小
	int m_size;
};

2 STL初識

2.1 STL的誕生

在這里插入圖片描述

2.2 STL基本概念

在這里插入圖片描述

2.3 STL六大組件

在這里插入圖片描述

2.4 STL中容器、演算法、迭代器

在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述

2.5 容器、演算法、迭代器初識

2.5.1 vector存放內置資料型別

在這里插入圖片描述

#include<vector>
#include<algorithm> //標準演算法頭檔案

void myPrint(int val) {
	cout << val << endl;
}

void test() {
	vector<int> v1;
	//尾插資料
	v1.push_back(1);
	v1.push_back(2);
	v1.push_back(3);
	//第一種遍歷
	vector<int>::iterator itBegin = v1.begin();	//起始迭代器 指向容器中第一個元素
	vector<int>::iterator itEnd = v1.end();		//結束迭代器 指向容器中最后一個元素的下一個位置
	while (itBegin != itEnd) {
		myPrint(*itBegin);
		itBegin++;
	}
	//第二種遍歷
	for (vector<int>::iterator it = v1.begin(); it != v1.end(); it++) {
		myPrint(*it);
	}
	//第三種遍歷 利用STL提供的遍歷演算法
	for_each(v1.begin(), v1.end(), myPrint);
}

int main() {
	test();
	return 0;
}

2.5.2 vector存放自定義資料型別

在這里插入圖片描述

#include<vector>

class person {
public:
	string m_name;
	int m_age;

	person(string name,int age) {
		this->m_name = name;
		this->m_age = age;
	}
};

void myPrint(person &p) {
	cout << p.m_name << "\t" << p.m_age << endl;
}

void test() {
	//自定義資料型別
	vector<person> p;
	person p1("張三", 18);
	person p2("李四", 28);
	person p3("王五", 38);

	p.push_back(p1);
	p.push_back(p2);
	p.push_back(p3);

	for (vector<person>::iterator it1 = p.begin(); it1 != p.end(); it1++) {
		myPrint(*it1);
		//cout << it1->m_name << "\t" << it1->m_age << endl;
	}
	
	//自定義資料指標
	vector<person*> v;
	person p4("張三", 19);
	person p5("李四", 29);
	person p6("王五", 39);

	v.push_back(&p4);
	v.push_back(&p5);
	v.push_back(&p6);

	for (vector<person*>::iterator it2 = v.begin(); it2 != v.end(); it2++) {
		myPrint(**it2);
		//cout << (*it2)->m_name << "\t" << (*it2)->m_age << endl;
	}
}

int main() {
	test();
	return 0;
}

2.5.3 vector容器嵌套容器

在這里插入圖片描述

#include<vector>

void test() {
	vector<vector<int>> v;
	vector<int> v1;
	vector<int> v2;
	vector<int> v3;
	for (int i = 0; i < 10; i++) {
		v1.push_back(i);
		v2.push_back(i * 10 + 1);
		v3.push_back((i + 2) * 7);
	}
	v.push_back(v1);
	v.push_back(v2);
	v.push_back(v3);

	for (vector<vector<int>>::iterator it1 = v.begin(); it1 != v.end(); it1++) {
		//(*it1) -- 容器 vector<int>
		for (vector<int>::iterator it2 = (*it1).begin(); (it2) != (*it1).end(); it2++) {
			cout << *it2 << "\t";
		}
		cout << endl;
	}
}

int main() {
	test();
	return 0;
}

3 STL-常用容器

3.1 string容器

3.1.1 string基本概念

在這里插入圖片描述

3.1.2 string建構式

在這里插入圖片描述

void test() {
	//string()
	string s1;
	//string(const char* s)
	const char* str = "hello world";
	string s2(str);
	//string(const string& str)
	string s3(s2);
	//string(int n,char c)
	string s4(5, 'a');

	cout << s1 << endl
		<< s2 << endl
		<< s3 << endl
		<< s4 << endl;
}

int main() {
	test();
	return 0;
}

3.1.3 string賦值操作

在這里插入圖片描述

void test() {
	string str1;
	str1.assign("hello world");
	cout << str1 << endl;

	//把前n個字符賦值
	string str2;
	str2.assign("hello world", 8);
	cout << str2 << endl;
}

int main() {
	test();
	return 0;
}

3.1.4 string字串拼接

在這里插入圖片描述

void test() {
	string str1 = "~$root:";
	str1 += "zxy";
	cout << str1 << endl;

	string str2 = ":";
	str1 += str2;
	cout << str1 << endl;
	//截取字串的前 n 個添加
	str1.append("sudo apt-get install ros-kinetic-moveit",10);
	cout << str1 << endl;
	//截取字串的第 m 到第 n 個添加
	string str3 = "sudo apt-get install ros-kinetic-moveit";
	str1.append(str3, 10,-1);
	cout << str1 << endl;
}

int main() {
	test();
	return 0;
}

3.1.5 string查找與替換

在這里插入圖片描述

void test() {
	string str = "abcdab";
	//如果找到 回傳字串首位置,未找到回傳值-1
	int pos;
	//find	從左往右第一次出現的位置
	pos = str.find("ab");
	cout << "find : " << pos << endl;
	//rfind	從右往左第一次出現的位置
	pos = str.rfind("ab");
	cout << "rfind: " << pos << endl;
	//str.replace(替換的起始位置<從0開始>, 替換的個數, 替換后的內容);
	string str2 = " ab ** ab ";
	str.replace(2, 2, str2);
	cout << str << endl;
}

int main() {
	test();
	return 0;
}

3.1.6 string字串比較

在這里插入圖片描述

string str1 = "abc";
string str2 = "bbc";
int ret = str1.compare(str2);

3.1.7 string字符存取

在這里插入圖片描述

void test() {
	string str1 = "abcdefg";

	//通過[]、at訪問單個字符
	for (int i = 0; i < str1.size(); i++) {
		cout << str1[i] ;
		cout << str1.at(i) ;
	}

	//通過[]、at修改單個字符
	for (int i = 0; i < str1.size(); i++) {
		//str1[i] = 'x';
		str1.at(i) = 'x';
	}
	cout << str1 << endl;
}

int main() {
	test();
	return 0;
}

3.1.8 string插入與洗掉

在這里插入圖片描述

void test() {
	string str1 = "abcde";
	string str2 = "123";

	//從第2號位置插入字串str2<插入字串后的首位置為2>
	str1.insert(2, str2);
	cout << str1 << endl;

	//洗掉第2號位置起的3個字符
	str1.erase(2, 3);
	cout << str1 << endl;
}

int main() {
	test();
	return 0;
}

3.1.9 string子串

在這里插入圖片描述

void test() {
	string email = "zhangsan@qq.com";
	
	int pos = email.find('@');
	
	//從第0號位置開始,截取pos個字符
	string sub_name = email.substr(0, pos);
	cout << sub_name << endl;
}

int main() {
	test();
	return 0;
}

3.2 vector容器

3.2.1 vector基本概念

在這里插入圖片描述
在這里插入圖片描述

3.2.2 vector建構式

在這里插入圖片描述

#include<vector>

void printVector(vector<int> &v) {
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
		cout << *it << " " ;
	}
	cout << endl;
}

void test() {
	//默認無參構造
	vector<int> v1;
	for (int i = 0; i < 10; i++) {
		v1.push_back(i * 6 + 8);
	}
	printVector(v1);
	//通過區間構造
	vector<int> v2(v1.begin(), v1.end());
	printVector(v2);
	//通過 n 個 elem 構造(元素個數,元素值)
	vector<int> v3(10,100);
	printVector(v3);
	//通過拷貝構造
	vector<int> v4(v3);
	printVector(v4);
}

int main() {
	test();
	return 0;
}

3.2.3 vector賦值操作

在這里插入圖片描述

	vector<int> v1;
	for (int i = 0; i < 10; i++) {
		v1.push_back(i * 6 + 8);
	}


	vector<int> v2;
	v2 = v1;
	
	vector<int> v3;
	v3.assign(v1.begin(), v1.end());

	vector<int> v4;
	v4.assign(10,100);

3.2.4 vector容量和大小

在這里插入圖片描述

#include<vector>

void printVector(vector<int> &v) {
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
		cout << *it << " " ;
	}
	cout << endl;
	cout << "v1的容量為: " << v.capacity() << endl;
	cout << "v1的大小為: " << v.size() << endl;
}

void test() {
	vector<int> v1;
	for (int i = 0; i < 10; i++) {
		v1.push_back(i * 9 + 8);
	}
	//判斷是否為空
	if (v1.empty()) {
		cout << "v1 is empty" << endl;
	}
	else {
		printVector(v1);
		//重新指定容器大小,(容器大小,填充值(默認為0))
		v1.resize(15,100);
		printVector(v1);
		v1.resize(5);
		printVector(v1);
	}
}

int main() {
	test();
	return 0;
}

3.2.5 vector插入與洗掉

在這里插入圖片描述

#include<vector>

void printVector(vector<int> &v) {
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

void test() {
	vector<int> v1;
	//尾插
	for (int i = 0; i < 10; i++) {
		v1.push_back(i * 8 + 8);
	}
	printVector(v1);
	//尾刪
	v1.pop_back();
	printVector(v1);
	//insert(位置迭代器,插入個數(默認1個),插入值)
	v1.insert(v1.begin() + 1, 2, 99);
	printVector(v1);
	//洗掉
	v1.erase(v1.begin() + 2);
	printVector(v1);
	//清空
	v1.clear();
	printVector(v1);
}

int main() {
	test();
	return 0;
}

3.2.6 vector資料存取

在這里插入圖片描述

#include<vector>

void test() {
	vector<int> v1;
	for (int i = 0; i < 10; i++) {
		v1.push_back(i * 11 + 45);
	}
	//利用[]訪問陣列元素
	for (int i = 0; i < v1.size(); i++) {
		cout << v1[i] << " ";
	}
	cout << endl;
	//利用at訪問陣列元素
	for (int i = 0; i < v1.size(); i++) {
		cout << v1.at(i) << " ";
	}
	cout << endl;
	//獲取第一個元素
	cout << "第一個元素  : " << v1.front() << endl;
	//獲取最后一個元素
	cout << "最后一個元素: " << v1.back() << endl;
}

int main() {
	test();
	return 0;
}

3.2.7 vector互換容器

在這里插入圖片描述

#include<vector>

void printVector(vector<int> &v,string index) {
	cout << index << ": ";
	for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
		cout << *it << " " ;
	}
	cout << endl;
}

void test() {
	vector<int> v1;
	for (int i = 0; i < 10; i++) {
		v1.push_back(i * 13 + 24);
	}
	printVector(v1,"v1");
	vector<int> v2;
	for (int i = 0; i < 10; i++) {
		v2.push_back(i * 56 + 2);
	}
	printVector(v2, "v2");
	//容器元素互換
	v1.swap(v2);
	printVector(v1, "v1");
	printVector(v2, "v2");
	
	//收縮記憶體
	vector<int> v3;
	for (int i = 0; i < 1000; i++) {
		v3.push_back(i * 13 + 24);
	}
	cout << "v3的容量為: " << v3.capacity() << endl;
	cout << "v3的大小為: " << v3.size() << endl;
	v3.resize(10);
	cout << "v3的容量為: " << v3.capacity() << endl;
	cout << "v3的大小為: " << v3.size() << endl;
	//vector<int>(v3)為匿名物件,系統自動回收
	vector<int>(v3).swap(v3);
	cout << "v3的容量為: " << v3.capacity() << endl;
	cout << "v3的大小為: " << v3.size() << endl;
}

int main() {
	test();
	return 0;
}

3.2.8 vector預留空間

在這里插入圖片描述

#include<vector>

void test() {
	vector<int> v1;
	int num = 0;
	int * p = NULL;
	for (int i = 0; i < 1000; i++) {
		v1.push_back(i);
		//如果重新開辟了記一次
		if (p != &v1[0]) {
			p = &v1[0];
			num++;
		}
	}
	cout << "v1開辟記憶體空間次數: " << num << endl;

	vector<int> v2;
	v2.reserve(1000);
	int re_num = 0;
	int * re_p = NULL;
	for (int i = 0; i < 1000; i++) {
		v2.push_back(i);
		//如果重新開辟了記一次
		if (re_p != &v2[0]) {
			re_p = &v2[0];
			re_num++;
		}
	}
	cout << "v2開辟記憶體空間次數: " << re_num << endl;
}

int main() {
	test();
	return 0;
}

3.3 deque容器

3.3.1 deque容器基本概念

在這里插入圖片描述
在這里插入圖片描述

3.3.2 deque建構式

在這里插入圖片描述

#include<deque>

void printDeque(const deque<int>& d) {
	for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {
		//*it = 100;	//常量需要使用const_iterator
		cout << *it << " ";
	}
	cout << endl;
}

void test() {
	deque<int> d1;
	for (int i = 0; i < 10; i++) {
		d1.push_back(i * 11);
		d1.push_front(i * 10);
	}
	printDeque(d1);

	deque<int> d2(d1.begin() + 1, d1.end()-1);
	printDeque(d2);

	deque<int> d3(20,99);
	printDeque(d3);

	deque<int> d4(d3);
	printDeque(d4);
}

int main() {
	test();
	return 0;
}

3.3.3 deque賦值操作

在這里插入圖片描述

3.3.4 deque大小操作

在這里插入圖片描述

3.3.5 deque插入與洗掉

在這里插入圖片描述

	deque<int> d1;
	deque<int> d2;
	//在指定位置插入區間值
	d1.insert(d1.begin(),d2.begin(),d2.end())

3.3.6 deque資料存取

在這里插入圖片描述

3.3.7 deque排序

在這里插入圖片描述

#include<deque>
#include<algorithm>

void printDeque(const deque<int>& d) {
	for (int i = 0; i < d.size(); i++) {
		cout << d[i] << " ";
	}
	cout << endl;
}

void test() {
	deque<int> d1;
	for (int i = 0; i < 10; i++) {
		d1.push_back(i * 11);
		d1.push_front(i * 10);
	}
	printDeque(d1);
	//默認由小到大排序
	//支持隨機訪問的迭代器的容器,都可以利用sort進行排序
	sort(d1.begin(), d1.end());
	printDeque(d1);
}

int main() {
	test();
	return 0;
}

3.4 案例 – 評委打分

3.4.1 案例描述

在這里插入圖片描述

3.4.2 實作步驟

在這里插入圖片描述

3.4.3 案例實作

#include<vector>
#include<algorithm>
#include<deque>
#include<ctime>

class player {
public:
	int m_id;			//編號
	int m_score;		//平均分
	deque<int> score;	//所有評分

	player(int m_id,int m_score){
		this->m_id = m_id;
		this->m_score = m_score;
	}
	void printScore() {
		for (int i = 0; i < 10; i++) {
			cout << this->score[i] << " ";
		}
		cout << endl;
	}
};

void pushPlayer(vector<player> &play) {
	for (int i = 0; i < 5; i++) {
		player p(i + 1, 0);
		play.push_back(p);
	}
}

void test() {
	vector<player> play;
	play.reserve(5);
	//選手參加
	pushPlayer(play);

	srand((unsigned int)time(NULL));
	for (vector<player>::iterator it = play.begin(); it != play.end(); it++) {
		for (int i = 0; i < 10; i++) {
			//打分
			//rand() % 41 為0 ~ 40
			int score_rand = rand() % 41 + 60;
			it->score.push_back(score_rand);
		}
		//對成績進行排序
		sort(it->score.begin(), it->score.end());
		it->printScore();
		//去掉最高分和最低分
		it->score.pop_back();
		it->score.pop_front();
		//求平均分
		int sum = 0;
		for (int i = 0; i < it->score.size(); i++) {
			sum += it->score[i];
		}
		int avg = sum / it->score.size();
		it->m_score = avg;
		cout << "id: " << it->m_id << " 成績為: " << it->m_score << endl << endl;
	}
}

int main() {
	test();
	return 0;
}

3.5 stack容器

3.5.1 stack基本概念

在這里插入圖片描述
在這里插入圖片描述

  • 堆疊不允許有遍歷行為
  • 堆疊可以判斷容器是否為空 empty()
  • 堆疊可以回傳元素個數 size()

3.5.2 stack常用介面

在這里插入圖片描述

#include<stack>

void test() {
	stack<int> s;
	for (int i = 0; i < 5; i++) {
		s.push(i * 4 + 1);
	}
	cout << "出堆疊前堆疊的大小: " << s.size() << endl;
	while (!s.empty()) {
		//查看堆疊頂元素
		cout << s.top() << endl;
		//出堆疊
		s.pop();
	}
	cout << "出堆疊后堆疊的大小: " << s.size() << endl;
}

int main() {
	test();
	return 0;
}

3.6 queue容器

3.6.1 queue基本概念

在這里插入圖片描述

  • 佇列不允許有遍歷行為
  • 佇列可以判斷容器是否為空 empty()
  • 佇列可以回傳元素個數 size()

3.6.2 queue常用介面

在這里插入圖片描述

#include<queue>

void test() {
	queue<int> q;
	for (int i = 0; i < 5; i++) {
		q.push(i * 7 + 2);
	}
	while (!q.empty()) {
		cout << "佇列的隊頭: " << q.front() << endl;
		cout << "佇列的隊尾: " << q.back() << endl;
		q.pop();
	}
	cout << "" << q.size() << endl;
}

int main() {
	test();
	return 0;
}

3.7 list容器

3.7.1 list基本概念

在這里插入圖片描述
在這里插入圖片描述

  • 鏈表可以在任意位置進行快速的插入或洗掉元素
  • 鏈表動態分配存盤,不會造成記憶體浪費
  • 鏈表遍歷速度慢
  • 鏈表占用空間大
    在這里插入圖片描述
  • List鏈表中,插入和洗掉元素不會造成原有list迭代器的失效,而vector是不成立的(記憶體滿了之后另開一處空間進行存盤)

3.7.2 list建構式

在這里插入圖片描述

#include<list>

void printList(const list<int> &L) {
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

void test() {
	//默認構造
	list<int> L1;
	for (int i = 0; i < 10; i++) {
		L1.push_back(i * 2 + 3);
	}
	printList(L1);
	//區間構造
	list<int> L2(L1.begin(), L1.end());
	printList(L2);
	//拷貝構造
	list<int> L3(L2);
	printList(L3);
}

int main() {
	test();
	return 0;
}

3.7.3 list賦值與交換

在這里插入圖片描述

3.7.4 list大小操作

在這里插入圖片描述

3.7.5 list插入與洗掉

在這里插入圖片描述

#include<list>

void printList(const list<int> &L) {
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

void test() {
	list<int> L1;
	for (int i = 0; i < 10; i++) {
		L1.push_back(i % 2 );
	}
	printList(L1);
	//insert插入
	L1.insert(++L1.begin(), 2, 3);
	printList(L1);
	//erase洗掉
	L1.erase(++L1.begin());
	printList(L1);
	//remove洗掉,洗掉容器中所有指定的元素值
	L1.remove(0);
	printList(L1);
}

int main() {
	test();
	return 0;
}

3.7.6 list資料存取

在這里插入圖片描述

3.7.7 list反轉與排序

在這里插入圖片描述

#include<list>

void printList(const list<int> &L) {
	for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

//排序的判斷函式
bool myCompare(int v1, int v2) {
	return v1 > v2;
}

void test() {
	list<int> L1;
	for (int i = 0; i < 10; i++) {
		L1.push_back((i % 2) * 6 + i);
	}
	printList(L1);

	L1.reverse();
	cout << "反轉后的鏈表: " << endl;
	printList(L1);

	L1.sort();//默認升序
	cout << "排序后的鏈表: " << endl;
	printList(L1);

	//降序排列操作
	L1.sort(myCompare);
	printList(L1);

	//所有不支持隨機訪問迭代器的容器,不可以用標準演算法(eg:sort())(全域函式)
	//不支持隨機訪問迭代器的容器,內部會提供對應的演算法(成員函式)
}

int main() {
	test();
	return 0;
}

3.7.8 list排序案例

在這里插入圖片描述

#include<list>
#include<ctime>

class person {
public:
	string m_name;
	int m_age;
	int m_height;
	person() {};
	person(string name, int age,int height) {
		this->m_name = name;
		this->m_age = age;
		this->m_height = height;
	}
};
//創建物件
void creatPerson(list<person> &L,int num) {
	string nameSeed = "ABCDEFGHIJK";
	for (int i = 0; i < num; i++) {
		person p;
		p.m_name += nameSeed[i];
		p.m_age = 20 + rand() % 5;
		p.m_height = 180 + rand() % 10;

		L.push_back(p);
	}
}
//列印資訊
void printList(const list<person> &L) {
	for (list<person>::const_iterator it = L.begin(); it != L.end(); it++) {
		cout << "姓名: " << (*it).m_name << " 年齡: " << (*it).m_age << " 身高: " << (*it).m_height << endl;
	}
}
//排序規則
bool myCompare(person &p1,person &p2) {
	//如果年齡不同,進行升序排列
	if (p1.m_age != p2.m_age) {
		return p1.m_age < p2.m_age;
	}
	//如果年齡相同,對身高進行降序排列
	else {
		return p1.m_height > p2.m_height;
	}
}

void test() {
	srand((unsigned int)time(NULL));

	list<person> L1;
	creatPerson(L1, 10);

	cout << "排序前:" << endl;
	printList(L1);

	cout << "排序后:" << endl;
	L1.sort(myCompare);
	printList(L1);
}

int main() {
	test();
	return 0;
}

3.8 set/multiset容器

3.8.1 set基本概念

在這里插入圖片描述

3.8.2 set構造和賦值

在這里插入圖片描述

#include<set>
#include<ctime>

void printSet(const set<int> &s) {
	for (set<int>::const_iterator it = s.begin(); it != s.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}
void printSet(const multiset<int> &s) {
	for (multiset<int>::const_iterator it = s.begin(); it != s.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;
}

void test() {
	srand((unsigned)time(NULL));
	set<int> s1;
	for (int i = 0; i < 20; i++) {
		//插入資料只能用insert
		s1.insert(rand() % 10);
	}
	//set容器不允許重復的值插入
	printSet(s1);
	
	multiset<int> s2;
	for (int i = 0; i < 20; i++) {
		s2.insert(rand() % 10);
	}
	//multiset容器允許重復的值插入
	printSet(s2);
}

int main() {
	test();
	return 0;
}

3.8.3 set大小和交換

在這里插入圖片描述

3.8.4 set插入與洗掉

在這里插入圖片描述

3.8.5 set查找和統計

在這里插入圖片描述

#include<set>
#include<ctime>

void test() {
	srand((unsigned)time(NULL));

	set<int> s1;
	for (int i = 0; i < 20; i++) {
		s1.insert(rand() % 10);
	}
	//找到元素回傳其迭代器位置,沒找到回傳set.end()位置
	set<int>::iterator pos = s1.find(5);
	if (pos != s1.end()) {
		cout << "找到了" << endl;
	}
	else {
		cout << "沒有找到" << endl;
	}

	multiset<int> s2;
	for (int i = 0; i < 20; i++) {
		s2.insert(rand() % 10);
	}
	//回傳元素的個數
	//對于set而言結果只有0或1
	int num = s2.count(5);
	cout << "元素個數為: " << num << endl;
}

int main() {
	test();
	return 0;
}

3.8.6 set和multiset區別

在這里插入圖片描述

#include<set>
#include<ctime>

void test() {
	srand((unsigned)time(NULL));

	set<int> s1;
	for (int i = 0; i < 10; i++) {
		pair<set<int>::iterator, bool> ret = s1.insert(rand() % 10);
		if (ret.second) {
			cout << "資料插入成功  " << *ret.first << endl;
		}
		else {
			cout << "資料插入失敗  " << *ret.first << endl;
		}
	}

	multiset<int> s2;
	for (int i = 0; i < 20; i++) {
		s2.insert(rand() % 10);
	}
}

int main() {
	test();
	return 0;
}

3.8.7 pair對組創建

在這里插入圖片描述

void test() {
	//第一種
	pair<int, string> p1(1, "a");
	cout << p1.first << " " << p1.second << endl;
	//第二種
	pair<int, string> p2 = make_pair(2, "b");
	cout << p2.first << " " << p2.second << endl;
}

int main() {
	test();
	return 0;
}

3.8.8 set容器排序

在這里插入圖片描述

#include<set>

class person {
public:
	string m_name;
	int m_age;
	int m_height;
	person() {};
	person(string name, int age, int height) {
		this->m_name = name;
		this->m_age = age;
		this->m_height = height;
	}
};

//仿函式建立排序規則
class myCompare1 {
public:
	bool operator()(int v1, int v2) {
		return v1 > v2;
	}
};
class myCompare2 {
public:
	bool operator()(const person &p1, const person &p2) {
		if (p1.m_age == p2.m_age) {
			return p1.m_height > p2.m_height;
		}
		else {
			return p1.m_age > p2.m_age;
		}
	}
};
//創建物件
void creatPerson(int num, set<person, myCompare2> &s) {
	string nameSeed = "ABCDEFGHIJKLMN";
	for (int i = 0; i < num; i++) {
		person p;
		p.m_name += nameSeed[i];
		p.m_age = 20 + rand() % 10;
		p.m_height = 170 + rand() % 10;
		s.insert(p);
	}
}
//列印資訊
void printSet(set<person, myCompare2> &s) {
	for (set<person, myCompare2>::iterator it = s.begin(); it != s.end(); it++) {
		cout << " 姓名: " << (*it).m_name << " 年齡: " << (*it).m_age << " 身高: " << (*it).m_height << endl;
	}
}

void test() {
	//內置資料型別
	//排序規則在插入資料之前
	set<int, myCompare1> s1;
	for (int i = 0; i < 20; i++) {
		s1.insert(rand() % 10);
	}
	for (set<int, myCompare1>::iterator it = s1.begin(); it != s1.end(); it++) {
		cout << *it << " ";
	}
	cout << endl;

	//自定義資料型別
	set<person, myCompare2> s2;
	creatPerson(9, s2);
	printSet(s2);
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

3.9 map/multimap容器

3.9.1 map基本概念

在這里插入圖片描述

3.9.2 map構造和賦值

在這里插入圖片描述

#include<map>

void printMap(const map<int, int> &m) {
	for (map<int, int>::const_iterator it = m.begin(); it != m.end(); it++) {
		cout << it->first << "\t" << it->second << endl;
	}
}

void test() {
	map<int, int> m1;
	for (int i = 0; i < 10; i++) {
		//插入元素要使用對組pair
		m1.insert(pair<int, int>(i, rand() % 41 + 60));
	}
	printMap(m1);
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

3.9.3 map大小和交換

在這里插入圖片描述

3.9.4 map插入與洗掉

在這里插入圖片描述

#include<map>

void printMap(const map<int, int> &m) {
	for (map<int, int>::const_iterator it = m.begin(); it != m.end(); it++) {
		cout << it->first << "\t" << it->second << endl;
	}
}

void test() {
	map<int, int> m1;
	//第一種
	m1.insert(pair<int, int>(5, 10));
	//第二種
	m1.insert(make_pair(4, 20));
	//第三種
	m1.insert(map<int, int>::value_type(3, 30));
	//第四種 不建議用于插入資料 可以用于讀取value值
	//m1[2] = 40;
	//cout << m1[3] << endl;
	printMap(m1);

	m1.erase(m1.begin());
	printMap(m1);
	//根據key值進行洗掉
	m1.erase(4);
	printMap(m1);

	m1.erase(m1.begin(),m1.end());
	printMap(m1);
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

3.9.5 map查找和統計

在這里插入圖片描述

3.9.6 map容器排序

在這里插入圖片描述

#include<map>

class mapCompare {
public:
	bool operator()(int v1, int v2) {
		return v1 > v2;
	}
};

void printMap(const map<int, int, mapCompare> &m) {
	for (map<int, int, mapCompare>::const_iterator it = m.begin(); it != m.end(); it++) {
		cout << it->first << "\t" << it->second << endl;
	}
}

void test() {
	map<int, int, mapCompare> m1;
	for (int i = 0; i < 10; i++) {
		m1.insert(make_pair(i, rand() % 41 + 60));
	}
	printMap(m1);
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

3.10 案例 – 員工分組

3.10.1 案例描述

在這里插入圖片描述

3.10.2 實作步驟

在這里插入圖片描述

3.10.3 案例實作

#include<vector>
#include<map>
#include<ctime>
#define CEHUA 0
#define MEISHU 1
#define YANFA 2

class stuff {
public:
	string m_name;
	int m_salary;
	stuff() {};
	stuff(string name, int salary) {
		this->m_name = name;
		this->m_salary = salary;
	}
};
//員工資訊填入
void creatStuff(vector<stuff> &v) {
	string nameSeed = "ABCDEFGHIJ";
	for (int i = 0; i < 10; i++) {
		stuff s;
		s.m_name += nameSeed[i];
		s.m_salary = 5000 + (rand() % 10) * 500;
		v.push_back(s);
	}
}
//列印員工資訊
void printStuff(const multimap<int, stuff> &m) {
		cout << "------------------------" << endl;
		cout << "策劃部門:" << endl;
		multimap<int, stuff>::const_iterator pos = m.find(CEHUA);//策劃第一個人位置
		int num = m.count(CEHUA);//策劃組人數
		int index = 0;
		for (; pos != m.end() && index < num; pos++, index++) {
				cout << "姓名:" << pos->second.m_name << "   工資:" << pos->second.m_salary << endl;
		}

		cout << "------------------------" << endl;
		cout << "美術部門:" << endl;
		pos = m.find(MEISHU);
		num = m.count(MEISHU);
		index = 0;
		for (; pos != m.end() && index < num; pos++, index++) {
			cout << "姓名:" << pos->second.m_name << "   工資:" << pos->second.m_salary << endl;
		}

		cout << "------------------------" << endl;
		cout << "研發部門:" << endl;
		pos = m.find(YANFA);
		num = m.count(YANFA);
		index = 0;
		for (; pos != m.end() && index < num; pos++, index++) {
			cout << "姓名:" << pos->second.m_name << "   工資:" << pos->second.m_salary << endl;
		}
}
//分配部門
void allocateDepart(const vector<stuff> &v, multimap<int, stuff> &m) {

	for (vector<stuff>::const_iterator it = v.begin(); it != v.end(); it++) {
		m.insert(make_pair(rand() % 3 , *it));
	}
}

void test() {
	//招聘員工
	vector<stuff> v;
	creatStuff(v);

	//部門分配
	multimap<int, stuff> m;
	allocateDepart(v,m);

	//列印資訊
	printStuff(m);
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

4 STL-函式物件

4.1 函式物件

4.1.1 函式物件概念

在這里插入圖片描述

4.1.2 函式物件使用

在這里插入圖片描述

class myPrint {
public:
	//函式物件相較于普通函式,可以有自己的狀態,可以統計次數等
	int count;
	myPrint() {
		this->count = 0;
	}
	void operator()(string text) {
		cout << text << endl;
		count++;
	}
};
//函式物件可以作為引數傳遞
void print_test(myPrint &mP, string text) {
	for (int i = 0; i < 5; i++) {
		mP(text);
	}
	cout << mP.count << endl;
}

void test() {
	//函式物件創建
	myPrint mP;
	string text = "hello world";
	print_test(mP, text);
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

4.2 謂詞

4.2.1 謂詞概念

在這里插入圖片描述

  • 謂詞體現在回傳型別,元數 體現在引數個數

4.2.1 一元謂詞

#include<vector>
#include<algorithm>

class score {
public:
	bool operator()(int value) {
		return value > 90;
	}
};

void test() {
	vector<int> v;
	for (int i = 0; i < 10; i++) {
		v.push_back(60 + rand() % 41);
	}
	//score()匿名函式物件
	vector<int>::iterator pos = find_if(v.begin(), v.end(), score());
	if (pos == v.end()) {
		cout << "failed" << endl;
	}
	else {
		cout << *pos << endl;
	}
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

4.2.1 二元謂詞

#include<vector>
#include<algorithm>

class sortRules {
public:
	bool operator()(int v1, int v2) {
		return v1 > v2;
	}
};

void printVector(vector<int> &v) {
	for (vector<int>::iterator pos = v.begin(); pos != v.end(); pos++) {
		cout << *pos << " ";
	}
	cout << endl;
}

void test() {
	vector<int> v;
	for (int i = 0; i < 10; i++) {
		v.push_back(60 + rand() % 41);
	}

	cout << "修改規則前:" << endl;
	sort(v.begin(), v.end());
	printVector(v);

	cout << "修改規則后: " << endl;
	sort(v.begin(), v.end(), sortRules());
	printVector(v);
}

int main() {
	srand((unsigned)time(NULL));
	test();	return 0;
}

4.3 內建函式物件

4.3.1 內建函式物件意義

在這里插入圖片描述

4.3.2 算術仿函式

在這里插入圖片描述

#include<functional>

void test() {
	//取反仿函式
	negate<int> n;
	cout << n(10) << endl;

	//取模仿函式
	//二元仿函式也只定義一個資料型別,默認兩個相同
	modulus<int> m;
	cout << m(50, 7) << endl;
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

4.3.3 關系仿函式

在這里插入圖片描述

#include<functional>
#include<vector>
#include<algorithm>

void test() {
	vector<int> v;
	for (int i = 0; i < 10; i++) {
		v.push_back(60 + rand() % 41);
	}
	//greater<int>() 內建大于函式的匿名函式物件
	sort(v.begin(), v.end(), greater<int>());
	for (vector<int>::iterator pos = v.begin(); pos != v.end(); pos++) {
		cout << *pos << " ";
	}
	cout << endl;
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

4.3.4 邏輯仿函式

在這里插入圖片描述

#include<functional>
#include<vector>
#include<algorithm>

void test() {
	vector<bool> v1;
	for (int i = 0; i < 10; i++) {
		v1.push_back(rand() % 2);
	}

	vector<bool> v2;
	v2.resize(v1.size());
	//將容器v1的值搬運到v2 搬運前必須指定目標容器的大小 即:v2.resize(v1.size());
	transform(v1.begin(), v1.end(), v2.begin(), logical_not<bool>());

	for (vector<bool>::iterator pos = v2.begin(); pos != v2.end(); pos++) {
		cout << *pos << " ";
	}
	cout << endl;
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

5 STL-常用演算法

在這里插入圖片描述

5.1 常用遍歷演算法

在這里插入圖片描述

5.1.1 for_each

在這里插入圖片描述

#include<vector>
#include<algorithm>

void printVector1(int val) {
	cout << val << " ";
}

class printVector2 {
public:
	void operator()(int val) {
		cout << val << " ";
	}
};

void test() {
	vector<int> v;
	for (int i = 0; i < 10; i++) {
		v.push_back(rand() % 100);
	}
	//普通函式直接用函式名
	cout << "普通函式:" << endl;
	for_each(v.begin(), v.end(), printVector1);
	cout << endl;
	//仿函式用函式物件
	cout << "仿函式:" << endl;
	for_each(v.begin(), v.end(), printVector2());
	cout << endl;
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

5.1.2 transform

在這里插入圖片描述

#include<vector>
#include<algorithm>

void printVector(int val) {
	cout << val << " ";
}

class transRules {
public:
	int operator()(int val) {
		return ++val;
	}
};

void test() {
	vector<int> v1;
	for (int i = 0; i < 10; i++) {
		v1.push_back(i);
	}
	for_each(v1.begin(), v1.end(), printVector);
	cout << endl;

	vector<int> v2;
	//目標容器 v2 必須提前設定大小
	v2.resize(v1.size());

	transform(v1.begin(),v1.end(),v2.begin(),transRules());

	for_each(v2.begin(), v2.end(), printVector);
	cout << endl;

}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

5.2 常用查找演算法

在這里插入圖片描述

5.2.1 find

在這里插入圖片描述

#include<vector>
#include<algorithm>

class person {
public:
	string m_name;
	int m_age;
	person() {};
	person(string name,int age) {
		this->m_name = name;
		this->m_age = age;
	}
	//自定義資料型別 多載 == 號便于查找
	bool operator==(const person &p) {
		if (this->m_name == p.m_name&&this->m_age == p.m_age) {
			return true;
		}
		else {
			return false;
		}
	}
};

void test() {
	vector<person> v;
	string nameSeed = "ABCDEFGHIJK";
	for (int i = 0; i < 5; i++) {
		person p;
		p.m_name += nameSeed[i];
		//p.m_age = 25;
		p.m_age = 23 + rand() % 3;
		v.push_back(p);
	}

	person pFind("A",25);
	vector<person>::iterator pos = find(v.begin(), v.end(), pFind);
	if (pos == v.end()) {
		cout << "未找到一樣的人" << endl;
	}
	else {
		cout << "找到一樣的人" << endl;
	}
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

5.2.2 find_if

在這里插入圖片描述

#include<vector>
#include<algorithm>

class person {
public:
	string m_name;
	int m_age;
	person() {};
	person(string name, int age) {
		this->m_name = name;
		this->m_age = age;
	}
};

class Greater {
public:
	bool operator()(const person &p) {
		if (p.m_age > 25) {
			return true;
		}
		else {
			return false;
		}
	}
};

void test() {
	vector<person> v;
	string nameSeed = "ABCDEFGHIJK";
	for (int i = 0; i < 5; i++) {
		person p;
		p.m_name += nameSeed[i];
		//p.m_age = 25;
		p.m_age = 23 + rand() % 4;
		v.push_back(p);
	}

	//自定義資料型別 用謂詞進行操作
	vector<person>::iterator pos = find_if(v.begin(), v.end(), Greater());
	if (pos == v.end()) {
		cout << "未找到年齡大于25的人" << endl;
	}
	else {
		cout << "找到年齡大于25的人" << endl;
	}
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

5.2.3 adjacent_find

在這里插入圖片描述

5.2.4 binary_search

在這里插入圖片描述

  • 必須是有序排布的容器(遞增或遞減)

5.2.5 count

在這里插入圖片描述

#include<vector>
#include<algorithm>

class person {
public:
	string m_name;
	int m_age;
	person() {};
	person(string name, int age) {
		this->m_name = name;
		this->m_age = age;
	}
	//自定義資料型別 多載 == 進行操作
	bool operator==(const person &p) {
		if (this->m_age == p.m_age) {
			return true;
		}
		else {
			return false;
		}
	}
};

void test() {
	vector<person> v;
	string nameSeed = "ABCDEFJHISAHJDJSAKLHFCVSDL";
	for (int i = 0; i < 10; i++) {
		person p;
		p.m_name = nameSeed[i];
		p.m_age = rand() % 3 + 20;
		v.push_back(p);
	}
	person pCount("Z", 21);
	int num = count(v.begin(), v.end(), pCount);
	cout << "年齡相同的人數:" << num << endl;
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

5.2.6 count_find

在這里插入圖片描述

#include<vector>
#include<algorithm>

class person {
public:
	string m_name;
	int m_age;
	person() {};
	person(string name, int age) {
		this->m_name = name;
		this->m_age = age;
	}
};

class PCount {
public:
	bool operator()(const person &p) {
		return p.m_age == 20;
	}
};

void test() {
	vector<person> v;
	string nameSeed = "ABCDEFJHISAHJDJSAKLHFCVSDL";
	for (int i = 0; i < 10; i++) {
		person p;
		p.m_name = nameSeed[i];
		p.m_age = rand() % 3 + 20;
		v.push_back(p);
	}
	int num = count_if(v.begin(), v.end(), PCount());
	cout << "年齡相同的人數:" << num << endl;
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

5.3 常用排序演算法

在這里插入圖片描述

5.3.1 sort

在這里插入圖片描述

#include<vector>
#include<algorithm>

class person {
public:
	string m_name;
	int m_age;
	person() {};
	person(string name, int age) {
		this->m_name = name;
		this->m_age = age;
	}
};
//排序規則
class sortRules {
public:
	bool operator()(const person &p1, const person &p2) {
		return p1.m_age > p2.m_age;
	}
};
//列印函式
void printVector(const person &p) {
	cout << "姓名:" << p.m_name << " 年齡:" << p.m_age << endl;
}

void test() {
	vector<person> v;
	string nameSeed = "ABCDEFJHISAHJDJSAKLHFCVSDL";
	for (int i = 0; i < 10; i++) {
		person p;
		p.m_name = nameSeed[i];
		p.m_age = rand() % 10 + 20;
		v.push_back(p);
	}
	sort(v.begin(), v.end(), sortRules());
	for_each(v.begin(), v.end(), printVector);
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

5.3.2 random_shuffle

在這里插入圖片描述

//亂數種子
srand((unsigned)time(NULL));

5.3.3 merge

在這里插入圖片描述

#include<vector>
#include<algorithm>

class person {
public:
	string m_name;
	int m_age;
	person() {};
	person(string name, int age) {
		this->m_name = name;
		this->m_age = age;
	}
};
//排序規則
class sortRules {
public:
	bool operator()(const person &p1, const person &p2) {
		return p1.m_age > p2.m_age;
	}
};

void printVector(const person &p) {
	cout << "姓名:" << p.m_name << " 年齡:" << p.m_age << endl;
}

void test() {
	vector<person> v1;
	vector<person> v2;
	for (int i = 0; i < 10; i++) {
		person p1;
		p1.m_name = "A";
		p1.m_age = 20 + rand() % 10;
		v1.push_back(p1);
		
		person p2;
		p2.m_name = "B";
		p2.m_age = 20 + rand() % 10;
		v1.push_back(p2);
	}
	//兩個合并的容器必須是有序的排列,同時遞增或遞減
	sort(v1.begin(), v1.end(), sortRules());
	sort(v2.begin(), v2.end(), sortRules());
	//需要給目標容器提取分配空間
	vector<person> vTarget;
	vTarget.resize(v1.size() + v2.size());
	merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin(), sortRules());
	for_each(vTarget.begin(), vTarget.end(), printVector);
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

5.3.4 reverse

在這里插入圖片描述

5.4 常用拷貝和替換演算法

在這里插入圖片描述

5.4.1 copy

在這里插入圖片描述

5.4.2 replace

在這里插入圖片描述

#include<vector>
#include<algorithm>

class person {
public:
	string m_name;
	int m_age;
	person() {};
	person(string name, int age) {
		this->m_name = name;
		this->m_age = age;
	}
	bool operator==(const person &p) {
		return(this->m_name == p.m_name&&this->m_age == p.m_age);
	}
};

class printVector {
public:
	void operator()(const person &p) {
		cout << "姓名:" << p.m_name << " 年齡:" << p.m_age << endl;
	}
};

void test() {
	vector<person> v;
	string nameSeed = "ABCDEFJHISAHJDJSAKLHFCVSDL";
	for (int i = 0; i < 10; i++) {
		person p;
		p.m_name = nameSeed[0];
		p.m_age = rand() % 3 + 20;
		v.push_back(p);
	}
	cout << "替換前:" << endl;
	for_each(v.begin(), v.end(), printVector());

	person pOLD("A",22);
	person pNEW("a", 22000);
	replace(v.begin(), v.end(), pOLD, pNEW);
	cout << "替換后:" << endl;
	for_each(v.begin(), v.end(), printVector());
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

5.4.3 replace_if

在這里插入圖片描述

#include<vector>
#include<algorithm>

class person {
public:
	string m_name;
	int m_age;
	person() {};
	person(string name, int age) {
		this->m_name = name;
		this->m_age = age;
	}
	//多載替換的 = 操作
	void operator=(string name) {
		this->m_name = name;
	}
};

class printVector {
public:
	void operator()(const person &p) {
		cout << "姓名:" << p.m_name << " 年齡:" << p.m_age << endl;
	}
};
//謂詞,替換條件
class replaceRules {
public:
	bool operator()(const person&p) {
		return p.m_age > 30;
	}
};

void test() {
	vector<person> v;
	string nameSeed = "ABCDEFJHISAHJDJSAKLHFCVSDL";
	for (int i = 0; i < 10; i++) {
		person p;
		p.m_name = nameSeed[i];
		p.m_age = rand() % 10 + 25;
		v.push_back(p);
	}
	cout << "替換前:" << endl;
	for_each(v.begin(), v.end(), printVector());

	replace_if(v.begin(), v.end(), replaceRules(), "大齡青年");
	cout << "替換后:" << endl;
	for_each(v.begin(), v.end(), printVector());
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

5.4.4 swap

在這里插入圖片描述

5.5 常用算術生成演算法

在這里插入圖片描述

5.5.1 accumulate

在這里插入圖片描述

#include<numeric>
//第三個引數為 起始累加值
accumulate(v.begin(),v.end(),0);

5.5.2 fill

在這里插入圖片描述

5.6 常用集合演算法

在這里插入圖片描述

5.6.1 set_intersection

在這里插入圖片描述

#include<vector>
#include<algorithm>

void printVector(int val) {
	cout << val << " ";
}

void test() {
	//取交集的兩個容器的元素必須是順序排列的
	vector<int> v1;
	vector<int> v2;
	for (int i = 0; i < 10; i++) {
		v1.push_back(i);
		v2.push_back(i + 5);
	}

	vector<int> vTarget;
	//提前分配目標容器大小
	//目標容器的大小為 兩個容器中較小的容器大小
	vTarget.resize(min(v1.size(), v2.size()));
	//回傳的是一個迭代器
	vector<int>::iterator it_end = set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
	cout << "交集為:" << endl;
	//遍歷時使用it_end(系統回傳的值) 不使用vTarget.end()
	for_each(vTarget.begin(), it_end, printVector);
	cout << endl;
}

int main() {
	srand((unsigned)time(NULL));
	test();
	return 0;
}

5.6.2 set_union

在這里插入圖片描述

//目標容器大小
vTarget.resize(v1.size() + v2.size());

5.6.3 set_difference

在這里插入圖片描述

  • 差集是所有元素除去交集部分后剩下的元素
  • v1與v2的差集 和 v2對與v1的差集 結果不同
//目標容器大小
vTarget.resize(max(v1.size(), v2.size()));

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/385901.html

標籤:其他

上一篇:2021年浙江工商大學新生賽題解

下一篇:ARDUINO.

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 面試突擊第一季,第二季,第三季

    第一季必考 https://www.bilibili.com/video/BV1FE411y79Y?from=search&seid=15921726601957489746 第二季分布式 https://www.bilibili.com/video/BV13f4y127ee/?spm_id_fro ......

    uj5u.com 2020-09-10 05:35:24 more
  • 第三單元作業總結

    1.前言 這應該是本學期最后一次寫作業總結了吧。總體來說,對作業的節奏也差不多掌握了,作業做起來的效率也更高了。雖然和之前的作業一樣,作業中都要用到新的知識,但是相比之前,更加懂得了如何利用工具以及資料。雖然之間卡過殼,但總體而言,這幾次作業還算完成的比較好。 2.作業程序總結 相比前兩個單元,此單 ......

    uj5u.com 2020-09-10 05:35:41 more
  • 北航OO(2020)第四單元博客作業暨課程總結博客

    北航OO(2020)第四單元博客作業暨課程總結博客 本單元作業的架構設計 在本單元中,由于UML圖具有比較清晰的樹形結構,因此我對其中需要進行查詢操作的元素進行了包裝,在樹的父節點中存盤所有孩子的參考。考慮到性能問題,我采用了快取機制,一次查詢后盡可能快取已經遍歷過的資訊,以減少遍歷次數。 本單元我 ......

    uj5u.com 2020-09-10 05:35:48 more
  • BUAA_OO_第四單元

    一、UML決議器設計 ? 先看下題目:第四單元實作一個基于JDK 8帶有效性檢查的UML(Unified Modeling Language)類圖,順序圖,狀態圖分析器 MyUmlInteraction,實際上我們要建立一個有向圖模型,UML中的物件(元素)可能與同級元素連接,也可與低級元素相連形成 ......

    uj5u.com 2020-09-10 05:35:54 more
  • 6.1邏輯運算子

    邏輯運算子 1. && 短路與 運算式1 && 運算式2 01.運算式1為true并且運算式2也為true 整體回傳為true 02.運算式1為false,將不會執行運算式2 整體回傳為false 03.只要有一個運算式為false 整體回傳為false 2. || 短路或 運算式1 || 運算式2 ......

    uj5u.com 2020-09-10 05:35:56 more
  • BUAAOO 第四單元 & 課程總結

    1. 第四單元:StarUml檔案決議 本單元采用了圖模型決議UML。 UML檔案可以抽象為圖、子圖、邊的邏輯結構。 在實作中,圖的節點包括類、介面、屬性,子圖包括狀態圖、順序圖等。 采用了三次遍歷UML元素的方法建圖,第一遍遍歷建點,第二、三次遍歷設定屬性、連邊,實作圖物件的初始化。這里借鑒了一些 ......

    uj5u.com 2020-09-10 05:36:06 more
  • 談談我對C# 多型的理解

    面向物件三要素:封裝、繼承、多型。 封裝和繼承,這兩個比較好理解,但要理解多型的話,可就稍微有點難度了。今天,我們就來講講多型的理解。 我們應該經常會看到面試題目:請談談對多型的理解。 其實呢,多型非常簡單,就一句話:呼叫同一種方法產生了不同的結果。 具體實作方式有三種。 一、多載 多載很簡單。 p ......

    uj5u.com 2020-09-10 05:36:09 more
  • Python 資料驅動工具:DDT

    背景 python 的unittest 沒有自帶資料驅動功能。 所以如果使用unittest,同時又想使用資料驅動,那么就可以使用DDT來完成。 DDT是 “Data-Driven Tests”的縮寫。 資料:http://ddt.readthedocs.io/en/latest/ 使用方法 dd. ......

    uj5u.com 2020-09-10 05:36:13 more
  • Python里面的xlrd模塊詳解

    那我就一下面積個問題對xlrd模塊進行學習一下: 1.什么是xlrd模塊? 2.為什么使用xlrd模塊? 3.怎樣使用xlrd模塊? 1.什么是xlrd模塊? ?python操作excel主要用到xlrd和xlwt這兩個庫,即xlrd是讀excel,xlwt是寫excel的庫。 今天就先來說一下xl ......

    uj5u.com 2020-09-10 05:36:28 more
  • 當我們創建HashMap時,底層到底做了什么?

    jdk1.7中的底層實作程序(底層基于陣列+鏈表) 在我們new HashMap()時,底層創建了默認長度為16的一維陣列Entry[ ] table。當我們呼叫map.put(key1,value1)方法向HashMap里添加資料的時候: 首先,呼叫key1所在類的hashCode()計算key1 ......

    uj5u.com 2020-09-10 05:36:38 more
最新发布
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:20:47 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:20:25 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:20:17 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:20:10 more
  • 【中介者設計模式詳解】C/Java/JS/Go/Python/TS不同語言實作

    * 中介者模式是一種行為型設計模式,它可以用來減少類之間的直接依賴關系,
    * 將物件之間的通信封裝到一個中介者物件中,從而使得各個物件之間的關系更加松散。
    * 在中介者模式中,物件之間不再直接相互互動,而是通過中介者來中轉訊息。 ......

    uj5u.com 2023-04-20 08:19:44 more
  • 露天煤礦現場調研和交流案例分享

    他們集團的資訊化公司及研究院在一個礦區正在做智能礦山的統一平臺的 試點,專案投資大概1億,包括了礦山的各方面的內容,顯示得我們這次交流有點多余。他們2年前開始做智能礦山的規劃,有很多煤礦行業專家的加持,他們的描述是非常完美,但是去年底應該上線的平臺,現在還沒有看到影子。他們確實有很多場景需求,但是被... ......

    uj5u.com 2023-04-20 08:19:07 more
  • 《社區人員管理》實戰案例設計&個人案例分享

    設計是一個讓人夢想成真程序,開始編碼、測驗、除錯之前進行需求分析和架構設計,才能保證關鍵方面都做正確 ......

    uj5u.com 2023-04-20 08:18:57 more
  • 軟體架構生態化-多角色交付的探索實踐

    作為一個技術架構師,不僅僅要緊跟行業技術趨勢,還要結合研發團隊現狀及痛點,探索新的交付方案。在日常中,你是否遇到如下問題 “ 業務需求排期長研發是瓶頸;非研發角色感受不到研發技改提效的變化;引入ISV 團隊又擔心質量和安全,培訓周期長“等等,基于此我們探索了一種新的技術體系及交付方案來解決如上問題。 ......

    uj5u.com 2023-04-20 08:18:49 more
  • 05單件模式

    #經典的單件模式 public class Singleton { private static Singleton uniqueInstance; //一個靜態變數持有Singleton類的唯一實體。 // 其他有用的實體變數寫在這里 //構造器宣告為私有,只有Singleton可以實體化這個類! ......

    uj5u.com 2023-04-19 08:42:51 more
  • 【架構與設計】常見微服務分層架構的區別和落地實踐

    軟體工程的方方面面都遵循一個最基本的道理:沒有銀彈,架構分層模型更是如此,每一種都有各自優缺點,所以請根據不同的業務場景,并遵循簡單、可演進這兩個重要的架構原則選擇合適的架構分層模型即可。 ......

    uj5u.com 2023-04-19 08:42:41 more