演算法模板

我爱读论文發表於2024-08-16

拓撲排序

點選檢視程式碼
public Boolean bfsOptimize(int n, int[][] edges) {
    // 初始化入度陣列,每個節點有兩個元素,第一個元素表示入度,第二個元素暫時未使用
    int[][] indegrees = new int[n][2];
    // 初始化鄰接表,用於儲存圖的連線關係
    List<List<Integer>> adj = new ArrayList<>();
    // 遍歷所有節點,為每個節點建立一個空的鄰接表
    for (int i = 0; i < n; i++) {
        adj.add(new ArrayList<>());
    }
    // 遍歷所有邊,構建鄰接表並更新節點的入度
    for (int i = 0; i < edges.length; i++) {
        int pre = edges[i][1]; // 邊的起點
        int next = edges[i][0]; // 邊的終點
        adj.get(pre).add(next); // 將終點新增到起點的鄰接表中
        // 更新終點的入度
        indegrees[next][0]++;
    }
    // 初始化佇列,用於進行廣度優先搜尋
    Deque<Integer> queue = new LinkedList<>();
    // 將所有入度為0的節點加入佇列
    for (int i = 0; i < n; i++) {
        if (indegrees[i][0] == 0) {
            queue.addLast(i);
        }
    }
    // 記錄已經訪問過的節點數量
    int count = 0;
    // 當佇列不為空時,繼續搜尋
    while (!queue.isEmpty()) {
        int cur = queue.poll(); // 出隊一個節點
        System.out.println(cur); // 列印當前節點
        count++; // 訪問節點數量加1
        // 遍歷當前節點的所有鄰接節點
        for (int next : adj.get(cur)) {
            indegrees[next][0]--; // 將鄰接節點的入度減1
            // 如果鄰接節點的入度變為0,則將其加入佇列
            if (indegrees[next][0] == 0) {
                queue.addLast(next);
            }
        }
    }
    // 如果訪問過的節點數量等於總節點數,說明可以進行拓撲排序,返回true
    return count == n;
}

並查集

點選檢視程式碼
class Union {
    int n;// 節點數
    int[] p;// 父節點陣列,p[i]表示節點i的父節點
    int[] s;// 當前分支大小陣列,s[i]表示以節點i為根的集合的大小
    int count;// 連通分量數,即當前有多少個獨立的集合

    //初始化
    public Union(int n) {
        //注意事項:節點從0開始
        // 注意事項:節點從0開始
        this.n = n; // 將傳入的引數n賦值給類的成員變數n,表示集合的大小
        p = new int[n]; // 建立一個長度為n的陣列p,用於儲存每個節點的父節點
        s = new int[n]; // 建立一個長度為n的陣列s,用於儲存以當前節點為根的集合的大小
        count = n; // 初始化連通分量的數量為n,即每個節點初始時都是一個獨立的集合
        for (int i = 0; i < n; i++) { // 遍歷所有節點
            p[i] = i; // 將節點i的父節點設定為其自身,表示每個節點初始時都是自己的父節點
            s[i] = 1; // 將節點i所在集合的大小設定為1,因為每個節點初始時都是一個獨立的集合
        }
    }
    public int find(int x){
        // 如果節點x的父節點是它自己,說明x就是根節點,直接返回x
        if(x==p[x])
            return x;
        else{
            // 如果節點x的父節點不是它自己,遞迴查詢其父節點的根節點
            p[x] = find(p[x]);
            // 路徑壓縮,將x的父節點直接設定為找到的根節點,最佳化後續查詢操作
            return p[x];
        }
    }

    public void union(int x,int y){
        // 查詢節點x的根節點
        int rootX = find(x);
        // 查詢節點y的根節點
        int rootY = find(y);
        // 如果x和y的根節點相同,說明它們已經在同一個集合中,無需合併
        if (rootX == rootY)
            return;
        // 如果x的根節點所在集合的大小大於y的根節點所在集合的大小
        if (s[rootX] > s[rootY]) {
            // 將y的根節點的父節點設定為x的根節點,實現合併
            p[rootY] = rootX;
            // 更新x的根節點所在集合的大小,加上y的根節點所在集合的大小
            s[rootX] += s[rootY];
        } else {
            // 如果y的根節點所在集合的大小大於等於x的根節點所在集合的大小
            // 將x的根節點的父節點設定為y的根節點,實現合併
            p[rootX] = rootY;
            // 更新y的根節點所在集合的大小,加上x的根節點所在集合的大小
            s[rootY] += s[rootX];
        }
        // 合併後,連通分量的數量減1
        count--;
    }
    // 獲取最大分支節點個數
    public int getMaxCount(){
        int max=0; // 初始化最大分支節點個數為0
        for(int i=0;i<n;i++){ // 遍歷所有節點
            max=Math.max(max,s[i]); // 更新最大分支節點個數,取當前最大值與節點i所在集合大小的較大值
        }
        return max; // 返回最大分支節點個數
    }
    // 獲取連通分量個數
    public int getCount(){
        return count; // 直接返回連通分量個數
    }

}

Flody演算法

點選檢視程式碼
 	/**
     * 弗洛伊德演算法:任意兩點之間最短距離
     */
    public void floyd() {

        //對中間頂點遍歷
        for (int k = 0; k < dis.length; k++) {
            //從i頂點開始出發
            for (int i = 0; i < dis.length; i++) {
                //到達j頂點
                for (int j = 0; j < dis.length; j++) {
                    //求出從i頂點出發經過k到達j的距離
                   if(dis[i][k] + dis[k][j] < dis[i][j]) {
                       //更新距離
                       dis[i][j] = dis[i][k] + dis[k][j];
                }
            }
        }
    }

相關文章