【算法基础】数据结构

这篇具有很好参考价值的文章主要介绍了【算法基础】数据结构。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

链表 

单链表

826. 单链表 - AcWing题库

【算法基础】数据结构,ac算法,数据结构,算法,链表

#include<bits/stdc++.h>
using namespace std;
const int N =100010;
int m;
int e[N],ne[N];//记录数据和下一结点坐标
int head,idx;//当前指向的结点 
void init()
{
	head=-1;
	idx=0;
}
void addtohead(int x)
{
	e[idx]=x;
	ne[idx]=head;
	head=idx;
	idx++;
}
void remove(int x)
{
	ne[x]=ne[ne[x]];
}
void add(int k,int x)
{
	e[idx]=x;
	ne[idx]=ne[k];
	ne[k]=idx;
	idx++;
}
signed main()
{
    scanf("%d",&m);
    init();
	while(m--)
	{
		char op;
		scanf("%s",&op);
		if(op=='H')//向链表头插入一个数x 
		{
			int x;
			scanf("%d",&x);
			addtohead(x);	
		}
        //第k个插入的数的对应坐标是k-1
		if(op=='D')//删除第 k个插入的数后面的数(当 k为 0时,表示删除头结点)
		{
			int x;
			scanf("%d",&x);
			if(!x) head=ne[head];//如果是删除头结点 ,移动头结点head 
			else remove(x-1);
		}	
		if(op=='I')//第 k个插入的数后面插入一个数 x
		{
			int k,x;
			scanf("%d %d",&k,&x);
			add(k-1,x);
		}
	}
	for(int i=head;i!=-1;i=ne[i]) cout<<e[i]<<" ";
    return 0;
}

双链表

827. 双链表 - AcWing题库

【算法基础】数据结构,ac算法,数据结构,算法,链表

#include<bits/stdc++.h>
using namespace std;
const int N =100010;
int m;
int e[N],l[N],r[N],idx;
void init()
{
	r[0]=1,l[1]=0;
	idx=2;
}
void add(int k,int x)
{
	e[idx]=x;
	l[idx]=k;
	r[idx]=r[k];
	l[r[k]]=idx;
	r[k]=idx++;
}
void remove(int k)
{
	r[l[k]]=r[k];
	l[r[k]]=l[k];
}
signed main()
{//0,1代表头尾 
	cin>>m;
	init();
	while(m--)
	{
		string op;
		cin>>op;
		if(op=="L")
		{
			int x;
			cin>>x; 
			add(0,x);
		}
		if(op=="R")
		{
			int x;
			cin>>x;
			add(l[1],x);
		}
		if(op=="D")
		{
			int k;
			cin>>k;
			remove(k+1);
		}
		if(op=="IL")
		{
			int k,x;
			cin>>k>>x;
			add(l[k+1],x);
		}
		if(op=="IR")
		{
			int k,x;
			cin>>k>>x;
			add(k+1,x);
		}
	}
	for(int i=r[0];i!=1;i=r[i]) cout<<e[i]<<" ";
    return 0;
}

828. 模拟栈 - AcWing题库

【算法基础】数据结构,ac算法,数据结构,算法,链表

#include<bits/stdc++.h>
using namespace std;
const int N =100010;
int m;
int stk[N],tt;
void init()
{
	tt=0;
	memset(stk,0,sizeof(stk));
}
signed main()
{
    cin>>m;
    init();
    while(m--)
    {
    	string op;
    	cin>>op;
    	if(op=="push")
    	{
    		int x;
    		cin>>x;
    		stk[++tt]=x;
		}
		if(op=="pop")
		{
			tt--;
		}
		if(op=="empty")
		{
			if(tt>0) cout<<"NO"<<'\n';
			else cout<<"YES"<<'\n';
		}
		if(op=="query")
		{
			cout<<stk[tt]<<'\n';
		}
	}
    return 0;
}

3302. 表达式求值 - AcWing题库

遍历输入的操作

如果是数字就存入num的堆栈 (同时注意123,2123这种长数字要一次性存入)

如果是(  直接存入op的堆栈

如果是  )就一直运算,直到遇到(

如果是操作符(如+-*/),一直与栈顶比较运算符优先级,如果栈里的运算符优先级大就运算,直到目前这个运算符优先级小为止。

运算是从num里弹出两个数,从op里弹出一个运算符,直接运算。

如果最后遍历完了,栈内还有运算符就算完,最后num栈顶的元素就是最后的运算结果

#include <iostream>
#include <string>
#include <stack>
#include <unordered_map>

using namespace std;

stack<char> op;
stack<int> num;
unordered_map<char, int> pr = {{'+', 1}, {'-', 1}, {'*', 2}, {'/', 2}};

void eval()
{
    int b = num.top(); num.pop();
    int a = num.top(); num.pop();
    char c = op.top(); op.pop();

    int x;
    if(c == '+') x = a + b;
    else if(c == '-') x = a - b;
    else if(c == '*') x = a * b;
    else x = a / b;

    num.push(x);
}

int main()
{
    string s;
    cin >> s;

    for(int i = 0; i < s.size(); i++)
    {
        char c = s[i];
        if(isdigit(c))
        {
            int x = 0, j = i;
            while(j < s.size() && isdigit(s[j])) x = 10 * x + s[j++] - '0';
            i = j - 1;
            num.push(x);
        }
        else if(c == '(') op.push(c);
        else if(c == ')')
        {
            while(op.size() && op.top() != '(') eval();
            op.pop();
        }
        else
        {
            while(op.size() && pr[op.top()] >= pr[c]) eval();
            op.push(c);
        }
    }
    while(op.size()) eval();
    cout << num.top() << endl;

    return 0;
}

队列

829. 模拟队列 - AcWing题库

【算法基础】数据结构,ac算法,数据结构,算法,链表

#include<bits/stdc++.h>
using namespace std;
//头删尾插 
const int N=1e5+10; 
int q[N],hh,tt=-1;
int m;
signed main()
{
	cin>>m;
	while(m--)
	{
		string op;
		cin>>op;
		if(op=="push")
		{
			int x;
			cin>>x;
			q[++tt]=x;
		}else if(op=="pop"){
			hh++;
		}else if(op=="empty"){
			if(hh<=tt) cout<<"NO"<<endl;
			else cout<<"YES"<<endl;
		}else if(op=="query"){
			cout<<q[hh]<<endl;
		}
	}
	return 0;
}

 单调栈

830. 单调栈 - AcWing题库

 单调递增或递减的栈

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10; 
int stk[N],tt;
int n;
signed main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	{
		int x;
		cin>>x;
		while(tt&&stk[tt]>=x) tt--;
		if(tt) cout<<stk[tt]<<" ";
		else cout<<"-1 ";
		stk[++tt]=x;	
	}
	
	return 0;
}

单调队列

154. 滑动窗口 - AcWing题库

数组a存数值,数组q模拟队列。

保持滑动窗口的大小为k。同时保持单调队列,也就是如果队头的数比进来的数大就丢出去,这样保持队头是当前这个区间内的最小值。

#include<iostream>
using namespace std;
const int N = 1e6 + 10;
int n,k,q[N],a[N];//q[N]存的是数组下标
int main()
{
    int tt=-1,hh=0;//hh队列头 tt队列尾
    cin>>n>>k;
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<n;i++)
    {
    	if(hh<=tt&&i>q[hh]+k-1) hh++;
    	while(hh<=tt&&a[i]<=a[q[tt]]) tt--;
    	q[++tt]=i;
    	if(i>=k-1) cout<<a[q[hh]]<<" ";
	}
	cout<<endl;
	hh=0,tt=-1;
	for(int i=0;i<n;i++)
	{
		if(hh<=tt&&i>q[hh]+k-1) hh++;
		while(hh<=tt&&a[i]>=a[q[tt]]) tt--;
		q[++tt]=i;
		if(i>=k-1) cout<<a[q[hh]]<<" ";
	}
    return 0;
}

 KMP

831. KMP字符串 - AcWing题库

这篇写得很好:KMP算法详解-彻底清楚了(转载+部分原创) - sofu6 - 博客园 (cnblogs.com)  

#include<iostream>
using namespace std;
const int N=100010,M=1000010;
char q[N],s[M];
int ne[N];//保存next数组
int main()
{
    int n,m;
    cin>>n>>q+1>>m>>s+1;//下标均从1开始
    ne[1]=0;
    for(int i=2,j=0;i<=n;i++)
    //j表示匹配成功的长度,i表示q数组中的下标,因为q数组的下标是从1开始的,只有1个时,一定为0,所以i从2开始
    {
        while(j&&q[i]!=q[j+1]) j=ne[j];
        //如果不行可以换到next数组
        if(q[i]==q[j+1]) j++;
        //成功了就加1
        ne[i]=j;
        //对应其下标
    }
    //j表示匹配成功的长度,因为刚开始还未开始匹配,所以长度为0
    for(int i=1,j=0;i<=m;i++)
    {
        while(j&&s[i]!=q[j+1]) j=ne[j];
        //如果匹配不成功,则换到j对应的next数组中的值
        if(s[i]==q[j+1]) j++;
        //匹配成功了,那么j就加1,继续后面的匹配
        if(j==n)//如果长度等于n了,说明已经完全匹配上去了
        {
            printf("%d ",i-j);
            //因为题目中的下标从0开始,所以i-j不用+1;
            j=ne[j];
            //为了观察其后续是否还能跟S数组后面的数配对成功
        }
    }
    return 0;
}

理解后自己a的版本 

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
char p[N],s[N];
int m,n;
int ne[N];
signed 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)
		{
			cout<<i-j<<" ";
			j=ne[j];
		}
	}
	
	return 0;
}

Trie树

835. Trie字符串统计 - AcWing题库

Trie树:用来高效的存储和字符串集合的数据结构。 

 【算法基础】数据结构,ac算法,数据结构,算法,链表

#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int son[N][26], cnt[N], idx; //下标是0的点,既是根节点,又是空节点
char str[N];
void insert(char str[])
{
    int p=0;
    for(int i=0;str[i]!='\0';++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];
}
signed main() 
{
    int m;cin>>m;
    while(m--)
    {
        char c;
        cin>>c>>str;
        if(c=='I') insert(str);
        else {
            cout<<query(str)<<endl;
        }
    }
    return 0;
}

143. 最大异或对 - AcWing题库

异或,不进位的加法。

先转化成二进制,进行异或运算后,再转化。

比如3^5=6

3的二进制是011,5的二进制是101

101

011

110(结果),对应十进制里的6 

【算法基础】数据结构,ac算法,数据结构,算法,链表

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int son[N*31][2];
int idx,n;
void insert(int x)
{
	int p=0;
	for(int i=31;i>=0;i--)
	{
		int u=x>>i&1;
		if(!son[p][u]) son[p][u]=++idx;
		p=son[p][u];
	}
}
int query(int x)
{
	int p=0,ret=0;
	for(int i=31;i>=0;i--)
	{
		int u=x>>i&1;
		if(son[p][!u])
		{
			p=son[p][!u];
			ret=ret*2+!u;
		}else{
			p=son[p][u];
			ret=ret*2+u;
		}
	}
	return ret^x;
}
signed main()
{
    cin>>n;
    int maxn=0;
    while(n--)
    {
    	int x;
    	cin>>x;
    	insert(x);
    	maxn=max(maxn,query(x));
	}
	cout<<maxn;
	return 0;
}

并查集

并查集适于以下操作:

1.合并两个集合

2.查询两个元素是否同一个集合

合并集合 

836. 合并集合 - AcWing题库

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int p[N];
int find(int x)
{
	if(p[x]!=x) p[x]=find(p[x]);
	return p[x];
}
void merge(int a,int b)
{
	int pa=find(a);int pb=find(b);
	if(pa!=pb)
	{
		p[pa]=pb;
	}
}
void query(int a,int b)
{
	int pa=find(a);
	int pb=find(b);
	if(pa==pb) cout<<"Yes"<<endl;
	else cout<<"No"<<endl;
}
signed main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++) p[i]=i; 
    while(m--)
    {
    	char op;
    	cin>>op;
    	int a,b;
    	cin>>a>>b;
    	if(op=='M') merge(a,b);
    	if(op=='Q') query(a,b);
	}
	return 0;
}

 连通块中点的数量

837. 连通块中点的数量 - AcWing题库

 用集合维护连通块。

在点之间连边相当于合并两个集合。

额外需要注意的操作就只有统计每个集合中的元素个数,开一个s数组记录就好。

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int p[N],s[N];//只保证根节点的size有意义 
int find(int x)
{
	if(p[x]!=x) p[x]=find(p[x]);
	return p[x];
}
void merge(int a,int b)
{
	int pa=find(a);int pb=find(b);
	if(pa!=pb)
	{
		p[pa]=pb;
		s[pb]+=s[pa]; 
	}
}
void query(int a,int b)
{
	int pa=find(a);
	int pb=find(b);
	if(pa==pb) cout<<"Yes"<<endl;
	else cout<<"No"<<endl;
}
signed main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++) p[i]=i,s[i]=1; 
    while(m--)
    {
    	char op[5];
    	cin>>op;
    	int a,b;
    	if(op[0]=='C') cin>>a>>b,merge(a,b);
    	if(op[1]=='1') cin>>a>>b,query(a,b);
    	if(op[1]=='2') cin>>a,cout<<s[find(a)]<<endl;
	}
	return 0;
}

食物链

240. 食物链 - AcWing题库

 有问题可以看这个题解的评论,解答得很漂亮!!

#include<bits/stdc++.h>
using namespace std;
const int N=5e4+10;
int n,m;
int p[N],d[N];
int res;
int find(int x)
{
	if(p[x]!=x) 
	{
		int t = find(p[x]);//这一步是直接找到根
        d[x] += d[p[x]];
        p[x] = t;
	}
	return p[x];
}
signed main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++) p[i]=i;
	while(m--)
	{
		int t,x,y;
		cin>>t>>x>>y;
		
		if(x>n||y>n) res++;	
		else{
			
			int px=find(x),py=find(y);
			if(t==1)//同类的 
			{
				if(px==py&&(d[x]-d[y])%3!=0) res++;//如果在一个集合内但不满足同级的条件
				else if(px!=py)
				{
					p[px]=py;
					d[px]=d[y]-d[x];	
				} 
			}else if(t==2){
				if(px==py&&(d[x]-d[y]-1)%3!=0) res++;
				else if(px!=py)
				{
					p[px]=py;
					d[px]=d[y]+1-d[x];
				}
				
			}
		}
	}	
	cout<<res;
	return 0;
}

堆排序

838. 堆排序 - AcWing题库

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m,a[N],r;
void down(int u)
{
	int t=u;//标记最小的点
	if(2*u<=r&&a[2*u]<a[t]) t=2*u; 
	if(2*u+1<=r&&a[2*u+1]<a[t]) t=2*u+1;
	if(u!=t)
	{
		swap(a[u],a[t]);
		down(t);
	}
}
signed main()
{
	cin>>n>>m;
	r=n;
	for(int i=1;i<=n;i++) cin>>a[i];
	//建堆
	for(int i=n/2;i>=1;i--) down(i); 
	while(m--)
	{
		cout<<a[1]<<" ";
		a[1]=a[r--];
		/*swap(a[1],a[size]);
		size--;*/
		down(1);
	}
	
	return 0;
}

哈希表

哈希表根据处理哈希冲突的方式,又可以分为开放寻址法拉链法

模拟散列表

840. 模拟散列表 - AcWing题库

1.拉链法

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+3;
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;
} 
signed main()
{
	int n;
	cin>>n;
	memset(h,-1,sizeof(h));
	while(n--)
	{
		char op;
		int x;
		cin>>op>>x;
		if(op=='I') insert(x);
		else{
			if(find(x)) puts("Yes");
			else puts("No");
		}
	}
	return 0;
}

 数学里-10%3=2,但在c++中结果是-1,负数模上一个数的结果是负数。

所以我们   (x%N+N)%N

 2.开放寻址法

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+3,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;//循环从0开始	
	}	
	return k; 
}
signed main()
{
	int n;
	cin>>n;
	memset(h,0x3f,sizeof(h));
	while(n--)
	{
		char op;
		int x;
		cin>>op>>x;
		if(op=='I')
		{
			h[find(x)]=x;
		}else{
			if(h[find(x)]!=null) puts("Yes");
			else puts("No"); 
		}
	}
	return 0;
}

字符串哈希

841. 字符串哈希 - AcWing题库

这篇题解解释得很好:AcWing 841. 字符串哈希 【公式助理解】 - AcWing文章来源地址https://www.toymoban.com/news/detail-530468.html

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N=1e5+10,P=131;
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];
}
signed main()
{
	cin>>n>>m>>str+1;
	p[0]=1;
	for(int i=1;i<=n;i++)
	{
		h[i]=h[i-1]*P+str[i];
		p[i]=p[i-1]*P;
	}
	
	while(m--)
	{
		int l1,r1,l2,r2;
		cin>>l1>>r1>>l2>>r2;
		
		if(get(l1,r1)==get(l2,r2)) puts("Yes");
		else puts("No");
	}
	
	return 0;
} 

到了这里,关于【算法基础】数据结构的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 02-链表 (数据结构和算法)

    3.1 链表的基本概念 前面我们在学习顺序表时,线性表的顺序存储结构的特点是逻辑关系上相邻的两个数据元素在物理位置上也是相邻的。我们会发现虽然顺序表的查询很快,时间复杂度为O(1),但是增删的效率是比较低的,因为每一次增删操作都伴随着大量的数据元素移动。为

    2024年02月16日
    浏览(32)
  • Python数据结构与算法-数据结构(列表、栈、队列、链表)

    数据结构是指相互之间存在这一种或者多种关系的数据元素的集合和该集合中元素之间的关系组成。 简单来说,数据结构就是设计数据以何种方式组织并存储在计算机中。 比如:列表、集合与字典等都是一种数据结构。 N.Wirth:“程序=数据结构+算法” 数据结构按照其 逻辑结

    2024年02月08日
    浏览(36)
  • 【零基础学数据结构】链表

      目录 1.链表的概念 ​编辑 2.链表的雏形 ​编辑 3.链表的组成 ​编辑 4.链表代码  4.1创建节点  4.2链表的打印  4.3链表的尾插  4.4链表的头插  4.5链表的尾删  4.6链表的头删  4.7链表的查找  4.8链表在指定位置之前插⼊数据  4.9链表在指定位置之后插⼊数据  4.9-1删除p

    2024年04月13日
    浏览(21)
  • 算法与数据结构之链表

    链表的定义,相信大家都知道,这里就不赘述了只是链表分单向链表和双向链表,废话不多说,直接上代码 链表节点的定义: 打印链表的两种方式: 翻转单向链表:核心思路是先断开连接,再将next指向前继节点,为了避免断开之后,找不到前继节点,需要用一个临时变量记

    2024年02月05日
    浏览(39)
  • 【数据结构和算法】奇偶链表

    Java基础合集 数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 其他系列文章导航 文章目录 前言 一、题目描述 二、题解 2.1 方法一:分离节点后合并 三、代码 3.1 方法一:分离节点后合并 四、复杂度分析 4.1 方法一:分离节点后合并 这是力扣的 328 题,难

    2024年01月20日
    浏览(37)
  • 数据结构与算法:双向链表

    朋友们大家好啊,在上节完成单链表的讲解后,我们本篇文章来对 带头循环双向链表进行讲解 单链表中,一个节点存储数据和指向下一个节点的指针,而双向链表除了上述两个内容,还包括了 指向上一个节点的指针 带头的双向链表,是指在双向链表的最前端添加了一个 额

    2024年02月20日
    浏览(36)
  • 【数据结构和算法】反转链表

    Java基础合集 数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 其他系列文章导航 文章目录 前言 一、题目描述 二、题解 2.1 方法一:迭代(双指针) 2.2 方法二:递归 三、代码 3.1 方法一:迭代(双指针) 3.2 方法二:递归 四、复杂度分析 4.1 方法一:迭代

    2024年01月18日
    浏览(40)
  • 【数据结构与算法】双向链表

    作者:旧梦拾遗186 专栏:数据结构成长日记   带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带来很多优势,实现反而简单了。 现在我们来通

    2024年02月11日
    浏览(39)
  • 数据结构与算法(四):双向链表

    双向链表概念和单向链表是一致的,区别在于双向链表在单向链表的基础上,指针区域多了一个指向上一个节点的指针。单向链表内容可以参考我的上一篇文章:http://t.csdn.cn/Iu56H。 基本的数据结构如图所示: 双向链表结构包含了节点的数据内容和两个指针:指向前一个节点

    2024年02月14日
    浏览(34)
  • 数据结构与算法(三):单向链表

    链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑是通过链表种的指针链接次序实现的。链表由一系列节点组成,每个节点包括两部分:一个是存储数据元素的数据域,一个是存储下一个节点地址的指针域。单向链表从头节点(也可以没有头节点)开始

    2024年02月15日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包