数据结构(c++实现)

news2024/10/6 8:28:05

数据结构

目录

  • 数据结构
      • 1.链表实现
        • 单链表
        • 双链表
      • 2.栈(先进后出,后进先出)
      • 3.单调栈
      • 4.队列(先进先出)
      • 5.单调队列
      • 6.小根堆
        • 操作
      • 7.KMP
      • 8.Trie树(字典树)

1.链表实现

单链表

#include <iostream>
 
using namespace std;
 
const int N = 100010;
 
 
// head 表示头结点的下标
// e[i] 表示节点i的值
// ne[i] 表示节点i的next指针是多少
// idx 存储当前已经用到了哪个点
int head, e[N], ne[N], idx;
 
// 初始化
void init()
{
    head = -1;
    idx = 0;
}
 
// 将x插到头结点
void add_to_head(int x)
{
    e[idx] = x, ne[idx] = head, head = idx ++ ;
}
 
// 将x插到下标是k的点后面
void add(int k, int x)
{
    e[idx] = x, ne[idx] = ne[k], ne[k] = idx ++ ;
}
 
// 将下标是k的点后面的点删掉
void remove(int k)
{
    ne[k] = ne[ne[k]];
}
 
int main()
{
    int m;
    cin >> m;
 
    init();
 
    while (m -- )
    {
        int k, x;
        char op;
 
        cin >> op;
        if (op == 'H')
        {
            cin >> x;
            add_to_head(x);
        }
        else if (op == 'D')
        {
            cin >> k;
            if (!k) head = ne[head];
            else remove(k - 1);
        }
        else
        {
            cin >> k >> x;
            add(k - 1, x);
        }
    }
 
    for (int i = head; i != -1; i = ne[i]) cout << e[i] << ' ';
    cout << endl;
 
    return 0;
}

双链表

#include <iostream>

using namespace std;

const int N = 100010;

int m;
int e[N], l[N], r[N], idx;

// 在节点a的右边插入一个数x
void insert(int a, int x)
{
    e[idx] = x;
    l[idx] = a, r[idx] = r[a];
    l[r[a]] = idx, r[a] = idx ++ ;
}

// 删除节点a
void remove(int a)
{
    l[r[a]] = l[a];
    r[l[a]] = r[a];
}

int main()
{
    cin >> m;

    // 0是左端点,1是右端点
    r[0] = 1, l[1] = 0;
    idx = 2;

    while (m -- )
    {
        string op;
        cin >> op;
        int k, x;
        if (op == "L")
        {
            cin >> x;
            insert(0, x);
        }
        else if (op == "R")
        {
            cin >> x;
            insert(l[1], x);
        }
        else if (op == "D")
        {
            cin >> k;
            remove(k + 1);
        }
        else if (op == "IL")
        {
            cin >> k >> x;
            insert(l[k + 1], x);
        }
        else
        {
            cin >> k >> x;
            insert(k + 1, x);
        }
    }

    for (int i = r[0]; i != 1; i = r[i]) cout << e[i] << ' ';
    cout << endl;

    return 0;
}


2.栈(先进后出,后进先出)

数组模拟栈:

用top表示栈顶所在的索引。初始时,top = -1。表示没有元素。

push x :栈顶所在索引往后移动一格,然后放入x。st[++top] = x。

pop : top 往前移动一格。top–。

empty :top 大于等于 0 栈非空,小于 0 栈空。top == -1 ? “YES” : “NO”

query : 返回栈顶元素。st[top]

#include <iostream>

using namespace std;

const int N = 100010;

int m;
int stk[N], tt;

int main()
{
    cin >> m;
    while (m -- )
    {
        string op;
        int x;

        cin >> op;
        if (op == "push")
        {
            cin >> x;
            stk[ ++ tt] = x;
        }
        else if (op == "pop") tt -- ;
        else if (op == "empty") cout << (tt ? "NO" : "YES") << endl;
        else cout << stk[tt] << endl;
    }

    return 0;
}

// stl版本
#include <iostream>
#include <stack>
using namespace std;
stack<int> stk;
int main() {
    int n;
    cin >> n;
    while (n--) {
        string s;
        cin >> s;
        int x;
        if (s == "push") {
            cin >> x;
            stk.push(x);
        }
        else if (s == "pop") {
            stk.pop();
        }
        else if (s == "query")
            cout << stk.top() << endl;
        else
            cout << ((stk.empty()) ? "YES": "NO") << endl;

    }
    return 0;
}

3.单调栈

  • 常见模型: 找出每个数左边(右边)离他最近的比他大/小的数
int tt = 0;
for (int i = 1; i <= n; ++i) {
    while (tt && check(q[tt], i)) tt --;
    stk[++ tt] = i
}

**实例:**给定一个长度为 N的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1。

#include <iostream>
#include <cstdio>

using namespace std;

const int N = 1e5 + 10;

int stk[N], tt;

int main() {
   
    int n;
    scanf("%d", &n);
    while (n--) {
        int x;
        cin >> x;
        while (tt && stk[tt] >= x)   tt --;
        if (!tt)     printf("-1 ");
        else    printf("%d ", stk[tt]);
        stk[++tt] = x;
    }

    return 0;
}

4.队列(先进先出)

用一个数组 q 保存数据。

用 hh 代表队头,q[hh] 就是队头元素, q[hh + 1] 就是第二个元素。

用 tt 代表队尾, q[tt] 就是队尾元素, q[tt + 1] 就是下一次入队,元素应该放的位置。

[hh, tt] 左闭右闭,代表队列中元素所在的区间。

出队pop:因为 hh 代表队头,[hh, tt] 代表元素所在区间。所以出队可以用 hh++实现,hh++后,区间变为[hh + 1, tt]。

入队push:因为 tt 代表队尾,[hh, tt] 代表元素所在区间。所以入出队可以用 tt++实现,tt++后,区间变为[hh, tt + 1], 然后在q[tt+1]位置放入入队元素。

是否为空empty:[hh, tt] 代表元素所在区间,当区间非空的时候,对列非空。也就是tt >= hh的时候,对列非空。

询问队头query:用 hh 代表队头,q[hh] 就是队头元素,返回 q[hh] 即可。

#include <iostream>

using namespace std;

const int N = 1e5 + 10;

int q[N];
int hh, tt = -1;

int main() {
    int n;
    cin >> n;
    while (n--) {
        string s;
        cin >> s;
        int x;
        if (s == "push") {
            cin >> x;
            q[++tt] = x;
        }
        else if (s == "empty") 
            cout << (hh <= tt? "NO": "YES") << endl;
        else if (s == "query")
            cout << q[hh] << endl;
        else    ++hh;
    }

    return 0;
}
// STL版本
#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#define ll long long
#define PII pair<int, int>

using namespace std;
queue<int> q;

int main()
{
    int n;
    cin >> n;
    while (n--) {
        int x; string s;
        cin >> s;
        if (s == "push") 
        {
            cin >> x;
            q.push(x);
        }
        else if (s == "pop") {
            q.pop();
        }
        else if (s == "empty") {
            cout << (q.empty()? "YES": "NO") << endl;
        }
        else {
            cout << q.front() << endl;
        }
    }
    return 0;
}

5.单调队列

滑动窗口

给定一个大小为 n ≤ 1 0 6 n≤10^6 n106 的数组。

有一个大小为 k 的滑动窗口,它从数组的最左边移动到最右边。

你只能在窗口中看到 k 个数字。

每次滑动窗口向右移动一个位置。

只要后一个进队的比前面的小,前面的将永无出头之日

#include <iostream>
#include <cstdio>
#include <deque>

using namespace std;

const int N = 1e6 + 10;
int q[N], a[N];
int hh, tt = -1;

int main() {
    int n, k;
    scanf("%d%d", &n, &k);
    for (int i = 0; i < n; ++i)     scanf("%d", &a[i]);
    for (int i = 0; i < n; ++i) {
        while (hh <= tt && i - k + 1 > q[hh])   hh ++;
        while (hh <= tt && a[q[tt]] >= a[i])     tt --;
        q[++ tt] = i;
        if (i >= k - 1) printf("%d ", a[q[hh]]); 
    }
    printf("\n");
    hh = 0, tt = -1;
    for (int i = 0; i < n; ++i) {
        while (hh <= tt && i - k + 1 > q[hh])   hh ++;
        while (hh <= tt && a[q[tt]] <= a[i])     tt --;
        q[++ tt] = i;
        if (i >= k - 1) printf("%d ", a[q[hh]]); 
    }

    return 0;
}
// stl版本
#include <iostream>
#include <cstdio>
#include <deque>

using namespace std;

const int N = 1e6 + 10;
int q[N], a[N];
int hh, tt = -1;

int main() {
    int n, k;
    scanf("%d%d", &n, &k);
    for (int i = 0; i < n; ++i)     scanf("%d", &a[i]);
    deque<int> dq;
    for (int i = 0; i < n; ++i) {
        // 判断队头是否划出窗口
        while (!dq.empty() && i - k + 1 > dq.front())   dq.pop_front();
        while (!dq.empty() && a[dq.back()] >= a[i])     dq.pop_back();
        dq.push_back(i);
        if (i >= k - 1)     printf("%d ", a[dq.front()]);
    }
    printf("\n");
    dq.clear();
    for (int i = 0; i < n; ++i) {
        // 判断队头是否划出窗口
        while (!dq.empty() && i - k + 1 > dq.front())   dq.pop_front();
        while (!dq.empty() && a[dq.back()] <= a[i])     dq.pop_back();
        dq.push_back(i);
        if (i >= k - 1)     printf("%d ", a[dq.front()]);
    }

    return 0;
}

6.小根堆

优先队列–大根堆

完全二叉树, 每个父节点都小于两个子节点。

存储:x的做儿子2x,有儿子2x+1(下标从1 开始)

**down操作:**把某个数变大,将其往下移

void down(int u) {
    int t = u;
    if (2 * u <= size && h[u] < h[2 * u])    t = 2 * u;
    if (2 * u + 1 <= size && h[u] < h[2 * u + 1])        t = 2 * u + 1;
    if (u != t) {
        swap(h[u], h[t]);
        down(t);
    }
}
void up(int u) {
	while (u / 2 && h[u/2] > h[u]) {
        swap(h[u], h[u/2]);
        u
    }
}

操作

  • 插入一个数
heap[++size] = x;
up(size);
  • 求集合最小值
heap[1]
  • 删除最小值
    • 把最后元素移到堆顶 size--
    • down
heap[1] = heap[size];
size--;
down(1);
  • 删除任意一个元素
heap[k] = heap[size];
size --;
down(k);
up(k);
  • 修改任意一个元素
heap[k] = x;
down(k);
up(k);

维护一个集合,初始时集合为空,支持如下几种操作:

  1. I x,插入一个数 x;
  2. PM,输出当前集合中的最小值;
  3. DM,删除当前集合中的最小值(数据保证此时的最小值唯一);
  4. D k,删除第 k 个插入的数;
  5. C k x,修改第 k 个插入的数,将其变为 x;

现在要进行 N� 次操作,对于所有第 22 个操作,输出当前集合的最小值。

#include <iostream>
#include <algorithm>
#include <string.h>

using namespace std;

const int N = 100010;

int h[N], ph[N], hp[N], cnt;

void heap_swap(int a, int b)
{
    swap(ph[hp[a]],ph[hp[b]]);
    swap(hp[a], hp[b]);
    swap(h[a], h[b]);
}

void down(int u)
{
    int t = u;
    if (u * 2 <= cnt && h[u * 2] < h[t]) t = u * 2;
    if (u * 2 + 1 <= cnt && h[u * 2 + 1] < h[t]) t = u * 2 + 1;
    if (u != t)
    {
        heap_swap(u, t);
        down(t);
    }
}

void up(int u)
{
    while (u / 2 && h[u] < h[u / 2])
    {
        heap_swap(u, u / 2);
        u >>= 1;
    }
}

int main()
{
    int n, m = 0;
    scanf("%d", &n);
    while (n -- )
    {
        char op[5];
        int k, x;
        scanf("%s", op);
        if (!strcmp(op, "I"))
        {
            scanf("%d", &x);
            cnt ++ ;
            m ++ ;
            ph[m] = cnt, hp[cnt] = m;
            h[cnt] = x;
            up(cnt);
        }
        else if (!strcmp(op, "PM")) printf("%d\n", h[1]);
        else if (!strcmp(op, "DM"))
        {
            heap_swap(1, cnt);
            cnt -- ;
            down(1);
        }
        else if (!strcmp(op, "D"))
        {
            scanf("%d", &k);
            k = ph[k];
            heap_swap(k, cnt);
            cnt -- ;
            up(k);
            down(k);
        }
        else
        {
            scanf("%d%d", &k, &x);
            k = ph[k];
            h[k] = x;
            up(k);
            down(k);
        }
    }

    return 0;
}

7.KMP

next数组的值是代表着字符串(模式串)的前缀与后缀相同的最大长度,(不能包括自身)

给定一个字符串 S,以及一个模式串 P,所有字符串中只包含大小写英文字母以及阿拉伯数字。

模式串 P 在字符串 S中多次作为子串出现。

求出模式串 P 在字符串 S 中所有出现的位置的起始下标。

#include <iostream>

using namespace std;

const int N = 1e5 + 10, M = 1e6 + 10;

int ne[N];
char p[N], s[M];

int main() {
    int n, m;
    cin >> n >> p + 1 >> m >> s + 1;
    
    // next数组
    for (int i = 2, j = 0; i <= n; i ++) 
    {
        while (j && p[i] != p[j + 1])       j = ne[j];
        if (p[i] == p[1 + j])    j ++;
        ne[i] = j;
    }
    
    for (int i = 1, j = 0; i <= m; i ++) 
    {
        while (j && s[i] != p[j + 1])       j = ne[j];
        if (s[i] == p[1 + j])   j ++;
        if (j == n)     cout << i - n << ' ';
    }
    
    return 0;
}

8.Trie树(字典树)

在这里插入图片描述

维护一个字符串集合,支持两种操作:

  1. I x 向集合中插入一个字符串 x;
  2. Q x 询问一个字符串在集合中出现了多少次。

共有 N 个操作,所有输入的字符串总长度不超过 105105,字符串仅包含小写英文字母。

#include <iostream>

using namespace std;

const int N = 1e5 + 10;

int son[N][26], cnt[N], idx;

void insert(char str[]) {
   
    int p = 0;
    for (int i = 0; str[i]; ++i) {
        int u = str[i] - 'a';
        if (!son[p][u])     son[p][u] = ++ idx;
        p = son[p][u];

    }
    cnt[p]++;
}

int query(char str[]) {
    
    int p = 0;
    for (int i = 0; str[i]; ++i) {
        int u = str[i] - 'a';
        if (!son[p][u])     return 0;
        p = son[p][u];
    }
    return cnt[p];
}

int main() {
    int n;
    cin >> n;
    while (n--) {
        char c;
        char s[N];
        cin >> c >> s;
        if (c == 'I')
            insert(s);
        else 
            cout  << query(s) << endl;

    }

    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/791730.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AcWing 3708. 求矩阵的鞍点

输入样例&#xff1a; 3 4 1 2 3 4 1 2 3 4 1 2 3 4输出样例&#xff1a; 1 4 4 2 4 4 3 4 4 #include<bits/stdc.h> using namespace std; const int N1010; int n,m,a[N][N],x[N],y[N],flag1; int main(){scanf("%d%d",&n,&m);for(int i1;i<n;i…

抖音西瓜实时作品监控,一秒更新提醒

抖音西瓜实时作品监控&#xff0c;一秒更新提醒 安装必要的依赖库&#xff1a;使用pip安装aweme库。 pip install aweme 导入所需的库。 import datetime import time import schedule from aweme import API 创建一个函数&#xff0c;用于检查抖音作品是否更新。 def check_u…

端到端的视频编码方法及码率控制算法

文章目录 基于卷积神经网络的的端到端的视频编码方法自编码器 基于端到端学习的图像编码研究及进展变换量化熵编码 面向视频会议场景的 H.266/VVC 码率控制算法研究基于强化学习的视频码率自适应决策研究自适应流媒体传输技术码率自适应算法研究现状强化学习深度强化学习算法介…

mp4视频太大怎么压缩?教你轻松减小视频大小

MP4视频太大怎么办&#xff1f;很多人都会遇到这样的问题&#xff0c;MP4视频往因为画面清晰度高&#xff0c;画面流畅&#xff0c;所以视频文件会比较大&#xff0c;如果你想向朋友或者家人分享这个视频&#xff0c;但是又因为文件太大无法发送&#xff0c;那么怎么办呢&#…

可视化开发工具:让软件应用开发变得更轻松

一、前言 你是否为编程世界的各种挑战感到头痛&#xff1f;想要以更高效、简单的方式开发出专业级的项目&#xff1f; JNPF低代码工具正是你苦心寻找的产品&#xff01;它是一款专为稍微懂一点点编程思想的入门级人员设计的神奇工具&#xff0c;集成了丰富的功能和组件&#xf…

使用 CSS 自定义属性

我们常见的网站日夜间模式的变化&#xff0c;其实用到了 css 自定义属性。 CSS 自定义属性&#xff08;也称为 CSS 变量&#xff09;是一种在 CSS 中预定义和使用的变量。它们提供了一种简洁和灵活的方式来通过多个 CSS 规则共享相同的值&#xff0c;使得样式更易于维护和修改。…

深度剖析APP开发中的UI/UX设计

作为一个 UI/UX设计师&#xff0c;除了要关注 UI/UX设计之外&#xff0c;还要掌握移动开发知识&#xff0c;同时在日常工作中也需要对用户体验有一定的认知&#xff0c;在本次分享中&#xff0c;笔者就针对自己在工作中积累的一些经验来进行一个总结&#xff0c;希望能够帮助到…

暑假学生使用什么牌子台灯好?分享五款学生使用的台灯

临近暑假&#xff0c;是不是开始补课或写暑假作业了呢&#xff1f;是不是还在为选一款学生使用的台灯而发愁&#xff1f;今天小编就来给大家推荐几款台灯供大家参考参考。 那么问题来了&#xff0c;怎么选择合适的护眼台灯&#xff1f; 第一&#xff1a;先考虑个人预算选择适…

Modbus RTU通信应用

一、功能概述 1.1 概述 Modbus串行通信协议是Modicon公司在1970年开发的。 Modbus串行通信协议有Modbus ASCII和Modbus RTU两种模式&#xff0c;Modbus RTU协议通信效率较高&#xff0c;应用更加广泛。 Modbus RTU协议是基于RS232和RS485串行通信的一种协议&#xff0c;数据通…

论文解读|用于从RGB-D数据进行3D物体检测的Frustum PointNets

原创 | 文 BFT机器人 01 摘要 论文研究了室内和室外场景中基于RGBD数据的3D目标检测。论文的方法不仅仅依赖于3D方案&#xff0c;而是利用成熟的2D对象检测器和先进的3D深度学习进行对象定位&#xff0c;即使是小对象也能实现高效率和高召回。 直接在原始点云中学习&#xff0…

如何让GPT自己命令自己?榨干最后一丝智能,解放双手!

1.让GPT先别说话 2.接下来&#xff0c;看看它学的怎么样 使用成功了&#xff01;效果拔群&#xff01; 3.接下来&#xff0c;让他回答自己生成的指令&#xff1a; 效果比想象的还要好&#xff01;果然最懂GPT的还是它自己&#xff0c;生成的prompt比自己手写的prompt更加精准有…

rocketmq客户端本地日志文件过大调整配置(导致pod缓存cache过高)

现象 在使用rocketmq时&#xff0c;发现本地项目中文件越来越大&#xff0c;查找发现在/home/root/logs/rocketmqlog目录下存在大量rocketmq_client.log日志文件。 配置调整 开启slf4j日志模式&#xff0c;在项目启动项中增加-Drocketmq.client.logUseSlf4jtrue因为配置使用的…

Bug管理规范

目录 1.目的 2.角色和职责 3.缺陷等级定义 4.缺陷提交原则 5.缺陷流转流程 5.1创建缺陷 5.2缺陷分拣/分配 5.3研发认领缺陷 5.4.研发解决缺陷 5.5关闭缺陷 5.6缺陷激活 1.目的 项目过程中对缺陷管理的规则&#xff0c;明确提单规范、用例优先级的选择规则、走单流程、…

为Android构建现代应用——应用架构

选择风格(Choosing a style) 我们将依照Google在《应用架构指南》中推荐的最佳实践和架构指南来构建OrderNow的架构。 这些定义包括通过各层定义组件的一些Clean Architecture原则。 层次的定义(Definition of the layers) 在应用程序中&#xff0c;我们将定义以下主要层次…

【C++ 进阶】继承

一.继承的定义格式 基类又叫父类&#xff0c;派生类又叫子类&#xff1b; 二.继承方式 继承方式分为三种&#xff1a; 1.public继承 2.protected继承 3.private继承 基类成员与继承方式的关系共有9种&#xff0c;见下表&#xff1a; 虽然说是有9种&#xff0c;但其实最常用的还…

【教学类-34-07】20230726拼图(“菱形”凹凸拼图)3*4格子(中班主题《个别化拼图》偏美术)

作品展示&#xff1a; 背景需求 我尝试将拼图的“圆形凹凸角”变成"正方形凹凸角”&#xff0c;没有成功&#xff0c;但做出了“菱形凹凸角”。 实用性思考&#xff1a; 1、这种菱形凹凸角与正方形结构近似&#xff0c;裁剪难度中等&#xff08;比圆角容易剪&#xff0…

Android Studio Giraffe 发布,快来看有什么更新吧

又双叒叕到了「激动人心」 的 Android Studio 更新&#xff0c;这次更新的版本是 Giraffe | 2022.3.1&#xff0c;本次更新的 Giraffe&#xff08;长颈鹿&#xff09;将 IntelliJ 平台升级到 2022.3 版本&#xff0c;也将 AGP 支持提高到 8.1 &#xff0c;虽然最低支持 3.2&…

LED智能照明在商业照明中的应用都有哪些?SLM421A数明深力科带你一起去了解

数明深力科SLM421A系列产品是用于两通道、高精度恒流源的LED线性驱动芯片。无需功率电感&#xff0c;无频闪、无EMC困扰&#xff0c;支持高频率PWM调色调光&#xff0c;在LED智能照明产品运用中周边线路简单&#xff0c;成本低。 SLM421每路驱动仅需要从SET到GND接一个电阻即可…

fpga_pwm呼吸灯(EP4CE6F17C8)

文章目录 一、呼吸灯二、代码实现三、引脚分配 一、呼吸灯 呼吸灯是指灯光在微电脑的控制之下完成由亮到暗的逐渐变化&#xff0c;使用开发板上的四个led灯实现1s间隔的呼吸灯。 二、代码实现 c module pwm_led( input clk ,input rst_n ,output reg [3:0] led ); …

从安装到实战!Citespace保姆级教程!

来源&#xff1a;浙师教育研会 软件介绍 Citespace是一款文献梳理软件 支持从主要来源&#xff08;如Web of Science&#xff0c;Scopus&#xff0c;Dimensions&#xff0c;CNKI&#xff0c;CSSCI和其他一些来源&#xff09;检索的书目和引文数据。能够把文件之间的关系&…