2021-02-20

数据结构(一)

单链表:邻接表

作用是存储图和树
我们用数组模拟链表即静态链表,因为速度快;而C++中的动态链表慢。且只有一个指向后的指针。

我们需要学会初始化,头插法,在某个下标后的数插入一个数,删除某个下标后的数…

例题 单链表

#include <iostream>

using namespace std;

const int N = 100010;
//e[i]节点i的数值  ne[i]指向下一个数的下标  heaad头结点下标   idx处理的数的位置
int e[N],ne[N],idx,head;

//初始化
void init()
{
    head = -1;
    idx = 0;
}
//头插法
void add_to_head(int x)
{
    e[idx] = x;
    ne[idx] = head;
    head  = idx;
    idx ++;
}
//在下标为k的数后添加一个数
void add(int k,int x)
{
    e[idx] = x;
    ne[idx] = ne[k];
    ne[k] = idx;
    idx ++;
}
//删除下标为k的数的后一个数
void remove_(int k)
{
    ne[k]  = ne[ne[k]];
}

int main()
{
    int m;
    cin >> m;
    init();  //先初始化

    while(m--)
    {
        char op;
        int k,x;
        
        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);  //是k-1不是k啦}
            }
        }
        else
        {
            cin >> k >> x;
            add(k-1,x); //下标从0开始>>k-1
        }
    }
    for(int i = head; i != -1; i=ne[i]) cout << e[i] << ' ';
    cout << endl;
    return 0;
}

双链表

优化某些问题
和单链表不同的是他有两个指针,一个指向前,一个指向后
双链表

对第k个节点的操作变成了k+1了
因为一开始有了一个头节点0和尾节点1,所以第k个插入的数就是下标就是k+1;
单链表中 (k - 1)是因为idx从0开始,双链表这里(k + 1)是因为idx从2开始的

#include <iostream>

using namespace std;
const int N = 100010;
int l[N],r[N],e[N],idx;

//初始化,让0为左端点,1为右端点
void init()
{
    l[1] = 0;
    r[0] = 1;
    idx  = 2;
}

//在下标为k的数的右边插入一个数  若是想在左边插入可以和自己将k变成l[k]
void add_r(int a,int x)
{
    e[idx] = x;
    r[idx] = r[a];
    l[idx] = a;
    l[r[a]] = idx;
    r[a] = idx;
    idx ++;
}

void remove_(int a)
{
    l[r[a]] = l[a];
    r[l[a]] = r[a];
}

int main()
{
    int m;
    cin >> m;
    init();

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

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

单调栈

和单调队列一样应用不多,背过即可
题目 单调栈

栈里面只会保留比当前入栈元素小的数字

//yxc
#include <iostream>
using namespace std;
const int N = 100010;
int stk[N], tt;

int main()
{
    int n;
    cin >> n;
    while (n -- )
    {
        int x;
        scanf("%d", &x);
        while (tt && stk[tt] >= x) tt -- ;//如果栈顶元素大于当前待入栈元素,则出栈
        if (!tt) printf("-1 ");//如果栈空,则没有比该元素小的值。
        else printf("%d ", stk[tt]);//栈顶元素就是左侧第一个比它小的元素。
        stk[ ++ tt] = x;
    }
    return 0;
}

单调队列

单调队列

# include <iostream>
using namespace std;
const int N = 1000010;
int a[N], q[N], hh, tt = -1;

int main()
{
    int n, k;
    cin >> n >> k;
    for (int i = 0; i < n; ++ i)
    {
        scanf("%d", &a[i]);
        if (i - k + 1 > q[hh]) ++ hh;                  // 若队首出窗口,hh加1
        while (hh <= tt && a[i] <= a[q[tt]]) -- tt;    // 若队尾不单调,tt减1
        q[++ tt] = i;                                  // 下标加到队尾
        if (i + 1 >= k) printf("%d ", a[q[hh]]);       // 输出结果
    }
    cout << endl;
    hh = 0; tt = -1;                                   // 重置!
    for (int i = 0; i < n; ++ i)
    {
        if (i - k + 1 > q[hh]) ++ hh;
        while (hh <= tt && a[i] >= a[q[tt]]) -- tt;
        q[++ tt] = i;
        if (i + 1 >= k) printf("%d ", a[q[hh]]);
    }
    return 0;
}

KMP QAQ

需要好好理解
KMP字符串

#include <iostream>

using namespace std;

const int N = 100010, M = 1000010;

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

int main()
{
    cin >> n >> p + 1 >> m >> s + 1;

    for (int i = 2, j = 0; i <= n; i ++ )
    {
        while (j && p[i] != p[j + 1]) j = ne[j];
        if (p[i] == p[j + 1]) 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[j + 1]) j ++ ;
        if (j == n)
        {
            printf("%d ", i - n);
            j = ne[j];
        }
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

紫薯C菌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值