├── .ci ├── install_darwin.sh └── install_linux.sh ├── .clang-format ├── .gitignore ├── .travis.yml ├── BUILD ├── LICENSE ├── README.md ├── WORKSPACE ├── appveyor.yml ├── priority_queue.sln ├── priority_queue ├── BUILD ├── BinaryHeap.h ├── Heap.h ├── KHeap.h ├── PriorityQueue.h ├── priority_queue.filters └── priority_queue.vcxproj ├── tests ├── BUILD ├── MaxBinaryHeap_test.cpp ├── MaxKHeap_test.cpp ├── MinBinaryHeap_test.cpp └── MinKHeap_test.cpp └── variables.bzl /.ci/install_darwin.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -ev 4 | 5 | OS=darwin 6 | ARCH=x86_64 7 | 8 | # install bazel 9 | GH_BASE="https://github.com/bazelbuild/bazel/releases/download/$V_BAZEL" 10 | GH_ARTIFACT="bazel-$V_BAZEL-installer-$OS-$ARCH.sh" 11 | URL="$GH_BASE/$GH_ARTIFACT" 12 | echo "$URL" 13 | wget -O install_bazel.sh "$URL" 14 | chmod +x install_bazel.sh 15 | ./install_bazel.sh --user 16 | rm -f install_bazel.sh 17 | 18 | # install clang-format 19 | brew install clang-format 20 | clang-format --version 21 | -------------------------------------------------------------------------------- /.ci/install_linux.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -ev 4 | 5 | OS=linux 6 | ARCH=x86_64 7 | 8 | # install bazel 9 | GH_BASE="https://github.com/bazelbuild/bazel/releases/download/$V_BAZEL" 10 | GH_ARTIFACT="bazel-$V_BAZEL-installer-$OS-$ARCH.sh" 11 | URL="$GH_BASE/$GH_ARTIFACT" 12 | echo "$URL" 13 | wget -O install_bazel.sh "$URL" 14 | chmod +x install_bazel.sh 15 | ./install_bazel.sh --user 16 | rm -f install_bazel.sh 17 | 18 | # install clang-format 19 | sudo apt install clang-format 20 | clang-format --version 21 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: Google 3 | AccessModifierOffset: '-4' 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveMacros: 'false' 6 | AlignConsecutiveAssignments: 'false' 7 | AlignConsecutiveDeclarations: 'false' 8 | AlignOperands: 'true' 9 | AllowAllArgumentsOnNextLine: 'false' 10 | AllowAllParametersOfDeclarationOnNextLine: 'false' 11 | AllowShortBlocksOnASingleLine: 'false' 12 | AllowShortFunctionsOnASingleLine: None 13 | AllowShortIfStatementsOnASingleLine: Never 14 | AllowShortLambdasOnASingleLine: None 15 | AllowShortLoopsOnASingleLine: 'false' 16 | AlwaysBreakAfterDefinitionReturnType: None 17 | AlwaysBreakAfterReturnType: None 18 | AlwaysBreakTemplateDeclarations: 'Yes' 19 | BreakConstructorInitializers: AfterColon 20 | BreakStringLiterals: 'true' 21 | ColumnLimit: '100' 22 | Cpp11BracedListStyle: 'true' 23 | FixNamespaceComments: 'true' 24 | IndentCaseLabels: 'false' 25 | IndentWidth: '4' 26 | IndentWrappedFunctionNames: 'false' 27 | KeepEmptyLinesAtTheStartOfBlocks: 'true' 28 | Language: Cpp 29 | NamespaceIndentation: All 30 | SpaceInEmptyParentheses: 'false' 31 | SpacesInAngles: 'false' 32 | SpacesInCStyleCastParentheses: 'false' 33 | SpacesInContainerLiterals: 'false' 34 | SpacesInParentheses: 'false' 35 | SpacesInSquareBrackets: 'false' 36 | Standard: Cpp11 37 | TabWidth: '4' 38 | UseTab: Never 39 | 40 | ... 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/c++,bazel,visualstudio,visualstudiocode 3 | # Edit at https://www.gitignore.io/?templates=c++,bazel,visualstudio,visualstudiocode 4 | 5 | ### Bazel ### 6 | # gitignore template for Bazel build system 7 | # website: https://bazel.build/ 8 | 9 | # Ignore all bazel-* symlinks. There is no full list since this can change 10 | # based on the name of the directory bazel is cloned into. 11 | /bazel-* 12 | 13 | ### C++ ### 14 | # Prerequisites 15 | *.d 16 | 17 | # Compiled Object files 18 | *.slo 19 | *.lo 20 | *.o 21 | *.obj 22 | 23 | # Precompiled Headers 24 | *.gch 25 | *.pch 26 | 27 | # Compiled Dynamic libraries 28 | *.so 29 | *.dylib 30 | *.dll 31 | 32 | # Fortran module files 33 | *.mod 34 | *.smod 35 | 36 | # Compiled Static libraries 37 | *.lai 38 | *.la 39 | *.a 40 | *.lib 41 | 42 | # Executables 43 | *.exe 44 | *.out 45 | *.app 46 | 47 | ### VisualStudioCode ### 48 | .vscode/* 49 | !.vscode/settings.json 50 | !.vscode/tasks.json 51 | !.vscode/launch.json 52 | !.vscode/extensions.json 53 | 54 | ### VisualStudioCode Patch ### 55 | # Ignore all local history of files 56 | .history 57 | 58 | ### VisualStudio ### 59 | ## Ignore Visual Studio temporary files, build results, and 60 | ## files generated by popular Visual Studio add-ons. 61 | ## 62 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 63 | 64 | # User-specific files 65 | *.rsuser 66 | *.suo 67 | *.user 68 | *.userosscache 69 | *.sln.docstates 70 | 71 | # User-specific files (MonoDevelop/Xamarin Studio) 72 | *.userprefs 73 | 74 | # Mono auto generated files 75 | mono_crash.* 76 | 77 | # Build results 78 | [Dd]ebug/ 79 | [Dd]ebugPublic/ 80 | [Rr]elease/ 81 | [Rr]eleases/ 82 | x64/ 83 | x86/ 84 | [Aa][Rr][Mm]/ 85 | [Aa][Rr][Mm]64/ 86 | bld/ 87 | [Bb]in/ 88 | [Oo]bj/ 89 | [Ll]og/ 90 | 91 | # Visual Studio 2015/2017 cache/options directory 92 | .vs/ 93 | # Uncomment if you have tasks that create the project's static files in wwwroot 94 | #wwwroot/ 95 | 96 | # Visual Studio 2017 auto generated files 97 | Generated\ Files/ 98 | 99 | # MSTest test Results 100 | [Tt]est[Rr]esult*/ 101 | [Bb]uild[Ll]og.* 102 | 103 | # NUnit 104 | *.VisualState.xml 105 | TestResult.xml 106 | nunit-*.xml 107 | 108 | # Build Results of an ATL Project 109 | [Dd]ebugPS/ 110 | [Rr]eleasePS/ 111 | dlldata.c 112 | 113 | # Benchmark Results 114 | BenchmarkDotNet.Artifacts/ 115 | 116 | # .NET Core 117 | project.lock.json 118 | project.fragment.lock.json 119 | artifacts/ 120 | 121 | # StyleCop 122 | StyleCopReport.xml 123 | 124 | # Files built by Visual Studio 125 | *_i.c 126 | *_p.c 127 | *_h.h 128 | *.ilk 129 | *.iobj 130 | *.pdb 131 | *.ipdb 132 | *.pgc 133 | *.pgd 134 | *.rsp 135 | *.sbr 136 | *.tlb 137 | *.tli 138 | *.tlh 139 | *.tmp 140 | *.tmp_proj 141 | *_wpftmp.csproj 142 | *.log 143 | *.vspscc 144 | *.vssscc 145 | .builds 146 | *.pidb 147 | *.svclog 148 | *.scc 149 | 150 | # Chutzpah Test files 151 | _Chutzpah* 152 | 153 | # Visual C++ cache files 154 | ipch/ 155 | *.aps 156 | *.ncb 157 | *.opendb 158 | *.opensdf 159 | *.sdf 160 | *.cachefile 161 | *.VC.db 162 | *.VC.VC.opendb 163 | 164 | # Visual Studio profiler 165 | *.psess 166 | *.vsp 167 | *.vspx 168 | *.sap 169 | 170 | # Visual Studio Trace Files 171 | *.e2e 172 | 173 | # TFS 2012 Local Workspace 174 | $tf/ 175 | 176 | # Guidance Automation Toolkit 177 | *.gpState 178 | 179 | # ReSharper is a .NET coding add-in 180 | _ReSharper*/ 181 | *.[Rr]e[Ss]harper 182 | *.DotSettings.user 183 | 184 | # JustCode is a .NET coding add-in 185 | .JustCode 186 | 187 | # TeamCity is a build add-in 188 | _TeamCity* 189 | 190 | # DotCover is a Code Coverage Tool 191 | *.dotCover 192 | 193 | # AxoCover is a Code Coverage Tool 194 | .axoCover/* 195 | !.axoCover/settings.json 196 | 197 | # Visual Studio code coverage results 198 | *.coverage 199 | *.coveragexml 200 | 201 | # NCrunch 202 | _NCrunch_* 203 | .*crunch*.local.xml 204 | nCrunchTemp_* 205 | 206 | # MightyMoose 207 | *.mm.* 208 | AutoTest.Net/ 209 | 210 | # Web workbench (sass) 211 | .sass-cache/ 212 | 213 | # Installshield output folder 214 | [Ee]xpress/ 215 | 216 | # DocProject is a documentation generator add-in 217 | DocProject/buildhelp/ 218 | DocProject/Help/*.HxT 219 | DocProject/Help/*.HxC 220 | DocProject/Help/*.hhc 221 | DocProject/Help/*.hhk 222 | DocProject/Help/*.hhp 223 | DocProject/Help/Html2 224 | DocProject/Help/html 225 | 226 | # Click-Once directory 227 | publish/ 228 | 229 | # Publish Web Output 230 | *.[Pp]ublish.xml 231 | *.azurePubxml 232 | # Note: Comment the next line if you want to checkin your web deploy settings, 233 | # but database connection strings (with potential passwords) will be unencrypted 234 | *.pubxml 235 | *.publishproj 236 | 237 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 238 | # checkin your Azure Web App publish settings, but sensitive information contained 239 | # in these scripts will be unencrypted 240 | PublishScripts/ 241 | 242 | # NuGet Packages 243 | *.nupkg 244 | # NuGet Symbol Packages 245 | *.snupkg 246 | # The packages folder can be ignored because of Package Restore 247 | **/[Pp]ackages/* 248 | # except build/, which is used as an MSBuild target. 249 | !**/[Pp]ackages/build/ 250 | # Uncomment if necessary however generally it will be regenerated when needed 251 | #!**/[Pp]ackages/repositories.config 252 | # NuGet v3's project.json files produces more ignorable files 253 | *.nuget.props 254 | *.nuget.targets 255 | 256 | # Microsoft Azure Build Output 257 | csx/ 258 | *.build.csdef 259 | 260 | # Microsoft Azure Emulator 261 | ecf/ 262 | rcf/ 263 | 264 | # Windows Store app package directories and files 265 | AppPackages/ 266 | BundleArtifacts/ 267 | Package.StoreAssociation.xml 268 | _pkginfo.txt 269 | *.appx 270 | *.appxbundle 271 | *.appxupload 272 | 273 | # Visual Studio cache files 274 | # files ending in .cache can be ignored 275 | *.[Cc]ache 276 | # but keep track of directories ending in .cache 277 | !?*.[Cc]ache/ 278 | 279 | # Others 280 | ClientBin/ 281 | ~$* 282 | *~ 283 | *.dbmdl 284 | *.dbproj.schemaview 285 | *.jfm 286 | *.pfx 287 | *.publishsettings 288 | orleans.codegen.cs 289 | 290 | # Including strong name files can present a security risk 291 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 292 | #*.snk 293 | 294 | # Since there are multiple workflows, uncomment next line to ignore bower_components 295 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 296 | #bower_components/ 297 | 298 | # RIA/Silverlight projects 299 | Generated_Code/ 300 | 301 | # Backup & report files from converting an old project file 302 | # to a newer Visual Studio version. Backup files are not needed, 303 | # because we have git ;-) 304 | _UpgradeReport_Files/ 305 | Backup*/ 306 | UpgradeLog*.XML 307 | UpgradeLog*.htm 308 | ServiceFabricBackup/ 309 | *.rptproj.bak 310 | 311 | # SQL Server files 312 | *.mdf 313 | *.ldf 314 | *.ndf 315 | 316 | # Business Intelligence projects 317 | *.rdl.data 318 | *.bim.layout 319 | *.bim_*.settings 320 | *.rptproj.rsuser 321 | *- [Bb]ackup.rdl 322 | *- [Bb]ackup ([0-9]).rdl 323 | *- [Bb]ackup ([0-9][0-9]).rdl 324 | 325 | # Microsoft Fakes 326 | FakesAssemblies/ 327 | 328 | # GhostDoc plugin setting file 329 | *.GhostDoc.xml 330 | 331 | # Node.js Tools for Visual Studio 332 | .ntvs_analysis.dat 333 | node_modules/ 334 | 335 | # Visual Studio 6 build log 336 | *.plg 337 | 338 | # Visual Studio 6 workspace options file 339 | *.opt 340 | 341 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 342 | *.vbw 343 | 344 | # Visual Studio LightSwitch build output 345 | **/*.HTMLClient/GeneratedArtifacts 346 | **/*.DesktopClient/GeneratedArtifacts 347 | **/*.DesktopClient/ModelManifest.xml 348 | **/*.Server/GeneratedArtifacts 349 | **/*.Server/ModelManifest.xml 350 | _Pvt_Extensions 351 | 352 | # Paket dependency manager 353 | .paket/paket.exe 354 | paket-files/ 355 | 356 | # FAKE - F# Make 357 | .fake/ 358 | 359 | # CodeRush personal settings 360 | .cr/personal 361 | 362 | # Python Tools for Visual Studio (PTVS) 363 | __pycache__/ 364 | *.pyc 365 | 366 | # Cake - Uncomment if you are using it 367 | # tools/** 368 | # !tools/packages.config 369 | 370 | # Tabs Studio 371 | *.tss 372 | 373 | # Telerik's JustMock configuration file 374 | *.jmconfig 375 | 376 | # BizTalk build output 377 | *.btp.cs 378 | *.btm.cs 379 | *.odx.cs 380 | *.xsd.cs 381 | 382 | # OpenCover UI analysis results 383 | OpenCover/ 384 | 385 | # Azure Stream Analytics local run output 386 | ASALocalRun/ 387 | 388 | # MSBuild Binary and Structured Log 389 | *.binlog 390 | 391 | # NVidia Nsight GPU debugger configuration file 392 | *.nvuser 393 | 394 | # MFractors (Xamarin productivity tool) working folder 395 | .mfractor/ 396 | 397 | # Local History for Visual Studio 398 | .localhistory/ 399 | 400 | # BeatPulse healthcheck temp database 401 | healthchecksdb 402 | 403 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 404 | MigrationBackup/ 405 | 406 | # End of https://www.gitignore.io/api/c++,bazel,visualstudio,visualstudiocode 407 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | cache: 4 | - directories: 5 | - $HOME/.cache 6 | 7 | notifications: 8 | email: 9 | on_success: change 10 | on_failure: change 11 | 12 | stages: 13 | - name: test 14 | - name: deploy 15 | if: tag IS present 16 | 17 | env: 18 | global: 19 | # Bazel version 20 | - V_BAZEL=3.1.0 21 | 22 | # Execute unit tests in Linux and MacOSX with the latest stable versions of 23 | # g++ and clang++ 24 | jobs: 25 | include: 26 | - stage: test 27 | os: linux 28 | dist: xenial 29 | before_install: chmod +x ./.ci/install_linux.sh 30 | install: ./.ci/install_linux.sh 31 | addons: 32 | apt: 33 | sources: 34 | - ubuntu-toolchain-r-test 35 | packages: 36 | - g++-9 37 | env: 38 | - MATRIX_EVAL="CXX=g++-9" 39 | - CC="g++-9" 40 | 41 | - stage: test 42 | os: linux 43 | dist: xenial 44 | before_install: chmod +x ./.ci/install_linux.sh 45 | install: ./.ci/install_linux.sh 46 | addons: 47 | apt: 48 | sources: 49 | - ubuntu-toolchain-r-test 50 | - sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main' 51 | key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key' 52 | packages: 53 | - clang-10 54 | env: 55 | - MATRIX_EVAL="CXX=clang++-10" 56 | - CC="clang++-10" 57 | 58 | - stage: test 59 | os: osx 60 | osx_image: xcode11.3 61 | before_install: chmod +x ./.ci/install_darwin.sh 62 | install: ./.ci/install_darwin.sh 63 | env: 64 | - MATRIX_EVAL="CXX=clang++" 65 | - CC="clang++" 66 | 67 | - stage: deploy 68 | before_script: skip 69 | script: skip 70 | install: skip 71 | before_deploy: 72 | # prepare release folder 73 | - tar -czf ./priority-queue.tar.gz ./priority_queue/*.h 74 | - export DEPLOY_PACKAGE=./priority-queue.tar.gz 75 | - echo "DEPLOY_PACKAGE is ${DEPLOY_PACKAGE}" 76 | deploy: 77 | provider: releases 78 | api_key: $GITHUB_TOKEN 79 | file: 80 | - README.md 81 | - $DEPLOY_PACKAGE 82 | skip_cleanup: true 83 | overwrite: true 84 | on: 85 | # Releases deployment will trigger if and only if the build is tagged 86 | tags: true 87 | 88 | before_script: 89 | - eval "${MATRIX_EVAL}" 90 | 91 | script: 92 | - find . -name "*.h" -o -name "*.cpp" -exec clang-format -i {} \; 93 | # throw error if the project doesn't follow clang-format 94 | - git diff --exit-code 95 | 96 | # run unit tests 97 | - | 98 | bazel \ 99 | --output_base=$HOME/.cache/bazel \ 100 | --batch \ 101 | --host_jvm_args=-Xmx500m \ 102 | --host_jvm_args=-Xms500m \ 103 | test //... 104 | -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jkomyno/priority-queue/6d8a3d3d5f33d16abcfe7aadcd11769d57350ff8/BUILD -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Alberto Schiabel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Priority Queue 2 | 3 | [![Build Status Travis](https://travis-ci.org/jkomyno/priority-queue.svg?branch=master)](https://travis-ci.org/jkomyno/priority-queue) 4 | [![Build status AppVeyor](https://ci.appveyor.com/api/projects/status/p4j96cu6e3x1k34w?svg=true)](https://ci.appveyor.com/project/jkomyno/priority-queue) 5 | [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE) 6 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/939d15efb7374e85a92250ac7bbecbe0)](https://www.codacy.com/manual/jkomyno/priority-queue?utm_source=github.com&utm_medium=referral&utm_content=jkomyno/priority-queue&utm_campaign=Badge_Grade) 7 | 8 | **Deprecation Notice**: please use the container classes `BinaryHeap`, `KHeap`, and `PriorityQueue` in [`jkomyno/jkds`](https://github.com/jkomyno/jkds). 9 | 10 | This package provides a header-only, generic and dependency-free C++17 implementation of Heaps and Priority Queues. 11 | It exposes two namespaces: `heap` and `priority_queue`. 12 | 13 | ## Table of Contents 14 | 15 | - [Why](#why) 16 | - [Heap](#heap) 17 | - [Example usage of BinaryHeap](#example-usage-of-binaryheap) 18 | - [Example usage of KHeap](#example-usage-of-kheap) 19 | - [Priority Queue](#priority-queue-1) 20 | - [Example usage of PriorityQueue with BinaryHeap](#example-usage-of-priorityqueue-with-binaryheap) 21 | - [Example usage of PriorityQueue with KHeap](#example-usage-of-priorityqueue-with-kheap) 22 | - [Best practices adopted](#best-practices-adopted) 23 | - [Test](#test) 24 | - [Contributing](#contributing) 25 | 26 | ## Why 27 | 28 | > Why did you have to go through the hassle of creating your own Heap and Priority Queue implementations when 29 | > the standard library offers `std::make_heap` and the `std::priority_queue container` adaptor? 30 | 31 | My answers to this question are multifold: 32 | 33 | - The STL doesn't offer any method to update the keys when the elements are stored in the Heap. 34 | Doing that manually can be non-trivial and usually requires at least O(N) time (while this library achieves that faster). 35 | - The STL doesn't provide any way of creating K-ary Heaps or Priority Queues based on K-ary Heaps. 36 | - For University, I was required to implement Prim's algorithm, but wasn't allowed to use `std::make_heap` and `std::priority_queue container`. 37 | - I've used this project as an exercise to enhance my comprehension of C++17 and its best practices, as well as _DRY_ principles. 38 | 39 | ## Heap 40 | 41 | The `heap` namespace contains the abstract class [`Heap`](./priority_queue/Heap.h) and the concrete implementations [`BinaryHeap`](./priority_queue/BinaryHeap.h) (for Binary Heaps) 42 | and [`KHeap`](./priority_queue/KHeap.h) (for K-ary Heaps). A Binary Heap can be seen as a complete binary tree which satisfies the heap ordering property. 43 | A K-ary Heap is, on the other hand, a generalization of the Binary Heap in which the nodes have `K` children instead of 2. 44 | 45 | Both `BinaryHeap` and `KHeap` are either Min Heaps or Max Heaps depending on comparator used to initialize them, 46 | much like what happens in the STL. To get a Min Heap, the given comparator should be `std::less<>{}`, whereas to get 47 | a Max Heap, the given comparator should be `std::greater<>{}`. 48 | 49 | A number of utility factory functions are provided to easily create the type of Heap you want, namely: 50 | 51 | - `make_min_heap`: create a Min Binary Heap starting from a vector of values. 52 | - `make_max_heap`: create a Max Binary Heap starting from a vector of values. 53 | - `make_min_k_heap`: create a Min K-ary Heap starting from a vector of keys and a vector of values. 54 | - `make_max_k_heap`: create a Max K-ary Heap starting from a vector of keys and a vector of values. 55 | 56 | Each of these functions supports both copy and move semantics for the given inputs. 57 | 58 | Optionally, if you know that the vector you're feeding to the Heap implementation already respects the Heap property 59 | (i.e. `std::is_heap(your_vector)` evaluates to `true`), you can set the template argument `IsAlreadyHeap` to true. 60 | This avoids the `O(N)` time required to build the heap. This template argument is checked at compile time thanks to `if constexpr`. 61 | 62 | ### Example usage of BinaryHeap 63 | 64 | ```c++ 65 | #include 66 | #include "priority_queue/BinaryHeap.h" 67 | 68 | int main() { 69 | std::vector vec { 'b', 'c', 'f', 'a', 'e', 'd' }; 70 | auto min_heap(heap::make_min_heap(std::move(vec))); 71 | 72 | while (!min_heap.empty()) { 73 | std::cout << "Min: " << min_heap.top() << std::endl; 74 | min_heap.pop(); 75 | } 76 | 77 | // Output: 78 | // Min: a 79 | // Min: b 80 | // Min: c 81 | // Min: d 82 | // Min: e 83 | // Min: f 84 | 85 | std::cout << std::endl << std::endl; 86 | 87 | auto max_heap(heap::make_max_heap()); 88 | 89 | max_heap.push(30); 90 | max_heap.push(15); 91 | max_heap.push(5000); 92 | max_heap.push(50); 93 | max_heap.push(599); 94 | 95 | while (!max_heap.empty()) { 96 | std::cout << "Max: " << max_heap.top() << std::endl; 97 | max_heap.pop(); 98 | } 99 | 100 | // Output: 101 | // Max: 5000 102 | // Max: 599 103 | // Max: 50 104 | // Max: 30 105 | // Max: 15 106 | } 107 | ``` 108 | 109 | ### Example usage of KHeap 110 | 111 | ```c++ 112 | #include 113 | #include "priority_queue/KHeap.h" 114 | 115 | int main() { 116 | std::vector vec { 'b', 'c', 'f', 'a', 'e', 'd' }; 117 | constexpr std::size_t K1 = 4; 118 | auto min_heap(heap::make_min_k_heap(std::move(vec))); 119 | 120 | while (!min_heap.empty()) { 121 | std::cout << "Min: " << min_heap.top() << std::endl; 122 | min_heap.pop(); 123 | } 124 | 125 | // Output: 126 | // Min: a 127 | // Min: b 128 | // Min: c 129 | // Min: d 130 | // Min: e 131 | // Min: f 132 | 133 | std::cout << std::endl << std::endl; 134 | 135 | constexpr std::size_t K2 = 3; 136 | auto max_heap(heap::make_max_k_heap()); 137 | 138 | max_heap.push(30); 139 | max_heap.push(15); 140 | max_heap.push(5000); 141 | max_heap.push(50); 142 | max_heap.push(599); 143 | 144 | while (!max_heap.empty()) { 145 | std::cout << "Max: " << max_heap.top() << std::endl; 146 | max_heap.pop(); 147 | } 148 | 149 | // Output: 150 | // Max: 5000 151 | // Max: 599 152 | // Max: 50 153 | // Max: 30 154 | // Max: 15 155 | } 156 | ``` 157 | 158 | ## Priority Queue 159 | 160 | The `priority_queue` namespace contains the concrete class [`PriorityQueue`](./priority_queue/PriorityQueue.h). 161 | It implements a Priority Queue data-structure based on a generic Heap. 162 | It privately extends either `BinaryHeap` or `KHeap`, 163 | depending on the first template argument received. This allows `PriorityQueue` to access the `protected` vector of nodes stored in `Heap`. 164 | A SFINAE check ensures that `PriorityQueue` can only extend a concrete implementation of `heap::Heap` compatible with the other template arguments received. 165 | 166 | The main methods exposed by `PriorityQueue` are: 167 | 168 | - `size()`: return the number of elements in the heap. Time complexity: O(1). 169 | - `empty()`: return true iff the heap is empty. Time complexity: O(1). 170 | - `push(const Key& key, const T& element)`: add a new element to the heap and associates the given key to it. Time complexity: O(logN) amortized if using BinaryHeap, O(k\*log_k(N)) amortized instead. 171 | - `update_key(const Key& key, const T& element)`: update the key of an existing element in the priority queue. Time: O(logN) amortized if using BinaryHeap, O(k\*log_k(N)) amortized instead. 172 | - `contains(const T& element)`: return true iff the given element is in the priority queue. Time: O(1) amortized. 173 | - `top()`: return the top element. Time: O(1). 174 | - `pop()`: remove the top element. Time: O(logN) amortized if using BinaryHeap, O(k\*log_k(N)) amortized instead. 175 | 176 | **Note**: in order to keep `update_key`'s complexity logarithmic instead of linear, there's a quite important caveat: arbitrary key updates are not allowed. 177 | If you're using a Priority Queue based on a Max-Heap, you can only perform a "increase key" operation. 178 | If you're using a Priority Queue based on a Min-Heap, you can only perform a "decrease key" operation. 179 | Arbitrary key updates may result in undefined behaviour. 180 | 181 | A number of utility factory functions are provided to easily create the type of Priority Queue you want, namely: 182 | 183 | - `make_min_priority_queue>`: create a Priority Queue based on a Min Heap starting from a vector of values. 184 | - `make_max_priority_queue>`: create a Priority Queue based on a Max Heap starting from a vector of values. 185 | - `make_min_k_priority_queue>`: create a Priority Queue based on a Min K-ary Heap starting from a vector of keys and a vector of values. 186 | - `make_max_k_priority_queue>`: create a Priority Queue based on a Max K-Heap starting from a vector of keys and a vector of values. 187 | 188 | Each of these functions supports both copy and move semantics for the given inputs. 189 | 190 | **Note**: `PriorityQueue` is implemented using `unordered_map` for fast retrieval of keys and element index given an element stored in the underlying `Heap`. 191 | This means that your values' type must have an hash implementation. If you use trivial types (int, double, etc) you're already covered, otherwise you will 192 | have to provide your own custom hash functor as the last template argument of the utility factory functions defined above. 193 | 194 | ### Example usage of PriorityQueue with BinaryHeap 195 | 196 | ```c++ 197 | #include 198 | #include "priority_queue/PriorityQueue.h" 199 | 200 | int main() { 201 | std::vector keys1{ 5, 4, 1, 3, 6, 0, 2 }; 202 | std::vector vec1{ 'm', 'i', 'n', 'h', 'e', 'a', 'p' }; 203 | auto min_pq1(priority_queue::make_min_priority_queue(keys1, vec1)); 204 | 205 | while (!min_pq1.empty()) { 206 | const auto& [top_key, top_value] = min_pq1.top_key_value(); 207 | std::cout << "Min (key, value): (" << top_key << ", " << top_value << ")" << std::endl; 208 | min_pq1.pop(); 209 | } 210 | 211 | // Output: 212 | // Min (key, value): (0, a) 213 | // Min (key, value): (1, n) 214 | // Min (key, value): (2, p) 215 | // Min (key, value): (3, h) 216 | // Min (key, value): (4, i) 217 | // Min (key, value): (5, m) 218 | // Min (key, value): (6, e) 219 | 220 | std::cout << std::endl << std::endl; 221 | 222 | // notice that keys already sorted 223 | std::vector keys2{ 0, 2, 4, 6, 8, 10, 12 }; 224 | std::vector vec2{ 'm', 'i', 'n', 'h', 'e', 'a', 'p' }; 225 | auto min_pq2(priority_queue::make_min_priority_queue(keys2, vec2)); 226 | 227 | while (!min_pq2.empty()) { 228 | const auto& [top_key, top_value] = min_pq2.top_key_value(); 229 | std::cout << "Min (key, value): (" << top_key << ", " << top_value << ")" << std::endl; 230 | min_pq2.pop(); 231 | } 232 | 233 | // Output: 234 | // Min (key, value): (0, m) 235 | // Min (key, value): (2, i) 236 | // Min (key, value): (4, n) 237 | // Min (key, value): (6, h) 238 | // Min (key, value): (8, e) 239 | // Min (key, value): (10, a) 240 | // Min (key, value): (12, p) 241 | 242 | std::cout << std::endl << std::endl; 243 | auto min_pq2_update(priority_queue::make_min_priority_queue(keys2, vec2)); 244 | 245 | // Min Heap: keys can only decrease 246 | min_pq2_update.update_key(5, 'e'); // set key of value 'e' from 8 to 5 247 | min_pq2_update.update_key(1, 'p'); // set key of value 'p' from 12 to 1 248 | 249 | while (!min_pq2_update.empty()) { 250 | const auto& [top_key, top_value] = min_pq2_update.top_key_value(); 251 | std::cout << "Min (key, value): (" << top_key << ", " << top_value << ")" << std::endl; 252 | min_pq2_update.pop(); 253 | } 254 | 255 | // Output: 256 | // Min (key, value): (0, m) 257 | // Min (key, value): (1, p) 258 | // Min (key, value): (2, i) 259 | // Min (key, value): (4, n) 260 | // Min (key, value): (5, e) 261 | // Min (key, value): (6, h) 262 | // Min (key, value): (10, a) 263 | } 264 | ``` 265 | 266 | ### Example usage of PriorityQueue with KHeap 267 | 268 | ```c++ 269 | #include 270 | #include "priority_queue/PriorityQueue.h" 271 | 272 | int main() { 273 | std::vector keys1{ 5, 4, 1, 3, 6, 0, 2 }; 274 | std::vector vec1{ 'm', 'i', 'n', 'h', 'e', 'a', 'p' }; 275 | constexpr std::size_t K1 = 4; 276 | auto min_pq1(priority_queue::make_min_k_priority_queue(keys1, vec1)); 277 | 278 | while (!min_pq1.empty()) { 279 | const auto& [top_key, top_value] = min_pq1.top_key_value(); 280 | std::cout << "Min (key, value): (" << top_key << ", " << top_value << ")" << std::endl; 281 | min_pq1.pop(); 282 | } 283 | 284 | // Output: 285 | // Min (key, value): (0, a) 286 | // Min (key, value): (1, n) 287 | // Min (key, value): (2, p) 288 | // Min (key, value): (3, h) 289 | // Min (key, value): (4, i) 290 | // Min (key, value): (5, m) 291 | // Min (key, value): (6, e) 292 | 293 | std::cout << std::endl << std::endl; 294 | 295 | // notice that keys already sorted 296 | std::vector keys2{ 0, 2, 4, 6, 8, 10, 12 }; 297 | std::vector vec2{ 'm', 'i', 'n', 'h', 'e', 'a', 'p' }; 298 | constexpr std::size_t K2 = 3; 299 | auto min_pq2(priority_queue::make_min_k_priority_queue(keys2, vec2)); 300 | 301 | while (!min_pq2.empty()) { 302 | const auto& [top_key, top_value] = min_pq2.top_key_value(); 303 | std::cout << "Min (key, value): (" << top_key << ", " << top_value << ")" << std::endl; 304 | min_pq2.pop(); 305 | } 306 | 307 | // Output: 308 | // Min (key, value): (0, m) 309 | // Min (key, value): (2, i) 310 | // Min (key, value): (4, n) 311 | // Min (key, value): (6, h) 312 | // Min (key, value): (8, e) 313 | // Min (key, value): (10, a) 314 | // Min (key, value): (12, p) 315 | 316 | std::cout << std::endl << std::endl; 317 | constexpr std::size_t K3 = 5; 318 | auto min_pq2_update(priority_queue::make_min_k_priority_queue(keys2, vec2)); 319 | 320 | // Min Heap: keys can only decrease 321 | min_pq2_update.update_key(5, 'e'); // set key of value 'e' from 8 to 5 322 | min_pq2_update.update_key(1, 'p'); // set key of value 'p' from 12 to 1 323 | 324 | while (!min_pq2_update.empty()) { 325 | const auto& [top_key, top_value] = min_pq2_update.top_key_value(); 326 | std::cout << "Min (key, value): (" << top_key << ", " << top_value << ")" << std::endl; 327 | min_pq2_update.pop(); 328 | } 329 | 330 | // Output: 331 | // Min (key, value): (0, m) 332 | // Min (key, value): (1, p) 333 | // Min (key, value): (2, i) 334 | // Min (key, value): (4, n) 335 | // Min (key, value): (5, e) 336 | // Min (key, value): (6, h) 337 | // Min (key, value): (10, a) 338 | } 339 | ``` 340 | 341 | ## Best practices adopted 342 | 343 | - Most of the methods offered by this library are marked with `noexcept`. 344 | - Every overriden method is marked with `override`. 345 | - This library doesn't perform any heap allocation, at least not directly. Everything is stack-allocated 346 | and built around containers of the standard library (`std::vector` and `std::unordered_map`). 347 | - When possible, if-expressions are performed at compile time. 348 | - Bit-shifting is used instead of division by 2 when possible. 349 | - Heap's methods `heapify_up` and `heapify_down` use iteration instead of recursion. 350 | - Even though the class defined in the `heap` and `priority_queue` namespaces may require a lot of template arguments, 351 | for most practical cases they can be automatically inferred by the compiler. See the examples. 352 | 353 | ## Test 354 | 355 | This project has been developer with Microsoft Visual Studio 2019, but it supports multiplatform builds via [`Bazel`](https://bazel.build/). 356 | 357 | The [./tests](./tests) folder contains some unit tests. Coverage isn't 100% as of now, though these libraries have worked well in practice 358 | with more than 90k elements. 359 | To run the [`googletest`](https://github.com/google/googletest) test suite, just execute the following command: 360 | 361 | - `bazel test //..` 362 | 363 | A note for Windows Users: run that command either in Powershell or in CMD, because it won't work in Git Bash. 364 | 365 | ## Contributing 366 | 367 | Contributions, issues and feature requests are welcome! 368 | The code is short and throughly commented, so you should feel quite comfortable looking at it. 369 | If you have any doubt or suggestion, please open an issue. 370 | 371 | Don't be afraid to show your support. Give a ⭐️ if this project helped or inspired you!. 372 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | # build with: 2 | # bazel build //... 3 | 4 | workspace(name = "priority_queue") 5 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 6 | load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") 7 | 8 | # Google Test 9 | git_repository( 10 | name = "googletest", 11 | remote = "https://github.com/google/googletest", 12 | tag = "release-1.10.0", 13 | ) 14 | 15 | # C++ rules for Bazel. 16 | http_archive( 17 | name = "rules_cc", 18 | urls = ["https://github.com/bazelbuild/rules_cc/archive/9e10b8a6db775b1ecd358d8ddd3dab379a2c29a5.zip"], 19 | strip_prefix = "rules_cc-9e10b8a6db775b1ecd358d8ddd3dab379a2c29a5", 20 | sha256 = "954b7a3efc8752da957ae193a13b9133da227bdacf5ceb111f2e11264f7e8c95", 21 | ) 22 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: '{build}' 2 | 3 | environment: 4 | matrix: 5 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 6 | configuration: Debug 7 | platform: x64 8 | CXX_FLAGS: "/std:c++17 /Od /W4 /WX-" 9 | LINKER_FLAGS: "" 10 | GENERATOR: Visual Studio 16 2019 11 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 12 | configuration: Release 13 | platform: x64 14 | CXX_FLAGS: "/std:c++17 /O2 /Oi /Oy /GL /W4" 15 | LINKER_FLAGS: "" 16 | GENERATOR: Visual Studio 16 2019 17 | 18 | install: 19 | - ps: | 20 | Write-Output "Generator: $env:generator" 21 | Write-Output "Env:Configuration: $env:configuration" 22 | Write-Output "Env: $env" 23 | 24 | # install Bazel 25 | appveyor DownloadFile https://github.com/bazelbuild/bazel/releases/download/3.1.0/bazel-3.1.0-windows-x86_64.exe -FileName bazel.exe 26 | before_build: 27 | - ps: | 28 | $env:root=$env:APPVEYOR_BUILD_FOLDER 29 | Write-Output "env:root: $env:root" 30 | 31 | test_script: 32 | - ps: | 33 | # Test with Bazel 34 | & $env:root\bazel.exe test //... 35 | 36 | # bazel writes to StdErr and PowerShell interprets it as an error 37 | if ($LastExitCode -eq 0) { 38 | $host.SetShouldExit(0) 39 | } else { # a real error 40 | throw "Exec: $ErrorMessage" 41 | } 42 | 43 | skip_commits: 44 | files: 45 | - '**/*.md' 46 | 47 | artifacts: 48 | - path: 'bazel-testlogs/**/test.log' 49 | name: test_logs 50 | - path: 'bazel-testlogs/**/test.xml' 51 | name: test_results 52 | -------------------------------------------------------------------------------- /priority_queue.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29926.136 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "priority_queue", "priority_queue\priority_queue.vcxproj", "{9CF1D084-63A5-4085-8FC2-58049D6431D0}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {9CF1D084-63A5-4085-8FC2-58049D6431D0}.Debug|x64.ActiveCfg = Debug|x64 17 | {9CF1D084-63A5-4085-8FC2-58049D6431D0}.Debug|x64.Build.0 = Debug|x64 18 | {9CF1D084-63A5-4085-8FC2-58049D6431D0}.Debug|x86.ActiveCfg = Debug|Win32 19 | {9CF1D084-63A5-4085-8FC2-58049D6431D0}.Debug|x86.Build.0 = Debug|Win32 20 | {9CF1D084-63A5-4085-8FC2-58049D6431D0}.Release|x64.ActiveCfg = Release|x64 21 | {9CF1D084-63A5-4085-8FC2-58049D6431D0}.Release|x64.Build.0 = Release|x64 22 | {9CF1D084-63A5-4085-8FC2-58049D6431D0}.Release|x86.ActiveCfg = Release|Win32 23 | {9CF1D084-63A5-4085-8FC2-58049D6431D0}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {E4509606-75C7-4B24-B733-950FCFF92938} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /priority_queue/BUILD: -------------------------------------------------------------------------------- 1 | package(default_visibility = ["//visibility:public"]) 2 | 3 | load("@rules_cc//cc:defs.bzl", "cc_library") #, "cc_binary") 4 | load("//:variables.bzl", "COPTS") 5 | 6 | cc_library( 7 | name = "priority_queue", 8 | hdrs = glob(["*.h"]), 9 | copts = COPTS, 10 | ) 11 | 12 | # cc_binary( 13 | # name = "priority_queue_main", 14 | # srcs = ["main.cpp"], 15 | # deps = [ 16 | # ":priority_queue" 17 | # ], 18 | # copts = COPTS, 19 | # ) 20 | -------------------------------------------------------------------------------- /priority_queue/BinaryHeap.h: -------------------------------------------------------------------------------- 1 | #ifndef BINARY_HEAP_H 2 | #define BINARY_HEAP_H 3 | 4 | #include // std::vector 5 | 6 | #include "Heap.h" 7 | 8 | namespace heap { 9 | 10 | /** 11 | * Generic Binary Heap implementation. Depending on the given comparator function, it can 12 | * either be a Min Heap or a Max Heap. 13 | * This class shouldn't be invoked directly. 14 | * Instead, the factories make_min_heap and make_max_heap should be used. 15 | * 16 | * T: the type of the objects stored in the heap. 17 | * IsAlreadyHeap: constexpr bool flag. If true, build_heap() won't be called 18 | * after the class is constructed. 19 | * If false, the given vector is considered an already valid heap. 20 | */ 21 | template 22 | class BinaryHeap : public Heap { 23 | using super = Heap; 24 | // returns the left child of nodes[i] 25 | [[nodiscard]] static std::size_t left(const std::size_t i) noexcept { 26 | return (i << 1) + 1; 27 | } 28 | 29 | // returns the right child of nodes[i] 30 | [[nodiscard]] static std::size_t right(const std::size_t i) noexcept { 31 | return (i << 1) + 2; 32 | } 33 | 34 | // returns true iff the nodes[i] is a leaf 35 | [[nodiscard]] bool is_leaf(const size_t i) const noexcept { 36 | return i >= (this->size() >> 1) + 1; 37 | } 38 | 39 | protected: 40 | using compare_t = typename super::compare_t; 41 | 42 | // protected constructor to let the subclass set the comparator after the initialization 43 | explicit BinaryHeap(const std::vector& inputs) noexcept : super(inputs) { 44 | } 45 | 46 | // protected constructor to let the subclass set the comparator after the initialization 47 | explicit BinaryHeap(std::vector&& inputs) noexcept : super(std::move(inputs)) { 48 | } 49 | 50 | // return the parent of nodes[i] 51 | [[nodiscard]] std::size_t parent(const std::size_t i) const noexcept override final { 52 | return (i - 1) >> 1; 53 | } 54 | 55 | // starting from a Heap with a misplaced node at the given index, 56 | // recover the shape and heap properties bubbling the node down 57 | void heapify_down(const std::size_t index_to_fix) noexcept override { 58 | const std::size_t len = this->size(); 59 | std::size_t i = index_to_fix; 60 | 61 | while (!is_leaf(i)) { 62 | const auto l = left(i); 63 | const auto r = right(i); 64 | 65 | // comp_est is the biggest element in a Max Heap, 66 | // or the smallest element in a Min Heap 67 | std::size_t comp_est = i; 68 | 69 | if (l < len && this->comp(this->nodes.at(i), this->nodes.at(l))) { 70 | comp_est = l; 71 | } 72 | if (r < len && this->comp(this->nodes.at(comp_est), this->nodes.at(r))) { 73 | comp_est = r; 74 | } 75 | 76 | if (i == comp_est) { 77 | return; 78 | } 79 | 80 | this->swap_nodes(i, comp_est); 81 | i = comp_est; 82 | } 83 | } 84 | 85 | // transform the internal vector in a heap in O(n) 86 | void build_heap() noexcept override final { 87 | for (std::size_t i = (this->size() >> 1) + 1; i > 0; --i) { 88 | heapify_down(i - 1); 89 | } 90 | } 91 | 92 | public: 93 | // disable public default constructor 94 | BinaryHeap() = delete; 95 | 96 | explicit BinaryHeap(const std::vector& inputs, compare_t&& comp) noexcept : 97 | super(inputs, std::move(comp)) { 98 | this->init(); 99 | } 100 | 101 | explicit BinaryHeap(std::vector&& inputs, compare_t&& comp) noexcept : 102 | super(std::move(inputs), std::move(comp)) { 103 | this->init(); 104 | } 105 | 106 | virtual ~BinaryHeap() = default; 107 | }; 108 | 109 | // create a Min Heap copying the input vector 110 | template 111 | auto make_min_heap(const std::vector& inputs) { 112 | return BinaryHeap(inputs, std::greater<>{}); 113 | } 114 | 115 | // create a Min Heap moving the input vector 116 | template 117 | auto make_min_heap(std::vector&& inputs = {}) { 118 | return BinaryHeap(std::move(inputs), std::greater<>{}); 119 | } 120 | 121 | // create a Max Heap copying the input vector 122 | template 123 | auto make_max_heap(const std::vector& inputs) { 124 | return BinaryHeap(inputs, std::less<>{}); 125 | } 126 | 127 | // create a Max Heap moving the input vector 128 | template 129 | auto make_max_heap(std::vector&& inputs = {}) { 130 | return BinaryHeap(std::move(inputs), std::less<>{}); 131 | } 132 | 133 | } // namespace heap 134 | 135 | #endif // BINARY_HEAP_H -------------------------------------------------------------------------------- /priority_queue/Heap.h: -------------------------------------------------------------------------------- 1 | #ifndef HEAP_H 2 | #define HEAP_H 3 | 4 | #include // std::swap 5 | #include // std::assert 6 | #include // std::function 7 | #include // std::vector 8 | 9 | namespace heap { 10 | 11 | /** 12 | * Generic Heap abstract class. The elements are allocated in a std::vector container. 13 | * 14 | * T: the type of the objects stored in the heap. 15 | * IsAlreadyHeap: constexpr bool flag. If true, build_heap() won't be called 16 | * after the child class is constructed. 17 | * If false, the given vector is considered an already valid heap. 18 | */ 19 | template 20 | class Heap { 21 | protected: 22 | // comparison function alias type 23 | using compare_t = std::function; 24 | 25 | // keep the values in the heap 26 | std::vector nodes; 27 | 28 | // comparison functor 29 | // std::greater<> -> Min Heap 30 | // std::less<> -> Max Heap 31 | compare_t comp; 32 | 33 | // protected constructor to let the subclass set the comparator after the initialization 34 | explicit Heap(const std::vector& inputs) noexcept : nodes(inputs) { 35 | } 36 | 37 | // protected constructor to let the subclass set the comparator after the initialization 38 | explicit Heap(std::vector&& inputs) noexcept : nodes(inputs) { 39 | } 40 | 41 | // return the parent of nodes[i] 42 | [[nodiscard]] virtual std::size_t parent(std::size_t i) const noexcept = 0; 43 | 44 | // transform the internal vector in a heap in O(n) 45 | virtual void build_heap() noexcept = 0; 46 | 47 | // starting from a Heap with a misplaced node at the given index, 48 | // recover the shape and heap properties bubbling the node down. 49 | virtual void heapify_down(std::size_t index_to_fix) noexcept = 0; 50 | 51 | // swap 2 nodes in the heap 52 | virtual void swap_nodes(std::size_t i, std::size_t j) noexcept { 53 | std::swap(nodes.at(i), nodes.at(j)); 54 | } 55 | 56 | // starting from a Heap with a misplaced node at the given index, 57 | // recover the shape and heap properties in O(logN) bubbling the node up 58 | void heapify_up(const std::size_t index_to_fix) noexcept { 59 | std::size_t i = index_to_fix; 60 | 61 | while (i > 0 && comp(nodes.at(parent(i)), nodes.at(i))) { 62 | const auto p = parent(i); 63 | swap_nodes(i, p); 64 | i = p; 65 | } 66 | } 67 | 68 | // spend O(n) to build the heap only if the given vector wasn't already a 69 | // valid heap from the beginning 70 | void init() noexcept { 71 | if constexpr (!IsAlreadyHeap) { 72 | build_heap(); 73 | } 74 | } 75 | 76 | public: 77 | // disable public default constructor 78 | Heap() = delete; 79 | 80 | explicit Heap(const std::vector& inputs, compare_t&& comp) noexcept : 81 | nodes(inputs), comp(comp) { 82 | } 83 | 84 | explicit Heap(std::vector&& inputs, compare_t&& comp) noexcept : 85 | nodes(inputs), comp(comp) { 86 | } 87 | 88 | // virtual destructor because this is a base class 89 | virtual ~Heap() = default; 90 | 91 | // return the number of elements in the heap 92 | [[nodiscard]] size_t size() const noexcept { 93 | return nodes.size(); 94 | } 95 | 96 | // return true iff the heap is empty 97 | [[nodiscard]] bool empty() const noexcept { 98 | return size() == 0; 99 | } 100 | 101 | // return ths top element of the heap (which must exist) 102 | [[nodiscard]] const T& top() const { 103 | assert(size() > 0); 104 | 105 | return nodes.at(0); 106 | } 107 | 108 | // remove the top element of the heap (which must exist) 109 | void pop() { 110 | assert(size() > 0); 111 | 112 | // replace root of the heap with the last element of the vector 113 | nodes.at(0) = nodes.back(); 114 | 115 | // remove the last element of the vector 116 | nodes.pop_back(); 117 | 118 | // the root violates the heap property, so it must be fixed 119 | heapify_down(0); 120 | } 121 | 122 | // add a new element to the heap 123 | template 124 | void push(Args&&... args) { 125 | const size_t index_to_fix = size(); 126 | 127 | // insert new node at the end of the vector 128 | nodes.emplace_back(std::forward(args)...); 129 | 130 | // the root violates the heap property. Let's fix that 131 | heapify_up(index_to_fix); 132 | } 133 | }; 134 | 135 | } // namespace heap 136 | 137 | #endif // HEAP_H -------------------------------------------------------------------------------- /priority_queue/KHeap.h: -------------------------------------------------------------------------------- 1 | #ifndef K_HEAP_H 2 | #define K_HEAP_H 3 | 4 | #include // std::enable_if 5 | #include // std::vector 6 | 7 | #include "Heap.h" 8 | 9 | namespace heap { 10 | 11 | /** 12 | * Generic K-ary Heap implementation. Depending on the given comparator function, it can 13 | * either be a Min K-ary Heap or a Max K-ary Heap. 14 | * This class shouldn't be invoked directly. 15 | * Instead, the factories make_min_k_heap and make_max_k_heap should be used. 16 | * 17 | * K: the Heap arity. It must be bigger than 2. 18 | * T: the type of the objects stored in the heap. 19 | * IsAlreadyHeap: constexpr bool flag. If true, build_heap() won't be called 20 | * the class is constructed. 21 | * If false, the given vector is considered an already valid heap. 22 | */ 23 | template 2)>::type> 25 | class KHeap : public Heap { 26 | using super = Heap; 27 | 28 | // returns the j-th child of the i-th node. 29 | [[nodiscard]] static size_t child(const size_t i, const size_t j) noexcept { 30 | return (K * i) + j + 1; 31 | } 32 | 33 | // returns true iff the i-th is a leaf 34 | [[nodiscard]] bool is_leaf(const size_t i) const noexcept { 35 | return i > ((this->size() - 2) / K); 36 | } 37 | 38 | protected: 39 | using compare_t = typename super::compare_t; 40 | 41 | // protected constructor to let the subclass set the comparator after the initialization 42 | explicit KHeap(const std::vector& inputs) noexcept : super(inputs) { 43 | } 44 | 45 | // protected constructor to let the subclass set the comparator after the initialization 46 | explicit KHeap(std::vector&& inputs) noexcept : super(std::move(inputs)) { 47 | } 48 | 49 | // return the parent of nodes[i] 50 | [[nodiscard]] std::size_t parent(const std::size_t i) const noexcept final override { 51 | return (i - 1) / K; 52 | } 53 | 54 | // starting from a Heap with a misplaced node at the given index, 55 | // recover the shape and heap properties bubbling the node down. 56 | void heapify_down(const std::size_t index_to_fix) noexcept override { 57 | const std::size_t len = this->size(); 58 | std::size_t i = index_to_fix; 59 | 60 | // comp_est is the biggest element in a Max Heap, 61 | // or the smallest element in a Min Heap 62 | std::size_t comp_est = i; 63 | 64 | while (!is_leaf(i)) { 65 | // Time: O(K) 66 | for (std::size_t j = 0; j < K; ++j) { 67 | const auto son = child(i, j); 68 | if (son < len && this->comp(this->nodes.at(comp_est), this->nodes.at(son))) { 69 | comp_est = son; 70 | } 71 | } 72 | 73 | if (i == comp_est) { 74 | return; 75 | } 76 | 77 | this->swap_nodes(i, comp_est); 78 | i = comp_est; 79 | } 80 | } 81 | 82 | // transform the internal vector in a heap in O(n) 83 | void build_heap() noexcept override final { 84 | for (std::size_t i = (this->size() / K) + 1; i > 0; --i) { 85 | heapify_down(i - 1); 86 | } 87 | } 88 | 89 | public: 90 | // disable public default constructor 91 | KHeap() = delete; 92 | 93 | explicit KHeap(const std::vector& inputs, compare_t&& comp) noexcept : 94 | super(inputs, std::move(comp)) { 95 | this->init(); 96 | } 97 | 98 | explicit KHeap(std::vector&& inputs, compare_t&& comp) noexcept : 99 | super(std::move(inputs), std::move(comp)) { 100 | this->init(); 101 | } 102 | 103 | virtual ~KHeap() = default; 104 | }; 105 | 106 | // create a Min K-Heap copying the input vector 107 | template 108 | auto make_min_k_heap(const std::vector& inputs) { 109 | return KHeap(inputs, std::greater<>{}); 110 | } 111 | 112 | // create a Min K-Heap moving the input vector 113 | template 114 | auto make_min_k_heap(std::vector&& inputs = {}) { 115 | return KHeap(std::move(inputs), std::greater<>{}); 116 | } 117 | 118 | // create a Max K-Heap copying the input vector 119 | template 120 | auto make_max_k_heap(const std::vector& inputs) { 121 | return KHeap(inputs, std::less<>{}); 122 | } 123 | 124 | // create a Max K-Heap moving the input vector 125 | template 126 | auto make_max_k_heap(std::vector&& inputs = {}) { 127 | return KHeap(std::move(inputs), std::less<>{}); 128 | } 129 | 130 | } // namespace heap 131 | 132 | #endif // K_HEAP_H -------------------------------------------------------------------------------- /priority_queue/PriorityQueue.h: -------------------------------------------------------------------------------- 1 | #ifndef PRIORITY_QUEUE_H 2 | #define PRIORITY_QUEUE_H 3 | 4 | #include // std::swap, std::find 5 | #include // std::assert 6 | #include // std::function 7 | #include // std::enable_if 8 | #include // std::unordered_map 9 | 10 | #include "BinaryHeap.h" 11 | #include "Heap.h" 12 | #include "KHeap.h" 13 | 14 | namespace priority_queue { 15 | 16 | // utility enum class used in PriorityQueue.update_key() to understand at compile time 17 | // whether PriorityQueue is using a Min Heap or a Max Heap implementation. 18 | enum class Type { min_heap, max_heap }; 19 | 20 | /** 21 | * Generic Priority Queue based on a Heap. Whether it is based on a MinHeap or a MaxHeap 22 | * depends on CompareFactory object used for initialization. 23 | * This class shouldn't be invoked directly. 24 | * Instead, the factories make_min_priority_queue, make_max_priority_queue, 25 | * make_min_k_priority_queue, make_max_k_priority_queue should be used. 26 | * 27 | * Heap: type of the parent class of PriorityQueue. It must derive heap::Heap. 28 | * Key: type of the keys used to order the Heap. 29 | * T: type of the elements stored in the Heap underlying the Priority Queue. 30 | * IsAlreadyHeap: constexpr flag. If true, build_heap() won't be called after the class is 31 | * constructed. If false, the given input is considered an already valid heap 32 | * according to its keys. 33 | * T_Hash: functor used to hash values of type T. Necessary only if T is a non-trivial type. 34 | * HeapType: enum utility used to understand whether Heap is a Min Heap or a Max Heap. 35 | */ 36 | template , Type HeapType = Type::min_heap, 38 | typename = std::enable_if, Heap>::value>> 39 | class PriorityQueue : Heap { 40 | using super = Heap; 41 | using key_map_type = std::unordered_map; 42 | using index_map_type = std::unordered_map; 43 | using compare_t = std::function; 44 | using compare_factory_t = std::function; 45 | 46 | // keep track of the value of the keys of each node. 47 | // key_map[element] -> key assigned to element 48 | key_map_type key_map; 49 | 50 | // keep track of the index of the nodes stored in the Heap. 51 | // index_map[element] -> index in this->nodes of element 52 | index_map_type index_map; 53 | 54 | // initialize key_map 55 | template 56 | [[nodiscard]] static auto build_key_map(const std::vector& keys, 57 | const std::vector& node_list) { 58 | assert(keys.size() == node_list.size()); 59 | 60 | std::unordered_map local_key_map(node_list.size()); 61 | 62 | // traverses keys and node_list at the same time 63 | std::size_t index = 0; 64 | for (const auto& node : node_list) { 65 | local_key_map[node] = keys[index]; 66 | index++; 67 | } 68 | 69 | return local_key_map; 70 | } 71 | 72 | // initialize index_map 73 | template 74 | [[nodiscard]] static auto build_index_map(const std::vector& node_list) { 75 | std::unordered_map local_index_map(node_list.size()); 76 | 77 | std::size_t index = 0; 78 | for (const auto& node : node_list) { 79 | local_index_map[node] = index; 80 | index++; 81 | } 82 | 83 | return local_index_map; 84 | } 85 | 86 | // initialize class 87 | void init(compare_factory_t&& comp_factory) { 88 | // set comparator in base class after initialization of key_map and index_map. 89 | // We can't set it directly in super(inputs, comp_factory(key_map) because we need 90 | // to initialize key_map first, and member objects can only be initialized after 91 | // the parent class is completely initialized. 92 | this->comp = comp_factory(key_map); 93 | super::init(); 94 | } 95 | 96 | protected: 97 | void swap_nodes(std::size_t i, std::size_t j) noexcept { 98 | auto node_i = this->nodes.at(i); 99 | auto node_j = this->nodes.at(j); 100 | 101 | // swap the indexes 102 | std::swap(index_map.at(node_i), index_map.at(node_j)); 103 | 104 | // swap the nodes 105 | super::swap_nodes(i, j); 106 | } 107 | 108 | public: 109 | PriorityQueue() = delete; 110 | 111 | explicit PriorityQueue(const std::vector& keys, const std::vector& inputs, 112 | compare_factory_t&& comp_factory) : 113 | super(inputs), 114 | key_map(build_key_map(keys, this->nodes)), 115 | index_map(build_index_map(this->nodes)) { 116 | init(std::move(comp_factory)); 117 | } 118 | 119 | explicit PriorityQueue(std::vector&& keys, std::vector&& inputs, 120 | compare_factory_t&& comp_factory) : 121 | super(std::move(inputs)), 122 | key_map(build_key_map(std::move(keys), this->nodes)), 123 | index_map(build_index_map(this->nodes)) { 124 | init(std::move(comp_factory)); 125 | } 126 | 127 | ~PriorityQueue() = default; 128 | 129 | // return the number of elements in the heap. 130 | // Time: O(1). 131 | // Space: O(1). 132 | [[nodiscard]] std::size_t size() const noexcept { 133 | return super::size(); 134 | } 135 | 136 | // return true iff the heap is empty. 137 | // Time: O(1). 138 | // Space: O(1). 139 | [[nodiscard]] bool empty() const noexcept { 140 | return super::empty(); 141 | } 142 | 143 | // add a new element to the heap and associates the given key to it. 144 | // Time: O(logN) amortized if using BinaryHeap, O(k*log_k(N)) amortized instead. 145 | // Space: O(1) amortized. 146 | void push(const Key& key, const T& element) { 147 | const std::size_t index_to_fix = this->size(); 148 | index_map[element] = index_to_fix; 149 | key_map[element] = key; 150 | 151 | super::push(element); 152 | } 153 | 154 | // update the key of an element in the priority queue. 155 | // The element must exist in the priority queue. 156 | // Time: O(logN) amortized if using BinaryHeap, O(k*log_k(N)) amortized instead. 157 | // Space: O(1) amortized. 158 | void update_key(const Key& key, const T& element) { 159 | const std::size_t index_to_fix = index_map.at(element); 160 | key_map.at(element) = key; 161 | 162 | // recover the heap property 163 | if constexpr (HeapType == Type::min_heap) { 164 | // we're using a MinHeap, thus we are decreasing the key 165 | this->heapify_up(index_to_fix); 166 | } else { 167 | // we're using a MaxHeap, thus we are increasing the key 168 | this->heapify_down(index_to_fix); 169 | } 170 | } 171 | 172 | // return the value of the key of the given element. 173 | // Time: O(1) amortized. 174 | // Space: O(1). 175 | [[nodiscard]] const Key& key_at(const T& element) const { 176 | return key_map.at(element); 177 | } 178 | 179 | // return true iff the given element is in the priority queue. 180 | // Time: O(1) amortized. 181 | // Space: O(1). 182 | [[nodiscard]] bool contains(const T& element) const noexcept { 183 | const auto search = index_map.find(element); 184 | return search != index_map.end(); 185 | } 186 | 187 | // return the top element. 188 | // Time: O(1). 189 | // Space: O(1). 190 | [[nodiscard]] const T& top() const { 191 | return super::top(); 192 | } 193 | 194 | // return top key-value pair. 195 | // Time: O(1). 196 | // Space: O(1). 197 | [[nodiscard]] std::pair top_key_value() const { 198 | const auto& top_value = super::top(); 199 | const auto& top_key = key_at(top_value); 200 | return {top_key, top_value}; 201 | } 202 | 203 | // remove the top element. 204 | // Time: O(logN) amortized if using BinaryHeap, O(k*log_k(N)) amortized instead. 205 | // Space: O(1). 206 | void pop() { 207 | assert(this->size() > 0); 208 | 209 | const std::size_t index_to_remove = 0; 210 | const auto node = this->nodes.at(index_to_remove); 211 | index_map.erase(node); 212 | key_map.erase(node); 213 | 214 | // replace root of the heap with the last element of the vector 215 | this->nodes.at(0) = this->nodes.back(); 216 | 217 | // remove the last element of the vector 218 | this->nodes.pop_back(); 219 | 220 | // no need to recover the heap property if the heap is empty 221 | if (this->size() > 0) { 222 | const auto front = this->nodes.front(); 223 | index_map.at(front) = 0; 224 | 225 | // the root violates the heap property. Let's fix that 226 | this->heapify_down(0); 227 | } 228 | } 229 | }; 230 | 231 | namespace detail { 232 | 233 | inline auto min_heap_comp_factory = [](auto& key_map) { 234 | return [&key_map](auto&& a, auto&& b) -> bool { 235 | return key_map.at(a) > key_map.at(b); 236 | }; 237 | }; 238 | 239 | inline auto max_heap_comp_factory = [](auto& key_map) { 240 | return [&key_map](auto&& a, auto&& b) -> bool { 241 | return key_map.at(a) < key_map.at(b); 242 | }; 243 | }; 244 | 245 | } // namespace detail 246 | 247 | // create a Priority Queue based on a Min Heap. It copies the given vectors. 248 | template > 250 | auto make_min_priority_queue(const std::vector& keys, const std::vector& inputs) { 251 | using pq = PriorityQueue, Key, Value, IsAlreadyHeap, 252 | THash, Type::min_heap>; 253 | return pq(keys, inputs, detail::min_heap_comp_factory); 254 | } 255 | 256 | // create a Priority Queue based on a Min Heap. It moves the given vectors. 257 | template > 259 | auto make_min_priority_queue(std::vector&& keys = {}, std::vector&& inputs = {}) { 260 | using pq = PriorityQueue, Key, Value, IsAlreadyHeap, 261 | THash, Type::min_heap>; 262 | return pq(std::move(keys), std::move(inputs), detail::min_heap_comp_factory); 263 | } 264 | 265 | // create a Priority Queue based on a Max Heap. It copies the given vectors. 266 | template > 268 | auto make_max_priority_queue(const std::vector& keys, const std::vector& inputs) { 269 | using pq = PriorityQueue, Key, Value, IsAlreadyHeap, 270 | THash, Type::max_heap>; 271 | return pq(keys, inputs, detail::max_heap_comp_factory); 272 | } 273 | 274 | // create a Priority Queue based on a Max Heap. It moves the given vectors. 275 | template > 277 | auto make_max_priority_queue(std::vector&& keys = {}, std::vector&& inputs = {}) { 278 | using pq = PriorityQueue, Key, Value, IsAlreadyHeap, 279 | THash, Type::max_heap>; 280 | return pq(std::move(keys), std::move(inputs), detail::max_heap_comp_factory); 281 | } 282 | 283 | // create a Priority Queue based on a Min K-Heap. It copies the given vectors. 284 | template > 286 | auto make_min_k_priority_queue(const std::vector& keys, const std::vector& inputs) { 287 | using pq = PriorityQueue, Key, Value, IsAlreadyHeap, 288 | THash, Type::min_heap>; 289 | return pq(keys, inputs, detail::min_heap_comp_factory); 290 | } 291 | 292 | // create a Priority Queue based on a Min K-Heap. It moves the given vectors. 293 | template > 295 | auto make_min_k_priority_queue(std::vector&& keys = {}, std::vector&& inputs = {}) { 296 | using pq = PriorityQueue, Key, Value, IsAlreadyHeap, 297 | THash, Type::min_heap>; 298 | return pq(std::move(keys), std::move(inputs), detail::min_heap_comp_factory); 299 | } 300 | 301 | // create a Priority Queue based on a Max K-Heap. It copies the given vectors. 302 | template > 304 | auto make_max_k_priority_queue(const std::vector& keys, const std::vector& inputs) { 305 | using pq = PriorityQueue, Key, Value, IsAlreadyHeap, 306 | THash, Type::max_heap>; 307 | return pq(keys, inputs, detail::max_heap_comp_factory); 308 | } 309 | 310 | // create a Priority Queue based on a Max K-Heap. It moves the given vectors. 311 | template > 313 | auto make_max_k_priority_queue(std::vector&& keys = {}, std::vector&& inputs = {}) { 314 | using pq = PriorityQueue, Key, Value, IsAlreadyHeap, 315 | THash, Type::max_heap>; 316 | return pq(std::move(keys), std::move(inputs), detail::max_heap_comp_factory); 317 | } 318 | 319 | } // namespace priority_queue 320 | 321 | #endif // PRIORITY_QUEUE_H -------------------------------------------------------------------------------- /priority_queue/priority_queue.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | -------------------------------------------------------------------------------- /priority_queue/priority_queue.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | 16.0 23 | {9CF1D084-63A5-4085-8FC2-58049D6431D0} 24 | priority_queue 25 | 10.0 26 | priority_queue 27 | 28 | 29 | 30 | Application 31 | true 32 | v142 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | v142 39 | true 40 | Unicode 41 | 42 | 43 | Application 44 | true 45 | v142 46 | Unicode 47 | 48 | 49 | Application 50 | false 51 | v142 52 | true 53 | Unicode 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | true 75 | 76 | 77 | true 78 | 79 | 80 | false 81 | 82 | 83 | false 84 | 85 | 86 | 87 | Level4 88 | true 89 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 90 | true 91 | stdcpp17 92 | true 93 | Speed 94 | 95 | 96 | Console 97 | true 98 | 99 | 100 | 101 | 102 | Level4 103 | true 104 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 105 | true 106 | stdcpp17 107 | true 108 | Speed 109 | 110 | 111 | Console 112 | true 113 | 114 | 115 | 116 | 117 | Level4 118 | true 119 | true 120 | true 121 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 122 | true 123 | stdcpp17 124 | true 125 | Speed 126 | 127 | 128 | Console 129 | true 130 | true 131 | true 132 | 133 | 134 | 135 | 136 | Level4 137 | true 138 | true 139 | true 140 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 141 | true 142 | stdcpp17 143 | true 144 | Speed 145 | 146 | 147 | Console 148 | true 149 | true 150 | true 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /tests/BUILD: -------------------------------------------------------------------------------- 1 | load("//:variables.bzl", "COPTS") 2 | 3 | cc_test( 4 | name = "tests", 5 | srcs = glob(["**/*.cpp"]), 6 | deps = [ 7 | "//priority_queue:priority_queue", 8 | "@googletest//:gtest_main", 9 | ], 10 | copts = COPTS, 11 | ) -------------------------------------------------------------------------------- /tests/MaxBinaryHeap_test.cpp: -------------------------------------------------------------------------------- 1 | #include // std::sort 2 | #include // std::vector 3 | 4 | #include "gtest/gtest.h" 5 | #include "priority_queue/BinaryHeap.h" 6 | 7 | using namespace heap; 8 | 9 | // The fixture for testing class Foo. 10 | class BinaryMaxHeapTest : public ::testing::Test { 11 | protected: 12 | BinaryMaxHeapTest() { 13 | std::sort(test_vector_sorted.begin(), test_vector_sorted.end(), std::greater<>()); 14 | } 15 | 16 | std::vector test_vector = {30, 1, 50, 20, 40, 60, 100}; 17 | std::vector test_vector_sorted = test_vector; 18 | 19 | BinaryHeap empty_max_heap = make_max_heap(); 20 | BinaryHeap max_heap = make_max_heap(test_vector); 21 | 22 | std::vector already_max_seed = {8, 7, 6, 5, 4, 3, 2, 1, 0}; 23 | BinaryHeap already_max_heap = make_max_heap(already_max_seed); 24 | }; 25 | 26 | TEST_F(BinaryMaxHeapTest, WorksIfEmpty) { 27 | ASSERT_TRUE(empty_max_heap.empty()); 28 | 29 | for (const auto& v : test_vector) { 30 | empty_max_heap.push(v); 31 | } 32 | 33 | ASSERT_FALSE(empty_max_heap.empty()); 34 | ASSERT_EQ(empty_max_heap.size(), test_vector.size()); 35 | 36 | for (const auto& v : test_vector_sorted) { 37 | const auto x = empty_max_heap.top(); 38 | ASSERT_EQ(x, v); 39 | empty_max_heap.pop(); 40 | } 41 | } 42 | 43 | TEST_F(BinaryMaxHeapTest, WorksIfFull) { 44 | ASSERT_FALSE(max_heap.empty()); 45 | ASSERT_EQ(max_heap.size(), test_vector.size()); 46 | 47 | for (const auto& v : test_vector_sorted) { 48 | const auto x = max_heap.top(); 49 | ASSERT_EQ(x, v); 50 | max_heap.pop(); 51 | } 52 | } 53 | 54 | TEST_F(BinaryMaxHeapTest, WorksIfAlreadyHeap) { 55 | ASSERT_FALSE(already_max_heap.empty()); 56 | ASSERT_EQ(already_max_heap.size(), already_max_seed.size()); 57 | 58 | for (const auto& v : already_max_seed) { 59 | const auto x = already_max_heap.top(); 60 | ASSERT_EQ(x, v); 61 | already_max_heap.pop(); 62 | } 63 | } -------------------------------------------------------------------------------- /tests/MaxKHeap_test.cpp: -------------------------------------------------------------------------------- 1 | #include // std::sort 2 | #include // std::vector 3 | 4 | #include "gtest/gtest.h" 5 | #include "priority_queue/KHeap.h" 6 | 7 | using namespace heap; 8 | 9 | ///////////////// 10 | // K=4 11 | ///////////////// 12 | 13 | class K4MaxHeapTest : public ::testing::Test { 14 | protected: 15 | K4MaxHeapTest() { 16 | std::sort(test_vector_sorted.begin(), test_vector_sorted.end(), std::greater<>()); 17 | } 18 | 19 | std::vector test_vector = {30, 1, 50, 20, 40, 60, 100}; 20 | std::vector test_vector_sorted = test_vector; 21 | 22 | KHeap<4, int, false> empty_max_heap = make_max_k_heap<4, false, int>(); 23 | KHeap<4, int, false> max_heap = make_max_k_heap<4, false>(std::vector(test_vector)); 24 | 25 | std::vector already_max_seed = {8, 7, 6, 5, 4, 3, 2, 1, 0}; 26 | KHeap<4, int, true> already_max_heap = 27 | make_max_k_heap<4, true>(std::vector(already_max_seed)); 28 | }; 29 | 30 | TEST_F(K4MaxHeapTest, WorksIfEmpty) { 31 | ASSERT_TRUE(empty_max_heap.empty()); 32 | 33 | for (const auto& v : test_vector) { 34 | empty_max_heap.push(v); 35 | } 36 | 37 | ASSERT_FALSE(empty_max_heap.empty()); 38 | ASSERT_EQ(empty_max_heap.size(), test_vector.size()); 39 | 40 | for (const auto& v : test_vector_sorted) { 41 | const auto x = empty_max_heap.top(); 42 | ASSERT_EQ(x, v); 43 | empty_max_heap.pop(); 44 | } 45 | } 46 | 47 | TEST_F(K4MaxHeapTest, WorksIfFull) { 48 | ASSERT_FALSE(max_heap.empty()); 49 | ASSERT_EQ(max_heap.size(), test_vector.size()); 50 | 51 | for (const auto& v : test_vector_sorted) { 52 | const auto x = max_heap.top(); 53 | ASSERT_EQ(x, v); 54 | max_heap.pop(); 55 | } 56 | } 57 | 58 | TEST_F(K4MaxHeapTest, WorksIfAlreadyHeap) { 59 | ASSERT_FALSE(already_max_heap.empty()); 60 | ASSERT_EQ(already_max_heap.size(), already_max_seed.size()); 61 | 62 | for (const auto& v : already_max_seed) { 63 | const auto x = already_max_heap.top(); 64 | ASSERT_EQ(x, v); 65 | already_max_heap.pop(); 66 | } 67 | } 68 | 69 | ///////////////// 70 | // K=8 71 | ///////////////// 72 | 73 | class K8MaxHeapTest : public ::testing::Test { 74 | protected: 75 | K8MaxHeapTest() { 76 | std::sort(test_vector_sorted.begin(), test_vector_sorted.end(), std::greater<>()); 77 | } 78 | 79 | std::vector test_vector = {30, 1, 50, 20, 80, 60, 100}; 80 | std::vector test_vector_sorted = test_vector; 81 | 82 | KHeap<8, int, false> empty_max_heap = make_max_k_heap<8, false, int>(); 83 | KHeap<8, int, false> max_heap = make_max_k_heap<8, false>(test_vector); 84 | 85 | std::vector already_max_seed = {8, 7, 6, 5, 4, 3, 2, 1, 0}; 86 | KHeap<8, int, true> already_max_heap = make_max_k_heap<8, true>(already_max_seed); 87 | }; 88 | 89 | TEST_F(K8MaxHeapTest, WorksIfEmpty) { 90 | ASSERT_TRUE(empty_max_heap.empty()); 91 | 92 | for (const auto& v : test_vector) { 93 | empty_max_heap.push(v); 94 | } 95 | 96 | ASSERT_FALSE(empty_max_heap.empty()); 97 | ASSERT_EQ(empty_max_heap.size(), test_vector.size()); 98 | 99 | for (const auto& v : test_vector_sorted) { 100 | const auto x = empty_max_heap.top(); 101 | ASSERT_EQ(x, v); 102 | empty_max_heap.pop(); 103 | } 104 | } 105 | 106 | TEST_F(K8MaxHeapTest, WorksIfFull) { 107 | ASSERT_FALSE(max_heap.empty()); 108 | ASSERT_EQ(max_heap.size(), test_vector.size()); 109 | 110 | for (const auto& v : test_vector_sorted) { 111 | const auto x = max_heap.top(); 112 | ASSERT_EQ(x, v); 113 | max_heap.pop(); 114 | } 115 | } 116 | 117 | TEST_F(K8MaxHeapTest, WorksIfAlreadyHeap) { 118 | ASSERT_FALSE(already_max_heap.empty()); 119 | ASSERT_EQ(already_max_heap.size(), already_max_seed.size()); 120 | 121 | for (const auto& v : already_max_seed) { 122 | const auto x = already_max_heap.top(); 123 | ASSERT_EQ(x, v); 124 | already_max_heap.pop(); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /tests/MinBinaryHeap_test.cpp: -------------------------------------------------------------------------------- 1 | #include // std::sort 2 | #include // std::vector 3 | 4 | #include "gtest/gtest.h" 5 | #include "priority_queue/BinaryHeap.h" 6 | 7 | using namespace heap; 8 | 9 | // The fixture for testing class Foo. 10 | class BinaryMinHeapTest : public ::testing::Test { 11 | protected: 12 | BinaryMinHeapTest() { 13 | std::sort(test_vector_sorted.begin(), test_vector_sorted.end()); 14 | } 15 | 16 | std::vector test_vector = {30, 1, 50, 20, 40, 60, 100}; 17 | std::vector test_vector_sorted = test_vector; 18 | 19 | BinaryHeap empty_min_heap = make_min_heap(); 20 | BinaryHeap min_heap = make_min_heap(test_vector); 21 | 22 | std::vector already_min_seed = {0, 1, 2, 3, 4, 5, 6, 7, 8}; 23 | BinaryHeap already_min_heap = make_min_heap(already_min_seed); 24 | }; 25 | 26 | TEST_F(BinaryMinHeapTest, WorksIfEmpty) { 27 | ASSERT_TRUE(empty_min_heap.empty()); 28 | 29 | for (const auto& v : test_vector) { 30 | empty_min_heap.push(v); 31 | } 32 | 33 | ASSERT_FALSE(empty_min_heap.empty()); 34 | ASSERT_EQ(empty_min_heap.size(), test_vector.size()); 35 | 36 | for (const auto& v : test_vector_sorted) { 37 | const auto x = empty_min_heap.top(); 38 | ASSERT_EQ(x, v); 39 | empty_min_heap.pop(); 40 | } 41 | } 42 | 43 | TEST_F(BinaryMinHeapTest, WorksIfFull) { 44 | ASSERT_FALSE(min_heap.empty()); 45 | ASSERT_EQ(min_heap.size(), test_vector.size()); 46 | 47 | for (const auto& v : test_vector_sorted) { 48 | const auto x = min_heap.top(); 49 | ASSERT_EQ(x, v); 50 | min_heap.pop(); 51 | } 52 | } 53 | 54 | TEST_F(BinaryMinHeapTest, WorksIfAlreadyHeap) { 55 | ASSERT_FALSE(already_min_heap.empty()); 56 | ASSERT_EQ(already_min_heap.size(), already_min_seed.size()); 57 | 58 | for (const auto& v : already_min_seed) { 59 | const auto x = already_min_heap.top(); 60 | ASSERT_EQ(x, v); 61 | already_min_heap.pop(); 62 | } 63 | } -------------------------------------------------------------------------------- /tests/MinKHeap_test.cpp: -------------------------------------------------------------------------------- 1 | #include // std::sort 2 | #include // std::vector 3 | 4 | #include "gtest/gtest.h" 5 | #include "priority_queue/KHeap.h" 6 | 7 | using namespace heap; 8 | 9 | ///////////////// 10 | // K=4 11 | ///////////////// 12 | 13 | class K4MinHeapTest : public ::testing::Test { 14 | protected: 15 | K4MinHeapTest() { 16 | std::sort(test_vector_sorted.begin(), test_vector_sorted.end()); 17 | } 18 | 19 | std::vector test_vector = {30, 1, 50, 20, 40, 60, 100}; 20 | std::vector test_vector_sorted = test_vector; 21 | 22 | KHeap<4, int, false> empty_min_heap = make_min_k_heap<4, false, int>(); 23 | KHeap<4, int, false> min_heap = make_min_k_heap<4, false, int>(test_vector); 24 | 25 | std::vector already_min_seed = {0, 1, 2, 3, 4, 5, 6, 7, 8}; 26 | KHeap<4, int, true> already_min_heap = make_min_k_heap<4, true, int>(already_min_seed); 27 | }; 28 | 29 | TEST_F(K4MinHeapTest, WorksIfEmpty) { 30 | ASSERT_TRUE(empty_min_heap.empty()); 31 | 32 | for (const auto& v : test_vector) { 33 | empty_min_heap.push(v); 34 | } 35 | 36 | ASSERT_FALSE(empty_min_heap.empty()); 37 | ASSERT_EQ(empty_min_heap.size(), test_vector.size()); 38 | 39 | for (const auto& v : test_vector_sorted) { 40 | const auto x = empty_min_heap.top(); 41 | ASSERT_EQ(x, v); 42 | empty_min_heap.pop(); 43 | } 44 | } 45 | 46 | TEST_F(K4MinHeapTest, WorksIfFull) { 47 | ASSERT_FALSE(min_heap.empty()); 48 | ASSERT_EQ(min_heap.size(), test_vector.size()); 49 | 50 | for (const auto& v : test_vector_sorted) { 51 | const auto x = min_heap.top(); 52 | ASSERT_EQ(x, v); 53 | min_heap.pop(); 54 | } 55 | } 56 | 57 | TEST_F(K4MinHeapTest, WorksIfAlreadyHeap) { 58 | ASSERT_FALSE(already_min_heap.empty()); 59 | ASSERT_EQ(already_min_heap.size(), already_min_seed.size()); 60 | 61 | for (const auto& v : already_min_seed) { 62 | const auto x = already_min_heap.top(); 63 | ASSERT_EQ(x, v); 64 | already_min_heap.pop(); 65 | } 66 | } 67 | 68 | ///////////////// 69 | // K=8 70 | ///////////////// 71 | 72 | class K8MinHeapTest : public ::testing::Test { 73 | protected: 74 | K8MinHeapTest() { 75 | std::sort(test_vector_sorted.begin(), test_vector_sorted.end()); 76 | } 77 | 78 | std::vector test_vector = {30, 1, 50, 20, 40, 60, 100}; 79 | std::vector test_vector_sorted = test_vector; 80 | 81 | KHeap<8, int, false> empty_min_heap = make_min_k_heap<8, false, int>(); 82 | KHeap<8, int, false> min_heap = make_min_k_heap<8, false, int>(std::vector(test_vector)); 83 | 84 | std::vector already_min_seed = {0, 1, 2, 3, 4, 5, 6, 7, 8}; 85 | KHeap<8, int, true> already_min_heap = 86 | make_min_k_heap<8, true, int>(std::vector(already_min_seed)); 87 | }; 88 | 89 | TEST_F(K8MinHeapTest, WorksIfEmpty) { 90 | ASSERT_TRUE(empty_min_heap.empty()); 91 | 92 | for (const auto& v : test_vector) { 93 | empty_min_heap.push(v); 94 | } 95 | 96 | ASSERT_FALSE(empty_min_heap.empty()); 97 | ASSERT_EQ(empty_min_heap.size(), test_vector.size()); 98 | 99 | for (const auto& v : test_vector_sorted) { 100 | const auto x = empty_min_heap.top(); 101 | ASSERT_EQ(x, v); 102 | empty_min_heap.pop(); 103 | } 104 | } 105 | 106 | TEST_F(K8MinHeapTest, WorksIfFull) { 107 | ASSERT_FALSE(min_heap.empty()); 108 | ASSERT_EQ(min_heap.size(), test_vector.size()); 109 | 110 | for (const auto& v : test_vector_sorted) { 111 | const auto x = min_heap.top(); 112 | ASSERT_EQ(x, v); 113 | min_heap.pop(); 114 | } 115 | } 116 | 117 | TEST_F(K8MinHeapTest, WorksIfAlreadyHeap) { 118 | ASSERT_FALSE(already_min_heap.empty()); 119 | ASSERT_EQ(already_min_heap.size(), already_min_seed.size()); 120 | 121 | for (const auto& v : already_min_seed) { 122 | const auto x = already_min_heap.top(); 123 | ASSERT_EQ(x, v); 124 | already_min_heap.pop(); 125 | } 126 | } -------------------------------------------------------------------------------- /variables.bzl: -------------------------------------------------------------------------------- 1 | COPTS = select({ 2 | "@bazel_tools//src/conditions:windows": ["/std:c++17", "/W4", "/Oi", "/Ot", "/WX"], 3 | "//conditions:default": ["-std=c++17", "-O3", "-Wall", "-Wextra"], 4 | }) 5 | --------------------------------------------------------------------------------