第6章 图

6.2.2 邻接表

邻接表(Adjacency List)是图的一种顺序存储与链式存储相结合的存储结构,类似于与树的孩子链表表示法。顺序存储指的是图中的顶点信息用一个顶点数组来存储,一个顶点数组元素是一个顶点结点,顶点节点有两个域,一个是数据域,存放与结点相关的信息,一个是引用域firstAdj。顶点的邻接表示把所有邻接于某顶点的顶点构成一个表,它是采用链式存储结构。所以,我们说邻接表是图的一种顺序存储与链式存储相结合的存储结构。

上图的邻接表如下,可以看出每个邻接点代表一个弧。如果是无向图,可以看成是特殊的有向图来表示。

邻接表的C#代码实现:

using System;

namespace GraphObject
{
    //Graph node class
    public class GraphNode<T>
    {
        public T Value { get; set; }

        public GraphNode(T value)
        {
            Value = value;
        }
    }

    //Actions of graph
    public interface IGraph<T>
    {
        int NodeNum { get; }
        int EdageNum { get; }

        int IsNode(GraphNode<T> node);
        bool SetNode(GraphNode<T> node);
        bool DelNode(GraphNode<T> node);

        bool SetEdge(GraphNode<T> node1, GraphNode<T> node2, int value);
        bool DelEdge(GraphNode<T> node1, GraphNode<T> node2);
        bool IsEdge(GraphNode<T> node1, GraphNode<T> node2);
    }

    //邻接结点类
    public class AdjListNode<T>
    {
        public int AdjVexIndex { get; set; }
        public int Weight { get; set; }
        public AdjListNode<T> Next { get; set; }

        public AdjListNode(int vexIndex, int weight)
        {
            this.AdjVexIndex = vexIndex;
            this.Weight = weight;
            this.Next = null;
        }
    }

    //邻接根结点类
    public class VexListNode<T>
    {
        public GraphNode<T> Node { get; set; }
        public AdjListNode<T> FirstAdj { get; set; }

        public VexListNode(GraphNode<T> node)
        {
            Node = node;
            FirstAdj = null;
        }
    }

    public class GraphAdjList<T> : IGraph<T>
    {
        private VexListNode<T>[] vexList;

        public int NodeNum { get; private set; }
        public int EdageNum { get; private set; }

        public GraphAdjList(int length)
        {
            vexList = new VexListNode<T>[length];
        }

        public int IsNode(GraphNode<T> node)
        {
            for (int i = 0; i < NodeNum; i++)
            {
                if (vexList[i].Node == node)
                    return i;
            }

            return -1;
        }

        public bool SetNode(GraphNode<T> node)
        {
            if (IsNode(node) != -1)
                return false;

            VexListNode<T> vex = new VexListNode<T>(node);
            vexList[NodeNum] = vex;
            NodeNum += 1;
            return true;       
        }

        public bool DelNode(GraphNode<T> node)
        {
            int vexIndex = IsNode(node);

            if (vexIndex == -1)
                return false;

            AdjListNode<T> adjNode = vexList[vexIndex].FirstAdj;
            if (adjNode != null)
                EdageNum -= 1;

            while (adjNode.Next != null)
            {
                adjNode = adjNode.Next;
                EdageNum -= 1;
            }

            vexList[vexIndex] = vexList[NodeNum - 1];
            vexList[NodeNum - 1] = null;
            NodeNum -= 1;

            for (int i = 0; i < NodeNum; i++)
            {
                VexListNode<T> vexNode = vexList[i];
               adjNode = vexNode.FirstAdj;

                if (adjNode != null)
                {
                    if (adjNode.AdjVexIndex == vexIndex)
                    {
                        vexNode.FirstAdj = adjNode.Next;
                        EdageNum -= 1;
                    }
                    else if (adjNode.AdjVexIndex == NodeNum)
                        adjNode.AdjVexIndex = vexIndex;
                }

                while (adjNode != null && adjNode.Next != null)
                {
                    if (adjNode.Next.AdjVexIndex == vexIndex)
                    {
                        adjNode.Next = adjNode.Next.Next;
                        EdageNum -= 1;
                    }
                    else
                    {
                        if (adjNode.Next.AdjVexIndex == NodeNum)
                            adjNode.Next.AdjVexIndex = vexIndex;

                        adjNode = adjNode.Next;
                    }
                   
                }
            }

            return true;
        }

        public bool SetEdge(GraphNode<T> node1, GraphNode<T> node2, int value)
        {
            int vexIndex1 = IsNode(node1);
            int vexIndex2 = IsNode(node2);

            if (vexIndex1 == -1 || vexIndex2 == -1)
                return false;

            if (IsEdge(node1, node2))
                return false;

            AdjListNode<T> adjNode = new AdjListNode<T>(vexIndex2, value);
            adjNode.Next = vexList[vexIndex1].FirstAdj;
            vexList[vexIndex1].FirstAdj = adjNode;
            EdageNum += 1;

            return true;
        }

        public bool DelEdge(GraphNode<T> node1, GraphNode<T> node2)
        {
            if (!IsEdge(node1, node2))
                return false;

            int vexIndex1 = IsNode(node1);
            int vexIndex2 = IsNode(node2);

            VexListNode<T> vexNode = vexList[vexIndex1];
            AdjListNode<T> adj = vexNode.FirstAdj;

            if (adj.AdjVexIndex == vexIndex2)
            {
                vexNode.FirstAdj = adj.Next;
                EdageNum -= 1;
                return true;
            }

            while (adj.Next != null)
            {
                if (adj.Next.AdjVexIndex == vexIndex2)
                {
                    adj.Next = adj.Next.Next;
                    EdageNum -= 1;
                    return true;
                }
                else
                    adj = adj.Next;
            }

            return false;
        }

        public bool IsEdge(GraphNode<T> node1, GraphNode<T> node2)
        {
            int vexIndex1 = IsNode(node1);
            int vexIndex2 = IsNode(node2);

            if (vexIndex1 == -1 || vexIndex2 == -1)
                return false;

            VexListNode<T> vexNode = vexList[vexIndex1];
            AdjListNode<T> adjNode = vexNode.FirstAdj;

            if (adjNode == null)
                return false;

            if (adjNode.AdjVexIndex == vexIndex2)
                return true;

            while (adjNode.Next != null)
            {
                if (adjNode.Next.AdjVexIndex == vexIndex2)
                    return true;
                else
                    adjNode = adjNode.Next;
            }

            return false;
        }

        public void PrintGraphAdjList()
        {
            for (int i = 0; i < NodeNum; i++)
            {
                VexListNode<T> vexNode = vexList[i];
                AdjListNode<T> adjNode = vexNode.FirstAdj;

                Console.Write(vexNode.Node.Value);

                while (adjNode != null)
                {
                    Console.Write(" --(");
                    Console.Write(adjNode.Weight);
                    Console.Write(")--> ");
                    vexNode = vexList[adjNode.AdjVexIndex];
                    Console.Write(vexNode.Node.Value);

                    adjNode = adjNode.Next;
                }

                Console.WriteLine();
            }
        }
    }
  
}


验证代码:

using GraphObject;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            GraphAdjList<int> adjList = new GraphAdjList<int>(100);

            //Inial graph object
            GraphNode<int> node1 = new GraphNode<int>(1);
            GraphNode<int> node2 = new GraphNode<int>(2);
            GraphNode<int> node3 = new GraphNode<int>(3);
            GraphNode<int> node4 = new GraphNode<int>(4);
            GraphNode<int> node5 = new GraphNode<int>(5);
            GraphNode<int> node6 = new GraphNode<int>(6);
            GraphNode<int> node7 = new GraphNode<int>(7);
            GraphNode<int> node8 = new GraphNode<int>(8);

            adjList.SetNode(node1);
            adjList.SetNode(node2);
            adjList.SetNode(node3);
            adjList.SetNode(node4);
            adjList.SetNode(node5);
            adjList.SetNode(node6);
            adjList.SetNode(node7);
            adjList.SetNode(node8);

            adjList.SetEdge(node2, node1, 2);
            adjList.SetEdge(node3, node1, 3);
            adjList.SetEdge(node2, node3, 4);
            adjList.SetEdge(node3, node4, 5);
            adjList.SetEdge(node5, node6, 4);
            adjList.SetEdge(node8, node6, 1);

            Assert.AreEqual<int>(8, adjList.NodeNum);
            Assert.AreEqual<int>(6, adjList.EdageNum);

            //Scenario 1: Test add new node
            GraphNode<int> node9 = new GraphNode<int>(9);
            adjList.SetNode(node9);
            adjList.SetEdge(node9, node5, 3);
            adjList.SetEdge(node9, node8, 1);
            adjList.SetEdge(node6, node9, 2);

            Assert.AreEqual<int>(9, adjList.NodeNum);
            Assert.AreEqual<int>(9, adjList.EdageNum);
            adjList.PrintGraphAdjList();

            //Scenario 2: Test remove node
            adjList.DelNode(node8);
            Assert.AreEqual<int>(8, adjList.NodeNum);
            Assert.AreEqual<int>(7, adjList.EdageNum);

            adjList.SetNode(node8);
            adjList.SetEdge(node8, node6, 1);
            adjList.SetEdge(node9, node8, 1);
            Assert.AreEqual<int>(9, adjList.NodeNum);
            Assert.AreEqual<int>(9, adjList.EdageNum);

            //Scenario 3: Test add/remove new edage
            adjList.DelEdge(node3, node4);
            Assert.AreEqual<int>(9, adjList.NodeNum);
            Assert.AreEqual<int>(8, adjList.EdageNum);
            adjList.SetEdge(node3, node4, 5);
            Assert.AreEqual<int>(9, adjList.NodeNum);
            Assert.AreEqual<int>(9, adjList.EdageNum);

            //Scenario 4: Other medthods
            Assert.IsTrue(adjList.IsNode(node4) >= 0, "node4 should be exist in matrix");
            Assert.IsFalse(adjList.IsNode(new GraphNode<int>(10)) >= 0, "node4 should not be exist in matrix");
            Assert.IsTrue(adjList.IsEdge(node3, node1), "edage should be exist in matrix");
            Assert.IsFalse(adjList.IsEdge(node3, node2), "edage should not be exist in matrix");
        }
    }
}


上述代码的类结构图如下:

上述代码的类关系图如下:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值