拓撲排序
點選檢視程式碼
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];
}
}
}
}