《啊哈!演算法》第7章 神奇的樹

OpenSoucre發表於2014-06-26

第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;
}
並查集

 

相關文章