圖系列(一)圖的表示與入度
雖然好像沒什麼人看,但是我還是寫一下,佛系。就當給自己做一個備忘錄好了!總算,進入到圖系列了。圖的部分,問題很多,算法很多,應用也很廣。圖的兩個比較重要的基石就是圖的表示和圖的遍歷。有了這兩個才能更好地搭建其他的算法。
圖的表示
我們知道G = (V, E),所以最原始的表示方式是,int n, int[][] edges。其中,n表示有n個節點,分別爲{0, 1, 2, 3, ..., n-1},edges表示所有的邊, edges = new int[n][2],edges[i]表示第i條邊,而edges[i][0]表示起點,edges[i][1]表示終點。有關面向對象的思考: 其實可以把edges看作是一個對象數組, 每一個對象edge=edges[i], 是int[2], 包含了兩個屬性edge[0]和edge[1],實際上並不需要顯式地進行class的定義。
鄰接鏈表法
本來想直接做後面的題目,但是這些基礎的操作沒有定義好,做後面的題目會比較麻煩。好的,我們開始介紹鄰接鏈表的使用吧。鄰接鏈表每一個元素是每個點相鄰的點組成的鏈表, 比如點0與1,2,3相鄰,那麼0的鄰接鏈表就是{1, 2, 3}。 下面給出代碼示例。
class Solution {
private List<Integer>[] adjs;
public void func1(int n, int[][] edges) {
adjs = new List[n]; // 數組初始化
for (int i = 0 ; i < n ; i++) {
adjs[i] = new LinkedList<>(); // 元素初始化
}
for (int i = 0; i < edges.length;i++) {
int[] edge = edges[i];
int from = edge[0];
int to = edge[1];
adjs[from].add(to); // 利用邊元素進行初始化
// 如果是無向圖
// adjs[to].add(from);
}
}
}
注意,上面使用的是LinkedList,原因是: 首先, 一般遍歷的時候,都是逐個遍歷的,並不需要按照下標來訪問元素,因此使用數組和使用鏈表沒有區別;其次, 給鏈表新增元素很容易。當然,如果你知道鄰接的元素不超過一定數量m時,你可以使用int[n][m+1] adjs, 其中adjs[i][0]表示stackSize, 而ajds[i][1]~adjs[i][m]是一個stack。見leetcode題目:不鄰接植花 。
另外,如果需要給每條邊加上weight,就需要使用對象了。
class Solution {
private List<Node>[] adjs;
public void func1(int n, int[][] edges) {
adjs = new List[n]; // 數組初始化
// 暫略
}
private class Node {
public int val;
public int weight;
public Node(int val, int weight) {
this.val = val;
this.weight = weight;
}
}
}
鄰接矩陣法
以後再寫
入度
入度的意思,也就是進入該點的邊的數量。入度的用途其實蠻大的,比如找出拓撲排序中的起點,或者判斷一些特殊的點。解題的時候,不妨從入度或者出度比較特殊的點開始。代碼如下:
class Solution {
public void calculateIndegree(int n, int[][] edges) {
int[] indegrees = new int[n];
for (int i = 0 ; i < edges.length;i++) {
int[] edge = edges[i];
int from = edge[0];
int to = edge[1];
indegrees[to] += 1;
}
}
}
見leetcode題目: 課程表 。