{"id":13520379,"url":"https://github.com/bexxmodd/priq","last_synced_at":"2026-03-17T23:38:24.546Z","repository":{"id":62442914,"uuid":"455924950","full_name":"bexxmodd/priq","owner":"bexxmodd","description":"Blazing fast Priority Queue that allows sorting for elements with partial ordering","archived":false,"fork":false,"pushed_at":"2022-04-20T15:02:09.000Z","size":62,"stargazers_count":23,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-02T15:36:24.551Z","etag":null,"topics":["data-structures","heap","rust"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/priq","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bexxmodd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-02-05T16:37:53.000Z","updated_at":"2025-09-23T18:38:11.000Z","dependencies_parsed_at":"2022-11-01T22:16:34.725Z","dependency_job_id":null,"html_url":"https://github.com/bexxmodd/priq","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/bexxmodd/priq","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bexxmodd%2Fpriq","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bexxmodd%2Fpriq/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bexxmodd%2Fpriq/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bexxmodd%2Fpriq/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bexxmodd","download_url":"https://codeload.github.com/bexxmodd/priq/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bexxmodd%2Fpriq/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30635282,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-17T22:38:22.569Z","status":"ssl_error","status_checked_at":"2026-03-17T22:38:11.804Z","response_time":56,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["data-structures","heap","rust"],"created_at":"2024-08-01T05:02:18.828Z","updated_at":"2026-03-17T23:38:24.506Z","avatar_url":"https://github.com/bexxmodd.png","language":"Rust","readme":"# priq\n\nPriority queue (min/max heap) using raw binary heap.\n\n`PriorityQueue` is built using raw array for efficient performance.\n\nThere are two major reasons what makes this `PriorityQueue` different from\nother binary heap implementations currently available:\n\n1 - Allows data ordering to scores with `PartialOrd`.\n    - Every other min-max heap requires [total ordering](https://bit.ly/3GCWvYL) \n    of scores (e.g. should implement `Ord` trait). This can be an issue, \n    for example, when you want to order items based on a float scores, \n    which doesn't implement `Ord` trait.\n    - Because of partial ordering, non-comparable values are thrown in \n    the end of the queue. One will see non-comparable values only after all \n    the comparable elements have been `pop`-ed.\n    - You can read about Rust's implementation or `Ord`, `PartialOrd` and \n    what's the different [here](https://bit.ly/3J7NwQI)\n\n2 - Separation of score and item you wish to store.\n    - This frees enforcement for associated items to implement any ordering.\n    - Makes easier to evaluate items' order.\n\n3 - Equal scoring items are stored at first available free space.\n    - This gives performance boost for large number of entries.\n\n4 - Easy to use!\n\nYou can read more about this crate on [my blog](https://www.bexxmodd.com)\n\n# Implementation\n\nA Min-Max Heap with designated arguments for `score` and associated `item`!\n\nA `Default` implementation is a Min-Heap where the top node (root) is the \nlowest scoring element:\n\n                        10\n                       /  \\\n                    58      70\n                   /  \\    /  \\\n                 80   92  97   99\n\n\u003e The value of Parent Node is small than Child Node.\n\nEvery parent node, including the top (root) node, is less than or equal to \nequal to the right child.\n\n`PriorityQueue ` allows duplicate score/item values. When you [`put`]the \nitem with a similar score that’s already in the queue new entry will be \nstored at the first empty location in memory. This gives an incremental \nperformance boost (instead of resolving by using the associated item as a \nsecondary tool to priority evaluation). Also, this form of implementation \ndoesn’t enforce for the element `T` to have any implemented ordering. This\nguarantees that the top node will always be of minimum value.\n\nYou can initialize an empty `PriorityQueue` and later add items:\n\n```rust\nuse priq::PriorityQueue;\n\n// create queue with `usize` key and `String` elements\nlet pq: PriorityQueue\u003cusize, String\u003e = PriorityQueue::new();\n```\n\nOr you can _heapify_ a `Vec` and/or a `slice`:\n\n```rust\nuse priq::PriorityQueue;\n\nlet pq_from_vec = PriorityQueue::from(vec![(5, 55), (1, 11), (4, 44)]);\nlet pq_from_slice = PriorityQueue::from([(5, 55), (1, 11), (4, 44)]);\n```\n\n# Partial Ordering\n\nBecause `priq` allows `score` arguments that only implement `PartialOrd`, \nelements that can't be compared are evaluated and are put in the back of\nthe queue:\n\n```rust\nuse priq::PriorityQueue;\n\nlet mut pq: PriorityQueue\u003cf32, isize\u003e = PriorityQueue::new();\n\npq.put(1.1, 10);\npq.put(f32::NAN, -1);\npq.put(2.2, 20);\npq.put(3.3, 30);\npq.put(f32::NAN, -3);\npq.put(4.4, 40);\n\n(1..=4).for_each(|i| assert_eq!(i * 10, pq.pop().unwrap().1));\n\n// NAN scores will not have deterministic order\n// they are just stored after all the comparable scores\nassert!(0 \u003e pq.pop().unwrap().1);\nassert!(0 \u003e pq.pop().unwrap().1);\n```\n\n# Time\n\nThe standard usage of this data structure is to [`put`] an element to the \nqueue and [`pop`] to remove the top element and peek to check what’s the \ntop element in the queue. The stored structure of the elements is a balanced\ntree realized using an array with a contiguous memory location. This allows\nmaintaining a proper parent-child relationship between put-ed items.\n\n[`put`]: PriorityQueue::put\n[`peek`]: PriorityQueue::peek\n[`pop`]: PriorityQueue::pop\n\n\nRuntime complexity with Big-O Notation:\n\n| method    | Time Complexity |\n|-----------|-----------------|\n| [`put`]   | _O(log(n))_     |\n| [`pop`]   | _O(log(n))_     |\n| [`peek`]  | _O(1)_          |\n\nYou can also iterate over elements using for loop but the returned slice \nwill not be properly order as the heap is re-balanced after each insertion \nand deletion. If you want to grab items in a proper priority call [`pop`] \nin a loop until it returns `None`.\n\n\n# Custom `struct`\n\nWhat if you want to custom `struct ` without having a separate and \nspecific score? You can pass the `struct`’s clone as a `score` and as an \nassociated value, but if in this kind of scenario I’d recommend using\n[`BinaryHeap`] as it better fits the purpose.\n\n\n# Min-Heap\n\nIf instead of Min-Heap you want to have Max-Heap, where the highest-scoring \nelement is on top you can pass score using [`Reverse`] or a custom [`Ord`] \nimplementation can be used to have custom prioritization logic.\n\n[`BinaryHeap`]: std::collections::BinaryHeap\n[`Reverse`]: std::cmp::Reverse\n\n# Example\n\n```rust\nuse priq::PriorityQueue;\nuse std::cmp::Reverse;\n\nlet mut pq: PriorityQueue\u003cReverse\u003cu8\u003e, String\u003e = PriorityQueue::new();\n\npq.put(Reverse(26), \"Z\".to_string());\npq.put(Reverse(1), \"A\".to_string());\n\nassert_eq!(pq.pop().unwrap().1, \"Z\");\n```\n# Merging and Combining \n\nYou can merge another priority queue to this one. Right hand side priority\nqueue will be drained into the left hand side priority queue.\n\n# Examples\n\n```rust\nuse priq::PriorityQueue;\n\nlet mut pq1 = PriorityQueue::from([(5, 55), (6, 66), (3, 33), (2, 22)]);\nlet mut pq2 = PriorityQueue::from([(4, 44), (1, 11)]);\n\npq1.merge(\u0026mut pq2);\n// at this point `pq2` is empty\n\nassert_eq!(6, pq1.len());\nassert_eq!(11, pq1.peek().unwrap().1);\n```\n\nYou can also use `+` operator to combine two priority queues. Operands will\nbe intact. New priority queue will be build from cloning and merging them.\n\n# Example\n\n```rust\nuse priq::PriorityQueue;\n\nlet pq1 = PriorityQueue::from([(5, 55), (1, 11), (4, 44), (2, 22)]);\nlet pq2 = PriorityQueue::from([(8, 44), (1, 22)]);\n\nlet res = pq1 + pq2;\n\nassert_eq!(6, res.len());\nassert_eq!(11, res.peek().unwrap().1);\n```\n\n## Performance\n\nThis are the benchmark results for `priq::PriorityQueue`:\n\n\n| `priq` benches | median | nanosecs | std.dev |\n|-----|-------:|:----------:|:--------|\n| pq_pop_100      |        146 | ns/iter | (+/- 1)\n| pq_pop_100k     |    291,818 | ns/iter | (+/- 5,686)\n| pq_pop_10k      |     14,129 | ns/iter | (+/- 39)\n| pq_pop_1k       |      1,646 | ns/iter | (+/- 32)\n| pq_pop_1mil     | 16,517,047 | ns/iter | (+/- 569,128|\n| pq_put_100      |        488 | ns/iter | (+/- 21)\n| pq_put_100k     |    758,422 | ns/iter | (+/- 13,961)\n| pq_put_100k_wcap|    748,824 | ns/iter | (+/- 7,926)\n| pq_put_10k      |     80,668 | ns/iter | (+/- 1,324)\n| pq_put_1k       |      8,769 | ns/iter | (+/- 78)\n| pq_put_1mil     |  6,728,203 | ns/iter | (+/- 76,416)\n| pq_put_1mil_wcap|  6,622,341 | ns/iter | (+/- 77,162)\n\n\nHow it compares to `std::collections::BinaryHeap`:\n\n| `BinaryHeap` benches | median | nanosecs | std.dev |\n|-----|-------:|:----------:|:--------|\n| bh_pop_100  |         272 | ns/iter | (+/- 90)\n| bh_pop_100k |     171,071 | ns/iter | (+/- 6,131)\n| bh_pop_10k  |      13,904 | ns/iter | (+/- 130)\n| bh_pop_1k   |       1,847 | ns/iter | (+/- 6)\n| bh_pop_1mil |   8,772,066 | ns/iter | (+/- 611,613)\n| bh_push_100 |         857 | ns/iter | (+/- 50)\n| bh_push_100k|     943,465 | ns/iter | (+/- 108,698)\n| bh_push_10k |      92,807 | ns/iter | (+/- 7,930)\n| bh_push_1k  |       8,606 | ns/iter | (+/- 639)\n| bh_push_1mil|  12,946,815 | ns/iter | (+/- 900,347)\n\n\n------------\nProject is distributed under the MIT license. Please see the `LICENSE` for more information.\n","funding_links":[],"categories":["Rust"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbexxmodd%2Fpriq","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbexxmodd%2Fpriq","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbexxmodd%2Fpriq/lists"}