C++(13)-适配器容器和C++11新语法

189 阅读5分钟

多重映射 ------ multimap

多重映射就是在映射的基础上允许key重复(一对多)

image-20220819201550642

使用需要包含头文件:#include

特性

1.允许key重复
    A - 100
    A - 200
    A - 300
2.不支持关于key的下标运算    

新增成员函数

//获取匹配的上限 -----> 返回首个大于给定key的迭代器
iterator upper_bound(const key_value &key);
//获取匹配的下限 -----> 返回首个不小于给定key的迭代器
iterator lower_bound(const key_value &key);
//同时获取上下线
pair<iterator,iterator> equal_range(const key_value &key);

A - 100
B - 200 ----- B的下限
B - 300
B - 400
C - 500 ----- B的上限

//find查找是返回任意一个匹配key的元素,一般不使用                //获取匹配的上限 -----> 返回首个大于给定key的迭代器 iterator upper_bound(const key_value &key); //获取匹配的下限 -----> 返回首个不小于给定key的迭代器 iterator lower_bound(const key_value &key); //同时获取上下线 pair<iterator,iterator> equal_range(const key_value &key); A - 100 B - 200 ----- B的下限 B - 300 B - 400 C - 500 ----- B的上限 //find查找是返回任意一个匹配key的元素,一般不使用            

集合 -------- set

集合就是没有value的映射

使用需要包含头文件:#include

使用:

set<key类型> set对象
set<key类型,比较器类型> set对象;

多重集合

多重集合是没有value的多重映射

允许key重复,其余和set一样

使用需要包含头文件:#include

C++11新增关联容器

C++新增了4种无序的关联容器,内部使用哈希表管理key,实现常数时间的查找。

unordered_set
unordered_map
unordered_multiset
unordered_multimap

补充 ----- 快速排序

算法:

1.从待排序序列中任意挑选一个元素,作为基准
2.将所有小于基准的元素放到基准之前,所有大于基准的元素放到基准之后,等于基准的元素随意
  这个过程叫做分组
3.采用递归,分别对基准之前和基准之后的分组继续进行分组
  直到每个分组内的元素不多于一个为止    

算法实现

1.记录该组第一个(L)和最后一个(R)的下标,取出左边作为基准
2.用右边指向的元素和基准比较,大于等于基准将R左移;小于基准将R指向的元素赋值给L指向的元素
  换左边和基准比较
3.用左边指向的元素和基准比较,小于等于基准将L右移;大于基准将L指向的元素赋值给R指向的元素
  换右边和基准比较
4.重复2~3步,直到L和R重合,将基准赋值给重合的位置,完成一次分组  

评价

空间复杂度:O(logN)
时间复杂度:O(NlongN) 最差 --- O(N^2)
如果每次分组都能做到均匀分组,可以达到最快排序速度
属于非稳定排序

快速排序的优化

快速排序的速度取决于分组是否均匀,为了尽可能达到均匀分组,要找到一个尽可能接近中间值的数。

通常可以找三个数中的中间值数,三个数可以选第一个,最后一个和中间那个

C++11新特性

新的初始化语法

C++11扩展了大括号进行初始化的范围,可以用于所有的基本类型和类类型。初始化时"="可加可不加。

int x = {5};
short s_arr[5] {4,5,6,7,8};

int *pa = new int[4] {1,2,3,4};

class A{
public:
    //......    
private:
    int id;
    double weight;       
};

A a1{1,4.3};
A a2{5,7.6};

新的声明语法

auto

C++11扩展了auto的用法,实现了自动类型推断

auto num = 10;//int
auto pt = &num;//int *
int add(int,int);
auto pf = add;//函数指针类型 int(*)(int,int);

list<int> li;
auto it = li.begin();//迭代器类型 list<int>::iterator

decltype

关键字decltype的作用是将变量的类型声明为表达式指定的类型,语法如下:

decltype(x) y;//x是一个表达式,y是变量名

int n;
double x;

decltype(x*n) p;//p是double类型
decltype(&x) q;//q是double *类型

//模板中使用
template <typename T,typename K>
void func(T t,K k)
{
   decltype(t*k) tk;//tk就是t*k的类型
   //....
}

返回值类型后置

C++11新增了一种返回值类型后置的语法,将函数的返回值写到参数列表之后,语法如下:

double add(double,int);
auto add(double,int) -> double;//返回double

//模板中使用
template <typename T,typename K>
auto func(T t,K k) -> decltype(t*k)
{
    return t*k;
}

模板别名

C++新增了使用 using= 创建别名的语法。

等价于typedef的用法

using IT = array<char,10>::iterator;//相当于typedef

using=可以用于模板实例化

template <typename T>
using arr12 = array<T,12>;

array<double,12> <=====> arr12<double>
arrar<string,12> <=====> arr12<string>                template <typename T> using arr12 = array<T,12>; array<double,12> <=====> arr12<double> arrar<string,12> <=====> arr12<string>              

新的for循环用法

C++11扩展了for的用法,简化了对于数组/容器的遍历,比如:

int arr[] = {1,2,3,4,5,6,7,8,9};

for(int x:arr)
    cout<< x<<" ";
cout<<endl;    

//和auto结合使用
for(auto x:arr)
    cout<< x<<" ";
cout<<endl;

vector<int> vi(arr,arr+9);
//修改容器
for(auto &x:vi)
    x = rand();
//遍历容器
for(auto x:vi)
    cout<< x<<" ";
cout<<endl;    

右值引用

C++原有的引用属于左值引用,C++11扩展了右值引用,就是使用引用指向一个右值类型的数据。

int x = 10;
int y = 33;

//右值引用
int &&r1 = 11;
int &&r2 = x+y;
double &&r3 = sqrt(3.0);

//右值引用和常量的区别在于可以获取右值引用的地址

移动语义c

如果类中有动态分配的内存,C++的拷贝过程必须重新分配新的内存,并且拷贝内存中的数据。在某些时候(比如返回值返回),拷贝完成之后原对象已经不再需要,如果还是沿用之前的拷贝操作,相当于将一个对象拷贝到另一个位置,再释放原对象。这种操作显然不恰当,移动语义就是在这种情形下,并不去拷贝原始的数据,只是修改数据的记录。

image-20220819201917870

image-20220819201923032

 vector<int> func() {  

  vector<int> vi;   

 //...       

 return vi;

 }              

使用情形:

在使用右值初始化或者返回对象会调用移动构造函数,使用右值赋值会调用移动赋值运算符重载函数。

//移动构造函数
类名(对象的右值引用)
{
    //...
}

//移动赋值运算符重载函数
本对象引用 operaotr=(对象的右值引用)
{
    //...
}

//编译默认会优化移动操作,可以添加编译选项 -fno-elide-constructors,去掉编译对构造类函数的优化   

λ(Lambda)表达式/函数

Lambda函数也叫匿名函数,提供了一种新的实现传递函数作为参数的用法,也就是可以在传递参数时直接定义函数。

Snipaste_2022-08-13_21-54-31

语法

 函数对象的参数](重载操作符的参数)->返回值类型
 {  

 			 函数体

 }              

格式

[]中用来传递外部数据进Lambda表达式,多个数据用,分开,可以传引用
()中是使用Lambda表达式的形参
返回值类型是void或者函数体只有一条return语句是可以省略

C++书籍

C++ primer plus

C++并发编程 ----- 多任务 

Effective C++