第3節 堆排序
把n個元素建立一個堆,首先將這n個結點以自頂向下、從左到右的方式從1到n編碼,這樣可以把n個結點轉換成一顆完全二叉樹
緊接著從最後一個非葉子結點(結點編號為n/2)開始到根節點(結點編號為1),逐個掃描所有結點,根據需要將當前結點向下調整,直到以當前結點為根結點的子樹符合堆的特性。
#include <iostream> #include <vector> #include <algorithm> using namespace std; //向下調整函式 void shiftdown(vector<int>& a, int n,int index){ while(index*2<= n ){ int t = index; if(a[t] > a[2*index]) t = 2*index; if( 2*index+1 <= n && a[t] > a[2*index+1] ) t = 2*index+1; if(t!=index) {swap(a[t],a[index]); index = t;} else break; } } //刪除最大的元素 int deletemax(vector<int>& a , int& n){ int res = a[1]; swap(a[1],a[n]); n--; shiftdown(a,n,1); return res; } //向上調整函式 void shiftup(vector<int>& a, int n, int index){ if(index == 1) return; while(index!=1){ if(a[index] < a[index/2]) swap(a[index],a[index/2]); else break; index/=2; } } // 建立堆 void make_heap(vector<int>& a, int n){ //注意索引是從0開始的 for(int i = n/2; i> 0; -- i){ shiftdown(a,n,i); } } void heap_sort(vector<int>& a){ int n =a.size()-1; while( n > 1){ swap(a[1],a[n]); n--; shiftdown(a,n,1); } } int main(){ int n; cin >> n; vector<int> a(n+1,0); for(int i = 1 ; i <= n; ++ i){ cin >> a[i]; } //建堆 make_heap(a,n); heap_sort(a); for(int i = 1 ; i <= n; ++ i){ cout<<a[i]<<" "; } cout<<endl; int num = n; for(int i = 1; i <= n; ++ i){ cout<<deletemax(a,num)<<endl; } }
第4節 並查集
並查集的優化有兩種,一種是路徑壓縮,一種是按秩合併,具體的可以參考《演算法導論》
/* *並查集操作 */ #include <iostream> #include <vector> #include <algorithm> using namespace std; int f[1000]={0}; void make_set(int size){ for(int i =1; i <= size; ++ i ) f[i] = i; } //採用路徑壓縮的方法查詢元素 int find_set(int x){ if(f[x] == x) return x; else{ f[x] = find_set(f[x]); //查詢x元素所在的集合,回溯時壓縮路徑 return f[x]; } } void union_set(int x, int y){ int t1 = find_set(x), t2 = find_set(y); if(t1 != t2){ f[t2] = t1; } } int main(){ int n, m; cin >> n >> m; make_set(n); for(int i = 1; i<=m; ++ i){ int x,y; cin >> x >> y; union_set(x,y); } int sum = 0; for(int i = 1; i<= n; ++ i){ if(f[i] == i) sum++; } cout<<sum<<endl; return 0; }