基础数据结构

数据结构板子

1.单链表


单链表

模板:

// head存储链表头,e[]存储节点的值,ne[]存储节点的next指针,idx表示当前用到了哪个节点
int head, e[N], ne[N], idx;

// 初始化
void init()
{
    head = -1;
    idx = 0;
}

// 在链表头插入一个数a
void insert(int a)
{
    e[idx] = a, ne[idx] = head, head = idx ++ ;
}

// 将头结点删除,需要保证头结点存在
void remove()
{
    head = ne[head];
}

 
 

2.双链表


双链表

模板:

// e[]表示节点的值,l[]表示节点的左指针,r[]表示节点的右指针,idx表示当前用到了哪个节点
int e[N], l[N], r[N], idx;

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

// 在节点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];
}


 

模拟栈


 
 

3.栈


模拟栈

模板:

// tt表示栈顶
int stk[N], tt = 0;

// 向栈顶插入一个数
stk[ ++ tt] = x;

// 从栈顶弹出一个数
tt -- ;

// 栈顶的值
stk[tt];

// 判断栈是否为空
if (tt > 0)
{

}

 
 

4.队列


模拟队列

模板:

//                                1. 普通队列:
// hh 表示队头,tt表示队尾
int q[N], hh = 0, tt = -1;

// 向队尾插入一个数
q[ ++ tt] = x;

// 从队头弹出一个数
hh ++ ;

// 队头的值
q[hh];

// 判断队列是否为空
if (hh <= tt)
{

}

//                                  2. 循环队列
// hh 表示队头,tt表示队尾的后一个位置
int q[N], hh = 0, tt = 0;

// 向队尾插入一个数
q[tt ++ ] = x;
if (tt == N) tt = 0;

// 从队头弹出一个数
hh ++ ;
if (hh == N) hh = 0;

// 队头的值
q[hh];

// 判断队列是否为空
if (hh != tt)
{

}

 
 

5.单调栈


单调栈

在这里插入图片描述

输入样例:

5
3 4 2 7 5

输出样例:

-1 3 -1 2 2

模板:

//单调栈
#include<iostream>

using namespace std;
const int N = 100010;
int n;
int skt[N],tt;
int main(){
	
	cin>>n;
	
	for(int i=0;i<n;i++){
		int x;
		cin>>x;
		while(tt&&skt[tt]>=x) tt--;
		if(tt) cout<<skt[tt]<<" ";
		else cout<<-1<<" ";
		
		skt[++tt]=x;
	}
	return 0;
} 

 
 

6.单调队列


滑动窗口

在这里插入图片描述

输入样例:

8 3
1 3 -1 -3 5 3 6 7

输出样例:

-1 -3 -3 -3 3 3 
3 3 5 5 6 7

模板:

//单调队列
#include<iostream>

using namespace std;

const int N = 1000010;

int n,k;
int a[N],q[N];
int main(){
	scanf("%d%d",&n,&k);
	for(int i=0;i<n;i++) scanf("%d",&a[i]);
	
	int hh=0,tt=-1;
	for(int i=0;i<n;i++){
		//判断队头是否已经滑出窗口
		if(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]]);
		
	}
	
	puts("");
	return 0;
}


 

 

8.Trie


Trie字符串统计

在这里插入图片描述
输入样例:

5
I abc
Q abc
Q ab
I ab
Q ab

输出样例:

1
0
1

模板:

// Trie 树 字 符 串 统 计 
#include<iostream>
using namespace std;
const int N = 100010;
int son[N][26],cnt[N],idx;
char str[N];
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;
	scanf("%d",&n);
	while(n--){
		char op[2];
		scanf("%s %s",op,str);
		if(op[0]=='I') insert(str);
		else printf("%d\n",query(str));
	}
	return 0;
} 

 

最大异或对


 

10.堆

堆排序

在这里插入图片描述

输入样例:

5 3
4 5 1 3 2

输出样例:

1 2 3

模板:

//堆 --->平衡二叉树
//堆排序 
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 100010;
int n,m;
int h[N],size;
void down(int u){
	int t=u;
	if(u*2<=size && h[u*2]<h[t])  t=u*2;
	if(u*2+1<=size && h[u*2+1]<h[t]) t=u*2+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/2],h[u]);
		u/=2;
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&h[i]);
	size = n;
	for(int i=n/2;i;i--) down(i);
	
	while(m--){
		printf("%d ",h[1]);
		h[1]=h[size];
		size--;
		down(1);
	}
	return 0;
}

 

模拟堆

在这里插入图片描述

输入样例:

10
I -10
PM
I -10
D 1
C 2 8
I 6
PM
DM

输出样例:

-10
6

模板:

// h[N]存储堆中的值, h[1]是堆顶,x的左儿子是2x, 右儿子是2x + 1
// ph[k]存储第k个插入的点在堆中的位置
// hp[k]存储堆中下标是k的点是第几个插入的
int h[N], ph[N], hp[N], size;

// 交换两个点,及其映射关系
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 <= size && h[u * 2] < h[t]) t = u * 2;
    if (u * 2 + 1 <= size && 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;
    }
}

// O(n)建堆
for (int i = n / 2; i; i -- ) down(i);

 
 

11.哈希表


模拟散列表

在这里插入图片描述

输入样例:

5
I 1
I 2
I 3
Q 2
Q 5

输出样例:

Yes
No

模板:

//哈希表  拉链法
#include<iostream>
#include<cstring>
using namespace std;
const int N = 100003;
int h[N],e[N],ne[N],idx;   //存储的是下标 
void insert(int x){
	int k=(x%N+N)%N;
	e[idx]=x;
	ne[idx]=h[k];
	h[k]=idx++;
}
bool find(int x){
	int k=(x%N+N)%N;
	for(int i=h[k];i!=-1;i=ne[i]){
		if(e[i]==x) return true;
	}
	return false;
}
int main(){
	int n;
	scanf("%d",&n);
	memset(h,-1,sizeof h);
	while(n--){
		char op[2];
		int x;
		scanf("%s%d",op,&x);
		
		if(*op=='I') insert(x);
		else{
			if(find(x)) puts("Yes");
			else puts("No");
		}
	}
	return 0;
} 


//哈希表  开放寻址法
#include<iostream>
#include<cstring> 
using namespace std;
const int N = 200003,null=0x3f3f3f3f;
int h[N];
int find(int x){
	int k=(x%N+N)%N;
	while(h[k]!=null&&h[k]!=x){
		k++;
		if(k==N) k=0;
	}
	return k;
}
int main(){
	int n;
	scanf("%d",&n);
	memset(h,0x3f,sizeof h);
	
	while(n--){
		char op[2];
		int x;
		scanf("%s%d",op,&x);
		
		int k=find(x);
		if(*op=='I') h[k]=x;
		else{
			if(h[k]!=null) puts("Yes");
			else puts("No");
		}
	}
	return 0;
} 

 
 

字符串哈希

在这里插入图片描述

输入样例:

8 3
aabbaabb
1 3 5 7
1 3 6 8
1 2 1 2

输出样例:

Yes
No
Yes

模板:

#include<iostream>
using namespace std;
const int N = 100010,P = 131;
typedef unsigned long long ULL;
int n,m;
char str[N];
ULL h[N],p[N];
ULL get(int l,int r){
	return h[r]-h[l-1]*p[r-l+1];
}
int main(){
	scanf("%d%d%s",&n,&m,str+1);
	
	p[0]=1;
	for(int i=1;i<=n;i++){
		p[i]=p[i-1]*P;
		h[i]=h[i-1]*P+str[i];
	}
	while(m--){
		int l1,r1,l2,r2;
		scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
		
		if(get(l1,r1)==get(l2,r2)) puts("Yes");
		else puts("No");
	}
	return 0;
}
//补码: 原码的反码 + 1 

 
 

12.STL


C++ STL 简介:

vector, 变长数组,倍增的思想
    size()  返回元素个数
    empty()  返回是否为空
    clear()  清空
    front()/back()
    push_back()/pop_back()
    begin()/end()
    []
    支持比较运算,按字典序

pair<int, int>
    first, 第一个元素
    second, 第二个元素
    支持比较运算,以first为第一关键字,以second为第二关键字(字典序)

string,字符串
    size()/length()  返回字符串长度
    empty()
    clear()
    substr(起始下标,(子串长度))  返回子串
    c_str()  返回字符串所在字符数组的起始地址

queue, 队列
    size()
    empty()
    push()  向队尾插入一个元素
    front()  返回队头元素
    back()  返回队尾元素
    pop()  弹出队头元素

priority_queue, 优先队列,默认是大根堆
    size()
    empty()
    push()  插入一个元素
    top()  返回堆顶元素
    pop()  弹出堆顶元素
    定义成小根堆的方式:priority_queue<int, vector<int>, greater<int>> q;

stack, 栈
    size()
    empty()
    push()  向栈顶插入一个元素
    top()  返回栈顶元素
    pop()  弹出栈顶元素

deque, 双端队列
    size()
    empty()
    clear()
    front()/back()
    push_back()/pop_back()
    push_front()/pop_front()
    begin()/end()
    []

set, map, multiset, multimap, 基于平衡二叉树(红黑树),动态维护有序序列
    size()
    empty()
    clear()
    begin()/end()
    ++, -- 返回前驱和后继,时间复杂度 O(logn)

    set/multiset
        insert()  插入一个数
        find()  查找一个数
        count()  返回某一个数的个数
        erase()
            (1) 输入是一个数x,删除所有x   O(k + logn)
            (2) 输入一个迭代器,删除这个迭代器
        lower_bound()/upper_bound()
            lower_bound(x)  返回大于等于x的最小的数的迭代器
            upper_bound(x)  返回大于x的最小的数的迭代器
    map/multimap
        insert()  插入的数是一个pair
        erase()  输入的参数是pair或者迭代器
        find()
        []  注意multimap不支持此操作。 时间复杂度是 O(logn)
        lower_bound()/upper_bound()

unordered_set, unordered_map, unordered_multiset, unordered_multimap, 哈希表
    和上面类似,增删改查的时间复杂度是 O(1)
    不支持 lower_bound()/upper_bound(), 迭代器的++,--

bitset, 圧位
    bitset<10000> s;
    ~, &, |, ^
    >>, <<
    ==, !=
    []

    count()  返回有多少个1

    any()  判断是否至少有一个1
    none()  判断是否全为0

    set()  把所有位置成1
    set(k, v)  将第k位变成v
    reset()  把所有位变成0
    flip()  等价于~
    flip(k) 把第k位取反

 
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值