ACM算法题以及答案.docx
《ACM算法题以及答案.docx》由会员分享,可在线阅读,更多相关《ACM算法题以及答案.docx(38页珍藏版)》请在冰豆网上搜索。
ACM算法题以及答案
ACM算法题使用C++实现
在做这些题目之前必须了解vector(数组),list(链表)、deque(双端队列)、queue(队列),priority_queue(优先队列)Stack(栈)、set(集合)、map(键值对),mutilset、mutilmap。
stack堆栈,没有迭代器,支持push()方法。
后进先出,top()返回最顶端的元素,pop()剔除最顶元素
deque双端队列,支持迭代器,有push_back()方法,跟vector差不多,比vector多了个pop_front,push_front方法
queue队列,先进先出,不支持迭代器,有push()方法,pop()剔除第一个元素,front()返回第一个元素
vector使用
vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库。
vector之所以被认为是一个容器,是因为它能够像容器一样存放各种类型的对象,简单地说vector是一个能够存放任意类型的动态数组,能够增加和压缩数据。
为了可以使用vector,必须在你的头文件中包含下面的代码:
#include
vector属于std命名域的,因此需要通过命名限定,如下完成你的代码:
usingstd:
:
vector; vectorv;
或者连在一起,使用全名:
std:
:
vectorv;
建议使用全局的命名域方式:
usingnamespacestd;
1.vector的声明
vectorc; 创建一个空的vector
vectorc1(c2);创建一个vectorc1,并用c2去初始化c1
vectorc(n);创建一个含有n个ElemType类型数据的vector;
vectorc(n,elem);创建一个含有n个ElemType类型数据的vector,并全部初始化为elem;
c.~vector();销毁所有数据,释放资源;
2.vector容器中常用的函数。
(c为一个容器对象)
c.push_back(elem); 在容器最后位置添加一个元素elem
c.pop_back(); 删除容器最后位置处的元素
c.at(index); 返回指定index位置处的元素
c.begin(); 返回指向容器最开始位置数据的指针
c.end(); 返回指向容器最后一个数据单元的指针+1
c.front(); 返回容器最开始单元数据的引用
c.back(); 返回容器最后一个数据的引用
c.max_size(); 返回容器的最大容量
c.size(); 返回当前容器中实际存放元素的个数
c.capacity(); 同c.size()
c.resize(); 重新设置vector的容量
c.reserve(); 同c.resize()
c.erase(p); 删除指针p指向位置的数据,返回下指向下一个数据位置的指针(迭代器)
c.erase(begin,end) 删除begin,end区间的数据,返回指向下一个数据位置的指针(迭代器)
c.clear(); 清除所有数据
c.rbegin(); 将vector反转后的开始指针返回(其实就是原来的end-1)
c.rend(); 将vector反转后的结束指针返回(其实就是原来的begin-1)
c.empty(); 判断容器是否为空,若为空返回true,否则返回false
c1.swap(c2); 交换两个容器中的数据
c.insert(p,elem); 在指针p指向的位置插入数据elem,返回指向elem位置的指针
c.insert(p,n,elem); 在位置p插入n个elem数据,无返回值
c.insert(p,begin,end)在位置p插入在区间[begin,end)的数据,无返回值
3.vector中的操作
operator[]如:
c.[i];
同at()函数的作用相同,即取容器中的数据。
list使用:
STL 中的list 就是一 双向链表,可高效地进行插入删除元素。
list不支持随机访问。
所以没有at(pos)和operator[]。
list 对象list1,list2 分别有元素list1(1,2,3),list2(4,5,6) 。
list< int>:
:
iteratorit;
list成员
说明
constructor
构造函数
destructor
析构函数
operator=
赋值重载运算符
assign
分配值
front
返回第一个元素的引用
back
返回最后一元素的引用
begin
返回第一个元素的指针(iterator)
end
返回最后一个元素的下一位置的指针
rbegin
返回链表最后一元素的后向指针(reverse_iteratororconst)
rend
返回链表第一元素的下一位置的后向指针
push_back
增加一元素到链表尾
push_front
增加一元素到链表头
pop_back
pop_back()删除链表尾的一个元素
pop_front
删除链表头的一元素
clear
删除所有元素
erase
删除一个元素或一个区域的元素(两个重载)
remove
删除链表中匹配值的元素(匹配元素全部删除)
remove_if
删除条件满足的元素(遍历一次链表),参数为自定义的回调函数
empty
判断是否链表为空
max_size
返回链表最大可能长度
size
返回链表中元素个数
resize
重新定义链表长度(两重载函数)
reverse
反转链表
sort
对链表排序,默认升序
merge
合并两个有序链表并使之有序
splice
对两个链表进行结合(三个重载函数) 结合后第二个链表清空
insert
在指定位置插入一个或多个元素(三个重载函数)
swap
交换两个链表(两个重载)
unique
删除相邻重复元素
Deque双端队列使用:
容器deque和vector非常相似,操作函数基本一致。
它采用动态数组来管理元素,提供随机存取,可以在头尾两端进行快速安插和删除元素操作。
特别要注意,除了头尾两端,在任何地方安插与删除元素,都将导致指向deque元素的任何pointersreferencesiterators失效。
包括的头文件为:
#include
usingnamespacestd;
声明一个deque时,一般需要前缀std:
:
,如std:
:
dequec;
因为类型deque是一个定义在namespacestd内的template。
构造函数:
dequec;//产生一个空的deque,其中没有任何元素
dequec1(c2);//产生另一个同型deque的副本(所有元素都被拷贝)
dequec(n);//产生一个大小为n的deque
dequec(n,elem);//产生一个大小为n的deque,
//每个元素值都是elem。
dequerc(begin,end);//产生一个deque,以区间[begin;end]
//做为元素初值
析构函数:
c.~deque();销毁所有元素,并释放内存。
非变动性操作
c.size();//返回当前的元素数量
c.empty();//判断大小是否为零。
等同于c.size()==0,但可能更快
c.max_size();//可容纳元素的最大数量
c.at(idx);//返回索引为idx所标示的元素。
如果idx越界,抛出out_of_range
c[idx];//返回索引idx所标示的元素。
不进行范围检查
c.front();//返回第一个元素,不检查元素是否存在
c.back();//返回最后一个元素
c.begin();//返回一个随机迭代器,指向第一个元素
c.end();//返回一个随机迭代器,指向最后元素的下一位置
变动性操作:
c1=c2;//将c2的所有元素赋值给c1;
c.assign(n,elem);//将n个elem副本赋值给c
c.assing(beg,end);//将区间[beg;end]中的元素赋值给c;
c.push_back(elem);//在尾部添加元素elem
c.pop_back();//移除最后一个元素(但不回传)
c.push_front();//在头部添加元素elem
c.pop_front();//移除头部一个元素(但不回传)
c.erase(pos);//移除pos位置上的元素,返回一元素位置
//如c.erase(c.begin()+5)//移除第五个元素
c.insert(pos,elem);//在pos位置插入一个元素elem,并返回新元素的位置
c.insert(pos,n,elem);//在pos位置插入n个元素elem,无返回值
c.insert(pos,beg,end);
c.resize(num);//将容器大小改为num。
可更大或更小。
c.resize(num,elem);//将容器大小改为num,新增元素都为elem
c.clear();//移除所有元素,将容器清空
PS:
Deque和Vector是智能容器,删除或者增加元素时,其他位置与元素会进行相应的移动。
queue的使用
queue模板类的定义在头文件中。
与stack模板类很相似,queue模板类也需要两个模板参数,一个是元素类型,一个容器类
型,元素类型是必要的,容器类型是可选的,默认为deque类型。
定义queue对象的示例代码如下:
queueq1;
queueq2;
queue的基本操作有:
入队,如例:
q.push(x);将x接到队列的末端。
出队,如例:
q.pop();弹出队列的第一个元素,注意,并不会返回被弹出元素的值。
访问队首元素,如例:
q.front(),即最早被压入队列的元素。
访问队尾元素,如例:
q.back(),即最后被压入队列的元素。
判断队列空,如例:
q.empty(),当队列空时,返回true。
访问队列中的元素个数,如例:
q.size()
priority_queue的使用
在头文件中,还定义了另一个非常有用的模板类priority_queue(优先队列)。
优先队
列与队列的差别在于优先队列不是按照入队的顺序出队,而是按照队列中元素的优先权顺序
出队(默认为大者优先,也可以通过指定算子来指定自己的优先顺序)。
priority_queue模板类有三个模板参数,第一个是元素类型,第二个容器类型,第三个是比
较算子。
其中后两个都可以省略,默认容器为vector,默认算子为less,即小的往前排,大
的往后排(出队时序列尾的元素出队)。
定义priority_queue对象的示例代码如下:
priority_queueq1;
priority_queue>q2;//注意在两个尖括号之间一定要留空格。
priority_queue,greater>q3;//定义小的先出队
priority_queue的基本操作与queue相同。
初学者在使用priority_queue时,最困难的可能就是如何定义比较算子了。
如果是基本数据类型,或已定义了比较运算符的类,可以直接用STL的less算子和greater
算子——默认为使用less算子,即小的往前排,大的先出队。
如果要定义自己的比较算子,方法有多种,这里介绍其中的一种:
重载比较运算符。
优先队
列试图将两个元素x和y代入比较运算符(对less算子,调用xy),
若结果为真,则x排在y前面,y将先于x出队,反之,则将y排在x前面,x将先出队。
看下面这个简单的示例:
#include
#include
usingnamespacestd;
classT
{
public:
intx,y,z;
T(inta,intb,intc):
x(a),y(b),z(c)
{
}
};
booloperator<(constT&t1,constT&t2)
{
returnt1.z}
main()
{
priority_queueq;
q.push(T(4,4,3));
q.push(T(2,2,5));
q.push(T(1,5,4));
q.push(T(3,3,6));
while(!
q.empty())
{
Tt=q.top();q.pop();
cout<}
return1;
}
输出结果为(注意是按照z的顺序从大到小出队的):
336
225
154
443
Statck使用
statck栈中的数据是先进后出的(FirstInLastOut,FILO)。
栈只有一个出口,允许新增元素(只能在栈顶上增加)、移出元素(只能移出栈顶元素)、取得栈顶元素等操作。
set和multiset的功能
和所有关联式容器类似,通常使用平衡二叉树完成。
事实上,set和multiset通常以红黑树实作而成。
自动排序的优点是使得搜寻元素时具有良好的性能,具有对数时间复杂度。
但是造成的一个缺点就是:
不能直接改变元素值。
因为这样会打乱原有的顺序。
改变元素值的方法是:
先删除旧元素,再插入新元素。
存取元素只能通过迭代器,从迭代器的角度看,元素值是常数。
三、操作函数
构造函数和析构函数
set的形式可以是:
有两种方式可以定义排序准则:
1、以template参数定义:
[cpp] viewplaincopyprint?
1.set> col1;
此时,排序准则就是型别的一部分。
型别系统确保只有排序准则相同的容器才能被合并。
程序实例:
[cpp] viewplaincopyprint?
1.#include
2.#include
3.using namespace std;
4.
5.int main()
6.{
7. set s1;
8. set > s2;
9.
10. for (int i = 1;i < 6;++i)
11. {
12. s1.insert(i);
13. s2.insert(i);
14. }
15. if(s1 == s2)
16. cout << "c1 equals c2 !
" << endl;
17. else
18. cout << "c1 not equals c2 !
" << endl;
19.}
程序运行会报错。
但是如果把s1的排序准则也指定为greater便运行成功。
2、以构造函数参数定义。
这种情况下,同一个型别可以运用不同的排序准则,而排序准则的初始值或状态也可以不同。
如果执行期才获得排序准则,而且需要用到不同的排序准则,这种方式可以派上用场。
程序实例:
[cpp] viewplaincopyprint?
1.#include
2.#include "print.hpp"
3.#include
4.using namespace std;
5.
6.template
7.class RuntimeCmp{
8.public:
9. enum cmp_mode{normal,reverse};
10.private:
11. cmp_mode mode;
12.public:
13. RuntimeCmp(cmp_mode m = normal):
mode(m){}
14.
15. bool operator()(const T &t1,const T &t2)
16. {
17. return mode == normal ?
t1 < t2 :
t2 < t1;
18. }
19.
20. bool operator==(const RuntimeCmp &rc)
21. {
22. return mode == rc.mode;
23. }
24.};
25.
26.typedef set > IntSet;
27.
28.void fill(IntSet& set);
29.
30.int main()
31.{
32. IntSet set1;
33. fill(set1);
34. PRINT_ELEMENTS(set1,"set1:
");
35.
36. RuntimeCmp reverse_order(RuntimeCmp:
:
reverse);
37.
38. IntSet set2(reverse_order);
39. fill(set2);
40. PRINT_ELEMENTS(set2,"set2:
");
41.
42. set1 = set2;//assignment:
OK
43. set1.insert(3);
44. PRINT_ELEMENTS(set1,"set1:
");
45.
46. if(set1.value_comp() == set2.value_comp())//value_comp verdana, arial, helvetica, sans-serif; ">Returns the comparison object associated with the container
47. cout << "set1 and set2 have the same sorting criterion" << endl;
48. else
49. cout << "set1 and set2 have the different sorting criterion" << endl;
50.}
51.
52.void fill(IntSet &set)
53.{
54. set.insert(4);
55. set.insert(7);
56. set.insert(5);
57. set.insert
(1);
58. set.insert(6);
59. set.insert
(2);
60. set.insert(5);
61.}
运行结果:
虽然set1和set2的而比较准则本身不同,但是型别相同,所以可以进行赋值操作。
非变动性操作
注意:
元素比较操作只能用于型别相同的容器。
特殊的搜寻函数
赋值
赋值操作两端的容器必须具有相同的型别,但是比较准则本身可以不同,但是其型别必须相同。
如果比较准则的不同,准则本身也会被赋值或交换。
迭代器相关函数
元素的插入和删除
注意:
插入函数的返回值不完全相同。
set提供的插入函数:
[cpp] viewplaincopyprint?
1.pair insert(const value_type& elem);
2.iterator insert(iterator pos_hint, const value_type& elem);
multiset提供的插入函数:
[cpp] viewplaincopyprint?
1.iterator insert(const value_type& elem);
2.iterator insert(iterator pos_hint, const value_type& elem);
返回值型别不同的原因是set不允许元素重复,而multiset允许。
当插入的元素在set中已经包含有同样值的元素时,插入就会失败。
所以set的返回值型别是由pair组织起来的两个值:
第一个元素返回新元素的位置,或返回现存的同值元素的位置。
第二个元素表示插入是否成功。
set的第二个insert函数,如果插入失败,就只返回重复元素的位置!
但是,所有拥有位置提示参数的插入函数的返回值型别是相同的。
这样就确保了至少有了一个通用型的插入函数,在各种容器中有共通接口。
注意:
还有一个返回