1. 程式人生 > 其它 >【alg4-圖】無向圖

【alg4-圖】無向圖

技術標籤:演算法資料結構

無向圖

圖定義:圖是一組頂點和一組能夠將兩個頂點相連的邊組成的。
若邊僅僅是兩個頂點之間的連線,為了和其他圖模型相區別,我們稱為無向圖。

術語表

相鄰:當兩個頂點通過一條邊相連時,我們稱這兩個頂點是相鄰的,並稱這條邊依附於這兩個頂點。
度數:某個頂點的度數即為依附於它的邊的總數。
子圖:是由一幅圖的所有邊的一個子集(以及它們所依附的所有頂點)組成的圖。許多計算問題都需要識別各種型別的子圖,特別是由能夠順序連線一系列頂點的邊所組成的子圖。
路徑:是由邊順序連線的一系列頂點。
簡單路徑:是一條沒有重複頂點的路徑。
:是一條至少含有一條邊且起點和終點相同的路徑。
簡單環

:是一條(除了起點和終點必須相同之外)不含有重複頂點和邊的環。
長度:路徑或環的長度為其中所包含的邊數。
連通:當兩個頂點之間存在一條連線雙方的路徑時,我們稱一個頂點和另一個頂點是連通的。我們用類似u-v-w-x的記法來表示u到x的一條路徑,用u-v-w-x-u表示一條環。
連通圖:如果從任意一個頂點都存在一條路徑到達另一個任意頂點,我們稱這幅圖是連通圖。
非連通的圖:由若干連通部分組成,它們都是極大連通子圖。
無環圖:是一種不包含環的圖。
:是一幅無環連通圖。
森林:互不相連的樹組成的集合稱為森林。
生成樹:連通圖的生成樹是它的一幅子圖,它含有圖中的所有頂點且是一棵樹。
生成樹森林:是它的所有連通子圖的生成樹的集合。
在這裡插入圖片描述在這裡插入圖片描述在這裡插入圖片描述
當且僅當一幅含有V個結點的圖G滿足下列5個條件之一時,它就是一棵樹:

  • G有V-1條邊且不含有環;
  • G有V-1條邊且是連通的;
  • G是連通的,但刪除任意一條邊都會使它不再連通;
  • G是無環圖,但新增任意一條邊都會產生一條環;
  • G中的任意一對頂點之間僅存在一條簡單路徑。

圖的密度:是指已經連線的頂點對佔所有可能被連線的頂點對的比例。在稀疏圖中,被連線的頂點對很少;而在稠密圖中,只有少部分頂點對之間沒有邊連線。
二分圖:是一種能夠將所有結點分為兩部分的圖,其中圖的每條邊所連線的兩個頂點都分別屬於不同的部分。

圖的幾種表示方法

圖的表示方法(資料結構),應包含以下兩個要求:

  • 它必須為可能在應用中碰到的各種型別的圖預留出足夠的空間;
  • Graph的例項方法的實現一定要快——它們是開發處理圖的各種用例的基礎。

三種圖的表示:

  • 鄰接矩陣。我們可以使用一個V乘V的布林矩陣。當頂點v和頂點w之間有相連線的邊時,定義v行w列的元素值為true,否則為false。這種表示方法不符合第一個條件——含有上百萬個頂點的圖是很常見的,V^2個布林值所需的空間是不能滿足的。
  • 邊的陣列。我們可以使用一個Edge類,它含有兩個int例項變數。這種表示方法很簡潔但不滿足第二個條件——要實現adj()需要檢查圖中的所有邊。
  • 鄰接表陣列。我們可以使用一個以頂點為索引的列表陣列,其中的每個元素都是和該頂點相鄰的頂點列表。這種資料結構能夠同時滿足典型應用所需的以上兩個條件。如圖:

在這裡插入圖片描述

鄰接表的資料結構

非稠密圖的標準表示稱為鄰接表的資料結構,它將每個頂點的所有相鄰頂點都儲存在該頂點對應的元素所指向的一張連結串列中。我們使用這個陣列就是為了快速訪問給定頂點的鄰接頂點列表。

無向圖的API

API功能
Graph(int V)建立一個含有V個頂點但不含有邊的圖
Graph(int V, int E, int[][] data)通過引數構建一幅圖
int V()頂點數
int E()邊數
void addEdge(int v, int w)向圖中新增一條邊v-w
Iterable<Integer> adj(int v)和v相鄰的所有頂點
String toString()物件的字串表示

程式碼

Bag.java

package section1_3;

import java.util.Iterator;
import java.util.NoSuchElementException;

public class Bag<Item> implements Iterable<Item> {
    private Node<Item> first;
    private int n;

    private class Node<Item> {
        Item item;
        Node<Item> next;
    }

    public Bag() {
        first = null;
        n = 0;
    }

    public boolean isEmpty() {
        return first == null;
    }

    public int size() {
        return n;
    }

    public void add(Item item) {
        Node oldfirst = first;
        first = new Node<>();
        first.item = item;
        first.next = oldfirst;
        n++;
    }

    @Override
    public Iterator<Item> iterator() {
        return new LinkedIterator(first);
    }

    private class LinkedIterator implements Iterator<Item> {
        private Node<Item> current;

        public LinkedIterator(Node<Item> first) {
            current = first;
        }

        public boolean hasNext()  { return current != null;                     }
        public void remove()      { throw new UnsupportedOperationException();  }

        public Item next() {
            if (!hasNext()) throw new NoSuchElementException();
            Item item = current.item;
            current = current.next;
            return item;
        }
    }
}

Graph.java

package section4_1;

import section1_3.Bag;

public class Graph {

    private final int V;
    private int E;
    private Bag<Integer>[] adj;

    public Graph(int V) {
        this.V = V;
        adj = (Bag<Integer>[])new Bag[V];
        for (int v = 0;v < V;v++) {
            adj[v] = new Bag<>();
        }
    }

    public Graph(int V, int E, int[][] data) {
        this(V);
        int e = E;
        for (int i = 0;i < e;i++) {
            int v = data[i][0];
            int w = data[i][1];
            addEdge(v,w);
        }
    }

    public int V() { return V; }

    public int E() { return E; }

    public void addEdge(int v, int w) {
        adj[v].add(w);
        adj[w].add(v);
        E++;
    }

    public Iterable<Integer> adj(int v) {
        return adj[v];
    }

    public String toString() {
        String s = V + " vertices, " + E + " edges\n";
        for (int v = 0;v < V;v++) {
            s += v + ": ";
            for (int w : this.adj(v)) {
                s += w + " ";
            }
            s += "\n";
        }
        return s;
    }

    public static int degree(Graph G, int v) {
        int degree = 0;
        for (int w : G.adj(v)) {
            degree++;
        }
        return degree;
    }

    public static int maxDegree(Graph G) {
        int max = 0;
        for (int v = 0;v < G.V();v++) {
            if (degree(G,v) > max) {
                max = degree(G,v);
            }
        }
        return max;
    }

    public static double avgDegree(Graph G) {
        return 2.0 * G.E() /G.V();
    }

    public static int numberOfSelfLoops(Graph G) {
        int count = 0;
        for (int v = 0;v < G.V();v++) {
            for (int w : G.adj(v)) {
                if (v == w) count++;
            }
        }
        return count / 2;
    }

    public static void main(String[] args) {
        int[][] data = {
                {0,5},
                {4,3},
                {0,1},
                {9,12},
                {6,4},
                {5,4},
                {0,2},
                {11,12},
                {9,10},
                {0,6},
                {7,8},
                {9,11},
                {5,3}
        };
        int v = 13;
        int e = 13;
        Graph graph = new Graph(v,e,data);
        System.out.println("vertex of maximum degree = " + maxDegree(graph));
        System.out.println("average degree           = " + avgDegree(graph));
        System.out.println("number of self loops     = " + numberOfSelfLoops(graph));
        System.out.println(graph);
    }
}