From cb68117d83e7754f9c6fd0909adfa12ac8d26d0f Mon Sep 17 00:00:00 2001 From: MarcUs7i <96580944+MarcUs7i@users.noreply.github.com> Date: Thu, 5 Dec 2024 23:14:53 +0100 Subject: [PATCH] Add function doesnt work as supposed at 3+ participants --- Marathons/Marathon.cs | 188 +++++++++++++++++++++++++++++++++++++++++- Marathons/Node.cs | 5 +- 2 files changed, 187 insertions(+), 6 deletions(-) diff --git a/Marathons/Marathon.cs b/Marathons/Marathon.cs index 97f87ea..99780d9 100644 --- a/Marathons/Marathon.cs +++ b/Marathons/Marathon.cs @@ -2,7 +2,8 @@ public sealed class Marathon { - //private Node? _head; + private Node? _head; + private Node? _tail; public readonly string City; public readonly DateOnly Date; public int ParticipantCount { get; private set; } @@ -13,16 +14,61 @@ public sealed class Marathon Date = date; } + /// + /// Adds a participant to the list + /// + /// The participant public void AddParticipant(Participant participant) { + int insertIndex = GetIndex(participant, out bool exactPosFound); + if (exactPosFound) + { + return; + } + ParticipantCount++; + Node middleNode = new Node(participant); + Node? leftNode = GetNodeByIndex(insertIndex - 1); + Node? rightNode = GetNodeByIndex(insertIndex); + if (leftNode == null || rightNode == null) + { + _head = middleNode; + _tail = middleNode; + return; + } + MoveNode(leftNode, rightNode, middleNode); } - public bool RemoveParticipant(int index) + public bool RemoveParticipant(int startNo) { - return false; - } + Node? nodeToRemove = GetNodeByStartNo(startNo); + if (nodeToRemove == null) + { + return false; + } + ParticipantCount--; + Node? leftNode = GetNodeByIndex(GetIndex(nodeToRemove.Data!, out _) - 1); + // some explanation here |↑ node of → |↑ index of → |↑ Participant + Node? rightNode = nodeToRemove.Next; + + // If nodeToRemove is the first node + if (leftNode == null) + { + _head = rightNode; + return true; + } + // If nodeToRemove is the last node + if (rightNode == null) + { + _tail = leftNode; + return true; + } + + MoveNode(leftNode, rightNode); + return true; + } + public string[] GetResultList() { return Array.Empty(); @@ -32,4 +78,138 @@ public sealed class Marathon { return $"{City} marathon on {Date.ToString(Const.Culture)}"; } + + /// + /// Returns the index of the participant in the list + /// It's a merged method that can be used to determine the index of a participant, + /// or the index where the participant can be placed + /// Should be efficient for VERY large lists + /// + /// the participant you want to check + /// true: found exact location; false: no exact location/doesn't exist + /// The index where the participant is or might be + private int GetIndex(Participant participant, out bool exactPosFound) + { + //check if the list is empty + if (_head is null || _tail is null) + { + exactPosFound = false; + return 0; + } + + //check if the participant is the first or last + int result = _head.Data?.CompareTo(participant) ?? 0; // why ?? are you confused? you sure its not null?? + // haha, you sure?? + // I'm sure, I'm sure + // haha, okay, I trust you + // ok, i should stop talking to co-pilot now + // If the participant is the first or can be placed before the first + if (result <= 0) + { + exactPosFound = result == 0; + return 0; + } + // If the participant is the last or can be placed after the last + result = _tail.Data?.CompareTo(participant) ?? 0; + if (result >= 0) + { + exactPosFound = result == 0; + return ParticipantCount; + } + + // Half the list and check both sides + int left = 0; + int right = ParticipantCount; + while (left < right) + { + int middle = (left + right) / 2; + Node? current = _head; + for (int i = 0; i < middle; i++) + { + current = current?.Next; + } + result = current?.Data?.CompareTo(participant) ?? 0; + if (result == 0) + { + exactPosFound = true; + return middle; + } + if (result < 0) + { + left = middle + 1; + } + else + { + right = middle; + } + } + + // If not in the list, return the index where it should be + exactPosFound = false; + return left; + } + + /// + /// Makes the connection to the specified node + /// A -> B -> C + /// If no middle node specified, then it will be A -> C + /// + /// The starting Node, or A node + /// The targetNode, or the B node if no middle node specified, else C node + /// The middle node or the B node + private void MoveNode(Node startingNode, Node targetNode, Node? middleNode = null) + { + if(middleNode is null) + { + startingNode.Next = targetNode; + return; + } + + if(startingNode == targetNode) + { + _tail = middleNode; + } + else middleNode.Next = targetNode; + startingNode.Next = middleNode; + } + + Node? GetNodeByIndex(int index) + { + if(index <= 0) + { + return _head; + } + if(index >= ParticipantCount) + { + return _tail; + } + + Node? current = _head; + for (int i = 0; i < index; i++) + { + current = current?.Next; + } + + return current; + } + + Node? GetNodeByStartNo(int startNo) + { + Node? current = _head; + for (int i = 0; i < ParticipantCount; i++) + { + if (current == null) + { + return null; + } + + if (current.Data?.StartNo == startNo) + { + return current; + } + current = current.Next; + } + + return null; + } } \ No newline at end of file diff --git a/Marathons/Node.cs b/Marathons/Node.cs index a10214f..a7aef11 100644 --- a/Marathons/Node.cs +++ b/Marathons/Node.cs @@ -1,7 +1,8 @@ namespace Marathons; -public sealed class Node(double? value) +public sealed class Node(Participant? value) { - public double? Data { get; } = value; + //accept anything + public Participant? Data { get; } = value; public Node? Next { get; set; } }