{"id":24295401,"url":"https://github.com/phmatray/redblack","last_synced_at":"2026-06-09T14:31:32.489Z","repository":{"id":271945516,"uuid":"915064301","full_name":"phmatray/RedBlack","owner":"phmatray","description":"A C# implementation of a Red-Black Tree with full unit tests","archived":false,"fork":false,"pushed_at":"2026-03-09T12:19:12.000Z","size":18,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"dev","last_synced_at":"2026-03-09T16:57:27.297Z","etag":null,"topics":["algorithms","csharp","data-structures","dotnet","redblack-tree"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/phmatray.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2025-01-10T22:15:21.000Z","updated_at":"2026-03-04T22:57:35.000Z","dependencies_parsed_at":"2025-01-10T23:33:49.348Z","dependency_job_id":null,"html_url":"https://github.com/phmatray/RedBlack","commit_stats":null,"previous_names":["phmatray/redblack"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/phmatray/RedBlack","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phmatray%2FRedBlack","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phmatray%2FRedBlack/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phmatray%2FRedBlack/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phmatray%2FRedBlack/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phmatray","download_url":"https://codeload.github.com/phmatray/RedBlack/tar.gz/refs/heads/dev","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phmatray%2FRedBlack/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34112225,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-09T02:00:06.510Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["algorithms","csharp","data-structures","dotnet","redblack-tree"],"created_at":"2025-01-16T18:49:39.817Z","updated_at":"2026-06-09T14:31:32.461Z","avatar_url":"https://github.com/phmatray.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Red-Black Tree with Order Statistics \u0026 Duplicates\n\nA **C#** implementation of a **Red-Black Tree** supporting:\n\n- **Multiset Counting**: Multiple occurrences of the same key stored in a single node.\n- **Order Statistics**:\n    - **Select(k)**: Get the k-th smallest element.\n    - **Rank(key)**: Find how many elements are strictly less than `key`.\n- **Sentinel Node** design to simplify `null` checks, keeping the tree balanced at all times.\n- Classic **BST** operations: Insert, Search/Contains, and Delete in **\\(O(\\log n)\\)**.\n- Built-in **IEnumerable** (in-order traversal) yields duplicates consecutively in sorted order.\n\nTested with [**BenchmarkDotNet**](https://github.com/dotnet/BenchmarkDotNet) for performance measurements.\n\n## Table of Contents\n\n\u003c!-- TOC --\u003e\n* [Red-Black Tree with Order Statistics \u0026 Duplicates](#red-black-tree-with-order-statistics--duplicates)\n  * [Table of Contents](#table-of-contents)\n  * [Features](#features)\n  * [Installation](#installation)\n  * [Usage Example](#usage-example)\n  * [API Overview](#api-overview)\n  * [Benchmarking](#benchmarking)\n    * [Quick Start](#quick-start)\n  * [Contributing](#contributing)\n  * [License](#license)\n\u003c!-- TOC --\u003e\n\n---\n\n## Features\n\n1. **Red-Black Balancing**\n    - Guaranteed worst-case height of \\(O(\\log n)\\) for insertion, deletion, and search.\n\n2. **Multiset**\n    - Storing duplicates directly in a node’s `DuplicateCount` (instead of having separate nodes for identical keys).\n    - Reduces tree growth for repeated values.\n\n3. **Order Statistics**\n    - **Select(k)**: Get the k-th smallest element (1-based).\n    - **Rank(key)**: How many elements are strictly less than `key`. (Adjustable to “less or equal” if needed.)\n\n4. **Sentinel Node**\n    - One `Nil` node for all `null` references. Simplifies logic, fewer `null` checks.\n\n5. **IEnumerable**\n    - Traverse in ascending order (duplicates included multiple times).\n\n6. **BenchmarkDotNet Setup**\n    - Sample benchmark class to measure performance of typical operations.\n\n---\n\n## Installation\n\n1. **Clone** or **download** this repository.\n2. **Open** it in Visual Studio, Rider, VSCode, or any other C# IDE.\n3. Make sure your project references the **.cs** file(s) containing the Red-Black Tree code.\n\n---\n\n## Usage Example\n\nBelow is a simple program showing how to use the **RedBlackTree** data structure:\n\n```csharp\nusing System;\nusing RedBlackTreeOrderStats;\n\npublic class Program\n{\n    public static void Main(string[] args)\n    {\n        var tree = new RedBlackTree\u003cint\u003e();\n\n        // Insert elements\n        tree.Insert(10);\n        tree.Insert(5);\n        tree.Insert(5);  // Duplicate\n        tree.Insert(20);\n        tree.Insert(15);\n        tree.Insert(15); // Duplicate\n        tree.Insert(15); // Another duplicate\n\n        // Print total count (including duplicates)\n        Console.WriteLine($\"Tree Count = {tree.Count}\"); \n        // In-order\n        foreach (var x in tree)\n            Console.Write(x + \" \");\n        Console.WriteLine();\n\n        // Check membership\n        Console.WriteLine($\"Contains(10)? {tree.Contains(10)}\"); // true\n\n        // Order-statistics\n        Console.WriteLine(\"Rank(15) = \" + tree.Rank(15));  // # of elements \u003c 15\n        Console.WriteLine(\"Select(3) = \" + tree.Select(3)); // 3rd smallest\n\n        // Deletion: If a node has duplicates, we decrement first\n        // Deleting 15 once\n        tree.Delete(15);\n        Console.WriteLine($\"After deleting 15 once, count = {tree.Count}\");\n        \n        // Print in-order again\n        tree.PrintInOrder();\n    }\n}\n```\n\n**Expected Output** might look like:\n\n```\nTree Count = 7\n5 5 10 15 15 15 20 \nContains(10)? True\nRank(15) = 2\nSelect(3) = 10\nAfter deleting 15 once, count = 6\n5(Red):2[2] 10(Black):1[1] 15(Red):2[2] 20(Black):1[1] \n```\n\n(The exact color output depends on the internal balancing.)\n\n---\n\n## API Overview\n\nBelow are key members of the `RedBlackTree\u003cT\u003e` class:\n\n- **Insert(T key)**  \n  Inserts a new key in \\(O(\\log n)\\). If `key` already exists, it increments `DuplicateCount` in that node.\n\n- **Delete(T key)**  \n  Removes one occurrence of `key`. If that node has `DuplicateCount \u003e 1`, it decrements; otherwise removes the node from the tree. Returns `true` if a key was removed, `false` if not found.\n\n- **Contains(T key)**  \n  Checks membership in \\(O(\\log n)\\).\n\n- **int Count**  \n  Total number of elements, including duplicates.\n\n- **T Select(int k)**  \n  Returns the k-th smallest element (1-based). Throws if `k` is out of range.\n\n- **int Rank(T key)**  \n  Returns how many elements are strictly less than `key`. If you want “less or equal,” adapt logic in code or do `Rank(key+1)` in some scenarios (for numeric types).\n\n- **IEnumerable\u003cT\u003e**  \n  The tree is enumerable in ascending order. For duplicates, each duplicate is yielded.\n\n- **PrintInOrder()**  \n  Debug method printing each node in ascending order, along with color, `DuplicateCount`, and subtree size.\n\n---\n\n## Benchmarking\n\nWe provide a **BenchmarkDotNet** sample that measures:\n- **Insert** performance (e.g., inserting \\(N\\) elements).\n- **Search** performance (e.g., random lookups).\n- **Delete** performance.\n\nBased on these **BenchmarkDotNet** results:\n\n| Method     | Mean (ns)       | Error (ns)    | StdDev (ns)   | Median (ns)     | Allocated (B) |\n|----------- |----------------:|--------------:|--------------:|----------------:|--------------:|\n| **InsertTest** | **3,689,277.60** | **18,956.626** | **16,804.555** | **3,682,642.58** | **556,619**     |\n| **SearchTest** |             15.13 |          0.025 |          0.022 |           15.13 | 0            |\n| **DeleteTest** |             36.98 |          0.753 |          1.237 |           36.35 | 0            |\n\nyou might think the **InsertTest** is “too large” or that there is a “problem,” especially compared to the tiny times for **SearchTest** and **DeleteTest**. However, there are a few key points to understand:\n\n**InsertTest Likely Performs *N* Operations, While Search/Delete Are 1 Operation**\n\n- **InsertTest** typically inserts **tens of thousands** (or even **hundreds of thousands**) of elements in a loop. The benchmark time (e.g., ~3.68 ms) is the total **for all those insertions** combined.\n- **SearchTest** and **DeleteTest** as shown are often just **one** operation each (searching or deleting a single element). That’s why you see extremely small times (15 ns or 37 ns).\n\n**Memory Allocation (~556 KB)**\n\n- Allocating **~556,619 bytes** for tens or hundreds of thousands of inserted elements may be **reasonable**.\n- Each node has overhead (fields for parent, left, right, color, size counters, etc.).\n- If you inserted 50k or 100k elements, half a megabyte is not surprising for a tree of that size.\n\nIn short, there’s **no inherent problem** in seeing a “large” (few milliseconds) total time for **InsertTest** in contrast to sub-100-nanosecond times for single **SearchTest** or **DeleteTest**. They’re measuring fundamentally different things: a **batch** of tens/hundreds of thousands of inserts vs. **one** search or one delete.\n\n### Quick Start\n\n1. **Create a Console Project** (or use the existing sample).\n2. **Install** BenchmarkDotNet:\n\n   ```bash\n   dotnet add package BenchmarkDotNet\n   ```\n\n3. **Add** a benchmark class referencing the Red-Black Tree. For instance:\n\n   ```csharp\n   using BenchmarkDotNet.Attributes;\n   using BenchmarkDotNet.Running;\n\n   [MemoryDiagnoser]\n   public class MyRedBlackBench\n   {\n       private RedBlackTree\u003cint\u003e? _tree;\n       private int[]? _data;\n       private const int N = 100_000;\n\n       [GlobalSetup]\n       public void Setup()\n       {\n           _tree = new RedBlackTree\u003cint\u003e();\n           _data = new int[N];\n           var rand = new Random(0);\n           for (int i = 0; i \u003c N; i++)\n           {\n               _data[i] = rand.Next(1, 10_000);\n           }\n       }\n\n       [Benchmark]\n       public void InsertTest()\n       {\n           var tree = new RedBlackTree\u003cint\u003e();\n           for (int i = 0; i \u003c N; i++)\n           {\n               tree.Insert(_data![i]);\n           }\n       }\n\n       [Benchmark]\n       public bool SearchTest()\n       {\n           return _tree!.Contains(_data![N / 2]);\n       }\n   }\n\n   class Program\n   {\n       static void Main(string[] args)\n       {\n           var summary = BenchmarkRunner.Run\u003cMyRedBlackBench\u003e();\n       }\n   }\n   ```\n\n4. **Run** in Release mode:\n\n   ```bash\n   dotnet run -c Release\n   ```\n\nYou’ll see an output table with timings and memory usage.\n\n---\n\n## Contributing\n\nContributions are welcome! Feel free to:\n\n1. Open issues for bugs, edge-case failures, or enhancements.\n2. Submit pull requests with improved balancing logic, concurrency support, or additional features (like **range queries**, custom comparers, etc.).\n\nPlease include relevant **tests** for any changes to maintain code quality.\n\n---\n\n## License\n\nThis project is available under a permissive license \\(e.g. [MIT License](https://opensource.org/licenses/MIT)\\).\n\n---\n\n**Enjoy using the Red-Black Tree with order statistics and multiset support!** If you find any issues, please open an issue or create a pull request. Happy coding!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphmatray%2Fredblack","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphmatray%2Fredblack","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphmatray%2Fredblack/lists"}