├── .gitignore
├── CourseWork.sln
└── CourseWork
├── CourseWork.csproj
├── Program.cs
└── Structures
├── Node.cs
├── Tree.ConcurrentPassThrough.cs
├── Tree.ParallelPassThrough.cs
└── Tree.cs
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea/
2 | ./CourseWork/bin/
3 | ./CourseWork/obj/
4 | *.json
5 | *.targets
6 |
--------------------------------------------------------------------------------
/CourseWork.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CourseWork", "CourseWork\CourseWork.csproj", "{54FF4B0A-57BF-4C82-AA57-E1A37C0FBA1F}"
4 | EndProject
5 | Global
6 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
7 | Debug|Any CPU = Debug|Any CPU
8 | Release|Any CPU = Release|Any CPU
9 | EndGlobalSection
10 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
11 | {54FF4B0A-57BF-4C82-AA57-E1A37C0FBA1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
12 | {54FF4B0A-57BF-4C82-AA57-E1A37C0FBA1F}.Debug|Any CPU.Build.0 = Debug|Any CPU
13 | {54FF4B0A-57BF-4C82-AA57-E1A37C0FBA1F}.Release|Any CPU.ActiveCfg = Release|Any CPU
14 | {54FF4B0A-57BF-4C82-AA57-E1A37C0FBA1F}.Release|Any CPU.Build.0 = Release|Any CPU
15 | EndGlobalSection
16 | EndGlobal
17 |
--------------------------------------------------------------------------------
/CourseWork/CourseWork.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net7.0
6 | enable
7 | enable
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/CourseWork/Program.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 | using CourseWork.Structures;
3 |
4 | namespace CourseWork;
5 |
6 | public static class Program
7 | {
8 | public static async Task Main()
9 | {
10 | int size = 10_000_000;
11 | List<(int, int)> src = new List<(int, int)>(size);
12 | for (int i = size-1; i >= 0; i--)
13 | {
14 | src.Add((i, size-i));
15 | }
16 |
17 | Tree tree = new Tree(src);
18 | Console.WriteLine($"Tree building done ({size})");
19 | Stopwatch sw = Stopwatch.StartNew();
20 | var arr1 = await tree.ToSortedArrayConcurrent();
21 | sw.Stop();
22 | Console.WriteLine("Time: " + sw.ElapsedMilliseconds + "ms");
23 |
24 | tree.ClearNodesUsages();
25 | sw = Stopwatch.StartNew();
26 | var arr2 = await tree.ToSortedArrayParallel();
27 | sw.Stop();
28 | Console.WriteLine("Time: " + sw.ElapsedMilliseconds + "ms");
29 |
30 | Console.WriteLine("Correctness: "+Check(arr1, arr2));
31 | Console.ReadLine();
32 | }
33 |
34 | private static bool Check((int, int)[] arr1, (int, int)[] arr2, bool printArray = false)
35 | {
36 | for (int i = 0; i < arr1.Length; i++)
37 | {
38 | var el1 = arr1[i];
39 | var el2 = arr2[i];
40 | if (printArray) Console.WriteLine(el1);
41 | if (el1 != el2)
42 | return false;
43 | }
44 |
45 | return true;
46 | }
47 | }
--------------------------------------------------------------------------------
/CourseWork/Structures/Node.cs:
--------------------------------------------------------------------------------
1 | namespace CourseWork.Structures;
2 |
3 | public class Node where TKey: IEquatable, IComparable
4 | {
5 | public TKey Key { get; }
6 | public TVal Value { get; set; }
7 |
8 | public Node? FirstChild { get; set; }
9 | public Node? SecondChild { get; set; }
10 | public int SubtreeSize { get; private set; }
11 | public Node? Parent { get; set; }
12 | public bool IsPassed { get; protected set; }
13 |
14 | public (TKey, TVal)? Pass()
15 | {
16 | lock (this)
17 | {
18 | if (IsPassed)
19 | return null;
20 | IsPassed = true;
21 | }
22 | return (Key, Value);
23 | }
24 |
25 | public Node(Node? parent, TKey key, TVal value)
26 | {
27 | Key = key;
28 | Value = value;
29 | Parent = parent;
30 | IsPassed = false;
31 | SubtreeSize = 1;
32 | }
33 |
34 | public void Add((TKey Key, TVal Value) child)
35 | {
36 | SubtreeSize++;
37 | if (child.Key.CompareTo(this.Key) == 1)
38 | {
39 | if (SecondChild is null)
40 | SecondChild = new Node(this, child.Key, child.Value);
41 | else SecondChild.Add(child);
42 | }
43 | else
44 | {
45 | if (FirstChild is null)
46 | FirstChild = new Node(this, child.Key, child.Value);
47 | else FirstChild.Add(child);
48 | }
49 | }
50 |
51 | public void Clear()
52 | {
53 | IsPassed = false;
54 | if (FirstChild is not null)
55 | FirstChild.Clear();
56 | if (SecondChild is not null)
57 | SecondChild.Clear();
58 | }
59 | }
--------------------------------------------------------------------------------
/CourseWork/Structures/Tree.ConcurrentPassThrough.cs:
--------------------------------------------------------------------------------
1 | namespace CourseWork.Structures;
2 |
3 | public partial class Tree
4 | {
5 | public async Task<(TKey, TValue)[]> ToSortedArrayConcurrent(Node? subtreeRoot = null)
6 | {
7 | Node workingTreeRoot = subtreeRoot ?? Root!;
8 | (TKey, TValue)[] array = new (TKey, TValue)[workingTreeRoot.SubtreeSize];
9 | if (Count == 0)
10 | return array;
11 |
12 | int ctr = 0;
13 | Node? current = workingTreeRoot;
14 | while (current != workingTreeRoot!.Parent)
15 | {
16 | if (current!.FirstChild is not null && !current.FirstChild.IsPassed)
17 | {
18 | current = current.FirstChild;
19 | continue;
20 | }
21 |
22 | if (current.SecondChild is null || !current.SecondChild.IsPassed)
23 | array[ctr++] = current.Pass()!.Value;
24 |
25 | if (current.SecondChild is not null && !current.SecondChild.IsPassed)
26 | {
27 | current = current.SecondChild;
28 | continue;
29 | }
30 |
31 | current = current.Parent;
32 | }
33 |
34 | return array;
35 | }
36 | }
--------------------------------------------------------------------------------
/CourseWork/Structures/Tree.ParallelPassThrough.cs:
--------------------------------------------------------------------------------
1 | namespace CourseWork.Structures;
2 |
3 | public partial class Tree
4 | {
5 | private (TKey, TValue)[] finalResult;
6 | public async Task<(TKey, TValue)[]> ToSortedArrayParallel(Node? subtreeRoot = null, int threads = 8)
7 | {
8 | Node workingTreeRoot = subtreeRoot! ?? Root!;
9 | if (Count == 0)
10 | {
11 | return Array.Empty<(TKey, TValue)>();
12 | }
13 |
14 | finalResult = new (TKey, TValue)[workingTreeRoot.SubtreeSize];
15 |
16 | await ParallelPassThrough(workingTreeRoot, threads, 0);
17 | return finalResult;
18 | }
19 |
20 | private async Task ParallelPassThrough(Node subtreeRoot, int threads, int arrayStartingIndex)
21 | {
22 | if (threads < 2)
23 | {
24 | (await ToSortedArrayConcurrent(subtreeRoot)).CopyTo(finalResult, arrayStartingIndex);
25 | return;
26 | }
27 |
28 | if (HasTwoChildren(subtreeRoot))
29 | {
30 | Task task1 = Task.Run(async () =>
31 | await ParallelPassThrough(subtreeRoot.FirstChild!, threads / 2, arrayStartingIndex));
32 | Task task2 = Task.Run(async () => await ParallelPassThrough(subtreeRoot.SecondChild!,
33 | threads - threads / 2, arrayStartingIndex + subtreeRoot.FirstChild!.SubtreeSize + 1));
34 |
35 | finalResult[arrayStartingIndex + subtreeRoot.FirstChild!.SubtreeSize] =
36 | (subtreeRoot.Key, subtreeRoot.Value);
37 | await task1;
38 | await task2;
39 | return;
40 | }
41 |
42 | finalResult[arrayStartingIndex] = (subtreeRoot.Key, subtreeRoot.Value);
43 | if (HasOneChild(subtreeRoot))
44 | {
45 | if (subtreeRoot.FirstChild is not null)
46 | {
47 | Task task1 =Task.Run(async () => await ParallelPassThrough(subtreeRoot.FirstChild!, threads, arrayStartingIndex));
48 |
49 | finalResult[arrayStartingIndex + subtreeRoot.FirstChild!.SubtreeSize] =
50 | (subtreeRoot.Key, subtreeRoot.Value);
51 | await task1;
52 | return;
53 | }
54 |
55 | await ParallelPassThrough(subtreeRoot.SecondChild!, threads, arrayStartingIndex+1);
56 | }
57 | }
58 |
59 | private bool HasTwoChildren(Node node)
60 | {
61 | return (node.FirstChild is not null && node.SecondChild is not null);
62 | }
63 |
64 | private bool HasOneChild(Node node)
65 | {
66 | return node.SubtreeSize > 1;
67 | }
68 | }
--------------------------------------------------------------------------------
/CourseWork/Structures/Tree.cs:
--------------------------------------------------------------------------------
1 | namespace CourseWork.Structures;
2 |
3 | public partial class Tree where TKey: IComparable, IEquatable
4 | {
5 | public Node? Root { get; private set; }
6 | public int Count { get; private set; }
7 | public Tree()
8 | {
9 | Count = 0;
10 | }
11 |
12 | public Tree(IEnumerable<(TKey, TValue)> source)
13 | {
14 | var sourceList = source.ToList();
15 | sourceList.Sort((p1, p2) => p1.Item1.CompareTo(p2.Item1));
16 | Count = 0;
17 |
18 | foreach (int index in GetBalancingIndexes(sourceList.Count))
19 | {
20 | Add(sourceList[index]);
21 | }
22 | }
23 |
24 | public void Add((TKey, TValue) element)
25 | {
26 | Count++;
27 | if (Root is null)
28 | {
29 | Root = new Node(null, element.Item1, element.Item2);
30 | }
31 | else
32 | {
33 | Root.Add(element);
34 | }
35 | }
36 |
37 | public void Add(TKey key, TValue value) => Add((key, value));
38 |
39 | private static IEnumerable GetBalancingIndexes(int elementsNumber)
40 | {
41 | if (elementsNumber == 0)
42 | yield break;
43 | int ownInd = elementsNumber / 2;
44 | yield return ownInd;
45 | if (elementsNumber == 1)
46 | yield break;
47 | foreach (var ind in GetBalancingIndexes(ownInd))
48 | {
49 | yield return ind;
50 | }
51 |
52 | foreach (var ind in GetBalancingIndexes(elementsNumber - ownInd - 1))
53 | {
54 | yield return ownInd + 1 + ind;
55 | }
56 | }
57 |
58 | public void ClearNodesUsages()
59 | {
60 | Root?.Clear();
61 | }
62 | }
--------------------------------------------------------------------------------