【AcWing】 数据结构 听课笔记

本文深入探讨了数据结构如链表、栈、队列、树和图的存储方式,以及算法如KMP、Trie、并查集、堆、Hash表的应用技巧。通过具体实例介绍了数组模拟这些数据结构的方法。


链表与邻接表: 树与图的存储

数组模拟单链表

链表中的每一个结点只有两个部分。我们可以用一个数组data来存储序列中的每一个数。那么每一个数的右边我们就需要再用一个数组right来存放序列中每一个数。
在这里插入图片描述

现在需要在8前面插入一个6,只需要将6直接存放在数组data的末尾data[10] = 6。接下来只需要将right[3]改为10,表示新序列中3号元素右边的元素存放在data[10]中。再将right[10]改为4,表示新序列中10号元素右边的元素存放在data[4]中。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

#include<iostream>

using namespace std;

const int N = 100010;

int head, e[N], ne[N], idx;

void init()
{
   
   
    head = -1;
    idx = 0;
}

void add_to_head(int x)
{
   
   
    e[idx] = x, ne[idx] = head, head = idx ++ ;
}

void add(int k, int x)
{
   
   
    e[idx] = x, ne[idx] = ne[k], ne[k] = idx ++;
}

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];
            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;
}

10
H 9
I 1 1
D 1
D 0
H 6
I 3 6
I 4 5
I 4 5
I 3 4
D 6

// 6 4 6 5

数组模拟单链表

const int N  = 100010;
int head,e[N],ne[N],idx;//所有idx表示的是节点的下标,也就是索引,然后当前idx的值表示下一个插入的节点的索引是多少,或者说当前插入新的节点用到的下标是多少,e[N]表示
void init(){
   
   
	head = -1;//用-1来表示null
	idx = 0;//下标也可以从1开始,无所谓
}
//头插法 ,在head后面插入一个节点值为x的节点 
void add_to_head(int x){
   
   
	e[idx] = x;
	ne[idx] = head;
	head = idx ++; 
}
//在索引是k的下一个位置插入x ,如果知道第k的元素的索引 那么后面那个元素删除和插入操作复杂度都是O(1) 
void add_after_k(int k,int x){
   
   
	e[idx] = x;
	ne[idx] = ne[k];
	ne[k] = idx ++;
}
//删除在索引是k的下一个节点 
void remove_after_k(int k){
   
   
	ne[k] = ne[ne[k]];
}

//遍历一个单链表.固定模板
for(int i = head;i != -1;i = ne[i]) {
   
   
    cout << e[i] << " ";
}

数组模拟双链表

const int N= 100010;
int m;
int e[N],l[N],r[N],idx;
//双链表的的插入应该先把新节点的左右指向先赋值好,然后其他操作都用新界点的左右指向来操作,这样就会方便
//应该这样不会考虑原来的指向指针丢失的问题
void init(){
   
   //链表为空的初始化状态,head和tail可以用0 1来代表,所以idx 应该从2开始
	r[0] = 1,l[1] = 0;
	idx = 2;
}
//在第k个元素的右边插入一个新元素,若想在k的左边插入元素直接调用add(l[k],x)就可以,或者重新实现一编逻辑 
void addR(int k,int x){
   
   
	e[idx] = x;
	l[idx] = k;
	r[idx] = r[k];
	l[r[idx]] = idx;
	r[k] = idx ++;
}

void addL(int k,int x) {
   
   
    e[idx] = x;
    r[idx]= k;
    l[idx] = l[k];
    l[k] = idx;
    r[l[idx]] = idx ++;
}


//删除双链表中的第k个元素 
void remove_k(int k){
   
   
	r[l[k]] = r[k];
	l[r[k]] = l[k]; 
}
void add_to_begin(int x){
   
   
	e[idx] = x;
	r[idx] = r[0];
	l[idx] = 0;
	r[0] = idx;
	l[r[idx]] = idx ++;
} 

void add_to_last(int x) {
   
   
	e[idx] = x;
	l[idx] = l[1];
	r[idx] = 1;
	r[l[idx]] = idx;
	l[1] = idx ++;
}

数组模拟邻接表

const int N = 100010,M = 100010;//N 为最大节点数,M 为最大边数
int h[N],e[M],ne[M],w[M],idx;//


//加边操作模板
void add(int a,int b,int c){
   
   //加入一条从a----->b,而且权值为c,将其看作单链表的操作会更好理解
    e[idx] = b;
    ne[idx] = h[a];
    w[idx] = c;
    h[a] = idx ++;
}

数组模拟栈

const int N =  100010;
int stk[N],tt;//tt表示栈顶元素的索引,为0的时候表示没有元素
void push(int x){
   
   
    stk[++ tt] = x;    
}

//delete
void pop(){
   
   
    tt --;//删除元素直接指针下移就行
}
int top(){
   
   
    return stk[tt];
}
//判空
bool 
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值