【学习笔记】《STL使用入门教程》第六讲:容器使用时机、算法、删除元素的注意点

晓石头的博客 邮箱:178673693@qq.com 转载请注明出处,原文链接:http://blog.csdn.net/QIULANZHU/article/details/50520649

 

一、共同性

1.值的语意

所有容器提供的都是值的语意,而不是引用的语意。

容器执行插入元素的动作,背后实现是拷贝的动作。

STL容器存储的元素必须是能够被拷贝的,故元素需要提高拷贝构造函数

 

2.构造函数

每个容器都提供了一个默认构造函数和一个默认拷贝构造函数。

vector<int> cecIntA;//默认构造函数

vector<int> vecIntB(vecIntA);//调用拷贝构造函数

 

3.容器大小

与大小相关的操作方法(c代表容器):

c.size();//放回容器中元素的个数

c.empty()//判断容器是否为空

 

 

4.比较操作(c1c2代表容器)

c1==c2

c1!=c2

 

二、各个容器的使用时机

1、vectordeque的比较:

①.vector.at()deque.at()效率高

vector.at(0),开始位置是固定的

deque的开始位置却是不固定的

 

②.如果有大量释放操作的话,vector花的时间更少,这和二者的内部实现有关。。

 

③.deque支持头部的快速插入与快速移除,这是deque的优点。

 

2、list---适合于频繁的不确定位置元素的添加移除操作。

 

3、set---分数排行榜,自动排序

 

4、map---有关键字的排序

 

三、算法(Algorithm)的介绍

1.算法部分主要由头文件<algorithm>,<numeric><functional>组成。

<algorithm>是所有STL头文件中最大的一个,其中常用到的功能范围涉及到比较 、交换、查找、遍历、复制、修改、反转、排序、合并等等。

 

2.<numeric>体积很小,只包含几个在序列上面进行简单数学运算的模板函数,包括加法和乘法在序列上的一些操作。

 

3.<functional>中则定义了一些模板类,用以声明函数对象。

 

4.查找算法的选择

首先,选择查找算法时,区间是否排序是一个至关重要的因素,可以按是否需要排序区间分为两组:

 A. count,find

 B. binary_search,lower_bound,upper_bound,equal_range

A组不需排序区间, B组需要排序区间。

当一个区间被排序,优先选择B组,因为他们提供对数时间的效率。而A则是线性时间。

另外AB组所依赖的查找判断法则不同,A使用相等性法则(查找对象需要定义operator==), B使用等价性法则(查找对象需要定义operator<,必须在相等时返回false)

 

1、常用的查找算法

相邻重复元素查找:

adjacent_find(beg,end);//[beg,end)区间,查找一对相邻重复元素,找到则范围这对元素中第一个元素的迭代器。否则返回pass-the-end

例:

 

  1. #include "stdafx.h"  
  2. #include <iostream>  
  3. #include <string>  
  4. #include <vector>  
  5. #include <algorithm>  
  6.   
  7. using namespace std;  
  8.     
  9. bool greater(int iNum)  
  10. {  
  11.     if(iNum >3)  
  12.     {  
  13.         return true;  
  14.     }  
  15.     else  
  16.     {  
  17.         return false;  
  18.     }  
  19. }  
  20.   
  21. int main()  
  22. {  
  23.     int data[] = {1,2,4,5,6,8,6,11};  
  24.     vector<int> vecInt(data, data+sizeof(data)/sizeof(int));  
  25.   
  26.     int iCount = count_if(vecInt.begin(), vecInt.end(), greater);  
  27.     cout<<iCount<<endl;  
  28.       
  29.     return 0;  
  30. }  
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;
  
bool greater(int iNum)
{
	if(iNum >3)
	{
		return true;
	}
	else
	{
		return false;
	}
}

int main()
{
	int data[] = {1,2,4,5,6,8,6,11};
	vector<int> vecInt(data, data+sizeof(data)/sizeof(int));

	int iCount = count_if(vecInt.begin(), vecInt.end(), greater);
	cout<<iCount<<endl;
	
    return 0;
}

 

折半查找

bianry_search();//在有序序列中查找value,找到则返回true。注意:在无序序列中,不可使用。

例:

int data[] = {1,2,4,5,6,6,8,11};

vector<int> vecInt(data, data+sizeof(data)/sizeof(int));

bool bFind = binary_search(vecInt.begin(), vecInt.end(), 8);

 

查找指定元素个数:

count();//利用等于操作符,把标志范围内的元素与输入值比较,返回相等的个数。

例:

int data[] = {1,2,4,5,6,8,6,11};

vector<int> vecInt(data, data+sizeof(data)/sizeof(int));

int iCount = count(vecInt.begin(), vecInt.end(), 6);

 

查找满足条件的元素个数:

count_if:();//利用输入的函数,对标志范围内的元素进行比较操作,返回结果为true的个数。

例:

 

  1. #include "stdafx.h"  
  2. #include <iostream>  
  3. #include <string>  
  4. #include <vector>  
  5. #include <algorithm>  
  6.   
  7. using namespace std;  
  8.     
  9. bool greater(int iNum)  
  10. {  
  11.     if(iNum >3)  
  12.     {  
  13.         return true;  
  14.     }  
  15.     else  
  16.     {  
  17.         return false;  
  18.     }  
  19. }  
  20.   
  21. int main()  
  22. {  
  23.     int data[] = {1,2,4,5,6,8,6,11};  
  24.     vector<int> vecInt(data, data+sizeof(data)/sizeof(int));  
  25.   
  26.     int iCount = count_if(vecInt.begin(), vecInt.end(), greater);  
  27.     cout<<iCount<<endl;  
  28.       
  29.     return 0;  
  30. }  
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;
  
bool greater(int iNum)
{
	if(iNum >3)
	{
		return true;
	}
	else
	{
		return false;
	}
}

int main()
{
	int data[] = {1,2,4,5,6,8,6,11};
	vector<int> vecInt(data, data+sizeof(data)/sizeof(int));

	int iCount = count_if(vecInt.begin(), vecInt.end(), greater);
	cout<<iCount<<endl;
	
    return 0;
}

 

 

条件查找

find_if();//查找满足条件的元素位置

例:

 

  1. #include "stdafx.h"  
  2. #include <iostream>  
  3. #include <string>  
  4. #include <vector>  
  5. #include <algorithm>  
  6.   
  7. using namespace std;  
  8.     
  9. bool greater(int iNum)  
  10. {  
  11.     if(iNum >3)  
  12.     {  
  13.         return true;  
  14.     }  
  15.     else  
  16.     {  
  17.         return false;  
  18.     }  
  19. }  
  20.   
  21. int main()  
  22. {  
  23.     int data[] = {1,2,4,5,6,3,6,11};  
  24.     vector<int> vecInt(data, data+sizeof(data)/sizeof(int));  
  25.   
  26.     vector<int>::iterator it = find_if(vecInt.begin(), vecInt.end(), greater);  
  27.   
  28.     while(it != vecInt.end())  
  29.     {  
  30.         cout<<*it<<endl;  
  31.         it = find_if(it+1, vecInt.end(), greater);  
  32.     }  
  33.   
  34.       
  35.     return 0;  
  36. }  
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;
  
bool greater(int iNum)
{
	if(iNum >3)
	{
		return true;
	}
	else
	{
		return false;
	}
}

int main()
{
	int data[] = {1,2,4,5,6,3,6,11};
	vector<int> vecInt(data, data+sizeof(data)/sizeof(int));

	vector<int>::iterator it = find_if(vecInt.begin(), vecInt.end(), greater);

	while(it != vecInt.end())
	{
		cout<<*it<<endl;
		it = find_if(it+1, vecInt.end(), greater);
	}

	
    return 0;
}

 

2、常用合并算法 

加集:

merge()//合并:合并容器AB到容器C

例:

merge(vecIntA.begin(),vecIntA.end(),vecIntB.begin(),vecIntB.end(), vecIntC.begin());

 

并集:

set_union() //实现求集合AB的并。

例:

set_union(vecInt1.begin(), vecInt1.end(), vecInt2.begin(), vecInt2.end(), vecInt.begin());

 

交集:

set_intersection()//实现求集合AB交集。

例:

set_intersection(vecInt1.begin(), vecInt1.end(), vecInt2.begin(), vecInt2.end(), vecInt.begin());

 

差集:

set_difference()//实现求集合AB的差(即AB)(差集)。

例:

set_difference(vecInt1.begin(), vecInt1.end(), vecInt2.begin(), vecInt2.end(), vecInt.begin());

 

3、常用其他算法

排序:

sort()//默认升序排序

例:

sort(vec.begin(), vec.end())

 

自定义排序:

sort(beg,end,compare)//按照自定义的规则排序

例:

 

  1. #include "stdafx.h"  
  2. #include <iostream>  
  3. #include <string>  
  4. #include <vector>  
  5. #include <algorithm>  
  6. #include <time.h>  
  7.   
  8. using namespace std;  
  9.   
  10. class Student  
  11. {  
  12. public:  
  13.     Student(int id, string name):m_id(id),m_name(name){}  
  14. public:  
  15.     int m_id;  
  16.     string m_name;  
  17. };  
  18.   
  19. bool compare(const Student &stuA, const Student &stuB)  
  20. {  
  21.     return stuA.m_id<stuB.m_id ? true : false;  
  22. }  
  23.   
  24. int main(int argc, char* argv[])  
  25. {  
  26.     srand(time(0));//随机数发生器的初始化  
  27.     vector<Student> vecStudent;  
  28.   
  29.     vecStudent.push_back(Student(3, "小明3"));  
  30.     vecStudent.push_back(Student(5, "小明5"));  
  31.     vecStudent.push_back(Student(2, "小明2"));  
  32.     vecStudent.push_back(Student(1, "小明1"));  
  33.     vecStudent.push_back(Student(4, "小明4"));  
  34.   
  35.     sort(vecStudent.begin(), vecStudent.end(), compare);  
  36.   
  37.     vector<Student>::iterator it;  
  38.     for(it=vecStudent.begin(); it!=vecStudent.end(); it++)  
  39.     {  
  40.         cout<<(*it).m_name<<" "<<endl;  
  41.     }  
  42.   
  43.     return 0;  
  44. }  
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <time.h>

using namespace std;

class Student
{
public:
	Student(int id, string name):m_id(id),m_name(name){}
public:
	int m_id;
	string m_name;
};

bool compare(const Student &stuA, const Student &stuB)
{
	return stuA.m_id<stuB.m_id ? true : false;
}

int main(int argc, char* argv[])
{
	srand(time(0));//随机数发生器的初始化
	vector<Student> vecStudent;

	vecStudent.push_back(Student(3, "小明3"));
	vecStudent.push_back(Student(5, "小明5"));
	vecStudent.push_back(Student(2, "小明2"));
	vecStudent.push_back(Student(1, "小明1"));
	vecStudent.push_back(Student(4, "小明4"));

	sort(vecStudent.begin(), vecStudent.end(), compare);

	vector<Student>::iterator it;
	for(it=vecStudent.begin(); it!=vecStudent.end(); it++)
	{
		cout<<(*it).m_name<<" "<<endl;
	}

	return 0;
}

 

 随机洗盘:

random_shuffle();//打乱原有排序

random_shuffle(vec.begin(), vec.end());

 

颠倒顺序:

reverse();//反转原有排序

reverse(vec.begin(), vec.end());

 

拷贝:

copy();//拷贝容器A的指定区间到容器B

例:

 

  1. #include "stdafx.h"  
  2. #include <iostream>  
  3. #include <string>  
  4. #include <vector>  
  5. #include <algorithm>  
  6.   
  7. using namespace std;  
  8.   
  9. class Student  
  10. {  
  11. public:  
  12.     Student(){}  
  13.     Student(int id, string name):m_id(id),m_name(name){}  
  14. public:  
  15.     int m_id;  
  16.     string m_name;  
  17. };  
  18.   
  19. int main(int argc, char* argv[])  
  20. {  
  21.     vector<Student> vecStudent;  
  22.     vector<Student> vecStu;  
  23.   
  24.     vecStudent.push_back(Student(3, "小明3"));  
  25.     vecStudent.push_back(Student(5, "小明5"));  
  26.     vecStudent.push_back(Student(2, "小明2"));  
  27.     vecStudent.push_back(Student(1, "小明1"));  
  28.     vecStudent.push_back(Student(4, "小明4"));  
  29.   
  30.     vecStu.resize(vecStudent.size());//需要有默认的构造函数Student()  
  31.     copy(vecStudent.begin(), vecStudent.end(), vecStu.begin());  
  32.   
  33.     vector<Student>::iterator it;  
  34.     for(it=vecStu.begin(); it!=vecStu.end(); it++)  
  35.     {  
  36.         cout<<(*it).m_name<<endl;  
  37.     }  
  38.   
  39.     return 0;  
  40. }  
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

class Student
{
public:
	Student(){}
	Student(int id, string name):m_id(id),m_name(name){}
public:
	int m_id;
	string m_name;
};

int main(int argc, char* argv[])
{
	vector<Student> vecStudent;
	vector<Student> vecStu;

	vecStudent.push_back(Student(3, "小明3"));
	vecStudent.push_back(Student(5, "小明5"));
	vecStudent.push_back(Student(2, "小明2"));
	vecStudent.push_back(Student(1, "小明1"));
	vecStudent.push_back(Student(4, "小明4"));

	vecStu.resize(vecStudent.size());//需要有默认的构造函数Student()
	copy(vecStudent.begin(), vecStudent.end(), vecStu.begin());

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

	return 0;
}

 

替换:

replace();//将指定元素替换成给定的元素

replace(vec.begin(), vec.end(), 3, 10);//将容器中所用等于3的元素替换成10

 

条件替换:

replace_if();//替换满足条件的元素

例:

 

  1. #include "stdafx.h"  
  2. #include <iostream>  
  3. #include <string>  
  4. #include <vector>  
  5. #include <algorithm>  
  6.   
  7. using namespace std;  
  8.     
  9. bool greater(int iNum)  
  10. {  
  11.     if(iNum >3)  
  12.     {  
  13.         return true;  
  14.     }  
  15.     else  
  16.     {  
  17.         return false;  
  18.     }  
  19. }  
  20.   
  21. int main()  
  22. {  
  23.     int data[] = {1,2,4,5,6,3,6,11};  
  24.     vector<int> vecInt(data, data+sizeof(data)/sizeof(int));  
  25.   
  26.     replace_if(vecInt.begin(), vecInt.end(), greater, 10);  
  27.   
  28.     vector<int>::iterator it;  
  29.   
  30.     for(it=vecInt.begin(); it!=vecInt.end(); it++)  
  31.     {  
  32.         cout<<*it<<endl;  
  33.     }  
  34.       
  35.     return 0;  
  36. }  
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;
  
bool greater(int iNum)
{
	if(iNum >3)
	{
		return true;
	}
	else
	{
		return false;
	}
}

int main()
{
	int data[] = {1,2,4,5,6,3,6,11};
	vector<int> vecInt(data, data+sizeof(data)/sizeof(int));

	replace_if(vecInt.begin(), vecInt.end(), greater, 10);

	vector<int>::iterator it;

	for(it=vecInt.begin(); it!=vecInt.end(); it++)
	{
		cout<<*it<<endl;
	}
	
    return 0;
}

 

 

交换:

swap(vec1,vec2);//交换容器元素

 

计算和:

accumulate(vec.begin(), vec.end(), 100);//计算从vec.begin()vec.end()的和再加上最后的100

 

填充:

fill(vec.begin(), vec.end(), 100);//vec里的值全部填充成100

 

遍历:

for_each();//遍历区间元素

例:

for_each(vecInt.begin(), vecInt.end(), show);

 

转换:

transform();//改变遍历的元素

例:

  1. #include "stdafx.h"  
  2. #include <iostream>  
  3. #include <string>  
  4. #include <vector>  
  5. #include <algorithm>  
  6.   
  7. using namespace std;  
  8.   
  9. void show(const int &item)  
  10. {  
  11.     cout<<item<< " ";  
  12. }  
  13.   
  14. int increase(int item)  
  15. {  
  16.     return item + 1;  
  17. }  
  18.   
  19. int main()  
  20. {  
  21.     int data1[] = {1,2,3,4,5,6,7,8};  
  22.     vector<int> vecInt1(data1, data1+sizeof(data1)/sizeof(int));  
  23.   
  24.     vector<int> vecInt;  
  25.     vecInt.resize(vecInt1.size());  
  26.   
  27.     transform(vecInt1.begin(), vecInt1.end(), vecInt.begin(), increase);  
  28.   
  29.     for_each(vecInt.begin(), vecInt.end(), show);  
  30.   
  31.     return 0;  
  32. }  
#include "stdafx.h"
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>

using namespace std;

void show(const int &item)
{
	cout<<item<< " ";
}

int increase(int item)
{
	return item + 1;
}

int main()
{
	int data1[] = {1,2,3,4,5,6,7,8};
	vector<int> vecInt1(data1, data1+sizeof(data1)/sizeof(int));

	vector<int> vecInt;
	vecInt.resize(vecInt1.size());

	transform(vecInt1.begin(), vecInt1.end(), vecInt.begin(), increase);

	for_each(vecInt.begin(), vecInt.end(), show);

    return 0;
}

四、删除元素的注意点

 

1. 对于关联容器(如map, set,multimap,multiset)

删除当前的iterator,仅仅会使当前的iterator失效,只要在erase时,递增当前iterator即可。这是因为map之类的容器,使用了红黑树来实现,插入、删除一个结点不会对其他结点造成影响。

 

  1. for (iter = cont.begin(); it != cont.end();)  
  2. {  
  3.    if(shouldDelete(*iter))  
  4.    {  
  5.     cont.erase(iter++);  
  6.    }  
  7.    else  
  8.    {  
  9.     ++iter;  
  10.    }    
  11. }  
for (iter = cont.begin(); it != cont.end();)
{
   if(shouldDelete(*iter))
   {
	cont.erase(iter++);
   }
   else
   {
	++iter;
   }  
}

因为iter传给erase方法的是一个副本,iter++会指向下一个元素。

 

2. 对于序列式容器(如vector,deque)

删除当前的iterator会使后面所有元素的iterator都失效。这是因为vetor,deque使用了连续分配的内存,删除一个元素导致后面所有的元素会向前移动一个位置。还好erase方法可以返回下一个有效的iterator。

 

  1. for (iter = cont.begin(); iter != cont.end();)  
  2. {  
  3.     if(shouldDelete(*iter))  
  4.     {  
  5.         iter = cont.erase(iter);   
  6.     }  
  7.    else  
  8.    {  
  9.         ++iter;  
  10.    }    
  11. }  
for (iter = cont.begin(); iter != cont.end();)
{
    if(shouldDelete(*iter))
    {
        iter = cont.erase(iter); 
    }
   else
   {
        ++iter;
   }  
}

 

3. 对于list来说

它使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的iterator,因此上面两种方法都可以使用。

后置++的代码:

  1. _Myiter operator++(int)  
  2. {    // postincrement  
  3.     _Myiter _Tmp = *this;  
  4.     ++*this;  
  5.     return (_Tmp);  
  6. }  
_Myiter operator++(int)
{    // postincrement
    _Myiter _Tmp = *this;
    ++*this;
    return (_Tmp);
}

*this:表示当前迭代器 _Tmp:当前迭代器的副本 ++*this;//*this变成下一个迭代器

return (_Tmp);//最后返回的是当前迭代器的副本

 

前置++的代码:

  1. _Myiter& operator++()  
  2. {    
  3.     ++(*(_Mybase *)this);//*this变成下一个迭代器  
  4.     return (*this);//返回的是下一个迭代器  
  5. }  
_Myiter& operator++()
{  
    ++(*(_Mybase *)this);//*this变成下一个迭代器
    return (*this);//返回的是下一个迭代器
}

 

 

   

posted @ 2017-02-26 15:45  sky20080101  阅读(163)  评论(0)    收藏  举报