并查集:一种维护集合的数据结构
一、合并onion
二、查找find
初始化、查找(路径压缩)、合并
堆:本质是二叉树
//并查集的复习 //堆的复习 #include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<stack> #include<cstdio> #include<queue> #include<map> #include<vector> #include<set> using namespace std; const int maxn=1010; const int INF=0x3fffffff; //并查集的数据结构:数组 int fa[maxn]; //操作:查找、合并 //查找的优化:路径压缩 int findfa(int x){ if(x!=fa[x]) fa[x]=findfa(fa[x]); return fa[x]; } //合并其实有也优化,有时候并查集有权值的时候会有选择性的合并,根据权值大小合并 void ini(int a,int b){ int fa1=findfa(a); int fa2=findfa(b); if(fa1!=fa2) fa[fa2]=fa1; } //并查集产生的集合:一棵树 //堆: //a heap is a specialized tree-based data structure(树)、并查集、堆的实质其实都可以是树 //一般的快速数据结构:优先队列: //优先队列默认:大顶堆 (不用自己写函数) priority_queue<int> q1; //小顶堆 priority_queue<int,vector<int>,greater<int> > q2; //跟一般的数据结构(需要自己写函数的那种) //需要自己写函数 int heap[maxn]; //just like堆 //但是掌握堆的自顶向上和自底向上的两种写法是很重要的 //建堆的过程:自上向下调整,但是需要倒着枚举调整,调整所有的非叶子节点,从n/2到1,倒着调整,但是调整是自顶向下的 //包括删除节点的时候:删除堆顶元素,用最后一个元素覆盖第一个,然后调整downjust(1,n) void downadjust(int low,int high){ //向下调整:删除、建堆、堆排序 int i=low,j=2*i; while(j<=high){ //如果有孩子存在,且有孩子的值大于左孩子的值,就像后移,然后再跟i比较大小 if(j+1<=high&&heap[j+1]>heap[j]) j++; if(heap[j]>heap[i]){ //如果孩子比爸爸大,就要交换 swap(heap[j],heap[i]); i=j; j=2*i; } else break; //不然就退出 } } void create(){ for(int i=1;i<=n;i++) cin>>heap[i]; for(int i=n/2;i>=1;i--) downadjust(i,n); } //倒着调整:这样才能满足每个节点都是以他为父节点的最大值 //删除堆顶元素 void del(){ heap[1]=heap[n--]; downadjust(1,n); //调整堆顶 } //添加一个元素的时候:添加再最后面,然后自底向上调整 void upadjust(int high,int low){ int i=high,j=high/2; while(j>=low){ //总是和父亲比较的话,就不存在j++或者j--了,直接比较就可以了 if(heap[j]<heap[i]){ swap(heap[j],heap[i]); i=j; //如果父亲比小的话,就交换 j/=2; } else break; } } void insert(int x){ heap[++n]=x; //添加再末尾 upadjust(n,1); } //删除堆顶,添加末尾 //堆排序 //由于堆中堆顶元素是确定的最大的,所以每次都去堆顶元素和最末尾的元素交换,然后从堆顶进行自顶向下的调整 //这样每次都取出了最大堆顶元素,而且对的范围也在缩小 void heapsort(){ create(); //先建堆 for(int i=n;i>1;i--) { swap(a[i],a[1]); //交换 downadjust(1,i-1); //范围再缩小 } for(int i=1;i<=n;i++) cout<<heap[i]<<" "; //自小到大的序列 }