主頁 > 後端開發 > c++基礎2

c++基礎2

2022-11-15 06:23:42 後端開發

模板

c++另一種編程思想稱為泛型編程,主要利用的技術就是模板

c++提供兩種模板機制:函式模板和類模板

函式模板

建立一個通用函式,函式的回傳值型別和形參型別可以不具體指定,用一個虛擬的型別來代表

語法:

template<typename T> 
//或者
template<class T>
函式宣告或定義

當使用class的時候,如果T有子類,編譯器會認為是宣告,所以還是使用typename吧

template<typename T>

void test(T& a, T& b) {
	T temp = a;
	a = b;
	b = temp;
}

int main() {

	int a = 1, b = 2;
	//自動推導型別
	test(a, b);
	//指定型別
	test<int>(a, b);
	cout << a << "==" << b << endl;
}       

注意事項:

自動型別推導,必須推匯出一致的資料型別T才可以使用

模板必須要確定出T的資料型別,才可以使用

template<typename T>

void test(T& a, T& b) {
	T temp = a;
	a = b;
	b = temp;
}

int main() {

	int a = 1, b = 2;
	char c='1';
	//自動推導型別錯誤,因為兩個型別不同
	test(a, c);
}    
template<typename T>

void test() {
	cout << "hhhh" << endl;
	
}
int main() {
	test();//錯誤,因為推導不出T是什么型別
}                                  
template<typename T>
void test() {
	cout << "hhhh" << endl;
	
}

int main() {
	test<int>(); //明確指定就可以
    test<string>();//這個也可以
}                                  

普通模板和函式模板區別

  • 普通函式呼叫時可以發生自動型別轉換(隱式型別轉換)
  • 函式模板呼叫時,如果利用自動型別推導,不會發生隱式型別轉換
  • 函式模板如果利用顯示指定的方法,可以發生型別轉換

普通函式會發生隱式轉換,例如下面的例子中,將char型別的c轉換為了int,對應的就是c的ascll碼

void print1(int a, int b) {
	cout << a + b << endl;
}

int main() {
	int a = 1;
	char b = 'c';
	print1(a,b);
}   

而使用模板函式時

template<typename T>

void print(T a,T b) {
	cout << a+b << endl;
}

int main() {
	int a = 1;
	char b = 'c';
	print(a,b);  //報錯
}   
template<typename T>

void print(T a,T b) {
	cout << a+b << endl;
}

int main() {
	int a = 1;
	char b = 'c';
	print<int>(a,b);  //除非我們指定了資料型別為int
}     

普通函式和模板函式的呼叫規則

  • 如果函式模板和普通函式都可以實作,優先調普通函式
  • 可以通過空模板引數來強制呼叫函式模板
  • 函式模板也可以發生多載
  • 如果函式模板可以產生更好的匹配,優先呼叫函式模板

如果函式模板和普通函式都可以實作,優先調普通函式

template<typename T>

void test(T a) {
	cout <<"函式模板" << endl;
}
void test(int a) {
	cout << "普通函式" << endl;
}

int main() {
	int a = 1;
	test(a);
}                                  

結果:普通函式

template<typename T>

void test(T a) {
	cout <<"函式模板" << endl;
}
void test(int a);

int main() {
	int a = 1;
	test(a);
}    

如果普通函式只有宣告也是呼叫普通函式,會報錯沒有找到定義

可以通過空模板引數來強制呼叫函式模板

template<typename T>

void test(T a) {
	cout <<"函式模板" << endl;
}
void test(int a) {
	cout << "普通函式" << endl;
}

int main() {
	int a = 1;
	test<>(a);
}     

這樣就可以強制呼叫函式模板,當然,尖括號里面隨便寫個型別也可以,但沒必要

函式模板也可以發生多載

template<typename T>
void test(T a) {
	cout <<"函式模板一個引數" << endl;
}

template<typename T>
void test(T a,T b) {
	cout << "函式模板兩個引數" << endl;
}


int main() {
	int a = 1;
	test<>(a); //函式模板一個引數
	test<>(a,a); //函式模板兩個引數
} 

如果函式模板可以產生更好的匹配,優先呼叫函式模板

template<typename T>
void test(T a) {
	cout <<"函式模板一個引數" << endl;
}


void test(int a) {
	cout << "普通函式" << endl;
}

int main() {
	char a = '1';
	test(a);
}     

會優先使用函式模板,因為普通函式確定了型別為int,而char需要轉int,呼叫函式模板則不需要任何轉換

模板的局限性

模板并不是萬能的,例如

template<typename T>
bool test(T& a,T& b) {
	return a == b;
}

int main() {
	char a = '1';
	char b = '2';
	cout<<test(a,b);
}    

當我們傳基礎的資料類代碼可以正常使用,但是當傳入的資料是自定義型別的時候

class A {
public:
	string name;
};

template<typename T>
bool test(T& a,T& b) {
	return a == b;
}

int main() {
	A a1 = { "小明" };
	A a2 = { "大明" };
	cout<<test(a1,a2);
}  

就會報錯了,因為沒有找到A型別的==判斷

解決辦法有兩個:

1 重寫運算子

class A {
public:
	string name;
	bool operator==(A& a) {
		return (this->name == a.name);
	}
};

template<typename T>
bool test(T& a, T& b) {
	return a == b;
}

int main() {
	A a1 = { "小明" };
	A a2 = { "大明" };
	cout << test(a1, a2);
}

2 重寫一個針對A類的函式模板

class A {
public:
	string name;
};


template<typename T>
bool test(T& a, T& b) {
	return a == b;
}

template<> bool test(A& a, A& b) {
	return a.name == b.name;
}

int main() {
	A a1 = { "小明" };
	A a2 = { "大明" };
	cout << test(a1, a2);
}

利用具體化的模板,可以解決自定義型別的通用化

類模板

建立一個通用的類,類中的成員資料型別可以不具體指定,用一個虛擬的型別來代表

語法:

template<typename T>
class 類名 {

};
//宣告下面的類中可以使用這兩個型別
template<typename NameType,typename AgeType>
class A {
public:
	NameType name;
	AgeType age;
};

int main() {
    //使用時指定兩個型別
	A<string, int> a = { "小明",19 };
	cout << a.age << "==" << a.name << endl;
}

類模板和函式模板區別

  • 類模板沒有自動推導型別的使用方式

    template<typename NameType,typename AgeType>
    class A {
    public:
    	A(NameType _name, AgeType _age) {
    		this->name = _name;
    		this->age = _age;
    	}
    	NameType name;
    	AgeType age;
    };
    
    
    
    int main() {
        //A a("哈哈哈", 1); 報錯,類模板沒有自動推導
        A<string,int> a("哈哈哈", 1);  //可以正常使用
    	cout << a.age << "==" << a.name << endl;
    }
    
  • 類模板在模板引數串列中可以有默認引數

    template<typename NameType, typename AgeType=int>  //這里給AgeType設定了默認型別為int
    class A {
    public:
    	A(NameType _name, AgeType _age) {
    		this->name = _name;
    		this->age = _age;
    	}
    	NameType name;
    	AgeType age;
    };
    
    
    
    int main() {
    	//下面在使用時就只需要指定一個string即可
    	A<string> a("哈哈哈", 1);
    	cout << a.age << "==" << a.name << endl;
    }
    

需要注意的是,如果有兩個或多個引數,只能從最右邊開始指定默認型別

例如下面的就是錯誤的

template<typename NameType=string, typename AgeType>

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

類模板的成員函式和普通類的成員函式創建時機是有區別的

  • 普通類中的成員函式一開始就可以創建
  • 模板類中的成員函式在呼叫的時候才會創建
class A {
public:
	void func1() {
		cout << "A-func" << endl;
	}
    A() {
		cout << "A-init"<<endl;
	}
};

class B {
public:
	void func2() {
		cout << "A-func" << endl;
	}
};


template <typename T>
class MyRun {
public:

	T t;
	void run1() {
		t.func1();
	}
	void run2() {
		t.func2();
	}

};

int main() {
	MyRun<A> m;
	m.run1();
	//m.run2();
}

當main方法中什么都不寫的時候,可以正常運行,因為MyRun類中的屬性t并沒有確認是什么型別,只有在運行的時候才能確認t的型別,判斷t有沒有func1或func2的函式

當指定型別為A的時候就已經初始化創建了一個A物件

A-init
A-func

類模板物件做函式引數

三種傳入方式

  • 指定傳入型別
  • 引數模板化
  • 整個類模板化

1 指定傳入型別


template <typename NameType,typename AgeType>
class User {
public:

	NameType name;
	AgeType age;

	User(NameType _name,AgeType _age) :name(_name), age(_age) {
	}
};
//直接標明都是什么型別
void print(User<string, int>& u) {
	cout <<   u.name << "==" << u.age << endl;

}

int main() {
	User<string, int> user("小明", 20);
	print(user);
}

2 引數模板化

template <typename NameType,typename AgeType>
class User {
public:

	NameType name;
	AgeType age;

	User(NameType _name,AgeType _age) :name(_name), age(_age) {
	
	}

};
//模板的名稱不需要和類模板定義名稱一樣,只是單純定義函式模板
template <typename F_NameType,typename F_AgeType>
void print(User<F_NameType, F_AgeType>& u) {
	cout <<   u.name << "==" << u.age << endl;
    cout <<"F_NameType的資料型別為:" << typeid(F_NameType).name() << endl;
	cout <<"F_AgeType的資料型別為:" << typeid(F_AgeType).name() << endl;

}

int main() {
	User<string, int> user("小明", 20);
	print(user);
}

3 整個類模板化

template <typename NameType,typename AgeType>
class User {
public:

	NameType name;
	AgeType age;

	User(NameType _name,AgeType _age) :name(_name), age(_age) {
	
	}

};
//再定義有一個模板函式作為接收引數
template <typename T>
void print(T& u) {
	cout <<   u.name << "==" << u.age << endl;
	cout <<"T的資料型別dfsdfs為:" << typeid(T).name() << endl;
}

int main() {
	User<string, int> user("小明", 20);
	print(user);
}

類模板與繼承

  • 當子類繼承的父類是一個類模板時,子類在宣告的時候,要指出父類中T的型別
  • 如果不指定,編譯器無法給子類分配記憶體
  • 如果想靈活指定父類中的T型別,子類也需要變為類模板

1 當子類繼承的父類是一個類模板時,子類在宣告的時候,要指出父類中T的型別

template <typename T>
class Father {
public:
	T obj;
};

class Son : public Father<int> {
	
};

int main() {
	Son s;
	s.obj = 100;
	cout << s.obj << endl;
}

2 如果想靈活指定父類中的T型別,子類也需要變為類模板

template <typename T>
class Father {
public:
	T obj;
};
//宣告同時指定T2型別
template <typename T1,typename T2=int>
class Son : public Father<T1> {
public:
	T2 t2;
};

int main() {
	//傳入的是Father的模板型別,Son的已經有默認型別了
	Son<int> s;
	s.obj = 100;
	s.t2 = 200;
	cout << s.obj << endl;
	cout << s.t2 << endl;
}

類模板成員函式類外實作

template<typename T>
class A {
public:
	A(T n); //宣告構造
	void print(); //宣告函式
	T number;
	
};
//類外實作構造
template<typename T>
A<T>::A(T n) {
	this->number = n;
}
//類外實作函式
template<typename T>
void A<T>::print() {
		cout << this->number;
}

int main() {
	A<int> a(1);
	a.print();
}

類模板分檔案撰寫

問題: 類模板中成員函式創建時機在呼叫階段,導致分檔案撰寫時鏈接不到

解決方式1: 直接包含.cpp源檔案

解決方式2 將宣告和實作寫到同一個檔案中,并將后綴改為hpp,hpp是約定名稱,不是強制

A.h

#pragma once
#include <iostream>
#include<string>
using namespace std; 


template<typename T>
class A {
public:
	A(T n);
	void print();
	T number;
};

A.cpp

#include "A.h"

template<typename T>
A<T>::A(T n) {
	this->number = n;
}

template<typename T>
void A<T>::print() {
	cout << this->number;
}

主檔案

#include "A.h"

int main() {
	A<int> a(1);
	a.print();
}

運行報錯,無法決議符號

方式1:把主檔案中的#include "A.h" 改為#include "A.cpp"

方式2:將A.cpp的內容移動到A.h中,然后修改A.h為A.hpp

A.hpp

#pragma once
#include <iostream>
#include<string>
using namespace std; 


template<typename T>
class A {
public:
	A(T n);
	void print();
	T number;
};


template<typename T>
A<T>::A(T n) {
	this->number = n;
}

template<typename T>
void A<T>::print() {
	cout << this->number;
}

主函式

#include "A.hpp"

int main() {
	A<int> a(1);
	a.print();
}

類模板和友元

全域函式類外實作- 直接在類中宣告友元即可

全域函式類外實作,需要提前讓編譯器知道全域函式的存在

類內實作:

#include <iostream>
#include<string>
using namespace std;

template <typename T>
class G {
    //這個就是全域函式,不是成員函式
    //還有一種是類內宣告,類外實作,這個是直接實作
    //因為要指定那個方法作為當前類的友元,所以會在類中定義全域函式
	friend void print(G<T> g) {
		cout << g.name << endl;
	}
public:
	G(T t) {
		this->name = t;
	}

private:
	T name;
};

int main() {
	G<string> g("小明");
	print(g);
}

類外實作1:

template <typename T>
class G {
    //標明這個函式是一個函式模板
	template <typename T>
	friend void print(G<T>& g);
public:
	G(T t) {
		this->name = t;
	}

private:
	T name;
};
//實作
template <typename T>
void print(G<T>& g) {
	cout << g.name << endl;
};


int main() {
	G<string> g("小明");
	print(g);
}

類外實作2:

//因為print方法提前到了G類的定義前
//需要讓編譯器提前知道還有個G類
template <typename T>
class G;

//在G類上方定義函式模板,讓編譯器知道這個方法
template <typename T>
void print(G<T>& g) {
	cout << g.name << endl;
};

template <typename T>
class G {

	//=======注意! 需要加一個空模板引數串列
	friend void print<>(G<T>& g);
public:
	G(T t) {
		this->name = t;
	}

private:
	T name;
};


int main() {
	G<string> g("小明");
	print(g);
}

練習-使用模板類實作一個容器

MyArray.hpp

#pragma once
#include <iostream>
#include <string>
using namespace std;


template <typename T>
class MyArray {

public:

	MyArray(int _size) {
		//cout << "有參構造" << endl;
		this->size = _size;
		this->count = 0;
		this->p = new T[_size];
	}
    //重寫拷貝構造,解決淺拷貝問題
	MyArray(const MyArray& arr) {
		//cout << "拷貝構造" << endl;
		this->count = arr.count;
		this->size = arr.size;
		//深拷貝
		this->p = new T[arr.size];
		for (int i = 0; i < size; i++) {
			this->p[i] = arr.p[i];
		}
	}
	//多載賦值符號,解決淺拷貝問題
	MyArray& operator=(const MyArray& arr) {
		//cout << "賦值多載" << endl;
		if (this->p != NULL) {
			delete[] this->p;
			p = NULL;
		}

		this->count = arr.count;
		this->size = arr.size;
		this->p = new T[arr.size];

		for (int i = 0; i < size; i++) {
			this->p[i] = arr.p[i];
		}
		return *this;
	}

	T& operator[](int index) {
		return this->p[index];
	}


	int getSize() {
		return this->size;
	}

	int getCount() {
		return this->count;
	}

	~MyArray() {
		//cout << "解構式" << endl;
		if (this->p != NULL)
		{
			//洗掉陣列
			delete[] this->p;
			p = NULL;
		}
	}

	void add(const T& t) {
		if (this->count == this->size) {
			cout << "已經滿了" << endl;
			return;
		}
		this->p[count++] = t;
	}

	void remove() {
		if (this->count == 0) {
			return;
		}
		this->p[--count] = 0;
	}
	
private:
	T* p;
	//陣列已占用個數
	int count;
	//陣列大小
	int size;
};

主函式

1 測驗基礎資料型別

#include <iostream>
#include "MyArray.hpp" //引入自定義的頭檔案需要使用""而不是<>
#include<string>
using namespace std;

int main() {
	MyArray<int>* p = new MyArray<int>(10);
	cout << "陣列大小:" << p->getSize() << endl;
	cout << "陣列容量:" << p->getCount() << endl;
	for (int b = 0; b < 10; b++) {
		p->add(b);
	}

	cout << "陣列容量:" << p->getCount() << endl;

	for (int i = 0; i < p->getCount(); i++) {
		//因為是指標,所有需要先解參考然后再[下標]取值
		cout << (*p)[i] << endl;
	}

	p->remove();
	p->remove();
	p->remove();

	MyArray<int> arr2 = *p;

	cout << "arr2===copy===:" <<  endl;
	for (int i = 0; i < arr2.getCount(); i++) {
		cout << arr2[i] << endl;
	}
	cout << "arr2===end:" << endl;
	for (int i = 0; i < p->getCount(); i++) {
		cout << (*p)[i] << endl;
	}
	delete p;
	p = NULL;

}

2 測驗自定義資料型別

#include <iostream>
#include "MyArray.hpp"
#include<string>


using namespace std;


class A {
public:
	//無參構造,用于自定義容器中的深拷貝的創建物件
	// this->p = new T[_size];
	A() {}

	A(string _name, int _age) :name(_name), age(_age) {

	}
    string name;
	int age;
};

ostream& operator<<(ostream& o, A& a) {
	cout <<"年齡:" << a.age<<" 姓名:" << a.name;
	return o;
}

int main() {

	MyArray<A> arr(10);
	
	A a2 = { "A2",20 };
	A a3 = { "A3",30 };
	A a4 = { "A4",40 };
	arr.add(a1);
	arr.add(a2);
	arr.add(a3);
	arr.add(a4);
	for (int i = 0; i < arr.getCount(); i++) {
		cout << arr[i]<<"====地址:"<<&(arr[i]) << endl;
	}
	MyArray<A> arr2(arr);
	for (int i = 0; i < arr2.getCount(); i++) {
		cout << arr2[i] <<"====地址:" << &(arr[i])<< endl;
	}

	cout << "兩個陣列地址==arr:" << (int) & arr << "  arr2:" << (int)&arr2 << endl;

}

STL容器

  • STL(Standard Template Library) 標準模板庫

  • STL從廣義上分為容器,演算法,迭代器

  • 容器和演算法直接通過迭代器進行無縫銜接

  • STL幾乎所有代碼都使用了模板類或模板函式

STL六大組件

容器,演算法,迭代器,仿函式,配接器(配接器),空間配置器

  1. 容器:各種資料結構,如vector,list,deque,set,map等,用來存放資料
  2. 演算法:各種常用的演算法,如sort,find,copy,for_each等
  3. 迭代器:扮演了容器與演算法之間的膠合器
  4. 仿函式:行為類似函式,可作為演算法的某種策略
  5. 配接器:一種用來修飾容器或仿函式或迭代器介面的東西
  6. 空間配置器:賦值空間的配置與管理

容器

常用資料結構:陣列,鏈表,數,堆疊,佇列,集合等

容器分為序列式容器和關聯式容器

  • 序列式容器:強調值的排序,序列式容器中每個元素都有固定的位置
  • 關聯式容器:二叉樹結構,各元素之間沒有嚴格的物理上的順序關系

演算法

演算法分為質變演算法和非質變演算法

質變演算法:指運算程序中會改變區間內容的元素內容例如拷貝,替換,洗掉等

非質變演算法:指運算程序中不會更改區間的元素內容,例如查找,計數,變數,尋找極值等

迭代器

提供一種方法,能夠依序尋訪某個容器中所包含的每個元素,而又無需暴露該容器的內部表示方式

每個容器都有自己的迭代器,迭代器非常類似于指標,初學階段可以先理解為指標

迭代器種類:

輸入迭代器:對資料的只讀訪問,支持++ == !=

輸出迭代器:對資料的只寫操作,支持++

前向迭代器 讀寫操作,并能向前推進迭代器 支持++ == !=

雙向迭代器 讀寫,并能向前和向后操作 支持++ --

隨機訪問迭代器 讀寫操作 可以跳躍的訪問任何資料 支持++ -- [n] -n < <= > >=

string容器

**string和char ***區別

  • char *是一個指標
  • string是一個類,內部封裝了char* 管理這個字串,是一個char*型的容器

string 建構式

  • string() 創建一個空字串,例如string s;
  • string(const char* s) 使用字串s初始化
  • string(const string& str) 使用一個string物件來初始化另一個
  • string(int n,char c) 使用n個字符c初始化
int main() {
	//默認構造
	string s;

	const char* str = "hello!";
	string s1(str);
		 
	cout << "s1" << s1 << endl;

	//拷貝構造
	string s2(s1);

	cout << "s2" << s2 << endl;
	//4個h
	string s3(4, 'h');
	cout << "s3" << s3 << endl;
}

string 賦值操作

  • string& operator=(const char* s) char*型別字串賦值給當前字串
  • string& operator=(const string& s) 字串s賦值給當前字串
  • string& operator=(char c) 字符賦值給當前字串
  • string& assign(const char* s) 字串s賦值給當前字串
  • string& assign(const char* s,int n) 把字串s的前n個字符賦值給當前字串
  • string& assign(const string& s) 把字串s賦值給當前字串
  • string& assign(int n,char c) 用n個字符c賦值給當前字串

int main() {
	//默認構造
	string s;
	const char* str = "hello!";
	s = str;
	cout << "s=" << s << endl;

	string s1 = s;
	cout << "s1=" << s1 << endl;

	string s2;
	s2 = 'a';
	cout << "s2=" << s2 << endl;

	string s3;
	s3.assign("hellowwww");
	cout << "s3=" << s3 << endl;

	string s4;
	s4.assign("hellowwww",3);
	cout << "s4=" << s4 << endl;

	string s5;
	s5.assign(s4);
	cout << "s5=" << s5 << endl;

	string s6;
	s6.assign(6, 't');
	cout << "s6=" << s6 << endl;
}


string 拼接

  • string& operator+=(const char* str)
  • string& operator+=(const char c)
  • string& operator+=(const string& str)
  • string& append(const char* s) 把s字串拼接到當前字串結尾
  • string& append(const char* s,int n) 把c字串前n個字符拼接到當前字串結尾
  • string& append(const string& s) 同operator+=(const string& str)
  • string& append(const string& s,int pos,int n) 字串s中從pos開始的n個字符拼接到字串結尾
int main() {
	//默認構造
	string s = "hello!";
	s += " i ";
	s += 'a';
	string s1 = "m";
	s += s1;
	s.append(" j");
	s.append("a==", 1);
	s.append(s1);
	string s2 = "asme";
	s.append(s2,3,1);
	cout << s << endl;
	// hello! i am jame
}

string 查找替換

  • int find(const string& str,int pos=0) const 查找str第一次出現的位置,從pos開始
  • int find(const char* s,int pos=0) const 查找s第一次出現的位置,從pos開始查找
  • int find(const char* s,int pos,int n) const 從pos位置查找s前n個字符第一次出現的位置
  • int find(const char c,int pos=0) const 查找字符c第一次出現的位置
  • int rfind(const string& str,int pos=npos) const 查找str最后一次出現的位置,從pos開始查找
  • int rfind(const char* s,int pos=npos) const 查找s最后一次出現的位置,從pos開始查找
  • int rfind(const char* s,int pos,int n) const 從pos查找s前n個字符最后一次出現的位置
  • int rfind(const char c,int pos=0) const 查找字符c最后一次出現的位置
  • string& replace(int pos,int n,const string& str) 從pos開始n個字符替換為str
  • string& replace(int pos,int n const char* s) 替換從pos開始n個字符為s

find和rfind區別 find是從左往右,rfind是從右往左

int main() {
	string s = "2===2=";
	string s1 = "6";
	cout<<s.find(s1)<<endl; //s.find(s1,0) 省略
	cout << s.find("2") << endl; //s.find("2",0) 省略
	cout << s.find("234", 0, 1) << endl; //先把234拆開,從0開始,拆一個,獲取到2,然后再查
	cout << s.find('2') << endl;//s.find('2',0)省略 
	cout << s.rfind(s1,6) << endl;//從下標6開始從右往左查 
	cout << s.rfind("2",6) << endl;//從下標6開始從右往左查 
	cout << s.rfind('2',6) << endl;//從下標6開始從右往左查 
	cout<<s.replace(0, 1, s1)<<endl;//從0開始1個字符替換為6
	cout<<s.replace(0, 1, "7")<<endl;//從0開始1個字符替換為6
}

string 比較

字串比較是按字符的ASCII碼進行對比

= 回傳0 > 回傳 1 < 回傳-1

  • int compare(const string& s) const 與字串s比較
  • int compare(const char* s)const 與字串s比較
int main() {
	string s = "hello";
	string s1 = "hello";
	string s2 = "xello";
	cout << (s.compare(s1) == 0) << endl;
	cout << (s.compare(s2) == 0) << endl;
	cout << (s.compare("hello") == 0) << endl;
	cout << (s.compare("xello") == 0) << endl;
}

string 字串存取

  • char& operator[](int n) 通過[]獲取字符
  • char& at(int n) 通過at方法獲取字符
int main() {
	string s = "hello";
	s[0] = 'y';
	for (int i = 0; i < s.length(); i++) {
		cout << s[i];
	}
	s.at(0) = 'y';
	for (int i = 0; i < s.length(); i++) {
		cout << s.at(i);
	}
}

string 插入和洗掉

  • string& insert(int pos,const char* s); 插入字串
  • string& insert(int post,const string& str) 插入字串
  • string& insert(int pos,int n,char c) pos位置插入n個字符c
  • string& erase(int pos,int n=pos) 洗掉從pos開始的n個字符
int main() {
	string s = "hello";
	string s1 = "wu";
	cout<<s.insert(1, "+")<<endl; //在下標1后面插入---
	cout << s.insert(1, s1) << endl;  //在下標1后面插入s1
	cout << s.insert(1, 4, 'x') << endl; //在下標1后面插入4個字符x
	cout << s.erase(1, 2) << endl;//從下標1后洗掉2個字符
}

string 子串

string substr(int pos=0,int n=pos) const 回傳從pos開始的n個字符組成的字串

int main() {
	string s = "hello";
	cout << s.substr() << endl;
	cout << s.substr(0,1) << endl;
}

vector容器

vector資料結構和陣列非常相似,也稱之為單端陣列,但是不同于陣列是靜態空間,vector是可以動態擴展的

動態擴展

并不是在原空間后繼續開辟空間,而是找一段更大的空間,之后將原資料復制到新空間上,釋放原空間

vector的迭代器是支持隨機訪問的

容器:vector

演算法:for_each

迭代器:vector<int>::iterator

#include <iostream>
#include <vector>
using namespace std;  //vector需要匯入

#include<algorithm>  //for_each 匯入


void print(int val) {
	cout << val;
}

int main() {
	vector<int> v;
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);
	//直接通過下標訪問
	int& a = v[1];

	//通過迭代器訪問1
	//vector<int>::iterator itBegin = v.begin();
	//vector<int>::iterator itEnd = v.end();
	//while (itBegin != itEnd) {
	//	cout << *itBegin << endl;
	//	itBegin++;
	//
	//}
	// 
	//通過迭代器訪問2
	//for (vector<int>::iterator itBegin = v.begin(); itBegin != v.end(); itBegin++){
	//	cout << *itBegin << endl;
	//	
	//}

	//通過for_each 
	for_each(v.begin(), v.end(), print);

}

添加自定義的型別

class A {
public :
	string name;

};

int main() {
	vector<A> v;
	A a1 = { "a1" };
	A a2 = { "a2" };
	A a3 = { "a3" };
	v.push_back(a1);
	v.push_back(a2);
	v.push_back(a3);

	//通過迭代器訪問2
	for (vector<A>::iterator itBegin = v.begin(); itBegin != v.end(); itBegin++){
		cout << (* itBegin).name << endl;
	}
}

存放類的指標

int main() {
	vector<A*> v;
	A a1 = { "a1" };
	A a2 = { "a2" };
	A a3 = { "a3" };
	v.push_back(&a1);
	v.push_back(&a2);
	v.push_back(&a3);

	//通過迭代器訪問2
	for (vector<A*>::iterator itBegin = v.begin(); itBegin != v.end(); itBegin++){
		cout <<  (*itBegin)->name << endl;
		cout <<  (**itBegin).name << endl;//或者
	}
}

容器記憶體放容器

	vector<vector<A>> v;
	A a1 = { "a1" };
	A a2 = { "a2" };
	A a3 = { "a3" };
	vector<A> v1;
	v1.push_back(a1);
	v1.push_back(a2);
	v1.push_back(a3);

	vector<A> v2;
	v2.push_back(a1);
	v2.push_back(a3);
	v2.push_back(a2);

	vector<A> v3;
	v3.push_back(a1);
	v3.push_back(a3);
	v3.push_back(a2);

	v.push_back(v1);
	v.push_back(v2);
	v.push_back(v3);

	for (vector<vector<A>>::iterator itBegin = v.begin(); itBegin != v.end(); itBegin++){
		for (vector<A>::iterator itb = itBegin->begin(); itb != itBegin->end(); itb++) {
			cout << itb->name << endl;
		}
	}

vector 構造

  • vector<T> v 采用模板實作,默認構造
  • vector(v.begin(),v.end()) 將v[begin(),end()]區間中的元素拷貝給本身
  • vector(n,elem) 構造將n個elem拷貝給本身
  • vector(const vector &vec) 拷貝構造
int main() {
	vector<int> v;
	for (int i = 0; i < 10; i++){
		v.push_back(i);
	}

	//把v的begin到end的資料復制給v2
	vector<int> v2(v.begin(), v.end());

	//創建10個100放到v3
	vector<int> v3(10, 100);

	//拷貝構造
	vector<int> v4(v3);

	for (vector<int>::iterator it = v3.begin(); it != v3.end(); it++) {
		cout << *it << endl;
	}
}

vector 賦值操作

  • vector& operator=(const vector &vec) 多載=
  • assign(beg,end) 將v[begin(),end()]區間中的元素拷貝給本身
  • assign(n,elem) 將n個elem拷貝賦值給本身
int main() {
	vector<int> v;
	for (int i = 0; i < 10; i++){
		v.push_back(i);
	}

	//直接=賦值
	vector<int> v2 = v;

	vector<int> v3;
	//把v的begin到end資料賦值給v3
	v3.assign(v.begin(), v.end());

	//放10個100到v4里面
	vector<int> v4;
	v4.assign(10, 100);


	for (vector<int>::iterator it = v4.begin(); it != v4.end(); it++) {
		cout << *it << endl;
	}
}

vector 容量和大小

  • empty() 回傳容器是否為空
  • capacity() 容器的容量
  • size() 回傳容器中的元素個數
  • resize(int num) 重新定義容器長度為num,若大于原長度,則新位置填充默認值,若小于原長度,超出部分元素被洗掉
  • resize(int num,elem) 重新定義容器長度為num,若大于原長度,則新位置填充elem,若小于原長度,超出部分元素被洗掉
int main() {
	vector<int> v;
	for (int i = 0; i < 10; i++){
		v.push_back(i);
	}
	cout << v.empty() << endl;
	cout << v.capacity() << endl;
	cout << v.size() << endl;
	v.resize(9);
	v.resize(9,4);
}

vector 插入和洗掉

  • push_back(ele) 尾部插入元素ele
  • pop_back() 洗掉最后一個元素
  • insert(const_iterator pos,ele) 迭代器指向位置pos插入元素ele
  • insert(const_iterator pos,int count,ele) 迭代器指向位置pos插入count個元素ele
  • erase(const_iterator pos) 洗掉迭代器指向的元素
  • erase(const_iterator start,const_iterator end) 洗掉迭代器從start到en之間的元素
  • clear() 洗掉容器中所有元素
int main() {
	vector<int> v;
	for (int i = 0; i < 10; i++){
		v.push_back(i);
	}
	
	v.push_back(1);
	v.pop_back();
	v.insert(v.begin(), 1);
	v.insert(v.begin(), 1, 2);
	v.erase(v.begin());
	v.erase(v.begin(), v.end());
	v.clear();
}

vector 資料存取

  • at(int index) 回傳索引指向的資料
  • operator[] 回傳索引指向的資料
  • front() 回傳容器中第一個元素
  • back() 回傳最后一個元素
int main() {
	vector<int> v;
	for (int i = 0; i < 10; i++) {
		v.push_back(i);
	}

	cout << v.at(2) << endl;
	cout << v[2] << endl;
	cout << v.front() << endl;
	cout << v.back() << endl;
}

vector 互換容器

  • swap(vec) 與另一個vector容器互換元素
int main() {
	vector<int> v;
	for (int i = 0; i < 10; i++) {
		v.push_back(i);
	}

	vector<int> v2;
	for (int i = 0; i < 5; i++) {
		v2.push_back(i);
	}


	v.swap(v2);

	for (vector<int>::iterator t = v.begin(); t != v.end(); t++) {
		cout << *t;
	}
	cout << "\n";
	for (vector<int>::iterator t = v2.begin(); t != v2.end(); t++) {
		cout << *t ;
	}

}

還可以使用swap來重構vector的大小

例如有一個容量為1萬的容器,之后洗掉到只剩10個元素,現在希望縮小它的容量

int main() {
	vector<int> v;
	for (int i = 0; i < 10000; i++) {
		v.push_back(i);
	}

	vector<int>(v).swap(v);
}

首先vector<int>(v)呼叫復制拷貝來初始化一個新的vector物件,會使用v的元素個數來初始化新vector的容量大小,之后交換兩個容器的指標,因為是匿名物件,運行完銷毀原來的容器占用空間

vector 預留空間

減少vector在動態擴展容量時的次數

  • reserve(int len) 給容器預留len個位置,預留位置不可訪問,不初始化
int main() {
	vector<int> v;
//	v.reserve(100000);
	int number = 0;
	int* p = NULL;
	for (int i = 0; i < 100000; i++) {
		v.push_back(i);
		if (p != &(v[0])) {
			p = &(v[0]);
			number++;
		}
	}
    //查看擴容次數
	cout << number << endl;
}

deque容器

雙端操作,可以對頭端進行插入洗掉,也支持隨機訪問

deque與vector的區別

  • vector對于頭部的插入洗掉效率低,資料量越大,效率越低

  • deque相對vector頭部的插入洗掉速度要快

  • vector訪問元素時的速度會比deque快

  • deque<T> deqT; 默認構造

  • deque(beg,end) 建構式將beg,end區間的元素拷貝給本身

  • deque(n,elem) 建構式將n個elem拷貝給本身

  • deque(const deque &deq) 拷貝構造

#include <iostream>
#include <deque>
using namespace std;



void pirnt(deque<int> &d) {

	for (deque<int>::iterator i = d.begin(); i != d.end(); i++) {
		cout << *i << endl;
	}

}

int main() {
	//默認構造
	deque<int> d;
	for (int i = 0; i < 10; i++)
	{
		//尾部添加
		//d.push_back(i);
		//頭添加
		d.push_front(i);
	}
	
	//pirnt(d);
	cout << "====" << endl;
	 
	deque<int> d2(++d.begin(), d.end());
	
	//初始化10個100
	deque<int> d3(10, 100) ;
	
	//拷貝構造
	deque<int> d4(d3);
	pirnt(d4);
}

deque賦值操作

  • deque&~operator=(const deque &deq) 多載等號
  • assign(beg,end) 將beg,end區間資料拷貝賦值給本身
  • assign(n,elem) 將n個elem賦值給本身

#include <deque>
using namespace std;

void pirnt(const deque<int> &d) {

	for (deque<int>::const_iterator i = d.begin(); i != d.end(); i++) {
		cout << *i << endl;
	}

}

int main() {
	//默認構造
	deque<int> d;
	for (int i = 0; i < 10; i++)
	{
		//尾部添加
		//d.push_back(i);
		//頭添加
		d.push_front(i);
	}
	
	//pirnt(d);
	cout << "====" << endl;
	 
	deque<int> d2;
	//多載=賦值
	d2 = d;


	deque<int> d3;
	d3.assign(d2.begin(), d2.end());


	deque<int> d4;
	d4.assign(10, 100);

	pirnt(d4);
}

deque大小操作

  • deque.empty() 判斷容器是否為空
  • deque.size() 回傳容器中的元素個數
  • deque.resize(num) 重新指定容器長度num,若容器邊長,則默認值填充新位置,若變短,洗掉末尾元素
  • deque.resize(num,elem) 重新指定容器長度num,若容器邊長,則elem填充新位置,若變短,洗掉末尾元素

deque沒有容量概念

void pirnt(const deque<int> &d) {

	for (deque<int>::const_iterator i = d.begin(); i != d.end(); i++) {
		cout << *i << endl;
	}

}

int main() {
	//默認構造
	deque<int> d;
	for (int i = 0; i < 10; i++)
	{
		//尾部添加
		//d.push_back(i);
		//頭添加
		d.push_front(i);
	}
	
	cout << d.empty() << endl;
	cout << d.size() << endl;
	d.resize(15, 6);
	pirnt(d);
	cout << "====" << endl;
	d.resize(5);
	pirnt(d);
}

deque插入洗掉

兩端插入

  • push_back(e) 尾部添加e
  • push_front(e) 頭部插入e
  • pop_back() 洗掉最后的一個元素
  • poh_front() 洗掉第一個元素

指定位置插入

  • insert(pos,elem) 在pos位置插入elem元素的拷貝,回傳新資料的位置
  • insert(pos,n,elem) 在pos位置插入n個elem資料,無回傳值
  • insert(pos,beg,end) 在pos插入beg,end區間的資料,無返
  • clear() 清空容器
  • erase(beg,end) 洗掉beg-end區間的資料,回傳下一個資料的位置
  • erase(pos) 洗掉pos位置的資料,回傳下一個資料的位置
int main() {
	//默認構造
	deque<int> d;
	//尾部添加
	d.push_back(1);
	//頭添加
	d.push_front(2);
	//尾刪
	d.pop_back();
	//頭刪
	d.pop_front();
	//根據位置插入回傳一個迭代器
	deque<int>::iterator i = d.insert(d.begin(), 1);
	//插入兩個10
	d.insert(d.begin(), 2, 10);
	//在頭部添加了容器中所有的元素
	d.insert(d.begin(), d.begin(), d.end());
	//從第二個刪到倒數第二個
	deque<int>::iterator i2=d.erase(++d.begin(), --d.end());
	//洗掉第一個
	d.erase(d.begin());
	//清空
	d.clear();
}

deque資料存取

  • at(int ind) 回傳ind位置的資料
  • operator[] 回傳索引位置的資料
  • front() 回傳第一個元素
  • back() 回傳容器最后一個元素
int main() {
	//默認構造
	deque<int> d;
	d.push_front(1);
	d.push_front(2);
	d.push_front(3);
	d.push_front(4);
	//多載[]符
	cout << d[2] << endl;
	//at獲取
	cout << d.at(2) << endl;
	//取第一個
	cout << d.front() << endl;
	//取最后一個
	cout << d.back() << endl;
}

stack容器

堆疊容器,先進后出,只有頂端元素才能被使用,因此堆疊不允許有遍歷行為

stack構造

  • stack<T> stk 默認構造
  • stack(const stack &stk); 拷貝構造

stack賦值

  • stack& operator=(const stack &stk) 多載=

stack資料存取

  • push(elem) 壓入一個元素
  • pop() 彈出一個元素
  • top() 獲取堆疊頂元素

stack大小

  • empty() 回傳是否為空
  • size() 回傳堆疊大小
#include <stack>
using namespace std;
int main() {
	stack<int> s;
	//壓入一個元素
	s.push(1);
	s.push(2);

	//拷貝構造
	stack<int> s2(s);
	//多載=賦值
	stack<int> s3 = s2;

	//是否為空
	cout << s3.empty() << endl;
	//彈出一個元素
	s3.pop();
	//堆疊大小
	cout << s3.size() << endl;
	//獲取堆疊頂元素
	cout << s3.top() << endl;
}

queue容器

佇列,先進先出,只有頭尾能被外界訪問,因此沒有遍歷行為

queue構造

  • queue<T> que; 默認構造
  • queue(const queue & q) 拷貝構造

queue賦值操作

  • queue& operator=(const queue &que) 多載=

queue資料存取

  • push(e) 隊尾添加一個元素
  • pop() 隊頭移出第一個元素
  • back() 回傳最后一個元素
  • front() 回傳第一個元素

queue大小操作

  • empty() 回傳是否為空
  • size() 回傳大小
#include <queue>
using namespace std;

int main() {
	queue<int> q;
	queue<int> q2(q);
	queue<int> q3 = q2;

	q3.push(1);
	q3.push(2);
	q3.pop();
	cout << q3.front() << endl;
	cout << q3.back() << endl;
	cout << q3.size();
	cout << q3.empty();
}

list容器

通過雙向鏈表實作,list的迭代器只支持前移和后移,屬于雙向迭代器

list構造

  • list<T> list 默認構造
  • list(beg,end) 建構式將beg-end區間元素拷貝給本身
  • list(n,elem) 使用n個elem初始化本身
  • list(const list &list) 拷貝構造
#include <iostream>
#include <list>
using namespace std;

int main() {
	//默認構造
	list<int> l;
	//拷貝構造
	list<int> l2(l);
	//區間賦值
	list<int> l3(l2.begin(), l2.end());
	//使用4個5初始化
	list<int> l4(4, 5);
}

list賦值和交換

  • assign(beg,end) 將beg-end區間資料拷貝給本身
  • assign(n,m) 將n個m拷貝賦值給本身
  • list& operatpr=(const list &list) 多載=
  • swap(list) 交換
#include <iostream>
#include <list>
using namespace std;

int main() {
	//默認構造
	list<int> l;
	l.assign(6, 1);

	list<int> l2;
	l2.assign(l.begin(), l.end());
	//多載=
	list<int> l3 = l2;

	list<int> l4;
	//交換
	l4.swap(l3);

	for (list<int>::iterator it = l4.begin(); it != l4.end(); it++) {
		cout << *it << endl;
	}

}

list大小操作

  • size() 回傳容器中元素個數
  • empty() 回傳是否為空
  • resize(n) 重新指定長度為n,如果邊長,則默認值填充新位置,變短則超出長度的元素被洗掉
  • resize(n,e)重新指定長度為n,如果邊長,則e填充新位置,變短則超出長度的元素被洗掉
int main() {
	//默認構造
	list<int> l;
	l.assign(6, 1);
	l.resize(10);
	l.resize(15,7);

	for  (auto a : l)
	{
		cout << a ;
	}
	cout << l.size() << endl;
	cout << l.empty() << endl;
}

list插入洗掉

  • push_back(e) 尾部加入一個元素
  • pop_back() 洗掉容器中最后一個元素
  • push_front(e) 頭部插入一個元素
  • pop_front() 頭部洗掉一個元素
  • insert(pos,elem) 在pos位置插入elem元素的拷貝,回傳新資料位置
  • insert(pos,n,elem) 在pos位置插入n個elem,無返
  • insert(pos,beg,end) 在pos位置插入beg-end區間資料,無返
  • clear() 移除容器所有資料
  • erase(beg,end) 移除beg-end區間資料,回傳下一個資料的位置
  • erase(pos) 移除pos位置資料,回傳下一個元素的位置
  • remove(elem) 洗掉容器中所有和elem值匹配的元素
int main() {
	//默認構造
	list<int> l;
	//尾部添加
	l.push_back(1);
	l.push_back(2);
	l.push_back(3);
	//洗掉尾部
	l.pop_back();
	//洗掉頭部
	l.pop_front();

	list<int> l2;
	l2.insert(l2.begin(), 2);
	l2.insert(l2.begin(), 2, 1);
	l2.insert(l2.begin(), l.begin(), l.end());
	l2.clear();
	l2.erase(++l2.begin(), --l2.end());
	l2.erase(l2.begin());
	l2.remove(2);
}

list資料獲取

  • front() 回傳第一個元素
  • back() 回傳最后一個元素
int main() {
	//默認構造
	list<int> l;
	//尾部添加
	l.push_back(1);
	l.push_back(2);
	l.push_back(3);
	cout<<l.back();
	cout << l.front();
}

list反轉和排序

因為list不支持隨機訪問,所以不能用自帶的sort排序

  • revers() 反轉鏈表
  • sort() 鏈表排序 默認從小到大
bool a(int a,int b) {
	return a > b;
}

int main() {
	//默認構造
	list<int> l;
	//尾部添加
	l.push_back(1);
	l.push_back(4);
	l.push_back(3);
	l.reverse();
	//如果想自定義排序規則,傳入方法a
	l.sort(a);
	cout<<l.back();
	cout << l.front();
}

自定義資料型別排序

#include <iostream>
#include <list>
#include <string>
using namespace std;

class User {
public:
	User() {
	}
	User(int _age, int _money, string _name):age(_age), money(_money), name(_name) {
	}
	int age;
	int money;
	string  name;
};

bool a(User &a, User &b) {
	
	if (a.age >= b.age) {
		return a.money >= b.money;
	}
	return false;

}

int main() {
	User u1 = { 18,600,"小明" };
	User u2 = { 30,300,"小王" };
	User u3 = { 20,400,"小周" };

	list<User> l;

	l.push_back(u1);
	l.push_back(u2);
	l.push_back(u3);
	l.sort(a);

	for (list<User>::iterator it = l.begin(); it != l.end(); it++) {
		cout << it->age << "=" << it->money << "=" << it->name << endl;
	}
}

set/multiset容器

所有元素都會在插入時自動被排序.set/multiset屬于關聯式容器,底層使用二叉樹實作

set和multiset區別:

  • set不允許有重復的元素,插入會回傳插入結果和插入位置的迭代器
  • multiset允許存在重復的元素,回傳插入只有插入位置的迭代器

set的構造和賦值

構造:

  • set<T> st 默認構造
  • set(const set& st) 拷貝構造

賦值:

  • set& operator=(const set& set) 多載=
#include <iostream>
#include <set>
using namespace std;

int main() {
	set<int> s;
	s.insert(1);
	set<int> s2(s);
	set<int> s3 = s2;

	for (set<int>::iterator it = s3.begin(); it != s3.end(); it++) {
		cout << *it << endl;
	}
}

set容器大小和交換

  • size() 回傳元素個數
  • empty() 回傳是否為空
  • swap(st) 交換兩個集合容器
#include <iostream>
#include <set>
using namespace std;

int main() {
	set<int> s;
	s.insert(1);
	s.insert(1);
	cout << s.empty() << endl;
	cout << s.size() << endl;
	set<int> s2;
	s2.swap(s);
	cout << s2.size() << endl;
}

set的插入洗掉

  • insert(elem) 容器插入元素
  • clear() 清空所有元素
  • erase(pos) 洗掉pos迭代器所指向的元素,回傳下一個元素的迭代器
  • erase(beg,end) 洗掉區間beg-end的所有元素,回傳下一個元素的迭代器
  • erase(elem) 洗掉容器中值為elem的元素
#include <iostream>
#include <set>
using namespace std;

int main() {
	set<int> s;
	s.insert(1);
	s.clear();
	s.insert(2);
	s.insert(3);
	s.insert(4);
	s.insert(5);

	set<int>::iterator it1 = s.erase(s.begin());
	set<int>::iterator it2 = s.erase(s.begin(), --s.end());
	int a = s.erase(5);
}

set容器查找和統計

  • find(key) 查找元素是否存在,回傳元素的迭代器,如果不存在回傳set.end()
  • count(key) 統計key的元素個數 在set中作用不大,因為不可重復,要么0要么1
#include <iostream>
#include <set>
using namespace std;

int main() {
	set<int> s;
	s.insert(1);
	s.insert(2);
	set<int>::iterator it=s.find(1);
	if (it != s.end()) {
		cout << "find!" << endl;
	}
	else {
		cout << "null" << endl;
	}
	cout << s.count(1) << endl;
}

兩個set插入回傳結果

#include <iostream>
#include <set>
using namespace std;

int main() {
	set<int> s;
	pair<set<int>::iterator, bool> p = s.insert(1);
	set<int>::iterator it = p.first;
	cout << p.second << endl; 

	multiset<int> ms;
	set<int>::iterator it2= ms.insert(1);
}

pair對組創建

成對出現的資料,利用對組可以回傳兩個資料

  • pair<type,type p (v1,v2)
  • pair<type,type> p=make_pair(v1,v2)
#include <iostream>
#include <set>
using namespace std;

int main() {
	pair<string, int> p("老王", 50);
	cout << p.first << endl; //輸出第一個
	cout << p.second << endl;//輸出第二個

	pair<string, int> p2 = make_pair("小明", 15);
	cout << p2.first << endl;
	cout << p2.second << endl;
}

set容器排序

利用仿函式,修改排序規則

#include <iostream>
#include <set>
using namespace std;

class MyCompare {

public:
    //這里需要加const作用不知道,以后學了在回來解釋
	bool operator() (int v1,int v2)const {
		return v1 > v2;
	}

};

int main() {
	set<int,MyCompare> s;
	s.insert(4);
	s.insert(1);
	s.insert(2);
	s.insert(3);
	

	for (set<int>::iterator it = s.begin(); it != s.end(); it++) {
		cout << *it << endl;
	}
}

自定義型別的排序

對于自定義的資料型別,必須指定排序規則才能插入

#include <iostream>
#include <set>
using namespace std;

class People {
public:

	People(int _age) :age(_age) {

	}
	int age;

};


class MyCompare {

public:
    //	bool operator() (const People& v1,const  People& v2)const 
    //只加& 就會報錯 必須加const修飾
	bool operator() (People v1, People v2)const {
		return v1.age > v2.age;
	}

};




int main() {
	set<People,MyCompare> s;

	s.insert(People(1));
	s.insert(People(4));
	s.insert(People(6));
	s.insert(People(2));

	for (set<People>::iterator it = s.begin(); it != s.end(); it++) {
		cout << it->age << endl;
	}
}

map/multimap容器

  • map的所有元素都是pair
  • pair的第一個元素為key,起到索引作用,第二個元素的value
  • 所有元素都會根據元素的鍵值自動排序
  • map/multimap都屬于關聯式容器,底層是用二叉樹實作
  • 可以根據key快速找到value

二者區別: map不允許存在相同的key,mulitmap可以存在

map構造和賦值

  • map<T1,T2> m 默認構造
  • map(const map& m) 拷貝構造
  • map& operator=(consst map& m) 多載=
#include <iostream>
#include <map>
using namespace std;

int main() {
	map<int, int> m;
	m.insert(pair<int, int>(1, 10));
	m.insert(pair<int, int>(2, 20));
	m.insert(pair<int, int>(3, 30));
	m.insert(pair<int, int>(4, 40));

	map<int, int> m1(m);
	map<int, int>m2 = m1;
	

	for (map<int, int>::iterator it = m2.begin(); it != m2.end(); it++) {
		cout << it->first << "===" << it->second << endl;
	}
}

map大小和交換

  • size() 回傳元素個數
  • empty() 回傳是否為空
  • swap(m) 交換兩個map的元素
int main() {
	map<int, int> m;
	m.insert(pair<int, int>(1, 10));
	m.insert(pair<int, int>(2, 20));
	m.insert(pair<int, int>(3, 30));
	m.insert(pair<int, int>(4, 40));

	map<int, int> m2;
	m2.swap(m);

	cout << m2.size() << endl;
	cout << m2.empty() << endl;
}

map的插入和洗掉

  • insert(elem) 容器插入元素
  • clear() 清空元素
  • erase(pos) 洗掉pos迭代器指向的元素,回傳下一個元素的迭代器
  • erase(beg,end) 洗掉區間beg-end的元素,回傳下一個元素的迭代器
  • erase(key) 根據key洗掉元素
int main() {
	map<int, int> m;
	m.insert(pair<int, int>(1, 10));
	m.clear();
	m.insert(pair<int, int>(2, 20));
	m.insert(make_pair(3, 30));
	m.insert(map<int,int>::value_type(4,40));
    //不要使用[]方式來獲取,因為如果沒有這個就會給你創建一個key為5,value為0的元素
	m[5] = 50;
	map<int, int>::iterator it = m.erase(m.begin());
	map<int, int>::iterator it2 = m.erase(m.begin(), --m.end());
	int deleted = m.erase(5);
	cout << m.size();
}

map查找和統計

  • find(key) 查找key是否存在,回傳元素的迭代器,不存在回傳set.end()
  • count(key) 統計key的個數,map中不是0就是1,在multimap中有用
int main() {
	map<int, int> m;
	m.insert(pair<int, int>(1, 10));
	m.insert(make_pair(2, 20));
	map<int,int>::iterator it=m.find(1);
	
	cout << it->first<<"====" << it->second << endl;
	cout << m.count(1) << endl;

}
int main() {
	multimap<int, int> m;
	m.insert(pair<int, int>(1, 10));
	m.insert(make_pair(1, 20));
	multimap<int,int>::iterator it=m.find(1);
	
	cout << it->first<<"====" << it->second << endl;
	it++;
	cout << it->first<<"====" << it->second << endl;
	cout << m.count(1) << endl;
}

map排序

利用仿函式,改變排序規則 兩個引數是key,根據key排

class MyR {
public :
	bool operator()( int p1,  int p2) const  {
		return p1>p2;
	}


};

int main() {
	multimap<int, int, MyR> m;
	m.insert(pair<int, int>(1, 10));
	m.insert(make_pair(2, 20));
	m.insert(make_pair(4, 40));
	m.insert(make_pair(3, 30));

	for (map<int, int>::iterator it = m.begin(); it != m.end(); it++) {
		cout << it->first << "==" << it->second << endl;
	}
}

STL函式物件

函式物件

  • 多載函式呼叫運算子的類,其物件稱為函式物件
  • 函式物件使用多載的()時,行為類似函式的呼叫,也叫仿函式
  • 函式物件(仿函式)是一個類,不是一個函式

函式物件的使用

  • 函式物件使用可以像普通函式一樣,有引數和回傳值
  • 函式物件超出了普通函式的概念呢,函式物件可以有自己的狀態
  • 函式物件可以作為引數
class MyR {
public :

	bool v() {
		this->count++;
		return false;
	}
	
	bool operator()( int p1,  int p2){
		this->count++;
		cout << "operator" << endl;
		return p1<p2;
	}

	int count = 0;

};

int main() {
	MyR mr;
	mr(1, 2);
	mr(1, 2);
	mr(1, 2);
	cout << mr.count << endl;
}
class MyR {
public :

	bool v() {
		this->count++;
		return false;
	}
	
	bool operator()( int p1,  int p2){
		this->count++;
		cout << "operator" << endl;
		return p1<p2;
	}

	int count = 0;

};
void print(MyR & m,int a,int b) {
	m(a, b);
}
int main() {
	MyR mr;
	print(mr, 1, 2);
}

謂詞

回傳bool型別的仿函式稱為謂詞

如果operator接收一個引數,叫一元謂詞,兩個就叫二元謂詞

class MyR {
public :
	bool operator()( int a){
		return a>0;
	}
};

int main() {
	vector<int> v;
	v.push_back(-1);
	v.push_back(1);
	v.push_back(3);
	v.push_back(-2);
	v.push_back(2);


	for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
		vector<int>::iterator it2 = find_if(it, v.end(), MyR());
		it = it2;
		cout << *it2 << endl;
	}
} 
class MyR {
public :
	bool operator()( int a,int b){
		return a<b;
	}
};

int main() {
	vector<int> v;
	v.push_back(-1);
	v.push_back(1);
	v.push_back(3);
	v.push_back(-2);
	v.push_back(2);
	
	sort(v.begin(), v.end(), MyR());


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

內建函式物件

分類:

  • 算術仿函式
  • 關系仿函式
  • 邏輯仿函式

這些仿函式產生的物件,用法和普通函式完全相同

使用內建函式物件,需要引入頭檔案#include <functional>

算術仿函式

其中negate是一元,其他都是二元

  • template<class T> T plus<T> 加法
  • template<class T> T minus<T> 減法
  • template<class T> T multiplies<T> 乘法
  • template<class T> T divides<T> 除法
  • template<class T> T modulus<T> 取模
  • template<class T> T negate<T> 取反
#include <iostream>
#include <functional>
using namespace std;




int main() {
	negate<int> n;
	cout << n(2) << endl;

	minus<int> m;
	cout << m(10, 4) << endl;
}

關系仿函式

  • template<class T> bool equal_to<T> 等于
  • template<class T> bool not_equal_to<T> 不等于
  • template<class T> bool greater<T> 大于
  • template<class T> bool greater_equal<T> 大于等于
  • template<class T> bool less<T> 小于
  • template<class T> bool less_equal<T> 小于等于
#include <iostream>
#include <functional>
using namespace std;

int main() {
	less<int> l;
	cout << l(10, 20) << endl;

	equal_to<int> e;
	cout << e(10, 20) << endl;
}
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

	sort(v.begin(), v.end(), greater_equal<int>());

	for (vector<int>::iterator i = v.begin(); i != v.end(); i++) {
		cout << *i << endl;
	}
}

邏輯仿函式

  • template<class T> bool logical_and
  • template<class T> bool logical_or
  • template<class T> bool logical_not 非'

移動資料同時取反

#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
using namespace std;

int main() {
	vector<bool> v;
	v.push_back(1);
	v.push_back(0);
	v.push_back(1);
	v.push_back(0);

	vector<int> v2;
    //需要提前開辟空間
	v2.resize(v.size());

	transform(v.begin(), v.end(), v2.begin(), logical_not<bool>());

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

STL常用演算法

  • 演算法主要由頭檔案<algorithm> functional numberic 組成
  • <algorithm> 是所有STL頭檔案中最大的一個,涉及范圍比較,交換查找,遍歷,復制,修改
  • <numberic> 體積很小只包括幾個序列上面進行簡單數學運算和模板函式
  • <functional> 定義了一些模板類,用以宣告函式物件

遍歷

for_each

for_each(iterator beg,iterator end,_func)

beg 開始迭代器,

end 結束迭代器,

func函式或函式物件

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//普通函式
void print(bool a) {
	cout << a << endl;
}
//仿函式
class print2 {
public:
	void operator()(int a) {
		cout << a << endl;
	}

};

int main() {
	vector<bool> v;
	v.push_back(1);
	v.push_back(0);
	v.push_back(1);
	v.push_back(0);
	for_each(v.begin(), v.end(), print);
	for_each(v.begin(), v.end(), print2());
}

transform

將容器中元素轉移到另一個容器

轉移的容器需要提前開辟空間

transform(iterator beg, iterator end, iterator beg2, _func)

beg 原始容器開始迭代器

end 原始容器結束迭代器,

beg2 目標容器開始迭代器

func函式或函式物件

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

//普通函式
bool tran(bool a) {
	return !a;
}



//普通函式
bool print(bool a) {
	cout << a << endl;
	return a;
}


int main() {
	vector<bool> v;
	v.push_back(1);
	v.push_back(0);
	v.push_back(1);
	v.push_back(0);
	
	vector<bool> v2;
	v2.resize(v.size());

	transform(v.begin(),v.end(),v2.begin(), tran);

	for_each(v2.begin(), v2.end(), print);
}

查找

find

查找指定元素,找到回傳對應位置的迭代器,否則回傳end()

find(iterator beg,iterator end,value)

beg 開始迭代器

end 結束迭代器

value 元素

基礎資料型別

int main() {
	vector<bool> v;
	v.push_back(1);
	v.push_back(0);
	v.push_back(1);
	v.push_back(0);

	vector<bool>::iterator it = find(v.begin(), v.end(), 0);
	while (it != v.end())
	{
		cout << *it << endl;
		it = find(++it, v.end(), 0);
	}
}

自定義資料型別

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;


class A {
public:
	A(int _a):a(_a) {
	}
	int a;

	bool operator==(const A& a) {
		return this->a == a.a;
	}
};


/*
* 底層是呼叫==來判斷,我們需要多載==
    for (; _First != _Last; ++_First) {
        if (*_First == _Val) {
            break;
        }
    }
*/
int main() {
	vector<A> v;
	A a(1);
	v.psh_back(a);
	v.push_back(A(4));
	v.push_back(A(2));
	v.push_back(A(3));

	vector<A>::iterator it = find(v.begin(), v.end(),a);
	while (it != v.end())
	{
		cout << it->a << endl;
		it = find(++it, v.end(), 0);
	}
}

find_if

條件查找,找到回傳指向元素位置的迭代器,否則回傳end()

find_if(iterator beg, iterator end, _Pred)

beg 開始迭代器

end 結束迭代器

_Pred 函式或謂詞

基礎資料型別

bool myFind(int a) {
	return a == 3;
}


int main() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	
	vector<int>::iterator it = find_if(v.begin(), v.end(), myFind);
	while (it != v.end()){
		cout << *it << endl;
		it = find(++it, v.end(), 0);
	}
}

自定義資料型別

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class User {
public:

	User(int _age) :age(_age) {
	}
	int age;
};

class MyG {

public:
	bool operator()(const User& u) {
		return u.age == 100;
	}

};

int main() {
	vector<User> v;

	v.push_back(User(100));
	v.push_back(User(120));
	v.push_back(User(100));

	vector<User>::iterator it = find_if(v.begin(), v.end(), MyG());
	while (it != v.end()) {
		cout << it->age << endl;
		it = find_if(++it, v.end(), MyG());
	
	}
}

adjavent_find

查找相鄰重復元素,回傳相鄰元素第一個迭代器

adjavent_find(iterator beg, iterator end)

beg 迭代器開始

end 迭代器結束

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

void test1() {
	vector<int> v;
	v.push_back(1);
	v.push_back(1);
	v.push_back(3);
	v.push_back(2);
	v.push_back(2);
	v.push_back(3);

	
	vector<int>::iterator it = adjacent_find(v.begin(), v.end());
	cout << *it << endl;

}

查找指定元素是否存在,在無序列中不可用,回傳bool型別

binary_search(iterator beg, iterator end, value)

beg 開始迭代器

end 結束迭代器

value 值

void test1() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);


	cout<<binary_search(v.begin(), v.end(), 4);

}

count

統計元素個數

count(iterator beg, iterator end, value)

beg 開始迭代器

end 結束迭代器

value 值

void test1() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(2);

	cout<<count(v.begin(),v.end(),2);

}

count_if

按條件統計元素個數

count_if(iterator beg,iterator end, _Pred)

_pred 謂詞

class My {

public:
	bool operator()(const int a){
		return a >= 2;
	}

};


void test1() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(2);

	cout << count_if(v.begin(), v.end(), My());

}

排序

sort

sort(iterator beg, iterator end, _Pred)

void test1() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(2);


	sort(v.begin(), v.end());
	sort(v.begin(), v.end(), greater<int>());
}

random_shuffle

洗牌,指定范圍內元素隨機調整次序

random_shuffle(iterator beg, iterator end)

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <ctime>

void pirnt(int a) {
	cout << a << endl;
}
void test1() {
    //隨機種子
    srand((unsigned int)time(NULL));
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(2);

	random_shuffle(v.begin(), v.end());
	for_each(v.begin(), v.end(), pirnt);
}

merge

合并兩個容器元素到另一個容器中,注意,兩個容器必須是有序的

merge(iterator beg1, iterator end1, iterator beg2, iterator beg2, iterator dest)


void test1() {
	
	vector<int> v;
	v.push_back(1);
	v.push_back(2);

	vector<int> v2;
	v2.push_back(2);
	v2.push_back(3);


	vector<int> v3;
	//先開辟空間
	v3.resize(v.size() + v2.size());

	//合并不會去重
	merge(v.begin(), v.end(), v2.begin(), v2.end(), v3.begin());

	for_each(v3.begin(), v3.end(), pirnt);
}

reverse

將容器內元素進行反轉

reverse(iterator beg, iterator end)

void test1() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
    
	reverse(v.begin(), v.end());
    
	for_each(v.begin(), v.end(), pirnt);
}

拷貝和替換

copy

容器指定范圍元素拷貝到另一容器中

copy(iterator beg, iterator end, iterator dest)

void test1() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

	vector<int> v2;
	v2.resize(v.size());

	copy(v.begin(), v.end(), v2.begin());

	for_each(v2.begin(), v2.end(), pirnt);
}

replace

將容器指定范圍內的元素替換

replace(iterator beg, iterator end, oldValue, newValue)

void test1() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

	replace(v.begin(), v.end(), 1, 6);
	
	for_each(v.begin(), v.end(), pirnt);
}

replae_if

在指定區間內判斷如果符合條件則替換元素

replace_if(iterator beg, iterator end, _pred, newValue)

class My {
public:
	bool operator()(const int a) {
		return a >= 2;
	}
};

void pirnt(int a) {
	cout << a << endl;

}
void test1() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

	replace_if(v.begin(), v.end(), My(), 6);
	
	for_each(v.begin(), v.end(), pirnt);
}

swap

互換兩個容器中的元素,兩個容器的型別需要相同

swap(container c1, container c2)

void test1() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

	vector<int> v2;
	v2.push_back(444);
	swap(v, v2);
	
	for_each(v.begin(), v.end(), pirnt);
	cout << "===========" << endl;
	for_each(v2.begin(), v2.end(), pirnt);
}

算術生成

包含頭檔案#include <numeric>

accumulate

accumulate(iterator beg, iterator end, value)

value 起始值

計算區間容器元素總和

void test1() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

	cout<<accumulate(v.begin(), v.end(),0);
	
}

fill

向容器內填充指定元素

fill(iterator beg,iterator end,value)

void test1() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);

	fill(v.begin(), v.end(),0);
	
	for_each(v.begin(), v.end(), pirnt);
	
}

集合演算法

set_intersection

求兩個集合的交集,源容器必須是有序序列

set_interaection(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest)

void test1() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);

	vector<int> v1;
	v1.push_back(2);
	v1.push_back(3);

	vector<int> v2;
	//先初始化空間,任意一個集合的大小都行,因為交集不可能大于任意一個集合
	//使用min取最小的大小
	v2.resize(min(v.size(),v1.size()));
	
	vector<int>::iterator itEnd =set_intersection(v.begin(), v.end(), v1.begin(), v1.end(), v2.begin());

	for_each(v2.begin(), itEnd, pirnt);
}

set_union

取并集,源容器必須是有序序列

set_union(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest)

void test1() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);

	vector<int> v1;
	v1.push_back(2);
	v1.push_back(3);

	vector<int> v2;
	//先初始化空間,最極端的情況就是兩個容器中沒有相同的元素
	v2.resize(v.size()+v1.size());
	
	vector<int>::iterator itEnd=set_union(v.begin(), v.end(), v1.begin(), v1.end(), v2.begin());

	for_each(v2.begin(), itEnd, pirnt);
}

set_difference

set_difference(iterator beg1,iterator end1,iterator beg2,iterator end2,iterator dest)

取差集,源容器必須是有序序列

void test1() {
	vector<int> v;
	v.push_back(1);
	v.push_back(2);

	vector<int> v1;
	v1.push_back(2);
	v1.push_back(3);

	vector<int> v2;
	//先初始化空間,差集不可能大于自己
	v2.resize(v.size());
	
	vector<int>::iterator itEnd=set_difference(v.begin(), v.end(), v1.begin(), v1.end(), v2.begin());

	for_each(v2.begin(), itEnd, pirnt);
}

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

標籤:C++

上一篇:【C++】extern "C"詳解

下一篇:OpenGL ES OpenGL WebGL EGL WGL 區別

標籤雲
其他(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)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more