diff --git a/Tests/Tests.csproj b/Tests/Tests.csproj index ce10de11..9427da51 100644 --- a/Tests/Tests.csproj +++ b/Tests/Tests.csproj @@ -1,4 +1,4 @@ - + @@ -49,6 +49,7 @@ + @@ -65,6 +66,10 @@ {3511528E-8696-40B8-85AB-97456347A497} csharp-algorithms + + {8087DFD2-673A-499F-B130-0FAE0F31EADC} + dijkstrasAlgorithm + {A9022928-E9E9-45BE-BFEC-85A1A870A7EB} selectionsort @@ -80,4 +85,4 @@ - + \ No newline at end of file diff --git a/Tests/greedy/DijkstrasAlgorithmTests.cs b/Tests/greedy/DijkstrasAlgorithmTests.cs new file mode 100644 index 00000000..2c5cb387 --- /dev/null +++ b/Tests/greedy/DijkstrasAlgorithmTests.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using dijkstrasalgorithm; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Tests.greedy +{ + [TestClass] + public class DijkstrasAlgorithmTests + { + [TestMethod] + public void GetShortestPathTest() + { + //Arrange + var nodes = CreateNodeDictionary(); + var expectedPath = new List {"A", "C", "E", "F"}; + const int expectedCost = 10; + + //Act + var dijkstrasAlgorithm = new DijkstrasAlgorithm(nodes.Values, "A"); + var shortestPath = dijkstrasAlgorithm.GetShortestPath("F"); + + //LogAndAssert + var actualPath = shortestPath.Select(node => node.Id).ToList(); + var expectedPathString = string.Join(" -> ", expectedPath); + var actualPathString = string.Join(" -> ", actualPath); + var actualCost = shortestPath[shortestPath.Count - 1].Cost; + Console.WriteLine($"expected -- Cost: {expectedCost} Path: {expectedPathString}"); + Console.WriteLine($"actual -- Cost: {actualCost} Path: {actualPathString}"); + Assert.AreEqual(expectedCost, actualCost); + Assert.AreEqual(expectedPath.Count, actualPath.Count); + Assert.IsTrue(expectedPath.Zip(actualPath, (e, a) => e == a).All(e => e)); + } + + private IReadOnlyDictionary CreateNodeDictionary() + { + var node1 = new Node("A"); + var node2 = new Node("B"); + var node3 = new Node("C"); + var node4 = new Node("D"); + var node5 = new Node("E"); + var node6 = new Node("F"); + + node1.AddEdge(new Edge(node2, 5)); + node1.AddEdge(new Edge(node3, 4)); + node1.AddEdge(new Edge(node4, 2)); + + node2.AddEdge(new Edge(node1, 5)); + node2.AddEdge(new Edge(node6, 6)); + node2.AddEdge(new Edge(node3, 2)); + + node3.AddEdge(new Edge(node2, 2)); + node3.AddEdge(new Edge(node1, 4)); + node3.AddEdge(new Edge(node4, 3)); + node3.AddEdge(new Edge(node5, 2)); + + node4.AddEdge(new Edge(node1, 2)); + node4.AddEdge(new Edge(node3, 3)); + node4.AddEdge(new Edge(node5, 6)); + + node5.AddEdge(new Edge(node4, 6)); + node5.AddEdge(new Edge(node3, 2)); + node5.AddEdge(new Edge(node6, 4)); + + node6.AddEdge(new Edge(node2, 6)); + node6.AddEdge(new Edge(node5, 4)); + + return new Dictionary + { + { node1.Id, node1 }, + { node2.Id, node2 }, + { node3.Id, node3 }, + { node4.Id, node4 }, + { node5.Id, node5 }, + { node6.Id, node6 } + }; + } + + } +} \ No newline at end of file diff --git a/csharp-algorithms.sln b/csharp-algorithms.sln index 8cc34265..50253092 100644 --- a/csharp-algorithms.sln +++ b/csharp-algorithms.sln @@ -17,6 +17,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "search", "search", "{F61757 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "selectionsort", "selectionsort\selectionsort.csproj", "{A9022928-E9E9-45BE-BFEC-85A1A870A7EB}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dijkstrasAlgorithm", "dijkstrasAlgorithm\dijkstrasAlgorithm.csproj", "{8087DFD2-673A-499F-B130-0FAE0F31EADC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -39,6 +41,10 @@ Global {A9022928-E9E9-45BE-BFEC-85A1A870A7EB}.Debug|Any CPU.Build.0 = Debug|Any CPU {A9022928-E9E9-45BE-BFEC-85A1A870A7EB}.Release|Any CPU.ActiveCfg = Release|Any CPU {A9022928-E9E9-45BE-BFEC-85A1A870A7EB}.Release|Any CPU.Build.0 = Release|Any CPU + {8087DFD2-673A-499F-B130-0FAE0F31EADC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8087DFD2-673A-499F-B130-0FAE0F31EADC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8087DFD2-673A-499F-B130-0FAE0F31EADC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8087DFD2-673A-499F-B130-0FAE0F31EADC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -46,6 +52,7 @@ Global GlobalSection(NestedProjects) = preSolution {C557EF5B-AEFE-407B-8D99-43B9EA625B71} = {6A9C8607-AA57-4817-B2C8-B8DD5065AC7C} {A9022928-E9E9-45BE-BFEC-85A1A870A7EB} = {6A9C8607-AA57-4817-B2C8-B8DD5065AC7C} + {8087DFD2-673A-499F-B130-0FAE0F31EADC} = {05BBB622-53C5-4866-869B-B45978502CB5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {7F2BFC66-A9D6-4C6D-A15A-984F23C11D29} diff --git a/dijkstrasAlgorithm/DijkstrasAlgorithm.cs b/dijkstrasAlgorithm/DijkstrasAlgorithm.cs new file mode 100644 index 00000000..f21a7663 --- /dev/null +++ b/dijkstrasAlgorithm/DijkstrasAlgorithm.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; +using System.Linq; + +namespace dijkstrasalgorithm +{ + public class DijkstrasAlgorithm + { + private readonly IReadOnlyDictionary _nodes; + + public DijkstrasAlgorithm(IEnumerable nodes, string startId) + { + var nodeArray = nodes.ToArray(); + _nodes = nodeArray.ToDictionary(node => node.Id, node => node); + Resolve(startId); + } + + public List GetShortestPath(string endId) + { + var currentNode = _nodes[endId]; + var endToStartPath = new List(); + + while (true) + { + endToStartPath.Add(currentNode); + if (currentNode.PreviousNode == null) break; + currentNode = currentNode.PreviousNode; + } + + return Enumerable.Reverse(endToStartPath).ToList(); + } + + private void Resolve(string startId) + { + _nodes[startId].Cost = 0; + var destinationNodes = new Queue(); + destinationNodes.Enqueue(_nodes[startId]); + + do + { + var currentNode = destinationNodes.Dequeue(); + if (currentNode.Visited) continue; + + foreach (var edge in currentNode.Edges) + { + var node = edge.Node; + var cost = currentNode.Cost + edge.Cost; + + if (node.Cost > cost) + { + node.Cost = cost; + node.PreviousNode = currentNode; + } + + if (!node.Visited) destinationNodes.Enqueue(node); + } + + currentNode.Visited = true; + } while (destinationNodes.Any()); + } + } +} diff --git a/dijkstrasAlgorithm/Edge.cs b/dijkstrasAlgorithm/Edge.cs new file mode 100644 index 00000000..96b4a4ac --- /dev/null +++ b/dijkstrasAlgorithm/Edge.cs @@ -0,0 +1,14 @@ +namespace dijkstrasalgorithm +{ + public class Edge + { + public Edge(Node node, int cost) + { + Node = node; + Cost = cost; + } + + public Node Node { get; } + public int Cost { get; } + } +} \ No newline at end of file diff --git a/dijkstrasAlgorithm/Node.cs b/dijkstrasAlgorithm/Node.cs new file mode 100644 index 00000000..5b700452 --- /dev/null +++ b/dijkstrasAlgorithm/Node.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; + +namespace dijkstrasalgorithm +{ + public class Node + { + public Node(string id) + { + Id = id; + } + + public string Id { get; } + public HashSet Edges { get; } = new HashSet(); + public Node PreviousNode { get; set; } + public bool Visited { get; set; } + public int Cost { get; set; } = int.MaxValue; + + public void AddEdge(Edge edge) + { + Edges.Add(edge); + } + } +} \ No newline at end of file diff --git a/dijkstrasAlgorithm/Properties/AssemblyInfo.cs b/dijkstrasAlgorithm/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..c69a5e6c --- /dev/null +++ b/dijkstrasAlgorithm/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// アセンブリに関する一般情報は以下の属性セットをとおして制御されます。 +// アセンブリに関連付けられている情報を変更するには、 +// これらの属性値を変更してください。 +[assembly: AssemblyTitle("dijkstrasAlgorithm")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("dijkstrasAlgorithm")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// ComVisible を false に設定すると、このアセンブリ内の型は COM コンポーネントから +// 参照できなくなります。COM からこのアセンブリ内の型にアクセスする必要がある場合は、 +// その型の ComVisible 属性を true に設定してください。 +[assembly: ComVisible(false)] + +// このプロジェクトが COM に公開される場合、次の GUID が typelib の ID になります +[assembly: Guid("8087dfd2-673a-499f-b130-0fae0f31eadc")] + +// アセンブリのバージョン情報は次の 4 つの値で構成されています: +// +// メジャー バージョン +// マイナー バージョン +// ビルド番号 +// Revision +// +// すべての値を指定するか、次を使用してビルド番号とリビジョン番号を既定に設定できます +// 以下のように '*' を使用します: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/dijkstrasAlgorithm/dijkstrasAlgorithm.csproj b/dijkstrasAlgorithm/dijkstrasAlgorithm.csproj new file mode 100644 index 00000000..1f5970d7 --- /dev/null +++ b/dijkstrasAlgorithm/dijkstrasAlgorithm.csproj @@ -0,0 +1,50 @@ + + + + + Debug + AnyCPU + {8087DFD2-673A-499F-B130-0FAE0F31EADC} + Library + Properties + dijkstrasAlgorithm + dijkstrasAlgorithm + v4.6.1 + 512 + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + \ No newline at end of file