Day13

昨天終於證實了這兩天的疑惑:爲什麼我下載的這本數據結構和算法頁數這麼少?二叉樹部分明明沒有講完就開始下一章了,把那些頁數刪了還傳到網上的人也是有點兒可惡,唉,誰讓自己沒去買正版呢。。。先按照已有的內容把整本過一遍吧,之後再用另一本和做題的方法查漏補缺吧。。。


圖G(V, E)爲非線性結構,即互相之間均可存在二元關係的一組對象。從算法角度處理這類結構時,可通過遍歷將其轉化爲非線性結構,即爲樹,從而解決問題。
V爲頂點合集,E爲連接集合V中某一對定點(u, v)的邊的合集,V和E都是有限集,通常將其規模記爲 n = |V|, e = |E|。
無向邊:邊對應的頂點(u, v)的次序無所謂
有向邊:u和v的次序不對等。有向邊(u,v)表示從u指向v,u稱爲該邊的起點或尾頂點,v稱爲該邊的終點或頭頂點。
無向圖:E中各邊均無方向。
有向圖:E中只含有向邊。
混合圖:E同時包含無向邊和有向邊。
度數:在無向圖中與定點u關聯的邊數。
在有向圖中若e = (u, v), e稱作點u的出邊、點v的入邊,一個頂點的出邊的總數稱爲出度,入邊的總數成爲入度。
自環:連接於同一頂點的邊。
簡單圖:不含任何自環的圖。
路徑/通路:由m+1個頂點和m條邊交替而成的序列
π = {v0, e0, v1, e1 …… v(m-1), e(m), v(m)},
且對於任何 0 < i <= m都有 e(i) = (v(i-1), v(i)), m的總數成爲通路的長度,
記作 |π| = m。
簡化描述爲 π = {v0, v1 …… v(m)}。
簡單通路:沿途頂點互異的通路。
環路:對於m>=1的通路,起止頂點相同。
有向無環圖:不含有任何環路的有向圖。
簡單環路:除起止頂點相同外,沿途頂點互異的環路。
歐拉環路:經過圖中各邊一次且只有一次的環路。
哈密爾頓環路:經過途中各頂點一次且只有一次的環路。
帶權圖/帶權網絡/網絡:每一條邊都帶有權重的圖 G(V, E, wt())。
複雜度:對於無向圖,最多有 n(n-1)/2 條邊,有向圖最多有 n(n-1)條邊,所以複雜度 e = O(n(2))。
鄰接矩陣:矩陣A[n][n]表示由n個頂點構成的圖。對於無權圖,存在從點u到點v的邊,當且僅當A[u][v] = 1,不存在則爲0或∞。推廣到有權網絡可記錄邊的權重。鄰接矩陣的時間效率爲常數,空間效率最低爲O(n(2))。
鄰接表:由鄰接矩陣轉化可得。比矩陣效率高,尤其擅長批量處理同一頂點的所有關聯邊。

代碼參考:C# 鄰接表存儲結構C#有向圖拓撲排序

public class AdjacencyList<T>
{
    List<Vertex<T>> items;          //頂點集合
    List<KeyValuePair<Vertex<T>, Vertex<T>>> edges       //邊集合
    public AdjacencyList():this(10) {}   //構造函數
    public AdjacencyList(int capacity) { items = new List<Vertex<T>>(capacity)}          //指定容量的構造函數

    public class Vertex<TValue>          //表頭結點
    {
        public TValue data;
        public Node fistEdge;           //鄰接點鏈表頭指針
        public Boolean visited;         //記錄是否被訪問過
        public int InDegree;            //入度
        public int OutDegree;           //出度
        public VerTex(TValue value) { valuse = data; }
    }
    public class Node                    //表結點
    {
        public VerTex<T> adjver;         //鄰接點
        public Node next;                //下一個鄰接點指針
        public Node(Vertext<T> ver) { ver = adjver; }
    }

    public bool Contain(T item)
    {
        foreach(Vertex<T> v in items)
        {
            if(v.data.Equals(item))
            { return true; }
        }
        return false;
    }
    public Vertex<T> Find(T item)
    {
        foreach(Vertex<T> v in items)
        {
            if(v.data.Equals(item)
            { return v; }
        }
        return null;
    }
    public void AddVertex(T item)
    {
        if(!Contains(item))
        { 
            items.Add(new List<Vertex<T>>(item)); 
        }
    }
    public void AddDirectedEdge(T fromVer, T toVer)     //添加有向邊
    {
        if(fromVer.firstEdge == null)
        { 
            fromVer.firstEdge = new Node(toVer); 
        }
        else
        {
            Node temp, node = fromVer.firstEdge;
            do
            {
                if( !node.adjver.data.Equals(toVer.data)  //不能添加重複的邊
                {
                    tmp = node;
                    node = node.next;   
                }
            }while(node != null)
            tmp.next = new Node(toVer);    //添加到鏈表末尾
            edges.Add(new List<KeyValuePair<Vertex<T>, Vertex<T>>>(fromVer, toVer));
        }
    }
    public void AddNoDirectedEdge(T from, T to)         //添加無向邊
    {
        Vertex<T> fromVer = Find(from);
        Vertex<T> toVer = Find(to);
        if(fromVer != null && toVer != null)
        {
            AddDirectedEdge(fromVer, toVer);
            AddDirectedEdge(toVer, fromVer);
        }
    }
    public void RemoveEdge(Vertex<T> v)           //刪除點的出邊
    {
        int i = 0;
        while(edges.Count > 0)
        {
            if(v.data.Equals(edges[i].Key.data))
            {
                edges.RemoveAt(i);
                break;
            }
            i++;
        }
    }
    public void CountInOutDegrees()            //計算頂點的入度和出度
    {
        foreach(Vertex<T> v in items)
        {
            int inD = 0;
            int outD = 0;
            foreach(KeyValuePair<Vertex<T>, Vertex<T>> e in edges)
            {
                if(e.Key.data.Equals(v.data))
                {
                    outD++;
                }
                if(e.Value.data.Equals(v.data))
                {
                    inD++;  
                }
            }
            v.InDegree = inD;
            v.OutDegree = outD;
        }
    }
    public List<Vertex<T>> CycleExistOrNot()            //判斷是否有環路,有環路返回空,沒有環路返回點
    {
        foreach(Vertex<T> v in items)
        {
            if(v.InDegree == 0)
            {
                return v;
            }   
        }
        return null;
    }
}

圖搜索
波峯集:由所有已被訪問到的頂點中任未被訪問到的鄰居頂點構成。

廣度優先(BFS):
越早被訪問到的頂點,其鄰居越優先被選用。
即反覆在波峯集中查找最早被訪問到的頂點,若其鄰居均已被訪問到,則將該頂點逐出波峯集,否則任意選擇一個其尚未訪問到的鄰局訪問並將其加入波峯集。
(連通圖)

public void BFS(Vertex<T> v)
{
    print(v.data);
    v.visited = true;
    Queue<Vertex<T>> q = new Queue<Vertex<T>>();
    q.Enqueue(v);
    while(q.Any())
    {
        Vertex<T> nv = q.Dequeue();
        Node node = nv.firstEdge;
        while(node != null)
        {
            if(!node.adjver.visited)
            {
                print(node.adjver.data);
                node.adjver.visited = true;
                q.Enqueue(node.adjver);
            }
            node = node.next;
        }
    }
}

深度優先(DFS):
優先搜索最後一個被訪問到的頂點的鄰居。
各頂點被訪問的次序類似於樹的先序遍歷,各頂點被訪問完畢的次序類似於樹的後序遍歷。
(連通圖)

public void DFS(Vertex<T> v)
{
    print(v.data);
    v.visited = true;
    Node node = v.firstEdge;
    while(node != null)
    {
        if(!node.adjver.visited)
        {
            DFS(node.adjver);
        }
        node = node.next;
    }
}

非連通圖的廣度和深度遍歷就是以每個結點爲頂點遍歷整個鄰接表

public void BFS()
{
    foreach(Vertex<T> v in items)
    {
        if(!v.visited)
        {
            BFS(v);
        }   
    }
}
public void DFS()
{
    foreach(Vertex<T> v in items)
    {
        if(!v.visited)
        {
            DFS(v);
        }
    }
}

有向圖的拓撲排序:
在一個線性序列中,每一個頂點都不會通過邊指向其在該序列中的前驅點。
同一有向圖的拓撲排序未必唯一。
不含環路的有向無環圖,其拓撲排序一定存在。
過程:判斷圖中是否存在入度爲0的點,如果存在,記錄該點,然後將該點從圖中刪除,循環這一過程,直到所有點均被刪除,即得到一個排好序的結構。

public List<Vertex<T>> TopoSort()
{
    List<Vertex<T>> result = new List<Vertex<T>>();
    while(items.Count > 0)
    {
        List<Vertex<T>> tmp = CycleExistOrNot();
        if(tmp != null)
        {
            result.Add(tmp);
            items.Remove(tmp);
            RemoveEdge(tmp);
        }
    }
    return result;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章