导航图,无向稀疏连通图

8 篇文章 1 订阅

前言

我们上一篇描述了需求,这一篇详细地实现图类。

数据成员

public class SparseGraph:GraphRemote
    {
        protected Dictionary<int, object> _objects = new Dictionary<int, object>();
        protected List<VertexBase> _verts = new List<VertexBase>();
     }
  • 首先有两个protected成员,提供给子类使用。
  • _objects是存放实体的表,如果没有实体可以忽略。
  • _verts是用来存放顶点数组的,邻接表的数组部分

从xml加载

 public virtual bool LoadFromFile(string xmlname)
        {
            XmlDocument doc = new XmlDocument();

            string path = @"Assets/Resources/"+xmlname;

            try
            {
                doc.Load(path);
            }
            catch (Exception e)
            {
                MonoBehaviour.print(e);
                return false;
            }

            var root = doc.SelectSingleNode("ROOT");
            var vertList = root.ChildNodes;

            foreach (XmlNode vert in vertList)
            {
                //entity
                TestNode tn = new TestNode();
                VertexBase vertex = new VertexBase(this._objects);

                //id
                XmlNode idEle = vert.FirstChild;
                string idStr = idEle.InnerText;
                int idInt = 0;
                int.TryParse(idStr, out idInt);

                vertex.Index = idInt;
                this._objects.Add(idInt, tn);
                _verts.Add(vertex);

                //edges
                XmlNode edges = idEle.NextSibling;
                var edgeList = edges.ChildNodes;
                foreach (XmlNode edgeData in edgeList)
                {
                    //to
                    var toData = edgeData.FirstChild;
                    string s_edge_to = toData.InnerText;
                    int i_edge_to = 0;
                    int.TryParse(s_edge_to, out i_edge_to);

                    //cost
                    var costData = toData.NextSibling;
                    string s_edge_cost = costData.InnerText;
                    float f_edge_cost = 0.0f;
                    float.TryParse(s_edge_cost, out f_edge_cost);

                    //edge
                    EdgeBase edge = new EdgeBase();
                    edge.From = idInt;
                    edge.To = i_edge_to;
                    edge.Cost = f_edge_cost;

                    vertex.AddEdge(edge);
                }

                //type
                XmlNode nodeType = edges.NextSibling;
                string s_nt = nodeType.InnerText;
                tn.type = CommonUtils.SimpleFunctions.stringToType(s_nt);

                //pos
                XmlNode posData = nodeType.NextSibling;
                string s_pos = posData.InnerText;
                var posArr = s_pos.Split(',');
                float x = 0f;
                float y = 0f;
                float z = 0f;

                float.TryParse(posArr[0], out x);
                float.TryParse(posArr[1], out y);
                float.TryParse(posArr[2], out z);

                tn.pos = new Vector3(x, y, z);

                //extra info
            }

            calculateCostByDis();
            _verts.Sort();
            //re sort edges
            foreach (var v in _verts)
            {
                v.Edges.Sort();
            }

            return true;
        }
  • 从xml中实例图数据,可以自己定制,virtual以供重写。

这里我们提供一个xml表的样式:

<?xml version="1.0" encoding="utf-8"?>
<ROOT>
    <Vertex>
        <Idx>1</Idx>
        <Edges>
            <Edge>
                <To>2</To>
                <Cost>1</Cost>
            </Edge>
            <Edge>
                <To>3</To>
                <Cost>1</Cost>
            </Edge>
        </Edges>
        <NodeType>normal</NodeType>
        <Pos>0,0,0</Pos>
    </Vertex>

    <Vertex>
        <Idx>2</Idx>
        <Edges>
            <Edge>
                <To>3</To>
                <Cost>1</Cost>
            </Edge>
            <Edge>
                <To>5</To>
                <Cost>1</Cost>
            </Edge>
        </Edges>
        <NodeType>normal</NodeType>
        <Pos>10,0,0</Pos>
    </Vertex>

    <Vertex>
        <Idx>3</Idx>
        <Edges>
            <Edge>
                <To>1</To>
                <Cost>1</Cost>
            </Edge>
            <Edge>
                <To>2</To>
                <Cost>1</Cost>
            </Edge>
            <Edge>
                <To>4</To>
                <Cost>1</Cost>
            </Edge>
            <Edge>
                <To>6</To>
                <Cost>1</Cost>
            </Edge>
            <Edge>
                <To>7</To>
                <Cost>1</Cost>
            </Edge>
        </Edges>
        <NodeType>normal</NodeType>
        <Pos>10,0,10</Pos>
    </Vertex>

    <Vertex>
        <Idx>4</Idx>
        <Edges>
            <Edge>
                <To>3</To>
                <Cost>1</Cost>
            </Edge>
            <Edge>
                <To>5</To>
                <Cost>1</Cost>
            </Edge>
        </Edges>
        <NodeType>normal</NodeType>
        <Pos>21,0,4</Pos>
    </Vertex>

    <Vertex>
        <Idx>5</Idx>
        <Edges>
            <Edge>
                <To>2</To>
                <Cost>1</Cost>
            </Edge>
            <Edge>
                <To>4</To>
                <Cost>1</Cost>
            </Edge>
            <Edge>
                <To>8</To>
                <Cost>1</Cost>
            </Edge>
            <Edge>
                <To>9</To>
                <Cost>1</Cost>
            </Edge>
        </Edges>
        <NodeType>normal</NodeType>
        <Pos>11,0,-13</Pos>
    </Vertex>

    <Vertex>
        <Idx>6</Idx>
        <Edges>
            <Edge>
                <To>3</To>
                <Cost>1</Cost>
            </Edge>
        </Edges>
        <NodeType>normal</NodeType>
        <Pos>1,0,19</Pos>
    </Vertex>

    <Vertex>
        <Idx>7</Idx>
        <Edges>
            <Edge>
                <To>3</To>
                <Cost>1</Cost>
            </Edge>
        </Edges>
        <NodeType>normal</NodeType>
        <Pos>20,0,20</Pos>
    </Vertex>

    <Vertex>
        <Idx>8</Idx>
        <Edges>
            <Edge>
                <To>5</To>
                <Cost>1</Cost>
            </Edge>
        </Edges>
        <NodeType>normal</NodeType>
        <Pos>4,0,-22</Pos>
    </Vertex>

    <Vertex>
        <Idx>9</Idx>
        <Edges>
            <Edge>
                <To>5</To>
                <Cost>1</Cost>
            </Edge>
        </Edges>
        <NodeType>normal</NodeType>
        <Pos>29,0,-13</Pos>
    </Vertex>

</ROOT>

这个文件渲染出来的图(unity中)如下:
这里写图片描述

此处的cost都是1,因为我在程序里根据距离重新计算了

void calculateCostByDis()
        {
            for (int i = 0; i < _verts.Count; ++i)
            {
                var eachV = _verts[i];
                for (int j = 0; j < eachV.Edges.Count; ++j)
                {
                    var eachE = eachV.Edges[j];
                    float dis = Vector3.Distance((_objects[eachE.From] as TestNode).pos,
                        (_objects[eachE.To] as TestNode).pos);

                    eachE.Cost = dis;
                }
            }
        }

保存

和读取同理,此处省略。

添加和删除顶点

public bool AddVertex(TestNode refTn, VertexBase vert, int idx)
        {
            if ((refTn == null) || (vert == null))
            {
                return false;
            }

            if (_objects.ContainsKey(idx))
                return false;

            //注意此处将索引和实体同步,然后将顶点排序
            _objects.Add(idx, refTn);
            vert.Index = idx;
            _verts.Add(vert);
            _verts.Sort();
            return true;
        }

public bool RemoveVertex(int idx)
        {
            if (!_objects.ContainsKey(idx))
            {
                return false;
            }
            _objects.Remove(idx);

            object vertRef = null;
            foreach (VertexBase v in _verts)
            {
                if (v.Index == idx)
                {
                    vertRef = v;
                }
            }

            if (vertRef == null)
                return false;

            _verts.Remove(vertRef as VertexBase);
            return true;
        }

添加和删除边

注意数据验证,有些是不合理的,不允许添加或删除

public bool AddEdge(EdgeBase e)
        {
            if (_objects.ContainsKey(e.From))
            {
                foreach (VertexBase v in _verts)
                {
                    if (v.Index == e.From)
                    {
                        v.AddEdge(e);
                    }
                }
            }
            return false;
        }

public bool RemoveEdge(int from, int to)
        {
            if (!_objects.ContainsKey(from))
                return false;

            foreach (VertexBase v in _verts)
            {
                if (v.Index == from)
                {
                    foreach (EdgeBase e in v.Edges)
                    {
                        if (e.To == to)
                        {
                            v.Edges.Remove(e);
                            return true;
                        }
                    }
                }
            }

            return false;
        }

清空

使用索引的好处来了,清空极其方便。

public void Clear()
        {
            _objects.Clear();
            _verts.Clear();
        }

根据id获取顶点

虽然我们根据index对顶点进行了排序,但是一旦index不是连续的(比如过程中删除了一个顶点),我们就不能通过_verts[index-1]来访问(顶点从1开始,不是零)

public VertexBase GetVertByIdx(int index)
        {
            if (_verts[index - 1].Index == index)
            {
                return _verts[index - 1];
            }
            else
            {
                foreach (var v in _verts)
                {
                    if (v.Index == index)
                    {
                        return v;
                    }
                }
            }
            return null;
        }

To be continued…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值