Day13

1 篇文章 0 订阅

昨天终于证实了这两天的疑惑:为什么我下载的这本数据结构和算法页数这么少?二叉树部分明明没有讲完就开始下一章了,把那些页数删了还传到网上的人也是有点儿可恶,唉,谁让自己没去买正版呢。。。先按照已有的内容把整本过一遍吧,之后再用另一本和做题的方法查漏补缺吧。。。


图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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值