C++ STL

以下是C++ 机试里面最常用的数据结构和函数的操作,包括vector、stack、queue、set(和pair、tuple等组合)、unordered_set、map、unordered_map、 priority_queue 以及自定义sort、string、位操作、进制转换等(可充当常用api字典),没有技巧,全是模板;
vector
构造
 vector<int> v1(5); //创建一个vector,元素个数为5
 vector<int> v2(5, -1); //创建一个vector,元素个数为5,所有元素值-1
 vector<int> v3(v2); // 复制构造函数
 vector<int> v4(v3.begin(), v3.end()); //复制v3[begin,end)区间内的元素到v4中
 
操作
 v1.push_back(1); // 尾插
 cout << v1.size() << endl; // 输出6
 
 /* 插入 */
 v2.insert(v2.begin(), 100); // 第0个位置100,后面都是初始化的-1
 v2.insert(v2.begin() + 1, 5, -100); // 第1个位置开始连插入5个-100
 v2.insert(v2.end(), v1.begin(), v1.end()); // v2的末尾插入v1
 for (auto it : v2) cout << it << ' ';	// 遍历

 /* 删除 */
 v1.erase(v1.begin());
 v1.erase(v1.begin(), v1.end()); 
stack & queue (这两底层也是vector实现的)
就几个操作,一般用到stack或者queue的题都比较明显

栈:

stack<int> s1;

/* 状态 */
cout << s1.size() << endl;
cout << s1.empty() << endl;

/* 操作 */
s1.push(1);
int tmp = s1.top();
s1.pop();

队列:

queue<int> q1;

/* 状态 */
cout << q1.size() << endl;
cout << q1.empty() << endl;

/* 操作 */
q1.push(1);
int tmp = q1.front();
int tmp2 = q1.back(); // 最后一个元素(很少用)
q1.pop();
set & map

set 和 map 两者本身有序, set按照存放的数排序,map按照key排序(默认从小到大),所以插入查找等操作都是logN的;这里需要注意的是,专业级的设计题有点花,set和map经常结合pair/tuple存信息,unordered_map套set套pair这种,但下面总结的肯定够用;

集合:
/* 构造 */
set<int> set1;
set<pair<int, int>> set2;  // 按照 a 排, a 排完按照 b 排(前面是a,后面是b,意会一下)
set<tuple<int, int, int>> set3; // 按照 a 排, a 排完按照 b 排, b 排完按照 c
vector<int> v1;
set<int> set4(v1.begin(), v1.end());	// 偶尔可能需要把给的数据转换方便后续操作


/* 插入 */
set1.insert(1);
set2.insert(make_pair(1, 2));
set3.insert(make_tuple(1, 2, 3));

/* 查找find, 返回的是迭代器 */
set1.find(1) == set1.end() ? false : true;

/* 遍历 */
这里从前往后遍历出来的数 == 从小往大,如果题目要求从大往小,就从后往前遍历:
for(auto it = set1.end(); it != set1.begin(); it--)一样的
for (int it : set1) {
    cout << it << endl;
}

for (const auto &it : set2) {
    cout << it.first << '-' << it.second << endl;
}

for (const auto &it : set3) {
    cout << get<0>(it) << '-' << get<1>(it) << '-' << get<2>(it) << endl;
}

/* 删除 */
set1.erase(1);
set2.erase({1, 2});
set3.erase({2, 3, 2});


映射 map
// map<key, value> key 唯一

map<int, int> map1;
map<int, pair<int, int>> map2;
map<int, tuple<int, int, int>> map3;

/* 插入 */
map1.insert({1, 2});    // 等于map[2] = 3
map2[1] = {2, 3};	// map[key] = value, 显然key相同会自动重叠
map3[1] = {8, 9, 10};

/* 查找 */
ps:不要老想着用value查key,个人认为如果频繁用value查key就失去了map设计的意义;
如果value也是唯一的,可以再堆个map映射value到key,专业级有挺多这样花来花去的题,空间换时间

bool isExist = map1.find(1) == map1.end() ? false : true;
cout << "find:" << map1.find(1)->first << '-' <<  map1.find(1)->second << endl;	
cout << "find:" << map2[1].first << '-' << map2[1].second << endl;

/* 删除 */
map1.erase(1)
map2.erase(1)
map3.erase(1);  // 只需要erase key就行了


/* 遍历 */
for (auto it : map1) {
    cout << it.first << '-' << it.second << endl;
}

for (const auto it : map2) {
    cout << it.first << '-' << it.second.first << ',' << it.second.second << endl;
}

for (const auto &it : map3) {
    cout << it.first << '-' << get<0>(it.second) << ',' << get<1>(it.second) << ',' << get<2>(it.second) << endl;
}

unordered_set & unordered_map
这里不详细写了,和上面的操作语法一样,唯一不一样的是这两内部数据无序,hash实现的,查找和插入是O(1)
题目如果没有要求排序,总是要求查找就用这两

这里推荐一道题: leetcode 1912 这个题得做明白

String

string 的操作很碎,但有用(输出看一看,以免有错)

string str = "abcdefg";
string str_1 = "hijk";

/* 长度、空等 */
cout << str.empty() << endl;
cout << str.size() << endl;
cout << str.length() << endl;

/* 子串 */
cout << str.substr(0, 3) << endl;   // abc

/* 翻转 */
reverse(str.begin(), str.end());    // gfedcba
cout << str << endl;

/* 插入 */
str.insert(str.begin(), '1');   // 1gfedcba
str_1.insert(1, str);   // h1gfedcbaijk

/* 删除 */
cout << str << endl;    // 1gfedcba
str.erase(3, 2); // pos = 3, len = 2 : 1gfcba
str.erase(str.begin() + 2, str.begin() + 3);    // 1gcba

/* 数值转换 int & string */
string str_2 = "123";
int a = stoi(str_2);
str_2 = to_string(a);

/* char 数组 和 string 互相转换 */
char ch1[] = "1234567890";
string str_3(ch1);
string str_4 = ch1;
char buf[2];
str_3.copy(buf, 2); // 拷贝到buf里,考2位

sort

sort库函数下面本质是qsort快排,这里主要列举自定义排序规则的模板
优先队列heap_priority也放在这里,因为本质优先队列底层是堆排序,题目如果出现求topN可以考虑用优先队列,下面也列了优先队列自定义排序规则的模板

排序:sort

/* vector 直接排 */
vector<int> v1 = {21, 2, 23, 1};
sort(v1.begin(), v1.end());  // 小到大 1-2-21-23
sort(v1.begin(), v1.end(), greater<>());  // 大到小 23-21-2-1

/* 自定义结构体排 */

struct node
{
    int num1;
    int num2;

};

/* num1由小到大,num2由大到小,自定义 */
bool cmp_n(node a, node b) {
    if (a.num1 == b.num1) return a.num2 > b.num2;
    else return a.num1 < b.num1;
} 

int num1 = 2, num2 = 3;
vector<node> v2 = {node{1, 2}, node{num1, num2}, node{2, 4}};
sort(v2.begin(), v2.end(), cmp_n);  // {1, 2} {2, 4} {2, 3}


/* unordered_map value sort 极少出现,看看咋操作就行 */
unordered_map<string, int> umap = {
        {"zhangsan", 3},
        {"zhaoliu", 5},
        {"wangwu", 5},
        {"lisi", 4}
};
// 先转vector再排序
vector<pair<string, int>> arr;
for(const auto& it : umap) {
    arr.emplace_back(it);
}
sort(arr.begin(), arr.end(), [](auto p1, auto p2) {return p1.second == p2.second ?
p1.first < p2.first : p1.second < p2.second;});


优先队列

priority_queue<int> heap1; // 最基础,大顶堆
priority_queue<int, vector<int>, less<>> heap2; //   大根(这里vector是指定内部用什么来实现优先队列,这里就是用vector,下同)
priority_queue<int, vector<int>, greater<>> heap3; //    小根

/* 操作 */
heap1.push(2);
heap1.push(3);
heap1.push(0);
while (!heap1.empty()) {
    cout << heap1.top();
    heap1.pop();
} // 3 2 0

/* 自定义优先队列 */

template <typename T>
class cmp_n_2
{
public:
    //重载 () 运算符
    bool operator()(T a, T b)
    {
        return a.num1 < b.num1; // 大根堆
    }
};


priority_queue<node, vector<node>, cmp_n_2<node>> heap4;
heap4.push(node{1, 4});
heap4.push(node{3, 2});
heap4.push(node{2, 2});
while (!heap4.empty()) {
    cout << heap4.top().num1; // num1: 3 2 1
    heap4.pop(); 
}
cout << endl;

/* 优先队列配合 pair */
priority_queue<pair<int, int>> heap5; // first降序 + second降序
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> heap6;    // first升序 + second升序
pair<int, int> a(3, 4);
pair<int, int> b(5, 4);
pair<int, int> c(5, 3);
heap6.push(a);
heap6.push(b);
heap6.push(c);
while (!heap6.empty()) {
    cout << heap6.top().first << '-' << heap6.top().second << endl;
    cout << endl;
    heap6.pop();
}
进制转换

10进制2进制16进制互相转换,这里不用库函数是因为都想用string类型来承接转换结果

/*
 * 任意2-36进制数转化为10进制数, 入参radix:进制
 * */
int AtoInt(const string& s, int radix) {
    int ans = 0;
    for(char t : s)
    {
        if(t >= '0' && t <= '9') ans = ans * radix + t - '0';
        else ans = ans * radix + t -'a' + 10;
    }
    return ans;
}

/*
 * 10进制数转其他进制,注意最后出参是string
 * */
string intToA(int n, int radix)    // n是待转数字,radix是指定的进制
{
    string ans;
    do {
        int t = n % radix;
        if (t >= 0 && t <= 9) ans += t + '0';
        else ans += t - 10 + 'a';
        n /= radix;
    } while (n != 0);	// 以防止输入为0的情况
    reverse(ans.begin(), ans.end());
    return ans;
}

2进制和16进制互转,注意是string类型和string类型
void AToA() {
    /* string to string (16 to 2 & 2 to 16)
     * stoi(字符串,起始位置,string进制)*/
    string bi = "1111111001";
    string hex;
    stringstream ss;
    ss << std::hex << stoi(bi, nullptr, 2);
    ss >> hex;
    cout << hex << endl;
    cout << std::bitset<16>(stoi(hex, nullptr, 16)) << endl;    // 16->10->2
}
位运算
位运算: & | ~ ^ <<(left) >>(right)
位运算非常容易和进制转换配合使用,下面举例:

/* 如果需要固定字节,int,16进制需要转成 unsigned char型 */
/* 16进制转换 */
string str1 = "f0";
string str2 = "00";
unsigned char ch1 = char(AtoInt(str1, 16));	// 用上面自己抄的函数
unsigned char ch2 = char(AtoInt(str2, 16));

uint16_t show1 = ((ch1 << 8) + ch2); // 右移8位再拼接上ch2的8位就是16位,前面得拿16位的来接住
uint16_t show2 = (((ch1 << 8) + ch2) & 0x1FFF); // 多了一个mask前三位
cout << show1 << '-' << show2 << endl;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值