diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4a3e801 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/.idea +.env + +/bin +/obj \ No newline at end of file diff --git a/Program.cs b/Program.cs index ca40a0a..ead3de5 100644 --- a/Program.cs +++ b/Program.cs @@ -1,9 +1,30 @@ // See https://aka.ms/new-console-template for more information -using algorithms_cs.Algorithm.Sort.External.Merge; +using algorithms_cs.Algorithm.Sort.External.SeriesMerge; const int numberWays = 4; -const string pathFile = "E:\\projects\\algorithms-cs\\resource\\1.test"; +const string pathFile = "E:\\projects\\algorithms-cs\\resource\\4.txt"; var sort = new MultiwaySort(numberWays, pathFile); -sort.Start(); \ No newline at end of file +sort.Start(); + +// +// var test = new BufferedTapeReader(pathFile); +// var test2 = new TapeCollection(pathFile); +// var ss = new SeriesEnumerable(test); +// +// foreach (var VARIABLE in test2) +// { +// Console.WriteLine(VARIABLE); +// } +// +// while (!ss.IsEnd) +// { +// foreach (var VARIABLE in ss) +// { +// Console.WriteLine($"{VARIABLE.GetType()} {VARIABLE.GetValue()}"); +// } +// Console.WriteLine(); +// } + + diff --git a/TestAlgorithms-cs/.gitignore b/TestAlgorithms-cs/.gitignore new file mode 100644 index 0000000..1f3df4f --- /dev/null +++ b/TestAlgorithms-cs/.gitignore @@ -0,0 +1,2 @@ +/bin +/obj \ No newline at end of file diff --git a/TestAlgorithms-cs/TestAlgorithms-cs.csproj b/TestAlgorithms-cs/TestAlgorithms-cs.csproj new file mode 100644 index 0000000..6f512d2 --- /dev/null +++ b/TestAlgorithms-cs/TestAlgorithms-cs.csproj @@ -0,0 +1,22 @@ + + + + net6.0 + TestAlgorithms_cs + enable + + false + + + + + + + + + + + + + + diff --git a/TestAlgorithms-cs/TestTape.cs b/TestAlgorithms-cs/TestTape.cs new file mode 100644 index 0000000..2be9406 --- /dev/null +++ b/TestAlgorithms-cs/TestTape.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using algorithms_cs.Utils; +using algorithms_cs.Utils.Tape; + +namespace TestAlgorithms_cs; + +public class TestTape +{ + private const string PathResources = "../../../resource/"; + + [Test] + public void TestDefaultInitialization() + { + var utilReturn = new UtilReturn(); + + Assert.That(utilReturn.GetType() == UtilReturnType.TapeEnded); + } + + [Test] + public void TestInitializationWithValue() + { + const double value = (double)20; + var utilReturn = new UtilReturn(value); + + Assert.That(utilReturn.GetType() == UtilReturnType.Correct && Math.Abs(utilReturn.GetValue() - value) == 0); + } + + [Test] + public void TestTapeReader() + { + string path = PathResources + "4.test"; + + var answer = new List + { + -10, + -9.0, + -8.0, + -7.0012, + -6.0012, + 5, + 4.12, + 3.12 + }; + + var tapeResponse = new List(); + + var tape = new TapeReader(path); + + for (int i = 0; i < 8; i++) + { + tapeResponse.Add(tape.Next().GetValue()); + } + + Assert.AreEqual(tapeResponse, answer); + } +} \ No newline at end of file diff --git a/TestAlgorithms-cs/UnitTest1.cs b/TestAlgorithms-cs/UnitTest1.cs new file mode 100644 index 0000000..3333f00 --- /dev/null +++ b/TestAlgorithms-cs/UnitTest1.cs @@ -0,0 +1,19 @@ +using NUnit.Framework; + +namespace TestAlgorithms_cs; + +public class Tests +{ + [SetUp] + public void Setup() + { + } + + [Test] + public void Test1() + { + + + Assert.Pass(); + } +} \ No newline at end of file diff --git a/resource/1.test b/TestAlgorithms-cs/resource/1.test similarity index 100% rename from resource/1.test rename to TestAlgorithms-cs/resource/1.test diff --git a/resource/2.test b/TestAlgorithms-cs/resource/2.test similarity index 100% rename from resource/2.test rename to TestAlgorithms-cs/resource/2.test diff --git a/resource/3.test b/TestAlgorithms-cs/resource/3.test similarity index 100% rename from resource/3.test rename to TestAlgorithms-cs/resource/3.test diff --git a/TestAlgorithms-cs/resource/4.test b/TestAlgorithms-cs/resource/4.test new file mode 100644 index 0000000..19422c1 --- /dev/null +++ b/TestAlgorithms-cs/resource/4.test @@ -0,0 +1 @@ +-10 -9,0 -8.0 -7.0012 -6,0012 5 4.12 3,12 \ No newline at end of file diff --git a/algorithms-cs.sln b/algorithms-cs.sln index cc29e40..cbe0f9e 100644 --- a/algorithms-cs.sln +++ b/algorithms-cs.sln @@ -1,6 +1,8 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "algorithms-cs", "algorithms-cs.csproj", "{C310C318-7B2D-4C1C-AC20-23D3FDD31A9E}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "algorithms-cs", "algorithms-cs\algorithms-cs.csproj", "{91495899-7D40-4543-93B9-820F92C61B31}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestAlgorithms-cs", "TestAlgorithms-cs\TestAlgorithms-cs.csproj", "{FAC8701B-6897-488A-B78F-660E8B47FC25}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -8,9 +10,13 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C310C318-7B2D-4C1C-AC20-23D3FDD31A9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C310C318-7B2D-4C1C-AC20-23D3FDD31A9E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C310C318-7B2D-4C1C-AC20-23D3FDD31A9E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C310C318-7B2D-4C1C-AC20-23D3FDD31A9E}.Release|Any CPU.Build.0 = Release|Any CPU + {91495899-7D40-4543-93B9-820F92C61B31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {91495899-7D40-4543-93B9-820F92C61B31}.Debug|Any CPU.Build.0 = Debug|Any CPU + {91495899-7D40-4543-93B9-820F92C61B31}.Release|Any CPU.ActiveCfg = Release|Any CPU + {91495899-7D40-4543-93B9-820F92C61B31}.Release|Any CPU.Build.0 = Release|Any CPU + {FAC8701B-6897-488A-B78F-660E8B47FC25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FAC8701B-6897-488A-B78F-660E8B47FC25}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FAC8701B-6897-488A-B78F-660E8B47FC25}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FAC8701B-6897-488A-B78F-660E8B47FC25}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/algorithms-cs/.gitignore b/algorithms-cs/.gitignore new file mode 100644 index 0000000..1f3df4f --- /dev/null +++ b/algorithms-cs/.gitignore @@ -0,0 +1,2 @@ +/bin +/obj \ No newline at end of file diff --git a/algorithms-cs/Program.cs b/algorithms-cs/Program.cs new file mode 100644 index 0000000..6c91521 --- /dev/null +++ b/algorithms-cs/Program.cs @@ -0,0 +1,30 @@ +using algorithms_cs.Algorithm.Sort.External.SeriesMerge; + +const int numberWays = 4; +const string pathFile = "@\\algorithms-cs\\resource\\4.txt"; + +Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory); + +var sort = new MultiwaySort(numberWays, pathFile); +// sort.Start(); + + + +// +// var test = new BufferedTapeReader(pathFile); +// var test2 = new TapeCollection(pathFile); +// var ss = new SeriesEnumerable(test); +// +// foreach (var VARIABLE in test2) +// { +// Console.WriteLine(VARIABLE); +// } +// +// while (!ss.IsEnd) +// { +// foreach (var VARIABLE in ss) +// { +// Console.WriteLine($"{VARIABLE.GetType()} {VARIABLE.GetValue()}"); +// } +// Console.WriteLine(); +// } \ No newline at end of file diff --git a/algorithms-cs.csproj b/algorithms-cs/algorithms-cs.csproj similarity index 83% rename from algorithms-cs.csproj rename to algorithms-cs/algorithms-cs.csproj index 9d15e46..4057b1c 100644 --- a/algorithms-cs.csproj +++ b/algorithms-cs/algorithms-cs.csproj @@ -6,7 +6,6 @@ algorithms_cs enable enable - Windows diff --git a/src/Algorithm/Sort/External/Merge/Collector.cs b/algorithms-cs/src/Algorithm/Sort/External/SeriesMerge/Collector.cs similarity index 71% rename from src/Algorithm/Sort/External/Merge/Collector.cs rename to algorithms-cs/src/Algorithm/Sort/External/SeriesMerge/Collector.cs index 9528a24..78e8209 100644 --- a/src/Algorithm/Sort/External/Merge/Collector.cs +++ b/algorithms-cs/src/Algorithm/Sort/External/SeriesMerge/Collector.cs @@ -1,23 +1,23 @@ -using System.Diagnostics; -using algorithms_cs.Serial; +using algorithms_cs.Utils; +using algorithms_cs.Utils.Serial; -namespace algorithms_cs.Algorithm.Sort.External.Merge; +namespace algorithms_cs.Algorithm.Sort.External.SeriesMerge; internal struct MinReturn { - public SeriesReturn Element; + public UtilReturn Element; public int Index; } public class Collector { private readonly List _seriesCollection; - private readonly List> _bufferSeriesReturns; + private readonly List> _bufferSeriesReturns; public Collector(List seriesCollection) { _seriesCollection = seriesCollection; - _bufferSeriesReturns = new List>(); + _bufferSeriesReturns = new List>(); foreach (var seriesReturn in _seriesCollection) { _bufferSeriesReturns.Add(seriesReturn.Next()); @@ -36,7 +36,7 @@ private MinReturn Min() for (var i = 0; i < _bufferSeriesReturns.Count; i++) { - if (_bufferSeriesReturns[i].GetType() == SeriesReturnType.Correct + if (_bufferSeriesReturns[i].GetType() == UtilReturnType.Correct && value > _bufferSeriesReturns[i].GetValue()) { value = _bufferSeriesReturns[i].GetValue(); @@ -48,16 +48,16 @@ private MinReturn Min() return minReturn; } - private bool IsEmpty() => _bufferSeriesReturns.All(x => x.GetType() != SeriesReturnType.Correct); + private bool IsEmpty() => _bufferSeriesReturns.All(x => x.GetType() != UtilReturnType.Correct); - public bool TapeEnded() => _bufferSeriesReturns.All(x => x.GetType() == SeriesReturnType.TapeEnded); + public bool TapeEnded() => _bufferSeriesReturns.All(x => x.GetType() == UtilReturnType.TapeEnded); - public SeriesReturn Next() + public UtilReturn Next() { // Returns minimal Correct value from multiple Series, else returns SeriesEnd var seriesEnded = IsEmpty(); - if (seriesEnded) return new SeriesReturn(SeriesReturnType.SeriesEnded); + if (seriesEnded) return new UtilReturn(UtilReturnType.SeriesEnded); var minElement = Min(); diff --git a/src/Algorithm/Sort/External/Merge/MergeSort.cs b/algorithms-cs/src/Algorithm/Sort/External/SeriesMerge/ExternalSeriesMergeSort.cs similarity index 86% rename from src/Algorithm/Sort/External/Merge/MergeSort.cs rename to algorithms-cs/src/Algorithm/Sort/External/SeriesMerge/ExternalSeriesMergeSort.cs index 60515e9..4fc9f3a 100644 --- a/src/Algorithm/Sort/External/Merge/MergeSort.cs +++ b/algorithms-cs/src/Algorithm/Sort/External/SeriesMerge/ExternalSeriesMergeSort.cs @@ -1,15 +1,16 @@ -using algorithms_cs.Serial; -using algorithms_cs.Tape; +using algorithms_cs.Utils; +using algorithms_cs.Utils.Serial; +using algorithms_cs.Utils.Tape; -namespace algorithms_cs.Algorithm.Sort.External.Merge; +namespace algorithms_cs.Algorithm.Sort.External.SeriesMerge; -public class MultiwaySort: Sort +public class MultiwaySort { private readonly string _sourceFilePath; private readonly string _tempDirectory; private readonly int _n; private RotatingDominoes _dominoes; - private List _tapes; + private List _tapes; private readonly string _templateNameFiles; public MultiwaySort(int N, string sourceFilePath) @@ -25,7 +26,7 @@ public MultiwaySort(int N, string sourceFilePath) _templateNameFiles = _tempDirectory + "tempfile-{0}.multiwaymergesort"; Directory.CreateDirectory(_tempDirectory); - _tapes = new List(); + _tapes = new List(); _n = N; var firstFilenames = new List(); @@ -57,7 +58,7 @@ public void Start() private void TrashDelete(string outFilename) { - File.Copy(outFilename, _sourceFilePath+"-sorted"); + if (!File.Exists(_sourceFilePath+"-sorted")) File.Copy(outFilename, _sourceFilePath+"-sorted"); foreach (var filename in _dominoes.ReadFilenames) { File.Delete(filename); @@ -76,26 +77,25 @@ private void InitTapeSplit() var tapeWrites = _dominoes.WriteFilenames.Select(filename => new TapeWriter(filename)).ToList(); var indexTape = 0; - if (indexTape >= _n) throw new IndexOutOfRangeException("indexTape out of range tapeWrites"); var s1 = new Series(initTape); - SeriesReturn value; + UtilReturn value; do { do { value = s1.Next(); - if (value.GetType() == SeriesReturnType.Correct) + if (value.GetType() == UtilReturnType.Correct) { tapeWrites[indexTape].Write(value.GetValue()); } - } while (value.GetType() == SeriesReturnType.Correct); + } while (value.GetType() == UtilReturnType.Correct); indexTape += 1; if (indexTape >= _n) indexTape = 0; s1 = new Series(initTape); - } while (value?.GetType() != SeriesReturnType.TapeEnded); + } while (value?.GetType() != UtilReturnType.TapeEnded); foreach (var tape in tapeWrites) { @@ -131,17 +131,17 @@ private int MainRound() var multipleSeries = new List(); multipleSeries.AddRange(readTapes.Select(tape => new Series(tape))); var collector = new Collector(multipleSeries); - SeriesReturn value; + UtilReturn value; do { do { value = collector.Next(); - if (value.GetType() == SeriesReturnType.Correct) + if (value.GetType() == UtilReturnType.Correct) { writeTapes[indexTape].Write(value.GetValue()); } - } while (value.GetType() == SeriesReturnType.Correct); + } while (value.GetType() == UtilReturnType.Correct); count++; if (count > 2) count = 2; diff --git a/src/Algorithm/Sort/External/Merge/RotatingDominoes.cs b/algorithms-cs/src/Algorithm/Sort/External/SeriesMerge/RotatingDominoes.cs similarity index 89% rename from src/Algorithm/Sort/External/Merge/RotatingDominoes.cs rename to algorithms-cs/src/Algorithm/Sort/External/SeriesMerge/RotatingDominoes.cs index b7bcf8c..4ecc625 100644 --- a/src/Algorithm/Sort/External/Merge/RotatingDominoes.cs +++ b/algorithms-cs/src/Algorithm/Sort/External/SeriesMerge/RotatingDominoes.cs @@ -1,4 +1,4 @@ -namespace algorithms_cs.Algorithm.Sort.External.Merge; +namespace algorithms_cs.Algorithm.Sort.External.SeriesMerge; public class RotatingDominoes { diff --git a/algorithms-cs/src/Algorithm/Sort/External/SeriesMerge/readme.md b/algorithms-cs/src/Algorithm/Sort/External/SeriesMerge/readme.md new file mode 100644 index 0000000..b708e3e --- /dev/null +++ b/algorithms-cs/src/Algorithm/Sort/External/SeriesMerge/readme.md @@ -0,0 +1,184 @@ +External Series merge sort +=========== + +#### _or natural merge sort_ + + +Use +--- + +For start sorting file create `MultiwaySort()` with 2 parameters such `number of ways` and (`filename` or path file). +Then call `Start()` method. + +After sorting is completed, a new file will be created with the same name and postscript `-sorted`. + + +Example use +----------- +```csharp +using algorithms_cs.Algorithm.Sort.External.Merge; + +const int numberWays = 4; +const string pathFile = @"someDirectory\\file.test"; + +var sort = new MultiwaySort(NumberWays, PathFile); +sort.Start(); +``` + +``` +/file.test 12 4 1 2 -6 12 645 12 54 -2,0001 +/file.test-sorted -6 -2,0001 1 2 4 12 12 12 54 645 +``` + + +Overview +---------------------------- + + +_**Внешняя многопутевая естественная сортировка**_ отличается от _**обычной внешней сортировки**_ концепцией серий чисел. +**_Серия_** - это последовательность чисел, каждый следующий элемент которой больше предыдущего. + +Tape - последовательность чисел, описывает файл с числами. +Количество Series в Tape не ограниченно. Первая серия предшествует второй, и т.д. + +``` +TAPE <= FILE 12 4 1 2 -6 12 645 12 54 -2,0001 +``` + +| _index_ | 0 | 1 | 2 | 3 | 4 | 5 | +|------------|--------|------|--------|---------------|----------|-----------| +| **Series** | `12` | `4` | `1, 2` | `-6, 12, 645` | `12, 54` | `-2.0001` | + + +Еще одно отличие **_ВМЕС_** от **_ОВС_** - это потоки или пути (от этого и слово многопутевая в названии). + +Например, при `N = 3`, создаются 6 (3 + 3) файлов, 2 набора для записи и для чтения. + +| Read | Write | +|----------|----------| +| `Tape 1` | `Tape 4` | +| `Tape 2` | `Tape 5` | +| `Tape 3` | `Tape 6` | + +Алгоритм состоит из: + +1. **Инициализации**. Подготовка к основному раунду алгоритма +2. **Тело**. Циклическое повторение основного раунда. + +**Основной раунд** - слияние N Серий из каждой Полосы в Полосы другой группы. + +Задачу слияния N серий берет на себя Коллектор. Он создает новую серию, которая записывается в Tape +``` + _____ + \ +Series 1 \ + \ +Series 2 new Series + / +Series 3 / + _____/ + +``` + +1. +| slot | Series | +|-------|----------| +| [ _ ] | `12` | +| [ _ ] | `4` | +| [ _ ] | `1`, `2` | + +2. +| slot | Series | +|--------|------------| +| [ 12 ] | ~~12~~ | +| [ 4 ] | ~~4~~ | +| [ 1 ] | ~~1~~, `2` | + +return `1` + +3. + +| slot | Series | +|--------|--------------| +| [ 12 ] | ~~12~~ | +| [ 4 ] | ~~4~~ | +| [ 2 ] | ~~1~~, ~~2~~ | + +return `2` + +4. + +| slot | Series | +|--------|--------------| +| [ 12 ] | ~~12~~ | +| [ 4 ] | ~~4~~ | +| [ _ ] | ~~1~~, ~~2~~ | + +return `4` + +5. + +| slot | Series | +|--------|--------------| +| [ 12 ] | ~~12~~ | +| [ _ ] | ~~4~~ | +| [ _ ] | ~~1~~, ~~2~~ | + +return `12` + +6. + +| slot | Series | +|-------|--------------| +| [ _ ] | ~~12~~ | +| [ _ ] | ~~4~~ | +| [ _ ] | ~~1~~, ~~2~~ | + +Серии закончились. Коллектор осталовился. + +_____ + +### Example + +| _index_ | 0 | 1 | 2 | 3 | 4 | 5 | +|------------|--------|------|--------|---------------|----------|-----------| +| **Series** | `12` | `4` | `1, 2` | `-6, 12, 645` | `12, 54` | `-2.0001` | + +1. Инициализация + +| Write | Read | +|---------------------|--------| +| `12`, `-6, 12, 645` | `____` | +| `4`, `12, 54` | `____` | +| `1, 2`, `-2.0001` | `____` | + +2. Тело + +2.1. + +| Read | Write | +|-----------------------|---------------| +| ~~12~~, `-6, 12, 645` | `1, 2, 4, 12` | +| ~~4~~, `12, 54` | `____` | +| ~~1, 2~~, `-2.0001` | `____` | + +| Read | Write | +|-------------------------|--------------------------------| +| ~~12~~, ~~-6, 12, 645~~ | `1, 2, 4, 12` | +| ~~4~~, ~~12, 54~~ | `-6, -2.0001, 12, 12, 54, 645` | +| ~~1, 2~~, ~~-2.0001~~ | `____` | + +2.2. + +| Write | Read | +|------------------------------------|----------------------------------| +| `-6 -2,0001 1 2 4 12 12 12 54 645` | ~~1, 2, 4, 12~~ | +| `____` | ~~-6, -2.0001, 12, 12, 54, 645~~ | +| `____` | `____` | + + +Алгоритм завершаетс, в результате получась полоска с одной серией + +----- + +

Copyright (C) 2022 The EMMS Project

diff --git a/algorithms-cs/src/Utils/Serial/Series.cs b/algorithms-cs/src/Utils/Serial/Series.cs new file mode 100644 index 0000000..d8e6861 --- /dev/null +++ b/algorithms-cs/src/Utils/Serial/Series.cs @@ -0,0 +1,38 @@ +using algorithms_cs.Utils.Tape; + +namespace algorithms_cs.Utils.Serial; + +/// +/// Series representing a sequence of increasing numbers over BufferedTapeReader. +/// +public class Series +{ + private readonly BufferedTapeReader _lsTape; + private double _buffer; + + public Series(BufferedTapeReader tape) + { + _buffer = double.MinValue; + _lsTape = tape; + } + + /// + /// + /// + /// A next value if it is greater than the previous value + public UtilReturn Next() + { + var peekValue = _lsTape.Peek(); + if (peekValue.GetType() == UtilReturnType.Correct) + { + if (_buffer <= peekValue.GetValue()) + { + var value = _lsTape.Next(); + _buffer = value.GetValue(); + return new UtilReturn(value.GetValue()); + } + return new UtilReturn(UtilReturnType.SeriesEnded); + } + return new UtilReturn(UtilReturnType.TapeEnded); + } +} \ No newline at end of file diff --git a/algorithms-cs/src/Utils/Serial/SeriesEnumerable.cs b/algorithms-cs/src/Utils/Serial/SeriesEnumerable.cs new file mode 100644 index 0000000..d3c70d5 --- /dev/null +++ b/algorithms-cs/src/Utils/Serial/SeriesEnumerable.cs @@ -0,0 +1,31 @@ +using System.Collections; +using algorithms_cs.Utils.Tape; + +namespace algorithms_cs.Utils.Serial; + +/// +/// SeriesEnumerable represents Series over the tape like a collection for using foreach +/// Series representing a sequence of increasing numbers over tape. +/// +public class SeriesEnumerable: IEnumerable> +{ + private readonly BufferedTapeReader _tape; + + public SeriesEnumerable(BufferedTapeReader tape) + { + _tape = tape; + _tape.Peek(); + } + + public bool IsEnd => _tape.Peek().GetType() == UtilReturnType.TapeEnded; + + public IEnumerator> GetEnumerator() + { + return new SeriesEnumerator(_tape); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } +} \ No newline at end of file diff --git a/algorithms-cs/src/Utils/Serial/SeriesEnumerator.cs b/algorithms-cs/src/Utils/Serial/SeriesEnumerator.cs new file mode 100644 index 0000000..a1a4e1c --- /dev/null +++ b/algorithms-cs/src/Utils/Serial/SeriesEnumerator.cs @@ -0,0 +1,47 @@ +using algorithms_cs.Utils.Tape; + +namespace algorithms_cs.Utils.Serial; + +public class SeriesEnumerator: IEnumerator> +{ + private readonly BufferedTapeReader _tape; + private double _previous; + + public SeriesEnumerator(BufferedTapeReader tape) + { + _tape = tape; + _previous = double.MinValue; + } + + /// + /// Checks a correct of next number + /// + /// boolean indicating whether a next number is available and more than the previous number + public bool MoveNext() + { + var value = _tape.Peek(); + if (value.GetType() == UtilReturnType.Correct) + { + if (_previous <= value.GetValue()) + { + _previous = value.GetValue(); + return true; + } + } + return false; + } + + public void Reset() + { + // throw new NotImplementedException(); + } + + public object Current => _tape.Next(); + + UtilReturn IEnumerator>.Current => (UtilReturn)Current; + + public void Dispose() + { + // throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/algorithms-cs/src/Utils/Tape/BufferedTapeReader.cs b/algorithms-cs/src/Utils/Tape/BufferedTapeReader.cs new file mode 100644 index 0000000..bee2e92 --- /dev/null +++ b/algorithms-cs/src/Utils/Tape/BufferedTapeReader.cs @@ -0,0 +1,54 @@ +namespace algorithms_cs.Utils.Tape; + +/// +/// BufferedTapeReader is a wrapper of TapeReader. +/// BufferedTapeReader implements Peek for check next value of TapeReader without losses this value. +/// +public class BufferedTapeReader: TapeReader +{ + private readonly Queue _buffer; + + public BufferedTapeReader(string path) : base(path) + { + _buffer = new Queue(); + } + + public BufferedTapeReader(StreamReader streamReader) : base(streamReader) + { + _buffer = new Queue(); + } + + /// + /// Peek implements safe viewing of the following value from tape; + /// Peek always returns the value following the current value until the next value is read + /// + /// next value of Tape + public UtilReturn Peek() + { + // Если 2 раза подряд вызвать BufferedTapeReader.Peek() то вернутся одинаковое значение + if (_buffer.TryPeek(out var bufValue)) + { + return new UtilReturn(bufValue); + } + + var nextValue = base.Next(); + if (nextValue.GetType() is UtilReturnType.TapeEnded) + { + return new UtilReturn(UtilReturnType.TapeEnded); + } + + _buffer.Enqueue(nextValue.GetValue()); + return nextValue; + } + + /// + /// + /// + /// next value of Tape or buffered previous value + public override UtilReturn Next() + { + return _buffer.TryDequeue(out var bufValue) + ? new UtilReturn(bufValue) + : base.Next(); + } +} \ No newline at end of file diff --git a/algorithms-cs/src/Utils/Tape/Tape.cs b/algorithms-cs/src/Utils/Tape/Tape.cs new file mode 100644 index 0000000..e00352b --- /dev/null +++ b/algorithms-cs/src/Utils/Tape/Tape.cs @@ -0,0 +1,18 @@ +namespace algorithms_cs.Utils.Tape; + +/// +/// Base Tape class +/// +public class Tape +{ + public readonly string? TapePath; + + protected Tape() + { + } + + protected Tape(string path) + { + TapePath = path; + } +} \ No newline at end of file diff --git a/algorithms-cs/src/Utils/Tape/TapeCollection.cs b/algorithms-cs/src/Utils/Tape/TapeCollection.cs new file mode 100644 index 0000000..f03877d --- /dev/null +++ b/algorithms-cs/src/Utils/Tape/TapeCollection.cs @@ -0,0 +1,25 @@ +using System.Collections; + +namespace algorithms_cs.Utils.Tape; + +/// +/// TapeCollection represents TapeReader like a collection for using foreach +/// +public class TapeCollection: IEnumerable +{ + private readonly BufferedTapeReader _tape; + public TapeCollection(string path) + { + _tape = new BufferedTapeReader(path); + } + + public TapeCollection(BufferedTapeReader tape) + { + _tape = tape; + } + + public IEnumerator GetEnumerator() + { + return new TapeEnumerator(_tape); + } +} \ No newline at end of file diff --git a/algorithms-cs/src/Utils/Tape/TapeEnumerator.cs b/algorithms-cs/src/Utils/Tape/TapeEnumerator.cs new file mode 100644 index 0000000..27c6436 --- /dev/null +++ b/algorithms-cs/src/Utils/Tape/TapeEnumerator.cs @@ -0,0 +1,40 @@ +using System.Collections; + +namespace algorithms_cs.Utils.Tape; + +public class TapeEnumerator : IEnumerator +{ + private BufferedTapeReader _tape; + private readonly string? _path; + + public TapeEnumerator(string path) + { + _path = path; + _tape = new BufferedTapeReader(path); + } + + public TapeEnumerator(BufferedTapeReader tape) + { + _path = tape.TapePath; + _tape = tape; + } + + /// + /// Checks that the Tape is finished or there is no next number + /// + /// boolean indicating whether a next number is available + public bool MoveNext() + { + return !_tape.IsEnd || _tape.Peek().GetType() == UtilReturnType.Correct; + } + + public void Reset() + { + _tape = new BufferedTapeReader(_path!); + } + + /// + /// Returns a next number from the tape + /// + public object Current => _tape.Next().GetValue(); +} \ No newline at end of file diff --git a/src/Tape/TapeReader.cs b/algorithms-cs/src/Utils/Tape/TapeReader.cs similarity index 54% rename from src/Tape/TapeReader.cs rename to algorithms-cs/src/Utils/Tape/TapeReader.cs index 0afc364..00661e8 100644 --- a/src/Tape/TapeReader.cs +++ b/algorithms-cs/src/Utils/Tape/TapeReader.cs @@ -1,14 +1,23 @@ -namespace algorithms_cs.Tape; +namespace algorithms_cs.Utils.Tape; +/// +/// The TapeReader representing the file that contains numbers. +/// By using StreamReader for reading the file and .Next() for extracting the double number. +/// public class TapeReader : Tape { private readonly StreamReader? _file; - public TapeReader(string filepath) : base(filepath) + /// + /// The TapeReader representing the file that contains numbers. + /// By using StreamReader for reading the file and .Next() for extracting the double number. + /// + /// the path of file + public TapeReader(string path) : base(path) { try { - _file = new StreamReader(Filepath); + _file = new StreamReader(path); } catch (FileNotFoundException e) { @@ -22,25 +31,42 @@ public TapeReader(string filepath) : base(filepath) } } - // This methods returns a boolean value describing is the file ended - public bool IsEnd => _file!.Peek() == -1; + /// + /// The TapeReader representing the file that contains numbers. + /// By using StreamReader for reading the file and .Next() for extracting the double number. + /// + /// StreamReader + public TapeReader(StreamReader streamReader) + { + _file = streamReader; + } + /// + /// Returns true if the file ends + /// + public bool IsEnd => _file!.Peek() == -1; + + /// + /// Close the StreamReader + /// public void Close() { _file?.Close(); } - + private bool ValueIsDigit(int value) { return value is >= 48 and <= 57; } - // This methods reading file and returns a next number from this file - public virtual TapeReturn Next() + /// + /// Read next number from the file + /// + /// a next double number from StreamReader + public virtual UtilReturn Next() { var token = ""; var tokenIsNumber = false; - //_isHaveNumber = IsEnd(); while (!IsEnd) { @@ -62,7 +88,7 @@ public virtual TapeReturn Next() { if (token.Length > 0) { - return new TapeReturn(Convert.ToDouble(token.Replace('.', ','))); + return new UtilReturn(Convert.ToDouble(token.Replace('.', ','))); } break; } @@ -78,9 +104,9 @@ public virtual TapeReturn Next() if (nextChar == -1) { //_isHaveNumber = true; - return new TapeReturn(Convert.ToDouble(token.Replace('.', ','))); + return new UtilReturn(Convert.ToDouble(token.Replace('.', ','))); } } - return new TapeReturn(TapeReturnType.TapeEnded); + return new UtilReturn(); } } \ No newline at end of file diff --git a/src/Tape/TapeWriter.cs b/algorithms-cs/src/Utils/Tape/TapeWriter.cs similarity index 71% rename from src/Tape/TapeWriter.cs rename to algorithms-cs/src/Utils/Tape/TapeWriter.cs index 620d2bf..f63b02f 100644 --- a/src/Tape/TapeWriter.cs +++ b/algorithms-cs/src/Utils/Tape/TapeWriter.cs @@ -1,4 +1,4 @@ -namespace algorithms_cs.Tape; +namespace algorithms_cs.Utils.Tape; public class TapeWriter : Tape { @@ -7,12 +7,12 @@ public class TapeWriter : Tape public bool Recorded => _recorded; - public TapeWriter(string filepath) : base(filepath) + public TapeWriter(string path) { try { _recorded = false; - _file = new StreamWriter(Filepath); + _file = new StreamWriter(path); } catch (Exception e) { @@ -29,6 +29,6 @@ public void Close() public void Write(T value) { _recorded = true; - _file.Write(value.ToString() + " "); + _file.Write(value!.ToString() + " "); } } \ No newline at end of file diff --git a/algorithms-cs/src/Utils/UtilReturn.cs b/algorithms-cs/src/Utils/UtilReturn.cs new file mode 100644 index 0000000..2de2b52 --- /dev/null +++ b/algorithms-cs/src/Utils/UtilReturn.cs @@ -0,0 +1,63 @@ +namespace algorithms_cs.Utils; + +/// +/// SeriesReturnTape representing series type of return value +/// +[Flags] +public enum UtilReturnType +{ + /// + /// Correct using when next value was successfully received + /// + Correct = 1, + + /// + /// SeriesEnded using when series was ended or next value was not received + /// + SeriesEnded = 2, + + /// + /// TapeEnded using when tape was ended or next value was not read + /// + TapeEnded = 3, +} + +public class UtilReturn +{ + private readonly T? _value; + private readonly UtilReturnType _type; + + public T? GetValue() + { + return _type == UtilReturnType.Correct ? _value : default; + } + + public UtilReturnType GetType() + { + return _type; + } + + + /// + /// Default initialization with TapeEnded type + /// + public UtilReturn() + { + _type = UtilReturnType.TapeEnded; + } + + /// + /// Correct is the default series, since if a value is passed, it's already right. + /// + /// any value that to be passed from Series + public UtilReturn(T value) + { + _value = value; + _type = UtilReturnType.Correct; + } + + public UtilReturn(UtilReturnType type) + { + _type = type; + } +} \ No newline at end of file diff --git a/readme.md b/readme.md index 6a4491a..449da22 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -Algorithms C# +Algorithms C# ============= @@ -8,181 +8,9 @@ Overview This project is designed to learning **computer science** by [a roadmap](https://roadmap.sh/computer-science). -Use ---- +List +---- -For start sorting file create `MultiwaySort()` with 2 parameters such `number of ways` and (`filename` or path file). -Then call `Start()` method. - -After sorting is completed, a new file will be created with the same name and postscript `-sorted`. - - -Example use ------------ -```csharp -using algorithms_cs.Algorithm.Sort.External.Merge; - -const int numberWays = 4; -const string pathFile = @"someDirectory\\resource\\1.test"; - -var sort = new MultiwaySort(NumberWays, PathFile); -sort.Start(); -``` - -``` -/1.test 12 4 1 2 -6 12 645 12 54 -2,0001 -/1.test-sorted -6 -2,0001 1 2 4 12 12 12 54 645 -``` - - -External Multiway Merge Sort ----------------------------- - - -_**Внешняя многопутевая естественная сортировка**_ отличается от _**обычной внешней сортировки**_ концепцией серий чисел. -**_Серия_** - это последовательность чисел, каждый следующий элемент которой больше предыдущего. - -Tape - последовательность чисел, описывает файл с числами. -Количество Series в Tape не ограниченно. Первая серия предшествует второй, и т.д. - -``` -TAPE <= FILE 12 4 1 2 -6 12 645 12 54 -2,0001 -``` - -| _index_ | 0 | 1 | 2 | 3 | 4 | 5 | -|------------|--------|------|--------|---------------|----------|-----------| -| **Series** | `12` | `4` | `1, 2` | `-6, 12, 645` | `12, 54` | `-2.0001` | - - -Еще одно отличие **_ВМЕС_** от **_ОВС_** - это потоки или пути (от этого и слово многопутевая в названии). - -Например, при `N = 3`, создаются 6 (3 + 3) файлов, 2 набора для записи и для чтения. - -| Read | Write | -|----------|----------| -| `Tape 1` | `Tape 4` | -| `Tape 2` | `Tape 5` | -| `Tape 3` | `Tape 6` | - -Алгоритм состоит из: - -1. **Инициализации**. Подготовка к основному раунду алгоритма -2. **Тело**. Циклическое повторение основного раунда. - -**Основной раунд** - слияние N Серий из каждой Полосы в Полосы другой группы. - -Задачу слияния N серий берет на себя Коллектор. Он создает новую серию, которая записывается в Tape -``` - _____ - \ -Series 1 \ - \ -Series 2 new Series - / -Series 3 / - _____/ - -``` - -1. -| slot | Series | -|-------|----------| -| [ _ ] | `12` | -| [ _ ] | `4` | -| [ _ ] | `1`, `2` | - -2. -| slot | Series | -|--------|------------| -| [ 12 ] | ~~12~~ | -| [ 4 ] | ~~4~~ | -| [ 1 ] | ~~1~~, `2` | - -return `1` - -3. - -| slot | Series | -|--------|--------------| -| [ 12 ] | ~~12~~ | -| [ 4 ] | ~~4~~ | -| [ 2 ] | ~~1~~, ~~2~~ | - -return `2` - -4. - -| slot | Series | -|--------|--------------| -| [ 12 ] | ~~12~~ | -| [ 4 ] | ~~4~~ | -| [ _ ] | ~~1~~, ~~2~~ | - -return `4` - -5. - -| slot | Series | -|--------|--------------| -| [ 12 ] | ~~12~~ | -| [ _ ] | ~~4~~ | -| [ _ ] | ~~1~~, ~~2~~ | - -return `12` - -6. - -| slot | Series | -|-------|--------------| -| [ _ ] | ~~12~~ | -| [ _ ] | ~~4~~ | -| [ _ ] | ~~1~~, ~~2~~ | - -Серии закончились. Коллектор осталовился. - -_____ - -### Example - -| _index_ | 0 | 1 | 2 | 3 | 4 | 5 | -|------------|--------|------|--------|---------------|----------|-----------| -| **Series** | `12` | `4` | `1, 2` | `-6, 12, 645` | `12, 54` | `-2.0001` | - -1. Инициализация - -| Read | Write | -|---------------------|--------| -| `12`, `-6, 12, 645` | `____` | -| `4`, `12, 54` | `____` | -| `1, 2`, `-2.0001` | `____` | - -2. Тело - -2.1. - -| Read | Write | -|-----------------------|---------------| -| ~~12~~, `-6, 12, 645` | `1, 2, 4, 12` | -| ~~4~~, `12, 54` | `____` | -| ~~1, 2~~, `-2.0001` | `____` | - -| Read | Write | -|-------------------------|--------------------------------| -| ~~12~~, ~~-6, 12, 645~~ | `1, 2, 4, 12` | -| ~~4~~, ~~12, 54~~ | `-6, -2.0001, 12, 12, 54, 645` | -| ~~1, 2~~, ~~-2.0001~~ | `____` | - -2.2. - -| Read | Write | -|------------------------------------|----------------------------------| -| `-6 -2,0001 1 2 4 12 12 12 54 645` | ~~1, 2, 4, 12~~ | -| `____` | ~~-6, -2.0001, 12, 12, 54, 645~~ | -| `____` | `____` | - - -Алгоритм завершаетс, в результате получась полоска с одной серией - ------ - -

Copyright (C) 2022 The EMMS Project

+- Sort + - external + - [series merge](./algorithms-cs/src/Algorithm/Sort/External/SeriesMerge/readme.md) \ No newline at end of file diff --git a/src/Algorithm/Sort/Sort.cs b/src/Algorithm/Sort/Sort.cs deleted file mode 100644 index 706dc20..0000000 --- a/src/Algorithm/Sort/Sort.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace algorithms_cs.Algorithm.Sort; - -public abstract class Sort -{ - protected Sort() { } -} \ No newline at end of file diff --git a/src/Serial/ISeriesReturn.cs b/src/Serial/ISeriesReturn.cs deleted file mode 100644 index d10bd11..0000000 --- a/src/Serial/ISeriesReturn.cs +++ /dev/null @@ -1,37 +0,0 @@ -using algorithms_cs.Tape; - -namespace algorithms_cs.Serial; - -public enum SeriesReturnType -{ - Correct, - SeriesEnded, - TapeEnded, -} - -public class SeriesReturn -{ - private T? _value; - private SeriesReturnType _type; - - public T? GetValue() - { - return _type == SeriesReturnType.Correct ? _value : default; - } - - public SeriesReturnType GetType() - { - return _type; - } - - public SeriesReturn(T value) - { - _value = value; - _type = SeriesReturnType.Correct; - } - - public SeriesReturn(SeriesReturnType type) - { - _type = type; - } -} \ No newline at end of file diff --git a/src/Serial/Series.cs b/src/Serial/Series.cs deleted file mode 100644 index 9670c1e..0000000 --- a/src/Serial/Series.cs +++ /dev/null @@ -1,35 +0,0 @@ -using algorithms_cs.Tape; - -namespace algorithms_cs.Serial; - -public class Series -{ - private readonly BufferedTapeReader _lsTape; - private double _buffer; - - public Series(BufferedTapeReader tape) - { - _buffer = double.MinValue; - _lsTape = tape; - } - - public SeriesReturn Next() - { - var peekValue = _lsTape.Peek(); - if (peekValue.GetType() == TapeReturnType.Correct) - { - if (_buffer <= peekValue.GetValue()) - { - var value = _lsTape.Next(); - _buffer = value.GetValue(); - return new SeriesReturn(value.GetValue()); - } - - return new SeriesReturn(SeriesReturnType.SeriesEnded); - - //return new CorrectSeriesReturn(value.Value, SeriesReturnType.Correct); - } - - return new SeriesReturn(SeriesReturnType.TapeEnded); - } -} \ No newline at end of file diff --git a/src/Tape/BufferedTapeReader.cs b/src/Tape/BufferedTapeReader.cs deleted file mode 100644 index 4907a2d..0000000 --- a/src/Tape/BufferedTapeReader.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace algorithms_cs.Tape; - -public class BufferedTapeReader: TapeReader -{ - private readonly Queue _buffer; - - public BufferedTapeReader(string filepath) : base(filepath) - { - _buffer = new Queue(); - } - - public TapeReturn Peek() - { - // Если 2 раза подряд вызвать BufferedTapeReader.Peek() то вернутся одинаковое значение - if (_buffer.TryPeek(out var bufValue)) - { - return new TapeReturn(bufValue); - } - - var nextValue = base.Next(); - if (nextValue.GetType() is TapeReturnType.TapeEnded) - { - return new TapeReturn(TapeReturnType.TapeEnded); - } - - _buffer.Enqueue(nextValue.GetValue()); - return nextValue; - } - - public override TapeReturn Next() - { - return _buffer.TryDequeue(out var bufValue) - ? new TapeReturn(bufValue) - : base.Next(); - } -} \ No newline at end of file diff --git a/src/Tape/ITapeReturn.cs b/src/Tape/ITapeReturn.cs deleted file mode 100644 index e742ca3..0000000 --- a/src/Tape/ITapeReturn.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace algorithms_cs.Tape; - - -public enum TapeReturnType -{ - Correct, - TapeEnded, -} - -public class TapeReturn -{ - private T? _value; - private TapeReturnType _type; - - public T? GetValue() - { - return _type == TapeReturnType.Correct ? _value : default; - } - - public TapeReturnType GetType() - { - return _type; - } - - public TapeReturn(T value) - { - _value = value; - _type = TapeReturnType.Correct; - } - - public TapeReturn(TapeReturnType type) - { - _type = type; - } -} diff --git a/src/Tape/Tape.cs b/src/Tape/Tape.cs deleted file mode 100644 index 98bb147..0000000 --- a/src/Tape/Tape.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace algorithms_cs.Tape; - -public class Tape -{ - protected readonly string Filepath; - - protected Tape(string filepath) - { - Filepath = filepath; - } - -} \ No newline at end of file