ToB企服应用市场:ToB评测及商务社交产业平台

标题: C++算法之旅、05 基础篇 | 第二章 数据结构 [打印本页]

作者: 羊蹓狼    时间: 2023-9-3 23:57
标题: C++算法之旅、05 基础篇 | 第二章 数据结构
常用代码模板2——数据结构 - AcWing
笔试用数组模拟而不是结构体

使用结构体指针,new Node() 非常慢,创建10万个节点就超时了,做笔试题不会用这种方式(优化是提前初始化好数组,但这样跟数组模拟没区别了,而且代码量很长)

单链表(数组)

使用两个数组,e存储val,ne存储next。空节点next用-1表示
826 ⭐

826. 单链表 - AcWing题库
第1个插入的点下标为0,第5个插入点下标为4,第k个插入点下标为k-1;
  1. #include <algorithm>
  2. #include <cstdio>
  3. #include <iostream>
  4. using namespace std;
  5. const int N = 1e5 + 10;
  6. // head指向头结点,e[i]表示节点值,ne[i]表示节点next
  7. // idx指向可用空间(当前可以用的最新点下标)
  8. // 算法题不用考虑浪费的空间
  9. int head, e[N], ne[N], idx;
  10. void init() {
  11.     head = -1;
  12.     idx = 0;
  13. }
  14. // x 插到头结点后面
  15. void add_to_head(int x) {
  16.     e[idx] = x;
  17.     ne[idx] = head;
  18.     head = idx++;
  19. }
  20. // x 插到下标k的点后面
  21. void add(int k, int x) {
  22.     e[idx] = x;
  23.     ne[idx] = ne[k];
  24.     ne[k] = idx++;
  25. }
  26. // 将下标 k 后面点删掉
  27. void remove(int k) {
  28.     // if (ne[k] == -1) return; 题目保证合法不考虑边界情况
  29.     ne[k] = ne[ne[k]];
  30. }
  31. int main() {
  32.     int m;
  33.     cin >> m;
  34.     init();
  35.     while (m--) {
  36.         char c;
  37.         int k, x;
  38.         cin >> c;
  39.         if (c == 'H') {
  40.             cin >> x;
  41.             add_to_head(x);
  42.         } else if (c == 'D') {
  43.             cin >> k;
  44.             if (!k)
  45.                 head = ne[head];  // 特判删除头结点(链表第一个有效元素)
  46.             else
  47.                 remove(k - 1);
  48.         } else if (c == 'I') {
  49.             cin >> k >> x;
  50.             add(k - 1, x);
  51.         }
  52.     }
  53.     for (int i = head; i != -1; i = ne[i]) {
  54.         cout << e[i] << " ";
  55.     }
  56.     return 0;
  57. }
复制代码
837 ⭐⭐

837. 连通块中点的数量 - AcWing题库
保证根节点的nums有意义
  1. #include <algorithm>
  2. #include <cstdio>
  3. #include <iostream>
  4. using namespace std;
  5. const int N = 1e5 + 10;
  6. int e[N], l[N], r[N], idx;
  7. void init() {
  8.     r[0] = 1;
  9.     l[1] = 0;
  10.     idx = 2;
  11. }
  12. // 在下标k点的右边插入x(可以转化成左边)
  13. void add(int k, int x) {
  14.     e[idx] = x;
  15.     r[idx] = r[k];
  16.     l[idx] = k;
  17.     r[k] = idx;
  18.     l[r[idx]] = idx;
  19.     idx++;
  20. }
  21. // 删除下标k的点
  22. void remove(int k) {
  23.     l[r[k]] = l[k];
  24.     r[l[k]] = r[k];
  25. }
  26. int main() {
  27.     int m;
  28.     cin >> m;
  29.     init();
  30.     while (m--) {
  31.         string s;
  32.         int k, x;
  33.         cin >> s;
  34.         if (s == "L") {
  35.             cin >> x;
  36.             add(0, x);
  37.         } else if (s == "R") {
  38.             cin >> x;
  39.             add(l[1], x);
  40.         } else if (s == "D") {
  41.             cin >> k;
  42.             remove(k - 1 + 2);
  43.         } else if (s == "IL") {
  44.             cin >> k >> x;
  45.             add(l[k - 1 + 2], x);
  46.         } else if (s == "IR") {
  47.             cin >> k >> x;
  48.             add(k - 1 + 2, x);
  49.         }
  50.     }
  51.     for (int i = r[0]; i != 1; i = r[i]) {
  52.         cout << e[i] << " ";
  53.     }
  54.     return 0;
  55. }
复制代码
哈希表

情景
存储结构-解决冲突的方式 ⭐
算法题99%一般只有添加、查找,若要实现删除不会真删掉,开一个bool数组标记删除

字符串哈希-字符串前缀哈希法(特殊)
应用:可以快速判断一个字符串某两段是否相同。KMP望而却步(KMP擅长循环节),极困难题可用这种方法
⭐ 我们可以利用前缀哈希算出任意子段的哈希值


与整数离散化的区别
整数离散化需要保序,而且不会发生冲突,每一个元素都有唯一确定的位置(1 ~ n)
840 ⭐拉链法

840. 模拟散列表 - AcWing题库
h 数组维护 N 条链,空节点表示-1,e 数组与 ne 数组维护链上的每一个节点,idx为每个节点分配唯一标识符;插入操作从链表头结点插入
  1. #include <algorithm>
  2. #include <cstdio>
  3. #include <iostream>
  4. using namespace std;
  5. const int N = 1e5 + 10;
  6. int stk[N], tt;
  7. int main() {
  8.     int m;
  9.     cin >> m;
  10.     while (m--) {
  11.         string s;
  12.         int x;
  13.         cin >> s;
  14.         if (s == "push") {
  15.             cin >> x;
  16.             stk[++tt] = x;
  17.         } else if (s == "pop") {
  18.             tt--;
  19.         } else if (s == "empty") {
  20.             if (tt > 0)
  21.                 puts("NO");
  22.             else
  23.                 puts("YES");
  24.         } else if (s == "query") {
  25.             cout << stk[tt] << endl;
  26.         }
  27.     }
  28.     return 0;
  29. }
复制代码
840 ⭐开放寻址法
  1. #include <algorithm>
  2. #include <cstdio>
  3. #include <iostream>
  4. #include <unordered_map>
  5. using namespace std;
  6. const int N = 1e5 + 10;
  7. int op[N], num[N], opt = -1, numt = -1;
  8. unordered_map<char, int> priority;
  9. // 计算后缀表达式
  10. void eval() {
  11.     auto b = num[numt--];
  12.     auto a = num[numt--];
  13.     auto c = op[opt--];
  14.     int res;
  15.     if (c == '-')
  16.         res = a - b;
  17.     else if (c == '+')
  18.         res = a + b;
  19.     else if (c == '*')
  20.         res = a * b;
  21.     else if (c == '/')
  22.         res = a / b;
  23.     num[++numt] = res;
  24. }
  25. int main() {
  26.     priority = {{'-', 1}, {'+', 1}, {'*', 2}, {'/', 2}};
  27.     string str;
  28.     cin >> str;
  29.     for (int i = 0; i < str.size(); i++) {
  30.         if (isdigit(str[i])) {
  31.             int j = i, res = 0;
  32.             while (isdigit(str[j])) res = res * 10 + str[j++] - '0';
  33.             num[++numt] = res;
  34.             i = j - 1;
  35.         } else if (str[i] == '(')
  36.             op[++opt] = str[i];
  37.         else if (str[i] == ')') {
  38.             while (op[opt] != '(') eval();
  39.             opt--;
  40.         } else {
  41.             while (opt >= 0 && priority[str[i]] <= priority[op[opt]]) eval();
  42.             op[++opt] = str[i];
  43.         }
  44.     }
  45.     while (opt >= 0) eval();
  46.     cout << num[numt];
  47.     return 0;
  48. }
复制代码
841 ⭐⭐ 字符串哈希

841. 字符串哈希 - AcWing题库
如下的朴素算法会超时
  1. #include <algorithm>
  2. #include <cstdio>
  3. #include <iostream>
  4. #include <stack>
  5. #include <unordered_map>
  6. using namespace std;
  7. stack<int> num;
  8. stack<char> op;
  9. void eval() {
  10.     auto b = num.top();
  11.     num.pop();
  12.     auto a = num.top();
  13.     num.pop();
  14.     auto c = op.top();
  15.     op.pop();
  16.     int x;
  17.     if (c == '+')
  18.         x = a + b;
  19.     else if (c == '-')
  20.         x = a - b;
  21.     else if (c == '*')
  22.         x = a * b;
  23.     else
  24.         x = a / b;
  25.     num.push(x);
  26. }
  27. int main() {
  28.     unordered_map<char, int> pr{{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};
  29.     string str;
  30.     cin >> str;
  31.     for (int i = 0; i < str.size(); i++) {
  32.         auto c = str[i];
  33.         if (isdigit(c)) {
  34.             // 第一类双指针
  35.             int x = 0, j = i;
  36.             while (j < str.size() && isdigit(str[j]))
  37.                 x = x * 10 + str[j++] - '0';
  38.             i = j - 1;  // 考虑i++
  39.             num.push(x);
  40.         } else if (c == '(')
  41.             op.push(c);
  42.         else if (c == ')') {
  43.             while (op.top() != '(') eval();
  44.             op.pop();
  45.         } else {
  46.             while (op.size() && pr[op.top()] >= pr[c]) eval();
  47.             op.push(c);
  48.         }
  49.     }
  50.     while (op.size()) eval();
  51.     cout << num.top() << endl;
  52.     return 0;
  53. }
复制代码
p 数组提前存储预处理的 p 次方的值,减少计算量
  1. #include <algorithm>
  2. #include <cstdio>
  3. #include <iostream>
  4. using namespace std;
  5. const int N = 1e5 + 10;
  6. int que[N], st = -1, ed = -1;
  7. int main() {
  8.     int m;
  9.     cin >> m;
  10.     while (m--) {
  11.         string str;
  12.         int x;
  13.         cin >> str;
  14.         if (str == "push") {
  15.             cin >> x;
  16.             que[++ed] = x;
  17.         } else if (str == "pop") {
  18.             st++;
  19.         } else if (str == "empty") {
  20.             if (st == ed)
  21.                 puts("YES");
  22.             else
  23.                 puts("NO");
  24.         } else if (str == "query") {
  25.             cout << que[st + 1] << endl;
  26.         }
  27.     }
  28.     return 0;
  29. }
复制代码
STL

size()、empty() 所有容器都有,时间复杂度 \(O(1)\)
clear() 并不是所有容器都有,队列、优先队列、栈;范围遍历可以遍历所有容器
系统为某一个程序分配空间时,所需的时间与空间大小无关,与申请次数有关

vector

变长数组,倍增,支持比较运算(字典序(4个3小于3个4))。有erase但用得不多
插入操作\(O(1)\):插入1e6次,申请空间的次数 \(log_21e6\) ,拷贝的次数均摊是 1 (数组大小从1到1e6,总共拷贝次数是1e6(1+2+4+8+...))
[code]#include #include using namespace std;int main() {    // ^ 定义一个长度为10的vector,每个数都是3    vector a(10, 3);    vector b[10];    a.push_back(1);    cout




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4