前言:本课程是我看了侯捷老师的课程之后整理,为了避免忘记,故作此整理。只是对六大部件做一个简单的介绍,在第二讲中我们会观看它们的源代码做一个详细的讲解。
在本节最后的代码中,我用到了命名空间,主要是让我们写的程序比如类,对象,模板再封装起来,这样可以跟别人不会发生冲突。
面向对象和泛型编程的区别在于,面向对象这种编程技巧,鼓励我们把数据放在类里头,把处理数据的函数也放在类里头,而泛型编程却不一样,数据放在容器里头,而操作数据的都动作即算法则放在另一个类里面,所以其设计方式跟面向对象不一样。在GP中,容器和算法之间的桥梁是迭代器(iterators),迭代器也是一种泛型指针。
如下幻灯片。
以上就是C++的六大部件,其中容器和算法最为重要,容器需要放东西,东西要占用内存,容器的好处是帮我们把内存的东西解决掉,所以其背后需要另外一个东西作支撑即分配器,容器外头是适配器,他是用来对某些容器做一些改造的,其次,容器需要算法来对数据进行操作,所以中间需要一个桥梁即迭代器。其次仿函数,仿函数可能是一个类,或者一个模板。
以下我们用一个简单的例子,来把以上的六大部件,全部用一遍。
在11行,vector就是一种容器,他里面用来放整型数据,后面的那个allocator,就是一个分配器,他用来分配内存,而count_if则是一个算法名称,他后面的vi.begin(),vi.end()就是迭代器,not1是一个函数适配器,表示对条件取反,bind2nd也是一个函数适配器,用来绑定第二参数40,less
再来谈谈时间复杂度,时间复杂度中n,必须是那种很大的数,才有意义。
其次注意一个问题,前闭后开区间,如下所示,所以当我们用“*(c.end())”来取值是会出错的。
容器分为序列式容器和关联式容器。如下所示
序列式容器有array即数组,array的空间是连续的,因此他可以随机存取,其实其大小固定,不能改变,就好像在数组中,我们必须制定数组的大小。Vector这种容器是从尾部插入元素,他也是连续空间,但是其大小不固定,他的大小是两倍增长,即当前空间放满元素之后,分配器会自动在另一个地方分配一个两倍大的空间,然后将当前数据元素,逐一拷贝到另外一个两倍大的空间,这些动作均可以在源代码中看到。其次Deque是一个分段连续的空间,在第二讲中再做详细讲解。其次List是一个双向链表,他并非连续空间,他是通过指针将空间中散落的点,串联起来,所以他不支持随机存取,但是其插入删除较快,其次forward_list是一个单向链表。其次再看关联式容器,关联式容器其底部由红黑树或者哈希表这种数据结构作支撑。像Unordered_containers其底部就是由哈希表做支撑,而另外的则是由红黑树做支撑。set是一个不允许元素重复的容器,其次因为其底部是由红黑书做支撑,所以它是有序的,multi_set则允许元素重复。map和multi_map,则是一个pair,他key和value组成,map不允许key重复,multi_map允许key重复,其次因为其底部为红黑树,所以其key为有序。像以红黑树,和哈希表做支撑的容器,适合用来查找,查找很快,所以这些容器会自带查找算法。
下面讲一下分配器,分配器一般不需要我们指定,编译器会自动制定,不同的编译器,分配器也差不多一样。所以即使我们会用,也不建议使用。如下所示。
在gnu c2.9中有很多非标准的分配器,之所以说非标准,是因为在他是gnu自己扩展的分配器,在VC或者BC中不存在。如下所示。如果非要使用非标准的分配器,则必须指定其命名空间,因为这些分配器并非在命名空间std当中,而是在__gnu_cxx这个命名空间里面。右边的那个__pool_alloc就是一个很著名的内存池结构,他在gnu2.9版本中就叫alloc,而在gnu_4.9中才叫__pool_alloc。
之所以不建议我们指定分配器,是因为有一个致命伤,他必须让我们记住用了多少内存,还的时候,还要我们告诉其用了多少内存,这样它才能回收,如下所示。
以下代码,是对所有容器的一个简单测试,输入的数据应是百万级别的规模,这样才有意义。
#include
#include
#include
using std::cin;
using std::cout;
using std::string;
string get_a_target_string()
{
char buf[10];
long target = 0;
cout << "target (0~" << RAND_MAX << "):";
cin >> target;
snprintf(buf, 10, "%d", target);
return string(buf);
}
long get_a_target_long()
{
long target = 0;
cout << "target (0~" << RAND_MAX << "):";
cin >> target;
return target;
}
int compartLongs(const void* a, const void* b)
{
return (*(long*)a - *(long*)b);
}
int compareStrings(const void* a, const void* b)
{
if (*(string*)a > *(string*)b)
return 1;
else if (*(string*)a < *(string*)b)
return -1;
else
return 0;
}
#include
#include
#include
#include
namespace jj01
{
//array数据结构为一个数组
using namespace std;
void test_array()
{
cout << "\ntest_array().............\n";
const long ASIZE = 100000;
array c;
clock_t timeStart = clock();
for (long i = 0; i < ASIZE; i++)
{
c[i] = rand();
}
cout << "milll-seconds: " << (clock()-timeStart) << endl;
cout << "array.size()= " << c.size() << endl;
cout << "array.front()= " << c.front() << endl;
cout << "array.back()= " << c.back() << endl;
cout << "array.data()= " << c.data() << endl;
long target = get_a_target_long();
timeStart = clock();
qsort(c.data(), ASIZE, sizeof(long), compartLongs);
long* pItem = (long*)bsearch(&target, (c.data()), ASIZE, sizeof(long), compartLongs);
cout << "qsort()+bsearch(),milli-seconds : " << (clock() - timeStart) << endl;
if (pItem!=NULL)
{
cout << "found, " << *pItem << endl;
}
else
{
cout << "not found!" << endl;
}
}
}
#include
#include
#include
#include
#include
#include
#include
#include
namespace jj02
{
using namespace std;
//vector的空间是两倍增长的尾部可以插入元素的数组
void test_vector(long& value)
{
cout << "\ntest_vector()............\n";
vector c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; i++)
{
try
{
snprintf(buf, 10, "%d", rand());
c.push_back(string(buf));
}
catch (const std::exception& p)
{
cout << "i=" << i << " " << p.what() << endl;
abort();
}
}
cout << "milll-seconds: " << (clock()-timeStart) << endl;
cout << "vector.size()= " << c.size() << endl; //size()真正元素的个数
cout << "vector.front()= " << c.front() << endl; //vector的第一个元素
cout << "vector.back()= " << c.back() << endl; //vector的最后一个元素
cout << "vector.data()= " << c.data() << endl; //呼叫整个vector的起始空间
cout << "vector.capacity()= " << c.capacity() << endl;//capacity()表示真正容量有多大
string target = get_a_target_string();
{
timeStart = clock();
auto pItem = find(c.begin(), c.end(), target);
cout << "::find(),mill-second:" << (clock() - timeStart) << endl;
if (pItem != c.end())
cout << "found, " << *pItem << endl;
else
cout << "not found" << endl;
}
timeStart = clock();
sort(c.begin(), c.end());
string* pItem = (string*)bsearch(&target, (c.data()), c.size(), sizeof(string), compareStrings);
cout << "sort()+bsearch(),milli-seconds: " << (clock()-timeStart) << endl;
if (pItem != NULL)
{
cout << "found, " << *pItem << endl;
}
else
{
cout << "not found!" << endl;
}
}
}
#include
#include
#include
#include
#include
#include
namespace jj03
{
//list数据结构为一个双向链表
using namespace std;
void test_list(long& value)
{
cout << "\ntest_list().........\n";
list c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; i++)
{
try
{
snprintf(buf, 10, "%d", rand());
c.push_back(string(buf));
}
catch (const std::exception& p)
{
cout << "i=" << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds:" << (clock() - timeStart) << endl;
cout << "list.size():" << c.size() << endl;
cout << "list.max_size():" << c.max_size() << endl;
cout << "list.front():" << c.front() << endl;
cout << "list.back():" << c.back() << endl;
string target = get_a_target_string();
timeStart = clock();
auto pItem = find(c.begin(), c.end(), target);
cout << "::find(),milli-seconds:" << (clock()-timeStart) << endl;
if (pItem != c.end())
{
cout << "found, " << *pItem << endl;
}
else
{
cout << "not found!" << endl;
}
timeStart = clock();
c.sort(); //list容器里面有自带的排序算法,所以我们选择自带的排序算法,效率比较高
cout << "c.sort(),mill-seconds:" << (clock() - timeStart) << endl;
}
}
#include
#include
#include
#include
namespace jj04
{
//forward_list数据结构为单向链表
using namespace std;
void test_forward_list(long& value)
{
cout << "\ntest_forward_list()............\n";
forward_list c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; i++)
{
try
{
snprintf(buf, 10, "%d", rand());
c.push_front(string(buf)); //注意forward_list只有push_front()放元素,没有push_back()方法
}
catch (const std::exception& p)
{
cout << "i=" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds():" << (clock() - timeStart) << endl;
cout << "forward_list.max_size():" << c.max_size() << endl; //最多可以放多少个元素
cout << "forward_list.front():" << c.front() << endl;
//注意,forward_list没有back()方法,也没有size()方法
string target = get_a_target_string();
timeStart = clock();
auto pItem = find(c.begin(), c.end(), target);
cout <<"::find(),milli-seconds:" << (clock() - timeStart) << endl;
//这样写是不对的,因为pItem是一个迭代器,或者是泛型指针,但是不是指针,所以不可以这样写
//if (pItem != NULL)
if (pItem!=c.end())
{
cout << "found," << *pItem << endl;
}
else
{
cout << "not found!" << endl;
}
timeStart = clock();
c.sort();
cout << "c.sort(),milli-seconds:" << (clock() - timeStart) << endl;
}
}
#include
namespace jj05
{
//deque数据结构为双端队列
using namespace std;
void test_deque(long& value)
{
cout << "\ntest_deque()...............";
deque c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; i++)
{
try
{
snprintf(buf, 10, "%d", rand());
c.push_back(string(buf));
}
catch (const std::exception& p)
{
cout << "i:" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds:" << (clock() - timeStart) << endl;
cout << "deque.size():" << c.size() << endl;
cout << "deque.front():" << c.front() << endl;
cout << "deque.back():" << c.back() << endl;
cout << "deque.max_size():" << c.max_size() << endl;
string target = get_a_target_string();
timeStart = clock();
auto pItem = find(c.begin(), c.end(), target);
cout << "::find(),milli-seconds:" << (clock() - timeStart) << endl;
if (pItem!=c.end())
{
cout << "found," << *pItem << endl;
}
else
{
cout << "not found!" << endl;
}
timeStart = clock();
sort(c.begin(), c.end());
cout << "::sort(),milli-seconds:" << (clock() - timeStart) << endl;
}
}
#include
namespace jj06
{
using namespace std;
void test_stack(long& value)
{
cout << "\ntest_stack()..............\n";
stack c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; i++)
{
try
{
snprintf(buf, 10, "%d", rand());
c.push(string(buf));
}
catch (const std::exception& p)
{
cout << "i:" << i << " " << p.what() << endl;
abort();
}
}
//因为这里是栈,所以不存在查找,排序以及插入等功能
cout << "milli-seconds:" << (clock() - timeStart) << endl;
cout << "stack.size():" << c.size() << endl;
cout << "stack.top():" << c.top() << endl;
c.pop();
cout << "stack.size():" << c.size() << endl;
cout << "stack.top():" << c.top() << endl;
}
}
#include
namespace jj07
{
//queue数据结构为deque
using namespace std;
void test_queue(long& value)
{
cout << "test_queue()..............\n";
queue c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; i++)
{
try
{
snprintf(buf, 10, "%d", rand());
c.push(string(buf));
}
catch (const std::exception& p)
{
cout << "i:" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds:" << (clock() - timeStart) << endl;
cout << "queue.size():" << c.size() << endl;
cout << "queue.front():" << c.front() << endl;
cout << "queue.back():" << c.back() << endl;
c.pop();
cout << "queue.size():" << c.size() << endl;
cout << "queue.front():" << c.front() << endl;
cout << "queue.back():" << c.back() << endl;
}
}
#include
namespace jj08
{
//unordered_map的数据结构为哈希表
using namespace std;
void test_unordered_map(long& value)
{
cout << "\ntest_inordefed_map()..............";
unordered_map c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; i++)
{
try
{
snprintf(buf, 10, "%d", rand());
c[i] = string(buf); //注意unordered_map插入元素的方法,i表示key,buf表示value
}
catch (const std::exception& p)
{
cout << "i:" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds:" << (clock() - timeStart) << endl;
cout << "unordered_map.size():" << c.size() << endl;
cout << "unordered_map.max_size():" << c.max_size() << endl;
long target = get_a_target_long();
timeStart = clock();
//注意这里是调用unordered_map自己的查找方法,有自己的方法
//一定要用自己的查找方法
auto pItem = c.find(target);
cout << "c.find(),milli-seconds:" << (clock() - timeStart) << endl;
if (pItem!=c.end())
{
//注意这里取(*pItem).second表示取value
cout << "found:" << (*pItem).second << endl;
}
else
{
cout << "not found!" << endl;
}
}
}
#include
namespace jj09
{
//unordered_set数据结构为哈希表
using namespace std;
void test_unordered_set(long& value)
{
cout << "\ntest_unordered_set()............\n";
unordered_set c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; i++)
{
try
{
snprintf(buf, 10, "%d", rand());
//注意这里的插入方法,是不允许以下标的方式插入数据的
c.insert(string(buf));
}
catch (const std::exception& p)
{
cout << "i:" << i << " " << p.what();
abort();
}
}
cout << "milli-seconds:" << (clock() - timeStart) << endl;
cout << "unordered_set.size()" << c.size() << endl;
cout << "unordered_set.max_size()" << c.max_size() << endl;
//输出篮子的个数
cout << "unordered_set.bucker_count()" << c.bucket_count() << endl;
//输出填充因子
cout << "unordered_set.load_factor()" << c.load_factor() << endl;
cout << "unordered_set.max_load_factor()"<
namespace jj10
{
using namespace std;
void test_map(long& value)
{
cout << "\ntest_map().............\n";
map c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; i++)
{
try
{
snprintf(buf, 10, "%d", rand());
c[i] = string(buf);
}
catch (const std::exception& p)
{
cout << "i:" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds:" << (clock() - timeStart) << endl;
cout << "map.size():" << c.size() << endl;
cout << "map.max_size():" << c.max_size() << endl;
long target = get_a_target_long();
timeStart = clock();
auto pItem = c.find(target);
cout << "c.find(),milli-seconds:" << (clock() - timeStart) << endl;
if (pItem!=c.end())
{
cout << "found,value" << (*pItem).second << endl;
}
else
{
cout << "not found!" << endl;
}
}
}
#include
namespace jj11
{
using namespace std;
void test_multiset(long& value)
{
cout << "\ntest_multiset()..............\n";
multiset c;
char buf[10];
clock_t timeStart = clock();
for (long i = 0; i < value; i++)
{
try
{
snprintf(buf, 10, "%d", rand());
c.insert(string(buf));
}
catch (const std::exception& p)
{
cout << "i:" << i << " " << p.what() << endl;
abort();
}
}
cout << "milli-seconds:" << (clock() - timeStart) << endl;
cout << "multiset.size():" << c.size() << endl;
cout << "multiset.max_size():" << c.max_size() << endl;
string target = get_a_target_string();
{
timeStart = clock();
auto pItem = find(c.begin(), c.end(), target);
if (pItem!=c.end())
{
cout << "found," << *pItem << endl;
}
else
{
cout << "not found!" << endl;
}
}
{
timeStart = clock();
auto pItem = c.find(target);
cout << "c.find(),milli-seconds:" << (clock() - timeStart) << endl;
if (pItem!=c.end())
{
cout << "found," << *pItem << endl;
}
else
{
cout << "not found!" << endl;
}
}
}
}
#include