机试技巧与STL
[TOC]
vs2018 快捷键
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| CTRL + J 列出成员 Ctrl+E,D 格式化全部代码 Ctrl+K,F 格式化选中的代码 CTRL + SHIFT + E 显示资源视图 F12 转到定义 CTRL + F12 转到声明 CTRL + ALT + J 对象浏览 CTRL + ALT + F1 帮助目录 CTRL + F1 动态帮助 CTRL + K, CTRL + C 注释选择的代码 CTRL + K, CTRL + U 取消对选择代码的注释 CTRL + U 转小写 CTRL + SHIFT + U 转大写 F5 运行调试 CTRL + F5 运行不调试 F10 跨过程序执行 F11 单步逐句执行
|
头文件
标准c库
头文件 |
说明 |
头文件 |
说明 |
头文件 |
说明 |
assert.h |
断言相关 |
ctype.h |
字符类型判断 |
errno.h |
标准错误机制 |
float.h |
浮点限制 |
limits.h |
整形限制 |
locale.h |
本地化接口 |
math.h |
数学函数 |
setjmp.h |
非本地跳转 |
signal.h |
信号相关 |
stdarg.h |
可变参数处理 |
stddef.h |
宏和类型定义 |
stdio.h |
标准I/O |
stdlib.h |
标准工具库 |
string.h |
字符串和内存处理 |
time.h |
时间相关 |
c++ STL
using namespace std;
头文件 |
说明 |
头文件 |
说明 |
头文件 |
说明 |
algorithm |
通用算法 |
deque |
双端队列 |
vector |
向量 |
iterator |
迭代器 |
stack |
栈 |
map |
图(键值对) |
list |
列表 |
string |
字符串 |
set |
集合 |
queue |
队列 |
bitset |
bit类 |
numeric |
数值算法 |
常用头
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<vector> #include<stack> #include<bitset> #include<cstdlib> #include<cmath> #include<set> #include<list> #include<deque> #include<map> #include<queue> using namespace std;
|
常用宏定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #define MAX(x,y) (((x)>(y)) ? (x) : (y)) #define MIN(x,y) (((x) < (y)) ? (x) : (y))
#define mod(x) ((x)%MOD)
#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)
#define ARR_SIZE(a) (sizeof((a))/sizeof((a[0])))
#define MT(x,i) memset(x,i,sizeof(x)) #define MEM(a,b) memset((a),(b),sizeof(a))
#define LL long long #define ull unsigned long long #define pii pair<int,int>
#define PI acos(-1.0) #define eps 1e-12 #define INF 0x3f3f3f3f const int INF_INT = 2147483647; const ll INF_LL = 9223372036854775807LL; const ull INF_ULL = 18446744073709551615Ull; const ll P = 92540646808111039LL; const ll maxn = 1e5 + 10, MOD = 1e9 + 7; const int Move[4][2] = {-1,0,1,0,0,1,0,-1}; const int Move_[8][2] = {-1,-1,-1,0,-1,1,0,-1,0,1,1,-1,1,0,1,1};
|
结构体
定义
1 2 3 4 5 6 7
| struct InitMember { int first; double second; char* third; float four; };
|
初始化
方法一:定义时赋值
1
| struct InitMember test = {-10,3.141590,"method one",0.25};
|
方法二:定义后逐个赋值
1 2 3 4 5 6
| struct InitMember test;
test.first = -10; test.second = 3.141590; test.third = "method two"; test.four = 0.25;
|
方法三:定义时乱序赋值(C++风格)
1 2 3 4 5 6
| struct InitMember test = { second:3.141590, third:"method three", first:-10, four:0.25 };
|
方法四:构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| //定义图的定点 typedef struct Vertex { int id,inDegree,outDegree; vector<int> connectors; //存储节点的后续连接顶点编号 Vertex() : id(-1),inDegree(0),outDegree(0) {} Vertex(int nid) : id(nid),inDegree(0),outDegree(0) {} } Vertex; //定义Graph的邻接表表示 typedef struct Graph { vector<Vertex> vertexs; //存储定点信息 int nVertexs; //计数:邻接数 bool isDAG; //标志:是有向图吗 Graph(int n, bool isDAG) : nVertexs(n), isDAG(isDAG) { vertexs.resize(n); } Graph() : nVertexs(1), isDAG(1) { vertexs.resize(1); } //向图中添加边 bool addEdge(int id1, int id2) { ... ... ... return true; } } Graph;
Graph g(8, false);
|
运算符重载
1 2
| typedef struct{int id;int h;} node; bool operator <(const node& a,const node & b){return (a.h)<(b.h);}
|
c++new的使用
常规
1 2 3 4
| int *x = new int; int *a = new int(100); char *b = new char[10]; float *p=new float (3.14159);
|
动态申请列大小固定的二维数组
1 2 3 4 5 6 7
| const int MAXCOL = 3; cin>>row;
int *pp_arr = new int[nRow * MAXCOL]; int (*p)[MAXCOL] = (int(*)[MAXCOL])pp_arr;
|
动态申请大小不固定的二维数组
1 2 3 4 5 6
| cin>>row>>col; int **p = new int*[row]; for (int i = 0; i < row; i ++) { p[i] = new int[col]; }
|
常用STL
参考:
https://blog.csdn.net/f_zyj/article/details/51594851
https://download.csdn.net/download/f_zyj/9988653
简述
STL底层说明
C++ STL 的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| 1.vector 底层数据结构为数组 ,支持快速随机访问
2.list 底层数据结构为双向链表,支持快速增删
3.deque 底层数据结构为一个中央控制器和多个缓冲区,详细见STL源码剖析P146,支持首尾(中间不能)快速增删,也支持随机访问 deque是一个双端队列(double-ended queue),也是在堆中保存内容的.它的保存形式如下: [堆1] --> [堆2] -->[堆3] --> ... 每个堆保存好几个元素,然后堆和堆之间有指针指向,看起来像是list和vector的结合品.
4.stack 底层一般用list或deque实现,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时
5.queue 底层一般用list或deque实现,封闭头部即可,不用vector的原因应该是容量大小有限制,扩容耗时
(stack和queue其实是适配器,而不叫容器,因为是对容器的再封装)
6.priority_queue 的底层数据结构一般为vector为底层容器,堆heap为处理规则来管理底层容器实现
7.set 底层数据结构为红黑树,有序,不重复
8.multiset 底层数据结构为红黑树,有序,可重复
9.map 底层数据结构为红黑树,有序,不重复
10.multimap 底层数据结构为红黑树,有序,可重复
11.hash_set 底层数据结构为hash表,无序,不重复
12.hash_multiset 底层数据结构为hash表,无序,可重复
13.hash_map 底层数据结构为hash表,无序,不重复
14.hash_multimap 底层数据结构为hash表,无序,可重复
|
CCF 编译出错原因: 不允许C++STL容器嵌套(需要满足相应的格式)
就是要在后面的“>”之间,必须得有一个空格,如果有多层,那每层都得有一个空格。
1
| map<string,list<string> > user;
|
algorithm
头文件:lgorithm
函数参数,返回值以及具体的使用方法请自行去头文件找定义!!!
不修改内容的序列操作
函数 |
说明 |
adjacent_find |
查找两个相邻(Adjacent)的等价(Identical)元素 |
all_ofC++11 |
检测在给定范围中是否所有元素都满足给定的条件 |
any_ofC++11 |
检测在给定范围中是否存在元素满足给定条件 |
count |
返回值等价于给定值的元素的个数 |
count_if |
返回值满足给定条件的元素的个数 |
equal |
返回两个范围是否相等 |
find |
返回第一个值等价于给定值的元素 |
find_end |
查找范围A中与范围B等价的子范围最后出现的位置 |
find_first_of |
查找范围A中第一个与范围B中任一元素等价的元素的位置 |
find_if |
返回第一个值满足给定条件的元素 |
find_if_notC++11 |
返回第一个值不满足给定条件的元素 |
for_each |
对范围中的每个元素调用指定函数 |
mismatch |
返回两个范围中第一个元素不等价的位置 |
none_ofC++11 |
检测在给定范围中是否不存在元素满足给定的条件 |
search |
在范围A中查找第一个与范围B等价的子范围的位置 |
search_n |
在给定范围中查找第一个连续n个元素都等价于给定值的子范围的位置 |
修改内容的序列操作
函数 |
说明 |
copy |
将一个范围中的元素拷贝到新的位置处 |
copy_backward |
将一个范围中的元素按逆序拷贝到新的位置处 |
copy_ifC++11 |
将一个范围中满足给定条件的元素拷贝到新的位置处 |
copy_nC++11 |
拷贝 n 个元素到新的位置处 |
fill |
将一个范围的元素赋值为给定值 |
fill_n |
将某个位置开始的 n 个元素赋值为给定值 |
generate |
将一个函数的执行结果保存到指定范围的元素中,用于批量赋值范围中的元素 |
generate_n |
将一个函数的执行结果保存到指定位置开始的 n 个元素中 |
iter_swap |
交换两个迭代器(Iterator)指向的元素 |
moveC++11 |
将一个范围中的元素移动到新的位置处 |
move_backwardC++11 |
将一个范围中的元素按逆序移动到新的位置处 |
random_shuffle |
随机打乱指定范围中的元素的位置 |
remove |
将一个范围中值等价于给定值的元素删除 |
remove_if |
将一个范围中值满足给定条件的元素删除 |
remove_copy |
拷贝一个范围的元素,将其中值等价于给定值的元素删除 |
remove_copy_if |
拷贝一个范围的元素,将其中值满足给定条件的元素删除 |
replace |
将一个范围中值等价于给定值的元素赋值为新的值 |
replace_copy |
拷贝一个范围的元素,将其中值等价于给定值的元素赋值为新的值 |
replace_copy_if |
拷贝一个范围的元素,将其中值满足给定条件的元素赋值为新的值 |
replace_if |
将一个范围中值满足给定条件的元素赋值为新的值 |
reverse |
反转排序指定范围中的元素 |
reverse_copy |
拷贝指定范围的反转排序结果 |
rotate |
循环移动指定范围中的元素 |
rotate_copy |
拷贝指定范围的循环移动结果 |
shuffleC++11 |
用指定的随机数引擎随机打乱指定范围中的元素的位置 |
swap |
交换两个对象的值 |
swap_ranges |
交换两个范围的元素 |
transform |
对指定范围中的每个元素调用某个函数以改变元素的值 |
unique |
删除指定范围中的所有连续重复元素,仅仅留下每组等值元素中的第一个元素。 |
unique_copy |
拷贝指定范围的唯一化(参考上述的 unique)结果 |
划分操作
函数 |
说明 |
is_partitionedC++11 |
检测某个范围是否按指定谓词(Predicate)划分过 |
partition |
将某个范围划分为两组 |
partition_copyC++11 |
拷贝指定范围的划分结果 |
partition_pointC++11 |
返回被划分范围的划分点 |
stable_partition |
稳定划分,两组元素各维持相对顺序 |
排序操作
函数 |
说明 |
is_sortedC++11 |
检测指定范围是否已排序 |
is_sorted_untilC++11 |
返回最大已排序子范围 |
nth_element 部份排序指定范围中的元素,使得范围按给定位置处的元素划分 |
|
partial_sort |
部份排序 |
partial_sort_copy |
拷贝部分排序的结果 |
sort |
排序 |
stable_sort |
稳定排序 |
二分法查找操作
函数 |
说明 |
binary_search |
判断范围中是否存在值等价于给定值的元素 |
equal_range |
返回范围中值等于给定值的元素组成的子范围 |
lower_bound |
返回指向范围中第一个值大于或等于给定值的元素的迭代器 |
upper_bound |
返回指向范围中第一个值大于给定值的元素的迭代器 |
集合操作
函数 |
说明 |
includes |
判断一个集合是否是另一个集合的子集 |
inplace_merge |
就绪合并 |
merge 合并 |
|
set_difference |
获得两个集合的差集 |
set_intersection |
获得两个集合的交集 |
set_symmetric_difference |
获得两个集合的对称差 |
set_union |
获得两个集合的并集 |
堆操作
函数 |
说明 |
is_heap |
检测给定范围是否满足堆结构 |
is_heap_untilC++11 |
检测给定范围中满足堆结构的最大子范围 |
make_heap |
用给定范围构造出一个堆 |
pop_heap |
从一个堆中删除最大的元素 |
push_heap |
向堆中增加一个元素 |
sort_heap |
将满足堆结构的范围排序 |
最大/最小操作
函数 |
说明 |
is_permutationC++11 |
判断一个序列是否是另一个序列的一种排序 |
lexicographical_compare |
比较两个序列的字典序 |
max |
返回两个元素中值最大的元素 |
max_element |
返回给定范围中值最大的元素 |
min |
返回两个元素中值最小的元素 |
min_element |
返回给定范围中值最小的元素 |
minmaxC++11 |
返回两个元素中值最大及最小的元素 |
minmax_elementC++11 |
返回给定范围中值最大及最小的元素 |
next_permutation |
返回给定范围中的元素组成的下一个按字典序的排列 |
prev_permutation |
返回给定范围中的元素组成的上一个按字典序的排列 |
vector
头文件:vector
在STL的vector头文件中定义了vector(向量容器模版类),vector容器以连续数组的方式存储元素序列,可以将vector看作是以顺序结构实现的线性表。当我们在程序中需要使用动态数组时,vector将会是理想的选择,vector可以在使用过程中动态地增长存储空间。
vector模版类需要两个模版参数,第一个参数是存储元素的数据类型,第二个参数是存储分配器的类型,其中第二个参数是可选的,如果不给出第二个参数,将使用默认的分配器
下面给出几个常用的定义vector向量对象的方法示例:
1 2 3 4 5 6 7
| vector<int> s;
vector<int> s(n);
vector<int> s(first, last);
|
vector的基本操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| s[i] s.front() s.back() s.push_back(x) s.size() s.empty() s.pop_back() s.begin() s.end() s.insert(it, val) s.insert(it, n, val) s.insert(it, first, last)
s.erase(it) s.erase(first, last) s.reserve(n) s.resize(n) s.resize(n, val) s.clear() s.swap(v) s.assign(first, last)
#include <iostream> #include <vector>
using namespace std;
int main() { vector<int> L; int x; while(cin >> x) { L.push_back(x); } for (int i = L.size() - 1; i >= 0; i--) { cout << L[i] << " "; } cout << endl; return 0; }
|
list
头文件:list
下面给出几个常用的定义list对象的方法示例:
1 2 3 4 5
| list<int>a{1,2,3} list<int>a(n) list<int>a(n, m) list<int>a(first, last)
|
list的基本操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| a.begin() a.end() a.push_front(x) a.push_back(x) a.pop_back() a.pop_front() a.size() a.empty() a.resize(n) a.resize(n, val) a.clear() a.front() a.back() a.swap(v) a.merge(b) a.insert(it, val) a.insert(it, n, val) a.insert(it, first, last)
a.erase(it) a.erase(first, last) a.remove(x) a.assign(n, val) a.assign(b.begin(), b.end())
|
string
头文件:string
string是STL的字符串类型,通常用来表示字符串。而在使用string之前,字符串通常是用char*
表示的。
string和char*
的区别
string是一个类, char*
是一个指向字符的指针。
string封装了char*
,管理这个字符串,是一个char*
型的容器。也就是说string是一个容器,里面元素的数据类型是char*
。
string不用考虑内存释放和越界。
string管理char*
所分配的内存。每一次string的复制,取值都由string类负责维护,不用担心复制越界和取值越界等。 string提供了一系列的字符串操作函数
查找find,拷贝copy,删除erase,替换replace,插入insert.
构造和析构函数:
表达式 |
效果 |
string s |
生成一个空字符串 |
string s(str) |
copy构造函数,生成一个str的复制品 |
string s(str,idx) |
将string内始于位置idx的部分当作字符串s的初值 |
string s(str,idx,len) |
将string内始于位置idx且长度最多为len的部分当作字符串s的初值 |
string s(cstr) |
以C-string字符串cstr作为字符串s的初值 |
string s(cstr,len) |
以C-string字符串cstr的前len个字符作为字符串s的初值 |
string s(num,c) |
生成一个字符串,包含num个字符c |
string s(beg,end) |
以区间[beg,end]内所有字符作为字符串s的初值 |
操作函数:
操作函数 |
效果 |
=,assign() |
赋以新值 |
swap() |
交换两个字符串的内容 |
+=, append(),push_back() |
添加字符 |
insert() |
插入字符 |
erase() |
删除字符 |
clear() |
移除全部字符 |
resize() |
改变字符数量 |
replace() |
替换字符 |
+ |
串联字符串 |
==,!=,<,<=,>,>=,compare() |
比较字符串内容 |
size(),length() |
返回字符数量,等效函数 |
max_size() |
返回字符的最大可能个数 |
empty() |
判断字符串是否为空 |
capacity() |
返回重新分配之前的字符容量 |
reserve() |
保留一定量内存以容纳一定数量的字符 |
[ ],at() |
存取单一字符 |
>>,getline() |
从stream中读取某值 |
<< |
将某值写入stream |
copy() |
将内容复制为一个C-string |
c_str() |
将内容以C-string形式返回 |
data() |
将内容以字符数组形式返回 |
substr() |
返回某个子字符串 |
begin(),end() |
提供正常的迭代器支持 |
rbegin(),rend() |
提供逆向迭代器支持 |
pair
头文件:utility
STL的utility头文件中描述了一个看上去非常简单的模版类pair,用来表示一个二元组或元素对,并提供了按照字典序对元素对进行大小比较运算符模版函数。
Example,想要定义一个对象表示一个平面坐标点,则可以:
1 2
| pair<double, double> p; cin >> p.first >> p.second;
|
pair模版类需要两个参数:首元素的数据类型和尾元素的数据类型。pair模版类对象有两个成员:first和second,分别表示首元素和尾元素。
在其中已经定义了pair上的六个比较运算符:<、>、<=、>=、==、!=,其规则是先比较first,first相等时再比较second,这符合大多数应用的逻辑。当然,也可以通过重载这几个运算符来重新指定自己的比较逻辑。
除了直接定义一个pair对象外,如果需要即时生成一个pair对象,也可以调用在其中定义的一个模版函数:make_pair。make_pair需要两个参数,分别为元素对的首元素和尾元素。
map
头文件:map
在STL的头文件中map中定义了模版类map和multimap,用有序二叉树表存储类型为pair<const Key, T>
的元素对序列。序列中的元素以const Key部分作为标识,map中所有元素的Key值必须是唯一的,multimap则允许有重复的Key值。
可以将map看作是由Key标识元素的元素集合,这类容器也被称为“关联容器”,可以通过一个Key值来快速决定一个元素,因此非常适合于需要按照Key值查找元素的容器。
map模版类需要四个模版参数,第一个是键值类型,第二个是元素类型,第三个是比较算子,第四个是分配器类型。其中键值类型和元素类型是必要的。
定义map对象的代码示例:
map的基本操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| m[key] = value; m.insert(make_pair(key, value));
int i = m[key]; map<string, int>::iterator it = m.find(key);
m.erase(key); m.erase(it);
m.size(); m.empty(); m.clear();
|
stack
头文件:stack
stack模版类的定义在stack头文件中。
stack模版类需要两个模版参数,一个是元素类型,另一个是容器类型,但是只有元素类型是必要的,在不指定容器类型时,默认容器的类型为deque。
定义stack对象的示例代码如下:
1 2
| stack<int> s; stack<string> ss;
|
stack的基本操作有:
1 2 3 4 5
| s.push(x); s.pop(); s.top(); s.empty(); s.size();
|
queue
头文件:queue
queue模版类的定义在queue头文件中。
queue与stack相似,queue模版类也需要两个模版参数,一个元素类型,一个容器类型,元素类型时必须的,容器类型时可选的,默认为deque类型。
定义queue对象的示例代码必须如下:
1 2
| queue<int> q; queue<double> qq;
|
queue的基本操作:
1 2 3 4 5 6
| q.push(x); q.pop(); q.front(); q.back(); q.empty(); q.size();
|
set
头文件:set
set是与集合相关的容器,STL为我们提供了set的实现,在编程题中遇见集合问题直接调用是十分方便的。
定义set对象的示例代码如下:
1 2
| set<int> s; set<double> ss;
|
set的基本操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| s.begin() s.clear() s.count() s.empty() s.end() s.equal_range() s.erase() s.find() s.get_allocator() s.insert() s.lower_bound() s.key_comp() s.max_size() s.rbegin() s.rend() s.size() s.swap() s.upper_bound() s.value_comp()
|
multiset
头文件:set
在set头文件中,还定义了另一个非常实用的模版类multiset(多重集合)。多重集合与集合的区别在于集合中不能存在相同元素,而多重集合中可以存在。
定义multiset对象的示例代码如下:
1 2
| multiset<int> s; multiset<double> ss;
|
multiset和set的基本操作相似,需要注意的是,集合的count()能返回0(无)或者1(有),而多重集合是有多少个返回多少个。
bitset
头文件:bitset
在 STLSTL 的头文件中 bitset中定义了模版类 bitsetbitset,用来方便地管理一系列的 bitbit 位的类。bitsetbitset 除了可以访问指定下标的 bitbit 位以外,还可以把它们作为一个整数来进行某些统计。
bitsetbitset 模板类需要一个模版参数,用来明确指定含有多少位。
定义 bitsetbitset 对象的示例代码:
1 2 3 4 5 6
| const int MAXN = 32; bitset<MAXN> bt; bitset<MAXN> bt1(0xf); bitset<MAXN> bt2(012); bitset<MAXN> bt3("1010"); bitset<MAXN> bt4(s, pos, n);
|
bitsetbitset 基本操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| bt.any() bt.none() bt.count() bt.size() bt[pos] bt.test(pos) bt.set() bt.set(pos) bt.reset() bt.reset(pos) bt.flip() bt.flip(pos) bt[pos].flip() bt.to_ulong() os << bt
|
图模板
不带出入度的最简模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
| #include <iostream> #include <vector> #include <set> using namespace std; #define MAX(a, b) ((a) > (b) ? (a) : (b) )
typedef struct Vertex { int id; vector<int> connectors; Vertex() : id(-1) {} Vertex(int nid) : id(nid) {} } Vertex;
typedef struct Graph { vector<Vertex> vertexs; int nVertexs; bool isDAG; Graph(int n, bool isDAG) : nVertexs(n), isDAG(isDAG) { vertexs.resize(n); } bool addEdge(int id1, int id2) { if (!(MAX(id1, id2) < vertexs.size())) return false; if (isDAG) { vertexs[id1].connectors.push_back(id2); } else { vertexs[id1].connectors.push_back(id2); vertexs[id2].connectors.push_back(id1); } return true; } vector<int> BFS(int start) { set<int> visited; vector<int> g, rst; g.push_back(start); visited.insert(start); while(g.size() > 0) { int id = g[0]; g.erase(g.begin()); rst.push_back(id); for(int i = 0; i < vertexs[id].connectors.size(); i++) { int id1 = vertexs[id].connectors[i]; if (visited.count(id1) == 0) { g.push_back(id1); visited.insert(id1); } } } return rst; } vector<int> DFS(int start) { set<int> visited; vector<int> g, rst; g.push_back(start); visited.insert(start); rst.push_back(start); bool found; while(g.size() > 0) { int id = g[g.size()-1]; found = false; for(int i = 0; i < vertexs[id].connectors.size(); i++) { int id1 = vertexs[id].connectors[i]; if (visited.count(id1) == 0) { g.push_back(id1); rst.push_back(id1); visited.insert(id1); found = true; break; } } if (!found) { int id2 = g[g.size()-1]; rst.push_back(-1 * id2); g.pop_back(); } } return rst; } } Graph; int main() { Graph g(8, false); g.addEdge(0, 1); g.addEdge(0, 3); g.addEdge(1, 2); g.addEdge(3, 4); g.addEdge(3, 5); g.addEdge(4, 5); g.addEdge(4, 6); g.addEdge(5, 6); g.addEdge(5, 7); g.addEdge(6, 7); vector<int> bv = g.BFS(0); cout << "宽度优先搜索节点顺序:"; for(int j = 0; j < bv.size(); j++) cout << bv[j] << " "; cout << endl; cout << "深度优先搜索节点顺序:"; Graph g1(6, false); g1.addEdge(0, 1); g1.addEdge(0, 4); g1.addEdge(0, 5); g1.addEdge(1, 5); g1.addEdge(4, 5); g1.addEdge(5, 2); g1.addEdge(5, 3); g1.addEdge(2, 3); vector<int> route = g1.DFS(0); for(int i = 0; i < route.size(); i++) cout << route[i] << " "; cout << endl; char ch; cin >> ch; return 0; }
|
带出入度的 (2019推免试题)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
| #include <algorithm> #include <iostream> #include <vector> #include <queue> #define MAX(a, b) ((a) > (b) ? (a) : (b) ) using namespace std; int n,m; vector<int> inDegreelist,outDegreelist;
typedef struct Vertex { int id,inDegree,outDegree; vector<int> connectors; Vertex() : id(-1),inDegree(0),outDegree(0) {} Vertex(int nid) : id(nid),inDegree(0),outDegree(0) {} } Vertex;
typedef struct Graph { vector<Vertex> vertexs; int nVertexs; bool isDAG; Graph(int n, bool isDAG) : nVertexs(n), isDAG(isDAG) { vertexs.resize(n); } Graph() : nVertexs(1), isDAG(1) { vertexs.resize(1); } bool addEdge(int id1, int id2) { if (!(MAX(id1, id2) < vertexs.size())) return false; if (isDAG) { vertexs[id1].connectors.push_back(id2); vertexs[id1].outDegree++; vertexs[id2].inDegree++; } else { vertexs[id1].connectors.push_back(id2); vertexs[id2].connectors.push_back(id1);
vertexs[id1].outDegree++; vertexs[id1].inDegree++;
vertexs[id2].outDegree++; vertexs[id2].inDegree++;
} return true; } } Graph;
Graph g;
void init(){ cin>>n>>m; g=Graph(n, true); int src,dst; while(m--){ cin>>src>>dst; g.addEdge(src,dst); } vector<Vertex>::iterator it = g.vertexs.begin(); while(it!=g.vertexs.end()){ inDegreelist.push_back(it->inDegree); outDegreelist.push_back(it->outDegree); it++; } } int countin(int n){ return count(inDegreelist.begin(),inDegreelist.end(),n); } int countout(int n){ return count(outDegreelist.begin(),outDegreelist.end(),n); }
bool Is_List(){ return (countin(0)==1)&&(countout(0)==1)&&(countin(1)==n-1)&&(countout(1)==n-1); }
bool Is_Tree(){ return (countin(0)==1)&&(countin(1)==n-1); }
bool topologicalSort(){ int num=0; queue<int> q; for(int i=0;i<n;i++){ if(inDegreelist[i]==0){ q.push(i); } }
while(!q.empty()){ int u=q.front(); q.pop(); for(int i=0;i<g.vertexs[u].connectors.size();i++){ int v=g.vertexs[u].connectors[i]; inDegreelist[v]--; if(inDegreelist[v]==0){ q.push(v); } } g.vertexs[u].connectors.clear(); num++; } if(num==n) return true; else return false; }
int main(){ init(); if(n==0||m==0){ cout<<"error"<<endl; } if(Is_List()){ cout<<"list"<<endl; } else if(Is_Tree()){ cout<<"tree"<<endl; } else if(topologicalSort()){ cout<<"no ring"<<endl; } else{ cout<<"have ring"<<endl; } return 0; }
|
图算法:找出u到v的所有路径-邻接表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
| #include<stdio.h> #include<stdlib.h>
#ifndef BASE #define BASE #define TRUE 1 #define FALSE 0 #define OK 1 #define ERROR 0 #define INFEASIBLE -1 #define OVERFLOW -2 typedef int Status; typedef int bool; #endif
#define VertexType char #define VRType int #define maxSize 100 void Visit(VertexType e) { printf("%c", e); }
#define MAX_VERTEX_NUM 20 typedef enum{DG, UDG} GraphKind; typedef struct ArcNode{ int adjV; VRType weight; struct ArcNode *next; }ArcNode; typedef struct VNode{ VertexType data; ArcNode *firstarc; }VNode, AdjList[MAX_VERTEX_NUM]; typedef struct{ GraphKind kind; int vernum,arcnum; AdjList vers; }ALGraph;
Status InitGraph_AL(ALGraph *pG) { int i; pG->arcnum = 0; pG->vernum = 0; for (i=0; i<MAX_VERTEX_NUM; ++i) pG->vers[i].firstarc = NULL; return OK; } int LocateVex_AL(ALGraph G, VertexType e) { int i; for (i=0; i<G.vernum; ++i) { if (G.vers[i].data == e) { return i; } } return -1; } Status CreateDG_AL(ALGraph *pG) { int i,a,b; char tmp[MAX_VERTEX_NUM]; char h,t; ArcNode *p, *q;
InitGraph_AL(pG); pG->kind = DG; scanf("%d", &i); if (i<0) return ERROR; pG->vernum = i; scanf("%d", &i); if (i<0) return ERROR; pG->arcnum = i; scanf("%s", tmp); for (i=0; i<pG->vernum; ++i) pG->vers[i].data=tmp[i]; for (i=0; i<pG->arcnum; ++i) { scanf("%s", tmp); h = tmp[0]; t = tmp[2]; a = LocateVex_AL(*pG, h); b = LocateVex_AL(*pG, t); if (a<0 || b<0) return ERROR; p = (ArcNode *)malloc(sizeof(ArcNode)); if (!p) exit(OVERFLOW); p->adjV=b;p->next=NULL; if (pG->vers[a].firstarc) { for (q = pG->vers[a].firstarc; q->next; q=q->next) ; q->next = p; } else { pG->vers[a].firstarc = p; } } return OK; }
int visit[MAX_VERTEX_NUM]; VertexType paths[maxSize][MAX_VERTEX_NUM]; int path[MAX_VERTEX_NUM]; int pathnum=0; void FindAllPath(ALGraph G, int u,int v,int k) { int i; ArcNode *p; visit[u]=1; path[k]=u; if (u==v) { for (i=0; i<=k; i++) { paths[pathnum][i] = G.vers[path[i]].data; } paths[pathnum][i]='\0'; pathnum++; } else { for (p=G.vers[u].firstarc; p; p=p->next) { if (visit[p->adjV]==0) FindAllPath(G, p->adjV, v, k+1); } } visit[u]=0; path[k]=0; }
int main() {
int i,j; int cnt; ALGraph G; char tmp[20];
CreateDG_AL(&G);
while (1) { scanf("%s", tmp); i = LocateVex_AL(G, tmp[0]); j = LocateVex_AL(G, tmp[3]); for (cnt=0; cnt<MAX_VERTEX_NUM; cnt++) visit[cnt]=0; pathnum=0; printf("7.28 输出所有 %c 到 %c 的路径\n", tmp[0], tmp[3]); FindAllPath(G, i, j, 0); if (pathnum==0) { printf("\t- 走不通\n"); } for (i=0; i<pathnum; i++) { printf("\t%d %s\n", i+1, paths[i]); } } return 0; }
|
树模板
注释版
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
| #include<bits/stdc++.h> #include<cmath> #define mem(a,b) memset(a,b,sizeof a); using namespace std; typedef long long ll; const int maxn=50; int mid[maxn],po[maxn],pr[maxn]; int first; struct node { int l,r; }T[maxn];
int mid_pr_build(int la,int ra,int lb,int rb) { if(la>ra) return 0; int rt=pr[lb]; int p1=la,p2; while(mid[p1]!=rt) p1++; p2=p1-la; T[rt].l=mid_pr_build(la,p1-1,lb+1,lb+p2); T[rt].r=mid_pr_build(p1+1,ra,lb+p2+1,rb); return rt; }
int mid_po_build(int la,int ra,int lb,int rb) { if(la>ra) return 0; int rt=po[rb]; int p1=la,p2; while(mid[p1]!=rt) p1++; p2=p1-la; T[rt].l=mid_po_build(la,p1-1,lb,lb+p2-1); T[rt].r=mid_po_build(p1+1,ra,lb+p2,rb-1); return rt; }
int getHeight(int rt) { if(rt==0) return 0; return 1+max(getHeight(T[rt].l),getHeight(T[rt].r)); }
void bfs(int rt) { queue<int> q; vector<int> v; q.push(rt); while(!q.empty()) { int w=q.front(); q.pop(); v.push_back(w); if(T[w].l!=0) q.push(T[w].l); if(T[w].r!=0) q.push(T[w].r); } int len=v.size(); for(int i=0;i<len;i++) printf("%d%c",v[i],i==len-1?'\n':' '); }
void preT(int rt) { if(rt==0) return; printf(first?first=0,"%d":" %d",rt); preT(T[rt].l); preT(T[rt].r); }
void midT(int rt) { if(rt==0) return; midT(T[rt].l); printf(first?first=0,"%d":" %d",rt); midT(T[rt].r); }
void postT(int rt) { if(rt==0) return; postT(T[rt].l); postT(T[rt].r); printf(first?first=0,"%d":" %d",rt); } int main() { int n; while(~scanf("%d",&n)) { first=1; for(int i=0;i<n;i++) scanf("%d",&po[i]);
for(int i=0;i<n;i++) scanf("%d",&mid[i]); int rt=mid_po_build(0,n-1,0,n-1);
bfs(rt);
} return 0; }
|
简化版(Val As Index,若数据不在1~N内,则可能越界)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
| #include<bits/stdc++.h> #include<cmath> #define mem(a,b) memset(a,b,sizeof a); using namespace std; typedef long long ll; const int maxn=50; int mid[maxn],po[maxn],pr[maxn]; int first; struct node { int l,r; }T[maxn]; int mid_pr_build(int la,int ra,int lb,int rb) { if(la>ra) return 0; int rt=pr[lb]; int p1=la,p2; while(mid[p1]!=rt) p1++; p2=p1-la; T[rt].l=mid_pr_build(la,p1-1,lb+1,lb+p2); T[rt].r=mid_pr_build(p1+1,ra,lb+p2+1,rb); return rt; } int mid_po_build(int la,int ra,int lb,int rb) { if(la>ra) return 0; int rt=po[rb]; int p1=la,p2; while(mid[p1]!=rt) p1++; p2=p1-la; T[rt].l=mid_po_build(la,p1-1,lb,lb+p2-1); T[rt].r=mid_po_build(p1+1,ra,lb+p2,rb-1); return rt; } int getHeight(int rt) { if(rt==0) return 0; return 1+max(getHeight(T[rt].l),getHeight(T[rt].r)); } void bfs(int rt) { queue<int> q; vector<int> v; q.push(rt); while(!q.empty()) { int w=q.front(); q.pop(); v.push_back(w); if(T[w].l!=0) q.push(T[w].l); if(T[w].r!=0) q.push(T[w].r); } int len=v.size(); for(int i=0;i<len;i++) printf("%d%c",v[i],i==len-1?'\n':' '); } void preT(int rt) { if(rt==0) return; printf(first?first=0,"%d":" %d",rt); preT(T[rt].l); preT(T[rt].r); } void midT(int rt) { if(rt==0) return; midT(T[rt].l); printf(first?first=0,"%d":" %d",rt); midT(T[rt].r); } void postT(int rt) { if(rt==0) return; postT(T[rt].l); postT(T[rt].r); printf(first?first=0,"%d":" %d",rt); } int main() { int n; while(~scanf("%d",&n)) { first=1; for(int i=0;i<n;i++) scanf("%d",&po[i]);
for(int i=0;i<n;i++) scanf("%d",&mid[i]); int rt=mid_po_build(0,n-1,0,n-1);
bfs(rt);
} return 0; }
|
简化版(Val Not As Index,可以存任意的 Val)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| #include<bits/stdc++.h> #include<cmath> #define mem(a,b) memset(a,b,sizeof a) #define ssclr(ss) ss.clear(), ss.str("") #define INF 0x3f3f3f3f #define MOD 1000000007 using namespace std; typedef long long ll; const int maxn=5e4+1000; int f; int pre[maxn], in[maxn]; struct node { int l,r,d; }T[maxn]; int create(int l1,int r1,int l2,int r2) { if(l2>r2) return -1; int rt=l2; int p1=l1,p2; while(in[p1]!=pre[rt]) p1++; p2=p1-l1; T[rt].d=pre[rt]; T[rt].l=create(l1,p1-1,l2+1,l2+p2); T[rt].r=create(p1+1,r1,l2+p2+1,r2); return rt; } void postT(int rt) { if(rt==-1 || !f) return; postT(T[rt].l); postT(T[rt].r); if(f) f=0, printf("%d\n",T[rt].d); } int main() { int n; scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&pre[i]); for(int i=0;i<n;i++) scanf("%d",&in[i]); int rt=create(0,n-1,0,n-1); f=1, postT(rt); return 0; }
|