容器
容器,就是用來(lái)存放東西的盒子。
常用的數(shù)據(jù)結(jié)構(gòu)包括:數(shù)組array, 鏈表list, 樹(shù)tree, 棧stack, 隊(duì)列queue, 散列表hash table, 集合set、映射表map 等等。容器便是容納這些數(shù)據(jù)結(jié)構(gòu)的。這些數(shù)據(jù)結(jié)構(gòu)分為序列式與關(guān)聯(lián)式兩種,容器也分為序列式容器和關(guān)聯(lián)式容器。
STL 標(biāo)準(zhǔn)模板庫(kù),核心包括容器、算法、迭代器。
序列式容器/順序容器
元素排列次序與元素?zé)o關(guān),由元素添加到容器的順序決定
| 容器 | 說(shuō)明 |
|---|---|
| vector | 支持快速隨機(jī)訪問(wèn) |
| list | 支持快速插入、刪除 |
| deque | 雙端隊(duì)列 允許兩端都可以進(jìn)行入隊(duì)和出隊(duì)操作的隊(duì)列 |
| stack | 后進(jìn)先出LIFO(Last In First Out)堆棧 |
| queue | 先進(jìn)先出FIFO(First Input First Output)隊(duì)列 |
| priority_queue | 有優(yōu)先級(jí)管理的queue |
向量(vector)
連續(xù)存儲(chǔ)的元素
列表 (list)
由節(jié)點(diǎn)組成的雙向鏈表,每個(gè)結(jié)點(diǎn)包含著一個(gè)元素
雙端隊(duì)列(deque)
連續(xù)存儲(chǔ)的指向不同元素的指針?biāo)M成的數(shù)組
以上三種容器操作基本一樣
基本操作:
#include <vector>
using namespace std;
vector<int> vec_1;
//1個(gè)元素
vector<int> vec_2(1);
//6個(gè)值為 1 的元素
vector<int> vec_3(6,1);
//使用容器初始化
vector<int> vec_4(vec_3);
//通過(guò)下標(biāo)操作元素
int i = vec_3[1];
int j = vec_3.at(1);
//首尾元素
vec_3.front()
vec_3.back()
//插入元素
//vector不支持 push_front list,deque可以
vec_1.push_back(1);
//刪除元素 vector不支持 pop_front
vec_1.pop_back();
//釋放
//可以單個(gè)清除,也可以清除一段區(qū)間里的元素
vec_3.erase(vec_3.begin(),vec_3.end())
//清理容器 即erase所有
vec_3.clear();
//容量大小
vec_3.capacity();
//在容器中,其內(nèi)存占用的空間是只增不減的,
//clear釋放元素,卻不能減小vector占用的內(nèi)存
//所以可以對(duì)vector 收縮到合適的大小
vector< int >().swap(vec_3);
//在vec是全局變量時(shí)候
//建立臨時(shí)vector temp對(duì)象,swap調(diào)用之后對(duì)象vec占用的空間就等于默認(rèn)構(gòu)造的對(duì)象的大小
//temp就具有vec的大小,而temp隨即就會(huì)被析構(gòu),從而其占用的空間也被釋放。
迭代器
//獲得指向首元素的迭代器 模板類(lèi),不是指針,當(dāng)做指針來(lái)使用
vector<int>::iterator it = vec.begin();
//遍歷元素
for (; it < vec.end(); it++)
{
cout << *it << endl;
}
//begin和end 分別獲得 指向容器第一個(gè)元素和最后一個(gè)元素下一個(gè)位置的迭代器
//rbegin和rend 分別獲得 指向容器最后一個(gè)元素和第一個(gè)元素前一個(gè)位置的迭代器
//注意循環(huán)中操作元素對(duì)迭代器的影響
vector<int>::iterator it = vec.begin();
for (; it < vec.end(); )
{
//刪除值為2的元素
if (*it == 2) {
vec.erase(it);
}
else {
it++;
}
}
棧(stack)
后進(jìn)先出的值的排列
stack<int> s;
//入棧
s.push(1);
s.push(2);
//彈棧
s.pop();
//棧頂
cout << s.top() << endl;
隊(duì)列(queue)
先進(jìn)先出的值的排列
queue<int> q;
q.push(1);
q.push(2);
//移除最后一個(gè)
q.pop();
//獲得第一個(gè)
q.front();
//最后一個(gè)元素
cout << q.back() << endl;
優(yōu)先隊(duì)列(priority_queue )
元素的次序是由所存儲(chǔ)的數(shù)據(jù)的某個(gè)值排列的一種隊(duì)列
//最大的在隊(duì)首
priority_queue<int>;
//在vector之上實(shí)現(xiàn)的
priority_queue<int, vector<int>, less<int> >;
//vector 承載底層數(shù)據(jù)結(jié)構(gòu)堆的容器
//less 表示數(shù)字大的優(yōu)先級(jí)高,而 greater 表示數(shù)字小的優(yōu)先級(jí)高
//less 讓優(yōu)先隊(duì)列總是把最大的元素放在隊(duì)首
//greater 讓優(yōu)先隊(duì)列總是把最小的元素放在隊(duì)首
//less和greater都是一個(gè)模板結(jié)構(gòu)體 也可以自定義
class Student {
public:
int grade;
Student(int grade):grade(grade) {
}
};
struct cmp {
bool operator ()(Student* s1, Student* s2) {
// > 從小到大
// < 從大到小
return s1->grade > s2->grade;
}
bool operator ()(Student s1, Student s2) {
return s1.grade > s2.grade;
}
};
priority_queue<Student*, vector<Student*>, cmp > q1;
q1.push(new Student(2));
q1.push(new Student(1));
q1.push(new Student(3));
cout << q1.top()->grade << endl;
關(guān)聯(lián)式容器
關(guān)聯(lián)容器和大部分順序容器操作一致
關(guān)聯(lián)容器中的元素是按關(guān)鍵字來(lái)保存和訪問(wèn)的 支持高效的關(guān)鍵字查找與訪問(wèn)
集合(set)
由節(jié)點(diǎn)組成的紅黑樹(shù),每個(gè)節(jié)點(diǎn)都包含著一個(gè)元素,元素不可重復(fù)
set<string> a;
set<string> a1={"fengxin","666"};
a.insert("fengxin"); // 插入一個(gè)元素
a.erase("123"); //刪除
鍵值對(duì)(map)
由{鍵,值}對(duì)組成的集合
map<int, string> m;
map<int, string> m1 = { { 1,"aa" },{ 2,"bb" } };
//插入元素
m1.insert({ 3,"dd" });
//pair=鍵值對(duì)
pair<int, string> p(4, "gg");
m1.insert(p);
//insetrt 返回 map<int, string>::iterator : bool 鍵值對(duì)
//如果 插入已經(jīng)存在的 key,則會(huì)插入失敗
//multimap:允許重復(fù)key
//使用m1[3] = "xx" 能夠覆蓋
//通過(guò)【key】操作元素
m1[5] = "yihan";
cout << m1[5].c_str() << endl;
//通過(guò)key查找元素
map<int, string>::iterator it = m1.find(3);
cout << (*it).second.c_str()<< endl;
// 刪除
m1.erase(5);
//遍歷
for (it = m1.begin(); it != m1.end(); it++)
{
pair<int, string> item = *it;
cout << item.first << ":" << item.second.c_str() << endl;
}
//其他map================================
unordered_map c++11取代hash_map(哈希表實(shí)現(xiàn),無(wú)序)
哈希表實(shí)現(xiàn)查找速度會(huì)比RB樹(shù)實(shí)現(xiàn)快,但rb整體更節(jié)省內(nèi)存
需要無(wú)序容器,高頻快速查找刪除,數(shù)據(jù)量較大用unordered_map;
需要有序容器,查找刪除頻率穩(wěn)定,在意內(nèi)存時(shí)用map。
類(lèi)型轉(zhuǎn)換
除了能使用c語(yǔ)言的強(qiáng)制類(lèi)型轉(zhuǎn)換外,還有:轉(zhuǎn)換操作符 (新式轉(zhuǎn)換)
const_cast
修改類(lèi)型的const或volatile屬性
const char *a;
char *b = const_cast<char*>(a);
char *a;
const char *b = const_cast<const char*>(a);
static_cast
- 基礎(chǔ)類(lèi)型之間互轉(zhuǎn)。如:float轉(zhuǎn)成int、int轉(zhuǎn)成unsigned int等
- 指針與void之間互轉(zhuǎn)。如:float轉(zhuǎn)成void、Bean轉(zhuǎn)成void、函數(shù)指針轉(zhuǎn)成void*等
- 子類(lèi)指針/引用與 父類(lèi)指針/引用 轉(zhuǎn)換。
class Parent {
public:
void test() {
cout << "p" << endl;
}
};
class Child :public Parent{
public:
void test() {
cout << "c" << endl;
}
};
Parent *p = new Parent;
Child *c = static_cast<Child*>(p);
//輸出c
c->test();
//Parent test加上 virtual 輸出 p
dynamic_cast
主要 將基類(lèi)指針、引用 安全地轉(zhuǎn)為派生類(lèi).
在運(yùn)行期對(duì)可疑的轉(zhuǎn)型操作進(jìn)行安全檢查,僅對(duì)多態(tài)有效
//基類(lèi)至少有一個(gè)虛函數(shù)
//對(duì)指針轉(zhuǎn)換失敗的得到NULL,對(duì)引用失敗 拋出bad_cast異常
Parent *p = new Parent;
Child *c = dynamic_cast<Child*>(p);
if (!c) {
cout << "轉(zhuǎn)換失敗" << endl;
}
Parent *p = new Child;
Child *c = dynamic_cast<Child*>(p);
if (c) {
cout << "轉(zhuǎn)換成功" << endl;
}
reinterpret_cast
對(duì)指針、引用進(jìn)行原始轉(zhuǎn)換
float i = 10;
//&i float指針,指向一個(gè)地址,轉(zhuǎn)換為int類(lèi)型,j就是這個(gè)地址
int j = reinterpret_cast<int>(&i);
cout << hex << &i << endl;
cout << hex << j << endl;
cout<<hex<<i<<endl; //輸出十六進(jìn)制數(shù)
cout<<oct<<i<<endl; //輸出八進(jìn)制數(shù)
cout<<dec<<i<<endl; //輸出十進(jìn)制數(shù)
char*與int轉(zhuǎn)換
//char* 轉(zhuǎn)int float
int i = atoi("1");
float f = atof("1.1f");
cout << i << endl;
cout << f << endl;
//int 轉(zhuǎn) char*
char c[10];
//10進(jìn)制
itoa(100, c,10);
cout << c << endl;
//int 轉(zhuǎn) char*
char c1[10];
sprintf(c1, "%d", 100);
cout << c1 << endl;
異常
void test1()
{
throw "測(cè)試!";
}
void test2()
{
throw exception("測(cè)試");
}
try {
test1();
}
catch (const char *m) {
cout << m << endl;
}
try {
test2();
}
catch (exception &e) {
cout << e.what() << endl;
}
//自定義
class MyException : public exception
{
public:
virtual char const* what() const
{
return "myexception";
}
};
//隨便拋出一個(gè)對(duì)象都可以
文件與流操作
C 語(yǔ)言的文件讀寫(xiě)操作
頭文件:stdio.h
函數(shù)原型:FILE * fopen(const char * path, const char * mode);
path: 操作的文件路徑
mode:模式
| 模式 | 描述 |
|---|---|
| r | 打開(kāi)一個(gè)已有的文本文件,允許讀取文件。 |
| w | 打開(kāi)一個(gè)文本文件,允許寫(xiě)入文件。如果文件不存在,則會(huì)創(chuàng)建一個(gè)新文件。在這里,您的程序會(huì)從文件的開(kāi)頭寫(xiě)入內(nèi)容。如果文件存在,則該會(huì)被截?cái)酁榱汩L(zhǎng)度,重新寫(xiě)入。 |
| a | 打開(kāi)一個(gè)文本文件,以追加模式寫(xiě)入文件。如果文件不存在,則會(huì)創(chuàng)建一個(gè)新文件。在這里,您的程序會(huì)在已有的文件內(nèi)容中追加內(nèi)容。 |
| r+ | 打開(kāi)一個(gè)文本文件,允許讀寫(xiě)文件。 |
| w+ | 打開(kāi)一個(gè)文本文件,允許讀寫(xiě)文件。如果文件已存在,則文件會(huì)被截?cái)酁榱汩L(zhǎng)度,如果文件不存在,則會(huì)創(chuàng)建一個(gè)新文件。 |
| a+ | 打開(kāi)一個(gè)文本文件,允許讀寫(xiě)文件。如果文件不存在,則會(huì)創(chuàng)建一個(gè)新文件。讀取會(huì)從文件的開(kāi)頭開(kāi)始,寫(xiě)入則只能是追加模式。 |
FILE *f = fopen("xxxx\\t.txt","w");
//寫(xiě)入單個(gè)字符
fputc('a', f);
fclose(f);
FILE *f = fopen("xxxx\\t.txt","w");
char *txt = "123456";
//寫(xiě)入以 null 結(jié)尾的字符數(shù)組
fputs(txt, f);
//格式化并輸出
fprintf(f,"%s",txt);
fclose(f);
//========================================================================
fgetc(f); //讀取一個(gè)字符
char buff[255];
FILE *f = fopen("xxxx\\t.txt", "r");
//讀取 遇到第一個(gè)空格字符停止
fscanf(f, "%s", buff);
printf("1: %s\n", buff);
//最大讀取 255-1 個(gè)字符
fgets(buff, 255, f);
printf("2: %s\n", buff);
fclose(f);
//二進(jìn)制 I/O 函數(shù)
size_t fread(void *ptr, size_t size_of_elements,
size_t number_of_elements, FILE *a_file);
size_t fwrite(const void *ptr, size_t size_of_elements,
size_t number_of_elements, FILE *a_file);
//1、寫(xiě)入/讀取數(shù)據(jù)緩存區(qū)
//2、每個(gè)數(shù)據(jù)項(xiàng)的大小
//3、多少個(gè)數(shù)據(jù)項(xiàng)
//4、流
//如:圖片、視頻等以二進(jìn)制操作:
//寫(xiě)入buffer 有 1024個(gè)字節(jié)
fwrite(buffer,1024,1,f);
C++ 文件讀寫(xiě)操作
<iostream> 和 <fstream>
| 數(shù)據(jù)類(lèi)型 | 描述 |
|---|---|
| ofstream | 輸出文件流,創(chuàng)建文件并向文件寫(xiě)入信息。 |
| ifstream | 輸入文件流,從文件讀取信息。 |
| fstream | 文件流,且同時(shí)具有 ofstream 和 ifstream 兩種功能。 |
char data[100];
// 以寫(xiě)模式打開(kāi)文件
ofstream outfile;
outfile.open("XXX\\f.txt");
cout << "輸入你的名字: ";
//cin 接收終端的輸入
cin >> data;
// 向文件寫(xiě)入用戶輸入的數(shù)據(jù)
outfile << data << endl;
// 關(guān)閉打開(kāi)的文件
outfile.close();
// 以讀模式打開(kāi)文件
ifstream infile;
infile.open("XXX\\f.txt");
cout << "讀取文件" << endl;
infile >> data;
cout << data << endl;
// 關(guān)閉
infile.close();