zoukankan      html  css  js  c++  java
  • 简单数据结构模板

    一,STL

    1> STL中数据结构常见操作

    1. a.assign(b.begin(), b.begin()+3); //b为向量,将b的0~2个元素构成的向量赋给a
    2. a.assign(4,2); //是a只含4个元素,且每个元素为2
    3. a.back(); //返回a的最后一个元素
    4. a.front(); //返回a的第一个元素
    5. a[i]; //返回a的第i个元素,当且仅当a[i]存在2013-12-07
    6. a.clear(); //清空a中的元素
    7. a.empty(); //判断a是否为空,空则返回ture,不空则返回false
    8. a.pop_back(); //删除a向量的最后一个元素
    9. a.erase(a.begin()+1,a.begin()+3); //删除a中第1个(从第0个算起)到第2个元素,也就是说删除的元素从a.begin()+1算起(包括它)一直到a.begin()+ 3(不包括它)
    10. a.push_back(5); //在a的最后一个向量后插入一个元素,其值为5
    11. a.insert(a.begin()+1,5); //在a的第1个元素(从第0个算起)的位置插入数值5,如a为1,2,3,4,插入元素后为1,5,2,3,4
    12. a.insert(a.begin()+1,3,5); //在a的第1个元素(从第0个算起)的位置插入3个数,其值都为5
    13. a.insert(a.begin()+1,b+3,b+6); //b为数组,在a的第1个元素(从第0个算起)的位置插入b的第3个元素到第5个元素(不包括b+6),如b为1,2,3,4,5,9,8 ,插入元素后为1,4,5,9,2,3,4,5,9,8
    14. a.size(); //返回a中元素的个数;
    15. a.capacity(); //返回a在内存中总共可以容纳的元素个数
    16. a.resize(10); //将a的现有元素个数调至10个,多则删,少则补,其值随机
    17. a.resize(10,2); //将a的现有元素个数调至10个,多则删,少则补,其值为2
    18. a.reserve(100); //将a的容量(capacity)扩充至100,也就是说现在测试a.capacity();的时候返回值是100.这种操作只有在需要给a添加大量数据的时候才 显得有意义,因为这将避免内存多次容量扩充操作(当a的容量不足时电脑会自动扩容,当然这必然降低性能)
    19. a.swap(b); //b为向量,将a中的元素和b中的元素进行整体性交换
    20. a==b; //b为向量,向量的比较操作还有!=,>=,<=,>,<
    21. sort(a.begin(),a.end()); //对a中的从a.begin()(包括它)到a.end()(不包括它)的元素进行从小到大排列
    22. reverse(a.begin(),a.end()); //对a中的从a.begin()(包括它)到a.end()(不包括它)的元素倒置,但不排列,如a中元素为1,3,2,4,倒置后为4,2,3,1
    23. copy(a.begin(),a.end(),b.begin()+1); //把a中的从a.begin()(包括它)到a.end()(不包括它)的元素复制到b中,从b.begin()+1的位置(包括它)开 始复制,覆盖掉原有元素
    24. find(a.begin(),a.end(),10); //在a中的从a.begin()(包括它)到a.end()(不包括它)的元素中查找10,若存在返回其在向量中的位置

    2>优先队列

    大根堆声明方式:

    大根堆就是把大的元素放在堆顶的堆。优先队列默认实现的就是大根堆,所以大根堆的声明不需要任何花花肠子,直接按C++STLC++STL的声明规则声明即可

    #include<queue>
    priority_queue<int> q;
    priority_queue<string> q;
    priority_queue<pair<int,int> > q;//pair类型放入优先队列中总是先比较first的大小								//相同在比较second的大小 
    

    小根堆声明方式

    priority_queue<int,vector<int>,greater<int> >q;

    重载运算符

    语法格式:

    <返回类型> operator <运算符符号>(<参数>)

    {

    ​ <定义>;

    }

    例如:

    struct node
    {
        int id;
        double x,y;
    }//定义结构体
    bool operator <(const node &a,const node &b)
    {
        return a.x<b.x && a.y<b.y;
    }//重载运算符“
    

    3>bitset

    bitsetbitset容器概论

    bitsetbitset容器其实就是个01串。可以被看作是一个bool数组。它比bool数组更优秀的优点是:节约空间,节约时间,支持基本的位运算。在bitset容器中,8位占一个字节,相比于bool数组4位一个字节的空间利用率要高很多。同时,n位的bitset在执行一次位运算的复杂度可以被看作是n/32.

    bitset容器的声明

    因为bitset容器就是装01串的,所以不用在< >中装数据类型,这和一般的STL容器不太一样。< >中装01串的位数

    如:(声明一个1e5位的bitset)

    bitset<100000> s;

    常用的操作函数

    • count()函数

    它的作用是数出1的个数。

    s.count();
    
    • any()/none()函数

    如果,bitset中全都为0,那么s.any()返回false,s.none()返回true。

    反之,假如bitset中至少有一个1,即哪怕有一个1,那么s.any()返回true,s.none()返回false.

    s.any();
    s.none();
    
    • set()函数

    set()函数的作用是把bitset全部置为1.

    特别地,set()函数里面可以传参数。set(u,v)的意思是把bitset中的第u位变成v,v∈0/1。

    s.set();
    s.set(u,v);
    
    • reset()函数

    与set()函数相对地,reset()函数将bitset的所有位置为0。而reset()函数只传一个参数,表示把这一位改成0。

    s.reset();
    s.reset(k);
    
    • flip()函数

    flip()函数与前两个函数不同,它的作用是将整个bitset容器按位取反。同上,其传进的参数表示把其中一位取反。

    s.flip();
    s.flip(k);
    

    **PS:bitset能直接进行位运算,如:&,|,^,<<,>>,==/!= **


    二,链表

    1>链式前向星(邻接表)

    struct Edge
    {
        int nex, to;
    } e[N << 1];
    void add(int u, int v)
    {
        e[++cnt].nex = head[u];
        head[u] = cnt;
        e[cnt].to = v;
    }
    

    2>舞蹈链

    解决一类精确覆盖问题

    模板题目为:给定一个N行M列的矩阵,矩阵中每个元素要么是1,要么是0

    你需要在矩阵中挑选出若干行,使得对于矩阵的每一列j,在你挑选的这些行中,有且仅有一行的第j个元素为1

    #include <bits/stdc++.h>
    using namespace std;
    #define re register int
    #define ull unsigned long long
    #define ll long long
    #define inf 0x3f3f3f3f
    #define N 1000010
    #define mod 114514
    #define lson rt << 1
    #define rson rt << 1 | 1
    inline ll read()
    {
    	ll x=0,f=1;char ch=getchar();
    	while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    	while (ch>='0' && ch <= '9') { x=(x<<1) + (x<<3) + (ll)ch-'0';ch=getchar();}
    	return x*f;
    }
    int n, m, ans[1100],a[1100],l[250010],r[250010],las[1100];
    int up[250010],down[250010],row[250010],col[250010];
    int cnt,siz[1100];
    void newlr(int u)
    {
    	r[l[u]]=l[r[u]]=u;
    }
    void newud(int u)
    {
    	down[up[u]]=up[down[u]]=u;
    }
    void dellr(int u)
    {
    	r[l[u]]=r[u];
    	l[r[u]]=l[u];
    }
    void delud(int u)
    {
    	up[down[u]]=up[u];
    	down[up[u]]=down[u];
    }
    void link(int lef,int rr,int uu,int dd,int rw,int dw)
    {
    	l[cnt]=lef; r[cnt]=rr;
    	up[cnt]=uu; down[cnt]=dd;
    	row[cnt]=rw; col[cnt]=dw;
    }
    void prep(int x)
    {
    	l[0]=r[0]=up[0]=down[0]=0;
    	for (int i=1; i <= x; i++)
    	{
    		siz[i]=0;
    		las[i]=i;
    		cnt++;
    		link(i-1,r[i-1],i,i,0,i);
    		newlr(i);
    	}
    }
    void add(int rw)
    {
    	if (a[0] == 0) return ;
    	cnt++;
    	link(cnt,cnt,las[a[1]],down[las[a[1]]],rw,a[1]);
    	newud(cnt);
    	siz[a[1]]++;las[a[1]]=cnt;
    	for (int i=2;i<=a[0];i++)
    	{
    		cnt++;
    		link(cnt-1,r[cnt-1],las[a[i]],down[las[a[i]]],rw,a[i]);
    		newlr(cnt);newud(cnt);
    		siz[a[i]]++;las[a[i]]=cnt;
    	}
    }
    void del(int x)//因为节点序号1-m的节点的行数都为0,即虚拟节点,左右只用删除一次
    {
    	dellr(x);
    	for (int i=up[x];i!=x;i=up[i])
    	{
    		for (int j=l[i];j!=i;j=l[j])
    			delud(j),siz[col[j]]--;
    	}
    }
    void back(int x)
    {
    	newlr(x);
    	for (int i = up[x]; i!=x; i = up[i])
    	{
    		for (int j = l[i]; j!=i; j = l[j])
    			newud(j),siz[col[j]]++;
    	}
    }
    int dance(int step)
    {
    	if (!r[0])
    	{
    		for (int i=0;i<step;i++)
    			printf("%d ",ans[i]);
    		return step;
    	}
    	int x,minn=inf;
    	for (int i=r[0];i;i=r[i])//优化,选出1最少的列
    	{
    		if (siz[col[i]]<minn)
    			minn=siz[col[i]],x=i;
    	}
    	if (minn == 0) return 0;
    	del(x);//x为第0行该列的节点序号
    	for (int i = up[x];i!=x;i=up[i])//枚举该列有1的行
    	{
    		ans[step] = row[i];
    		for (int j=l[i];j!=i;j=l[j])
    			del(col[j]);
    		int tmp=dance(step+1);
    		if (tmp) return tmp;
    		for (int j=r[i];j!=i;j=r[j]) back(col[j]);
    	}
    	back(x);
    	return 0;
    }
    		
    int main()
    {
    	n = read(),m = read();
    	prep(m);
    	for (int i=1; i <= n; i++)
    	{
    		for (int j=1; j <= m; j++)
    		{
    			int x = read();
    			if (x) a[++a[0]] = j;
    		}
    		add(i);
    		a[0]=0;
    	}
    	if (!dance(0))
    		printf("No Solution!
    ");
    	return 0;
    }
    

    3>ST表

    区间查询,O(1),不能修改

    区间最大值模板:

    int main()
    {
    	n=read(),Q=read();
    	for (int i=1;i<=n;i++) f[i][0]=read();
    	for (int j=1;j<=18;j++)
    		for (int i=1;i+(1<<j)-1<=n;i++)
    		f[i][j]=max(f[i][j-1],f[i+(1<<(j-1)][j-1]);
    	while (Q--)
    	{
    		int l=read(),r=read();
    		int k=log2(r-l+1);
    		printf("%d
    ",max(f[l][k],f[r-(1<<k)+1][k]));
    	}
    	return 0;
    }
    

    4>并查集

    1. 普通并查集

      #include <bits/stdc++.h>
      using namespace std;
      int n, m, z, x, y, fa[100010];
      int getfa(int x)
      {
          return x == fa[x] ? x : fa[x] = getfa(fa[x]);
      } 
      int main()
      {
          scanf("%d%d", &n, &m);
          for (int i = 1; i <= n; i++)
              fa[i] = i; 
          for (int i = 1; i <= m; i++)
          {
              scanf("%d%d%d", &z, &x, &y);
              if (z == 1)
              {
                  fa[getfa(x)] = getfa(y);
              } 
              else
              {
                  if (getfa(x) == getfa(y))
                      puts("Y"); 
                  else
                      puts("N");
              }
          }
          return 0;
      }
      
    2. 带权并查集

      与普通并查集相比,在递归前加了一步赋值操作

      带权并查集图示为:

      img

    它的每一条边都记录了每个节点到根节点的一个权值,这个权值该设为什么由具体的问题而定,一般都是两个节点之间的某一种相对的关系

    查询:

    int getfa(int x)
    {
    	if (x != dad[x])
    	{
    		int t = dad[x];
    		dad[x] = getfa(dad[x]);
    		value[x] += value[t];
    	}
    	return dad[x];
    }
    

    合并:

    		int px = getfa(x);
    		int py = getfa(y);
    		if (px != py)
    		{
    			dad[px] = py;
    			value[px] = -value[x] + value[y] + s;
    		}
    

    3.种类并查集

    维护一类“朋友的朋友是朋友,朋友的敌人是敌人,敌人的敌人是朋友”的关系,一般用拆点

    经典例题1:食物链

    动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。A吃B, B吃C,C吃A。
    现有N个动物,以1-N编号。每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。
    有人用两种说法对这N个动物所构成的食物链关系进行描述:
    第一种说法是"1 X Y",表示X和Y是同类。
    第二种说法是"2 X Y",表示X吃Y。
    此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
    1) 当前的话与前面的某些真的话冲突,就是假话;
    2) 当前的话中X或Y比N大,就是假话;
    3) 当前的话表示X吃X,就是假话。
    你的任务是根据给定的N(1 <= N <= 50,000)和K句话(0 <= K <= 100,000),输出假话的总数。

    int n,k,dad[5000050],ans;
    int getf(int x)
    {
    	return x==dad[x]?x:dad[x]=getf(dad[x]);
    }
    int main()
    {
    	scanf("%d%d",&n,&k);
    	for (int i=1;i<=500100;i++) dad[i]=i;
    	while (k--)
    	{
    		int a,b,ty;
    		scanf("%d%d%d",&ty,&a,&b);
    		int aa=a+n,bb=b+n;
    		int aaa=a+2*n,bbb=b+2*n;
    		if (a>n||b>n)
    		{
    			ans++;
    			continue;
    		}
    		if (ty==1)
    		{
    			if (getf(aa)==getf(b)||getf(aaa)==getf(b))
    			{
    				ans++;
    				continue;
    			}
    			dad[getf(a)]=getf(b);
    			dad[getf(aa)]=getf(bb);
    			dad[getf(aaa)]=getf(bbb);
    		}
    		if (ty==2)
    		{
    			if (a==b)
    			{
    				ans++;
    				continue;
    			}
    			if (getf(a)==getf(b)||getf(aaa)==getf(b))
    			{
    				ans++;
    				continue;
    			}
    			dad[getf(a)]=getf(bbb);
    			dad[getf(aa)]=getf(b);
    			dad[getf(aaa)]=getf(bb);
    		}
    	}
    	printf("%d",ans);
    	return 0;
    }
    
  • 相关阅读:
    java读取ANSI编码或者UTF8编码文件乱码问题解决
    java集合框架(Framework)的性能
    堆排序程序
    Python监控Apache,MySQL
    堆排序和快速排序性能比较
    资源管理命令
    Python监控Apache,MySQL
    资源管理命令
    javap反编译
    浏览器的用户代理字符串
  • 原文地址:https://www.cnblogs.com/71-111/p/15257724.html
Copyright © 2011-2022 走看看