chore: import upstream snapshot with attribution
Awesome CI Workflow / Code Formatter (push) Waiting to run
Awesome CI Workflow / Compile checks (macOS-latest) (push) Blocked by required conditions
Awesome CI Workflow / Compile checks (ubuntu-latest) (push) Blocked by required conditions
Awesome CI Workflow / Compile checks (windows-latest) (push) Blocked by required conditions
Awesome CI Workflow / Code Formatter (push) Waiting to run
Awesome CI Workflow / Compile checks (macOS-latest) (push) Blocked by required conditions
Awesome CI Workflow / Compile checks (ubuntu-latest) (push) Blocked by required conditions
Awesome CI Workflow / Compile checks (windows-latest) (push) Blocked by required conditions
This commit is contained in:
+167
@@ -0,0 +1,167 @@
|
||||
---
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -3
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveMacros: true
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 80
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: true
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^<ext/.*\.h>'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
- Regex: '^<.*'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentCaseLabels: true
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Never
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 1
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerAlignment: Left
|
||||
RawStringFormats:
|
||||
- Language: Cpp
|
||||
Delimiters:
|
||||
- cc
|
||||
- CC
|
||||
- cpp
|
||||
- Cpp
|
||||
- CPP
|
||||
- 'c++'
|
||||
- 'C++'
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
- Language: TextProto
|
||||
Delimiters:
|
||||
- pb
|
||||
- PB
|
||||
- proto
|
||||
- PROTO
|
||||
EnclosingFunctions:
|
||||
- EqualsProto
|
||||
- EquivToProto
|
||||
- PARSE_PARTIAL_TEXT_PROTO
|
||||
- PARSE_TEST_PROTO
|
||||
- PARSE_TEXT_PROTO
|
||||
- ParseTextOrDie
|
||||
- ParseTextProtoOrDie
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: false
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
Standard: Auto
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 4
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
...
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
Checks: '-*,google-*,clang-analyzer-*,-clang-analyzer-security.insecureAPI.*,cppcoreguidelines-*,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-pro-bounds-*,openmp-*,performance-*,portability-*,modernize-*,-modernize-use-trailing-*'
|
||||
WarningsAsErrors: '*,-google-readability-*,-google-explicit-constructor,-modernize-*,modernize-avoid-c-arrays,-performance-move-const-arg,-performance-noexcept-move-constructor,-performance-unnecessary-value-param,-cppcoreguidelines-init-variables,-cppcoreguidelines-pro-*,-cppcoreguidelines-owning-memory,-clang-analyzer-cplusplus.Move'
|
||||
HeaderFilterRegex: ''
|
||||
AnalyzeTemporaryDtors: false
|
||||
FormatStyle: '{ BasedOnStyle: Google, UseTab: Never, IndentWidth: 4, TabWidth: 4, AllowShortIfStatementsOnASingleLine: false, IndentCaseLabels: true, ColumnLimit: 80, AccessModifierOffset: -3, AlignConsecutiveMacros: true }'
|
||||
@@ -0,0 +1 @@
|
||||
* @Panquesito7 @realstealthninja
|
||||
@@ -0,0 +1,54 @@
|
||||
name: Bug report
|
||||
description: Create a report to help us improve. Report bugs found while using the project
|
||||
title: "[BUG]"
|
||||
labels: [bug]
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Description
|
||||
description: Provide a general summary of the issue in the Title above
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: expectedbhv
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: Tell us what should happen
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: actualbhv
|
||||
attributes:
|
||||
label: Actual behavior
|
||||
description: Tell us what happens instead
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: steps
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: |
|
||||
Provide a link to a live example, or an unambiguous set of steps to
|
||||
reproduce this bug. Include code to reproduce, if relevant
|
||||
placeholder: |
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
4.
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Context
|
||||
description: How has this bug affected you? What were you trying to accomplish?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: extrainformation
|
||||
attributes:
|
||||
label: Additional information
|
||||
description: Is there anything else we should know about this bug?
|
||||
validations:
|
||||
required: false
|
||||
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Discord community
|
||||
url: https://the-algorithms.com/discord/
|
||||
about: Have any questions or found any bugs? Please contact us via Discord
|
||||
@@ -0,0 +1,38 @@
|
||||
name: Feature request
|
||||
description: Suggest features, propose improvements, discuss new ideas.
|
||||
title: "[FEATURE]"
|
||||
labels: [enhancement]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Provide a general summary of the issue in the Title above
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Detailed description
|
||||
description: Provide a detailed description of the change or addition you are proposing
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Context
|
||||
description: |
|
||||
Why is this change important to you? How would you use it?
|
||||
How can it benefit other users?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: possibleimpl
|
||||
attributes:
|
||||
label: Possible implementation
|
||||
description: Not obligatory, but suggest an idea for implementing addition or change
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
id: extrainformation
|
||||
attributes:
|
||||
label: Additional information
|
||||
description: Is there anything else we should know about this feature?
|
||||
validations:
|
||||
required: false
|
||||
@@ -0,0 +1,19 @@
|
||||
name: Other issue
|
||||
description: Use this for any other issues. Do NOT create blank issues
|
||||
title: "[OTHER]"
|
||||
labels: ["awaiting triage"]
|
||||
body:
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: What would you like to share?
|
||||
description: Provide a clear and concise explanation of your issue.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: extrainfo
|
||||
attributes:
|
||||
label: Additional information
|
||||
description: Is there anything else we should know about this issue?
|
||||
validations:
|
||||
required: false
|
||||
@@ -0,0 +1,21 @@
|
||||
#### Description of Change
|
||||
<!--
|
||||
Thank you for your Pull Request. Please provide a description above and review
|
||||
the requirements below.
|
||||
|
||||
Contributors guide: https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/CONTRIBUTING.md
|
||||
-->
|
||||
|
||||
#### Checklist
|
||||
<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->
|
||||
|
||||
- [ ] Added description of change
|
||||
- [ ] Added file name matches [File name guidelines](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/CONTRIBUTING.md#New-File-Name-guidelines)
|
||||
- [ ] Added tests and example, test must pass
|
||||
- [ ] Added documentation so that the program is self-explanatory and educational - [Doxygen guidelines](https://www.doxygen.nl/manual/docblocks.html)
|
||||
- [ ] Relevant documentation/comments is changed or added
|
||||
- [ ] PR title follows semantic [commit guidelines](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/CONTRIBUTING.md#Commit-Guidelines)
|
||||
- [ ] Search previous suggestions before making a new one, as yours may be a duplicate.
|
||||
- [ ] I acknowledge that all my contributions will be made under the project's license.
|
||||
|
||||
Notes: <!-- Please add a one-line description for developers or pull request viewers -->
|
||||
@@ -0,0 +1,15 @@
|
||||
on: pull_request_review
|
||||
name: Add "approved" label when approved
|
||||
permissions:
|
||||
pull-requests: write
|
||||
jobs:
|
||||
add_label:
|
||||
name: Add "approved" label when approved
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Add "approved" label when approved
|
||||
uses: realstealthninja/label-when-approved@main
|
||||
with:
|
||||
approvals: 1
|
||||
secret: ${{ secrets.GITHUB_TOKEN }}
|
||||
label: "approved"
|
||||
@@ -0,0 +1,76 @@
|
||||
name: Awesome CI Workflow
|
||||
on: [push, pull_request]
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
MainSequence:
|
||||
name: Code Formatter
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v4
|
||||
- name: requirements
|
||||
run: |
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get -qq install clang-tidy clang-format
|
||||
# checks are passing with less errors when used with this version.
|
||||
# The default installs v6.0 which did not work out well in my tests
|
||||
- name: Setup Git Specs
|
||||
run: |
|
||||
git config --global user.name github-actions[bot]
|
||||
git config --global user.email 'github-actions[bot]@users.noreply.github.com'
|
||||
- name: Filename Formatter
|
||||
run: |
|
||||
wget https://raw.githubusercontent.com/TheAlgorithms/scripts/main/filename_formatter.sh
|
||||
chmod +x filename_formatter.sh
|
||||
./filename_formatter.sh . .cpp,.hpp
|
||||
- name: Get file changes
|
||||
run: |
|
||||
git branch
|
||||
git diff --diff-filter=dr --name-only origin/master > git_diff.txt
|
||||
echo "Files changed-- `cat git_diff.txt`"
|
||||
- name: Configure for static lint checks
|
||||
# compiling first gives clang-tidy access to all the header files and settings used to compile the programs.
|
||||
# This will check for macros, if any, on linux and not for Windows. But the use of portability checks should
|
||||
# be able to catch any errors for other platforms.
|
||||
run: cmake -B build -S . -DCMAKE_EXPORT_COMPILE_COMMANDS=ON
|
||||
- name: Lint modified files
|
||||
shell: bash
|
||||
run: python3 scripts/file_linter.py
|
||||
- name: Commit and push changes
|
||||
run: |
|
||||
git diff DIRECTORY.md
|
||||
git commit -am "clang-format and clang-tidy fixes for ${GITHUB_SHA::8}" || true
|
||||
git push origin HEAD:$GITHUB_REF || true
|
||||
|
||||
build:
|
||||
name: Compile checks
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: [MainSequence]
|
||||
permissions:
|
||||
pull-requests: write
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- run: |
|
||||
cmake -B ./build -S .
|
||||
cmake --build build --parallel 4
|
||||
- name: Label on PR fail
|
||||
uses: actions/github-script@v6
|
||||
if: ${{ failure() && matrix.os == 'ubuntu-latest' && github.event_name == 'pull_request' }}
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.addLabels({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
labels: ['automated tests are failing']
|
||||
})
|
||||
@@ -0,0 +1,61 @@
|
||||
name: "Code Scanning - Action"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
branches: [master]
|
||||
schedule:
|
||||
# ┌───────────── minute (0 - 59)
|
||||
# │ ┌───────────── hour (0 - 23)
|
||||
# │ │ ┌───────────── day of the month (1 - 31)
|
||||
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
|
||||
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
|
||||
# │ │ │ │ │
|
||||
# │ │ │ │ │
|
||||
# │ │ │ │ │
|
||||
# * * * * *
|
||||
- cron: "30 1 * * 0"
|
||||
|
||||
jobs:
|
||||
CodeQL-Build:
|
||||
# CodeQL runs on ubuntu-latest, windows-latest, and macos-latest
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
# required for all workflows
|
||||
security-events: write
|
||||
|
||||
# only required for workflows in private repositories
|
||||
actions: read
|
||||
contents: read
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
# Override language selection by uncommenting this and choosing your languages
|
||||
with:
|
||||
languages: cpp
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below).
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following
|
||||
# three lines and modify them (or add more) to build your code if your
|
||||
# project uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
@@ -0,0 +1,29 @@
|
||||
name: Directory writer
|
||||
on:
|
||||
schedule:
|
||||
# ┌───────────── minute (0 - 59)
|
||||
# │ ┌───────────── hour (0 - 23)
|
||||
# │ │ ┌───────────── day of the month (1 - 31)
|
||||
# │ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
|
||||
# │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
|
||||
# │ │ │ │ │
|
||||
# │ │ │ │ │
|
||||
# │ │ │ │ │
|
||||
# * * * * *
|
||||
- cron: '0 0 * * *'
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
build:
|
||||
if: github.repository == 'TheAlgorithms/C-Plus-Plus' # We only need this to run in our repository.
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Build directory
|
||||
uses: TheAlgorithms/scripts/directory_md@main
|
||||
with:
|
||||
language: C-Plus-Plus
|
||||
working-directory: .
|
||||
filetypes: .cpp,.hpp,.h
|
||||
ignored-directories: doc/
|
||||
@@ -0,0 +1,36 @@
|
||||
name: Doxygen CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install requirements
|
||||
run: |
|
||||
brew install graphviz ninja doxygen
|
||||
- name: configure
|
||||
run: cmake -G Ninja -Duse_libclang=ON -DCMAKE_CXX_COMPILER=clang++ -B ./build -S .
|
||||
- name: build
|
||||
run: cmake --build build -t doc
|
||||
- name: gh-pages
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: "gh-pages"
|
||||
clean: false
|
||||
- name: Move & Commit files
|
||||
run: |
|
||||
git config --global user.name "$GITHUB_ACTOR"
|
||||
git config --global user.email "$GITHUB_ACTOR@users.noreply.github.com"
|
||||
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY
|
||||
rm -rf d* && rm *.html && rm *.svg && rm *.map && rm *.md5 && rm *.png && rm *.js
|
||||
git add .
|
||||
cp -rp ./build/html/* . && rm -rf ./build && ls -lah
|
||||
git add .
|
||||
git commit -m "Documentation for $GITHUB_SHA" || true
|
||||
git push --force || true
|
||||
@@ -0,0 +1,18 @@
|
||||
name: 'Close stale issues and PRs'
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v4
|
||||
with:
|
||||
stale-issue-message: 'This issue has been automatically marked as abandoned because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
|
||||
close-issue-message: 'Please ping one of the maintainers once you add more information and updates here. If this is not the case and you need some help, feel free to ask for help in our [Gitter](https://gitter.im/TheAlgorithms) channel or our [Discord server](https://the-algorithms.com/discord/). Thank you for your contributions!'
|
||||
stale-pr-message: 'This pull request has been automatically marked as abandoned because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.'
|
||||
close-pr-message: 'Please ping one of the maintainers once you commit the changes requested or make improvements on the code. If this is not the case and you need some help, feel free to ask for help in our [Gitter](https://gitter.im/TheAlgorithms) channel or our [Discord server](https://the-algorithms.com/discord/). Thank you for your contributions!'
|
||||
exempt-issue-labels: 'dont-close,approved'
|
||||
exempt-pr-labels: 'dont-close,approved'
|
||||
days-before-stale: 30
|
||||
days-before-close: 7
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
.DS_Store
|
||||
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
a.out
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Cache
|
||||
.cache/
|
||||
|
||||
# Build
|
||||
build/
|
||||
git_diff.txt
|
||||
@@ -0,0 +1,11 @@
|
||||
FROM gitpod/workspace-full-vnc
|
||||
|
||||
RUN sudo apt-get update \
|
||||
&& sudo apt-get install -y \
|
||||
doxygen \
|
||||
graphviz \
|
||||
ninja-build \
|
||||
freeglut3 \
|
||||
freeglut3-dev \
|
||||
&& pip install cpplint \
|
||||
&& sudo rm -rf /var/lib/apt/lists/*
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
image:
|
||||
file: .gitpod.dockerfile
|
||||
|
||||
github:
|
||||
prebuilds:
|
||||
addBadge: true
|
||||
addComment: false
|
||||
addCheck: false
|
||||
master: true
|
||||
branches: true
|
||||
pullRequestsFromForks: true
|
||||
|
||||
vscode:
|
||||
extensions:
|
||||
# - ms-vscode.cpptools
|
||||
- twxs.cmake
|
||||
- ms-vscode.cmake-tools
|
||||
- mhutchie.git-graph
|
||||
- notskm.clang-tidy
|
||||
- mitaki28.vscode-clang
|
||||
Vendored
+91
@@ -0,0 +1,91 @@
|
||||
{
|
||||
"C_Cpp.clang_format_style": "{ BasedOnStyle: Google, UseTab: Never, IndentWidth: 4, TabWidth: 4, AllowShortIfStatementsOnASingleLine: false, IndentCaseLabels: true, ColumnLimit: 80, AccessModifierOffset: -3, AlignConsecutiveMacros: true }",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnType": true,
|
||||
"editor.formatOnPaste": true,
|
||||
"files.associations": {
|
||||
"array": "cpp",
|
||||
"atomic": "cpp",
|
||||
"*.tcc": "cpp",
|
||||
"bitset": "cpp",
|
||||
"cctype": "cpp",
|
||||
"chrono": "cpp",
|
||||
"cinttypes": "cpp",
|
||||
"clocale": "cpp",
|
||||
"cmath": "cpp",
|
||||
"complex": "cpp",
|
||||
"cstdarg": "cpp",
|
||||
"cstddef": "cpp",
|
||||
"cstdint": "cpp",
|
||||
"cstdio": "cpp",
|
||||
"cstdlib": "cpp",
|
||||
"cstring": "cpp",
|
||||
"ctime": "cpp",
|
||||
"cwchar": "cpp",
|
||||
"cwctype": "cpp",
|
||||
"deque": "cpp",
|
||||
"list": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"vector": "cpp",
|
||||
"exception": "cpp",
|
||||
"algorithm": "cpp",
|
||||
"functional": "cpp",
|
||||
"iterator": "cpp",
|
||||
"map": "cpp",
|
||||
"memory": "cpp",
|
||||
"memory_resource": "cpp",
|
||||
"numeric": "cpp",
|
||||
"optional": "cpp",
|
||||
"random": "cpp",
|
||||
"ratio": "cpp",
|
||||
"set": "cpp",
|
||||
"string": "cpp",
|
||||
"string_view": "cpp",
|
||||
"system_error": "cpp",
|
||||
"tuple": "cpp",
|
||||
"type_traits": "cpp",
|
||||
"utility": "cpp",
|
||||
"fstream": "cpp",
|
||||
"initializer_list": "cpp",
|
||||
"iomanip": "cpp",
|
||||
"iosfwd": "cpp",
|
||||
"iostream": "cpp",
|
||||
"istream": "cpp",
|
||||
"limits": "cpp",
|
||||
"new": "cpp",
|
||||
"ostream": "cpp",
|
||||
"sstream": "cpp",
|
||||
"stdexcept": "cpp",
|
||||
"streambuf": "cpp",
|
||||
"typeinfo": "cpp",
|
||||
"valarray": "cpp",
|
||||
"bit": "cpp",
|
||||
"charconv": "cpp",
|
||||
"compare": "cpp",
|
||||
"concepts": "cpp",
|
||||
"format": "cpp",
|
||||
"forward_list": "cpp",
|
||||
"ios": "cpp",
|
||||
"locale": "cpp",
|
||||
"queue": "cpp",
|
||||
"stack": "cpp",
|
||||
"xfacet": "cpp",
|
||||
"xhash": "cpp",
|
||||
"xiosbase": "cpp",
|
||||
"xlocale": "cpp",
|
||||
"xlocbuf": "cpp",
|
||||
"xlocinfo": "cpp",
|
||||
"xlocmes": "cpp",
|
||||
"xlocmon": "cpp",
|
||||
"xlocnum": "cpp",
|
||||
"xloctime": "cpp",
|
||||
"xmemory": "cpp",
|
||||
"xstddef": "cpp",
|
||||
"xstring": "cpp",
|
||||
"xtr1common": "cpp",
|
||||
"xtree": "cpp",
|
||||
"xutility": "cpp",
|
||||
"climits": "cpp"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
project(TheAlgorithms/C++
|
||||
LANGUAGES CXX
|
||||
VERSION 1.0.0
|
||||
DESCRIPTION "Set of algorithms implemented in C++."
|
||||
)
|
||||
|
||||
# C++ standard
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# Additional warnings and errors
|
||||
if(MSVC)
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||
add_compile_options(/W4 /permissive-)
|
||||
else()
|
||||
add_compile_options(-Wall -Wextra -Wno-register -Werror=vla)
|
||||
endif()
|
||||
|
||||
option(USE_OPENMP "flag to use OpenMP for multithreading" ON)
|
||||
if(USE_OPENMP)
|
||||
find_package(OpenMP 3.0 COMPONENTS CXX)
|
||||
if (OpenMP_CXX_FOUND)
|
||||
message(STATUS "Building with OpenMP Multithreading.")
|
||||
else()
|
||||
message(STATUS "No OpenMP found, no multithreading.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_subdirectory(backtracking)
|
||||
add_subdirectory(bit_manipulation)
|
||||
add_subdirectory(ciphers)
|
||||
add_subdirectory(cpu_scheduling_algorithms)
|
||||
add_subdirectory(data_structures)
|
||||
add_subdirectory(divide_and_conquer)
|
||||
add_subdirectory(dynamic_programming)
|
||||
add_subdirectory(games)
|
||||
add_subdirectory(geometry)
|
||||
add_subdirectory(graph)
|
||||
add_subdirectory(graphics)
|
||||
add_subdirectory(greedy_algorithms)
|
||||
add_subdirectory(hashing)
|
||||
add_subdirectory(machine_learning)
|
||||
add_subdirectory(math)
|
||||
add_subdirectory(numerical_methods)
|
||||
add_subdirectory(operations_on_datastructures)
|
||||
add_subdirectory(others)
|
||||
add_subdirectory(physics)
|
||||
add_subdirectory(probability)
|
||||
add_subdirectory(range_queries)
|
||||
add_subdirectory(search)
|
||||
add_subdirectory(sorting)
|
||||
add_subdirectory(strings)
|
||||
|
||||
cmake_policy(SET CMP0054 NEW)
|
||||
cmake_policy(SET CMP0057 NEW)
|
||||
|
||||
find_package(Doxygen OPTIONAL_COMPONENTS dot dia)
|
||||
if(DOXYGEN_FOUND)
|
||||
if(MSVC)
|
||||
set(DOXYGEN_CPP_CLI_SUPPORT YES)
|
||||
endif()
|
||||
|
||||
if(Doxygen_dot_FOUND)
|
||||
set(DOXYGEN_HAVE_DOT YES)
|
||||
endif()
|
||||
|
||||
if(OPENMP_FOUND)
|
||||
set(DOXYGEN_PREDEFINED "_OPENMP=1")
|
||||
endif()
|
||||
|
||||
if(GLUT_FOUND)
|
||||
set(DOXYGEN_PREDEFINED ${DOXYGEN_PREDEFINED} "GLUT_FOUND=1")
|
||||
endif()
|
||||
|
||||
doxygen_add_docs(
|
||||
doc
|
||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
|
||||
COMMENT "Generate documentation"
|
||||
CONFIG_FILE ${CMAKE_CURRENT_SOURCE_DIR}/doc/Doxyfile
|
||||
)
|
||||
endif()
|
||||
|
||||
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
|
||||
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
|
||||
include(CPack)
|
||||
@@ -0,0 +1,132 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, caste, color, religion, or sexual
|
||||
identity and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the overall
|
||||
community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or advances of
|
||||
any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email address,
|
||||
without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
hello@the-algorithms.com.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series of
|
||||
actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or permanent
|
||||
ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within the
|
||||
community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.1, available at
|
||||
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
|
||||
|
||||
Community Impact Guidelines were inspired by
|
||||
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
|
||||
[https://www.contributor-covenant.org/translations][translations].
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
|
||||
[Mozilla CoC]: https://github.com/mozilla/diversity
|
||||
[FAQ]: https://www.contributor-covenant.org/faq
|
||||
[translations]: https://www.contributor-covenant.org/translations
|
||||
+352
@@ -0,0 +1,352 @@
|
||||
# CONTRIBUTION GUIDELINES
|
||||
|
||||
## Before contributing
|
||||
|
||||
Welcome to [TheAlgorithms/C-Plus-Plus](https://github.com/TheAlgorithms/C-Plus-Plus)! Before submitting pull requests, please make sure that you have **read the whole guidelines**. If you have any doubts about this contribution guide, please open [an issue](https://github.com/TheAlgorithms/C-Plus-Plus/issues/new/choose) or ask on our [Discord server](https://the-algorithms.com/discord/), and clearly state your concerns.
|
||||
|
||||
## Contributing
|
||||
|
||||
### Maintainer/reviewer
|
||||
|
||||
**Please check the [reviewer code](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/REVIEWER_CODE.md) file for maintainers and reviewers.**
|
||||
|
||||
### Contributor
|
||||
|
||||
Being a contributor at The Algorithms, we request you to follow the points mentioned below:
|
||||
|
||||
- You did your own work.
|
||||
- No plagiarism is allowed. Any plagiarized work will not be merged.
|
||||
- Your work will be distributed under the [MIT License](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/LICENSE) once your pull request has been merged.
|
||||
- Please follow the repository guidelines and standards mentioned below.
|
||||
|
||||
**New implementation**
|
||||
We welcome new implementations!
|
||||
|
||||
You can add new algorithms or data structures that are **not present in the repository** or that can **improve** the old implementations (**documentation**, **improving test cases**, removing bugs, or in any other reasonable sense)
|
||||
|
||||
**Issues** Please avoid opening issues asking to be "assigned” to a particular algorithm. This merely creates unnecessary noise for maintainers. Instead, please submit your implementation in a pull request, and it will be evaluated by project maintainers.
|
||||
|
||||
### Making Changes
|
||||
|
||||
#### Code
|
||||
|
||||
- Please use the directory structure of the repository.
|
||||
- Make sure the file extensions are `*.hpp`, `*.h` or `*.cpp`.
|
||||
- Don't use **`bits/stdc++.h`** because this is quite Linux-specific and slows down the compilation process.
|
||||
- Organize your code using **`struct`**, **`class`**, and/or **`namespace`** keywords.
|
||||
- If an implementation of the algorithm already exists, please refer to the [file-name section below](#file-name-guidelines).
|
||||
- You can suggest reasonable changes to existing algorithms.
|
||||
- Strictly use snake_case (underscore_separated) in filenames.
|
||||
- If you have added or modified code, please make sure the code compiles before submitting.
|
||||
- Our automated testing runs [**CMake**](https://cmake.org/) on all the pull requests, so please be sure that your code passes before submitting.
|
||||
- Please conform to [Doxygen](https://www.doxygen.nl/manual/docblocks.html) standards and document the code as much as possible. This not only facilitates the readers but also generates the correct info on the website.
|
||||
- **Be consistent in the use of these guidelines.**
|
||||
|
||||
#### Documentation
|
||||
|
||||
- Make sure you put useful comments in your code. Do not comment on obvious things.
|
||||
- Please avoid creating new directories if at all possible. Try to fit your work into the existing directory structure. If you want to create a new directory, then please check if a similar category has been recently suggested or created by other pull requests.
|
||||
- If you have modified/added documentation, please ensure that your language is concise and must not contain grammatical errors.
|
||||
- Do not update [`README.md`](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/README.md) along with other changes. First, create an issue and then link to that issue in your pull request to suggest specific changes required to [`README.md`](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/README.md).
|
||||
- The repository follows [Doxygen](https://www.doxygen.nl/manual/docblocks.html) standards and auto-generates the [repository website](https://thealgorithms.github.io/C-Plus-Plus). Please ensure the code is documented in this structure. A sample implementation is given below.
|
||||
|
||||
#### Test
|
||||
|
||||
- Make sure to add examples and test cases in your `main()` function.
|
||||
- If you find an algorithm or document without tests, please feel free to create a pull request or issue describing suggested changes.
|
||||
- Please try to add one or more `test()` functions that will invoke the algorithm implementation on random test data with the expected output. Use the `assert()` function to confirm that the tests will pass. Requires including the `cassert` library.
|
||||
- Test cases should fully verify that your program works as expected. Rather than asking the user for input, it's best to make sure the given output is the correct output.
|
||||
|
||||
##### Self-test examples
|
||||
|
||||
1. [Quick sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/sorting/quick_sort.cpp#L137) testing (complex).
|
||||
|
||||
```cpp
|
||||
// Let's make sure the array of numbers is ordered after calling the function.
|
||||
std::vector<uint64_t> arr = {5, 3, 8, 12, 14, 16, 28, 96, 2, 5977};
|
||||
std::vector<uint64_t> arr_sorted = sorting::quick_sort::quick_sort(
|
||||
arr, 0, int(std::end(arr) - std::begin(arr)) - 1);
|
||||
|
||||
assert(std::is_sorted(std::begin(arr_sorted), std::end(arr_sorted)));
|
||||
```
|
||||
|
||||
2. [Subset Sum](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/backtracking/subset_sum.cpp#L58) testing (medium).
|
||||
|
||||
```cpp
|
||||
std::vector<int32_t> array1 = {-7, -3, -2, 5, 8}; // input array
|
||||
assert(backtracking::subset_sum::number_of_subsets(0, array1) ==
|
||||
2); // first argument in subset_sum function is the required sum and
|
||||
// second is the input array
|
||||
```
|
||||
|
||||
3. Small C++ program that showcases and explains the use of tests.
|
||||
|
||||
```cpp
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
#include <cassert> /// for assert
|
||||
|
||||
/**
|
||||
* @brief Verifies if the given array
|
||||
* contains the given number on it.
|
||||
* @tparam T the type of array (e.g., `int`, `float`, etc.)
|
||||
* @param arr the array to be used for checking
|
||||
* @param number the number to check if it's inside the array
|
||||
* @return false if the number was NOT found in the array
|
||||
* @return true if the number WAS found in the array
|
||||
*/
|
||||
template <typename T>
|
||||
bool is_number_on_array(const std::vector<T> &arr, const int &number) {
|
||||
for (int i = 0; i < sizeof(arr) / sizeof(int); i++) {
|
||||
if (arr[i] == number) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// Number not in the current index, keep searching.
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void tests() {
|
||||
std::vector<int> arr = { 9, 14, 21, 98, 67 };
|
||||
|
||||
assert(is_number_on_array(arr, 9) == true);
|
||||
assert(is_number_on_array(arr, 4) == false);
|
||||
assert(is_number_on_array(arr, 98) == true);
|
||||
assert(is_number_on_array(arr, 512) == false);
|
||||
|
||||
std::cout << "All tests have successfully passed!\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
tests(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
#### Typical structure of a program
|
||||
|
||||
```cpp
|
||||
/**
|
||||
* @file
|
||||
* @brief Add one-line description here. Should contain a Wikipedia
|
||||
* link or another source explaining the algorithm/implementation.
|
||||
* @details
|
||||
* This is a multi-line
|
||||
* description containing links, references,
|
||||
* math equations, etc.
|
||||
* @author [Name](https://github.com/handle)
|
||||
* @see related_file.cpp, another_file.cpp
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include /// for `some function here`
|
||||
|
||||
/**
|
||||
* @namespace
|
||||
* @brief <namespace description>
|
||||
*/
|
||||
namespace name {
|
||||
|
||||
/**
|
||||
* @brief Class documentation
|
||||
*/
|
||||
class class_name {
|
||||
private:
|
||||
int variable; ///< short info of this variable
|
||||
char *message; ///< short info
|
||||
|
||||
public:
|
||||
// other members should be also documented as below
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function documentation
|
||||
* @tparam T this is a one-line info about T
|
||||
* @param param1 on-line info about param1
|
||||
* @param param2 on-line info about param2
|
||||
* @returns `true` if ...
|
||||
* @returns `false` if ...
|
||||
*/
|
||||
template<class T>
|
||||
bool func(int param1, T param2) {
|
||||
// function statements here
|
||||
if (/*something bad*/) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace name
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
/* descriptions of the following test */
|
||||
assert(func(...) == ...); // this ensures that the algorithm works as expected
|
||||
|
||||
// can have multiple checks
|
||||
|
||||
// this lets the user know that the tests have passed
|
||||
std::cout << "All tests have successfully passed!\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
// code here
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
#### File Name guidelines
|
||||
|
||||
- Use lowercase words with ``"_"`` as a separator
|
||||
- For instance
|
||||
|
||||
```markdown
|
||||
MyNewCppClass.CPP is incorrect
|
||||
my_new_cpp_class.cpp is correct format
|
||||
```
|
||||
|
||||
- It will be used to dynamically create a directory of files and implementation.
|
||||
- File name validation will run on Docker to ensure validity.
|
||||
- If an implementation of the algorithm already exists and your version is different from that implemented, please use incremental numeric digit as a suffix. For example: if `median_search.cpp` already exists in the `search` folder, and you are contributing a new implementation, the filename should be `median_search2.cpp`. For a third implementation, `median_search3.cpp`, and so on.
|
||||
|
||||
#### Directory guidelines
|
||||
|
||||
- We recommend adding files to existing directories as much as possible.
|
||||
- Use lowercase words with ``"_"`` as separator ( no spaces or ```"-"``` allowed )
|
||||
- For instance
|
||||
|
||||
```markdown
|
||||
SomeNew Fancy-Category is incorrect
|
||||
some_new_fancy_category is correct
|
||||
```
|
||||
|
||||
- Filepaths will be used to dynamically create a directory of our algorithms.
|
||||
- Filepath validation will run on GitHub Actions to ensure compliance.
|
||||
|
||||
##### Integrating CMake in a new directory
|
||||
|
||||
In case a new directory is 100% required, `CMakeLists.txt` file in the root directory needs to be updated, and a new `CMakeLists.txt` file needs to be created within the new directory.
|
||||
|
||||
An example of how your new `CMakeLists.txt` file should look like. Note that if there are any extra libraries/setup required, you must include that in this file as well.
|
||||
|
||||
```cmake
|
||||
# If necessary, use the RELATIVE flag, otherwise each source file may be listed
|
||||
# with full pathname. The RELATIVE flag makes it easier to extract an executable's name
|
||||
# automatically.
|
||||
|
||||
file( GLOB APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp )
|
||||
foreach( testsourcefile ${APP_SOURCES} )
|
||||
string( REPLACE ".cpp" "" testname ${testsourcefile} ) # File type. Example: `.cpp`
|
||||
add_executable( ${testname} ${testsourcefile} )
|
||||
|
||||
set_target_properties(${testname} PROPERTIES LINKER_LANGUAGE CXX)
|
||||
if(OpenMP_CXX_FOUND)
|
||||
target_link_libraries(${testname} OpenMP::OpenMP_CXX)
|
||||
endif()
|
||||
install(TARGETS ${testname} DESTINATION "bin/<foldername>") # Folder name. Do NOT include `<>`
|
||||
|
||||
endforeach( testsourcefile ${APP_SOURCES} )
|
||||
```
|
||||
|
||||
The `CMakeLists.txt` file in the root directory should be updated to include the new directory.\
|
||||
Include your new directory after the last subdirectory. Example:
|
||||
|
||||
```cmake
|
||||
...
|
||||
add_subdirectory(divide_and_conquer)
|
||||
add_subdirectory(<foldername>)
|
||||
```
|
||||
|
||||
#### Commit Guidelines
|
||||
|
||||
- It is recommended to keep your changes grouped logically within individual commits. Maintainers find it easier to understand changes that are logically spilled across multiple commits. Try to modify just one or two files in the same directory. Pull requests that span multiple directories are often rejected.
|
||||
|
||||
```bash
|
||||
git add file_xyz.cpp
|
||||
git commit -m "your message"
|
||||
```
|
||||
|
||||
Examples of commit messages with semantic prefixes:
|
||||
|
||||
```markdown
|
||||
fix: xyz algorithm bug
|
||||
feat: add xyx algorithm, class xyz
|
||||
test: add test for xyz algorithm
|
||||
docs: add comments and explanation to xyz algorithm/improve contributing guidelines
|
||||
chore: update Gitpod badge
|
||||
```
|
||||
|
||||
Common prefixes:
|
||||
|
||||
- fix: A bug fix
|
||||
- feat: A new feature
|
||||
- docs: Documentation changes
|
||||
- test: Correct existing tests or add new ones
|
||||
- chore: Miscellaneous changes that do not match any of the above.
|
||||
|
||||
### Pull Requests
|
||||
|
||||
- Checkout our [pull request template](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/.github/pull_request_template.md)
|
||||
|
||||
#### Building Locally
|
||||
|
||||
Before submitting a pull request,
|
||||
build the code locally or using the convenient [](https://gitpod.io/#https://github.com/TheAlgorithms/C-Plus-Plus) service.
|
||||
|
||||
```bash
|
||||
cmake -B build -S .
|
||||
```
|
||||
|
||||
#### Static Code Analyzer
|
||||
|
||||
We use [`clang-tidy`](https://clang.llvm.org/extra/clang-tidy/) as a static code analyzer with a configuration in [`.clang-tidy`](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/.clang-tidy).
|
||||
|
||||
```bash
|
||||
clang-tidy --fix --quiet -p build subfolder/file_to_check.cpp --
|
||||
```
|
||||
|
||||
#### Code Formatter
|
||||
|
||||
[`clang-format`](https://clang.llvm.org/docs/ClangFormat.html) is used for code formatting.
|
||||
|
||||
- Installation (only needs to be installed once.)
|
||||
- Mac (using home-brew): `brew install clang-format`
|
||||
- Mac (using macports): `sudo port install clang-10 +analyzer`
|
||||
- Windows (MSYS2 64-bit): `pacman -S mingw-w64-x86_64-clang-tools-extra`
|
||||
- Linux (Debian): `sudo apt-get install clang-format-10 clang-tidy-10`
|
||||
- Running (all platforms): `clang-format -i -style="file" my_file.cpp`
|
||||
|
||||
#### GitHub Actions
|
||||
|
||||
- Enable GitHub Actions on your fork of the repository.
|
||||
After enabling, it will execute `clang-tidy` and `clang-format` after every push (not a commit).
|
||||
- Click on the tab "Actions", then click on the big green button to enable it.
|
||||
|
||||

|
||||
|
||||
- The result can create another commit if the actions made any changes on your behalf.
|
||||
- Hence, it is better to wait and check the results of GitHub Actions after every push.
|
||||
- Run `git pull` in your local clone if these actions made many changes to avoid merge conflicts.
|
||||
|
||||
Most importantly,
|
||||
|
||||
- Happy coding!
|
||||
@@ -0,0 +1,18 @@
|
||||
# Code style convention
|
||||
|
||||
Please orient on this guide before you sent a pull request.
|
||||
|
||||
---
|
||||
|
||||
## User-interface
|
||||
|
||||
Please write a simple user interface for your programs. Not a blinking cursor!
|
||||
What does the program do?
|
||||
What want the program an user informations?
|
||||
|
||||
---
|
||||
|
||||
## Code style conventions
|
||||
|
||||
See [here](https://users.ece.cmu.edu/~eno/coding/CppCodingStandard.html)
|
||||
Don't push all code in one line!
|
||||
+417
@@ -0,0 +1,417 @@
|
||||
|
||||
## Backtracking
|
||||
* [Generate Parentheses](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/backtracking/generate_parentheses.cpp)
|
||||
* [Graph Coloring](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/backtracking/graph_coloring.cpp)
|
||||
* [Knight Tour](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/backtracking/knight_tour.cpp)
|
||||
* [Magic Sequence](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/backtracking/magic_sequence.cpp)
|
||||
* [Minimax](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/backtracking/minimax.cpp)
|
||||
* [N Queens](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/backtracking/n_queens.cpp)
|
||||
* [N Queens All Solution Optimised](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/backtracking/n_queens_all_solution_optimised.cpp)
|
||||
* [Nqueen Print All Solutions](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/backtracking/nqueen_print_all_solutions.cpp)
|
||||
* [Rat Maze](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/backtracking/rat_maze.cpp)
|
||||
* [Subarray Sum](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/backtracking/subarray_sum.cpp)
|
||||
* [Subset Sum](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/backtracking/subset_sum.cpp)
|
||||
* [Sudoku Solver](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/backtracking/sudoku_solver.cpp)
|
||||
* [Wildcard Matching](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/backtracking/wildcard_matching.cpp)
|
||||
|
||||
## Bit Manipulation
|
||||
* [Count Bits Flip](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/count_bits_flip.cpp)
|
||||
* [Count Of Set Bits](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/count_of_set_bits.cpp)
|
||||
* [Count Of Trailing Ciphers In Factorial N](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/count_of_trailing_ciphers_in_factorial_n.cpp)
|
||||
* [Find Non Repeating Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/find_non_repeating_number.cpp)
|
||||
* [Gray Code](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/gray_code.cpp)
|
||||
* [Hamming Distance](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/hamming_distance.cpp)
|
||||
* [Next Higher Number With Same Number Of Set Bits](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/next_higher_number_with_same_number_of_set_bits.cpp)
|
||||
* [Power Of 2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/power_of_2.cpp)
|
||||
* [Set Kth Bit](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/set_kth_bit.cpp)
|
||||
* [Travelling Salesman Using Bit Manipulation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/bit_manipulation/travelling_salesman_using_bit_manipulation.cpp)
|
||||
|
||||
## Ciphers
|
||||
* [A1Z26 Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/ciphers/a1z26_cipher.cpp)
|
||||
* [Atbash Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/ciphers/atbash_cipher.cpp)
|
||||
* [Base64 Encoding](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/ciphers/base64_encoding.cpp)
|
||||
* [Caesar Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/ciphers/caesar_cipher.cpp)
|
||||
* [Elliptic Curve Key Exchange](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/ciphers/elliptic_curve_key_exchange.cpp)
|
||||
* [Hill Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/ciphers/hill_cipher.cpp)
|
||||
* [Morse Code](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/ciphers/morse_code.cpp)
|
||||
* [Uint128 T](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/ciphers/uint128_t.hpp)
|
||||
* [Uint256 T](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/ciphers/uint256_t.hpp)
|
||||
* [Vigenere Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/ciphers/vigenere_cipher.cpp)
|
||||
* [Xor Cipher](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/ciphers/xor_cipher.cpp)
|
||||
|
||||
## Cpu Scheduling Algorithms
|
||||
* [Fcfs Scheduling](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/cpu_scheduling_algorithms/fcfs_scheduling.cpp)
|
||||
* [Non Preemptive Sjf Scheduling](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/cpu_scheduling_algorithms/non_preemptive_sjf_scheduling.cpp)
|
||||
|
||||
## Data Structures
|
||||
* [Avltree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/avltree.cpp)
|
||||
* [Binary Search Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/binary_search_tree.cpp)
|
||||
* [Binary Search Tree2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/binary_search_tree2.cpp)
|
||||
* [Binaryheap](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/binaryheap.cpp)
|
||||
* [Bloom Filter](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/bloom_filter.cpp)
|
||||
* [Circular Queue Using Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/circular_queue_using_linked_list.cpp)
|
||||
* Cll
|
||||
* [Cll](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/cll/cll.cpp)
|
||||
* [Cll](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/cll/cll.h)
|
||||
* [Main Cll](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/cll/main_cll.cpp)
|
||||
* [Disjoint Set](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/disjoint_set.cpp)
|
||||
* [Doubly Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/doubly_linked_list.cpp)
|
||||
* [Dsu Path Compression](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/dsu_path_compression.cpp)
|
||||
* [Dsu Union Rank](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/dsu_union_rank.cpp)
|
||||
* [Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/linked_list.cpp)
|
||||
* [Linkedlist Implentation Usingarray](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/linkedlist_implentation_usingarray.cpp)
|
||||
* [List Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/list_array.cpp)
|
||||
* [Morrisinorder](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/morrisinorder.cpp)
|
||||
* [Node](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/node.hpp)
|
||||
* [Queue](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/queue.hpp)
|
||||
* [Queue Using Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/queue_using_array.cpp)
|
||||
* [Queue Using Array2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/queue_using_array2.cpp)
|
||||
* [Queue Using Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/queue_using_linked_list.cpp)
|
||||
* [Queue Using Linkedlist](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/queue_using_linkedlist.cpp)
|
||||
* [Queue Using Two Stacks](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/queue_using_two_stacks.cpp)
|
||||
* [Rb Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/rb_tree.cpp)
|
||||
* [Reverse A Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/reverse_a_linked_list.cpp)
|
||||
* [Segment Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/segment_tree.cpp)
|
||||
* [Skip List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/skip_list.cpp)
|
||||
* [Sparse Table](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/sparse_table.cpp)
|
||||
* [Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/stack.hpp)
|
||||
* [Stack Using Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/stack_using_array.cpp)
|
||||
* [Stack Using Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/stack_using_linked_list.cpp)
|
||||
* [Stack Using Queue](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/stack_using_queue.cpp)
|
||||
* [Test Queue](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/test_queue.cpp)
|
||||
* [Test Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/test_stack.cpp)
|
||||
* [Test Stack Students](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/test_stack_students.cpp)
|
||||
* [Treap](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/treap.cpp)
|
||||
* [Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/tree.cpp)
|
||||
* [Tree 234](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/tree_234.cpp)
|
||||
* [Trie Modern](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/trie_modern.cpp)
|
||||
* [Trie Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/trie_tree.cpp)
|
||||
* [Trie Using Hashmap](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/data_structures/trie_using_hashmap.cpp)
|
||||
|
||||
## Divide And Conquer
|
||||
* [Karatsuba Algorithm For Fast Multiplication](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/divide_and_conquer/karatsuba_algorithm_for_fast_multiplication.cpp)
|
||||
* [Strassen Matrix Multiplication](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/divide_and_conquer/strassen_matrix_multiplication.cpp)
|
||||
|
||||
## Dynamic Programming
|
||||
* [0 1 Knapsack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/0_1_knapsack.cpp)
|
||||
* [Abbreviation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/abbreviation.cpp)
|
||||
* [Armstrong Number Templated](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/armstrong_number_templated.cpp)
|
||||
* [Bellman Ford](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/bellman_ford.cpp)
|
||||
* [Catalan Numbers](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/catalan_numbers.cpp)
|
||||
* [Coin Change](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/coin_change.cpp)
|
||||
* [Coin Change Topdown](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/coin_change_topdown.cpp)
|
||||
* [Cut Rod](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/cut_rod.cpp)
|
||||
* [Edit Distance](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/edit_distance.cpp)
|
||||
* [Egg Dropping Puzzle](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/egg_dropping_puzzle.cpp)
|
||||
* [Fibonacci Bottom Up](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/fibonacci_bottom_up.cpp)
|
||||
* [Floyd Warshall](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/floyd_warshall.cpp)
|
||||
* [House Robber](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/house_robber.cpp)
|
||||
* [Kadane](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/kadane.cpp)
|
||||
* [Longest Common String](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/longest_common_string.cpp)
|
||||
* [Longest Common Subsequence](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/longest_common_subsequence.cpp)
|
||||
* [Longest Increasing Subsequence](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/longest_increasing_subsequence.cpp)
|
||||
* [Longest Increasing Subsequence Nlogn](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/longest_increasing_subsequence_nlogn.cpp)
|
||||
* [Longest Palindromic Subsequence](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/longest_palindromic_subsequence.cpp)
|
||||
* [Matrix Chain Multiplication](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/matrix_chain_multiplication.cpp)
|
||||
* [Maximum Circular Subarray](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/maximum_circular_subarray.cpp)
|
||||
* [Minimum Edit Distance](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/minimum_edit_distance.cpp)
|
||||
* [Palindrome Partitioning](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/palindrome_partitioning.cpp)
|
||||
* [Partition Problem](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/partition_problem.cpp)
|
||||
* [Searching Of Element In Dynamic Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/searching_of_element_in_dynamic_array.cpp)
|
||||
* [Shortest Common Supersequence](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/shortest_common_supersequence.cpp)
|
||||
* [Subset Sum Dynamic](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/subset_sum_dynamic.cpp)
|
||||
* [Trapped Rainwater](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/trapped_rainwater.cpp)
|
||||
* [Trapped Rainwater2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/trapped_rainwater2.cpp)
|
||||
* [Tree Height](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/tree_height.cpp)
|
||||
* [Unbounded 0 1 Knapsack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/unbounded_0_1_knapsack.cpp)
|
||||
* [Word Break](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/dynamic_programming/word_break.cpp)
|
||||
|
||||
## Games
|
||||
* [Memory Game](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/games/memory_game.cpp)
|
||||
|
||||
## Geometry
|
||||
* [Graham Scan Algorithm](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/geometry/graham_scan_algorithm.cpp)
|
||||
* [Graham Scan Functions](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/geometry/graham_scan_functions.hpp)
|
||||
* [Jarvis Algorithm](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/geometry/jarvis_algorithm.cpp)
|
||||
* [Line Segment Intersection](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/geometry/line_segment_intersection.cpp)
|
||||
|
||||
## Graph
|
||||
* [Bidirectional Dijkstra](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/bidirectional_dijkstra.cpp)
|
||||
* [Breadth First Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/breadth_first_search.cpp)
|
||||
* [Bridge Finding With Tarjan Algorithm](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/bridge_finding_with_tarjan_algorithm.cpp)
|
||||
* [Connected Components](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/connected_components.cpp)
|
||||
* [Connected Components With Dsu](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/connected_components_with_dsu.cpp)
|
||||
* [Cycle Check Directed Graph](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/cycle_check_directed_graph.cpp)
|
||||
* [Depth First Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/depth_first_search.cpp)
|
||||
* [Depth First Search With Stack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/depth_first_search_with_stack.cpp)
|
||||
* [Dijkstra](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/dijkstra.cpp)
|
||||
* [Hamiltons Cycle](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/hamiltons_cycle.cpp)
|
||||
* [Hopcroft Karp](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/hopcroft_karp.cpp)
|
||||
* [Is Graph Bipartite](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/is_graph_bipartite.cpp)
|
||||
* [Is Graph Bipartite2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/is_graph_bipartite2.cpp)
|
||||
* [Kosaraju](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/kosaraju.cpp)
|
||||
* [Kruskal](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/kruskal.cpp)
|
||||
* [Lowest Common Ancestor](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/lowest_common_ancestor.cpp)
|
||||
* [Max Flow With Ford Fulkerson And Edmond Karp Algo](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/max_flow_with_ford_fulkerson_and_edmond_karp_algo.cpp)
|
||||
* [Prim](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/prim.cpp)
|
||||
* [Topological Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/topological_sort.cpp)
|
||||
* [Topological Sort By Kahns Algo](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/topological_sort_by_kahns_algo.cpp)
|
||||
* [Travelling Salesman Problem](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graph/travelling_salesman_problem.cpp)
|
||||
|
||||
## Graphics
|
||||
* [Spirograph](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/graphics/spirograph.cpp)
|
||||
|
||||
## Greedy Algorithms
|
||||
* [Binary Addition](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/greedy_algorithms/binary_addition.cpp)
|
||||
* [Boruvkas Minimum Spanning Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/greedy_algorithms/boruvkas_minimum_spanning_tree.cpp)
|
||||
* [Digit Separation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/greedy_algorithms/digit_separation.cpp)
|
||||
* [Dijkstra Greedy](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/greedy_algorithms/dijkstra_greedy.cpp)
|
||||
* [Gale Shapley](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/greedy_algorithms/gale_shapley.cpp)
|
||||
* [Huffman](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/greedy_algorithms/huffman.cpp)
|
||||
* [Jump Game](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/greedy_algorithms/jump_game.cpp)
|
||||
* [Knapsack](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/greedy_algorithms/knapsack.cpp)
|
||||
* [Kruskals Minimum Spanning Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/greedy_algorithms/kruskals_minimum_spanning_tree.cpp)
|
||||
* [Prims Minimum Spanning Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/greedy_algorithms/prims_minimum_spanning_tree.cpp)
|
||||
|
||||
## Hashing
|
||||
* [Chaining](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/hashing/chaining.cpp)
|
||||
* [Double Hash Hash Table](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/hashing/double_hash_hash_table.cpp)
|
||||
* [Linear Probing Hash Table](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/hashing/linear_probing_hash_table.cpp)
|
||||
* [Md5](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/hashing/md5.cpp)
|
||||
* [Quadratic Probing Hash Table](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/hashing/quadratic_probing_hash_table.cpp)
|
||||
* [Sha1](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/hashing/sha1.cpp)
|
||||
* [Sha256](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/hashing/sha256.cpp)
|
||||
|
||||
## Machine Learning
|
||||
* [A Star Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/machine_learning/a_star_search.cpp)
|
||||
* [Adaline Learning](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/machine_learning/adaline_learning.cpp)
|
||||
* [K Nearest Neighbors](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/machine_learning/k_nearest_neighbors.cpp)
|
||||
* [Kohonen Som Topology](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/machine_learning/kohonen_som_topology.cpp)
|
||||
* [Kohonen Som Trace](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/machine_learning/kohonen_som_trace.cpp)
|
||||
* [Neural Network](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/machine_learning/neural_network.cpp)
|
||||
* [Ordinary Least Squares Regressor](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/machine_learning/ordinary_least_squares_regressor.cpp)
|
||||
* [Vector Ops](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/machine_learning/vector_ops.hpp)
|
||||
|
||||
## Math
|
||||
* [Aliquot Sum](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/aliquot_sum.cpp)
|
||||
* [Approximate Pi](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/approximate_pi.cpp)
|
||||
* [Area](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/area.cpp)
|
||||
* [Armstrong Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/armstrong_number.cpp)
|
||||
* [Binary Exponent](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/binary_exponent.cpp)
|
||||
* [Binomial Calculate](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/binomial_calculate.cpp)
|
||||
* [Check Amicable Pair](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/check_amicable_pair.cpp)
|
||||
* [Check Factorial](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/check_factorial.cpp)
|
||||
* [Check Prime](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/check_prime.cpp)
|
||||
* [Complex Numbers](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/complex_numbers.cpp)
|
||||
* [Double Factorial](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/double_factorial.cpp)
|
||||
* [Eratosthenes](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/eratosthenes.cpp)
|
||||
* [Eulers Totient Function](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/eulers_totient_function.cpp)
|
||||
* [Extended Euclid Algorithm](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/extended_euclid_algorithm.cpp)
|
||||
* [Factorial](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/factorial.cpp)
|
||||
* [Fast Power](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/fast_power.cpp)
|
||||
* [Fibonacci](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/fibonacci.cpp)
|
||||
* [Fibonacci Fast](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/fibonacci_fast.cpp)
|
||||
* [Fibonacci Large](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/fibonacci_large.cpp)
|
||||
* [Fibonacci Matrix Exponentiation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/fibonacci_matrix_exponentiation.cpp)
|
||||
* [Fibonacci Sum](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/fibonacci_sum.cpp)
|
||||
* [Finding Number Of Digits In A Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/finding_number_of_digits_in_a_number.cpp)
|
||||
* [Gcd Iterative Euclidean](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/gcd_iterative_euclidean.cpp)
|
||||
* [Gcd Of N Numbers](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/gcd_of_n_numbers.cpp)
|
||||
* [Gcd Recursive Euclidean](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/gcd_recursive_euclidean.cpp)
|
||||
* [Integral Approximation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/integral_approximation.cpp)
|
||||
* [Integral Approximation2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/integral_approximation2.cpp)
|
||||
* [Inv Sqrt](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/inv_sqrt.cpp)
|
||||
* [Iterative Factorial](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/iterative_factorial.cpp)
|
||||
* [Large Factorial](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/large_factorial.cpp)
|
||||
* [Large Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/large_number.h)
|
||||
* [Largest Power](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/largest_power.cpp)
|
||||
* [Lcm Sum](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/lcm_sum.cpp)
|
||||
* [Least Common Multiple](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/least_common_multiple.cpp)
|
||||
* [Linear Recurrence Matrix](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/linear_recurrence_matrix.cpp)
|
||||
* [Magic Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/magic_number.cpp)
|
||||
* [Miller Rabin](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/miller_rabin.cpp)
|
||||
* [Modular Division](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/modular_division.cpp)
|
||||
* [Modular Exponentiation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/modular_exponentiation.cpp)
|
||||
* [Modular Inverse Fermat Little Theorem](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/modular_inverse_fermat_little_theorem.cpp)
|
||||
* [Modular Inverse Simple](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/modular_inverse_simple.cpp)
|
||||
* [N Bonacci](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/n_bonacci.cpp)
|
||||
* [N Choose R](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/n_choose_r.cpp)
|
||||
* [Ncr Modulo P](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/ncr_modulo_p.cpp)
|
||||
* [Number Of Positive Divisors](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/number_of_positive_divisors.cpp)
|
||||
* [Perimeter](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/perimeter.cpp)
|
||||
* [Power For Huge Numbers](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/power_for_huge_numbers.cpp)
|
||||
* [Power Of Two](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/power_of_two.cpp)
|
||||
* [Prime Factorization](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/prime_factorization.cpp)
|
||||
* [Prime Numbers](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/prime_numbers.cpp)
|
||||
* [Primes Up To Billion](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/primes_up_to_billion.cpp)
|
||||
* [Quadratic Equations Complex Numbers](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/quadratic_equations_complex_numbers.cpp)
|
||||
* [Realtime Stats](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/realtime_stats.cpp)
|
||||
* [Sieve Of Eratosthenes](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/sieve_of_eratosthenes.cpp)
|
||||
* [Sqrt Double](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/sqrt_double.cpp)
|
||||
* [String Fibonacci](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/string_fibonacci.cpp)
|
||||
* [Sum Of Binomial Coefficient](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/sum_of_binomial_coefficient.cpp)
|
||||
* [Sum Of Digits](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/sum_of_digits.cpp)
|
||||
* [Vector Cross Product](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/vector_cross_product.cpp)
|
||||
* [Volume](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/math/volume.cpp)
|
||||
|
||||
## Numerical Methods
|
||||
* [Babylonian Method](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/babylonian_method.cpp)
|
||||
* [Bisection Method](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/bisection_method.cpp)
|
||||
* [Brent Method Extrema](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/brent_method_extrema.cpp)
|
||||
* [Composite Simpson Rule](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/composite_simpson_rule.cpp)
|
||||
* [Durand Kerner Roots](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/durand_kerner_roots.cpp)
|
||||
* [False Position](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/false_position.cpp)
|
||||
* [Fast Fourier Transform](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/fast_fourier_transform.cpp)
|
||||
* [Gaussian Elimination](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/gaussian_elimination.cpp)
|
||||
* [Golden Search Extrema](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/golden_search_extrema.cpp)
|
||||
* [Gram Schmidt](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/gram_schmidt.cpp)
|
||||
* [Inverse Fast Fourier Transform](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/inverse_fast_fourier_transform.cpp)
|
||||
* [Lu Decompose](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/lu_decompose.cpp)
|
||||
* [Lu Decomposition](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/lu_decomposition.h)
|
||||
* [Midpoint Integral Method](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/midpoint_integral_method.cpp)
|
||||
* [Newton Raphson Method](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/newton_raphson_method.cpp)
|
||||
* [Ode Forward Euler](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/ode_forward_euler.cpp)
|
||||
* [Ode Midpoint Euler](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/ode_midpoint_euler.cpp)
|
||||
* [Ode Semi Implicit Euler](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/ode_semi_implicit_euler.cpp)
|
||||
* [Qr Decompose](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/qr_decompose.h)
|
||||
* [Qr Decomposition](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/qr_decomposition.cpp)
|
||||
* [Qr Eigen Values](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/qr_eigen_values.cpp)
|
||||
* [Rungekutta](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/rungekutta.cpp)
|
||||
* [Successive Approximation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/numerical_methods/successive_approximation.cpp)
|
||||
|
||||
## Operations On Datastructures
|
||||
* [Array Left Rotation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/operations_on_datastructures/array_left_rotation.cpp)
|
||||
* [Array Right Rotation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/operations_on_datastructures/array_right_rotation.cpp)
|
||||
* [Circular Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/operations_on_datastructures/circular_linked_list.cpp)
|
||||
* [Circular Queue Using Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/operations_on_datastructures/circular_queue_using_array.cpp)
|
||||
* [Get Size Of Linked List](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/operations_on_datastructures/get_size_of_linked_list.cpp)
|
||||
* [Inorder Successor Of Bst](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/operations_on_datastructures/inorder_successor_of_bst.cpp)
|
||||
* [Intersection Of Two Arrays](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/operations_on_datastructures/intersection_of_two_arrays.cpp)
|
||||
* [Reverse A Linked List Using Recusion](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/operations_on_datastructures/reverse_a_linked_list_using_recusion.cpp)
|
||||
* [Reverse Binary Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/operations_on_datastructures/reverse_binary_tree.cpp)
|
||||
* [Selectionsortlinkedlist](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/operations_on_datastructures/selectionsortlinkedlist.cpp)
|
||||
* [Trie Multiple Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/operations_on_datastructures/trie_multiple_search.cpp)
|
||||
* [Union Of Two Arrays](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/operations_on_datastructures/union_of_two_arrays.cpp)
|
||||
|
||||
## Others
|
||||
* [Buzz Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/buzz_number.cpp)
|
||||
* [Decimal To Binary](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/decimal_to_binary.cpp)
|
||||
* [Decimal To Hexadecimal](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/decimal_to_hexadecimal.cpp)
|
||||
* [Decimal To Roman Numeral](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/decimal_to_roman_numeral.cpp)
|
||||
* [Easter](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/easter.cpp)
|
||||
* [Fast Integer Input](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/fast_integer_input.cpp)
|
||||
* [Happy Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/happy_number.cpp)
|
||||
* [Iterative Tree Traversals](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/iterative_tree_traversals.cpp)
|
||||
* [Kadanes3](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/kadanes3.cpp)
|
||||
* [Kelvin To Celsius](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/kelvin_to_celsius.cpp)
|
||||
* [Lfu Cache](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/lfu_cache.cpp)
|
||||
* [Longest Substring Without Repeating Characters](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/longest_substring_without_repeating_characters.cpp)
|
||||
* [Lru Cache](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/lru_cache.cpp)
|
||||
* [Lru Cache2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/lru_cache2.cpp)
|
||||
* [Matrix Exponentiation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/matrix_exponentiation.cpp)
|
||||
* [Palindrome Of Number](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/palindrome_of_number.cpp)
|
||||
* [Paranthesis Matching](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/paranthesis_matching.cpp)
|
||||
* [Pascal Triangle](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/pascal_triangle.cpp)
|
||||
* [Postfix Evaluation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/postfix_evaluation.cpp)
|
||||
* [Primality Test](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/primality_test.cpp)
|
||||
* [Recursive Tree Traversal](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/recursive_tree_traversal.cpp)
|
||||
* [Smallest Circle](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/smallest_circle.cpp)
|
||||
* [Sparse Matrix](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/sparse_matrix.cpp)
|
||||
* [Spiral Print](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/spiral_print.cpp)
|
||||
* [Stairs Pattern](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/stairs_pattern.cpp)
|
||||
* [Tower Of Hanoi](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/tower_of_hanoi.cpp)
|
||||
* [Vector Important Functions](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/others/vector_important_functions.cpp)
|
||||
|
||||
## Physics
|
||||
* [Ground To Ground Projectile Motion](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/physics/ground_to_ground_projectile_motion.cpp)
|
||||
|
||||
## Probability
|
||||
* [Addition Rule](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/probability/addition_rule.cpp)
|
||||
* [Bayes Theorem](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/probability/bayes_theorem.cpp)
|
||||
* [Binomial Dist](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/probability/binomial_dist.cpp)
|
||||
* [Exponential Dist](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/probability/exponential_dist.cpp)
|
||||
* [Geometric Dist](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/probability/geometric_dist.cpp)
|
||||
* [Poisson Dist](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/probability/poisson_dist.cpp)
|
||||
* [Windowed Median](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/probability/windowed_median.cpp)
|
||||
|
||||
## Range Queries
|
||||
* [Fenwick Tree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/range_queries/fenwick_tree.cpp)
|
||||
* [Heavy Light Decomposition](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/range_queries/heavy_light_decomposition.cpp)
|
||||
* [Mo](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/range_queries/mo.cpp)
|
||||
* [Persistent Seg Tree Lazy Prop](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/range_queries/persistent_seg_tree_lazy_prop.cpp)
|
||||
* [Prefix Sum Array](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/range_queries/prefix_sum_array.cpp)
|
||||
* [Segtree](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/range_queries/segtree.cpp)
|
||||
* [Sparse Table Range Queries](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/range_queries/sparse_table_range_queries.cpp)
|
||||
|
||||
## Search
|
||||
* [Binary Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/search/binary_search.cpp)
|
||||
* [Exponential Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/search/exponential_search.cpp)
|
||||
* [Fibonacci Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/search/fibonacci_search.cpp)
|
||||
* [Floyd Cycle Detection Algo](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/search/floyd_cycle_detection_algo.cpp)
|
||||
* [Hash Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/search/hash_search.cpp)
|
||||
* [Interpolation Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/search/interpolation_search.cpp)
|
||||
* [Interpolation Search2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/search/interpolation_search2.cpp)
|
||||
* [Jump Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/search/jump_search.cpp)
|
||||
* [Linear Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/search/linear_search.cpp)
|
||||
* [Longest Increasing Subsequence Using Binary Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/search/longest_increasing_subsequence_using_binary_search.cpp)
|
||||
* [Median Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/search/median_search.cpp)
|
||||
* [Median Search2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/search/median_search2.cpp)
|
||||
* [Saddleback Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/search/saddleback_search.cpp)
|
||||
* [Sublist Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/search/sublist_search.cpp)
|
||||
* [Ternary Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/search/ternary_search.cpp)
|
||||
* [Text Search](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/search/text_search.cpp)
|
||||
|
||||
## Sorting
|
||||
* [Bead Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/bead_sort.cpp)
|
||||
* [Binary Insertion Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/binary_insertion_sort.cpp)
|
||||
* [Bitonic Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/bitonic_sort.cpp)
|
||||
* [Bogo Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/bogo_sort.cpp)
|
||||
* [Bubble Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/bubble_sort.cpp)
|
||||
* [Bucket Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/bucket_sort.cpp)
|
||||
* [Cocktail Selection Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/cocktail_selection_sort.cpp)
|
||||
* [Comb Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/comb_sort.cpp)
|
||||
* [Count Inversions](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/count_inversions.cpp)
|
||||
* [Counting Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/counting_sort.cpp)
|
||||
* [Counting Sort String](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/counting_sort_string.cpp)
|
||||
* [Cycle Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/cycle_sort.cpp)
|
||||
* [Dnf Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/dnf_sort.cpp)
|
||||
* [Gnome Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/gnome_sort.cpp)
|
||||
* [Heap Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/heap_sort.cpp)
|
||||
* [Insertion Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/insertion_sort.cpp)
|
||||
* [Insertion Sort Recursive](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/insertion_sort_recursive.cpp)
|
||||
* [Library Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/library_sort.cpp)
|
||||
* [Merge Insertion Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/merge_insertion_sort.cpp)
|
||||
* [Merge Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/merge_sort.cpp)
|
||||
* [Non Recursive Merge Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/non_recursive_merge_sort.cpp)
|
||||
* [Numeric String Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/numeric_string_sort.cpp)
|
||||
* [Odd Even Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/odd_even_sort.cpp)
|
||||
* [Pancake Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/pancake_sort.cpp)
|
||||
* [Pigeonhole Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/pigeonhole_sort.cpp)
|
||||
* [Quick Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/quick_sort.cpp)
|
||||
* [Quick Sort 3](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/quick_sort_3.cpp)
|
||||
* [Quick Sort Iterative](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/quick_sort_iterative.cpp)
|
||||
* [Radix Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/radix_sort.cpp)
|
||||
* [Radix Sort2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/radix_sort2.cpp)
|
||||
* [Random Pivot Quick Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/random_pivot_quick_sort.cpp)
|
||||
* [Recursive Bubble Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/recursive_bubble_sort.cpp)
|
||||
* [Selection Sort Iterative](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/selection_sort_iterative.cpp)
|
||||
* [Selection Sort Recursive](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/selection_sort_recursive.cpp)
|
||||
* [Shell Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/shell_sort.cpp)
|
||||
* [Shell Sort2](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/shell_sort2.cpp)
|
||||
* [Slow Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/slow_sort.cpp)
|
||||
* [Stooge Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/stooge_sort.cpp)
|
||||
* [Strand Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/strand_sort.cpp)
|
||||
* [Swap Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/swap_sort.cpp)
|
||||
* [Tim Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/tim_sort.cpp)
|
||||
* [Wave Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/wave_sort.cpp)
|
||||
* [Wiggle Sort](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/sorting/wiggle_sort.cpp)
|
||||
|
||||
## Strings
|
||||
* [Boyer Moore](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/strings/boyer_moore.cpp)
|
||||
* [Brute Force String Searching](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/strings/brute_force_string_searching.cpp)
|
||||
* [Duval](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/strings/duval.cpp)
|
||||
* [Horspool](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/strings/horspool.cpp)
|
||||
* [Knuth Morris Pratt](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/strings/knuth_morris_pratt.cpp)
|
||||
* [Manacher Algorithm](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/strings/manacher_algorithm.cpp)
|
||||
* [Rabin Karp](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/strings/rabin_karp.cpp)
|
||||
* [Z Function](https://github.com/TheAlgorithms/C-Plus-Plus/blob/HEAD/strings/z_function.cpp)
|
||||
@@ -0,0 +1,20 @@
|
||||
The MIT License
|
||||
Copyright (c) 2016-2024 TheAlgorithms and contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,40 @@
|
||||
# The Algorithms - C++ # {#mainpage}
|
||||
|
||||
<!-- the suffix in the above line is required for doxygen to consider this as the index page of the generated documentation site -->
|
||||
|
||||
[](https://gitpod.io/#https://github.com/TheAlgorithms/C-Plus-Plus)
|
||||
[](https://github.com/TheAlgorithms/C-Plus-Plus/actions/workflows/codeql.yml)
|
||||
[](https://gitter.im/TheAlgorithms)
|
||||
[](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/CONTRIBUTING.md)
|
||||

|
||||
[](https://TheAlgorithms.github.io/C-Plus-Plus)
|
||||
[](https://github.com/TheAlgorithms/C-Plus-Plus/actions?query=workflow%3A%22Awesome+CI+Workflow%22)
|
||||
[](https://liberapay.com/TheAlgorithms)
|
||||
[](https://the-algorithms.com/discord/)
|
||||
[](https://liberapay.com/TheAlgorithms/donate)
|
||||
|
||||
## Overview
|
||||
|
||||
This repository is a collection of open-source implementation of a variety of algorithms implemented in C++ and licensed under [MIT License](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/LICENSE). These algorithms span a variety of topics from computer science, mathematics and statistics, data science, machine learning, engineering, etc.. The implementations and the associated documentation are meant to provide a learning resource for educators and students. Hence, one may find more than one implementation for the same objective but using a different algorithm strategies and optimizations.
|
||||
|
||||
## Features
|
||||
|
||||
- The repository provides implementations of various algorithms in one of the most fundamental general purpose languages - [C++](https://en.wikipedia.org/wiki/C%2B%2B).
|
||||
- Well documented source code with detailed explanations provide a valuable resource for educators and students alike.
|
||||
- Each source code is atomic using [STL classes](https://en.wikipedia.org/wiki/Standard_Template_Library) and _no external libraries_ are required for their compilation and execution. Thus, the fundamentals of the algorithms can be studied in much depth.
|
||||
- Source codes are [compiled and tested](https://github.com/TheAlgorithms/C-Plus-Plus/actions?query=workflow%3A%22Awesome+CI+Workflow%22) for every commit on the latest versions of three major operating systems viz., Windows, MacOS, and Ubuntu (Linux) using MSVC 19 2022, AppleClang 15.0.15, and GNU 13.3.0 respectively.
|
||||
- Strict adherence to [C++17](https://en.wikipedia.org/wiki/C%2B%2B17) standard ensures portability of code to embedded systems as well like [ESP32](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-guides/cplusplus.html#c-language-standard), [ARM Cortex](https://developer.arm.com/documentation/101458/2404/Standards-support/Supported-C-C---standards-in-Arm-C-C---Compiler), etc. with little to no changes.
|
||||
- Self-checks within programs ensure correct implementations with confidence.
|
||||
- Modular implementations and OpenSource licensing enable the functions to be utilized conveniently in other applications.
|
||||
|
||||
## Documentation
|
||||
|
||||
[Online Documentation](https://TheAlgorithms.github.io/C-Plus-Plus) is generated from the repository source codes directly. The documentation contains all resources including source code snippets, details on execution of the programs, diagrammatic representation of program flow, and links to external resources where necessary. The documentation also introduces interactive source code with links to documentation for C++ STL library functions used.
|
||||
Click on [Files menu](https://TheAlgorithms.github.io/C-Plus-Plus/files.html) to see the list of all the files documented with the code.
|
||||
|
||||
[Documentation of Algorithms in C++](https://thealgorithms.github.io/C-Plus-Plus) by [The Algorithms Contributors](https://github.com/TheAlgorithms/C-Plus-Plus/graphs/contributors) is licensed under [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1)<br/>
|
||||
<a href="https://creativecommons.org/licenses/by-sa/4.0"><img alt="Creative Commons License" style="height:22px!important;margin-left: 3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/cc.svg" /><img alt="Credit must be given to the creator" style="height:22px!important;margin-left: 3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/by.svg" /><img alt="Adaptations must be shared under the same terms" style="height:22px!important;margin-left: 3px;vertical-align:text-bottom;" src="https://mirrors.creativecommons.org/presskit/icons/sa.svg" /></a>
|
||||
|
||||
## Contributions
|
||||
|
||||
As a community developed and maintained repository, we welcome new un-plagiarized quality contributions. Please read our [Contribution Guidelines](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/CONTRIBUTING.md).
|
||||
@@ -0,0 +1,7 @@
|
||||
# WeHub 来源说明
|
||||
|
||||
- 原始项目:`TheAlgorithms/C-Plus-Plus`
|
||||
- 原始仓库:https://github.com/TheAlgorithms/C-Plus-Plus
|
||||
- 导入方式:上游默认分支的最新快照
|
||||
- 原作者、版权和许可证信息以原始仓库及本仓库 LICENSE 为准
|
||||
- 本文件仅用于记录来源,不代表 WeHub 是原项目作者
|
||||
@@ -0,0 +1,13 @@
|
||||
# Guidelines for reviewers and maintainers
|
||||
|
||||
Following are some guidelines for contributors who are providing reviews to the pull-requests.
|
||||
|
||||
1. On any given pull-request, there only one reviewer should be active at a time. Once the reviewer is done, others may add short comments or any further reviews as needed. Again, one at a time.
|
||||
2. Assigning reviewers should be avoided unless the pull-request is for a particular task the reviewer is more proficient in.
|
||||
3. Any contributor who has had their code merged into the repo can provide with reviews as they have gone through the repo standards at least once before. The reviewer will be on a first-come-first serve basis.
|
||||
4. Most repositories have a check-list in the description for pull-requests. Many times, the contributors are not following them and simply remove the checklist or checkthem without taking the time to review the checklist items. These contributors are almost always copying the code from somewhere. These should be pointed out politely and reviews should be blocked until the contributor updates the basic code structure per the checklist and the repo standards.
|
||||
5. The reviewers should label every pull-request appropriately - including "invalid" as the case may be.
|
||||
6. Some pull-requests have existing duplicate code or duplicate pull-requests or sometimes, a novice might create a new pull-request for every new commit. This is a daunting task but one of the responsibility of a reviewer.
|
||||
7. Discourage creating branches on the repo but rather fork the repo to the respective userspace and contribute from that fork.
|
||||
8. Some repos - C & C++ - have collaboration with GitPod wherein the code and the contribution can be executed and tested online with relative simplicity. It also contains tools necessary to perform debug and CI checks without installing any tools. Encourage contributors to utilize the feature. Reviewers can test the contributed algorithms online without worrying about forks and branches.
|
||||
9. There should not be any hurry to merge pull-requests. Since the repos are educational, better to get the contributions right even if it takes a bit longer to review. Encourage patience and develop debugging skills of contributors.
|
||||
@@ -0,0 +1,18 @@
|
||||
# If necessary, use the RELATIVE flag, otherwise each source file may be listed
|
||||
# with full pathname. RELATIVE may makes it easier to extract an executable name
|
||||
# automatically.
|
||||
file( GLOB APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp )
|
||||
# file( GLOB APP_SOURCES ${CMAKE_SOURCE_DIR}/*.c )
|
||||
# AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} APP_SOURCES)
|
||||
foreach( testsourcefile ${APP_SOURCES} )
|
||||
# I used a simple string replace, to cut off .cpp.
|
||||
string( REPLACE ".cpp" "" testname ${testsourcefile} )
|
||||
add_executable( ${testname} ${testsourcefile} )
|
||||
|
||||
set_target_properties(${testname} PROPERTIES LINKER_LANGUAGE CXX)
|
||||
if(OpenMP_CXX_FOUND)
|
||||
target_link_libraries(${testname} OpenMP::OpenMP_CXX)
|
||||
endif()
|
||||
install(TARGETS ${testname} DESTINATION "bin/backtracking")
|
||||
|
||||
endforeach( testsourcefile ${APP_SOURCES} )
|
||||
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Well-formed [Generated
|
||||
* Parentheses](https://leetcode.com/explore/interview/card/top-interview-questions-medium/109/backtracking/794/) with all combinations.
|
||||
*
|
||||
* @details a sequence of parentheses is well-formed if each opening parentheses
|
||||
* has a corresponding closing parenthesis
|
||||
* and the closing parentheses are correctly ordered
|
||||
*
|
||||
* @author [Giuseppe Coco](https://github.com/WoWS17)
|
||||
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for I/O operation
|
||||
#include <vector> /// for vector container
|
||||
|
||||
/**
|
||||
* @brief Backtracking algorithms
|
||||
* @namespace backtracking
|
||||
*/
|
||||
namespace backtracking {
|
||||
/**
|
||||
* @brief generate_parentheses class
|
||||
*/
|
||||
class generate_parentheses {
|
||||
private:
|
||||
std::vector<std::string> res; ///< Contains all possible valid patterns
|
||||
|
||||
void makeStrings(std::string str, int n, int closed, int open);
|
||||
|
||||
public:
|
||||
std::vector<std::string> generate(int n);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief function that adds parenthesis to the string.
|
||||
*
|
||||
* @param str string build during backtracking
|
||||
* @param n number of pairs of parentheses
|
||||
* @param closed number of closed parentheses
|
||||
* @param open number of open parentheses
|
||||
*/
|
||||
|
||||
void generate_parentheses::makeStrings(std::string str, int n,
|
||||
int closed, int open) {
|
||||
if (closed > open) // We can never have more closed than open
|
||||
return;
|
||||
|
||||
if ((str.length() == 2 * n) &&
|
||||
(closed != open)) { // closed and open must be the same
|
||||
return;
|
||||
}
|
||||
|
||||
if (str.length() == 2 * n) {
|
||||
res.push_back(str);
|
||||
return;
|
||||
}
|
||||
|
||||
makeStrings(str + ')', n, closed + 1, open);
|
||||
makeStrings(str + '(', n, closed, open + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief wrapper interface
|
||||
*
|
||||
* @param n number of pairs of parentheses
|
||||
* @return all well-formed pattern of parentheses
|
||||
*/
|
||||
std::vector<std::string> generate_parentheses::generate(int n) {
|
||||
backtracking::generate_parentheses::res.clear();
|
||||
std::string str = "(";
|
||||
generate_parentheses::makeStrings(str, n, 0, 1);
|
||||
return res;
|
||||
}
|
||||
} // namespace backtracking
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
int n = 0;
|
||||
std::vector<std::string> patterns;
|
||||
backtracking::generate_parentheses p;
|
||||
|
||||
n = 1;
|
||||
patterns = {{"()"}};
|
||||
assert(p.generate(n) == patterns);
|
||||
|
||||
n = 3;
|
||||
patterns = {{"()()()"}, {"()(())"}, {"(())()"}, {"(()())"}, {"((()))"}};
|
||||
|
||||
assert(p.generate(n) == patterns);
|
||||
|
||||
n = 4;
|
||||
patterns = {{"()()()()"}, {"()()(())"}, {"()(())()"}, {"()(()())"},
|
||||
{"()((()))"}, {"(())()()"}, {"(())(())"}, {"(()())()"},
|
||||
{"(()()())"}, {"(()(()))"}, {"((()))()"}, {"((())())"},
|
||||
{"((()()))"}, {"(((())))"}};
|
||||
assert(p.generate(n) == patterns);
|
||||
|
||||
std::cout << "All tests passed\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief prints the assigned colors
|
||||
* using [Graph Coloring](https://en.wikipedia.org/wiki/Graph_coloring)
|
||||
* algorithm
|
||||
*
|
||||
* @details
|
||||
* In graph theory, graph coloring is a special case of graph labeling;
|
||||
* it is an assignment of labels traditionally called "colors" to elements of a
|
||||
* graph subject to certain constraints. In its simplest form, it is a way of
|
||||
* coloring the vertices of a graph such that no two adjacent vertices are of
|
||||
* the same color; this is called a vertex coloring. Similarly, an edge coloring
|
||||
* assigns a color to each edge so that no two adjacent edges are of the same
|
||||
* color, and a face coloring of a planar graph assigns a color to each face or
|
||||
* region so that no two faces that share a boundary have the same color.
|
||||
*
|
||||
* @author [Anup Kumar Panwar](https://github.com/AnupKumarPanwar)
|
||||
* @author [David Leal](https://github.com/Panquesito7)
|
||||
*/
|
||||
|
||||
#include <array> /// for std::array
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/**
|
||||
* @namespace backtracking
|
||||
* @brief Backtracking algorithms
|
||||
*/
|
||||
namespace backtracking {
|
||||
/**
|
||||
* @namespace graph_coloring
|
||||
* @brief Functions for the [Graph
|
||||
* Coloring](https://en.wikipedia.org/wiki/Graph_coloring) algorithm,
|
||||
*/
|
||||
namespace graph_coloring {
|
||||
/**
|
||||
* @brief A utility function to print the solution
|
||||
* @tparam V number of vertices in the graph
|
||||
* @param color array of colors assigned to the nodes
|
||||
*/
|
||||
template <size_t V>
|
||||
void printSolution(const std::array<int, V>& color) {
|
||||
std::cout << "Following are the assigned colors\n";
|
||||
for (auto& col : color) {
|
||||
std::cout << col;
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility function to check if the current color assignment is safe for
|
||||
* vertex v
|
||||
* @tparam V number of vertices in the graph
|
||||
* @param v index of graph vertex to check
|
||||
* @param graph matrix of graph nonnectivity
|
||||
* @param color vector of colors assigned to the graph nodes/vertices
|
||||
* @param c color value to check for the node `v`
|
||||
* @returns `true` if the color is safe to be assigned to the node
|
||||
* @returns `false` if the color is not safe to be assigned to the node
|
||||
*/
|
||||
template <size_t V>
|
||||
bool isSafe(int v, const std::array<std::array<int, V>, V>& graph,
|
||||
const std::array<int, V>& color, int c) {
|
||||
for (int i = 0; i < V; i++) {
|
||||
if (graph[v][i] && c == color[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Recursive utility function to solve m coloring problem
|
||||
* @tparam V number of vertices in the graph
|
||||
* @param graph matrix of graph nonnectivity
|
||||
* @param m number of colors
|
||||
* @param [in,out] color description // used in,out to notify in documentation
|
||||
* that this parameter gets modified by the function
|
||||
* @param v index of graph vertex to check
|
||||
*/
|
||||
template <size_t V>
|
||||
void graphColoring(const std::array<std::array<int, V>, V>& graph, int m,
|
||||
std::array<int, V> color, int v) {
|
||||
// base case:
|
||||
// If all vertices are assigned a color then return true
|
||||
if (v == V) {
|
||||
printSolution<V>(color);
|
||||
return;
|
||||
}
|
||||
|
||||
// Consider this vertex v and try different colors
|
||||
for (int c = 1; c <= m; c++) {
|
||||
// Check if assignment of color c to v is fine
|
||||
if (isSafe<V>(v, graph, color, c)) {
|
||||
color[v] = c;
|
||||
|
||||
// recur to assign colors to rest of the vertices
|
||||
graphColoring<V>(graph, m, color, v + 1);
|
||||
|
||||
// If assigning color c doesn't lead to a solution then remove it
|
||||
color[v] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace graph_coloring
|
||||
} // namespace backtracking
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
// Create following graph and test whether it is 3 colorable
|
||||
// (3)---(2)
|
||||
// | / |
|
||||
// | / |
|
||||
// | / |
|
||||
// (0)---(1)
|
||||
|
||||
const int V = 4; // number of vertices in the graph
|
||||
std::array<std::array<int, V>, V> graph = {
|
||||
std::array<int, V>({0, 1, 1, 1}), std::array<int, V>({1, 0, 1, 0}),
|
||||
std::array<int, V>({1, 1, 0, 1}), std::array<int, V>({1, 0, 1, 0})};
|
||||
|
||||
int m = 3; // Number of colors
|
||||
std::array<int, V> color{};
|
||||
|
||||
backtracking::graph_coloring::graphColoring<V>(graph, m, color, 0);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Knight's tour](https://en.wikipedia.org/wiki/Knight%27s_tour)
|
||||
* algorithm
|
||||
*
|
||||
* @details
|
||||
* A knight's tour is a sequence of moves of a knight on a chessboard
|
||||
* such that the knight visits every square only once. If the knight
|
||||
* ends on a square that is one knight's move from the beginning
|
||||
* square (so that it could tour the board again immediately, following
|
||||
* the same path, the tour is closed; otherwise, it is open.
|
||||
*
|
||||
* @author [Nikhil Arora](https://github.com/nikhilarora068)
|
||||
* @author [David Leal](https://github.com/Panquesito7)
|
||||
*/
|
||||
#include <array> /// for std::array
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/**
|
||||
* @namespace backtracking
|
||||
* @brief Backtracking algorithms
|
||||
*/
|
||||
namespace backtracking {
|
||||
/**
|
||||
* @namespace knight_tour
|
||||
* @brief Functions for the [Knight's
|
||||
* tour](https://en.wikipedia.org/wiki/Knight%27s_tour) algorithm
|
||||
*/
|
||||
namespace knight_tour {
|
||||
/**
|
||||
* A utility function to check if i,j are valid indexes for N*N chessboard
|
||||
* @tparam V number of vertices in array
|
||||
* @param x current index in rows
|
||||
* @param y current index in columns
|
||||
* @param sol matrix where numbers are saved
|
||||
* @returns `true` if ....
|
||||
* @returns `false` if ....
|
||||
*/
|
||||
template <size_t V>
|
||||
bool issafe(int x, int y, const std::array<std::array<int, V>, V> &sol) {
|
||||
return (x < V && x >= 0 && y < V && y >= 0 && sol[x][y] == -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Knight's tour algorithm
|
||||
* @tparam V number of vertices in array
|
||||
* @param x current index in rows
|
||||
* @param y current index in columns
|
||||
* @param mov movement to be done
|
||||
* @param sol matrix where numbers are saved
|
||||
* @param xmov next move of knight (x coordinate)
|
||||
* @param ymov next move of knight (y coordinate)
|
||||
* @returns `true` if solution exists
|
||||
* @returns `false` if solution does not exist
|
||||
*/
|
||||
template <size_t V>
|
||||
bool solve(int x, int y, int mov, std::array<std::array<int, V>, V> &sol,
|
||||
const std::array<int, V> &xmov, std::array<int, V> &ymov) {
|
||||
int k = 0, xnext = 0, ynext = 0;
|
||||
|
||||
if (mov == V * V) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (k = 0; k < V; k++) {
|
||||
xnext = x + xmov[k];
|
||||
ynext = y + ymov[k];
|
||||
|
||||
if (issafe<V>(xnext, ynext, sol)) {
|
||||
sol[xnext][ynext] = mov;
|
||||
|
||||
if (solve<V>(xnext, ynext, mov + 1, sol, xmov, ymov) == true) {
|
||||
return true;
|
||||
} else {
|
||||
sol[xnext][ynext] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace knight_tour
|
||||
} // namespace backtracking
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
const int n = 8;
|
||||
std::array<std::array<int, n>, n> sol = {0};
|
||||
|
||||
int i = 0, j = 0;
|
||||
for (i = 0; i < n; i++) {
|
||||
for (j = 0; j < n; j++) {
|
||||
sol[i][j] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
std::array<int, n> xmov = {2, 1, -1, -2, -2, -1, 1, 2};
|
||||
std::array<int, n> ymov = {1, 2, 2, 1, -1, -2, -2, -1};
|
||||
|
||||
sol[0][0] = 0;
|
||||
|
||||
bool flag = backtracking::knight_tour::solve<n>(0, 0, 1, sol, xmov, ymov);
|
||||
if (flag == false) {
|
||||
std::cout << "Error: Solution does not exist\n";
|
||||
} else {
|
||||
for (i = 0; i < n; i++) {
|
||||
for (j = 0; j < n; j++) {
|
||||
std::cout << sol[i][j] << " ";
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* @brief [Magic sequence](https://www.csplib.org/Problems/prob019/)
|
||||
* implementation
|
||||
*
|
||||
* @details Solve the magic sequence problem with backtracking
|
||||
*
|
||||
* "A magic sequence of length $n$ is a sequence of integers $x_0
|
||||
* \ldots x_{n-1}$ between $0$ and $n-1$, such that for all $i$
|
||||
* in $0$ to $n-1$, the number $i$ occurs exactly $x_i$ times in
|
||||
* the sequence. For instance, $6,2,1,0,0,0,1,0,0,0$ is a magic
|
||||
* sequence since $0$ occurs $6$ times in it, $1$ occurs twice, etc."
|
||||
* Quote taken from the [CSPLib](https://www.csplib.org/Problems/prob019/)
|
||||
* website
|
||||
*
|
||||
* @author [Jxtopher](https://github.com/Jxtopher)
|
||||
*/
|
||||
|
||||
#include <algorithm> /// for std::count
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
#include <list> /// for std::list
|
||||
#include <numeric> /// for std::accumulate
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace backtracking
|
||||
* @brief Backtracking algorithms
|
||||
*/
|
||||
namespace backtracking {
|
||||
/**
|
||||
* @namespace magic_sequence
|
||||
* @brief Functions for the [Magic
|
||||
* sequence](https://www.csplib.org/Problems/prob019/) implementation
|
||||
*/
|
||||
namespace magic_sequence {
|
||||
using sequence_t =
|
||||
std::vector<unsigned int>; ///< Definition of the sequence type
|
||||
/**
|
||||
* @brief Print the magic sequence
|
||||
* @param s working memory for the sequence
|
||||
*/
|
||||
void print(const sequence_t& s) {
|
||||
for (const auto& item : s) std::cout << item << " ";
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if the sequence is magic
|
||||
* @param s working memory for the sequence
|
||||
* @returns true if it's a magic sequence
|
||||
* @returns false if it's NOT a magic sequence
|
||||
*/
|
||||
bool is_magic(const sequence_t& s) {
|
||||
for (unsigned int i = 0; i < s.size(); i++) {
|
||||
if (std::count(s.cbegin(), s.cend(), i) != s[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sub-solutions filtering
|
||||
* @param s working memory for the sequence
|
||||
* @param depth current depth in tree
|
||||
* @returns true if the sub-solution is valid
|
||||
* @returns false if the sub-solution is NOT valid
|
||||
*/
|
||||
bool filtering(const sequence_t& s, unsigned int depth) {
|
||||
return std::accumulate(s.cbegin(), s.cbegin() + depth,
|
||||
static_cast<unsigned int>(0)) <= s.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Solve the Magic Sequence problem
|
||||
* @param s working memory for the sequence
|
||||
* @param ret list of the valid magic sequences
|
||||
* @param depth current depth in the tree
|
||||
*/
|
||||
void solve(sequence_t* s, std::list<sequence_t>* ret, unsigned int depth = 0) {
|
||||
if (depth == s->size()) {
|
||||
if (is_magic(*s)) {
|
||||
ret->push_back(*s);
|
||||
}
|
||||
} else {
|
||||
for (unsigned int i = 0; i < s->size(); i++) {
|
||||
(*s)[depth] = i;
|
||||
if (filtering(*s, depth + 1)) {
|
||||
solve(s, ret, depth + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace magic_sequence
|
||||
} // namespace backtracking
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// test a valid magic sequence
|
||||
backtracking::magic_sequence::sequence_t s_magic = {6, 2, 1, 0, 0,
|
||||
0, 1, 0, 0, 0};
|
||||
assert(backtracking::magic_sequence::is_magic(s_magic));
|
||||
|
||||
// test a non-valid magic sequence
|
||||
backtracking::magic_sequence::sequence_t s_not_magic = {5, 2, 1, 0, 0,
|
||||
0, 1, 0, 0, 0};
|
||||
assert(!backtracking::magic_sequence::is_magic(s_not_magic));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
|
||||
// solve magic sequences of size 2 to 11 and print the solutions
|
||||
for (unsigned int i = 2; i < 12; i++) {
|
||||
std::cout << "Solution for n = " << i << std::endl;
|
||||
// valid magic sequence list
|
||||
std::list<backtracking::magic_sequence::sequence_t> list_of_solutions;
|
||||
// initialization of a sequence
|
||||
backtracking::magic_sequence::sequence_t s1(i, i);
|
||||
// launch of solving the problem
|
||||
backtracking::magic_sequence::solve(&s1, &list_of_solutions);
|
||||
// print solutions
|
||||
for (const auto& item : list_of_solutions) {
|
||||
backtracking::magic_sequence::print(item);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief returns which is the longest/shortest number
|
||||
* using [minimax](https://en.wikipedia.org/wiki/Minimax) algorithm
|
||||
*
|
||||
* @details
|
||||
* Minimax (sometimes MinMax, MM or saddle point) is a decision rule used in
|
||||
* artificial intelligence, decision theory, game theory, statistics,
|
||||
* and philosophy for minimizing the possible loss for a worst case (maximum
|
||||
* loss) scenario. When dealing with gains, it is referred to as "maximin"—to
|
||||
* maximize the minimum gain. Originally formulated for two-player zero-sum game
|
||||
* theory, covering both the cases where players take alternate moves and those
|
||||
* where they make simultaneous moves, it has also been extended to more complex
|
||||
* games and to general decision-making in the presence of uncertainty.
|
||||
*
|
||||
* @author [Gleison Batista](https://github.com/gleisonbs)
|
||||
* @author [David Leal](https://github.com/Panquesito7)
|
||||
*/
|
||||
#include <algorithm> /// for std::max, std::min
|
||||
#include <array> /// for std::array
|
||||
#include <cmath> /// for log2
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/**
|
||||
* @namespace backtracking
|
||||
* @brief Backtracking algorithms
|
||||
*/
|
||||
namespace backtracking {
|
||||
/**
|
||||
* @brief Check which is the maximum/minimum number in the array
|
||||
* @param depth current depth in game tree
|
||||
* @param node_index current index in array
|
||||
* @param is_max if current index is the longest number
|
||||
* @param scores saved numbers in array
|
||||
* @param height maximum height for game tree
|
||||
* @returns the maximum or minimum number
|
||||
*/
|
||||
template <size_t T>
|
||||
int minimax(int depth, int node_index, bool is_max,
|
||||
const std::array<int, T> &scores, double height) {
|
||||
if (depth == height) {
|
||||
return scores[node_index];
|
||||
}
|
||||
|
||||
int v1 = minimax(depth + 1, node_index * 2, !is_max, scores, height);
|
||||
int v2 = minimax(depth + 1, node_index * 2 + 1, !is_max, scores, height);
|
||||
|
||||
return is_max ? std::max(v1, v2) : std::min(v1, v2);
|
||||
}
|
||||
} // namespace backtracking
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
std::array<int, 8> scores = {90, 23, 6, 33, 21, 65, 123, 34423};
|
||||
double height = log2(scores.size());
|
||||
|
||||
std::cout << "Optimal value: "
|
||||
<< backtracking::minimax(0, 0, true, scores, height) << std::endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Eight Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle)
|
||||
* puzzle
|
||||
*
|
||||
* @details
|
||||
* The **eight queens puzzle** is the problem of placing eight chess queens on
|
||||
* an 8×8 chessboard so that no two queens threaten each other; thus, a solution
|
||||
* requires that no two queens share the same row, column, or diagonal. The
|
||||
* eight queens puzzle is an example of the more general **n queens problem** of
|
||||
* placing n non-attacking queens on an n×n chessboard, for which solutions
|
||||
* exist for all natural numbers n with the exception of n = 2 and n = 3.
|
||||
*
|
||||
* @author Unknown author
|
||||
* @author [David Leal](https://github.com/Panquesito7)
|
||||
*
|
||||
*/
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
|
||||
/**
|
||||
* @namespace backtracking
|
||||
* @brief Backtracking algorithms
|
||||
*/
|
||||
namespace backtracking {
|
||||
/**
|
||||
* @namespace n_queens
|
||||
* @brief Functions for [Eight
|
||||
* Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle) puzzle.
|
||||
*/
|
||||
namespace n_queens {
|
||||
/**
|
||||
* Utility function to print matrix
|
||||
* @tparam n number of matrix size
|
||||
* @param board matrix where numbers are saved
|
||||
*/
|
||||
template <size_t n>
|
||||
void printSolution(const std::array<std::array<int, n>, n> &board) {
|
||||
std::cout << "\n";
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
std::cout << "" << board[i][j] << " ";
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a queen can be placed on matrix
|
||||
* @tparam n number of matrix size
|
||||
* @param board matrix where numbers are saved
|
||||
* @param row current index in rows
|
||||
* @param col current index in columns
|
||||
* @returns `true` if queen can be placed on matrix
|
||||
* @returns `false` if queen can't be placed on matrix
|
||||
*/
|
||||
template <size_t n>
|
||||
bool isSafe(const std::array<std::array<int, n>, n> &board, const int &row,
|
||||
const int &col) {
|
||||
int i = 0, j = 0;
|
||||
|
||||
// Check this row on left side
|
||||
for (i = 0; i < col; i++) {
|
||||
if (board[row][i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check upper diagonal on left side
|
||||
for (i = row, j = col; i >= 0 && j >= 0; i--, j--) {
|
||||
if (board[i][j]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Check lower diagonal on left side
|
||||
for (i = row, j = col; j >= 0 && i < n; i++, j--) {
|
||||
if (board[i][j]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Solve n queens problem
|
||||
* @tparam n number of matrix size
|
||||
* @param board matrix where numbers are saved
|
||||
* @param col current index in columns
|
||||
*/
|
||||
template <size_t n>
|
||||
void solveNQ(std::array<std::array<int, n>, n> board, const int &col) {
|
||||
if (col >= n) {
|
||||
printSolution<n>(board);
|
||||
return;
|
||||
}
|
||||
|
||||
// Consider this column and try placing
|
||||
// this queen in all rows one by one
|
||||
for (int i = 0; i < n; i++) {
|
||||
// Check if queen can be placed
|
||||
// on board[i][col]
|
||||
if (isSafe<n>(board, i, col)) {
|
||||
// Place this queen in matrix
|
||||
board[i][col] = 1;
|
||||
|
||||
// Recursive to place rest of the queens
|
||||
solveNQ<n>(board, col + 1);
|
||||
|
||||
board[i][col] = 0; // backtrack
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace n_queens
|
||||
} // namespace backtracking
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
const int n = 4;
|
||||
std::array<std::array<int, n>, n> board = {
|
||||
std::array<int, n>({0, 0, 0, 0}), std::array<int, n>({0, 0, 0, 0}),
|
||||
std::array<int, n>({0, 0, 0, 0}), std::array<int, n>({0, 0, 0, 0})};
|
||||
|
||||
backtracking::n_queens::solveNQ<n>(board, 0);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [N queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle) all
|
||||
* optimized
|
||||
*
|
||||
* @author [Sombit Bose](https://github.com/deadshotsb)
|
||||
* @author [David Leal](https://github.com/Panquesito7)
|
||||
*/
|
||||
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
|
||||
/**
|
||||
* @namespace backtracking
|
||||
* @brief Backtracking algorithms
|
||||
*/
|
||||
namespace backtracking {
|
||||
/**
|
||||
* @namespace n_queens_optimized
|
||||
* @brief Functions for [Eight
|
||||
* Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle) puzzle optimized.
|
||||
*/
|
||||
namespace n_queens_optimized {
|
||||
/**
|
||||
* Utility function to print matrix
|
||||
* @tparam n number of matrix size
|
||||
* @param board matrix where numbers are saved
|
||||
*/
|
||||
template <size_t n>
|
||||
void PrintSol(const std::array<std::array<int, n>, n> &board) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
std::cout << board[i][j] << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
if (n % 2 == 0 || (n % 2 == 1 && board[n / 2 + 1][0] != 1)) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
std::cout << board[j][i] << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a queen can be placed on matrix
|
||||
* @tparam n number of matrix size
|
||||
* @param board matrix where numbers are saved
|
||||
* @param row current index in rows
|
||||
* @param col current index in columns
|
||||
* @returns `true` if queen can be placed on matrix
|
||||
* @returns `false` if queen can't be placed on matrix
|
||||
*/
|
||||
template <size_t n>
|
||||
bool CanIMove(const std::array<std::array<int, n>, n> &board, int row,
|
||||
int col) {
|
||||
/// check in the row
|
||||
for (int i = 0; i <= col; i++) {
|
||||
if (board[row][i] == 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// check the first diagonal
|
||||
for (int i = row, j = col; i >= 0 && j >= 0; i--, j--) {
|
||||
if (board[i][j] == 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// check the second diagonal
|
||||
for (int i = row, j = col; i <= n - 1 && j >= 0; i++, j--) {
|
||||
if (board[i][j] == 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Solve n queens problem
|
||||
* @tparam n number of matrix size
|
||||
* @param board matrix where numbers are saved
|
||||
* @param col current index in columns
|
||||
*/
|
||||
template <size_t n>
|
||||
void NQueenSol(std::array<std::array<int, n>, n> board, int col) {
|
||||
if (col >= n) {
|
||||
PrintSol<n>(board);
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (CanIMove<n>(board, i, col)) {
|
||||
board[i][col] = 1;
|
||||
NQueenSol<n>(board, col + 1);
|
||||
board[i][col] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace n_queens_optimized
|
||||
} // namespace backtracking
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
const int n = 4;
|
||||
std::array<std::array<int, n>, n> board{};
|
||||
|
||||
if (n % 2 == 0) {
|
||||
for (int i = 0; i <= n / 2 - 1; i++) {
|
||||
if (backtracking::n_queens_optimized::CanIMove(board, i, 0)) {
|
||||
board[i][0] = 1;
|
||||
backtracking::n_queens_optimized::NQueenSol(board, 1);
|
||||
board[i][0] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i <= n / 2; i++) {
|
||||
if (backtracking::n_queens_optimized::CanIMove(board, i, 0)) {
|
||||
board[i][0] = 1;
|
||||
backtracking::n_queens_optimized::NQueenSol(board, 1);
|
||||
board[i][0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Eight Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle)
|
||||
* puzzle, printing all solutions
|
||||
*
|
||||
* @author [Himani Negi](https://github.com/Himani2000)
|
||||
* @author [David Leal](https://github.com/Panquesito7)
|
||||
*
|
||||
*/
|
||||
#include <array> /// for std::array
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/**
|
||||
* @namespace backtracking
|
||||
* @brief Backtracking algorithms
|
||||
*/
|
||||
namespace backtracking {
|
||||
/**
|
||||
* @namespace n_queens_all_solutions
|
||||
* @brief Functions for the [Eight
|
||||
* Queens](https://en.wikipedia.org/wiki/Eight_queens_puzzle) puzzle with all
|
||||
* solutions.
|
||||
*/
|
||||
namespace n_queens_all_solutions {
|
||||
/**
|
||||
* @brief Utility function to print matrix
|
||||
* @tparam n number of matrix size
|
||||
* @param board matrix where numbers are saved
|
||||
*/
|
||||
template <size_t n>
|
||||
void PrintSol(const std::array<std::array<int, n>, n>& board) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
std::cout << board[i][j] << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if a queen can be placed on the matrix
|
||||
* @tparam n number of matrix size
|
||||
* @param board matrix where numbers are saved
|
||||
* @param row current index in rows
|
||||
* @param col current index in columns
|
||||
* @returns `true` if queen can be placed on matrix
|
||||
* @returns `false` if queen can't be placed on matrix
|
||||
*/
|
||||
template <size_t n>
|
||||
bool CanIMove(const std::array<std::array<int, n>, n>& board, int row,
|
||||
int col) {
|
||||
/// check in the row
|
||||
for (int i = 0; i < col; i++) {
|
||||
if (board[row][i] == 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// check the first diagonal
|
||||
for (int i = row, j = col; i >= 0 && j >= 0; i--, j--) {
|
||||
if (board[i][j] == 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// check the second diagonal
|
||||
for (int i = row, j = col; i <= n - 1 && j >= 0; i++, j--) {
|
||||
if (board[i][j] == 1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function to solve the N Queens problem
|
||||
* @tparam n number of matrix size
|
||||
* @param board matrix where numbers are saved
|
||||
* @param col current index in columns
|
||||
*/
|
||||
template <size_t n>
|
||||
void NQueenSol(std::array<std::array<int, n>, n> board, int col) {
|
||||
if (col >= n) {
|
||||
PrintSol(board);
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (CanIMove(board, i, col)) {
|
||||
board[i][col] = 1;
|
||||
NQueenSol(board, col + 1);
|
||||
board[i][col] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace n_queens_all_solutions
|
||||
} // namespace backtracking
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
const int n = 4;
|
||||
std::array<std::array<int, n>, n> board{0};
|
||||
|
||||
backtracking::n_queens_all_solutions::NQueenSol(board, 0);
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implements [Rat in a
|
||||
* Maze](https://www.codesdope.com/blog/article/backtracking-to-
|
||||
* solve-a-rat-in-a-maze-c-java-pytho/) algorithm
|
||||
*
|
||||
* @details
|
||||
* A Maze is given as N*N binary matrix of blocks where source block is the
|
||||
* upper left most block i.e., maze[0][0] and destination block is lower
|
||||
* rightmost block i.e., maze[N-1][N-1]. A rat starts from source and has to
|
||||
* reach destination. The rat can move only in two directions: forward and down.
|
||||
* In the maze matrix, 0 means the block is dead end and 1 means the block can
|
||||
* be used in the path from source to destination.
|
||||
*
|
||||
* @author [Vaibhav Thakkar](https://github.com/vaithak)
|
||||
* @author [David Leal](https://github.com/Panquesito7)
|
||||
*/
|
||||
|
||||
#include <array> /// for std::array
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/**
|
||||
* @namespace backtracking
|
||||
* @brief Backtracking algorithms
|
||||
*/
|
||||
namespace backtracking {
|
||||
/**
|
||||
* @namespace rat_maze
|
||||
* @brief Functions for [Rat in a
|
||||
* Maze](https://www.codesdope.com/blog/article/backtracking-to-
|
||||
* solve-a-rat-in-a-maze-c-java-pytho/) algorithm
|
||||
*/
|
||||
namespace rat_maze {
|
||||
/**
|
||||
* @brief Solve rat maze problem
|
||||
* @tparam size number of matrix size
|
||||
* @param currposrow current position in rows
|
||||
* @param currposcol current position in columns
|
||||
* @param maze matrix where numbers are saved
|
||||
* @param soln matrix to problem solution
|
||||
* @returns `true` if there exists a solution to move one step ahead in a column
|
||||
* or in a row
|
||||
* @returns `false` for the backtracking part
|
||||
*/
|
||||
template <size_t size>
|
||||
bool solveMaze(int currposrow, int currposcol,
|
||||
const std::array<std::array<int, size>, size> &maze,
|
||||
std::array<std::array<int, size>, size> soln) {
|
||||
if ((currposrow == size - 1) && (currposcol == size - 1)) {
|
||||
soln[currposrow][currposcol] = 1;
|
||||
for (int i = 0; i < size; ++i) {
|
||||
for (int j = 0; j < size; ++j) {
|
||||
std::cout << soln[i][j] << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
soln[currposrow][currposcol] = 1;
|
||||
|
||||
// if there exist a solution by moving one step ahead in a column
|
||||
if ((currposcol < size - 1) && maze[currposrow][currposcol + 1] == 1 &&
|
||||
solveMaze(currposrow, currposcol + 1, maze, soln)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// if there exists a solution by moving one step ahead in a row
|
||||
if ((currposrow < size - 1) && maze[currposrow + 1][currposcol] == 1 &&
|
||||
solveMaze(currposrow + 1, currposcol, maze, soln)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// the backtracking part
|
||||
soln[currposrow][currposcol] = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} // namespace rat_maze
|
||||
} // namespace backtracking
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
const int size = 4;
|
||||
std::array<std::array<int, size>, size> maze = {
|
||||
std::array<int, size>{1, 0, 1, 0}, std::array<int, size>{1, 0, 1, 1},
|
||||
std::array<int, size>{1, 0, 0, 1}, std::array<int, size>{1, 1, 1, 1}};
|
||||
|
||||
std::array<std::array<int, size>, size> soln{};
|
||||
|
||||
// Backtracking: setup matrix solution to zero
|
||||
for (int i = 0; i < size; ++i) {
|
||||
for (int j = 0; j < size; ++j) {
|
||||
soln[i][j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int currposrow = 0; // Current position in the rows
|
||||
int currposcol = 0; // Current position in the columns
|
||||
|
||||
assert(backtracking::rat_maze::solveMaze<size>(currposrow, currposcol, maze,
|
||||
soln) == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Subset-sum](https://en.wikipedia.org/wiki/Subset_sum_problem) (only
|
||||
* continuous subsets) problem
|
||||
* @details We are given an array and a sum value. The algorithms find all
|
||||
* the subarrays of that array with sum equal to the given sum and return such
|
||||
* subarrays count. This approach will have \f$O(n)\f$ time complexity and
|
||||
* \f$O(n)\f$ space complexity. NOTE: In this problem, we are only referring to
|
||||
* the continuous subsets as subarrays everywhere. Subarrays can be created
|
||||
* using deletion operation at the end of the front of an array only. The parent
|
||||
* array is also counted in subarrays having 0 number of deletion operations.
|
||||
*
|
||||
* @author [Swastika Gupta](https://github.com/Swastyy)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
#include <unordered_map> /// for unordered_map
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace backtracking
|
||||
* @brief Backtracking algorithms
|
||||
*/
|
||||
namespace backtracking {
|
||||
/**
|
||||
* @namespace subarray_sum
|
||||
* @brief Functions for the [Subset
|
||||
* sum](https://en.wikipedia.org/wiki/Subset_sum_problem) implementation
|
||||
*/
|
||||
namespace subarray_sum {
|
||||
/**
|
||||
* @brief The main function that implements the count of the subarrays
|
||||
* @param sum is the required sum of any subarrays
|
||||
* @param in_arr is the input array
|
||||
* @returns count of the number of subsets with required sum
|
||||
*/
|
||||
uint64_t subarray_sum(int64_t sum, const std::vector<int64_t> &in_arr) {
|
||||
int64_t nelement = in_arr.size();
|
||||
int64_t count_of_subset = 0;
|
||||
int64_t current_sum = 0;
|
||||
std::unordered_map<int64_t, int64_t>
|
||||
sumarray; // to store the subarrays count
|
||||
// frequency having some sum value
|
||||
|
||||
for (int64_t i = 0; i < nelement; i++) {
|
||||
current_sum += in_arr[i];
|
||||
|
||||
if (current_sum == sum) {
|
||||
count_of_subset++;
|
||||
}
|
||||
// If in case current_sum is greater than the required sum
|
||||
if (sumarray.find(current_sum - sum) != sumarray.end()) {
|
||||
count_of_subset += (sumarray[current_sum - sum]);
|
||||
}
|
||||
sumarray[current_sum]++;
|
||||
}
|
||||
return count_of_subset;
|
||||
}
|
||||
} // namespace subarray_sum
|
||||
} // namespace backtracking
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 1st test
|
||||
std::cout << "1st test ";
|
||||
std::vector<int64_t> array1 = {-7, -3, -2, 5, 8}; // input array
|
||||
assert(
|
||||
backtracking::subarray_sum::subarray_sum(0, array1) ==
|
||||
1); // first argument in subarray_sum function is the required sum and
|
||||
// second is the input array, answer is the subarray {(-3,-2,5)}
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 2nd test
|
||||
std::cout << "2nd test ";
|
||||
std::vector<int64_t> array2 = {1, 2, 3, 3};
|
||||
assert(backtracking::subarray_sum::subarray_sum(6, array2) ==
|
||||
2); // here we are expecting 2 subsets which sum up to 6 i.e.
|
||||
// {(1,2,3),(3,3)}
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 3rd test
|
||||
std::cout << "3rd test ";
|
||||
std::vector<int64_t> array3 = {1, 1, 1, 1};
|
||||
assert(backtracking::subarray_sum::subarray_sum(1, array3) ==
|
||||
4); // here we are expecting 4 subsets which sum up to 1 i.e.
|
||||
// {(1),(1),(1),(1)}
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 4rd test
|
||||
std::cout << "4th test ";
|
||||
std::vector<int64_t> array4 = {3, 3, 3, 3};
|
||||
assert(backtracking::subarray_sum::subarray_sum(6, array4) ==
|
||||
3); // here we are expecting 3 subsets which sum up to 6 i.e.
|
||||
// {(3,3),(3,3),(3,3)}
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 5th test
|
||||
std::cout << "5th test ";
|
||||
std::vector<int64_t> array5 = {};
|
||||
assert(backtracking::subarray_sum::subarray_sum(6, array5) ==
|
||||
0); // here we are expecting 0 subsets which sum up to 6 i.e. we
|
||||
// cannot select anything from an empty array
|
||||
std::cout << "passed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of the [Subset
|
||||
* Sum](https://en.wikipedia.org/wiki/Subset_sum_problem) problem.
|
||||
* @details
|
||||
* We are given an array and a sum value. The algorithm finds all
|
||||
* the subsets of that array with sum equal to the given sum and return such
|
||||
* subsets count. This approach will have exponential time complexity.
|
||||
* @author [Swastika Gupta](https://github.com/Swastyy)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace backtracking
|
||||
* @brief Backtracking algorithms
|
||||
*/
|
||||
namespace backtracking {
|
||||
/**
|
||||
* @namespace Subsets
|
||||
* @brief Functions for the [Subset
|
||||
* Sum](https://en.wikipedia.org/wiki/Subset_sum_problem) problem.
|
||||
*/
|
||||
namespace subset_sum {
|
||||
/**
|
||||
* @brief The main function implements count of subsets
|
||||
* @param sum is the required sum of any subset
|
||||
* @param in_arr is the input array
|
||||
* @returns count of the number of subsets with required sum
|
||||
*/
|
||||
uint64_t number_of_subsets(int32_t sum, const std::vector<int32_t> &in_arr) {
|
||||
int32_t nelement = in_arr.size();
|
||||
uint64_t count_of_subset = 0;
|
||||
|
||||
for (int32_t i = 0; i < (1 << (nelement)); i++) {
|
||||
int32_t check = 0;
|
||||
for (int32_t j = 0; j < nelement; j++) {
|
||||
if (i & (1 << j)) {
|
||||
check += (in_arr[j]);
|
||||
}
|
||||
}
|
||||
if (check == sum) {
|
||||
count_of_subset++;
|
||||
}
|
||||
}
|
||||
return count_of_subset;
|
||||
}
|
||||
} // namespace subset_sum
|
||||
} // namespace backtracking
|
||||
|
||||
/**
|
||||
* @brief Test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 1st test
|
||||
std::cout << "1st test ";
|
||||
std::vector<int32_t> array1 = {-7, -3, -2, 5, 8}; // input array
|
||||
assert(backtracking::subset_sum::number_of_subsets(0, array1) ==
|
||||
2); // first argument in subset_sum function is the required sum and
|
||||
// second is the input array
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 2nd test
|
||||
std::cout << "2nd test ";
|
||||
std::vector<int32_t> array2 = {1, 2, 3, 3};
|
||||
assert(backtracking::subset_sum::number_of_subsets(6, array2) ==
|
||||
3); // here we are expecting 3 subsets which sum up to 6 i.e.
|
||||
// {(1,2,3),(1,2,3),(3,3)}
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 3rd test
|
||||
std::cout << "3rd test ";
|
||||
std::vector<int32_t> array3 = {1, 1, 1, 1};
|
||||
assert(backtracking::subset_sum::number_of_subsets(1, array3) ==
|
||||
4); // here we are expecting 4 subsets which sum up to 1 i.e.
|
||||
// {(1),(1),(1),(1)}
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 4th test
|
||||
std::cout << "4th test ";
|
||||
std::vector<int32_t> array4 = {3, 3, 3, 3};
|
||||
assert(backtracking::subset_sum::number_of_subsets(6, array4) ==
|
||||
6); // here we are expecting 6 subsets which sum up to 6 i.e.
|
||||
// {(3,3),(3,3),(3,3),(3,3),(3,3),(3,3)}
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// Test 5
|
||||
std::cout << "5th test ";
|
||||
std::vector<int32_t> array5 = {};
|
||||
assert(backtracking::subset_sum::number_of_subsets(6, array5) ==
|
||||
0); // here we are expecting 0 subsets which sum up to 6 i.e. we
|
||||
// cannot select anything from an empty array
|
||||
std::cout << "passed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Sudoku Solver](https://en.wikipedia.org/wiki/Sudoku) algorithm.
|
||||
*
|
||||
* @details
|
||||
* Sudoku (数独, sūdoku, digit-single) (/suːˈdoʊkuː/, /-ˈdɒk-/, /sə-/,
|
||||
* originally called Number Place) is a logic-based, combinatorial
|
||||
* number-placement puzzle. In classic sudoku, the objective is to fill a 9×9
|
||||
* grid with digits so that each column, each row, and each of the nine 3×3
|
||||
* subgrids that compose the grid (also called "boxes", "blocks", or "regions")
|
||||
* contain all of the digits from 1 to 9. The puzzle setter provides a
|
||||
* partially completed grid, which for a well-posed puzzle has a single
|
||||
* solution.
|
||||
*
|
||||
* @author [DarthCoder3200](https://github.com/DarthCoder3200)
|
||||
* @author [David Leal](https://github.com/Panquesito7)
|
||||
*/
|
||||
#include <array> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/**
|
||||
* @namespace backtracking
|
||||
* @brief Backtracking algorithms
|
||||
*/
|
||||
namespace backtracking {
|
||||
/**
|
||||
* @namespace sudoku_solver
|
||||
* @brief Functions for the [Sudoku
|
||||
* Solver](https://en.wikipedia.org/wiki/Sudoku) implementation
|
||||
*/
|
||||
namespace sudoku_solver {
|
||||
/**
|
||||
* @brief Check if it's possible to place a number (`no` parameter)
|
||||
* @tparam V number of vertices in the array
|
||||
* @param mat matrix where numbers are saved
|
||||
* @param i current index in rows
|
||||
* @param j current index in columns
|
||||
* @param no number to be added in matrix
|
||||
* @param n number of times loop will run
|
||||
* @returns `true` if 'mat' is different from 'no'
|
||||
* @returns `false` if 'mat' equals to 'no'
|
||||
*/
|
||||
template <size_t V>
|
||||
bool isPossible(const std::array<std::array<int, V>, V> &mat, int i, int j,
|
||||
int no, int n) {
|
||||
/// `no` shouldn't be present in either row i or column j
|
||||
for (int x = 0; x < n; x++) {
|
||||
if (mat[x][j] == no || mat[i][x] == no) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// `no` shouldn't be present in the 3*3 subgrid
|
||||
int sx = (i / 3) * 3;
|
||||
int sy = (j / 3) * 3;
|
||||
|
||||
for (int x = sx; x < sx + 3; x++) {
|
||||
for (int y = sy; y < sy + 3; y++) {
|
||||
if (mat[x][y] == no) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* @brief Utility function to print the matrix
|
||||
* @tparam V number of vertices in array
|
||||
* @param mat matrix where numbers are saved
|
||||
* @param starting_mat copy of mat, required by printMat for highlighting the
|
||||
* differences
|
||||
* @param n number of times loop will run
|
||||
* @return void
|
||||
*/
|
||||
template <size_t V>
|
||||
void printMat(const std::array<std::array<int, V>, V> &mat,
|
||||
const std::array<std::array<int, V>, V> &starting_mat, int n) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < n; j++) {
|
||||
if (starting_mat[i][j] != mat[i][j]) {
|
||||
std::cout << "\033[93m" << mat[i][j] << "\033[0m"
|
||||
<< " ";
|
||||
} else {
|
||||
std::cout << mat[i][j] << " ";
|
||||
}
|
||||
if ((j + 1) % 3 == 0) {
|
||||
std::cout << '\t';
|
||||
}
|
||||
}
|
||||
if ((i + 1) % 3 == 0) {
|
||||
std::cout << std::endl;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function to implement the Sudoku algorithm
|
||||
* @tparam V number of vertices in array
|
||||
* @param mat matrix where numbers are saved
|
||||
* @param starting_mat copy of mat, required by printMat for highlighting the
|
||||
* differences
|
||||
* @param i current index in rows
|
||||
* @param j current index in columns
|
||||
* @returns `true` if 'no' was placed
|
||||
* @returns `false` if 'no' was not placed
|
||||
*/
|
||||
template <size_t V>
|
||||
bool solveSudoku(std::array<std::array<int, V>, V> &mat,
|
||||
const std::array<std::array<int, V>, V> &starting_mat, int i,
|
||||
int j) {
|
||||
/// Base Case
|
||||
if (i == 9) {
|
||||
/// Solved for 9 rows already
|
||||
printMat<V>(mat, starting_mat, 9);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Crossed the last Cell in the row
|
||||
if (j == 9) {
|
||||
return solveSudoku<V>(mat, starting_mat, i + 1, 0);
|
||||
}
|
||||
|
||||
/// Blue Cell - Skip
|
||||
if (mat[i][j] != 0) {
|
||||
return solveSudoku<V>(mat, starting_mat, i, j + 1);
|
||||
}
|
||||
/// White Cell
|
||||
/// Try to place every possible no
|
||||
for (int no = 1; no <= 9; no++) {
|
||||
if (isPossible<V>(mat, i, j, no, 9)) {
|
||||
/// Place the 'no' - assuming a solution will exist
|
||||
mat[i][j] = no;
|
||||
bool solution_found = solveSudoku<V>(mat, starting_mat, i, j + 1);
|
||||
if (solution_found) {
|
||||
return true;
|
||||
}
|
||||
/// Couldn't find a solution
|
||||
/// loop will place the next `no`.
|
||||
}
|
||||
}
|
||||
/// Solution couldn't be found for any of the numbers provided
|
||||
mat[i][j] = 0;
|
||||
return false;
|
||||
}
|
||||
} // namespace sudoku_solver
|
||||
} // namespace backtracking
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
const int V = 9;
|
||||
std::array<std::array<int, V>, V> mat = {
|
||||
std::array<int, V>{5, 3, 0, 0, 7, 0, 0, 0, 0},
|
||||
std::array<int, V>{6, 0, 0, 1, 9, 5, 0, 0, 0},
|
||||
std::array<int, V>{0, 9, 8, 0, 0, 0, 0, 6, 0},
|
||||
std::array<int, V>{8, 0, 0, 0, 6, 0, 0, 0, 3},
|
||||
std::array<int, V>{4, 0, 0, 8, 0, 3, 0, 0, 1},
|
||||
std::array<int, V>{7, 0, 0, 0, 2, 0, 0, 0, 6},
|
||||
std::array<int, V>{0, 6, 0, 0, 0, 0, 2, 8, 0},
|
||||
std::array<int, V>{0, 0, 0, 4, 1, 9, 0, 0, 5},
|
||||
std::array<int, V>{0, 0, 0, 0, 8, 0, 0, 7, 9}};
|
||||
|
||||
backtracking::sudoku_solver::printMat<V>(mat, mat, 9);
|
||||
std::cout << "Solution " << std::endl;
|
||||
std::array<std::array<int, V>, V> starting_mat = mat;
|
||||
backtracking::sudoku_solver::solveSudoku<V>(mat, starting_mat, 0, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of the [Wildcard
|
||||
* Matching](https://www.geeksforgeeks.org/wildcard-pattern-matching/) problem.
|
||||
* @details
|
||||
* Given a matching string and a pattern, implement wildcard pattern
|
||||
* matching with support for `?` and `*`. `?` matches any single character.
|
||||
* `*` matches any sequence of characters (including the empty sequence).
|
||||
* The matching should cover the entire matching string (not partial). The task
|
||||
* is to determine if the pattern matches with the matching string
|
||||
* @author [Swastika Gupta](https://github.com/Swastyy)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace backtracking
|
||||
* @brief Backtracking algorithms
|
||||
*/
|
||||
namespace backtracking {
|
||||
/**
|
||||
* @namespace wildcard_matching
|
||||
* @brief Functions for the [Wildcard
|
||||
* Matching](https://www.geeksforgeeks.org/wildcard-pattern-matching/) problem.
|
||||
*/
|
||||
namespace wildcard_matching {
|
||||
/**
|
||||
* @brief The main function implements if pattern can be matched with given
|
||||
* string
|
||||
* @param s is the given matching string
|
||||
* @param p is the given pattern
|
||||
* @param pos1 is the starting index
|
||||
* @param pos2 is the last index
|
||||
* @returns 1 if pattern matches with matching string otherwise 0
|
||||
*/
|
||||
std::vector<std::vector<int64_t>> dpTable(1000, std::vector<int64_t>(1000, -1));
|
||||
bool wildcard_matching(std::string s, std::string p, uint32_t pos1,
|
||||
uint32_t pos2) {
|
||||
uint32_t n = s.length();
|
||||
uint32_t m = p.length();
|
||||
// matching is successfull if both strings are done
|
||||
if (pos1 == n && pos2 == m) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// matching is unsuccessfull if pattern is not finished but matching string
|
||||
// is
|
||||
if (pos1 != n && pos2 == m) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// all the remaining characters of patterns must be * inorder to match with
|
||||
// finished string
|
||||
if (pos1 == n && pos2 != m) {
|
||||
while (pos2 < m && p[pos2] == '*') {
|
||||
pos2++;
|
||||
}
|
||||
|
||||
return pos2 == m;
|
||||
}
|
||||
|
||||
// if already calculted for these positions
|
||||
if (dpTable[pos1][pos2] != -1) {
|
||||
return dpTable[pos1][pos2];
|
||||
}
|
||||
|
||||
// if the characters are same just go ahead in both the string
|
||||
if (s[pos1] == p[pos2]) {
|
||||
return dpTable[pos1][pos2] =
|
||||
wildcard_matching(s, p, pos1 + 1, pos2 + 1);
|
||||
}
|
||||
|
||||
else {
|
||||
// can only single character
|
||||
if (p[pos2] == '?') {
|
||||
return dpTable[pos1][pos2] =
|
||||
wildcard_matching(s, p, pos1 + 1, pos2 + 1);
|
||||
}
|
||||
// have choice either to match one or more charcters
|
||||
else if (p[pos2] == '*') {
|
||||
return dpTable[pos1][pos2] =
|
||||
wildcard_matching(s, p, pos1, pos2 + 1) ||
|
||||
wildcard_matching(s, p, pos1 + 1, pos2);
|
||||
}
|
||||
// not possible to match
|
||||
else {
|
||||
return dpTable[pos1][pos2] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace wildcard_matching
|
||||
} // namespace backtracking
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 1st test
|
||||
std::cout << "1st test ";
|
||||
std::string matching1 = "baaabab";
|
||||
std::string pattern1 = "*****ba*****ab";
|
||||
assert(backtracking::wildcard_matching::wildcard_matching(matching1,
|
||||
pattern1, 0, 0) ==
|
||||
1); // here the pattern matches with given string
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 2nd test
|
||||
std::cout << "2nd test ";
|
||||
std::string matching2 = "baaabab";
|
||||
std::string pattern2 = "ba*****ab";
|
||||
assert(backtracking::wildcard_matching::wildcard_matching(matching2,
|
||||
pattern2, 0, 0) ==
|
||||
1); // here the pattern matches with given string
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 3rd test
|
||||
std::cout << "3rd test ";
|
||||
std::string matching3 = "baaabab";
|
||||
std::string pattern3 = "ba*ab";
|
||||
assert(backtracking::wildcard_matching::wildcard_matching(matching3,
|
||||
pattern3, 0, 0) ==
|
||||
1); // here the pattern matches with given string
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 4th test
|
||||
std::cout << "4th test ";
|
||||
std::string matching4 = "baaabab";
|
||||
std::string pattern4 = "a*ab";
|
||||
assert(backtracking::wildcard_matching::wildcard_matching(matching4,
|
||||
pattern4, 0, 0) ==
|
||||
1); // here the pattern matches with given string
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 5th test
|
||||
std::cout << "5th test ";
|
||||
std::string matching5 = "baaabab";
|
||||
std::string pattern5 = "aa?ab";
|
||||
assert(backtracking::wildcard_matching::wildcard_matching(matching5,
|
||||
pattern5, 0, 0) ==
|
||||
1); // here the pattern matches with given string
|
||||
std::cout << "passed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
# If necessary, use the RELATIVE flag, otherwise each source file may be listed
|
||||
# with full pathname. RELATIVE may makes it easier to extract an executable name
|
||||
# automatically.
|
||||
file( GLOB APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp )
|
||||
# file( GLOB APP_SOURCES ${CMAKE_SOURCE_DIR}/*.c )
|
||||
# AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} APP_SOURCES)
|
||||
foreach( testsourcefile ${APP_SOURCES} )
|
||||
# I used a simple string replace, to cut off .cpp.
|
||||
string( REPLACE ".cpp" "" testname ${testsourcefile} )
|
||||
add_executable( ${testname} ${testsourcefile} )
|
||||
|
||||
set_target_properties(${testname} PROPERTIES LINKER_LANGUAGE CXX)
|
||||
if(OpenMP_CXX_FOUND)
|
||||
target_link_libraries(${testname} OpenMP::OpenMP_CXX)
|
||||
endif()
|
||||
install(TARGETS ${testname} DESTINATION "bin/bit_manipulation")
|
||||
|
||||
endforeach( testsourcefile ${APP_SOURCES} )
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation to [Check if a number is Even or Odd using Bitwise Operator]
|
||||
* (https://www.log2base2.com/c-examples/bitwise/odd-or-even-program-in-c-using-bitwise-operator.html)
|
||||
*
|
||||
* @details
|
||||
* Given an integer N, determine whether it is even or odd using bitwise manipulation.
|
||||
* The least significant bit (LSB) of a binary number determines its parity:
|
||||
* - If the LSB is 0, the number is even.
|
||||
* - If the LSB is 1, the number is odd.
|
||||
*
|
||||
* This can be checked efficiently using the bitwise AND operator (&) with 1.
|
||||
* - If (N & 1) == 0, N is even.
|
||||
* - If (N & 1) == 1, N is odd.
|
||||
*
|
||||
* Example:
|
||||
* Consider 8-bit binary representations of two numbers:
|
||||
* Number: 10 (decimal) -> 00001010 (binary)
|
||||
* LSB = 0 -> Even number
|
||||
*
|
||||
* Number: 13 (decimal) -> 00001101 (binary)
|
||||
* LSB = 1 -> Odd number
|
||||
*
|
||||
* In both cases, evaluating (N & 1) isolates the LSB:
|
||||
* - For 10: 00001010 & 00000001 = 0 (Even)
|
||||
* - For 13: 00001101 & 00000001 = 1 (Odd)
|
||||
*
|
||||
* Worst Case Time Complexity: O(1)
|
||||
* Space Complexity: O(1)
|
||||
*
|
||||
* @author [Vedant Mukhedkar](https://github.com/git5v)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint> /// for uint32_t
|
||||
#include <iostream> /// for IO operations
|
||||
#include <string> /// for std::string
|
||||
|
||||
/**
|
||||
* @namespace bit_manipulation
|
||||
* @brief Bit manipulation algorithms
|
||||
*/
|
||||
namespace bit_manipulation {
|
||||
/**
|
||||
* @namespace even_odd
|
||||
* @brief Functions for checking if a number is even or odd using bitwise operations
|
||||
*/
|
||||
namespace even_odd {
|
||||
|
||||
/**
|
||||
* @brief Checks if a number is even or odd using bitwise AND.
|
||||
* @param N The number to check.
|
||||
* @returns "Even" if N is even, "Odd" if N is odd.
|
||||
*/
|
||||
bool is_even(std::int64_t N) {
|
||||
return (N & 1) == 0 ? true : false;
|
||||
}
|
||||
|
||||
} // namespace even_odd
|
||||
} // namespace bit_manipulation
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
using bit_manipulation::even_odd::is_even;
|
||||
|
||||
// Test Even numbers
|
||||
assert(is_even(0) == true);
|
||||
assert(is_even(2) == true);
|
||||
assert(is_even(100) == true);
|
||||
assert(is_even(-4) == true);
|
||||
assert(is_even(-1000) == true);
|
||||
|
||||
// Test Odd numbers
|
||||
assert(is_even(1) == false);
|
||||
assert(is_even(3) == false);
|
||||
assert(is_even(101) == false);
|
||||
assert(is_even(-5) == false);
|
||||
assert(is_even(-999) == false);
|
||||
|
||||
std::cout << "All test cases successfully passed!" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation to
|
||||
* [Count number of bits to be flipped to convert A to B]
|
||||
* (https://www.geeksforgeeks.org/count-number-of-bits-to-be-flipped-to-convert-a-to-b/)
|
||||
* in an integer.
|
||||
*
|
||||
* @details
|
||||
* We are given two numbers A and B. Our task is to count the number of bits
|
||||
* needed to be flipped to convert A to B.
|
||||
*
|
||||
* Explanation:
|
||||
*
|
||||
* A = 01010 B = 10100
|
||||
* As we can see, the bits of A that need to be flipped are 01010.
|
||||
* If we flipthese bits, we get 10100, which is B.
|
||||
*
|
||||
* Worst Case Time Complexity: O(log n)
|
||||
* Space complexity: O(1)
|
||||
* @author [Yash Raj Singh](https://github.com/yashrajyash)
|
||||
*/
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
/**
|
||||
* @namespace bit_manipulation
|
||||
* @brief Bit manipulation algorithms
|
||||
*/
|
||||
namespace bit_manipulation {
|
||||
/**
|
||||
* @namespace count_bits_flip
|
||||
* @brief Functions for the [count bits
|
||||
* flip](https://www.geeksforgeeks.org/count-set-bits-in-an-integer/)
|
||||
* implementation
|
||||
*/
|
||||
namespace count_bits_flip {
|
||||
/**
|
||||
* @brief The main function implements count of bits flip required
|
||||
* @param A is the given number whose bits will be flipped to get number B
|
||||
* @param B is the given target number
|
||||
* @returns total number of bits needed to be flipped to convert A to B
|
||||
*/
|
||||
std::uint64_t countBitsFlip(
|
||||
std::int64_t A,
|
||||
std::int64_t B) { // int64_t is preferred over int so that
|
||||
// no Overflow can be there.
|
||||
|
||||
int count =
|
||||
0; // "count" variable is used to count number of bits flip of the
|
||||
// number A to form B in binary representation of number 'n'
|
||||
A = A ^ B;
|
||||
while (A) {
|
||||
A = A & (A - 1);
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
} // namespace count_bits_flip
|
||||
} // namespace bit_manipulation
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// A = 10, B = 20 return 4
|
||||
assert(bit_manipulation::count_bits_flip::countBitsFlip(10, 20) == 4);
|
||||
// A = 20, B = 25 return 3
|
||||
assert(bit_manipulation::count_bits_flip::countBitsFlip(20, 25) == 3);
|
||||
// A = 7, B = 10 return 3
|
||||
assert(bit_manipulation::count_bits_flip::countBitsFlip(7, 10) == 3);
|
||||
// A = 17, B = 25 return 1
|
||||
assert(bit_manipulation::count_bits_flip::countBitsFlip(17, 25) == 1);
|
||||
// A = 11, B = 8 return 2
|
||||
assert(bit_manipulation::count_bits_flip::countBitsFlip(11, 8) == 2);
|
||||
// A = 21, B = 22 return 2
|
||||
assert(bit_manipulation::count_bits_flip::countBitsFlip(21, 22) == 2);
|
||||
// A = 7, B = 786 return 5
|
||||
assert(bit_manipulation::count_bits_flip::countBitsFlip(7, 786) == 5);
|
||||
std::cout << "All test cases successfully passed!" << std::endl;
|
||||
}
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation to [count number of set bits of a number]
|
||||
* (https://www.geeksforgeeks.org/count-set-bits-in-an-integer/) in an
|
||||
* integer.
|
||||
*
|
||||
* @details
|
||||
* We are given an integer number. We need to calculate the number of set bits
|
||||
* in it.
|
||||
*
|
||||
* A binary number consists of two digits. They are 0 & 1. Digit 1 is known as
|
||||
* set bit in computer terms.
|
||||
* Worst Case Time Complexity: O(log n)
|
||||
* Space complexity: O(1)
|
||||
* @author [Swastika Gupta](https://github.com/Swastyy)
|
||||
* @author [Prashant Thakur](https://github.com/prashant-th18)
|
||||
*/
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
/**
|
||||
* @namespace bit_manipulation
|
||||
* @brief Bit manipulation algorithms
|
||||
*/
|
||||
namespace bit_manipulation {
|
||||
/**
|
||||
* @namespace count_of_set_bits
|
||||
* @brief Functions for the [count sets
|
||||
* bits](https://www.geeksforgeeks.org/count-set-bits-in-an-integer/)
|
||||
* implementation
|
||||
*/
|
||||
namespace count_of_set_bits {
|
||||
/**
|
||||
* @brief The main function implements set bit count
|
||||
* @param n is the number whose set bit will be counted
|
||||
* @returns total number of set-bits in the binary representation of number `n`
|
||||
*/
|
||||
std::uint64_t countSetBits(
|
||||
std ::uint64_t n) { // uint64_t is preferred over int so that
|
||||
// no Overflow can be there.
|
||||
//It's preferred over int64_t because it Guarantees that inputs are always non-negative,
|
||||
//which matches the algorithmic problem statement.
|
||||
//set bit counting is conceptually defined only for non-negative numbers.
|
||||
//Provides a type Safety: Using an unsigned type helps prevent accidental negative values,
|
||||
|
||||
std::uint64_t count = 0; // "count" variable is used to count number of set-bits('1')
|
||||
// in binary representation of number 'n'
|
||||
//Count is uint64_t because it Prevents theoretical overflow if someone passes very large integers.
|
||||
// Behavior stays the same for all normal inputs.
|
||||
// Safer for edge cases.
|
||||
|
||||
while (n != 0) {
|
||||
++count;
|
||||
n = (n & (n - 1));
|
||||
}
|
||||
return count;
|
||||
// Why this algorithm is better than the standard one?
|
||||
// Because this algorithm runs the same number of times as the number of
|
||||
// set-bits in it. Means if my number is having "3" set bits, then this
|
||||
// while loop will run only "3" times!!
|
||||
}
|
||||
} // namespace count_of_set_bits
|
||||
} // namespace bit_manipulation
|
||||
|
||||
static void test() {
|
||||
// n = 4 return 1
|
||||
assert(bit_manipulation::count_of_set_bits::countSetBits(4) == 1);
|
||||
// n = 6 return 2
|
||||
assert(bit_manipulation::count_of_set_bits::countSetBits(6) == 2);
|
||||
// n = 13 return 3
|
||||
assert(bit_manipulation::count_of_set_bits::countSetBits(13) == 3);
|
||||
// n = 9 return 2
|
||||
assert(bit_manipulation::count_of_set_bits::countSetBits(9) == 2);
|
||||
// n = 15 return 4
|
||||
assert(bit_manipulation::count_of_set_bits::countSetBits(15) == 4);
|
||||
// n = 25 return 3
|
||||
assert(bit_manipulation::count_of_set_bits::countSetBits(25) == 3);
|
||||
// n = 97 return 3
|
||||
assert(bit_manipulation::count_of_set_bits::countSetBits(97) == 3);
|
||||
// n = 31 return 5
|
||||
assert(bit_manipulation::count_of_set_bits::countSetBits(31) == 5);
|
||||
std::cout << "All test cases successfully passed!" << std::endl;
|
||||
}
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Count the number of
|
||||
* ciphers](https://www.tutorialspoint.com/count-trailing-zeros-in-factorial-of-a-number-in-cplusplus) in `n!` implementation
|
||||
* @details
|
||||
* Given an integer number as input. The goal is to find the number of trailing
|
||||
zeroes in the factorial calculated for
|
||||
* that number. A factorial of a number N is a product of all numbers in the
|
||||
range [1, N].
|
||||
|
||||
* We know that we get a trailing zero only if the number is multiple of 10 or
|
||||
has a factor pair (2,5). In all factorials of
|
||||
* any number greater than 5, we have many 2s more than 5s in the prime
|
||||
factorization of that number. Dividing a
|
||||
* number by powers of 5 will give us the count of 5s in its factors. So, the
|
||||
number of 5s will tell us the number of trailing zeroes.
|
||||
* @author [Swastika Gupta](https://github.com/Swastyy)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/**
|
||||
* @namespace bit_manipulation
|
||||
* @brief Bit manipulation algorithms
|
||||
*/
|
||||
namespace bit_manipulation {
|
||||
/**
|
||||
* @namespace count_of_trailing_ciphers_in_factorial_n
|
||||
* @brief Functions for the [Count the number of
|
||||
* ciphers](https://www.tutorialspoint.com/count-trailing-zeros-in-factorial-of-a-number-in-cplusplus)
|
||||
* in `n!` implementation
|
||||
*/
|
||||
namespace count_of_trailing_ciphers_in_factorial_n {
|
||||
/**
|
||||
* @brief Function to count the number of the trailing ciphers
|
||||
* @param n number for which `n!` ciphers are returned
|
||||
* @return count, Number of ciphers in `n!`.
|
||||
*/
|
||||
uint64_t numberOfCiphersInFactorialN(uint64_t n) {
|
||||
// count is to store the number of 5's in factorial(n)
|
||||
uint64_t count = 0;
|
||||
|
||||
// Keep dividing n by powers of
|
||||
// 5 and update count
|
||||
for (uint64_t i = 5; n / i >= 1; i *= 5) {
|
||||
count += static_cast<uint64_t>(n) / i;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
} // namespace count_of_trailing_ciphers_in_factorial_n
|
||||
} // namespace bit_manipulation
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 1st test
|
||||
std::cout << "1st test ";
|
||||
assert(bit_manipulation::count_of_trailing_ciphers_in_factorial_n::
|
||||
numberOfCiphersInFactorialN(395) == 97);
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 2nd test
|
||||
std::cout << "2nd test ";
|
||||
assert(bit_manipulation::count_of_trailing_ciphers_in_factorial_n::
|
||||
numberOfCiphersInFactorialN(977) == 242);
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 3rd test
|
||||
std::cout << "3rd test ";
|
||||
assert(bit_manipulation::count_of_trailing_ciphers_in_factorial_n::
|
||||
numberOfCiphersInFactorialN(871) == 215);
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 4th test
|
||||
std::cout << "4th test ";
|
||||
assert(bit_manipulation::count_of_trailing_ciphers_in_factorial_n::
|
||||
numberOfCiphersInFactorialN(239) == 57);
|
||||
std::cout << "passed" << std::endl;
|
||||
|
||||
// 5th test
|
||||
std::cout << "5th test ";
|
||||
assert(bit_manipulation::count_of_trailing_ciphers_in_factorial_n::
|
||||
numberOfCiphersInFactorialN(0) == 0);
|
||||
std::cout << "passed" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation to find the non repeating integer
|
||||
* in an array of repeating integers. [Single
|
||||
* Number](https://leetcode.com/problems/single-number/)
|
||||
*
|
||||
* @details
|
||||
* Given an array of integers in which all of the numbers occur exactly
|
||||
* twice except one integer which occurs only once. Find the non-repeating
|
||||
* integer.
|
||||
*
|
||||
* Worst Case Time Complexity: O(n)
|
||||
* Space complexity: O(1)
|
||||
|
||||
* @author [Ravidev Pandey](https://github.com/literalEval)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// storing the numbers
|
||||
|
||||
/**
|
||||
* @namespace bit_manipulation
|
||||
* @brief Bit manipulation algorithms
|
||||
*/
|
||||
namespace bit_manipulation {
|
||||
/**
|
||||
* @namespace find_non_repeating_integer
|
||||
* @brief Functions to find the non repeating integer
|
||||
* in an array of repeating integers. [Single
|
||||
* Number](https://leetcode.com/problems/single-number/)
|
||||
*/
|
||||
namespace find_non_repeating_integer {
|
||||
/**
|
||||
* @brief The main function implements find single number
|
||||
* @param nums vector of integers
|
||||
* @returns returns the integer that occurs only once
|
||||
*/
|
||||
int64_t find_non_repeating_integer(const std::vector<int>& nums) {
|
||||
// The idea is based on the property of XOR.
|
||||
// We know that 'a' XOR 'a' is '0' and '0' XOR 'b'
|
||||
// is b.
|
||||
// Using this, if we XOR all the elements of the array,
|
||||
// the repeating elements will give '0' and this '0'
|
||||
// with the single number will give the number itself.
|
||||
|
||||
int _xor = 0;
|
||||
|
||||
for (const int& num: nums) {
|
||||
_xor ^= num;
|
||||
}
|
||||
|
||||
return _xor;
|
||||
}
|
||||
} // namespace find_non_repeating_integer
|
||||
} // namespace bit_manipulation
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// n = 10,2 return 14
|
||||
|
||||
std::vector<int> nums_one{1, 1, 2, 2, 4, 5, 5};
|
||||
std::vector<int> nums_two{203, 3434, 4545, 3434, 4545};
|
||||
std::vector<int> nums_three{90, 1, 3, 90, 3};
|
||||
|
||||
assert(bit_manipulation::find_non_repeating_integer::
|
||||
find_non_repeating_integer(nums_one) ==
|
||||
4); // 4 is non repeating
|
||||
assert(bit_manipulation::find_non_repeating_integer::
|
||||
find_non_repeating_integer(nums_two) ==
|
||||
203); // 203 is non repeating
|
||||
assert(bit_manipulation::find_non_repeating_integer::
|
||||
find_non_repeating_integer(nums_three) ==
|
||||
1); // 1 is non repeating
|
||||
|
||||
std::cout << "All test cases successfully passed!" << std::endl;
|
||||
}
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* @brief Program to generate n-bit [Gray
|
||||
* code](https://en.wikipedia.org/wiki/Gray_code)
|
||||
*
|
||||
* @details
|
||||
* Gray code is a binary numeral system
|
||||
* where consecutive values differ in exactly 1 bit.
|
||||
* The following code offers one of many possible Gray codes
|
||||
* given some pre-determined number of bits.
|
||||
*/
|
||||
|
||||
#include <bitset> /// for gray code representation
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for vector data structure
|
||||
|
||||
/**
|
||||
* @namespace bit_manipulation
|
||||
* @brief Bit manipulation algorithms
|
||||
*/
|
||||
namespace bit_manipulation {
|
||||
/**
|
||||
* @namespace gray_code
|
||||
* @brief Generate n-bit Gray code
|
||||
*/
|
||||
namespace gray_code {
|
||||
/**
|
||||
* @brief The main function to generate n-bit Gray code
|
||||
*
|
||||
* @param n Number of bits
|
||||
* @return A vector that stores the n-bit Gray code
|
||||
*/
|
||||
std::vector<std::bitset<32>> gray_code_generation(int n) {
|
||||
std::vector<std::bitset<32>> gray_code = {}; // Initialise empty vector
|
||||
|
||||
// No Gray codes for non-positive values of n
|
||||
if (n <= 0) {
|
||||
return gray_code;
|
||||
}
|
||||
|
||||
int total_codes = 1 << n; // Number of n-bit gray codes
|
||||
|
||||
for (int i = 0; i < total_codes; i++) {
|
||||
int gray_num = i ^ (i >> 1); // Gray code formula
|
||||
gray_code.push_back(std::bitset<32>(gray_num)); // Store the value
|
||||
}
|
||||
|
||||
return gray_code;
|
||||
}
|
||||
} // namespace gray_code
|
||||
} // namespace bit_manipulation
|
||||
|
||||
/**
|
||||
* @brief Self-test implementation
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
std::vector<std::bitset<32>> gray_code_negative_1 = {};
|
||||
|
||||
std::vector<std::bitset<32>> gray_code_0 = {};
|
||||
|
||||
std::vector<std::bitset<32>> gray_code_1 = {
|
||||
std::bitset<32>(0), std::bitset<32>(1)
|
||||
};
|
||||
|
||||
std::vector<std::bitset<32>> gray_code_2 = {
|
||||
std::bitset<32>(0), std::bitset<32>(1), std::bitset<32>(3), std::bitset<32>(2)
|
||||
};
|
||||
|
||||
std::vector<std::bitset<32>> gray_code_3 = {
|
||||
std::bitset<32>(0), std::bitset<32>(1), std::bitset<32>(3), std::bitset<32>(2),
|
||||
std::bitset<32>(6), std::bitset<32>(7), std::bitset<32>(5), std::bitset<32>(4)
|
||||
};
|
||||
|
||||
std::vector<std::bitset<32>> gray_code_4 = {
|
||||
std::bitset<32>(0), std::bitset<32>(1), std::bitset<32>(3), std::bitset<32>(2),
|
||||
std::bitset<32>(6), std::bitset<32>(7), std::bitset<32>(5), std::bitset<32>(4),
|
||||
std::bitset<32>(12), std::bitset<32>(13), std::bitset<32>(15), std::bitset<32>(14),
|
||||
std::bitset<32>(10), std::bitset<32>(11), std::bitset<32>(9), std::bitset<32>(8)
|
||||
};
|
||||
|
||||
std::vector<std::bitset<32>> gray_code_5 = {
|
||||
std::bitset<32>(0), std::bitset<32>(1), std::bitset<32>(3), std::bitset<32>(2),
|
||||
std::bitset<32>(6), std::bitset<32>(7), std::bitset<32>(5), std::bitset<32>(4),
|
||||
std::bitset<32>(12), std::bitset<32>(13), std::bitset<32>(15), std::bitset<32>(14),
|
||||
std::bitset<32>(10), std::bitset<32>(11), std::bitset<32>(9), std::bitset<32>(8),
|
||||
std::bitset<32>(24), std::bitset<32>(25), std::bitset<32>(27), std::bitset<32>(26),
|
||||
std::bitset<32>(30), std::bitset<32>(31), std::bitset<32>(29), std::bitset<32>(28),
|
||||
std::bitset<32>(20), std::bitset<32>(21), std::bitset<32>(23), std::bitset<32>(22),
|
||||
std::bitset<32>(18), std::bitset<32>(19), std::bitset<32>(17), std::bitset<32>(16)
|
||||
};
|
||||
|
||||
// invalid values for n
|
||||
assert(bit_manipulation::gray_code::gray_code_generation(-1) == gray_code_negative_1);
|
||||
assert(bit_manipulation::gray_code::gray_code_generation(0) == gray_code_0);
|
||||
|
||||
// valid values for n
|
||||
assert(bit_manipulation::gray_code::gray_code_generation(1) == gray_code_1);
|
||||
assert(bit_manipulation::gray_code::gray_code_generation(2) == gray_code_2);
|
||||
assert(bit_manipulation::gray_code::gray_code_generation(3) == gray_code_3);
|
||||
assert(bit_manipulation::gray_code::gray_code_generation(4) == gray_code_4);
|
||||
assert(bit_manipulation::gray_code::gray_code_generation(5) == gray_code_5);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); //Run self-test implementation
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Returns the [Hamming
|
||||
* distance](https://en.wikipedia.org/wiki/Hamming_distance) between two
|
||||
* integers
|
||||
*
|
||||
* @details
|
||||
* To find hamming distance between two integers, we take their xor, which will
|
||||
* have a set bit iff those bits differ in the two numbers.
|
||||
* Hence, we return the number of such set bits.
|
||||
*
|
||||
* @author [Ravishankar Joshi](https://github.com/ravibitsgoa)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for io operations
|
||||
|
||||
/**
|
||||
* @namespace bit_manipulation
|
||||
* @brief Bit Manipulation algorithms
|
||||
*/
|
||||
namespace bit_manipulation {
|
||||
/**
|
||||
* @namespace hamming_distance
|
||||
* @brief Functions for [Hamming
|
||||
* distance](https://en.wikipedia.org/wiki/Hamming_distance) implementation
|
||||
*/
|
||||
namespace hamming_distance {
|
||||
/**
|
||||
* This function returns the number of set bits in the given number.
|
||||
* @param value the number of which we want to count the number of set bits.
|
||||
* @returns the number of set bits in the given number.
|
||||
*/
|
||||
uint64_t bitCount(uint64_t value) {
|
||||
uint64_t count = 0;
|
||||
while (value) { // until all bits are zero
|
||||
if (value & 1) { // check lower bit
|
||||
count++;
|
||||
}
|
||||
value >>= 1; // shift bits, removing lower bit
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns the hamming distance between two integers.
|
||||
* @param a the first number
|
||||
* @param b the second number
|
||||
* @returns the number of bits differing between the two integers.
|
||||
*/
|
||||
uint64_t hamming_distance(uint64_t a, uint64_t b) { return bitCount(a ^ b); }
|
||||
|
||||
/**
|
||||
* This function returns the hamming distance between two strings.
|
||||
* @param a the first string
|
||||
* @param b the second string
|
||||
* @returns the number of characters differing between the two strings.
|
||||
*/
|
||||
uint64_t hamming_distance(const std::string& a, const std::string& b) {
|
||||
assert(a.size() == b.size());
|
||||
size_t n = a.size();
|
||||
uint64_t count = 0;
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
count += (b[i] != a[i]);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
} // namespace hamming_distance
|
||||
} // namespace bit_manipulation
|
||||
|
||||
/**
|
||||
* @brief Function to the test hamming distance.
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
assert(bit_manipulation::hamming_distance::hamming_distance(11, 2) == 2);
|
||||
assert(bit_manipulation::hamming_distance::hamming_distance(2, 0) == 1);
|
||||
assert(bit_manipulation::hamming_distance::hamming_distance(11, 0) == 3);
|
||||
|
||||
assert(bit_manipulation::hamming_distance::hamming_distance("1101",
|
||||
"1111") == 1);
|
||||
assert(bit_manipulation::hamming_distance::hamming_distance("1111",
|
||||
"1111") == 0);
|
||||
assert(bit_manipulation::hamming_distance::hamming_distance("0000",
|
||||
"1111") == 4);
|
||||
|
||||
assert(bit_manipulation::hamming_distance::hamming_distance("alpha",
|
||||
"alphb") == 1);
|
||||
assert(bit_manipulation::hamming_distance::hamming_distance("abcd",
|
||||
"abcd") == 0);
|
||||
assert(bit_manipulation::hamming_distance::hamming_distance("dcba",
|
||||
"abcd") == 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // execute the tests
|
||||
uint64_t a = 11; // 1011 in binary
|
||||
uint64_t b = 2; // 0010 in binary
|
||||
|
||||
std::cout << "Hamming distance between " << a << " and " << b << " is "
|
||||
<< bit_manipulation::hamming_distance::hamming_distance(a, b)
|
||||
<< std::endl;
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Next higher number with same number of set bits]
|
||||
* (https://www.geeksforgeeks.org/next-higher-number-with-same-number-of-set-bits/)
|
||||
* implementation
|
||||
*
|
||||
* @details
|
||||
* Given a number x, find next number with same number of 1 bits in it’s binary
|
||||
* representation. For example, consider x = 12, whose binary representation is
|
||||
* 1100 (excluding leading zeros on 32 bit machine). It contains two logic 1
|
||||
* bits. The next higher number with two logic 1 bits is 17 (100012).
|
||||
*
|
||||
* A binary number consists of two digits. They are 0 & 1. Digit 1 is known as
|
||||
* set bit in computer terms.
|
||||
* @author [Kunal Nayak](https://github.com/Kunal766)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/**
|
||||
* @namespace bit_manipulation
|
||||
* @brief Bit manipulation algorithms
|
||||
*/
|
||||
namespace bit_manipulation {
|
||||
|
||||
/**
|
||||
* @brief The main function implements checking the next number
|
||||
* @param x the number that will be calculated
|
||||
* @returns a number
|
||||
*/
|
||||
uint64_t next_higher_number(uint64_t x) {
|
||||
uint64_t rightOne = 0;
|
||||
uint64_t nextHigherOneBit = 0;
|
||||
uint64_t rightOnesPattern = 0;
|
||||
|
||||
uint64_t next = 0;
|
||||
|
||||
if (x) {
|
||||
// right most set bit
|
||||
rightOne = x & -static_cast<signed>(x);
|
||||
|
||||
// reset the pattern and set next higher bit
|
||||
// left part of x will be here
|
||||
nextHigherOneBit = x + rightOne;
|
||||
|
||||
// nextHigherOneBit is now part [D] of the above explanation.
|
||||
|
||||
// isolate the pattern
|
||||
rightOnesPattern = x ^ nextHigherOneBit;
|
||||
|
||||
// right adjust pattern
|
||||
rightOnesPattern = (rightOnesPattern) / rightOne;
|
||||
|
||||
// correction factor
|
||||
rightOnesPattern >>= 2;
|
||||
|
||||
// rightOnesPattern is now part [A] of the above explanation.
|
||||
|
||||
// integrate new pattern (Add [D] and [A])
|
||||
next = nextHigherOneBit | rightOnesPattern;
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
} // namespace bit_manipulation
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// x = 4 return 8
|
||||
assert(bit_manipulation::next_higher_number(4) == 8);
|
||||
// x = 6 return 9
|
||||
assert(bit_manipulation::next_higher_number(6) == 9);
|
||||
// x = 13 return 14
|
||||
assert(bit_manipulation::next_higher_number(13) == 14);
|
||||
// x = 64 return 128
|
||||
assert(bit_manipulation::next_higher_number(64) == 128);
|
||||
// x = 15 return 23
|
||||
assert(bit_manipulation::next_higher_number(15) == 23);
|
||||
// x= 32 return 64
|
||||
assert(bit_manipulation::next_higher_number(32) == 64);
|
||||
// x = 97 return 98
|
||||
assert(bit_manipulation::next_higher_number(97) == 98);
|
||||
// x = 1024 return 2048
|
||||
assert(bit_manipulation::next_higher_number(1024) == 2048);
|
||||
|
||||
std::cout << "All test cases have successfully passed!" << std::endl;
|
||||
}
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Find whether a given number is power of 2]
|
||||
* (https://www.geeksforgeeks.org/program-to-find-whether-a-given-number-is-power-of-2/)
|
||||
* implementation
|
||||
*
|
||||
* @details
|
||||
* We are given a positive integer number. We need to check whether the number
|
||||
* is power of 2 or not.
|
||||
*
|
||||
* A binary number consists of two digits. They are 0 & 1. Digit 1 is known as
|
||||
* set bit in computer terms.
|
||||
* Worst Case Time Complexity: O(1)
|
||||
* Space complexity: O(1)
|
||||
* @author [Prafful Gupta](https://github.com/EcstaticPG-25811)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/**
|
||||
* @namespace bit_manipulation
|
||||
* @brief Bit manipulation algorithms
|
||||
*/
|
||||
namespace bit_manipulation {
|
||||
/**
|
||||
* @brief The main function implements check for power of 2
|
||||
* @param n is the number who will be checked
|
||||
* @returns either true or false
|
||||
*/
|
||||
bool isPowerOfTwo(std ::int64_t n) { // int64_t is preferred over int so that
|
||||
// no Overflow can be there.
|
||||
|
||||
return n > 0 && !(n & n - 1); // If we subtract a power of 2 numbers by 1
|
||||
// then all unset bits after the only set bit become set; and the set bit
|
||||
// becomes unset.
|
||||
|
||||
// If a number n is a power of 2 then bitwise and of n-1 and n will be zero.
|
||||
// The expression n&(n-1) will not work when n is 0.
|
||||
// To handle this case also, our expression will become n& (!n&(n-1))
|
||||
}
|
||||
} // namespace bit_manipulation
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// n = 4 return true
|
||||
assert(bit_manipulation::isPowerOfTwo(4) == true);
|
||||
// n = 6 return false
|
||||
assert(bit_manipulation::isPowerOfTwo(6) == false);
|
||||
// n = 13 return false
|
||||
assert(bit_manipulation::isPowerOfTwo(13) == false);
|
||||
// n = 64 return true
|
||||
assert(bit_manipulation::isPowerOfTwo(64) == true);
|
||||
// n = 15 return false
|
||||
assert(bit_manipulation::isPowerOfTwo(15) == false);
|
||||
// n = 32 return true
|
||||
assert(bit_manipulation::isPowerOfTwo(32) == true);
|
||||
// n = 97 return false
|
||||
assert(bit_manipulation::isPowerOfTwo(97) == false);
|
||||
// n = 1024 return true
|
||||
assert(bit_manipulation::isPowerOfTwo(1024) == true);
|
||||
std::cout << "All test cases successfully passed!" << std::endl;
|
||||
}
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation to [From the right, set the Kth bit in the binary
|
||||
* representation of N]
|
||||
* (https://practice.geeksforgeeks.org/problems/set-kth-bit3724/1/) in an
|
||||
* integer.
|
||||
*
|
||||
* @details
|
||||
* Given a number N and a value K. From the right, set the Kth bit in the binary
|
||||
* representation of N. The position of Least Significant Bit(or last bit) is 0,
|
||||
* the second last bit is 1 and so on. in it.
|
||||
*
|
||||
* A binary number consists of two digits. They are 0 & 1. Digit 1 is known as
|
||||
* set bit in computer terms.
|
||||
* Worst Case Time Complexity: O(1)
|
||||
* Space complexity: O(1)
|
||||
|
||||
* @author [Aman Raj](https://github.com/aman2000raj)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/**
|
||||
* @namespace bit_manipulation
|
||||
* @brief Bit manipulation algorithms
|
||||
*/
|
||||
namespace bit_manipulation {
|
||||
/**
|
||||
* @namespace setKthBit
|
||||
* @brief Functions for the [From the right, set the Kth bit in the binary
|
||||
* representation of N]
|
||||
* (https://practice.geeksforgeeks.org/problems/set-kth-bit3724/1/)
|
||||
* implementation
|
||||
*/
|
||||
namespace set_kth_bit {
|
||||
/**
|
||||
* @brief The main function implements set kth bit
|
||||
* @param N is the number whose kth bit will be set
|
||||
* @returns returns an integer after setting the K'th bit in N
|
||||
*/
|
||||
std::uint64_t setKthBit(std ::int64_t N,
|
||||
std ::int64_t k) { // int64_t is preferred over int so
|
||||
// that no Overflow can be there.
|
||||
|
||||
int pos =
|
||||
1 << k; // "pos" variable is used to store 1 at kth postion and
|
||||
// rest bits are 0. in binary representation of number 'n'
|
||||
|
||||
return N | pos; // by taking or with the pos and the N we set the bit of N
|
||||
// at kth position.
|
||||
}
|
||||
} // namespace set_kth_bit
|
||||
} // namespace bit_manipulation
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// n = 10,2 return 14
|
||||
assert(bit_manipulation::set_kth_bit::setKthBit(10, 2) == 14);
|
||||
// n = 25,1 return 27
|
||||
assert(bit_manipulation::set_kth_bit::setKthBit(25, 1) == 27);
|
||||
// n = 400001,5 return 400033
|
||||
assert(bit_manipulation::set_kth_bit::setKthBit(400001, 5) == 400033);
|
||||
// n = 123 return 123
|
||||
assert(bit_manipulation::set_kth_bit::setKthBit(123, 3) == 123);
|
||||
|
||||
std::cout << "All test cases successfully passed!" << std::endl;
|
||||
}
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation to
|
||||
* [Travelling Salesman problem using bit-masking]
|
||||
* (https://www.geeksforgeeks.org/travelling-salesman-problem-set-1/)
|
||||
*
|
||||
* @details
|
||||
* Given the distance/cost(as and adjacency matrix) between each city/node to
|
||||
* the other city/node , the problem is to find the shortest possible route that
|
||||
* visits every city exactly once and returns to the starting point or we can
|
||||
* say the minimum cost of whole tour.
|
||||
*
|
||||
* Explanation:
|
||||
* INPUT -> You are given with a adjacency matrix A = {} which contains the
|
||||
* distance between two cities/node.
|
||||
*
|
||||
* OUTPUT -> Minimum cost of whole tour from starting point
|
||||
*
|
||||
* Worst Case Time Complexity: O(n^2 * 2^n)
|
||||
* Space complexity: O(n)
|
||||
* @author [Utkarsh Yadav](https://github.com/Rytnix)
|
||||
*/
|
||||
#include <algorithm> /// for std::min
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
#include <limits> /// for limits of integral types
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace bit_manipulation
|
||||
* @brief Bit manipulation algorithms
|
||||
*/
|
||||
namespace bit_manipulation {
|
||||
/**
|
||||
* @namespace travellingSalesman_bitmanipulation
|
||||
* @brief Functions for the [Travelling Salesman
|
||||
* Bitmask](https://www.geeksforgeeks.org/travelling-salesman-problem-set-1/)
|
||||
* implementation
|
||||
*/
|
||||
namespace travelling_salesman_using_bit_manipulation {
|
||||
/**
|
||||
* @brief The function implements travellingSalesman using bitmanipulation
|
||||
* @param dist is the cost to reach between two cities/nodes
|
||||
* @param setOfCitites represents the city in bit form.\
|
||||
* @param city is taken to track the current city movement.
|
||||
* @param n is the no of citys .
|
||||
* @param dp vector is used to keep a record of state to avoid the
|
||||
* recomputation.
|
||||
* @returns minimum cost of traversing whole nodes/cities from starting point
|
||||
* back to starting point
|
||||
*/
|
||||
std::uint64_t travelling_salesman_using_bit_manipulation(
|
||||
std::vector<std::vector<uint32_t>>
|
||||
dist, // dist is the adjacency matrix containing the distance.
|
||||
// setOfCities as a bit represent the cities/nodes. Ex: if
|
||||
// setOfCities = 2 => 0010(in binary) means representing the
|
||||
// city/node B if city/nodes are represented as D->C->B->A.
|
||||
std::uint64_t setOfCities,
|
||||
std::uint64_t city, // city is taken to track our current city/node
|
||||
// movement,where we are currently.
|
||||
std::uint64_t n, // n is the no of cities we have.
|
||||
std::vector<std::vector<uint32_t>>
|
||||
&dp) // dp is taken to memorize the state to avoid recomputition
|
||||
{
|
||||
// base case;
|
||||
if (setOfCities == (1 << n) - 1) { // we have covered all the cities
|
||||
return dist[city][0]; // return the cost from the current city to the
|
||||
// original city.
|
||||
}
|
||||
|
||||
if (dp[setOfCities][city] != -1) {
|
||||
return dp[setOfCities][city];
|
||||
}
|
||||
// otherwise try all possible options
|
||||
uint64_t ans = 2147483647;
|
||||
for (int choice = 0; choice < n; choice++) {
|
||||
// check if the city is visited or not.
|
||||
if ((setOfCities & (1 << choice)) ==
|
||||
0) { // this means that this perticular city is not visited.
|
||||
std::uint64_t subProb =
|
||||
dist[city][choice] +
|
||||
travelling_salesman_using_bit_manipulation(
|
||||
dist, setOfCities | (1 << choice), choice, n, dp);
|
||||
// Here we are doing a recursive call to tsp with the updated set of
|
||||
// city/node and choice which tells that where we are currently.
|
||||
ans = std::min(ans, subProb);
|
||||
}
|
||||
}
|
||||
dp[setOfCities][city] = ans;
|
||||
return ans;
|
||||
}
|
||||
} // namespace travelling_salesman_using_bit_manipulation
|
||||
} // namespace bit_manipulation
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 1st test-case
|
||||
std::vector<std::vector<uint32_t>> dist = {
|
||||
{0, 20, 42, 35}, {20, 0, 30, 34}, {42, 30, 0, 12}, {35, 34, 12, 0}};
|
||||
uint32_t V = dist.size();
|
||||
std::vector<std::vector<uint32_t>> dp(1 << V, std::vector<uint32_t>(V, -1));
|
||||
assert(bit_manipulation::travelling_salesman_using_bit_manipulation::
|
||||
travelling_salesman_using_bit_manipulation(dist, 1, 0, V, dp) ==
|
||||
97);
|
||||
std::cout << "1st test-case: passed!"
|
||||
<< "\n";
|
||||
|
||||
// 2nd test-case
|
||||
dist = {{0, 5, 10, 15}, {5, 0, 20, 30}, {10, 20, 0, 35}, {15, 30, 35, 0}};
|
||||
V = dist.size();
|
||||
std::vector<std::vector<uint32_t>> dp1(1 << V,
|
||||
std::vector<uint32_t>(V, -1));
|
||||
assert(bit_manipulation::travelling_salesman_using_bit_manipulation::
|
||||
travelling_salesman_using_bit_manipulation(dist, 1, 0, V, dp1) ==
|
||||
75);
|
||||
std::cout << "2nd test-case: passed!"
|
||||
<< "\n";
|
||||
// 3rd test-case
|
||||
dist = {{0, 10, 15, 20}, {10, 0, 35, 25}, {15, 35, 0, 30}, {20, 25, 30, 0}};
|
||||
V = dist.size();
|
||||
std::vector<std::vector<uint32_t>> dp2(1 << V,
|
||||
std::vector<uint32_t>(V, -1));
|
||||
assert(bit_manipulation::travelling_salesman_using_bit_manipulation::
|
||||
travelling_salesman_using_bit_manipulation(dist, 1, 0, V, dp2) ==
|
||||
80);
|
||||
|
||||
std::cout << "3rd test-case: passed!"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
# If necessary, use the RELATIVE flag, otherwise each source file may be listed
|
||||
# with full pathname. RELATIVE may makes it easier to extract an executable name
|
||||
# automatically.
|
||||
file( GLOB APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp )
|
||||
# file( GLOB APP_SOURCES ${CMAKE_SOURCE_DIR}/*.c )
|
||||
# AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} APP_SOURCES)
|
||||
foreach( testsourcefile ${APP_SOURCES} )
|
||||
# I used a simple string replace, to cut off .cpp.
|
||||
string( REPLACE ".cpp" "" testname ${testsourcefile} )
|
||||
add_executable( ${testname} ${testsourcefile} )
|
||||
|
||||
set_target_properties(${testname} PROPERTIES LINKER_LANGUAGE CXX)
|
||||
if(OpenMP_CXX_FOUND)
|
||||
target_link_libraries(${testname} OpenMP::OpenMP_CXX)
|
||||
endif()
|
||||
install(TARGETS ${testname} DESTINATION "bin/ciphers")
|
||||
|
||||
endforeach( testsourcefile ${APP_SOURCES} )
|
||||
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of the [A1Z26
|
||||
* cipher](https://www.dcode.fr/letter-number-cipher)
|
||||
* @details The A1Z26 cipher is a simple substiution cipher where each letter is
|
||||
* replaced by the number of the order they're in. For example, A corresponds to
|
||||
* 1, B = 2, C = 3, etc.
|
||||
*
|
||||
* @author [Focusucof](https://github.com/Focusucof)
|
||||
*/
|
||||
|
||||
#include <algorithm> /// for std::transform and std::replace
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint> /// for uint8_t
|
||||
#include <iostream> /// for IO operations
|
||||
#include <map> /// for std::map
|
||||
#include <sstream> /// for std::stringstream
|
||||
#include <string> /// for std::string
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/**
|
||||
* @namespace ciphers
|
||||
* @brief Algorithms for encryption and decryption
|
||||
*/
|
||||
namespace ciphers {
|
||||
/**
|
||||
* @namespace a1z26
|
||||
* @brief Functions for [A1Z26](https://www.dcode.fr/letter-number-cipher)
|
||||
* encryption and decryption implementation
|
||||
*/
|
||||
namespace a1z26 {
|
||||
|
||||
std::map<uint8_t, char> a1z26_decrypt_map = {
|
||||
{1, 'a'}, {2, 'b'}, {3, 'c'}, {4, 'd'}, {5, 'e'}, {6, 'f'}, {7, 'g'},
|
||||
{8, 'h'}, {9, 'i'}, {10, 'j'}, {11, 'k'}, {12, 'l'}, {13, 'm'}, {14, 'n'},
|
||||
{15, 'o'}, {16, 'p'}, {17, 'q'}, {18, 'r'}, {19, 's'}, {20, 't'}, {21, 'u'},
|
||||
{22, 'v'}, {23, 'w'}, {24, 'x'}, {25, 'y'}, {26, 'z'},
|
||||
};
|
||||
|
||||
std::map<char, uint8_t> a1z26_encrypt_map = {
|
||||
{'a', 1}, {'b', 2}, {'c', 3}, {'d', 4}, {'e', 5}, {'f', 6}, {'g', 7},
|
||||
{'h', 8}, {'i', 9}, {'j', 10}, {'k', 11}, {'l', 12}, {'m', 13}, {'n', 14},
|
||||
{'o', 15}, {'p', 16}, {'q', 17}, {'r', 18}, {'s', 19}, {'t', 20}, {'u', 21},
|
||||
{'v', 22}, {'w', 23}, {'x', 24}, {'y', 25}, {'z', 26}};
|
||||
|
||||
/**
|
||||
* @brief a1z26 encryption implementation
|
||||
* @param text is the plaintext input
|
||||
* @returns encoded string with dashes to seperate letters
|
||||
*/
|
||||
std::string encrypt(std::string text) {
|
||||
std::string result;
|
||||
std::transform(text.begin(), text.end(), text.begin(),
|
||||
::tolower); // convert string to lowercase
|
||||
std::replace(text.begin(), text.end(), ':', ' ');
|
||||
for (char letter : text) {
|
||||
if (letter != ' ') {
|
||||
result += std::to_string(
|
||||
a1z26_encrypt_map[letter]); // convert int to string and append
|
||||
// to result
|
||||
result += "-"; // space out each set of numbers with spaces
|
||||
} else {
|
||||
result.pop_back();
|
||||
result += ' ';
|
||||
}
|
||||
}
|
||||
result.pop_back(); // remove leading dash
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief a1z26 decryption implementation
|
||||
* @param text is the encrypted text input
|
||||
* @param bReturnUppercase is if the decoded string should be in uppercase or
|
||||
* not
|
||||
* @returns the decrypted string in all uppercase or all lowercase
|
||||
*/
|
||||
std::string decrypt(const std::string& text, bool bReturnUppercase = false) {
|
||||
std::string result;
|
||||
|
||||
// split words seperated by spaces into a vector array
|
||||
std::vector<std::string> word_array;
|
||||
std::stringstream sstream(text);
|
||||
std::string word;
|
||||
while (sstream >> word) {
|
||||
word_array.push_back(word);
|
||||
}
|
||||
|
||||
for (auto& i : word_array) {
|
||||
std::replace(i.begin(), i.end(), '-', ' ');
|
||||
std::vector<std::string> text_array;
|
||||
|
||||
std::stringstream ss(i);
|
||||
std::string res_text;
|
||||
while (ss >> res_text) {
|
||||
text_array.push_back(res_text);
|
||||
}
|
||||
|
||||
for (auto& i : text_array) {
|
||||
result += a1z26_decrypt_map[stoi(i)];
|
||||
}
|
||||
|
||||
result += ' ';
|
||||
}
|
||||
result.pop_back(); // remove any leading whitespace
|
||||
|
||||
if (bReturnUppercase) {
|
||||
std::transform(result.begin(), result.end(), result.begin(), ::toupper);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace a1z26
|
||||
} // namespace ciphers
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 1st test
|
||||
std::string input = "Hello World";
|
||||
std::string expected = "8-5-12-12-15 23-15-18-12-4";
|
||||
std::string output = ciphers::a1z26::encrypt(input);
|
||||
|
||||
std::cout << "Input: " << input << std::endl;
|
||||
std::cout << "Expected: " << expected << std::endl;
|
||||
std::cout << "Output: " << output << std::endl;
|
||||
assert(output == expected);
|
||||
std::cout << "TEST PASSED";
|
||||
|
||||
// 2nd test
|
||||
input = "12-15-23-5-18-3-1-19-5";
|
||||
expected = "lowercase";
|
||||
output = ciphers::a1z26::decrypt(input);
|
||||
|
||||
std::cout << "Input: " << input << std::endl;
|
||||
std::cout << "Expected: " << expected << std::endl;
|
||||
std::cout << "Output: " << output << std::endl;
|
||||
assert(output == expected);
|
||||
std::cout << "TEST PASSED";
|
||||
|
||||
// 3rd test
|
||||
input = "21-16-16-5-18-3-1-19-5";
|
||||
expected = "UPPERCASE";
|
||||
output = ciphers::a1z26::decrypt(input, true);
|
||||
|
||||
std::cout << "Input: " << input << std::endl;
|
||||
std::cout << "Expected: " << expected << std::endl;
|
||||
std::cout << "Output: " << output << std::endl;
|
||||
assert(output == expected);
|
||||
std::cout << "TEST PASSED";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Atbash Cipher](https://en.wikipedia.org/wiki/Atbash) implementation
|
||||
* @details The Atbash cipher is a subsitution cipher where the letters of the
|
||||
* alphabet are in reverse. For example, A is replaced with Z, B is replaced
|
||||
* with Y, etc.
|
||||
*
|
||||
* ### Algorithm
|
||||
* The algorithm takes a string, and looks up the corresponding reversed letter
|
||||
* for each letter in the word and replaces it. Spaces are ignored and case is
|
||||
* preserved.
|
||||
*
|
||||
* @author [Focusucof](https://github.com/Focusucof)
|
||||
*/
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
#include <map> /// for std::map
|
||||
#include <string> /// for std::string
|
||||
|
||||
/** \namespace ciphers
|
||||
* \brief Algorithms for encryption and decryption
|
||||
*/
|
||||
namespace ciphers {
|
||||
/** \namespace atbash
|
||||
* \brief Functions for the [Atbash
|
||||
* Cipher](https://en.wikipedia.org/wiki/Atbash) implementation
|
||||
*/
|
||||
namespace atbash {
|
||||
std::map<char, char> atbash_cipher_map = {
|
||||
{'a', 'z'}, {'b', 'y'}, {'c', 'x'}, {'d', 'w'}, {'e', 'v'}, {'f', 'u'},
|
||||
{'g', 't'}, {'h', 's'}, {'i', 'r'}, {'j', 'q'}, {'k', 'p'}, {'l', 'o'},
|
||||
{'m', 'n'}, {'n', 'm'}, {'o', 'l'}, {'p', 'k'}, {'q', 'j'}, {'r', 'i'},
|
||||
{'s', 'h'}, {'t', 'g'}, {'u', 'f'}, {'v', 'e'}, {'w', 'd'}, {'x', 'c'},
|
||||
{'y', 'b'}, {'z', 'a'}, {'A', 'Z'}, {'B', 'Y'}, {'C', 'X'}, {'D', 'W'},
|
||||
{'E', 'V'}, {'F', 'U'}, {'G', 'T'}, {'H', 'S'}, {'I', 'R'}, {'J', 'Q'},
|
||||
{'K', 'P'}, {'L', 'O'}, {'M', 'N'}, {'N', 'M'}, {'O', 'L'}, {'P', 'K'},
|
||||
{'Q', 'J'}, {'R', 'I'}, {'S', 'H'}, {'T', 'G'}, {'U', 'F'}, {'V', 'E'},
|
||||
{'W', 'D'}, {'X', 'C'}, {'Y', 'B'}, {'Z', 'A'}, {' ', ' '}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief atbash cipher encryption and decryption
|
||||
* @param text Plaintext to be encrypted
|
||||
* @returns encoded or decoded string
|
||||
*/
|
||||
std::string atbash_cipher(const std::string& text) {
|
||||
std::string result;
|
||||
for (char letter : text) {
|
||||
result += atbash_cipher_map[letter];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace atbash
|
||||
} // namespace ciphers
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 1st test
|
||||
std::string text = "Hello World";
|
||||
std::string expected = "Svool Dliow";
|
||||
std::string encrypted_text = ciphers::atbash::atbash_cipher(text);
|
||||
std::string decrypted_text = ciphers::atbash::atbash_cipher(encrypted_text);
|
||||
assert(expected == encrypted_text);
|
||||
assert(text == decrypted_text);
|
||||
std::cout << "Original text: " << text << std::endl;
|
||||
std::cout << ", Expected text: " << expected << std::endl;
|
||||
std::cout << ", Encrypted text: " << encrypted_text << std::endl;
|
||||
std::cout << ", Decrypted text: " << decrypted_text << std::endl;
|
||||
std::cout << "\nAll tests have successfully passed!\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* @brief [Base64 Encoding and
|
||||
* Decoding](https://en.wikipedia.org/wiki/Base64)
|
||||
* @details In programming, [Base64](https://en.wikipedia.org/wiki/Base64) is a
|
||||
* group of binary-to-text encoding schemes that represent binary data (more
|
||||
* specifically, a sequence of 8-bit bytes) in an ASCII string format by
|
||||
* translating the data into a radix-64 representation. The term Base64
|
||||
* originates from a specific MIME content transfer encoding. Each non-final
|
||||
* Base64 digit represents exactly 6 bits of data. Three 8-bit bytes (i.e., a
|
||||
* total of 24 bits) can therefore be represented by four 6-bit Base64
|
||||
* digits.
|
||||
* @author [Ashish Daulatabad](https://github.com/AshishYUO)
|
||||
*/
|
||||
#include <cassert> /// for `assert` operations
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/**
|
||||
* @namespace ciphers
|
||||
* @brief Cipher algorithms
|
||||
*/
|
||||
namespace ciphers {
|
||||
/**
|
||||
* @namespace base64_encoding
|
||||
* @brief Functions for [Base64 Encoding and
|
||||
* Decoding](https://en.wikipedia.org/wiki/Base64) implementation.
|
||||
*/
|
||||
namespace base64_encoding {
|
||||
// chars denoting the format for encoding and decoding array.
|
||||
// This array is already decided by
|
||||
// [RFC4648](https://tools.ietf.org/html/rfc4648#section-4) standard
|
||||
const std::string chars =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
/**
|
||||
* @brief Base64 Encoder
|
||||
* @details Converts the given string to Base64 equivalent.
|
||||
* @param input Input as a string
|
||||
* @returns Base64 encoded string
|
||||
*/
|
||||
std::string base64_encode(const std::string &input) {
|
||||
std::string base64_string; /// Output of this function: base64 string
|
||||
// base64 deals with 6-bit chars encoded as per chars, so
|
||||
// we will always filter 6-bits from input.
|
||||
for (uint32_t i = 0; i < input.size(); i += 3) {
|
||||
char first_byte = input[i]; /// First byte of the iteration
|
||||
// Take first six bits of first character.
|
||||
// Encode the first six bits with character defined in string `chars`
|
||||
base64_string.push_back(chars[first_byte >> 2]);
|
||||
|
||||
if (i + 1 < input.size()) {
|
||||
char second_byte = input[i + 1]; /// Second byte of the iteration
|
||||
// Take remaining two bits of first character, and four first bits
|
||||
// from second character Combine two numbers as 6-bit digits and
|
||||
// encode by array chars (first two bits of first byte and next four
|
||||
// of second byte)
|
||||
base64_string.push_back(
|
||||
chars[(((first_byte & 3) << 4) | ((second_byte & 0xF0) >> 4))]);
|
||||
|
||||
if (i + 2 < input.size()) {
|
||||
char third_byte = input[i + 2]; /// Third byte of the iteration
|
||||
// Take remaining four bits of second character, and first two
|
||||
// bits from third character Combine two numbers as 6-bit digits
|
||||
// and encode by array chars (remaining four bits of second byte
|
||||
// and first two of third byte)
|
||||
base64_string.push_back(chars[((third_byte & 0xC0) >> 6) |
|
||||
((second_byte & 0x0F) << 2)]);
|
||||
// Encode remaining 6-bit of third byte by array chars
|
||||
base64_string.push_back(chars[(third_byte & 0x3F)]);
|
||||
} else {
|
||||
// Take remaining four bits of second character as 6-bit number
|
||||
base64_string.push_back(chars[((second_byte & 0x0F) << 2)]);
|
||||
base64_string.push_back('='); // padding characters
|
||||
}
|
||||
} else {
|
||||
// Take remaining two bits of first character as 6-bit number
|
||||
base64_string.push_back(chars[((first_byte & 3) << 4)]);
|
||||
base64_string.push_back('='); // padding characters
|
||||
base64_string.push_back('='); // padding characters
|
||||
}
|
||||
}
|
||||
return base64_string;
|
||||
}
|
||||
/**
|
||||
* @brief Utility function for finding index
|
||||
* @details Utility function for finding the position of a character in array
|
||||
* `chars`
|
||||
* @param c character to search in array `chars`
|
||||
* @returns integer denoting position of character in array `chars`
|
||||
*/
|
||||
uint8_t find_idx(const char c) {
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
return c - 'A';
|
||||
} else if (c >= 'a' && c <= 'z') {
|
||||
return c - 'a' + 26;
|
||||
} else if (c >= '0' && c <= '9') {
|
||||
return c - '0' + 52;
|
||||
} else if (c == '+') {
|
||||
return 62;
|
||||
} else if (c == '/') {
|
||||
return 63;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
/**
|
||||
* @brief Base64 Decoder
|
||||
* @details Decodes the Base64 string
|
||||
* @param base64_str Input as a Base64 string
|
||||
* @returns Base64 decoded string
|
||||
*/
|
||||
std::string base64_decode(const std::string &base64_str) {
|
||||
std::string
|
||||
base64_decoded; /// Output of this function: base64 decoded string
|
||||
for (uint32_t i = 0; i < base64_str.size(); i += 4) {
|
||||
/// First 6-bit representation of Base64
|
||||
char first_byte = base64_str[i];
|
||||
/// Second 6-bit representation of Base64
|
||||
char second_byte = base64_str[i + 1];
|
||||
// Actual str characters are of 8 bits (or 1 byte):
|
||||
// :: 8 bits are decode by taking 6 bits from 1st byte of base64 string
|
||||
// and first 2 bits from 2nd byte of base64 string.
|
||||
char first_actual_byte = static_cast<char>(
|
||||
(find_idx(first_byte) << 2) | ((find_idx(second_byte)) >> 4));
|
||||
base64_decoded.push_back(first_actual_byte);
|
||||
if (i + 2 < base64_str.size() && base64_str[i + 2] != '=') {
|
||||
/// Third 6-bit representation of Base64
|
||||
char third_byte = base64_str[i + 2];
|
||||
// :: Next 8 bits are decode by taking remaining 4 bits from 2nd
|
||||
// byte of base64 string and first 4 bits from 3rd byte of base64
|
||||
// string.
|
||||
char second_actual_byte =
|
||||
static_cast<char>(((find_idx(second_byte) & 0x0F) << 4) |
|
||||
(find_idx(third_byte) >> 2));
|
||||
base64_decoded.push_back(second_actual_byte);
|
||||
|
||||
if (i + 3 < base64_str.size() && base64_str[i + 3] != '=') {
|
||||
/// Fourth 6-bit representation of Base64 string
|
||||
char fourth_byte = base64_str[i + 3];
|
||||
// :: Taking remaining 2 bits from 3rd byte of base64 string
|
||||
// and all 6 bits from 4th byte of base64 string.
|
||||
char third_actual_byte =
|
||||
static_cast<char>(((find_idx(third_byte) & 0x03) << 6) |
|
||||
find_idx(fourth_byte));
|
||||
base64_decoded.push_back(third_actual_byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
return base64_decoded;
|
||||
}
|
||||
} // namespace base64_encoding
|
||||
} // namespace ciphers
|
||||
|
||||
/**
|
||||
* @brief Self test-implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// 1st Test
|
||||
std::string str =
|
||||
"To err is human, but to really foul things up you need a computer.";
|
||||
std::string base64_str = ciphers::base64_encoding::base64_encode(str);
|
||||
std::string verify =
|
||||
"VG8gZXJyIGlzIGh1bWFuLCBidXQgdG8gcmVhbGx5IGZvdWwgdGhpbmdzIHVwIHlvdSBuZW"
|
||||
"VkIGEgY29tcHV0ZXIu";
|
||||
// verify encoding
|
||||
assert(base64_str == verify);
|
||||
std::string original_str =
|
||||
ciphers::base64_encoding::base64_decode(base64_str);
|
||||
// verify decoding
|
||||
assert(original_str == str);
|
||||
|
||||
// 2nd Test from [Wikipedia](https://en.wikipedia.org/wiki/Base64)
|
||||
str =
|
||||
"Man is distinguished, not only by his reason, but by this singular "
|
||||
"passion from other animals, which is a lust of the mind, that by a "
|
||||
"perseverance of delight in the continued and indefatigable generation "
|
||||
"of knowledge, exceeds the short vehemence of any carnal pleasure.";
|
||||
|
||||
base64_str = ciphers::base64_encoding::base64_encode(str);
|
||||
verify =
|
||||
"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieS"
|
||||
"B0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBh"
|
||||
"IGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodC"
|
||||
"BpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25v"
|
||||
"d2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbG"
|
||||
"Vhc3VyZS4=";
|
||||
// verify encoding
|
||||
assert(base64_str == verify);
|
||||
original_str = ciphers::base64_encoding::base64_decode(base64_str);
|
||||
// verify decoding
|
||||
assert(original_str == str);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* @file caesar_cipher.cpp
|
||||
* @brief Implementation of [Caesar cipher](https://en.wikipedia.org/wiki/Caesar_cipher) algorithm.
|
||||
*
|
||||
* @details
|
||||
* In cryptography, a Caesar cipher, also known as Caesar's cipher, the shift cipher,
|
||||
* Caesar's code or Caesar shift, is one of the simplest and most widely known encryption
|
||||
* techniques. It is a type of substitution cipher in which each letter in the plaintext
|
||||
* is replaced by a letter some fixed number of positions down the alphabet. For example,
|
||||
* with a left shift of 3, D would be replaced by A, E would become B, and so on.
|
||||
* The method is named after Julius Caesar, who used it in his private correspondence.
|
||||
*
|
||||
* ### Algorithm
|
||||
* The encryption can also be represented using modular arithmetic by first transforming
|
||||
* the letters into numbers, according to the scheme, A → 0, B → 1, ..., Z → 25.
|
||||
* Encryption of a letter x by a shift n can be described mathematically as,
|
||||
* \f[ E(x) = (x + n)\;\mbox{mod}\; 26\f]
|
||||
* while decryption can be described as,
|
||||
* \f[ D(x) = (x - n) \;\mbox{mod}\; 26\f]
|
||||
*
|
||||
* \note This program implements caesar cipher for only uppercase English alphabet characters (i.e. A-Z).
|
||||
*
|
||||
* @author [Deep Raval](https://github.com/imdeep2905)
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
/** \namespace ciphers
|
||||
* \brief Algorithms for encryption and decryption
|
||||
*/
|
||||
namespace ciphers {
|
||||
/** \namespace caesar
|
||||
* \brief Functions for [Caesar cipher](https://en.wikipedia.org/wiki/Caesar_cipher) algorithm.
|
||||
*/
|
||||
namespace caesar {
|
||||
namespace {
|
||||
/**
|
||||
* This function finds character for given value (i.e.A-Z)
|
||||
* @param x value for which we want character
|
||||
* @returns corresponding character for perticular value
|
||||
*/
|
||||
inline char get_char(const int x) {
|
||||
// By adding 65 we are scaling 0-25 to 65-90.
|
||||
// Which are in fact ASCII values of A-Z.
|
||||
return char(x + 65);
|
||||
}
|
||||
/**
|
||||
* This function finds value for given character (i.e.0-25)
|
||||
* @param c character for which we want value
|
||||
* @returns returns corresponding value for perticular character
|
||||
*/
|
||||
inline int get_value(const char c) {
|
||||
// A-Z have ASCII values in range 65-90.
|
||||
// Hence subtracting 65 will scale them to 0-25.
|
||||
return int(c - 65);
|
||||
}
|
||||
} // Unnamed namespace
|
||||
/**
|
||||
* Encrypt given text using caesar cipher.
|
||||
* @param text text to be encrypted
|
||||
* @param shift number of shifts to be applied
|
||||
* @returns new encrypted text
|
||||
*/
|
||||
std::string encrypt (const std::string &text, const int &shift) {
|
||||
std::string encrypted_text = ""; // Empty string to store encrypted text
|
||||
for (char c : text) { // Going through each character
|
||||
int place_value = get_value(c); // Getting value of character (i.e. 0-25)
|
||||
place_value = (place_value + shift) % 26; // Applying encryption formula
|
||||
char new_char = get_char(place_value); // Getting new character from new value (i.e. A-Z)
|
||||
encrypted_text += new_char; // Appending encrypted character
|
||||
}
|
||||
return encrypted_text; // Returning encrypted text
|
||||
}
|
||||
/**
|
||||
* Decrypt given text using caesar cipher.
|
||||
* @param text text to be decrypted
|
||||
* @param shift number of shifts to be applied
|
||||
* @returns new decrypted text
|
||||
*/
|
||||
std::string decrypt (const std::string &text, const int &shift) {
|
||||
std::string decrypted_text = ""; // Empty string to store decrypted text
|
||||
for (char c : text) { // Going through each character
|
||||
int place_value = get_value(c); // Getting value of character (i.e. 0-25)
|
||||
place_value = (place_value - shift) % 26;// Applying decryption formula
|
||||
if(place_value < 0) { // Handling case where remainder is negative
|
||||
place_value = place_value + 26;
|
||||
}
|
||||
char new_char = get_char(place_value); // Getting original character from decrypted value (i.e. A-Z)
|
||||
decrypted_text += new_char; // Appending decrypted character
|
||||
}
|
||||
return decrypted_text; // Returning decrypted text
|
||||
}
|
||||
} // namespace caesar
|
||||
} // namespace ciphers
|
||||
|
||||
/**
|
||||
* Function to test above algorithm
|
||||
*/
|
||||
void test() {
|
||||
// Test 1
|
||||
std::string text1 = "ALANTURING";
|
||||
std::string encrypted1 = ciphers::caesar::encrypt(text1, 17);
|
||||
std::string decrypted1 = ciphers::caesar::decrypt(encrypted1, 17);
|
||||
assert(text1 == decrypted1);
|
||||
std::cout << "Original text : " << text1;
|
||||
std::cout << " , Encrypted text (with shift = 21) : " << encrypted1;
|
||||
std::cout << " , Decrypted text : "<< decrypted1 << std::endl;
|
||||
// Test 2
|
||||
std::string text2 = "HELLOWORLD";
|
||||
std::string encrypted2 = ciphers::caesar::encrypt(text2, 1729);
|
||||
std::string decrypted2 = ciphers::caesar::decrypt(encrypted2, 1729);
|
||||
assert(text2 == decrypted2);
|
||||
std::cout << "Original text : " << text2;
|
||||
std::cout << " , Encrypted text (with shift = 1729) : " << encrypted2;
|
||||
std::cout << " , Decrypted text : "<< decrypted2 << std::endl;
|
||||
}
|
||||
|
||||
/** Driver Code */
|
||||
int main() {
|
||||
// Testing
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of [Elliptic Curve Diffie Hellman Key
|
||||
* Exchange](https://cryptobook.nakov.com/asymmetric-key-ciphers/ecdh-key-exchange).
|
||||
*
|
||||
* @details
|
||||
* The ECDH (Elliptic Curve Diffie–Hellman Key Exchange) is anonymous key
|
||||
* agreement scheme, which allows two parties, each having an elliptic-curve
|
||||
* public–private key pair, to establish a shared secret over an insecure
|
||||
* channel.
|
||||
* ECDH is very similar to the classical DHKE (Diffie–Hellman Key Exchange)
|
||||
* algorithm, but it uses ECC point multiplication instead of modular
|
||||
* exponentiations. ECDH is based on the following property of EC points:
|
||||
* (a * G) * b = (b * G) * a
|
||||
* If we have two secret numbers a and b (two private keys, belonging to Alice
|
||||
* and Bob) and an ECC elliptic curve with generator point G, we can exchange
|
||||
* over an insecure channel the values (a * G) and (b * G) (the public keys of
|
||||
* Alice and Bob) and then we can derive a shared secret:
|
||||
* secret = (a * G) * b = (b * G) * a.
|
||||
* Pretty simple. The above equation takes the following form:
|
||||
* alicePubKey * bobPrivKey = bobPubKey * alicePrivKey = secret
|
||||
* @author [Ashish Daulatabad](https://github.com/AshishYUO)
|
||||
*/
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
#include "uint256_t.hpp" /// for 256-bit integer
|
||||
|
||||
/**
|
||||
* @namespace ciphers
|
||||
* @brief Cipher algorithms
|
||||
*/
|
||||
namespace ciphers {
|
||||
/**
|
||||
* @brief namespace elliptic_curve_key_exchange
|
||||
* @details Demonstration of [Elliptic Curve
|
||||
* Diffie-Hellman](https://cryptobook.nakov.com/asymmetric-key-ciphers/ecdh-key-exchange)
|
||||
* key exchange.
|
||||
*/
|
||||
namespace elliptic_curve_key_exchange {
|
||||
|
||||
/**
|
||||
* @brief Definition of struct Point
|
||||
* @details Definition of Point in the curve.
|
||||
*/
|
||||
typedef struct Point {
|
||||
uint256_t x, y; /// x and y co-ordinates
|
||||
|
||||
/**
|
||||
* @brief operator == for Point
|
||||
* @details check whether co-ordinates are equal to the given point
|
||||
* @param p given point to be checked with this
|
||||
* @returns true if x and y are both equal with Point p, else false
|
||||
*/
|
||||
inline bool operator==(const Point &p) { return x == p.x && y == p.y; }
|
||||
|
||||
/**
|
||||
* @brief ostream operator for printing Point
|
||||
* @param op ostream operator
|
||||
* @param p Point to be printed on console
|
||||
* @returns op, the ostream object
|
||||
*/
|
||||
friend std::ostream &operator<<(std::ostream &op, const Point &p) {
|
||||
op << p.x << " " << p.y;
|
||||
return op;
|
||||
}
|
||||
} Point;
|
||||
|
||||
/**
|
||||
* @brief This function calculates number raised to exponent power under modulo
|
||||
* mod using [Modular
|
||||
* Exponentiation](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/math/modular_exponentiation.cpp).
|
||||
* @param number integer base
|
||||
* @param power unsigned integer exponent
|
||||
* @param mod integer modulo
|
||||
* @return number raised to power modulo mod
|
||||
*/
|
||||
uint256_t exp(uint256_t number, uint256_t power, const uint256_t &mod) {
|
||||
if (!power) {
|
||||
return uint256_t(1);
|
||||
}
|
||||
uint256_t ans(1);
|
||||
number = number % mod;
|
||||
while (power) {
|
||||
if ((power & 1)) {
|
||||
ans = (ans * number) % mod;
|
||||
}
|
||||
power >>= 1;
|
||||
if (power) {
|
||||
number = (number * number) % mod;
|
||||
}
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Addition of points
|
||||
* @details Add given point to generate third point. More description can be
|
||||
* found
|
||||
* [here](https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Point_addition),
|
||||
* and
|
||||
* [here](https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Point_doubling)
|
||||
* @param a First point
|
||||
* @param b Second point
|
||||
* @param curve_a_coeff Coefficient `a` of the given curve (y^2 = x^3 + ax + b)
|
||||
* % mod
|
||||
* @param mod Given field
|
||||
* @return the resultant point
|
||||
*/
|
||||
Point addition(Point a, Point b, const uint256_t &curve_a_coeff,
|
||||
uint256_t mod) {
|
||||
uint256_t lambda(0); /// Slope
|
||||
uint256_t zero(0); /// value zero
|
||||
lambda = zero = 0;
|
||||
uint256_t inf = ~zero;
|
||||
if (a.x != b.x || a.y != b.y) {
|
||||
// Slope being infinite.
|
||||
if (b.x == a.x) {
|
||||
return {inf, inf};
|
||||
}
|
||||
uint256_t num = (b.y - a.y + mod), den = (b.x - a.x + mod);
|
||||
lambda = (num * (exp(den, mod - 2, mod))) % mod;
|
||||
} else {
|
||||
/**
|
||||
* slope when the line is tangent to curve. This operation is performed
|
||||
* while doubling. Taking derivative of `y^2 = x^3 + ax + b`
|
||||
* => `2y dy = (3 * x^2 + a)dx`
|
||||
* => `(dy/dx) = (3x^2 + a)/(2y)`
|
||||
*/
|
||||
/**
|
||||
* if y co-ordinate is zero, the slope is infinite, return inf.
|
||||
* else calculate the slope (here % mod and store in lambda)
|
||||
*/
|
||||
if (!a.y) {
|
||||
return {inf, inf};
|
||||
}
|
||||
uint256_t axsq = ((a.x * a.x)) % mod;
|
||||
// Mulitply by 3 adjustment
|
||||
axsq += (axsq << 1);
|
||||
axsq %= mod;
|
||||
// Mulitply by 2 adjustment
|
||||
uint256_t a_2 = (a.y << 1);
|
||||
lambda =
|
||||
(((axsq + curve_a_coeff) % mod) * exp(a_2, mod - 2, mod)) % mod;
|
||||
}
|
||||
Point c;
|
||||
// new point: x = ((lambda^2) - x1 - x2)
|
||||
// y = (lambda * (x1 - x)) - y1
|
||||
c.x = ((lambda * lambda) % mod + (mod << 1) - a.x - b.x) % mod;
|
||||
c.y = (((lambda * (a.x + mod - c.x)) % mod) + mod - a.y) % mod;
|
||||
return c;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief multiply Point and integer
|
||||
* @details Multiply Point by a scalar factor (here it is a private key p). The
|
||||
* multiplication is called as [double and add
|
||||
* method](https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Double-and-add)
|
||||
* @param a Point to multiply
|
||||
* @param curve_a_coeff Coefficient of given curve (y^2 = x^3 + ax + b) % mod
|
||||
* @param p The scalar value
|
||||
* @param mod Given field
|
||||
* @returns the resultant point
|
||||
*/
|
||||
Point multiply(const Point &a, const uint256_t &curve_a_coeff, uint256_t p,
|
||||
const uint256_t &mod) {
|
||||
Point N = a;
|
||||
N.x %= mod;
|
||||
N.y %= mod;
|
||||
uint256_t inf{};
|
||||
inf = ~uint256_t(0);
|
||||
Point Q = {inf, inf};
|
||||
while (p) {
|
||||
if ((p & 1)) {
|
||||
if (Q.x == inf && Q.y == inf) {
|
||||
Q.x = N.x;
|
||||
Q.y = N.y;
|
||||
} else {
|
||||
Q = addition(Q, N, curve_a_coeff, mod);
|
||||
}
|
||||
}
|
||||
p >>= 1;
|
||||
if (p) {
|
||||
N = addition(N, N, curve_a_coeff, mod);
|
||||
}
|
||||
}
|
||||
return Q;
|
||||
}
|
||||
} // namespace elliptic_curve_key_exchange
|
||||
} // namespace ciphers
|
||||
|
||||
/**
|
||||
* @brief Function to test the
|
||||
* uint128_t header
|
||||
* @returns void
|
||||
*/
|
||||
static void uint128_t_tests() {
|
||||
// 1st test: Operations test
|
||||
uint128_t a("122"), b("2312");
|
||||
assert(a + b == 2434);
|
||||
assert(b - a == 2190);
|
||||
assert(a * b == 282064);
|
||||
assert(b / a == 18);
|
||||
assert(b % a == 116);
|
||||
assert((a & b) == 8);
|
||||
assert((a | b) == 2426);
|
||||
assert((a ^ b) == 2418);
|
||||
assert((a << 64) == uint128_t("2250502776992565297152"));
|
||||
assert((b >> 7) == 18);
|
||||
|
||||
// 2nd test: Operations test
|
||||
a = uint128_t("12321421424232142122");
|
||||
b = uint128_t("23123212");
|
||||
assert(a + b == uint128_t("12321421424255265334"));
|
||||
assert(a - b == uint128_t("12321421424209018910"));
|
||||
assert(a * b == uint128_t("284910839733861759501135864"));
|
||||
assert(a / b == 532859423865LL);
|
||||
assert(a % b == 3887742);
|
||||
assert((a & b) == 18912520);
|
||||
assert((a | b) == uint128_t("12321421424236352814"));
|
||||
assert((a ^ b) == uint128_t("12321421424217440294"));
|
||||
assert((a << 64) == uint128_t("227290107637132170748078080907806769152"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to test the
|
||||
* uint256_t header
|
||||
* @returns void
|
||||
*/
|
||||
static void uint256_t_tests() {
|
||||
// 1st test: Operations test
|
||||
uint256_t a("122"), b("2312");
|
||||
assert(a + b == 2434);
|
||||
assert(b - a == 2190);
|
||||
assert(a * b == 282064);
|
||||
assert(b / a == 18);
|
||||
assert(b % a == 116);
|
||||
assert((a & b) == 8);
|
||||
assert((a | b) == 2426);
|
||||
assert((a ^ b) == 2418);
|
||||
assert((a << 64) == uint256_t("2250502776992565297152"));
|
||||
assert((b >> 7) == 18);
|
||||
|
||||
// 2nd test: Operations test
|
||||
a = uint256_t("12321423124513251424232142122");
|
||||
b = uint256_t("23124312431243243215354315132413213212");
|
||||
assert(a + b == uint256_t("23124312443564666339867566556645355334"));
|
||||
// Since a < b, the value is greater
|
||||
assert(a - b == uint256_t("115792089237316195423570985008687907853246860353"
|
||||
"221642219366742944204948568846"));
|
||||
assert(a * b == uint256_t("284924437928789743312147393953938013677909398222"
|
||||
"169728183872115864"));
|
||||
assert(b / a == uint256_t("1876756621"));
|
||||
assert(b % a == uint256_t("2170491202688962563936723450"));
|
||||
assert((a & b) == uint256_t("3553901085693256462344"));
|
||||
assert((a | b) == uint256_t("23124312443564662785966480863388892990"));
|
||||
assert((a ^ b) == uint256_t("23124312443564659232065395170132430646"));
|
||||
assert((a << 128) == uint256_t("4192763024643754272961909047609369343091683"
|
||||
"376561852756163540549632"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function to test the
|
||||
* provided algorithm above
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// demonstration of key exchange using curve secp112r1
|
||||
|
||||
// Equation of the form y^2 = (x^3 + ax + b) % P (here p is mod)
|
||||
uint256_t a("4451685225093714772084598273548424"),
|
||||
b("2061118396808653202902996166388514"),
|
||||
mod("4451685225093714772084598273548427");
|
||||
|
||||
// Generator value: is pre-defined for the given curve
|
||||
ciphers::elliptic_curve_key_exchange::Point ptr = {
|
||||
uint256_t("188281465057972534892223778713752"),
|
||||
uint256_t("3419875491033170827167861896082688")};
|
||||
|
||||
// Shared key generation.
|
||||
// For alice
|
||||
std::cout << "For alice:\n";
|
||||
// Alice's private key (can be generated randomly)
|
||||
uint256_t alice_private_key("164330438812053169644452143505618");
|
||||
ciphers::elliptic_curve_key_exchange::Point alice_public_key =
|
||||
multiply(ptr, a, alice_private_key, mod);
|
||||
std::cout << "\tPrivate key: " << alice_private_key << "\n";
|
||||
std::cout << "\tPublic Key: " << alice_public_key << std::endl;
|
||||
|
||||
// For Bob
|
||||
std::cout << "For Bob:\n";
|
||||
// Bob's private key (can be generated randomly)
|
||||
uint256_t bob_private_key("1959473333748537081510525763478373");
|
||||
ciphers::elliptic_curve_key_exchange::Point bob_public_key =
|
||||
multiply(ptr, a, bob_private_key, mod);
|
||||
std::cout << "\tPrivate key: " << bob_private_key << "\n";
|
||||
std::cout << "\tPublic Key: " << bob_public_key << std::endl;
|
||||
|
||||
// After public key exchange, create a shared key for communication.
|
||||
// create shared key:
|
||||
ciphers::elliptic_curve_key_exchange::Point alice_shared_key = multiply(
|
||||
bob_public_key, a,
|
||||
alice_private_key, mod),
|
||||
bob_shared_key = multiply(
|
||||
alice_public_key, a,
|
||||
bob_private_key, mod);
|
||||
|
||||
std::cout << "Shared keys:\n";
|
||||
std::cout << alice_shared_key << std::endl;
|
||||
std::cout << bob_shared_key << std::endl;
|
||||
|
||||
// Check whether shared keys are equal
|
||||
assert(alice_shared_key == bob_shared_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
uint128_t_tests(); // running predefined 128-bit unsigned integer tests
|
||||
uint256_t_tests(); // running predefined 256-bit unsigned integer tests
|
||||
test(); // running self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,543 @@
|
||||
/**
|
||||
* @file hill_cipher.cpp
|
||||
* @brief Implementation of [Hill
|
||||
* cipher](https://en.wikipedia.org/wiki/Hill_cipher) algorithm.
|
||||
*
|
||||
* Program to generate the encryption-decryption key and perform encryption and
|
||||
* decryption of ASCII text using the famous block cipher algorithm. This is a
|
||||
* powerful encryption algorithm that is relatively easy to implement with a
|
||||
* given key. The strength of the algorithm depends on the size of the block
|
||||
* encryption matrix key; the bigger the matrix, the stronger the encryption and
|
||||
* more difficult to break it. However, the important requirement for the matrix
|
||||
* is that:
|
||||
* 1. matrix should be invertible - all inversion conditions should be satisfied
|
||||
* and
|
||||
* 2. its determinant must not have any common factors with the length of
|
||||
* character set
|
||||
* Due to this restriction, most implementations only implement with small 3x3
|
||||
* encryption keys and a small subset of ASCII alphabets.
|
||||
*
|
||||
* In the current implementation, I present to you an implementation for
|
||||
* generating larger encryption keys (I have attempted upto 10x10) and an ASCII
|
||||
* character set of 97 printable characters. Hence, a typical ASCII text file
|
||||
* could be easily encrypted with the module. The larger character set increases
|
||||
* the modulo of cipher and hence the matrix determinants can get very large
|
||||
* very quickly rendering them ill-defined.
|
||||
*
|
||||
* \note This program uses determinant computation using LU decomposition from
|
||||
* the file lu_decomposition.h
|
||||
* \note The matrix generation algorithm is very rudimentary and does not
|
||||
* guarantee an invertible modulus matrix. \todo Better matrix generation
|
||||
* algorithm.
|
||||
*
|
||||
* @author [Krishna Vedala](https://github.com/kvedala)
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#include "../numerical_methods/lu_decomposition.h"
|
||||
|
||||
/**
|
||||
* operator to print a matrix
|
||||
*/
|
||||
template <typename T>
|
||||
static std::ostream &operator<<(std::ostream &out, matrix<T> const &v) {
|
||||
const int width = 15;
|
||||
const char separator = ' ';
|
||||
|
||||
for (size_t row = 0; row < v.size(); row++) {
|
||||
for (size_t col = 0; col < v[row].size(); col++)
|
||||
out << std::left << std::setw(width) << std::setfill(separator)
|
||||
<< v[row][col];
|
||||
out << std::endl;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/** \namespace ciphers
|
||||
* \brief Algorithms for encryption and decryption
|
||||
*/
|
||||
namespace ciphers {
|
||||
/** dictionary of characters that can be encrypted and decrypted */
|
||||
static const char *STRKEY =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~!@#$%^&"
|
||||
"*()_+`-=[]{}|;':\",./<>?\\\r\n \0";
|
||||
|
||||
/**
|
||||
* @brief Implementation of [Hill
|
||||
* Cipher](https://en.wikipedia.org/wiki/Hill_cipher) algorithm
|
||||
*/
|
||||
class HillCipher {
|
||||
private:
|
||||
/**
|
||||
* @brief Function to generate a random integer in a given interval
|
||||
*
|
||||
* @param a lower limit of interval
|
||||
* @param b upper limit of interval
|
||||
* @tparam T type of output
|
||||
* @return random integer in the interval \f$[a,b)\f$
|
||||
*/
|
||||
template <typename T1, typename T2>
|
||||
static const T2 rand_range(T1 a, T1 b) {
|
||||
// generate random number between 0 and 1
|
||||
long double r = static_cast<long double>(std::rand()) / RAND_MAX;
|
||||
|
||||
// scale and return random number as integer
|
||||
return static_cast<T2>(r * (b - a) + a);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function overload to fill a matrix with random integers in a given
|
||||
* interval
|
||||
*
|
||||
* @param M pointer to matrix to be filled with random numbers
|
||||
* @param a lower limit of interval
|
||||
* @param b upper limit of interval
|
||||
* @tparam T1 type of input range
|
||||
* @tparam T2 type of matrix
|
||||
* @return determinant of generated random matrix
|
||||
*
|
||||
* @warning There will need to be a balance between the matrix size and the
|
||||
* range of random numbers. If the matrix is large, the range of random
|
||||
* numbers must be small to have a well defined keys. Or if the matrix is
|
||||
* smaller, the random numbers range can be larger. For an 8x8 matrix, range
|
||||
* should be no more than \f$[0,10]\f$
|
||||
*/
|
||||
template <typename T1, typename T2>
|
||||
static double rand_range(matrix<T2> *M, T1 a, T1 b) {
|
||||
for (size_t i = 0; i < M->size(); i++) {
|
||||
for (size_t j = 0; j < M[0][0].size(); j++) {
|
||||
M[0][i][j] = rand_range<T1, T2>(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
return determinant_lu(*M);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compute
|
||||
* [GCD](https://en.wikipedia.org/wiki/Greatest_common_divisor) of two
|
||||
* integers using Euler's algorithm
|
||||
*
|
||||
* @param a first number
|
||||
* @param b second number
|
||||
* @return GCD of \f$a\f$ and \f$b\f$
|
||||
*/
|
||||
template <typename T>
|
||||
static const T gcd(T a, T b) {
|
||||
if (b > a) // ensure always a < b
|
||||
std::swap(a, b);
|
||||
|
||||
while (b != 0) {
|
||||
T tmp = b;
|
||||
b = a % b;
|
||||
a = tmp;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief helper function to perform vector multiplication with encryption
|
||||
* or decryption matrix
|
||||
*
|
||||
* @param vector vector to multiply
|
||||
* @param key encryption or decryption key matrix
|
||||
* @return corresponding encrypted or decrypted text
|
||||
*/
|
||||
static const std::valarray<uint8_t> mat_mul(
|
||||
const std::valarray<uint8_t> &vector, const matrix<int> &key) {
|
||||
std::valarray<uint8_t> out(vector); // make a copy
|
||||
|
||||
size_t L = std::strlen(STRKEY);
|
||||
|
||||
for (size_t i = 0; i < key.size(); i++) {
|
||||
int tmp = 0;
|
||||
for (size_t j = 0; j < vector.size(); j++) {
|
||||
tmp += key[i][j] * vector[j];
|
||||
}
|
||||
out[i] = static_cast<uint8_t>(tmp % L);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the character at a given index in the ::STRKEY
|
||||
*
|
||||
* @param idx index value
|
||||
* @return character at the index
|
||||
*/
|
||||
static inline char get_idx_char(const uint8_t idx) { return STRKEY[idx]; }
|
||||
|
||||
/**
|
||||
* @brief Get the index of a character in the ::STRKEY
|
||||
*
|
||||
* @param ch character to search
|
||||
* @return index of character
|
||||
*/
|
||||
static inline uint8_t get_char_idx(const char ch) {
|
||||
size_t L = std::strlen(STRKEY);
|
||||
|
||||
for (size_t idx = 0; idx <= L; idx++)
|
||||
if (STRKEY[idx] == ch)
|
||||
return idx;
|
||||
|
||||
std::cerr << __func__ << ":" << __LINE__ << ": (" << ch
|
||||
<< ") Should not reach here!\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convenience function to perform block cipher operations. The
|
||||
* operations are identical for both encryption and decryption.
|
||||
*
|
||||
* @param text input text to encrypt or decrypt
|
||||
* @param key key for encryption or decryption
|
||||
* @return encrypted/decrypted output
|
||||
*/
|
||||
static const std::string codec(const std::string &text,
|
||||
const matrix<int> &key) {
|
||||
size_t text_len = text.length();
|
||||
size_t key_len = key.size();
|
||||
|
||||
// length of output string must be a multiple of key_len
|
||||
// create output string and initialize with '\0' character
|
||||
size_t L2 = text_len % key_len == 0
|
||||
? text_len
|
||||
: text_len + key_len - (text_len % key_len);
|
||||
std::string coded_text(L2, '\0');
|
||||
|
||||
// temporary array for batch processing
|
||||
int i;
|
||||
#ifdef _OPENMP
|
||||
#pragma parallel omp for private(i)
|
||||
#endif
|
||||
for (i = 0; i < L2 - key_len + 1; i += key_len) {
|
||||
std::valarray<uint8_t> batch_int(key_len);
|
||||
for (size_t j = 0; j < key_len; j++) {
|
||||
batch_int[j] = get_char_idx(text[i + j]);
|
||||
}
|
||||
|
||||
batch_int = mat_mul(batch_int, key);
|
||||
|
||||
for (size_t j = 0; j < key_len; j++) {
|
||||
coded_text[i + j] =
|
||||
STRKEY[batch_int[j]]; // get character at key
|
||||
}
|
||||
}
|
||||
|
||||
return coded_text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get matrix inverse using Row-transformations. Given matrix must
|
||||
* be a square and non-singular.
|
||||
* \returns inverse matrix
|
||||
**/
|
||||
template <typename T>
|
||||
static matrix<double> get_inverse(matrix<T> const &A) {
|
||||
// Assuming A is square matrix
|
||||
size_t N = A.size();
|
||||
|
||||
matrix<double> inverse(N, std::valarray<double>(N));
|
||||
for (size_t row = 0; row < N; row++) {
|
||||
for (size_t col = 0; col < N; col++) {
|
||||
// create identity matrix
|
||||
inverse[row][col] = (row == col) ? 1.f : 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
if (A.size() != A[0].size()) {
|
||||
std::cerr << "A must be a square matrix!" << std::endl;
|
||||
return inverse;
|
||||
}
|
||||
|
||||
// preallocate a temporary matrix identical to A
|
||||
matrix<double> temp(N, std::valarray<double>(N));
|
||||
for (size_t row = 0; row < N; row++) {
|
||||
for (size_t col = 0; col < N; col++)
|
||||
temp[row][col] = static_cast<double>(A[row][col]);
|
||||
}
|
||||
|
||||
// start transformations
|
||||
for (size_t row = 0; row < N; row++) {
|
||||
for (size_t row2 = row; row2 < N && temp[row][row] == 0; row2++) {
|
||||
// this to ensure diagonal elements are not 0
|
||||
temp[row] = temp[row] + temp[row2];
|
||||
inverse[row] = inverse[row] + inverse[row2];
|
||||
}
|
||||
|
||||
for (size_t col2 = row; col2 < N && temp[row][row] == 0; col2++) {
|
||||
// this to further ensure diagonal elements are not 0
|
||||
for (size_t row2 = 0; row2 < N; row2++) {
|
||||
temp[row2][row] = temp[row2][row] + temp[row2][col2];
|
||||
inverse[row2][row] =
|
||||
inverse[row2][row] + inverse[row2][col2];
|
||||
}
|
||||
}
|
||||
|
||||
if (temp[row][row] == 0) {
|
||||
// Probably a low-rank matrix and hence singular
|
||||
std::cerr << "Low-rank matrix, no inverse!" << std::endl;
|
||||
return inverse;
|
||||
}
|
||||
|
||||
// set diagonal to 1
|
||||
double divisor = temp[row][row];
|
||||
temp[row] = temp[row] / divisor;
|
||||
inverse[row] = inverse[row] / divisor;
|
||||
// Row transformations
|
||||
for (size_t row2 = 0; row2 < N; row2++) {
|
||||
if (row2 == row)
|
||||
continue;
|
||||
double factor = temp[row2][row];
|
||||
temp[row2] = temp[row2] - factor * temp[row];
|
||||
inverse[row2] = inverse[row2] - factor * inverse[row];
|
||||
}
|
||||
}
|
||||
|
||||
return inverse;
|
||||
}
|
||||
|
||||
static int modulo(int a, int b) {
|
||||
int ret = a % b;
|
||||
if (ret < 0)
|
||||
ret += b;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Generate encryption matrix of a given size. Larger size matrices
|
||||
* are difficult to generate but provide more security. Important conditions
|
||||
* are:
|
||||
* 1. matrix should be invertible
|
||||
* 2. determinant must not have any common factors with the length of
|
||||
* character key
|
||||
* There is no head-fast way to generate hte matrix under the given
|
||||
* numerical restrictions of the machine but the conditions added achieve
|
||||
* the goals. Bigger the matrix, greater is the probability of the matrix
|
||||
* being ill-defined.
|
||||
*
|
||||
* @param size size of matrix (typically \f$\text{size}\le10\f$)
|
||||
* @param limit1 lower limit of range of random elements (default=0)
|
||||
* @param limit2 upper limit of range of random elements (default=10)
|
||||
* @return Encryption martix
|
||||
*/
|
||||
static matrix<int> generate_encryption_key(size_t size, int limit1 = 0,
|
||||
int limit2 = 10) {
|
||||
matrix<int> encrypt_key(size, std::valarray<int>(size));
|
||||
matrix<int> min_mat = encrypt_key;
|
||||
int mat_determinant = -1; // because matrix has only ints, the
|
||||
// determinant will also be an int
|
||||
int L = std::strlen(STRKEY);
|
||||
|
||||
double dd;
|
||||
do {
|
||||
// keeping the random number range smaller generates better
|
||||
// defined matrices with more ease of cracking
|
||||
dd = rand_range(&encrypt_key, limit1, limit2);
|
||||
mat_determinant = static_cast<int>(dd);
|
||||
|
||||
if (mat_determinant < 0)
|
||||
mat_determinant = (mat_determinant % L);
|
||||
} while (std::abs(dd) > 1e3 || // while ill-defined
|
||||
dd < 0.1 || // while singular or negative determinant
|
||||
!std::isfinite(dd) || // while determinant is not finite
|
||||
gcd(mat_determinant, L) != 1); // while no common factors
|
||||
// std::cout <<
|
||||
|
||||
return encrypt_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generate decryption matrix from an encryption matrix key.
|
||||
*
|
||||
* @param encrypt_key encryption key for which to create a decrypt key
|
||||
* @return Decryption martix
|
||||
*/
|
||||
static matrix<int> generate_decryption_key(matrix<int> const &encrypt_key) {
|
||||
size_t size = encrypt_key.size();
|
||||
int L = std::strlen(STRKEY);
|
||||
|
||||
matrix<int> decrypt_key(size, std::valarray<int>(size));
|
||||
int det_encrypt = static_cast<int>(determinant_lu(encrypt_key));
|
||||
|
||||
int mat_determinant = det_encrypt < 0 ? det_encrypt % L : det_encrypt;
|
||||
|
||||
matrix<double> tmp_inverse = get_inverse(encrypt_key);
|
||||
|
||||
// find co-prime factor for inversion
|
||||
int det_inv = -1;
|
||||
for (int i = 0; i < L; i++) {
|
||||
if (modulo(mat_determinant * i, L) == 1) {
|
||||
det_inv = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (det_inv == -1) {
|
||||
std::cerr << "Could not find a co-prime for inversion\n";
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
mat_determinant = det_inv * det_encrypt;
|
||||
|
||||
// perform modular inverse of encryption matrix
|
||||
int i;
|
||||
#ifdef _OPENMP
|
||||
#pragma parallel omp for private(i)
|
||||
#endif
|
||||
for (i = 0; i < size; i++) {
|
||||
for (int j = 0; j < size; j++) {
|
||||
int temp = std::round(tmp_inverse[i][j] * mat_determinant);
|
||||
decrypt_key[i][j] = modulo(temp, L);
|
||||
}
|
||||
}
|
||||
return decrypt_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Generate encryption and decryption key pair
|
||||
*
|
||||
* @param size size of matrix key (typically \f$\text{size}\le10\f$)
|
||||
* @param limit1 lower limit of range of random elements (default=0)
|
||||
* @param limit2 upper limit of range of random elements (default=10)
|
||||
* @return std::pair<matrix<int>, matrix<int>> encryption and decryption
|
||||
* keys as a pair
|
||||
*
|
||||
* @see ::generate_encryption_key
|
||||
*/
|
||||
static std::pair<matrix<int>, matrix<int>> generate_keys(size_t size,
|
||||
int limit1 = 0,
|
||||
int limit2 = 10) {
|
||||
matrix<int> encrypt_key = generate_encryption_key(size);
|
||||
matrix<int> decrypt_key = generate_decryption_key(encrypt_key);
|
||||
double det2 = determinant_lu(decrypt_key);
|
||||
while (std::abs(det2) < 0.1 || std::abs(det2) > 1e3) {
|
||||
encrypt_key = generate_encryption_key(size, limit1, limit2);
|
||||
decrypt_key = generate_decryption_key(encrypt_key);
|
||||
det2 = determinant_lu(decrypt_key);
|
||||
}
|
||||
return std::make_pair(encrypt_key, decrypt_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Encrypt a given text using a given key
|
||||
*
|
||||
* @param text string to encrypt
|
||||
* @param encrypt_key key for encryption
|
||||
* @return encrypted text
|
||||
*/
|
||||
static const std::string encrypt_text(const std::string &text,
|
||||
const matrix<int> &encrypt_key) {
|
||||
return codec(text, encrypt_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decrypt a given text using a given key
|
||||
*
|
||||
* @param text string to decrypt
|
||||
* @param decrypt_key key for decryption
|
||||
* @return decrypted text
|
||||
*/
|
||||
static const std::string decrypt_text(const std::string &text,
|
||||
const matrix<int> &decrypt_key) {
|
||||
return codec(text, decrypt_key);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ciphers
|
||||
|
||||
/**
|
||||
* @brief Self test 1 - using 3x3 randomly generated key
|
||||
*
|
||||
* @param text string to encrypt and decrypt
|
||||
*/
|
||||
void test1(const std::string &text) {
|
||||
// std::string text = "Hello world!";
|
||||
std::cout << "======Test 1 (3x3 key) ======\nOriginal text:\n\t" << text
|
||||
<< std::endl;
|
||||
|
||||
std::pair<matrix<int>, matrix<int>> p =
|
||||
ciphers::HillCipher::generate_keys(3, 0, 100);
|
||||
matrix<int> ekey = p.first;
|
||||
matrix<int> dkey = p.second;
|
||||
|
||||
// matrix<int> ekey = {{22, 28, 25}, {5, 26, 15}, {14, 18, 9}};
|
||||
// std::cout << "Encryption key: \n" << ekey;
|
||||
std::string gibberish = ciphers::HillCipher::encrypt_text(text, ekey);
|
||||
std::cout << "Encrypted text:\n\t" << gibberish << std::endl;
|
||||
|
||||
// matrix<int> dkey = ciphers::HillCipher::generate_decryption_key(ekey);
|
||||
// std::cout << "Decryption key: \n" << dkey;
|
||||
std::string txt_back = ciphers::HillCipher::decrypt_text(gibberish, dkey);
|
||||
std::cout << "Reconstruct text:\n\t" << txt_back << std::endl;
|
||||
|
||||
std::ofstream out_file("hill_cipher_test1.txt");
|
||||
out_file << "Block size: " << ekey.size() << "\n";
|
||||
out_file << "Encryption Key:\n" << ekey;
|
||||
out_file << "\nDecryption Key:\n" << dkey;
|
||||
out_file.close();
|
||||
|
||||
assert(txt_back == text);
|
||||
std::cout << "Passed :)\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Self test 2 - using 8x8 randomly generated key
|
||||
*
|
||||
* @param text string to encrypt and decrypt
|
||||
*/
|
||||
void test2(const std::string &text) {
|
||||
// std::string text = "Hello world!";
|
||||
std::cout << "======Test 2 (8x8 key) ======\nOriginal text:\n\t" << text
|
||||
<< std::endl;
|
||||
|
||||
std::pair<matrix<int>, matrix<int>> p =
|
||||
ciphers::HillCipher::generate_keys(8, 0, 3);
|
||||
matrix<int> ekey = p.first;
|
||||
matrix<int> dkey = p.second;
|
||||
|
||||
std::string gibberish = ciphers::HillCipher::encrypt_text(text, ekey);
|
||||
std::cout << "Encrypted text:\n\t" << gibberish << std::endl;
|
||||
|
||||
std::string txt_back = ciphers::HillCipher::decrypt_text(gibberish, dkey);
|
||||
std::cout << "Reconstruct text:\n\t" << txt_back << std::endl;
|
||||
|
||||
std::ofstream out_file("hill_cipher_test2.txt");
|
||||
out_file << "Block size: " << ekey.size() << "\n";
|
||||
out_file << "Encryption Key:\n" << ekey;
|
||||
out_file << "\nDecryption Key:\n" << dkey;
|
||||
out_file.close();
|
||||
|
||||
assert(txt_back.compare(0, text.size(), text) == 0);
|
||||
std::cout << "Passed :)\n";
|
||||
}
|
||||
|
||||
/** Main function */
|
||||
int main() {
|
||||
std::srand(std::time(nullptr));
|
||||
std::cout << "Key dictionary: (" << std::strlen(ciphers::STRKEY) << ")\n\t"
|
||||
<< ciphers::STRKEY << "\n";
|
||||
|
||||
std::string text = "This is a simple text with numb3r5 and exclamat!0n.";
|
||||
|
||||
test1(text);
|
||||
test2(text);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
/**
|
||||
* @file
|
||||
* @author [Deep Raval](https://github.com/imdeep2905)
|
||||
*
|
||||
* @brief Implementation of [Morse Code]
|
||||
* (https://en.wikipedia.org/wiki/Morse_code).
|
||||
*
|
||||
* @details
|
||||
* Morse code is a method used in telecommunication to encode text characters
|
||||
* as standardized sequences of two different signal durations, called dots
|
||||
* and dashes or dits and dahs. Morse code is named after Samuel Morse, an
|
||||
* inventor of the telegraph.
|
||||
*/
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/** \namespace ciphers
|
||||
* \brief Algorithms for encryption and decryption
|
||||
*/
|
||||
namespace ciphers {
|
||||
/** \namespace morse
|
||||
* \brief Functions for [Morse Code]
|
||||
* (https://en.wikipedia.org/wiki/Morse_code).
|
||||
*/
|
||||
namespace morse {
|
||||
/**
|
||||
* Get the morse representation for given character.
|
||||
* @param c Character
|
||||
* @returns morse representation string of character
|
||||
*/
|
||||
std::string char_to_morse(const char &c) {
|
||||
// return corresponding morse code
|
||||
switch (c) {
|
||||
case 'a':
|
||||
return ".-";
|
||||
case 'b':
|
||||
return "-...";
|
||||
case 'c':
|
||||
return "-.-.";
|
||||
case 'd':
|
||||
return "-..";
|
||||
case 'e':
|
||||
return ".";
|
||||
case 'f':
|
||||
return "..-.";
|
||||
case 'g':
|
||||
return "--.";
|
||||
case 'h':
|
||||
return "....";
|
||||
case 'i':
|
||||
return "..";
|
||||
case 'j':
|
||||
return ".---";
|
||||
case 'k':
|
||||
return "-.-";
|
||||
case 'l':
|
||||
return ".-..";
|
||||
case 'm':
|
||||
return "--";
|
||||
case 'n':
|
||||
return "-.";
|
||||
case 'o':
|
||||
return "---";
|
||||
case 'p':
|
||||
return ".--.";
|
||||
case 'q':
|
||||
return "--.-";
|
||||
case 'r':
|
||||
return ".-.";
|
||||
case 's':
|
||||
return "...";
|
||||
case 't':
|
||||
return "-";
|
||||
case 'u':
|
||||
return "..-";
|
||||
case 'v':
|
||||
return "...-";
|
||||
case 'w':
|
||||
return ".--";
|
||||
case 'x':
|
||||
return "-..-";
|
||||
case 'y':
|
||||
return "-.--";
|
||||
case 'z':
|
||||
return "--..";
|
||||
case '1':
|
||||
return ".----";
|
||||
case '2':
|
||||
return "..---";
|
||||
case '3':
|
||||
return "...--";
|
||||
case '4':
|
||||
return "....-";
|
||||
case '5':
|
||||
return ".....";
|
||||
case '6':
|
||||
return "-....";
|
||||
case '7':
|
||||
return "--...";
|
||||
case '8':
|
||||
return "---..";
|
||||
case '9':
|
||||
return "----.";
|
||||
case '0':
|
||||
return "-----";
|
||||
default:
|
||||
std::cerr << "Found invalid character: " << c << ' ' << std::endl;
|
||||
std::exit(0);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get character from the morse representation.
|
||||
* @param s Morse representation
|
||||
* @returns corresponding character
|
||||
*/
|
||||
char morse_to_char(const std::string &s) {
|
||||
// return corresponding character
|
||||
if (s == ".-") {
|
||||
return 'a';
|
||||
} else if (s == "-...") {
|
||||
return 'b';
|
||||
} else if (s == "-.-.") {
|
||||
return 'c';
|
||||
} else if (s == "-..") {
|
||||
return 'd';
|
||||
} else if (s == ".") {
|
||||
return 'e';
|
||||
} else if (s == "..-.") {
|
||||
return 'f';
|
||||
} else if (s == "--.") {
|
||||
return 'g';
|
||||
} else if (s == "....") {
|
||||
return 'h';
|
||||
} else if (s == "..") {
|
||||
return 'i';
|
||||
} else if (s == ".---") {
|
||||
return 'j';
|
||||
} else if (s == "-.-") {
|
||||
return 'k';
|
||||
} else if (s == ".-..") {
|
||||
return 'l';
|
||||
} else if (s == "--") {
|
||||
return 'm';
|
||||
} else if (s == "-.") {
|
||||
return 'n';
|
||||
} else if (s == "---") {
|
||||
return 'o';
|
||||
} else if (s == ".--.") {
|
||||
return 'p';
|
||||
} else if (s == "--.-") {
|
||||
return 'q';
|
||||
} else if (s == ".-.") {
|
||||
return 'r';
|
||||
} else if (s == "...") {
|
||||
return 's';
|
||||
} else if (s == "-") {
|
||||
return 't';
|
||||
} else if (s == "..-") {
|
||||
return 'u';
|
||||
} else if (s == "...-") {
|
||||
return 'v';
|
||||
} else if (s == ".--") {
|
||||
return 'w';
|
||||
} else if (s == "-..-") {
|
||||
return 'x';
|
||||
} else if (s == "-.--") {
|
||||
return 'y';
|
||||
} else if (s == "--..") {
|
||||
return 'z';
|
||||
} else if (s == ".----") {
|
||||
return '1';
|
||||
} else if (s == "..---") {
|
||||
return '2';
|
||||
} else if (s == "...--") {
|
||||
return '3';
|
||||
} else if (s == "....-") {
|
||||
return '4';
|
||||
} else if (s == ".....") {
|
||||
return '5';
|
||||
} else if (s == "-....") {
|
||||
return '6';
|
||||
} else if (s == "--...") {
|
||||
return '7';
|
||||
} else if (s == "---..") {
|
||||
return '8';
|
||||
} else if (s == "----.") {
|
||||
return '9';
|
||||
} else if (s == "-----") {
|
||||
return '0';
|
||||
} else {
|
||||
std::cerr << "Found invalid Morse code: " << s << ' ' << std::endl;
|
||||
std::exit(0);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Encrypt given text using morse code.
|
||||
* @param text text to be encrypted
|
||||
* @returns new encrypted text
|
||||
*/
|
||||
std::string encrypt(const std::string &text) {
|
||||
std::string encrypted_text = ""; // Empty string to store encrypted text
|
||||
// Going through each character of text and converting it
|
||||
// to morse representation
|
||||
for (const char &c : text) {
|
||||
encrypted_text += ciphers::morse::char_to_morse(c) + " ";
|
||||
}
|
||||
return encrypted_text; // Returning encrypted text
|
||||
}
|
||||
/**
|
||||
* Decrypt given morse coded text.
|
||||
* @param text text to be decrypted
|
||||
* @returns new decrypted text
|
||||
*/
|
||||
std::string decrypt(const std::string &text) {
|
||||
// Going through each character of text and converting it
|
||||
// back to normal representation.
|
||||
std::string decrypted_text = ""; // Empty string to store decrypted text
|
||||
// Spliting string (with delimiter = " ") and storing it
|
||||
// in vector
|
||||
std::size_t pos_start = 0, pos_end = 0, delim_len = 1;
|
||||
std::vector<std::string> splits;
|
||||
while ((pos_end = text.find(' ', pos_start)) != std::string::npos) {
|
||||
std::string token = text.substr(pos_start, pos_end - pos_start);
|
||||
pos_start = pos_end + delim_len;
|
||||
splits.push_back(token);
|
||||
}
|
||||
|
||||
// Traversing through each morse code string
|
||||
for (const std::string &s : splits) {
|
||||
// Add corresponding character
|
||||
decrypted_text += ciphers::morse::morse_to_char(s);
|
||||
}
|
||||
|
||||
return decrypted_text; // Returning decrypted text
|
||||
}
|
||||
} // namespace morse
|
||||
} // namespace ciphers
|
||||
|
||||
/**
|
||||
* @brief Function to test above algorithm
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// Test 1
|
||||
std::string text1 = "01234567890";
|
||||
std::string encrypted1 = ciphers::morse::encrypt(text1);
|
||||
std::string decrypted1 = ciphers::morse::decrypt(encrypted1);
|
||||
assert(text1 == decrypted1);
|
||||
std::cout << "Original text : " << text1 << std::endl;
|
||||
std::cout << "Encrypted text : " << encrypted1 << std::endl;
|
||||
std::cout << "Decrypted text : " << decrypted1 << std::endl;
|
||||
// Test 2
|
||||
std::string text2 = "abcdefghijklmnopqrstuvwxyz";
|
||||
std::string encrypted2 = ciphers::morse::encrypt(text2);
|
||||
std::string decrypted2 = ciphers::morse::decrypt(encrypted2);
|
||||
assert(text2 == decrypted2);
|
||||
std::cout << "Original text : " << text2 << std::endl;
|
||||
std::cout << "Encrypted text : " << encrypted2 << std::endl;
|
||||
std::cout << "Decrypted text : " << decrypted2 << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
// Testing
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* @file vigenere_cipher.cpp
|
||||
* @brief Implementation of [Vigenère cipher](https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher) algorithm.
|
||||
*
|
||||
* @details
|
||||
* The Vigenère cipher is a method of encrypting alphabetic text by using a series of interwoven vigenere
|
||||
* ciphers, based on the letters of a keyword. It employs a form of polyalphabetic substitution.
|
||||
*
|
||||
* ### Algorithm
|
||||
* The encryption can also be represented using modular arithmetic by first transforming
|
||||
* the letters into numbers, according to the scheme, A → 0, B → 1, ..., Z → 25.
|
||||
* Encryption of \f$i^{th}\f$ character in Message M by key K can be described mathematically as,
|
||||
*
|
||||
* \f[ E_{K}(M_{i}) = (M_{i} + K_{i})\;\mbox{mod}\; 26\f]
|
||||
*
|
||||
* while decryption of \f$i^{th}\f$ character in Cipher C by key K can be described mathematically as,
|
||||
*
|
||||
* \f[ D_{k}(C_{i}) = (C_{i} - K_{i} + 26)\;\mbox{mod}\; 26\f]
|
||||
*
|
||||
* Where \f$K_{i}\f$ denotes corresponding character in key. If \f$|key| < |text|\f$ than
|
||||
* same key is repeated untill their lengths are equal.
|
||||
*
|
||||
* For Example,
|
||||
* If M = "ATTACKATDAWN" and K = "LEMON" than K becomes "LEMONLEMONLE".
|
||||
*
|
||||
* \note Rather than creating new key of equal length this program does this by using modular index for key
|
||||
* (i.e. \f$(j + 1) \;\mbox{mod}\; |\mbox{key}|\f$)
|
||||
*
|
||||
* \note This program implements Vigenère cipher for only uppercase English alphabet characters (i.e. A-Z).
|
||||
*
|
||||
* @author [Deep Raval](https://github.com/imdeep2905)
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
/** \namespace ciphers
|
||||
* \brief Algorithms for encryption and decryption
|
||||
*/
|
||||
namespace ciphers {
|
||||
/** \namespace vigenere
|
||||
* \brief Functions for [vigenère cipher](https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher) algorithm.
|
||||
*/
|
||||
namespace vigenere {
|
||||
namespace {
|
||||
/**
|
||||
* This function finds character for given value (i.e.A-Z)
|
||||
* @param x value for which we want character
|
||||
* @return corresponding character for perticular value
|
||||
*/
|
||||
inline char get_char(const int x) {
|
||||
// By adding 65 we are scaling 0-25 to 65-90.
|
||||
// Which are in fact ASCII values of A-Z.
|
||||
return char(x + 65);
|
||||
}
|
||||
/**
|
||||
* This function finds value for given character (i.e.0-25)
|
||||
* @param c character for which we want value
|
||||
* @return returns corresponding value for perticular character
|
||||
*/
|
||||
inline int get_value(const char c) {
|
||||
// A-Z have ASCII values in range 65-90.
|
||||
// Hence subtracting 65 will scale them to 0-25.
|
||||
return int(c - 65);
|
||||
}
|
||||
} // Unnamed namespace
|
||||
/**
|
||||
* Encrypt given text using vigenere cipher.
|
||||
* @param text text to be encrypted
|
||||
* @param key to be used for encryption
|
||||
* @return new encrypted text
|
||||
*/
|
||||
std::string encrypt (const std::string &text, const std::string &key) {
|
||||
std::string encrypted_text = ""; // Empty string to store encrypted text
|
||||
// Going through each character of text and key
|
||||
// Note that key is visited in circular way hence j = (j + 1) % |key|
|
||||
for(size_t i = 0, j = 0; i < text.length(); i++, j = (j + 1) % key.length()) {
|
||||
int place_value_text = get_value(text[i]); // Getting value of character in text
|
||||
int place_value_key = get_value(key[j]); // Getting value of character in key
|
||||
place_value_text = (place_value_text + place_value_key) % 26; // Applying encryption
|
||||
char encrypted_char = get_char(place_value_text); // Getting new character from encrypted value
|
||||
encrypted_text += encrypted_char; // Appending encrypted character
|
||||
}
|
||||
return encrypted_text; // Returning encrypted text
|
||||
}
|
||||
/**
|
||||
* Decrypt given text using vigenere cipher.
|
||||
* @param text text to be decrypted
|
||||
* @param key key to be used for decryption
|
||||
* @return new decrypted text
|
||||
*/
|
||||
std::string decrypt (const std::string &text, const std::string &key) {
|
||||
// Going through each character of text and key
|
||||
// Note that key is visited in circular way hence j = (j + 1) % |key|
|
||||
std::string decrypted_text = ""; // Empty string to store decrypted text
|
||||
for(size_t i = 0, j = 0; i < text.length(); i++, j = (j + 1) % key.length()) {
|
||||
int place_value_text = get_value(text[i]); // Getting value of character in text
|
||||
int place_value_key = get_value(key[j]); // Getting value of character in key
|
||||
place_value_text = (place_value_text - place_value_key + 26) % 26; // Applying decryption
|
||||
char decrypted_char = get_char(place_value_text); // Getting new character from decrypted value
|
||||
decrypted_text += decrypted_char; // Appending decrypted character
|
||||
}
|
||||
return decrypted_text; // Returning decrypted text
|
||||
}
|
||||
} // namespace vigenere
|
||||
} // namespace ciphers
|
||||
|
||||
/**
|
||||
* Function to test above algorithm
|
||||
*/
|
||||
void test() {
|
||||
// Test 1
|
||||
std::string text1 = "NIKOLATESLA";
|
||||
std::string encrypted1 = ciphers::vigenere::encrypt(text1, "TESLA");
|
||||
std::string decrypted1 = ciphers::vigenere::decrypt(encrypted1, "TESLA");
|
||||
assert(text1 == decrypted1);
|
||||
std::cout << "Original text : " << text1;
|
||||
std::cout << " , Encrypted text (with key = TESLA) : " << encrypted1;
|
||||
std::cout << " , Decrypted text : "<< decrypted1 << std::endl;
|
||||
// Test 2
|
||||
std::string text2 = "GOOGLEIT";
|
||||
std::string encrypted2 = ciphers::vigenere::encrypt(text2, "REALLY");
|
||||
std::string decrypted2 = ciphers::vigenere::decrypt(encrypted2, "REALLY");
|
||||
assert(text2 == decrypted2);
|
||||
std::cout << "Original text : " << text2;
|
||||
std::cout << " , Encrypted text (with key = REALLY) : " << encrypted2;
|
||||
std::cout << " , Decrypted text : "<< decrypted2 << std::endl;
|
||||
}
|
||||
|
||||
/** Driver Code */
|
||||
int main() {
|
||||
// Testing
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* @file xor_cipher.cpp
|
||||
* @brief Implementation of [XOR cipher](https://en.wikipedia.org/wiki/XOR_cipher) algorithm.
|
||||
*
|
||||
* @details
|
||||
* In cryptography, the simple XOR cipher is a type of additive cipher, an encryption
|
||||
* algorithm that operates according to the principles:
|
||||
*
|
||||
* * \f$A {\oplus} 0 = A\f$
|
||||
* * \f$A {\oplus} A = 0\f$
|
||||
* * \f$ (A {\oplus} B) {\oplus} C = A {\oplus} (B {\oplus} C)\f$
|
||||
* * \f$ (B {\oplus} A) {\oplus} B = B {\oplus} 0 = B \f$
|
||||
*
|
||||
*
|
||||
* where \f$\oplus\f$ symbol denotes the exclusive disjunction (XOR) operation.
|
||||
* This operation is sometimes called modulus 2 addition (or subtraction, which is identical).
|
||||
* With this logic, a string of text can be encrypted by applying the bitwise XOR operator to
|
||||
* every character using a given key. To decrypt the output, merely reapplying the XOR function
|
||||
* with the key will remove the cipher.
|
||||
*
|
||||
* ### Algorithm
|
||||
* Choose the key for encryption and apply XOR operation to each character of a string.
|
||||
* Reapplying XOR operation to each character of encrypted string will give original string back.
|
||||
*
|
||||
* \note This program implements XOR Cipher for string with ASCII characters.
|
||||
*
|
||||
* @author [Deep Raval](https://github.com/imdeep2905)
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
/** \namespace ciphers
|
||||
* \brief Algorithms for encryption and decryption
|
||||
*/
|
||||
namespace ciphers {
|
||||
/** \namespace XOR
|
||||
* \brief Functions for [XOR cipher](https://en.wikipedia.org/wiki/XOR_cipher) algorithm.
|
||||
*/
|
||||
namespace XOR {
|
||||
/**
|
||||
* Encrypt given text using XOR cipher.
|
||||
* @param text text to be encrypted
|
||||
* @param key to be used for encyption
|
||||
* @return new encrypted text
|
||||
*/
|
||||
std::string encrypt (const std::string &text, const int &key) {
|
||||
std::string encrypted_text = ""; // Empty string to store encrypted text
|
||||
for (auto &c: text) { // Going through each character
|
||||
char encrypted_char = char(c ^ key); // Applying encyption
|
||||
encrypted_text += encrypted_char; // Appending encrypted character
|
||||
}
|
||||
return encrypted_text; // Returning encrypted text
|
||||
}
|
||||
/**
|
||||
* Decrypt given text using XOR cipher.
|
||||
* @param text text to be encrypted
|
||||
* @param key to be used for decryption
|
||||
* @return new decrypted text
|
||||
*/
|
||||
std::string decrypt (const std::string &text, const int &key) {
|
||||
std::string decrypted_text = ""; // Empty string to store decrypted text
|
||||
for (auto &c : text) { // Going through each character
|
||||
char decrypted_char = char(c ^ key); // Applying decryption
|
||||
decrypted_text += decrypted_char; // Appending decrypted character
|
||||
}
|
||||
return decrypted_text; // Returning decrypted text
|
||||
}
|
||||
} // namespace XOR
|
||||
} // namespace ciphers
|
||||
|
||||
/**
|
||||
* Function to test above algorithm
|
||||
*/
|
||||
void test() {
|
||||
// Test 1
|
||||
std::string text1 = "Whipalsh! : Do watch this movie...";
|
||||
std::string encrypted1 = ciphers::XOR::encrypt(text1, 17);
|
||||
std::string decrypted1 = ciphers::XOR::decrypt(encrypted1, 17);
|
||||
assert(text1 == decrypted1);
|
||||
std::cout << "Original text : " << text1;
|
||||
std::cout << " , Encrypted text (with key = 17) : " << encrypted1;
|
||||
std::cout << " , Decrypted text : "<< decrypted1 << std::endl;
|
||||
// Test 2
|
||||
std::string text2 = "->Valar M0rghulis<-";
|
||||
std::string encrypted2 = ciphers::XOR::encrypt(text2, 29);
|
||||
std::string decrypted2 = ciphers::XOR::decrypt(encrypted2, 29);
|
||||
assert(text2 == decrypted2);
|
||||
std::cout << "Original text : " << text2;
|
||||
std::cout << " , Encrypted text (with key = 29) : " << encrypted2;
|
||||
std::cout << " , Decrypted text : "<< decrypted2 << std::endl;
|
||||
}
|
||||
|
||||
/** Driver Code */
|
||||
int main() {
|
||||
// Testing
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
# If necessary, use the RELATIVE flag, otherwise each source file may be listed
|
||||
# with full pathname. The RELATIVE flag makes it easier to extract an executable's name
|
||||
# automatically.
|
||||
|
||||
file( GLOB APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp )
|
||||
foreach( testsourcefile ${APP_SOURCES} )
|
||||
string( REPLACE ".cpp" "" testname ${testsourcefile} ) # File type. Example: `.cpp`
|
||||
add_executable( ${testname} ${testsourcefile} )
|
||||
|
||||
set_target_properties(${testname} PROPERTIES LINKER_LANGUAGE CXX)
|
||||
if(OpenMP_CXX_FOUND)
|
||||
target_link_libraries(${testname} OpenMP::OpenMP_CXX)
|
||||
endif()
|
||||
install(TARGETS ${testname} DESTINATION "bin/cpu_scheduling_algorithms") # Folder name. Do NOT include `<>`
|
||||
|
||||
endforeach( testsourcefile ${APP_SOURCES} )
|
||||
@@ -0,0 +1,291 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of FCFS CPU scheduling algorithm
|
||||
* @details
|
||||
* FCFS is a non-preemptive CPU scheduling algorithm in which whichever process
|
||||
* arrives first, gets executed first. If two or more processes arrive
|
||||
* simultaneously, the process with smaller process ID gets executed first.
|
||||
* @link https://bit.ly/3ABNXOC
|
||||
* @author [Pratyush Vatsa](https://github.com/Pratyush219)
|
||||
*/
|
||||
|
||||
#include <algorithm> /// for sorting
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <cstdlib> /// random number generation
|
||||
#include <ctime> /// for time
|
||||
#include <iomanip> /// for formatting the output
|
||||
#include <iostream> /// for IO operations
|
||||
#include <queue> /// for std::priority_queue
|
||||
#include <unordered_set> /// for std::unordered_set
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
using std::cin;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::get;
|
||||
using std::left;
|
||||
using std::make_tuple;
|
||||
using std::priority_queue;
|
||||
using std::rand;
|
||||
using std::srand;
|
||||
using std::tuple;
|
||||
using std::unordered_set;
|
||||
using std::vector;
|
||||
/**
|
||||
* @brief Comparator function for sorting a vector
|
||||
* @tparam S Data type of Process ID
|
||||
* @tparam T Data type of Arrival time
|
||||
* @tparam E Data type of Burst time
|
||||
* @param t1 First tuple
|
||||
* @param t2 Second tuple
|
||||
* @returns true if t1 and t2 are in the CORRECT order
|
||||
* @returns false if t1 and t2 are in the INCORRECT order
|
||||
*/
|
||||
template <typename S, typename T, typename E>
|
||||
bool sortcol(tuple<S, T, E>& t1, tuple<S, T, E>& t2) {
|
||||
if (get<1>(t1) < get<1>(t2)) {
|
||||
return true;
|
||||
} else if (get<1>(t1) == get<1>(t2) && get<0>(t1) < get<0>(t2)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class Compare
|
||||
* @brief Comparator class for priority queue
|
||||
* @tparam S Data type of Process ID
|
||||
* @tparam T Data type of Arrival time
|
||||
* @tparam E Data type of Burst time
|
||||
*/
|
||||
template <typename S, typename T, typename E>
|
||||
class Compare {
|
||||
public:
|
||||
/**
|
||||
* @param t1 First tuple
|
||||
* @param t2 Second tuple
|
||||
* @brief A comparator function that checks whether to swap the two tuples
|
||||
* or not.
|
||||
* @link Refer to
|
||||
* https://www.geeksforgeeks.org/comparator-class-in-c-with-examples/ for
|
||||
* detailed description of comparator
|
||||
* @returns true if the tuples SHOULD be swapped
|
||||
* @returns false if the tuples SHOULDN'T be swapped
|
||||
*/
|
||||
bool operator()(tuple<S, T, E, double, double, double>& t1,
|
||||
tuple<S, T, E, double, double, double>& t2) {
|
||||
// Compare arrival times
|
||||
if (get<1>(t2) < get<1>(t1)) {
|
||||
return true;
|
||||
}
|
||||
// If arrival times are same, then compare Process IDs
|
||||
else if (get<1>(t2) == get<1>(t1)) {
|
||||
return get<0>(t2) < get<0>(t1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class FCFS
|
||||
* @brief Class which implements the FCFS scheduling algorithm
|
||||
* @tparam S Data type of Process ID
|
||||
* @tparam T Data type of Arrival time
|
||||
* @tparam E Data type of Burst time
|
||||
*/
|
||||
template <typename S, typename T, typename E>
|
||||
class FCFS {
|
||||
/**
|
||||
* Priority queue of schedules(stored as tuples) of processes.
|
||||
* In each tuple
|
||||
* 1st element: Process ID
|
||||
* 2nd element: Arrival Time
|
||||
* 3rd element: Burst time
|
||||
* 4th element: Completion time
|
||||
* 5th element: Turnaround time
|
||||
* 6th element: Waiting time
|
||||
*/
|
||||
priority_queue<tuple<S, T, E, double, double, double>,
|
||||
vector<tuple<S, T, E, double, double, double>>,
|
||||
Compare<S, T, E>>
|
||||
schedule;
|
||||
|
||||
// Stores final status of all the processes after completing the execution.
|
||||
vector<tuple<S, T, E, double, double, double>> result;
|
||||
|
||||
// Stores process IDs. Used for confirming absence of a process while adding
|
||||
// it.
|
||||
unordered_set<S> idList;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Adds the process to the ready queue if it isn't already there
|
||||
* @param id Process ID
|
||||
* @param arrival Arrival time of the process
|
||||
* @param burst Burst time of the process
|
||||
* @returns void
|
||||
*
|
||||
*/
|
||||
void addProcess(S id, T arrival, E burst) {
|
||||
// Add if a process with process ID as id is not found in idList.
|
||||
if (idList.find(id) == idList.end()) {
|
||||
tuple<S, T, E, double, double, double> t =
|
||||
make_tuple(id, arrival, burst, 0, 0, 0);
|
||||
schedule.push(t);
|
||||
idList.insert(id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Algorithm for scheduling CPU processes according to the First Come
|
||||
* First Serve(FCFS) scheduling algorithm.
|
||||
*
|
||||
* @details FCFS is a non-preemptive algorithm in which the process which
|
||||
* arrives first gets executed first. If two or more processes arrive
|
||||
* together then the process with smaller process ID runs first (each
|
||||
* process has a unique proces ID).
|
||||
*
|
||||
* I used a min priority queue of tuples to accomplish this task. The
|
||||
* processes are ordered by their arrival times. If arrival times of some
|
||||
* processes are equal, then they are ordered by their process ID.
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
vector<tuple<S, T, E, double, double, double>> scheduleForFcfs() {
|
||||
// Variable to keep track of time elapsed so far
|
||||
double timeElapsed = 0;
|
||||
|
||||
while (!schedule.empty()) {
|
||||
tuple<S, T, E, double, double, double> cur = schedule.top();
|
||||
|
||||
// If the current process arrived at time t2, the last process
|
||||
// completed its execution at time t1, and t2 > t1.
|
||||
if (get<1>(cur) > timeElapsed) {
|
||||
timeElapsed += get<1>(cur) - timeElapsed;
|
||||
}
|
||||
|
||||
// Add Burst time to time elapsed
|
||||
timeElapsed += get<2>(cur);
|
||||
|
||||
// Completion time of the current process will be same as time
|
||||
// elapsed so far
|
||||
get<3>(cur) = timeElapsed;
|
||||
|
||||
// Turnaround time = Completion time - Arrival time
|
||||
get<4>(cur) = get<3>(cur) - get<1>(cur);
|
||||
|
||||
// Waiting time = Turnaround time - Burst time
|
||||
get<5>(cur) = get<4>(cur) - get<2>(cur);
|
||||
|
||||
result.push_back(cur);
|
||||
schedule.pop();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility function for printing the status of each process after
|
||||
* execution
|
||||
* @returns void
|
||||
*/
|
||||
void printResult() {
|
||||
cout << "Status of all the proceses post completion is as follows:"
|
||||
<< endl;
|
||||
|
||||
cout << std::setw(17) << left << "Process ID" << std::setw(17) << left
|
||||
<< "Arrival Time" << std::setw(17) << left << "Burst Time"
|
||||
<< std::setw(17) << left << "Completion Time" << std::setw(17)
|
||||
<< left << "Turnaround Time" << std::setw(17) << left
|
||||
<< "Waiting Time" << endl;
|
||||
|
||||
for (size_t i{}; i < result.size(); i++) {
|
||||
cout << std::setprecision(2) << std::fixed << std::setw(17) << left
|
||||
<< get<0>(result[i]) << std::setw(17) << left
|
||||
<< get<1>(result[i]) << std::setw(17) << left
|
||||
<< get<2>(result[i]) << std::setw(17) << left
|
||||
<< get<3>(result[i]) << std::setw(17) << left
|
||||
<< get<4>(result[i]) << std::setw(17) << left
|
||||
<< get<5>(result[i]) << endl;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Function to be used for testing purposes. This function guarantees the
|
||||
* correct solution for FCFS scheduling algorithm.
|
||||
* @param input the input data
|
||||
* @details Sorts the input vector according to arrival time. Processes whose
|
||||
* arrival times are same get sorted according to process ID For each process,
|
||||
* completion time, turnaround time and completion time are calculated, inserted
|
||||
* in a tuple, which is added to the vector result.
|
||||
* @returns A vector of tuples consisting of process ID, arrival time, burst
|
||||
* time, completion time, turnaround time and waiting time for each process.
|
||||
*/
|
||||
template <typename S, typename T, typename E>
|
||||
vector<tuple<S, T, E, double, double, double>> get_final_status(
|
||||
vector<tuple<uint32_t, uint32_t, uint32_t>> input) {
|
||||
sort(input.begin(), input.end(), sortcol<S, T, E>);
|
||||
vector<tuple<S, T, E, double, double, double>> result(input.size());
|
||||
double timeElapsed = 0;
|
||||
for (size_t i{}; i < input.size(); i++) {
|
||||
T arrival = get<1>(input[i]);
|
||||
E burst = get<2>(input[i]);
|
||||
|
||||
if (arrival > timeElapsed) {
|
||||
timeElapsed += arrival - timeElapsed;
|
||||
}
|
||||
timeElapsed += burst;
|
||||
double completion = timeElapsed;
|
||||
double turnaround = completion - arrival;
|
||||
double waiting = turnaround - burst;
|
||||
|
||||
get<0>(result[i]) = get<0>(input[i]);
|
||||
get<1>(result[i]) = arrival;
|
||||
get<2>(result[i]) = burst;
|
||||
get<3>(result[i]) = completion;
|
||||
get<4>(result[i]) = turnaround;
|
||||
get<5>(result[i]) = waiting;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
for (int i{}; i < 1000; i++) {
|
||||
srand(time(nullptr));
|
||||
uint32_t n = 1 + rand() % 1000;
|
||||
FCFS<uint32_t, uint32_t, uint32_t> readyQueue;
|
||||
vector<tuple<uint32_t, uint32_t, uint32_t>> input(n);
|
||||
|
||||
for (uint32_t i{}; i < n; i++) {
|
||||
get<0>(input[i]) = i;
|
||||
srand(time(nullptr));
|
||||
get<1>(input[i]) = 1 + rand() % 10000;
|
||||
srand(time(nullptr));
|
||||
get<2>(input[i]) = 1 + rand() % 10000;
|
||||
}
|
||||
|
||||
for (uint32_t i{}; i < n; i++) {
|
||||
readyQueue.addProcess(get<0>(input[i]), get<1>(input[i]),
|
||||
get<2>(input[i]));
|
||||
}
|
||||
vector<tuple<uint32_t, uint32_t, uint32_t, double, double, double>>
|
||||
res = get_final_status<uint32_t, uint32_t, uint32_t>(input);
|
||||
assert(res == readyQueue.scheduleForFcfs());
|
||||
// readyQueue.printResult();
|
||||
}
|
||||
cout << "All the tests have successfully passed!" << endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Entry point of the program
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,316 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of SJF CPU scheduling algorithm
|
||||
* @details
|
||||
* shortest job first (SJF), also known as shortest job next (SJN), is a
|
||||
* scheduling policy that selects for execution the waiting process with the
|
||||
* smallest execution time. SJN is a non-preemptive algorithm. Shortest
|
||||
* remaining time is a preemptive variant of SJN.
|
||||
* <a href="https://www.guru99.com/shortest-job-first-sjf-scheduling.html">
|
||||
* detailed description on SJF scheduling </a>
|
||||
* <a href="https://github.com/LakshmiSrikumar">Author : Lakshmi Srikumar </a>
|
||||
*/
|
||||
|
||||
#include <algorithm> /// for sorting
|
||||
#include <cassert> /// for assert
|
||||
#include <iomanip> /// for formatting the output
|
||||
#include <iostream> /// for IO operations
|
||||
#include <queue> /// for std::priority_queue
|
||||
#include <random> /// random number generation
|
||||
#include <unordered_set> /// for std::unordered_set
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
using std::cin;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::get;
|
||||
using std::left;
|
||||
using std::make_tuple;
|
||||
using std::priority_queue;
|
||||
using std::tuple;
|
||||
using std::unordered_set;
|
||||
using std::vector;
|
||||
|
||||
/**
|
||||
* @brief Comparator function for sorting a vector
|
||||
* @tparam S Data type of Process ID
|
||||
* @tparam T Data type of Arrival time
|
||||
* @tparam E Data type of Burst time
|
||||
* @param t1 First tuple<S,T,E>t1
|
||||
* @param t2 Second tuple<S,T,E>t2
|
||||
* @returns true if t1 and t2 are in the CORRECT order
|
||||
* @returns false if t1 and t2 are in the INCORRECT order
|
||||
*/
|
||||
template <typename S, typename T, typename E>
|
||||
bool sortcol(tuple<S, T, E>& t1, tuple<S, T, E>& t2) {
|
||||
if (get<1>(t1) < get<1>(t2) ||
|
||||
(get<1>(t1) == get<1>(t2) && get<0>(t1) < get<0>(t2))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @class Compare
|
||||
* @brief Comparator class for priority queue
|
||||
* @tparam S Data type of Process ID
|
||||
* @tparam T Data type of Arrival time
|
||||
* @tparam E Data type of Burst time
|
||||
*/
|
||||
template <typename S, typename T, typename E>
|
||||
class Compare {
|
||||
public:
|
||||
/**
|
||||
* @param t1 First tuple
|
||||
* @param t2 Second tuple
|
||||
* @brief A comparator function that checks whether to swap the two tuples
|
||||
* or not.
|
||||
* <a
|
||||
* href="https://www.geeksforgeeks.org/comparator-class-in-c-with-examples/">
|
||||
* detailed description of comparator </a>
|
||||
* @returns true if the tuples SHOULD be swapped
|
||||
* @returns false if the tuples SHOULDN'T be swapped
|
||||
*/
|
||||
bool operator()(tuple<S, T, E, double, double, double>& t1,
|
||||
tuple<S, T, E, double, double, double>& t2) {
|
||||
// Compare burst times for SJF
|
||||
if (get<2>(t2) < get<2>(t1)) {
|
||||
return true;
|
||||
}
|
||||
// If burst times are the same, compare arrival times
|
||||
else if (get<2>(t2) == get<2>(t1)) {
|
||||
return get<1>(t2) < get<1>(t1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class SJF
|
||||
* @brief Class which implements the SJF scheduling algorithm
|
||||
* @tparam S Data type of Process ID
|
||||
* @tparam T Data type of Arrival time
|
||||
* @tparam E Data type of Burst time
|
||||
*/
|
||||
template <typename S, typename T, typename E>
|
||||
class SJF {
|
||||
/**
|
||||
* Priority queue of schedules(stored as tuples) of processes.
|
||||
* In each tuple
|
||||
* @tparam 1st element: Process ID
|
||||
* @tparam 2nd element: Arrival Time
|
||||
* @tparam 3rd element: Burst time
|
||||
* @tparam 4th element: Completion time
|
||||
* @tparam 5th element: Turnaround time
|
||||
* @tparam 6th element: Waiting time
|
||||
*/
|
||||
priority_queue<tuple<S, T, E, double, double, double>,
|
||||
vector<tuple<S, T, E, double, double, double>>,
|
||||
Compare<S, T, E>>
|
||||
schedule;
|
||||
|
||||
// Stores final status of all the processes after completing the execution.
|
||||
vector<tuple<S, T, E, double, double, double>> result;
|
||||
|
||||
// Stores process IDs. Used for confirming absence of a process while it.
|
||||
unordered_set<S> idList;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Adds the process to the ready queue if it isn't already there
|
||||
* @param id Process ID
|
||||
* @param arrival Arrival time of the process
|
||||
* @param burst Burst time of the process
|
||||
* @returns void
|
||||
*
|
||||
*/
|
||||
void addProcess(S id, T arrival, E burst) {
|
||||
// Add if a process with process ID as id is not found in idList.
|
||||
if (idList.find(id) == idList.end()) {
|
||||
tuple<S, T, E, double, double, double> t =
|
||||
make_tuple(id, arrival, burst, 0, 0, 0);
|
||||
schedule.push(t);
|
||||
idList.insert(id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Algorithm for scheduling CPU processes according to
|
||||
* the Shortest Job First (SJF) scheduling algorithm.
|
||||
*
|
||||
* @details Non pre-emptive SJF is an algorithm that schedules processes
|
||||
* based on the length of their burst times. The process with the smallest
|
||||
* burst time is executed first.In a non-preemptive scheduling algorithm,
|
||||
* once a process starts executing,it runs to completion without being
|
||||
* interrupted.
|
||||
*
|
||||
* I used a min priority queue because it allows you to efficiently pick the
|
||||
* process with the smallest burst time in constant time, by maintaining a
|
||||
* priority order where the shortest burst process is always at the front.
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
|
||||
vector<tuple<S, T, E, double, double, double>> scheduleForSJF() {
|
||||
// Variable to keep track of time elapsed so far
|
||||
double timeElapsed = 0;
|
||||
|
||||
while (!schedule.empty()) {
|
||||
tuple<S, T, E, double, double, double> cur = schedule.top();
|
||||
|
||||
// If the current process arrived at time t2, the last process
|
||||
// completed its execution at time t1, and t2 > t1.
|
||||
if (get<1>(cur) > timeElapsed) {
|
||||
timeElapsed += get<1>(cur) - timeElapsed;
|
||||
}
|
||||
|
||||
// Add Burst time to time elapsed
|
||||
timeElapsed += get<2>(cur);
|
||||
|
||||
// Completion time of the current process will be same as time
|
||||
// elapsed so far
|
||||
get<3>(cur) = timeElapsed;
|
||||
|
||||
// Turnaround time = Completion time - Arrival time
|
||||
get<4>(cur) = get<3>(cur) - get<1>(cur);
|
||||
|
||||
// Waiting time = Turnaround time - Burst time
|
||||
get<5>(cur) = get<4>(cur) - get<2>(cur);
|
||||
|
||||
// Turnaround time >= Burst time
|
||||
assert(get<4>(cur) >= get<2>(cur));
|
||||
|
||||
// Waiting time is never negative
|
||||
assert(get<5>(cur) >= 0);
|
||||
|
||||
result.push_back(cur);
|
||||
schedule.pop();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* @brief Utility function for printing the status of
|
||||
* each process after execution
|
||||
* @returns void
|
||||
*/
|
||||
|
||||
void printResult(
|
||||
const vector<tuple<S, T, E, double, double, double>>& processes) {
|
||||
cout << std::setw(17) << left << "Process ID" << std::setw(17) << left
|
||||
<< "Arrival Time" << std::setw(17) << left << "Burst Time"
|
||||
<< std::setw(17) << left << "Completion Time" << std::setw(17)
|
||||
<< left << "Turnaround Time" << std::setw(17) << left
|
||||
<< "Waiting Time" << endl;
|
||||
|
||||
for (const auto& process : processes) {
|
||||
cout << std::setprecision(2) << std::fixed << std::setw(17) << left
|
||||
<< get<0>(process) << std::setw(17) << left << get<1>(process)
|
||||
<< std::setw(17) << left << get<2>(process) << std::setw(17)
|
||||
<< left << get<3>(process) << std::setw(17) << left
|
||||
<< get<4>(process) << std::setw(17) << left << get<5>(process)
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Computes the final status of processes after
|
||||
* applying non-preemptive SJF scheduling
|
||||
* @tparam S Data type of Process ID
|
||||
* @tparam T Data type of Arrival time
|
||||
* @tparam E Data type of Burst time
|
||||
* @param input A vector of tuples containing Process ID, Arrival time, and
|
||||
* Burst time
|
||||
* @returns A vector of tuples containing Process ID, Arrival time, Burst time,
|
||||
* Completion time, Turnaround time, and Waiting time
|
||||
*/
|
||||
template <typename S, typename T, typename E>
|
||||
vector<tuple<S, T, E, double, double, double>> get_final_status(
|
||||
vector<tuple<S, T, E>> input) {
|
||||
// Sort the processes based on Arrival time and then Burst time
|
||||
sort(input.begin(), input.end(), sortcol<S, T, E>);
|
||||
|
||||
// Result vector to hold the final status of each process
|
||||
vector<tuple<S, T, E, double, double, double>> result(input.size());
|
||||
double timeElapsed = 0;
|
||||
|
||||
for (size_t i = 0; i < input.size(); i++) {
|
||||
// Extract Arrival time and Burst time
|
||||
T arrival = get<1>(input[i]);
|
||||
E burst = get<2>(input[i]);
|
||||
|
||||
// If the CPU is idle, move time to the arrival of the next process
|
||||
if (arrival > timeElapsed) {
|
||||
timeElapsed = arrival;
|
||||
}
|
||||
|
||||
// Update timeElapsed by adding the burst time
|
||||
timeElapsed += burst;
|
||||
|
||||
// Calculate Completion time, Turnaround time, and Waiting time
|
||||
double completion = timeElapsed;
|
||||
double turnaround = completion - arrival;
|
||||
double waiting = turnaround - burst;
|
||||
|
||||
// Store the results in the result vector
|
||||
result[i] = make_tuple(get<0>(input[i]), arrival, burst, completion,
|
||||
turnaround, waiting);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
// A vector to store the results of all processes across all test cases.
|
||||
vector<tuple<uint32_t, uint32_t, uint32_t, double, double, double>>
|
||||
finalResult;
|
||||
|
||||
for (int i{}; i < 10; i++) {
|
||||
std::random_device rd; // Seeding
|
||||
std::mt19937 eng(rd());
|
||||
std::uniform_int_distribution<> distr(1, 10);
|
||||
|
||||
uint32_t n = distr(eng);
|
||||
SJF<uint32_t, uint32_t, uint32_t> readyQueue;
|
||||
vector<tuple<uint32_t, uint32_t, uint32_t, double, double, double>>
|
||||
input(n);
|
||||
|
||||
// Generate random arrival and burst times
|
||||
for (uint32_t i{}; i < n; i++) {
|
||||
get<0>(input[i]) = i;
|
||||
get<1>(input[i]) = distr(eng); // Random arrival time
|
||||
get<2>(input[i]) = distr(eng); // Random burst time
|
||||
}
|
||||
|
||||
// Print processes before scheduling
|
||||
cout << "Processes before SJF scheduling:" << endl;
|
||||
readyQueue.printResult(input);
|
||||
|
||||
// Add processes to the queue
|
||||
for (uint32_t i{}; i < n; i++) {
|
||||
readyQueue.addProcess(get<0>(input[i]), get<1>(input[i]),
|
||||
get<2>(input[i]));
|
||||
}
|
||||
|
||||
// Perform SJF schedulings
|
||||
auto finalResult = readyQueue.scheduleForSJF();
|
||||
|
||||
// Print processes after scheduling
|
||||
cout << "\nProcesses after SJF scheduling:" << endl;
|
||||
readyQueue.printResult(finalResult);
|
||||
}
|
||||
cout << "All the tests have successfully passed!" << endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on successful exit
|
||||
*/
|
||||
int main() {
|
||||
test();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
# If necessary, use the RELATIVE flag, otherwise each source file may be listed
|
||||
# with full pathname. RELATIVE may makes it easier to extract an executable name
|
||||
# automatically.
|
||||
file( GLOB APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.cpp )
|
||||
# file( GLOB APP_SOURCES ${CMAKE_SOURCE_DIR}/*.c )
|
||||
# AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} APP_SOURCES)
|
||||
foreach( testsourcefile ${APP_SOURCES} )
|
||||
# I used a simple string replace, to cut off .cpp.
|
||||
string( REPLACE ".cpp" "" testname ${testsourcefile} )
|
||||
add_executable( ${testname} ${testsourcefile} )
|
||||
|
||||
set_target_properties(${testname} PROPERTIES LINKER_LANGUAGE CXX)
|
||||
if(OpenMP_CXX_FOUND)
|
||||
target_link_libraries(${testname} OpenMP::OpenMP_CXX)
|
||||
endif()
|
||||
install(TARGETS ${testname} DESTINATION "bin/data_structures")
|
||||
|
||||
endforeach( testsourcefile ${APP_SOURCES} )
|
||||
|
||||
add_subdirectory(cll)
|
||||
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* \file
|
||||
* \brief A simple tree implementation using nodes
|
||||
*
|
||||
* \todo update code to use C++ STL library features and OO structure
|
||||
* \warning This program is a poor implementation and does not utilize any of
|
||||
* the C++ STL features.
|
||||
*/
|
||||
#include <algorithm> /// for std::max
|
||||
#include <iostream> /// for std::cout
|
||||
#include <queue> /// for std::queue
|
||||
|
||||
using node = struct node {
|
||||
int data;
|
||||
int height;
|
||||
struct node *left;
|
||||
struct node *right;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief creates and returns a new node
|
||||
* @param[in] data value stored in the node
|
||||
* @return newly created node
|
||||
*/
|
||||
node *createNode(int data) {
|
||||
node *nn = new node();
|
||||
nn->data = data;
|
||||
nn->height = 0;
|
||||
nn->left = nullptr;
|
||||
nn->right = nullptr;
|
||||
return nn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param[in] root the root of the tree
|
||||
* @return height of tree
|
||||
*/
|
||||
int height(node *root) {
|
||||
if (root == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return 1 + std::max(height(root->left), height(root->right));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param[in] root of the tree
|
||||
* @return difference between height of left and right subtree
|
||||
*/
|
||||
int getBalance(node *root) { return height(root->left) - height(root->right); }
|
||||
|
||||
/**
|
||||
* @param root of the tree to be rotated
|
||||
* @return node after right rotation
|
||||
*/
|
||||
node *rightRotate(node *root) {
|
||||
node *t = root->left;
|
||||
node *u = t->right;
|
||||
t->right = root;
|
||||
root->left = u;
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param root of the tree to be rotated
|
||||
* @return node after left rotation
|
||||
*/
|
||||
node *leftRotate(node *root) {
|
||||
node *t = root->right;
|
||||
node *u = t->left;
|
||||
t->left = root;
|
||||
root->right = u;
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param root of the tree
|
||||
* @returns node with minimum value in the tree
|
||||
*/
|
||||
node *minValue(node *root) {
|
||||
if (root->left == nullptr) {
|
||||
return root;
|
||||
}
|
||||
return minValue(root->left);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief inserts a new element into AVL tree
|
||||
* @param root of the tree
|
||||
* @param[in] item the element to be insterted into the tree
|
||||
* @return root of the updated tree
|
||||
*/
|
||||
node *insert(node *root, int item) {
|
||||
if (root == nullptr) {
|
||||
return createNode(item);
|
||||
}
|
||||
if (item < root->data) {
|
||||
root->left = insert(root->left, item);
|
||||
} else {
|
||||
root->right = insert(root->right, item);
|
||||
}
|
||||
int b = getBalance(root);
|
||||
if (b > 1) {
|
||||
if (getBalance(root->left) < 0) {
|
||||
root->left = leftRotate(root->left); // Left-Right Case
|
||||
}
|
||||
return rightRotate(root); // Left-Left Case
|
||||
} else if (b < -1) {
|
||||
if (getBalance(root->right) > 0) {
|
||||
root->right = rightRotate(root->right); // Right-Left Case
|
||||
}
|
||||
return leftRotate(root); // Right-Right Case
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief removes a given element from AVL tree
|
||||
* @param root of the tree
|
||||
* @param[in] element the element to be deleted from the tree
|
||||
* @return root of the updated tree
|
||||
*/
|
||||
node *deleteNode(node *root, int element) {
|
||||
if (root == nullptr) {
|
||||
return root;
|
||||
}
|
||||
if (element < root->data) {
|
||||
root->left = deleteNode(root->left, element);
|
||||
} else if (element > root->data) {
|
||||
root->right = deleteNode(root->right, element);
|
||||
|
||||
} else {
|
||||
// Node to be deleted is leaf node or have only one Child
|
||||
if (!root->right || !root->left) {
|
||||
node *temp = !root->right ? root->left : root->right;
|
||||
delete root;
|
||||
return temp;
|
||||
}
|
||||
// Node to be deleted have both left and right subtrees
|
||||
node *temp = minValue(root->right);
|
||||
root->data = temp->data;
|
||||
root->right = deleteNode(root->right, temp->data);
|
||||
}
|
||||
// Balancing Tree after deletion
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief calls delete on every node
|
||||
* @param root of the tree
|
||||
*/
|
||||
void deleteAllNodes(const node *const root) {
|
||||
if (root) {
|
||||
deleteAllNodes(root->left);
|
||||
deleteAllNodes(root->right);
|
||||
delete root;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief prints given tree in the LevelOrder
|
||||
* @param[in] root of the tree
|
||||
*/
|
||||
void levelOrder(node *root) {
|
||||
std::queue<node *> q;
|
||||
q.push(root);
|
||||
while (!q.empty()) {
|
||||
root = q.front();
|
||||
std::cout << root->data << " ";
|
||||
q.pop();
|
||||
if (root->left) {
|
||||
q.push(root->left);
|
||||
}
|
||||
if (root->right) {
|
||||
q.push(root->right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
// Testing AVL Tree
|
||||
node *root = nullptr;
|
||||
int i = 0;
|
||||
for (i = 1; i <= 7; i++) root = insert(root, i);
|
||||
std::cout << "LevelOrder: ";
|
||||
levelOrder(root);
|
||||
root = deleteNode(root, 1); // Deleting key with value 1
|
||||
std::cout << "\nLevelOrder: ";
|
||||
levelOrder(root);
|
||||
root = deleteNode(root, 4); // Deletin key with value 4
|
||||
std::cout << "\nLevelOrder: ";
|
||||
levelOrder(root);
|
||||
deleteAllNodes(root);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* \file
|
||||
* \brief A simple tree implementation using structured nodes
|
||||
*
|
||||
* \todo update code to use C++ STL library features and OO structure
|
||||
* \warning This program is a poor implementation - C style - and does not
|
||||
* utilize any of the C++ STL features.
|
||||
*/
|
||||
#include <iostream>
|
||||
|
||||
struct node {
|
||||
int val;
|
||||
node *left;
|
||||
node *right;
|
||||
};
|
||||
|
||||
struct Queue {
|
||||
node *t[100];
|
||||
int front;
|
||||
int rear;
|
||||
};
|
||||
|
||||
Queue queue;
|
||||
|
||||
void enqueue(node *n) { queue.t[queue.rear++] = n; }
|
||||
|
||||
node *dequeue() { return (queue.t[queue.front++]); }
|
||||
|
||||
void Insert(node *n, int x) {
|
||||
if (x < n->val) {
|
||||
if (n->left == NULL) {
|
||||
node *temp = new node;
|
||||
temp->val = x;
|
||||
temp->left = NULL;
|
||||
temp->right = NULL;
|
||||
n->left = temp;
|
||||
} else {
|
||||
Insert(n->left, x);
|
||||
}
|
||||
} else {
|
||||
if (n->right == NULL) {
|
||||
node *temp = new node;
|
||||
temp->val = x;
|
||||
temp->left = NULL;
|
||||
temp->right = NULL;
|
||||
n->right = temp;
|
||||
} else {
|
||||
Insert(n->right, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int findMaxInLeftST(node *n) {
|
||||
while (n->right != NULL) {
|
||||
n = n->right;
|
||||
}
|
||||
return n->val;
|
||||
}
|
||||
|
||||
void Remove(node *p, node *n, int x) {
|
||||
if (n->val == x) {
|
||||
if (n->right == NULL && n->left == NULL) {
|
||||
if (x < p->val) {
|
||||
p->right = NULL;
|
||||
} else {
|
||||
p->left = NULL;
|
||||
}
|
||||
} else if (n->right == NULL) {
|
||||
if (x < p->val) {
|
||||
p->right = n->left;
|
||||
} else {
|
||||
p->left = n->left;
|
||||
}
|
||||
} else if (n->left == NULL) {
|
||||
if (x < p->val) {
|
||||
p->right = n->right;
|
||||
} else {
|
||||
p->left = n->right;
|
||||
}
|
||||
} else {
|
||||
int y = findMaxInLeftST(n->left);
|
||||
n->val = y;
|
||||
Remove(n, n->right, y);
|
||||
}
|
||||
} else if (x < n->val) {
|
||||
Remove(n, n->left, x);
|
||||
} else {
|
||||
Remove(n, n->right, x);
|
||||
}
|
||||
}
|
||||
|
||||
void BFT(node *n) {
|
||||
if (n != NULL) {
|
||||
std::cout << n->val << " ";
|
||||
enqueue(n->left);
|
||||
enqueue(n->right);
|
||||
BFT(dequeue());
|
||||
}
|
||||
}
|
||||
|
||||
void Pre(node *n) {
|
||||
if (n != NULL) {
|
||||
std::cout << n->val << " ";
|
||||
Pre(n->left);
|
||||
Pre(n->right);
|
||||
}
|
||||
}
|
||||
|
||||
void In(node *n) {
|
||||
if (n != NULL) {
|
||||
In(n->left);
|
||||
std::cout << n->val << " ";
|
||||
In(n->right);
|
||||
}
|
||||
}
|
||||
|
||||
void Post(node *n) {
|
||||
if (n != NULL) {
|
||||
Post(n->left);
|
||||
Post(n->right);
|
||||
std::cout << n->val << " ";
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
queue.front = 0;
|
||||
queue.rear = 0;
|
||||
int value;
|
||||
int ch;
|
||||
node *root = new node;
|
||||
std::cout << "\nEnter the value of root node :";
|
||||
std::cin >> value;
|
||||
root->val = value;
|
||||
root->left = NULL;
|
||||
root->right = NULL;
|
||||
do {
|
||||
std::cout << "\n1. Insert"
|
||||
<< "\n2. Delete"
|
||||
<< "\n3. Breadth First"
|
||||
<< "\n4. Preorder Depth First"
|
||||
<< "\n5. Inorder Depth First"
|
||||
<< "\n6. Postorder Depth First";
|
||||
|
||||
std::cout << "\nEnter Your Choice : ";
|
||||
std::cin >> ch;
|
||||
int x;
|
||||
switch (ch) {
|
||||
case 1:
|
||||
std::cout << "\nEnter the value to be Inserted : ";
|
||||
std::cin >> x;
|
||||
Insert(root, x);
|
||||
break;
|
||||
case 2:
|
||||
std::cout << "\nEnter the value to be Deleted : ";
|
||||
std::cin >> x;
|
||||
Remove(root, root, x);
|
||||
break;
|
||||
case 3:
|
||||
BFT(root);
|
||||
break;
|
||||
case 4:
|
||||
Pre(root);
|
||||
break;
|
||||
case 5:
|
||||
In(root);
|
||||
break;
|
||||
case 6:
|
||||
Post(root);
|
||||
break;
|
||||
}
|
||||
} while (ch != 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,565 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief A generic [binary search tree](https://en.wikipedia.org/wiki/Binary_search_tree) implementation.
|
||||
* Here you can find more information about the algorithm: [Scaler - Binary Search tree](https://www.scaler.com/topics/data-structures/binary-search-tree/).
|
||||
* @see binary_search_tree.cpp
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* @brief The Binary Search Tree class.
|
||||
*
|
||||
* @tparam T The type of the binary search tree key.
|
||||
*/
|
||||
template <class T>
|
||||
class binary_search_tree {
|
||||
private:
|
||||
/**
|
||||
* @brief A struct to represent a node in the Binary Search Tree.
|
||||
*/
|
||||
struct bst_node {
|
||||
T value; /**< The value/key of the node. */
|
||||
std::unique_ptr<bst_node> left; /**< Pointer to left subtree. */
|
||||
std::unique_ptr<bst_node> right; /**< Pointer to right subtree. */
|
||||
|
||||
/**
|
||||
* Constructor for bst_node, used to simplify node construction and
|
||||
* smart pointer construction.
|
||||
* @param _value The value of the constructed node.
|
||||
*/
|
||||
explicit bst_node(T _value) {
|
||||
value = _value;
|
||||
left = nullptr;
|
||||
right = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<bst_node> root_; /**< Pointer to the root of the BST. */
|
||||
std::size_t size_ = 0; /**< Number of elements/nodes in the BST. */
|
||||
|
||||
/**
|
||||
* @brief Recursive function to find the maximum value in the BST.
|
||||
*
|
||||
* @param node The node to search from.
|
||||
* @param ret_value Variable to hold the maximum value.
|
||||
* @return true If the maximum value was successfully found.
|
||||
* @return false Otherwise.
|
||||
*/
|
||||
bool find_max(std::unique_ptr<bst_node>& node, T& ret_value) {
|
||||
if (!node) {
|
||||
return false;
|
||||
} else if (!node->right) {
|
||||
ret_value = node->value;
|
||||
return true;
|
||||
}
|
||||
return find_max(node->right, ret_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Recursive function to find the minimum value in the BST.
|
||||
*
|
||||
* @param node The node to search from.
|
||||
* @param ret_value Variable to hold the minimum value.
|
||||
* @return true If the minimum value was successfully found.
|
||||
* @return false Otherwise.
|
||||
*/
|
||||
bool find_min(std::unique_ptr<bst_node>& node, T& ret_value) {
|
||||
if (!node) {
|
||||
return false;
|
||||
} else if (!node->left) {
|
||||
ret_value = node->value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return find_min(node->left, ret_value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Recursive function to insert a value into the BST.
|
||||
*
|
||||
* @param node The node to search from.
|
||||
* @param new_value The value to insert.
|
||||
* @return true If the insert operation was successful.
|
||||
* @return false Otherwise.
|
||||
*/
|
||||
bool insert(std::unique_ptr<bst_node>& node, T new_value) {
|
||||
if (root_ == node && !root_) {
|
||||
root_ = std::unique_ptr<bst_node>(new bst_node(new_value));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (new_value < node->value) {
|
||||
if (!node->left) {
|
||||
node->left = std::unique_ptr<bst_node>(new bst_node(new_value));
|
||||
return true;
|
||||
} else {
|
||||
return insert(node->left, new_value);
|
||||
}
|
||||
} else if (new_value > node->value) {
|
||||
if (!node->right) {
|
||||
node->right =
|
||||
std::unique_ptr<bst_node>(new bst_node(new_value));
|
||||
return true;
|
||||
} else {
|
||||
return insert(node->right, new_value);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Recursive function to remove a value from the BST.
|
||||
*
|
||||
* @param parent The parent node of node.
|
||||
* @param node The node to search from.
|
||||
* @param rm_value The value to remove.
|
||||
* @return true If the removal operation was successful.
|
||||
* @return false Otherwise.
|
||||
*/
|
||||
bool remove(std::unique_ptr<bst_node>& parent,
|
||||
std::unique_ptr<bst_node>& node, T rm_value) {
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node->value == rm_value) {
|
||||
if (node->left && node->right) {
|
||||
T successor_node_value{};
|
||||
find_max(node->left, successor_node_value);
|
||||
remove(root_, root_, successor_node_value);
|
||||
node->value = successor_node_value;
|
||||
return true;
|
||||
} else if (node->left || node->right) {
|
||||
std::unique_ptr<bst_node>& non_null =
|
||||
(node->left ? node->left : node->right);
|
||||
|
||||
if (node == root_) {
|
||||
root_ = std::move(non_null);
|
||||
} else if (rm_value < parent->value) {
|
||||
parent->left = std::move(non_null);
|
||||
} else {
|
||||
parent->right = std::move(non_null);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
if (node == root_) {
|
||||
root_.reset(nullptr);
|
||||
} else if (rm_value < parent->value) {
|
||||
parent->left.reset(nullptr);
|
||||
} else {
|
||||
parent->right.reset(nullptr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} else if (rm_value < node->value) {
|
||||
return remove(node, node->left, rm_value);
|
||||
} else {
|
||||
return remove(node, node->right, rm_value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Recursive function to check if a value is in the BST.
|
||||
*
|
||||
* @param node The node to search from.
|
||||
* @param value The value to find.
|
||||
* @return true If the value was found in the BST.
|
||||
* @return false Otherwise.
|
||||
*/
|
||||
bool contains(std::unique_ptr<bst_node>& node, T value) {
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value < node->value) {
|
||||
return contains(node->left, value);
|
||||
} else if (value > node->value) {
|
||||
return contains(node->right, value);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Recursive function to traverse the tree in in-order order.
|
||||
*
|
||||
* @param callback Function that is called when a value needs to processed.
|
||||
* @param node The node to traverse from.
|
||||
*/
|
||||
void traverse_inorder(std::function<void(T)> callback,
|
||||
std::unique_ptr<bst_node>& node) {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
traverse_inorder(callback, node->left);
|
||||
callback(node->value);
|
||||
traverse_inorder(callback, node->right);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Recursive function to traverse the tree in pre-order order.
|
||||
*
|
||||
* @param callback Function that is called when a value needs to processed.
|
||||
* @param node The node to traverse from.
|
||||
*/
|
||||
void traverse_preorder(std::function<void(T)> callback,
|
||||
std::unique_ptr<bst_node>& node) {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
callback(node->value);
|
||||
traverse_preorder(callback, node->left);
|
||||
traverse_preorder(callback, node->right);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Recursive function to traverse the tree in post-order order.
|
||||
*
|
||||
* @param callback Function that is called when a value needs to processed.
|
||||
* @param node The node to traverse from.
|
||||
*/
|
||||
void traverse_postorder(std::function<void(T)> callback,
|
||||
std::unique_ptr<bst_node>& node) {
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
traverse_postorder(callback, node->left);
|
||||
traverse_postorder(callback, node->right);
|
||||
callback(node->value);
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new Binary Search Tree object.
|
||||
*
|
||||
*/
|
||||
binary_search_tree() {
|
||||
root_ = nullptr;
|
||||
size_ = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Insert a new value into the BST.
|
||||
*
|
||||
* @param new_value The value to insert into the BST.
|
||||
* @return true If the insertion was successful.
|
||||
* @return false Otherwise.
|
||||
*/
|
||||
bool insert(T new_value) {
|
||||
bool result = insert(root_, new_value);
|
||||
if (result) {
|
||||
size_++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove a specified value from the BST.
|
||||
*
|
||||
* @param rm_value The value to remove.
|
||||
* @return true If the removal was successful.
|
||||
* @return false Otherwise.
|
||||
*/
|
||||
bool remove(T rm_value) {
|
||||
bool result = remove(root_, root_, rm_value);
|
||||
if (result) {
|
||||
size_--;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if a value is in the BST.
|
||||
*
|
||||
* @param value The value to find.
|
||||
* @return true If value is in the BST.
|
||||
* @return false Otherwise.
|
||||
*/
|
||||
bool contains(T value) { return contains(root_, value); }
|
||||
|
||||
/**
|
||||
* @brief Find the smallest value in the BST.
|
||||
*
|
||||
* @param ret_value Variable to hold the minimum value.
|
||||
* @return true If minimum value was successfully found.
|
||||
* @return false Otherwise.
|
||||
*/
|
||||
bool find_min(T& ret_value) { return find_min(root_, ret_value); }
|
||||
|
||||
/**
|
||||
* @brief Find the largest value in the BST.
|
||||
*
|
||||
* @param ret_value Variable to hold the maximum value.
|
||||
* @return true If maximum value was successfully found.
|
||||
* @return false Otherwise.
|
||||
*/
|
||||
bool find_max(T& ret_value) { return find_max(root_, ret_value); }
|
||||
|
||||
/**
|
||||
* @brief Get the number of values in the BST.
|
||||
*
|
||||
* @return std::size_t Number of values in the BST.
|
||||
*/
|
||||
std::size_t size() { return size_; }
|
||||
|
||||
/**
|
||||
* @brief Get all values of the BST in in-order order.
|
||||
*
|
||||
* @return std::vector<T> List of values, sorted in in-order order.
|
||||
*/
|
||||
std::vector<T> get_elements_inorder() {
|
||||
std::vector<T> result;
|
||||
traverse_inorder([&](T node_value) { result.push_back(node_value); },
|
||||
root_);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get all values of the BST in pre-order order.
|
||||
*
|
||||
* @return std::vector<T> List of values, sorted in pre-order order.
|
||||
*/
|
||||
std::vector<T> get_elements_preorder() {
|
||||
std::vector<T> result;
|
||||
traverse_preorder([&](T node_value) { result.push_back(node_value); },
|
||||
root_);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get all values of the BST in post-order order.
|
||||
*
|
||||
* @return std::vector<T> List of values, sorted in post-order order.
|
||||
*/
|
||||
std::vector<T> get_elements_postorder() {
|
||||
std::vector<T> result;
|
||||
traverse_postorder([&](T node_value) { result.push_back(node_value); },
|
||||
root_);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Function for testing insert().
|
||||
*
|
||||
* @returns `void`
|
||||
*/
|
||||
static void test_insert() {
|
||||
std::cout << "Testing BST insert...";
|
||||
|
||||
binary_search_tree<int> tree;
|
||||
bool res = tree.insert(5);
|
||||
int min = -1, max = -1;
|
||||
assert(res);
|
||||
assert(tree.find_max(max));
|
||||
assert(tree.find_min(min));
|
||||
assert(max == 5);
|
||||
assert(min == 5);
|
||||
assert(tree.size() == 1);
|
||||
|
||||
tree.insert(4);
|
||||
tree.insert(3);
|
||||
tree.insert(6);
|
||||
assert(tree.find_max(max));
|
||||
assert(tree.find_min(min));
|
||||
assert(max == 6);
|
||||
assert(min == 3);
|
||||
assert(tree.size() == 4);
|
||||
|
||||
bool fail_res = tree.insert(4);
|
||||
assert(!fail_res);
|
||||
assert(tree.size() == 4);
|
||||
|
||||
std::cout << "ok" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function for testing remove().
|
||||
*
|
||||
* @returns `void`
|
||||
*/
|
||||
static void test_remove() {
|
||||
std::cout << "Testing BST remove...";
|
||||
|
||||
binary_search_tree<int> tree;
|
||||
tree.insert(5);
|
||||
tree.insert(4);
|
||||
tree.insert(3);
|
||||
tree.insert(6);
|
||||
|
||||
bool res = tree.remove(5);
|
||||
int min = -1, max = -1;
|
||||
assert(res);
|
||||
assert(tree.find_max(max));
|
||||
assert(tree.find_min(min));
|
||||
assert(max == 6);
|
||||
assert(min == 3);
|
||||
assert(tree.size() == 3);
|
||||
assert(tree.contains(5) == false);
|
||||
|
||||
tree.remove(4);
|
||||
tree.remove(3);
|
||||
tree.remove(6);
|
||||
assert(tree.size() == 0);
|
||||
assert(tree.contains(6) == false);
|
||||
|
||||
bool fail_res = tree.remove(5);
|
||||
assert(!fail_res);
|
||||
assert(tree.size() == 0);
|
||||
|
||||
std::cout << "ok" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function for testing contains().
|
||||
*
|
||||
* @returns `void`
|
||||
*/
|
||||
static void test_contains() {
|
||||
std::cout << "Testing BST contains...";
|
||||
|
||||
binary_search_tree<int> tree;
|
||||
tree.insert(5);
|
||||
tree.insert(4);
|
||||
tree.insert(3);
|
||||
tree.insert(6);
|
||||
|
||||
assert(tree.contains(5));
|
||||
assert(tree.contains(4));
|
||||
assert(tree.contains(3));
|
||||
assert(tree.contains(6));
|
||||
assert(!tree.contains(999));
|
||||
|
||||
std::cout << "ok" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function for testing find_min().
|
||||
*
|
||||
* @returns `void`
|
||||
*/
|
||||
static void test_find_min() {
|
||||
std::cout << "Testing BST find_min...";
|
||||
|
||||
int min = 0;
|
||||
binary_search_tree<int> tree;
|
||||
assert(!tree.find_min(min));
|
||||
|
||||
tree.insert(5);
|
||||
tree.insert(4);
|
||||
tree.insert(3);
|
||||
tree.insert(6);
|
||||
|
||||
assert(tree.find_min(min));
|
||||
assert(min == 3);
|
||||
|
||||
std::cout << "ok" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function for testing find_max().
|
||||
*
|
||||
* @returns `void`
|
||||
*/
|
||||
static void test_find_max() {
|
||||
std::cout << "Testing BST find_max...";
|
||||
|
||||
int max = 0;
|
||||
binary_search_tree<int> tree;
|
||||
assert(!tree.find_max(max));
|
||||
|
||||
tree.insert(5);
|
||||
tree.insert(4);
|
||||
tree.insert(3);
|
||||
tree.insert(6);
|
||||
|
||||
assert(tree.find_max(max));
|
||||
assert(max == 6);
|
||||
|
||||
std::cout << "ok" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function for testing get_elements_inorder().
|
||||
*
|
||||
* @returns `void`
|
||||
*/
|
||||
static void test_get_elements_inorder() {
|
||||
std::cout << "Testing BST get_elements_inorder...";
|
||||
|
||||
binary_search_tree<int> tree;
|
||||
tree.insert(5);
|
||||
tree.insert(4);
|
||||
tree.insert(3);
|
||||
tree.insert(6);
|
||||
|
||||
std::vector<int> expected = {3, 4, 5, 6};
|
||||
std::vector<int> actual = tree.get_elements_inorder();
|
||||
assert(actual == expected);
|
||||
|
||||
std::cout << "ok" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function for testing get_elements_preorder().
|
||||
*
|
||||
* @returns `void`
|
||||
*/
|
||||
static void test_get_elements_preorder() {
|
||||
std::cout << "Testing BST get_elements_preorder...";
|
||||
|
||||
binary_search_tree<int> tree;
|
||||
tree.insert(5);
|
||||
tree.insert(4);
|
||||
tree.insert(3);
|
||||
tree.insert(6);
|
||||
|
||||
std::vector<int> expected = {5, 4, 3, 6};
|
||||
std::vector<int> actual = tree.get_elements_preorder();
|
||||
assert(actual == expected);
|
||||
|
||||
std::cout << "ok" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Function for testing get_elements_postorder().
|
||||
*
|
||||
* @returns `void`
|
||||
*/
|
||||
static void test_get_elements_postorder() {
|
||||
std::cout << "Testing BST get_elements_postorder...";
|
||||
|
||||
binary_search_tree<int> tree;
|
||||
tree.insert(5);
|
||||
tree.insert(4);
|
||||
tree.insert(3);
|
||||
tree.insert(6);
|
||||
|
||||
std::vector<int> expected = {3, 4, 6, 5};
|
||||
std::vector<int> actual = tree.get_elements_postorder();
|
||||
assert(actual == expected);
|
||||
|
||||
std::cout << "ok" << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_insert();
|
||||
test_remove();
|
||||
test_contains();
|
||||
test_find_max();
|
||||
test_find_min();
|
||||
test_get_elements_inorder();
|
||||
test_get_elements_preorder();
|
||||
test_get_elements_postorder();
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* \file
|
||||
* \brief A C++ program to demonstrate common Binary Heap Operations
|
||||
*/
|
||||
#include <climits>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
|
||||
/** A class for Min Heap */
|
||||
class MinHeap {
|
||||
int *harr; ///< pointer to array of elements in heap
|
||||
int capacity; ///< maximum possible size of min heap
|
||||
int heap_size; ///< Current number of elements in min heap
|
||||
|
||||
public:
|
||||
/** Constructor: Builds a heap from a given array a[] of given size
|
||||
* \param[in] capacity initial heap capacity
|
||||
*/
|
||||
explicit MinHeap(int cap) {
|
||||
heap_size = 0;
|
||||
capacity = cap;
|
||||
harr = new int[cap];
|
||||
}
|
||||
|
||||
/** to heapify a subtree with the root at given index */
|
||||
void MinHeapify(int);
|
||||
|
||||
int parent(int i) { return (i - 1) / 2; }
|
||||
|
||||
/** to get index of left child of node at index i */
|
||||
int left(int i) { return (2 * i + 1); }
|
||||
|
||||
/** to get index of right child of node at index i */
|
||||
int right(int i) { return (2 * i + 2); }
|
||||
|
||||
/** to extract the root which is the minimum element */
|
||||
int extractMin();
|
||||
|
||||
/** Decreases key value of key at index i to new_val */
|
||||
void decreaseKey(int i, int new_val);
|
||||
|
||||
/** Returns the minimum key (key at root) from min heap */
|
||||
int getMin() { return harr[0]; }
|
||||
|
||||
/** Deletes a key stored at index i */
|
||||
void deleteKey(int i);
|
||||
|
||||
/** Inserts a new key 'k' */
|
||||
void insertKey(int k);
|
||||
|
||||
~MinHeap() { delete[] harr; }
|
||||
};
|
||||
|
||||
// Inserts a new key 'k'
|
||||
void MinHeap::insertKey(int k) {
|
||||
if (heap_size == capacity) {
|
||||
std::cout << "\nOverflow: Could not insertKey\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// First insert the new key at the end
|
||||
heap_size++;
|
||||
int i = heap_size - 1;
|
||||
harr[i] = k;
|
||||
|
||||
// Fix the min heap property if it is violated
|
||||
while (i != 0 && harr[parent(i)] > harr[i]) {
|
||||
std::swap(harr[i], harr[parent(i)]);
|
||||
i = parent(i);
|
||||
}
|
||||
}
|
||||
|
||||
/** Decreases value of key at index 'i' to new_val. It is assumed that new_val
|
||||
* is smaller than harr[i].
|
||||
*/
|
||||
void MinHeap::decreaseKey(int i, int new_val) {
|
||||
harr[i] = new_val;
|
||||
while (i != 0 && harr[parent(i)] > harr[i]) {
|
||||
std::swap(harr[i], harr[parent(i)]);
|
||||
i = parent(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Method to remove minimum element (or root) from min heap
|
||||
int MinHeap::extractMin() {
|
||||
if (heap_size <= 0)
|
||||
return INT_MAX;
|
||||
if (heap_size == 1) {
|
||||
heap_size--;
|
||||
return harr[0];
|
||||
}
|
||||
|
||||
// Store the minimum value, and remove it from heap
|
||||
int root = harr[0];
|
||||
harr[0] = harr[heap_size - 1];
|
||||
heap_size--;
|
||||
MinHeapify(0);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/** This function deletes key at index i. It first reduced value to minus
|
||||
* infinite, then calls extractMin()
|
||||
*/
|
||||
void MinHeap::deleteKey(int i) {
|
||||
decreaseKey(i, INT_MIN);
|
||||
extractMin();
|
||||
}
|
||||
|
||||
/** A recursive method to heapify a subtree with the root at given index
|
||||
* This method assumes that the subtrees are already heapified
|
||||
*/
|
||||
void MinHeap::MinHeapify(int i) {
|
||||
int l = left(i);
|
||||
int r = right(i);
|
||||
int smallest = i;
|
||||
if (l < heap_size && harr[l] < harr[i])
|
||||
smallest = l;
|
||||
if (r < heap_size && harr[r] < harr[smallest])
|
||||
smallest = r;
|
||||
if (smallest != i) {
|
||||
std::swap(harr[i], harr[smallest]);
|
||||
MinHeapify(smallest);
|
||||
}
|
||||
}
|
||||
|
||||
// Driver program to test above functions
|
||||
int main() {
|
||||
MinHeap h(11);
|
||||
h.insertKey(3);
|
||||
h.insertKey(2);
|
||||
h.deleteKey(1);
|
||||
h.insertKey(15);
|
||||
h.insertKey(5);
|
||||
h.insertKey(4);
|
||||
h.insertKey(45);
|
||||
std::cout << h.extractMin() << " ";
|
||||
std::cout << h.getMin() << " ";
|
||||
h.decreaseKey(2, 1);
|
||||
std::cout << h.getMin();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Bloom Filter](https://en.wikipedia.org/wiki/Bloom_filter)
|
||||
* generic implementation in C++
|
||||
* @details A Bloom filter is a space-efficient probabilistic data structure,
|
||||
* a query returns either "possibly in set" or "definitely not in set".
|
||||
*
|
||||
* More generally, fewer than 10 bits per element are required for a 1% false
|
||||
* positive probability, independent of the size or number of elements in the
|
||||
* set.
|
||||
*
|
||||
* It helps us to not make an "expensive operations", like disk IO - we can
|
||||
* use bloom filter to check incoming request, and with a good probability
|
||||
* get an answer of bloom filter, that we don't need to make our "expensive
|
||||
* operation"
|
||||
*
|
||||
*
|
||||
* [Very good use case example](https://stackoverflow.com/a/30247022)
|
||||
*
|
||||
* Basic bloom filter doesn't support deleting of elements, so
|
||||
* we don't need to implement deletion in bloom filter and bitset in our case.
|
||||
* @author [DanArmor](https://github.com/DanArmor)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <functional> /// for list of hash functions for bloom filter constructor
|
||||
#include <initializer_list> /// for initializer_list for bloom filter constructor
|
||||
#include <string> /// for testing on strings
|
||||
#include <vector> /// for std::vector
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/**
|
||||
* @namespace data_structures
|
||||
* @brief Data Structures algorithms
|
||||
*/
|
||||
namespace data_structures {
|
||||
/**
|
||||
* @brief Simple bitset implementation for bloom filter
|
||||
*/
|
||||
class Bitset {
|
||||
private:
|
||||
std::vector<std::size_t> data; ///< short info of this variable
|
||||
static const std::size_t blockSize =
|
||||
sizeof(std::size_t); ///< size of integer type, that we are using in
|
||||
///< our bitset
|
||||
public:
|
||||
explicit Bitset(std::size_t);
|
||||
std::size_t size();
|
||||
void add(std::size_t);
|
||||
bool contains(std::size_t);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Utility function to return the size of the inner array
|
||||
* @returns the size of inner array
|
||||
*/
|
||||
std::size_t Bitset::size() { return data.size(); }
|
||||
|
||||
/**
|
||||
* @brief BitSet class constructor
|
||||
* @param initSize amount of blocks, each contain sizeof(std::size_t) bits
|
||||
*/
|
||||
Bitset::Bitset(std::size_t initSize) : data(initSize) {}
|
||||
|
||||
/**
|
||||
* @brief Turn bit on position x to 1s
|
||||
*
|
||||
* @param x position to turn bit on
|
||||
* @returns void
|
||||
*/
|
||||
void Bitset::add(std::size_t x) {
|
||||
std::size_t blockIndex = x / blockSize;
|
||||
if (blockIndex >= data.size()) {
|
||||
data.resize(blockIndex + 1);
|
||||
}
|
||||
data[blockIndex] |= 1 << (x % blockSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Doest bitset contains element x
|
||||
*
|
||||
* @param x position in bitset to check
|
||||
* @returns true if bit position x is 1
|
||||
* @returns false if bit position x is 0
|
||||
*/
|
||||
bool Bitset::contains(std::size_t x) {
|
||||
std::size_t blockIndex = x / blockSize;
|
||||
if (blockIndex >= data.size()) {
|
||||
return false;
|
||||
}
|
||||
return data[blockIndex] & (1 << (x % blockSize));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Bloom filter template class
|
||||
* @tparam T type of elements that we need to filter
|
||||
*/
|
||||
template <typename T>
|
||||
class BloomFilter {
|
||||
private:
|
||||
Bitset set; ///< inner bitset for elements
|
||||
std::vector<std::function<std::size_t(T)>>
|
||||
hashFunks; ///< hash functions for T type
|
||||
|
||||
public:
|
||||
BloomFilter(std::size_t,
|
||||
std::initializer_list<std::function<std::size_t(T)>>);
|
||||
void add(T);
|
||||
bool contains(T);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Constructor for Bloom filter
|
||||
*
|
||||
* @tparam T type of elements that we need to filter
|
||||
* @param size initial size of Bloom filter
|
||||
* @param funks hash functions for T type
|
||||
* @returns none
|
||||
*/
|
||||
template <typename T>
|
||||
BloomFilter<T>::BloomFilter(
|
||||
std::size_t size,
|
||||
std::initializer_list<std::function<std::size_t(T)>> funks)
|
||||
: set(size), hashFunks(funks) {}
|
||||
|
||||
/**
|
||||
* @brief Add function for Bloom filter
|
||||
*
|
||||
* @tparam T type of elements that we need to filter
|
||||
* @param x element to add to filter
|
||||
* @returns void
|
||||
*/
|
||||
template <typename T>
|
||||
void BloomFilter<T>::add(T x) {
|
||||
for (std::size_t i = 0; i < hashFunks.size(); i++) {
|
||||
set.add(hashFunks[i](x) % (sizeof(std::size_t) * set.size()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check element function for Bloom filter
|
||||
*
|
||||
* @tparam T type of elements that we need to filter
|
||||
* @param x element to check in filter
|
||||
* @return true if the element probably appears in the filter
|
||||
* @return false if the element certainly does not appear in the filter
|
||||
*/
|
||||
template <typename T>
|
||||
bool BloomFilter<T>::contains(T x) {
|
||||
for (std::size_t i = 0; i < hashFunks.size(); i++) {
|
||||
if (set.contains(hashFunks[i](x) %
|
||||
(sizeof(std::size_t) * set.size())) == false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief [Function djb2](http://www.cse.yorku.ca/~oz/hash.html)
|
||||
* to get hash for the given string.
|
||||
*
|
||||
* @param s string to get hash from
|
||||
* @returns hash for a string
|
||||
*/
|
||||
static std::size_t hashDJB2(std::string const& s) {
|
||||
std::size_t hash = 5381;
|
||||
for (char c : s) {
|
||||
hash = ((hash << 5) + hash) + c;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief [Hash
|
||||
* function](https://stackoverflow.com/questions/8317508/hash-function-for-a-string),
|
||||
* to get hash for the given string.
|
||||
*
|
||||
* @param s string to get hash from
|
||||
* @returns hash for the given string
|
||||
*/
|
||||
static std::size_t hashStr(std::string const& s) {
|
||||
std::size_t hash = 37;
|
||||
std::size_t primeNum1 = 54059;
|
||||
std::size_t primeNum2 = 76963;
|
||||
for (char c : s) {
|
||||
hash = (hash * primeNum1) ^ (c * primeNum2);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief [Hash function for
|
||||
* test](https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key)
|
||||
*
|
||||
* @param x to get hash from
|
||||
* @returns hash for the `x` parameter
|
||||
*/
|
||||
std::size_t hashInt_1(int x) {
|
||||
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||
x = (x >> 16) ^ x;
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief [Hash function for
|
||||
* test](https://stackoverflow.com/questions/664014/what-integer-hash-function-are-good-that-accepts-an-integer-hash-key)
|
||||
*
|
||||
* @param x to get hash from
|
||||
* @returns hash for the `x` parameter
|
||||
*/
|
||||
std::size_t hashInt_2(int x) {
|
||||
auto y = static_cast<std::size_t>(x);
|
||||
y = (y ^ (y >> 30)) * static_cast<std::size_t>(0xbf58476d1ce4e5b9);
|
||||
y = (y ^ (y >> 27)) * static_cast<std::size_t>(0x94d049bb133111eb);
|
||||
y = y ^ (y >> 31);
|
||||
return y;
|
||||
}
|
||||
} // namespace data_structures
|
||||
|
||||
/**
|
||||
* @brief Test for bloom filter with string as generic type
|
||||
* @returns void
|
||||
*/
|
||||
static void test_bloom_filter_string() {
|
||||
data_structures::BloomFilter<std::string> filter(
|
||||
10, {data_structures::hashDJB2, data_structures::hashStr});
|
||||
std::vector<std::string> toCheck{"hello", "world", "!"};
|
||||
std::vector<std::string> toFalse{"false", "world2", "!!!"};
|
||||
for (const auto& x : toCheck) {
|
||||
filter.add(x);
|
||||
}
|
||||
for (const auto& x : toFalse) {
|
||||
assert(filter.contains(x) == false);
|
||||
}
|
||||
for (const auto& x : toCheck) {
|
||||
assert(filter.contains(x));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test for bloom filter with int as generic type
|
||||
* @returns void
|
||||
*/
|
||||
static void test_bloom_filter_int() {
|
||||
data_structures::BloomFilter<int> filter(
|
||||
20, {data_structures::hashInt_1, data_structures::hashInt_2});
|
||||
std::vector<int> toCheck{100, 200, 300, 50};
|
||||
std::vector<int> toFalse{1, 2, 3, 4, 5, 6, 7, 8};
|
||||
for (int x : toCheck) {
|
||||
filter.add(x);
|
||||
}
|
||||
for (int x : toFalse) {
|
||||
assert(filter.contains(x) == false);
|
||||
}
|
||||
for (int x : toCheck) {
|
||||
assert(filter.contains(x));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test for bitset
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
static void test_bitset() {
|
||||
data_structures::Bitset set(2);
|
||||
std::vector<std::size_t> toCheck{0, 1, 5, 8, 63, 64, 67, 127};
|
||||
for (auto x : toCheck) {
|
||||
set.add(x);
|
||||
assert(set.contains(x));
|
||||
}
|
||||
assert(set.contains(128) == false);
|
||||
assert(set.contains(256) == false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
// run self-test implementations
|
||||
|
||||
test_bitset(); // run test for bitset, because bloom filter is depending on it
|
||||
test_bloom_filter_string();
|
||||
test_bloom_filter_int();
|
||||
|
||||
std::cout << "All tests have successfully passed!\n";
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
#include <iostream>
|
||||
|
||||
struct node {
|
||||
int data;
|
||||
struct node* next;
|
||||
};
|
||||
class Queue {
|
||||
node* front = nullptr;
|
||||
node* rear = nullptr;
|
||||
|
||||
Queue(const Queue&) = delete;
|
||||
Queue& operator=(const Queue&) = delete;
|
||||
|
||||
public:
|
||||
Queue() = default;
|
||||
~Queue() {
|
||||
while (front) {
|
||||
dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void createNode(int val) {
|
||||
auto* nn = new node;
|
||||
nn->data = val;
|
||||
nn->next = nullptr;
|
||||
front = nn;
|
||||
rear = nn;
|
||||
}
|
||||
|
||||
public:
|
||||
void enqueue(int val) {
|
||||
if (front == nullptr || rear == nullptr) {
|
||||
createNode(val);
|
||||
} else {
|
||||
node* nn = new node;
|
||||
nn->data = val;
|
||||
rear->next = nn;
|
||||
nn->next = front;
|
||||
rear = nn;
|
||||
}
|
||||
}
|
||||
void dequeue() {
|
||||
if (front == nullptr) {
|
||||
return;
|
||||
}
|
||||
const node* const n = front;
|
||||
if (front == rear) {
|
||||
front = nullptr;
|
||||
rear = nullptr;
|
||||
} else {
|
||||
front = front->next;
|
||||
rear->next = front;
|
||||
}
|
||||
delete n;
|
||||
}
|
||||
void traverse() {
|
||||
if (front == nullptr) {
|
||||
return;
|
||||
}
|
||||
const node* ptr = front;
|
||||
do {
|
||||
std::cout << ptr->data << ' ';
|
||||
ptr = ptr->next;
|
||||
} while (ptr != front);
|
||||
std::cout << '\n';
|
||||
}
|
||||
};
|
||||
int main(void) {
|
||||
Queue q;
|
||||
q.enqueue(10);
|
||||
q.enqueue(20);
|
||||
q.enqueue(30);
|
||||
q.enqueue(40);
|
||||
q.enqueue(50);
|
||||
q.enqueue(60);
|
||||
q.enqueue(70);
|
||||
q.traverse();
|
||||
q.dequeue();
|
||||
q.traverse();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
add_executable( cll
|
||||
cll.cpp
|
||||
main_cll.cpp
|
||||
)
|
||||
install(TARGETS cll DESTINATION "bin/data_structures")
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
A simple class for Cicular Linear Linked List
|
||||
*/
|
||||
#include "cll.h"
|
||||
using namespace std;
|
||||
|
||||
/* Constructor */
|
||||
cll::cll() {
|
||||
head = NULL;
|
||||
total = 0;
|
||||
}
|
||||
|
||||
cll::~cll() { /* Desstructure, no need to fill */
|
||||
}
|
||||
|
||||
/* Display a list. and total element */
|
||||
void cll::display() {
|
||||
if (head == NULL)
|
||||
cout << "List is empty !" << endl;
|
||||
else {
|
||||
cout << "CLL list: ";
|
||||
node *current = head;
|
||||
for (int i = 0; i < total; i++) {
|
||||
cout << current->data << " -> ";
|
||||
current = current->next;
|
||||
}
|
||||
cout << head->data << endl;
|
||||
cout << "Total element: " << total << endl;
|
||||
}
|
||||
}
|
||||
|
||||
/* List insert a new value at head in list */
|
||||
void cll::insert_front(int new_data) {
|
||||
node *newNode;
|
||||
newNode = new node;
|
||||
newNode->data = new_data;
|
||||
newNode->next = NULL;
|
||||
if (head == NULL) {
|
||||
head = newNode;
|
||||
head->next = head;
|
||||
} else {
|
||||
node *current = head;
|
||||
while (current->next != head) {
|
||||
current = current->next;
|
||||
}
|
||||
newNode->next = head;
|
||||
current->next = newNode;
|
||||
head = newNode;
|
||||
}
|
||||
total++;
|
||||
}
|
||||
|
||||
/* List insert a new value at head in list */
|
||||
void cll::insert_tail(int new_data) {
|
||||
node *newNode;
|
||||
newNode = new node;
|
||||
newNode->data = new_data;
|
||||
newNode->next = NULL;
|
||||
if (head == NULL) {
|
||||
head = newNode;
|
||||
head->next = head;
|
||||
} else {
|
||||
node *current = head;
|
||||
while (current->next != head) {
|
||||
current = current->next;
|
||||
}
|
||||
current->next = newNode;
|
||||
newNode->next = head;
|
||||
}
|
||||
total++;
|
||||
}
|
||||
|
||||
/* Get total element in list */
|
||||
int cll::get_size() { return total; }
|
||||
|
||||
/* Return true if the requested item (sent in as an argument)
|
||||
is in the list, otherwise return false */
|
||||
bool cll::find_item(int item_to_find) {
|
||||
if (head == NULL) {
|
||||
cout << "List is empty !" << endl;
|
||||
return false;
|
||||
} else {
|
||||
node *current = head;
|
||||
while (current->next != head) {
|
||||
if (current->data == item_to_find)
|
||||
return true;
|
||||
current = current->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Overloading method*/
|
||||
int cll::operator*() { return head->data; }
|
||||
|
||||
/* Overload the pre-increment operator.
|
||||
The iterator is advanced to the next node. */
|
||||
void cll::operator++() {
|
||||
if (head == NULL) {
|
||||
cout << "List is empty !" << endl;
|
||||
} else {
|
||||
node *current = head;
|
||||
while (current->next != head) {
|
||||
current = current->next;
|
||||
}
|
||||
current->next = head->next;
|
||||
head = head->next;
|
||||
}
|
||||
total--;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Simple data structure CLL (Circular Linear Linked List)
|
||||
* */
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
#ifndef CLL_H
|
||||
#define CLL_H
|
||||
/*The data structure is a linear linked list of integers */
|
||||
struct node {
|
||||
int data;
|
||||
node* next;
|
||||
};
|
||||
|
||||
class cll {
|
||||
public:
|
||||
cll(); /* Construct without parameter */
|
||||
~cll();
|
||||
void display(); /* Show the list */
|
||||
|
||||
/******************************************************
|
||||
* Useful method for list
|
||||
*******************************************************/
|
||||
void insert_front(int new_data); /* Insert a new value at head */
|
||||
void insert_tail(int new_data); /* Insert a new value at tail */
|
||||
int get_size(); /* Get total element in list */
|
||||
bool find_item(int item_to_find); /* Find an item in list */
|
||||
|
||||
/******************************************************
|
||||
* Overloading method for list
|
||||
*******************************************************/
|
||||
int operator*(); /* Returns the info contained in head */
|
||||
/* Overload the pre-increment operator.
|
||||
The iterator is advanced to the next node. */
|
||||
void operator++();
|
||||
|
||||
protected:
|
||||
node* head;
|
||||
int total; /* Total element in a list */
|
||||
};
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
#include "cll.h"
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
/* Test CLL */
|
||||
cout << "----------- Test construct -----------" << endl;
|
||||
cll list1;
|
||||
list1.display();
|
||||
cout << "----------- Test insert front -----------" << endl;
|
||||
list1.insert_front(5);
|
||||
cout << "After insert 5 at front: " << endl;
|
||||
list1.display();
|
||||
cout << "After insert 10 3 7 at front: " << endl;
|
||||
list1.insert_front(10);
|
||||
list1.insert_front(3);
|
||||
list1.insert_front(7);
|
||||
list1.display();
|
||||
cout << "----------- Test insert tail -----------" << endl;
|
||||
cout << "After insert 18 19 20 at tail: " << endl;
|
||||
list1.insert_tail(18);
|
||||
list1.insert_tail(19);
|
||||
list1.insert_tail(20);
|
||||
list1.display();
|
||||
cout << "----------- Test find item -----------" << endl;
|
||||
if (list1.find_item(10))
|
||||
cout << "PASS" << endl;
|
||||
else
|
||||
cout << "FAIL" << endl;
|
||||
if (!list1.find_item(30))
|
||||
cout << "PASS" << endl;
|
||||
else
|
||||
cout << "FAIL" << endl;
|
||||
cout << "----------- Test * operator -----------" << endl;
|
||||
int value = *list1;
|
||||
cout << "Value at *list1: " << value << endl;
|
||||
cout << "----------- Test ++ operator -----------" << endl;
|
||||
list1.display();
|
||||
++list1;
|
||||
cout << "After ++list1: " << endl;
|
||||
list1.display();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
*
|
||||
* \file
|
||||
* \brief [Disjoint Sets Data Structure
|
||||
* (Disjoint Sets)](https://en.wikipedia.org/wiki/Disjoint-set_data_structure)
|
||||
*
|
||||
* \author [leoyang429](https://github.com/leoyang429)
|
||||
*
|
||||
* \details
|
||||
* A disjoint set data structure (also called union find or merge find set)
|
||||
* is a data structure that tracks a set of elements partitioned into a number
|
||||
* of disjoint (non-overlapping) subsets.
|
||||
* Some situations where disjoint sets can be used are-
|
||||
* to find connected components of a graph, kruskal's algorithm for finding
|
||||
* Minimum Spanning Tree etc.
|
||||
* There are two operation which we perform on disjoint sets -
|
||||
* 1) Union
|
||||
* 2) Find
|
||||
*
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::vector;
|
||||
|
||||
vector<int> root, rank;
|
||||
|
||||
/**
|
||||
*
|
||||
* Function to create a set
|
||||
* @param n number of element
|
||||
*
|
||||
*/
|
||||
void CreateSet(int n) {
|
||||
root = vector<int>(n + 1);
|
||||
rank = vector<int>(n + 1, 1);
|
||||
for (int i = 1; i <= n; ++i) {
|
||||
root[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Find operation takes a number x and returns the set to which this number
|
||||
* belongs to.
|
||||
* @param x element of some set
|
||||
* @return set to which x belongs to
|
||||
*
|
||||
*/
|
||||
int Find(int x) {
|
||||
if (root[x] == x) {
|
||||
return x;
|
||||
}
|
||||
return root[x] = Find(root[x]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* A utility function to check if x and y are from same set or not
|
||||
* @param x element of some set
|
||||
* @param y element of some set
|
||||
*
|
||||
*/
|
||||
bool InSameUnion(int x, int y) { return Find(x) == Find(y); }
|
||||
|
||||
/**
|
||||
*
|
||||
* Union operation combines two disjoint sets to make a single set
|
||||
* in this union function we pass two elements and check if they are
|
||||
* from different sets then combine those sets
|
||||
* @param x element of some set
|
||||
* @param y element of some set
|
||||
*
|
||||
*/
|
||||
void Union(int x, int y) {
|
||||
int a = Find(x), b = Find(y);
|
||||
if (a != b) {
|
||||
if (rank[a] < rank[b]) {
|
||||
root[a] = b;
|
||||
} else if (rank[a] > rank[b]) {
|
||||
root[b] = a;
|
||||
} else {
|
||||
root[a] = b;
|
||||
++rank[b];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Main function */
|
||||
int main() {
|
||||
// tests CreateSet & Find
|
||||
int n = 100;
|
||||
CreateSet(n);
|
||||
for (int i = 1; i <= 100; ++i) {
|
||||
if (root[i] != i) {
|
||||
cout << "Fail" << endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// tests InSameUnion & Union
|
||||
cout << "1 and 2 are initially not in the same subset" << endl;
|
||||
if (InSameUnion(1, 2)) {
|
||||
cout << "Fail" << endl;
|
||||
}
|
||||
Union(1, 2);
|
||||
cout << "1 and 2 are now in the same subset" << endl;
|
||||
if (!InSameUnion(1, 2)) {
|
||||
cout << "Fail" << endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
struct node {
|
||||
int val;
|
||||
node *prev;
|
||||
node *next;
|
||||
} * start;
|
||||
|
||||
class double_linked_list {
|
||||
public:
|
||||
double_linked_list() { start = NULL; }
|
||||
void insert(int x);
|
||||
void remove(int x);
|
||||
void search(int x);
|
||||
void show();
|
||||
void reverseShow();
|
||||
};
|
||||
|
||||
void double_linked_list::insert(int x) {
|
||||
node *t = start;
|
||||
if (start != NULL) {
|
||||
while (t->next != NULL) {
|
||||
t = t->next;
|
||||
}
|
||||
node *n = new node;
|
||||
t->next = n;
|
||||
n->prev = t;
|
||||
n->val = x;
|
||||
n->next = NULL;
|
||||
} else {
|
||||
node *n = new node;
|
||||
n->val = x;
|
||||
n->prev = NULL;
|
||||
n->next = NULL;
|
||||
start = n;
|
||||
}
|
||||
}
|
||||
|
||||
void double_linked_list::remove(int x) {
|
||||
node *t = start;
|
||||
while (t != NULL && t->val != x) {
|
||||
t = t->next;
|
||||
}
|
||||
if (t == NULL) {
|
||||
return;
|
||||
}
|
||||
if (t->prev == NULL) {
|
||||
if (t->next == NULL) {
|
||||
start = NULL;
|
||||
} else {
|
||||
start = t->next;
|
||||
start->prev = NULL;
|
||||
}
|
||||
} else if (t->next == NULL) {
|
||||
t->prev->next = NULL;
|
||||
} else {
|
||||
t->prev->next = t->next;
|
||||
t->next->prev = t->prev;
|
||||
}
|
||||
delete t;
|
||||
}
|
||||
|
||||
void double_linked_list::search(int x) {
|
||||
node *t = start;
|
||||
int found = 0;
|
||||
while (t != NULL) {
|
||||
if (t->val == x) {
|
||||
std::cout << "\nFound";
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
t = t->next;
|
||||
}
|
||||
if (found == 0) {
|
||||
std::cout << "\nNot Found";
|
||||
}
|
||||
}
|
||||
|
||||
void double_linked_list::show() {
|
||||
node *t = start;
|
||||
while (t != NULL) {
|
||||
std::cout << t->val << "\t";
|
||||
t = t->next;
|
||||
}
|
||||
}
|
||||
|
||||
void double_linked_list::reverseShow() {
|
||||
node *t = start;
|
||||
while (t != NULL && t->next != NULL) {
|
||||
t = t->next;
|
||||
}
|
||||
while (t != NULL) {
|
||||
std::cout << t->val << "\t";
|
||||
t = t->prev;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
int choice, x;
|
||||
double_linked_list ob;
|
||||
do {
|
||||
std::cout << "\n1. Insert";
|
||||
std::cout << "\n2. Delete";
|
||||
std::cout << "\n3. Search";
|
||||
std::cout << "\n4. Forward print";
|
||||
std::cout << "\n5. Reverse print";
|
||||
std::cout << "\n\nEnter you choice : ";
|
||||
std::cin >> choice;
|
||||
switch (choice) {
|
||||
case 1:
|
||||
std::cout << "\nEnter the element to be inserted : ";
|
||||
std::cin >> x;
|
||||
ob.insert(x);
|
||||
break;
|
||||
case 2:
|
||||
std::cout << "\nEnter the element to be removed : ";
|
||||
std::cin >> x;
|
||||
ob.remove(x);
|
||||
break;
|
||||
case 3:
|
||||
std::cout << "\nEnter the element to be searched : ";
|
||||
std::cin >> x;
|
||||
ob.search(x);
|
||||
break;
|
||||
case 4:
|
||||
ob.show();
|
||||
break;
|
||||
case 5:
|
||||
ob.reverseShow();
|
||||
break;
|
||||
}
|
||||
} while (choice != 0);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [DSU (Disjoint
|
||||
* sets)](https://en.wikipedia.org/wiki/Disjoint-set-data_structure)
|
||||
* @details
|
||||
* It is a very powerful data structure that keeps track of different
|
||||
* clusters(sets) of elements, these sets are disjoint(doesnot have a common
|
||||
* element). Disjoint sets uses cases : for finding connected components in a
|
||||
* graph, used in Kruskal's algorithm for finding Minimum Spanning tree.
|
||||
* Operations that can be performed:
|
||||
* 1) UnionSet(i,j): add(element i and j to the set)
|
||||
* 2) findSet(i): returns the representative of the set to which i belogngs to.
|
||||
* 3) get_max(i),get_min(i) : returns the maximum and minimum
|
||||
* Below is the class-based approach which uses the heuristic of path
|
||||
* compression. Using path compression in findSet(i),we are able to get to the
|
||||
* representative of i in O(1) time.
|
||||
* @author [AayushVyasKIIT](https://github.com/AayushVyasKIIT)
|
||||
* @see dsu_union_rank.cpp
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::vector;
|
||||
|
||||
/**
|
||||
* @brief Disjoint sets union data structure, class based representation.
|
||||
* @param n number of elements
|
||||
*/
|
||||
class dsu {
|
||||
private:
|
||||
vector<uint64_t> p; ///< keeps track of the parent of ith element
|
||||
vector<uint64_t> depth; ///< tracks the depth(rank) of i in the tree
|
||||
vector<uint64_t> setSize; ///< size of each chunk(set)
|
||||
vector<uint64_t> maxElement; ///< maximum of each set to which i belongs to
|
||||
vector<uint64_t> minElement; ///< minimum of each set to which i belongs to
|
||||
public:
|
||||
/**
|
||||
* @brief contructor for initialising all data members.
|
||||
* @param n number of elements
|
||||
*/
|
||||
explicit dsu(uint64_t n) {
|
||||
p.assign(n, 0);
|
||||
/// initially, all of them are their own parents
|
||||
for (uint64_t i = 0; i < n; i++) {
|
||||
p[i] = i;
|
||||
}
|
||||
/// initially all have depth are equals to zero
|
||||
depth.assign(n, 0);
|
||||
maxElement.assign(n, 0);
|
||||
minElement.assign(n, 0);
|
||||
for (uint64_t i = 0; i < n; i++) {
|
||||
depth[i] = 0;
|
||||
maxElement[i] = i;
|
||||
minElement[i] = i;
|
||||
}
|
||||
setSize.assign(n, 0);
|
||||
/// initially set size will be equals to one
|
||||
for (uint64_t i = 0; i < n; i++) {
|
||||
setSize[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Method to find the representative of the set to which i belongs
|
||||
* to, T(n) = O(1)
|
||||
* @param i element of some set
|
||||
* @returns representative of the set to which i belongs to.
|
||||
*/
|
||||
uint64_t findSet(uint64_t i) {
|
||||
/// using path compression
|
||||
if (p[i] == i) {
|
||||
return i;
|
||||
}
|
||||
return (p[i] = findSet(p[i]));
|
||||
}
|
||||
/**
|
||||
* @brief Method that combines two disjoint sets to which i and j belongs to
|
||||
* and make a single set having a common representative.
|
||||
* @param i element of some set
|
||||
* @param j element of some set
|
||||
* @returns void
|
||||
*/
|
||||
void UnionSet(uint64_t i, uint64_t j) {
|
||||
/// check if both belongs to the same set or not
|
||||
if (isSame(i, j)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// we find the representative of the i and j
|
||||
uint64_t x = findSet(i);
|
||||
uint64_t y = findSet(j);
|
||||
|
||||
/// always keeping the min as x
|
||||
/// shallow tree
|
||||
if (depth[x] > depth[y]) {
|
||||
std::swap(x, y);
|
||||
}
|
||||
/// making the shallower root's parent the deeper root
|
||||
p[x] = y;
|
||||
|
||||
/// if same depth, then increase one's depth
|
||||
if (depth[x] == depth[y]) {
|
||||
depth[y]++;
|
||||
}
|
||||
/// total size of the resultant set
|
||||
setSize[y] += setSize[x];
|
||||
/// changing the maximum elements
|
||||
maxElement[y] = std::max(maxElement[x], maxElement[y]);
|
||||
minElement[y] = std::min(minElement[x], minElement[y]);
|
||||
}
|
||||
/**
|
||||
* @brief A utility function which check whether i and j belongs to
|
||||
* same set or not
|
||||
* @param i element of some set
|
||||
* @param j element of some set
|
||||
* @returns `true` if element `i` and `j` ARE in the same set
|
||||
* @returns `false` if element `i` and `j` are NOT in same set
|
||||
*/
|
||||
bool isSame(uint64_t i, uint64_t j) {
|
||||
if (findSet(i) == findSet(j)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @brief prints the minimum, maximum and size of the set to which i belongs
|
||||
* to
|
||||
* @param i element of some set
|
||||
* @returns void
|
||||
*/
|
||||
vector<uint64_t> get(uint64_t i) {
|
||||
vector<uint64_t> ans;
|
||||
ans.push_back(get_min(i));
|
||||
ans.push_back(get_max(i));
|
||||
ans.push_back(size(i));
|
||||
return ans;
|
||||
}
|
||||
/**
|
||||
* @brief A utility function that returns the size of the set to which i
|
||||
* belongs to
|
||||
* @param i element of some set
|
||||
* @returns size of the set to which i belongs to
|
||||
*/
|
||||
uint64_t size(uint64_t i) { return setSize[findSet(i)]; }
|
||||
/**
|
||||
* @brief A utility function that returns the max element of the set to
|
||||
* which i belongs to
|
||||
* @param i element of some set
|
||||
* @returns maximum of the set to which i belongs to
|
||||
*/
|
||||
uint64_t get_max(uint64_t i) { return maxElement[findSet(i)]; }
|
||||
/**
|
||||
* @brief A utility function that returns the min element of the set to
|
||||
* which i belongs to
|
||||
* @param i element of some set
|
||||
* @returns minimum of the set to which i belongs to
|
||||
*/
|
||||
uint64_t get_min(uint64_t i) { return minElement[findSet(i)]; }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations, 1st test
|
||||
* @returns void
|
||||
*/
|
||||
static void test1() {
|
||||
// the minimum, maximum, and size of the set
|
||||
uint64_t n = 10; ///< number of items
|
||||
dsu d(n + 1); ///< object of class disjoint sets
|
||||
// set 1
|
||||
d.UnionSet(1, 2); // performs union operation on 1 and 2
|
||||
d.UnionSet(1, 4); // performs union operation on 1 and 4
|
||||
vector<uint64_t> ans = {1, 4, 3};
|
||||
for (uint64_t i = 0; i < ans.size(); i++) {
|
||||
assert(d.get(4).at(i) == ans[i]); // makes sure algorithm works fine
|
||||
}
|
||||
cout << "1st test passed!" << endl;
|
||||
}
|
||||
/**
|
||||
* @brief Self-implementations, 2nd test
|
||||
* @returns void
|
||||
*/
|
||||
static void test2() {
|
||||
// the minimum, maximum, and size of the set
|
||||
uint64_t n = 10; ///< number of items
|
||||
dsu d(n + 1); ///< object of class disjoint sets
|
||||
// set 1
|
||||
d.UnionSet(3, 5);
|
||||
d.UnionSet(5, 6);
|
||||
d.UnionSet(5, 7);
|
||||
vector<uint64_t> ans = {3, 7, 4};
|
||||
for (uint64_t i = 0; i < ans.size(); i++) {
|
||||
assert(d.get(3).at(i) == ans[i]); // makes sure algorithm works fine
|
||||
}
|
||||
cout << "2nd test passed!" << endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
* */
|
||||
int main() {
|
||||
uint64_t n = 10; ///< number of items
|
||||
dsu d(n + 1); ///< object of class disjoint sets
|
||||
|
||||
test1(); // run 1st test case
|
||||
test2(); // run 2nd test case
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [DSU (Disjoint
|
||||
* sets)](https://en.wikipedia.org/wiki/Disjoint-set-data_structure)
|
||||
* @details
|
||||
* dsu : It is a very powerful data structure which keeps track of different
|
||||
* clusters(sets) of elements, these sets are disjoint(doesnot have a common
|
||||
* element). Disjoint sets uses cases : for finding connected components in a
|
||||
* graph, used in Kruskal's algorithm for finding Minimum Spanning tree.
|
||||
* Operations that can be performed:
|
||||
* 1) UnionSet(i,j): add(element i and j to the set)
|
||||
* 2) findSet(i): returns the representative of the set to which i belogngs to.
|
||||
* 3) getParents(i): prints the parent of i and so on and so forth.
|
||||
* Below is the class-based approach which uses the heuristic of union-ranks.
|
||||
* Using union-rank in findSet(i),we are able to get to the representative of i
|
||||
* in slightly delayed O(logN) time but it allows us to keep tracks of the
|
||||
* parent of i.
|
||||
* @author [AayushVyasKIIT](https://github.com/AayushVyasKIIT)
|
||||
* @see dsu_path_compression.cpp
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
using std::vector;
|
||||
|
||||
/**
|
||||
* @brief Disjoint sets union data structure, class based representation.
|
||||
* @param n number of elements
|
||||
*/
|
||||
class dsu {
|
||||
private:
|
||||
vector<uint64_t> p; ///< keeps track of the parent of ith element
|
||||
vector<uint64_t> depth; ///< tracks the depth(rank) of i in the tree
|
||||
vector<uint64_t> setSize; ///< size of each chunk(set)
|
||||
public:
|
||||
/**
|
||||
* @brief constructor for initialising all data members
|
||||
* @param n number of elements
|
||||
*/
|
||||
explicit dsu(uint64_t n) {
|
||||
p.assign(n, 0);
|
||||
/// initially all of them are their own parents
|
||||
depth.assign(n, 0);
|
||||
setSize.assign(n, 0);
|
||||
for (uint64_t i = 0; i < n; i++) {
|
||||
p[i] = i;
|
||||
depth[i] = 0;
|
||||
setSize[i] = 1;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Method to find the representative of the set to which i belongs
|
||||
* to, T(n) = O(logN)
|
||||
* @param i element of some set
|
||||
* @returns representative of the set to which i belongs to
|
||||
*/
|
||||
uint64_t findSet(uint64_t i) {
|
||||
/// using union-rank
|
||||
while (i != p[i]) {
|
||||
i = p[i];
|
||||
}
|
||||
return i;
|
||||
}
|
||||
/**
|
||||
* @brief Method that combines two disjoint sets to which i and j belongs to
|
||||
* and make a single set having a common representative.
|
||||
* @param i element of some set
|
||||
* @param j element of some set
|
||||
* @returns void
|
||||
*/
|
||||
void unionSet(uint64_t i, uint64_t j) {
|
||||
/// checks if both belongs to same set or not
|
||||
if (isSame(i, j)) {
|
||||
return;
|
||||
}
|
||||
/// we find representative of the i and j
|
||||
uint64_t x = findSet(i);
|
||||
uint64_t y = findSet(j);
|
||||
|
||||
/// always keeping the min as x
|
||||
/// in order to create a shallow tree
|
||||
if (depth[x] > depth[y]) {
|
||||
std::swap(x, y);
|
||||
}
|
||||
/// making the shallower tree, root parent of the deeper root
|
||||
p[x] = y;
|
||||
|
||||
/// if same depth, then increase one's depth
|
||||
if (depth[x] == depth[y]) {
|
||||
depth[y]++;
|
||||
}
|
||||
/// total size of the resultant set
|
||||
setSize[y] += setSize[x];
|
||||
}
|
||||
/**
|
||||
* @brief A utility function which check whether i and j belongs to same set
|
||||
* or not
|
||||
* @param i element of some set
|
||||
* @param j element of some set
|
||||
* @returns `true` if element i and j are in same set
|
||||
* @returns `false` if element i and j are not in same set
|
||||
*/
|
||||
bool isSame(uint64_t i, uint64_t j) {
|
||||
if (findSet(i) == findSet(j)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @brief Method to print all the parents of i, or the path from i to
|
||||
* representative.
|
||||
* @param i element of some set
|
||||
* @returns void
|
||||
*/
|
||||
vector<uint64_t> getParents(uint64_t i) {
|
||||
vector<uint64_t> ans;
|
||||
while (p[i] != i) {
|
||||
ans.push_back(i);
|
||||
i = p[i];
|
||||
}
|
||||
ans.push_back(i);
|
||||
return ans;
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @brief Self-implementations, 1st test
|
||||
* @returns void
|
||||
*/
|
||||
static void test1() {
|
||||
/* checks the parents in the resultant structures */
|
||||
uint64_t n = 10; ///< number of elements
|
||||
dsu d(n + 1); ///< object of class disjoint sets
|
||||
d.unionSet(2, 1); ///< performs union operation on 1 and 2
|
||||
d.unionSet(1, 4);
|
||||
d.unionSet(8, 1);
|
||||
d.unionSet(3, 5);
|
||||
d.unionSet(5, 6);
|
||||
d.unionSet(5, 7);
|
||||
d.unionSet(9, 10);
|
||||
d.unionSet(2, 10);
|
||||
// keeping track of the changes using parent pointers
|
||||
vector<uint64_t> ans = {7, 5};
|
||||
for (uint64_t i = 0; i < ans.size(); i++) {
|
||||
assert(d.getParents(7).at(i) ==
|
||||
ans[i]); // makes sure algorithm works fine
|
||||
}
|
||||
cout << "1st test passed!" << endl;
|
||||
}
|
||||
/**
|
||||
* @brief Self-implementations, 2nd test
|
||||
* @returns void
|
||||
*/
|
||||
static void test2() {
|
||||
// checks the parents in the resultant structures
|
||||
uint64_t n = 10; ///< number of elements
|
||||
dsu d(n + 1); ///< object of class disjoint sets
|
||||
d.unionSet(2, 1); /// performs union operation on 1 and 2
|
||||
d.unionSet(1, 4);
|
||||
d.unionSet(8, 1);
|
||||
d.unionSet(3, 5);
|
||||
d.unionSet(5, 6);
|
||||
d.unionSet(5, 7);
|
||||
d.unionSet(9, 10);
|
||||
d.unionSet(2, 10);
|
||||
|
||||
/// keeping track of the changes using parent pointers
|
||||
vector<uint64_t> ans = {2, 1, 10};
|
||||
for (uint64_t i = 0; i < ans.size(); i++) {
|
||||
assert(d.getParents(2).at(i) ==
|
||||
ans[i]); /// makes sure algorithm works fine
|
||||
}
|
||||
cout << "2nd test passed!" << endl;
|
||||
}
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test1(); // run 1st test case
|
||||
test2(); // run 2nd test case
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of singly linked list algorithm.
|
||||
* @details
|
||||
* The linked list is a data structure used for holding a sequence of
|
||||
* values, which can be added, removed and displayed.
|
||||
* ### Algorithm
|
||||
* Values can be added by iterating to the end of a list(by following
|
||||
* the pointers) starting from the first link. Whichever link points to null
|
||||
* is considered the last link and is pointed to the new value.
|
||||
*
|
||||
* Values can be removed by also iterating through the list. When the node
|
||||
* containing the value is found, the node pointing to the current node is made
|
||||
* to point to the node that the current node is pointing to, and then returning
|
||||
* the current node to heap store.
|
||||
*/
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* @namespace data_structures
|
||||
* @brief Data Structures algorithms
|
||||
*/
|
||||
namespace data_structures {
|
||||
|
||||
/**
|
||||
* @namespace linked_list
|
||||
* @brief Functions for singly linked list algorithm
|
||||
*/
|
||||
namespace linked_list {
|
||||
|
||||
/**
|
||||
* This function checks if the string passed consists
|
||||
* of only digits.
|
||||
* @param s To be checked if s contains only integers
|
||||
* @returns true if there are only digits present in the string
|
||||
* @returns false if any other character is found
|
||||
*/
|
||||
bool isDigit(const std::string& s) {
|
||||
// function statements here
|
||||
for (char i : s) {
|
||||
if (!isdigit(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* A link class containing a value and pointer to another link
|
||||
*/
|
||||
class link {
|
||||
private:
|
||||
int pvalue; ///< value of the current link
|
||||
std::shared_ptr<link> psucc; ///< pointer to the next value on the list
|
||||
|
||||
public:
|
||||
/**
|
||||
* function returns the integer value stored in the link.
|
||||
* @returns the integer value stored in the link.
|
||||
*/
|
||||
int val() { return pvalue; }
|
||||
|
||||
/**
|
||||
* function returns the pointer to next link
|
||||
* @returns the pointer to the next link
|
||||
* */
|
||||
std::shared_ptr<link>& succ() { return psucc; }
|
||||
|
||||
/**
|
||||
* Creates link with provided value and pointer to next link
|
||||
* @param value is the integer stored in the link
|
||||
*/
|
||||
explicit link(int value = 0) : pvalue(value), psucc(nullptr) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* A list class containing a sequence of links
|
||||
*/
|
||||
class list {
|
||||
private:
|
||||
std::shared_ptr<link> first; ///< link before the actual first element
|
||||
std::shared_ptr<link> last; ///< last link on the list
|
||||
public:
|
||||
/**
|
||||
* List constructor. Initializes the first and last link.
|
||||
*/
|
||||
list() {
|
||||
// Initialize the first link
|
||||
first = std::make_shared<link>();
|
||||
// Initialize the last link with the first link
|
||||
last = nullptr;
|
||||
}
|
||||
|
||||
bool isEmpty();
|
||||
|
||||
void push_back(int new_elem);
|
||||
void push_front(int new_elem);
|
||||
void erase(int old_elem);
|
||||
void display();
|
||||
std::shared_ptr<link> search(int find_elem);
|
||||
void reverse();
|
||||
};
|
||||
|
||||
/**
|
||||
* function checks if list is empty
|
||||
* @returns true if list is empty
|
||||
* @returns false if list is not empty
|
||||
*/
|
||||
bool list::isEmpty() {
|
||||
if (last == nullptr) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* function adds new element to the end of the list
|
||||
* @param new_elem to be added to the end of the list
|
||||
*/
|
||||
void list::push_back(int new_elem) {
|
||||
if (isEmpty()) {
|
||||
first->succ() = std::make_shared<link>(new_elem);
|
||||
last = first->succ();
|
||||
} else {
|
||||
last->succ() = std::make_shared<link>(new_elem);
|
||||
last = last->succ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* function adds new element to the beginning of the list
|
||||
* @param new_elem to be added to front of the list
|
||||
*/
|
||||
void list::push_front(int new_elem) {
|
||||
if (isEmpty()) {
|
||||
first->succ() = std::make_shared<link>(new_elem);
|
||||
last = first->succ();
|
||||
} else {
|
||||
std::shared_ptr<link> t = std::make_shared<link>(new_elem);
|
||||
t->succ() = first->succ();
|
||||
first->succ() = t;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* function erases old element from the list
|
||||
* @param old_elem to be erased from the list
|
||||
*/
|
||||
void list::erase(int old_elem) {
|
||||
if (isEmpty()) {
|
||||
std::cout << "List is Empty!";
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<link> t = first;
|
||||
std::shared_ptr<link> to_be_removed = nullptr;
|
||||
while (t != last && t->succ()->val() != old_elem) {
|
||||
t = t->succ();
|
||||
}
|
||||
if (t == last) {
|
||||
std::cout << "Element not found\n";
|
||||
return;
|
||||
}
|
||||
to_be_removed = t->succ();
|
||||
t->succ() = t->succ()->succ();
|
||||
to_be_removed.reset();
|
||||
if (t->succ() == nullptr) {
|
||||
last = t;
|
||||
}
|
||||
if (first == last){
|
||||
last = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* function displays all the elements in the list
|
||||
* @returns 'void'
|
||||
*/
|
||||
void list::display() {
|
||||
if (isEmpty()) {
|
||||
std::cout << "List is Empty!";
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<link> t = first;
|
||||
while (t->succ() != nullptr) {
|
||||
std::cout << t->succ()->val() << "\t";
|
||||
t = t->succ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* function searchs for @param find_elem in the list
|
||||
* @param find_elem to be searched for in the list
|
||||
*/
|
||||
std::shared_ptr<link> list::search(int find_elem) {
|
||||
if (isEmpty()) {
|
||||
std::cout << "List is Empty!";
|
||||
return nullptr;
|
||||
}
|
||||
std::shared_ptr<link> t = first;
|
||||
while (t != last && t->succ()->val() != find_elem) {
|
||||
t = t->succ();
|
||||
}
|
||||
if (t == last) {
|
||||
std::cout << "Element not found\n";
|
||||
return nullptr;
|
||||
}
|
||||
std::cout << "Element was found\n";
|
||||
return t->succ();
|
||||
}
|
||||
} // namespace linked_list
|
||||
} // namespace data_structures
|
||||
|
||||
/**
|
||||
* Main function:
|
||||
* Allows the user add and delete values from the list.
|
||||
* Also allows user to search for and display values in the list.
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
data_structures::linked_list::list l;
|
||||
int choice = 0;
|
||||
int x = 0;
|
||||
std::string s;
|
||||
do {
|
||||
std::cout << "\n1. Insert";
|
||||
std::cout << "\n2. Delete";
|
||||
std::cout << "\n3. Search";
|
||||
std::cout << "\n4. Print";
|
||||
std::cout << "\n0. Exit";
|
||||
std::cout << "\n\nEnter you choice : ";
|
||||
std::cin >> choice;
|
||||
switch (choice) {
|
||||
case 0:
|
||||
std::cout << "\nQuitting the program...\n";
|
||||
break;
|
||||
case 1:
|
||||
std::cout << "\nEnter the element to be inserted : ";
|
||||
std::cin >> s;
|
||||
|
||||
if (data_structures::linked_list::isDigit(s)) {
|
||||
x = std::stoi(s);
|
||||
l.push_back(x);
|
||||
} else {
|
||||
std::cout << "Wrong Input!\n";
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
std::cout << "\nEnter the element to be removed : ";
|
||||
std::cin >> s;
|
||||
if (data_structures::linked_list::isDigit(s)) {
|
||||
x = std::stoi(s);
|
||||
l.erase(x);
|
||||
} else {
|
||||
std::cout << "Wrong Input!\n";
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
std::cout << "\nEnter the element to be searched : ";
|
||||
std::cin >> s;
|
||||
if (data_structures::linked_list::isDigit(s)) {
|
||||
x = std::stoi(s);
|
||||
std::shared_ptr<data_structures::linked_list::link> found =
|
||||
l.search(x);
|
||||
} else {
|
||||
std::cout << "Wrong Input!\n";
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
l.display();
|
||||
std::cout << "\n";
|
||||
break;
|
||||
default:
|
||||
std::cout << "Invalid Input\n" << std::endl;
|
||||
break;
|
||||
}
|
||||
} while (choice != 0);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* \file
|
||||
* \brief Linked list implementation using Arrays
|
||||
*
|
||||
* The difference between the pointer implementation of linked list and array
|
||||
* implementation of linked list:
|
||||
* 1. The NULL is represented by -1;
|
||||
* 2. Limited size. (in the following case it is 100 nodes at max). But we can
|
||||
* reuse the nodes that are to be deleted by again linking it bacj to the list.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
struct Node {
|
||||
int data;
|
||||
int next;
|
||||
};
|
||||
|
||||
Node AvailArray[100]; ///< array that will act as nodes of a linked list.
|
||||
|
||||
int head = -1;
|
||||
int avail = 0;
|
||||
void initialise_list() {
|
||||
for (int i = 0; i <= 98; i++) {
|
||||
AvailArray[i].next = i + 1;
|
||||
}
|
||||
AvailArray[99].next = -1; // indicating the end of the linked list.
|
||||
}
|
||||
|
||||
/** This will return the index of the first free node present in the avail list
|
||||
*/
|
||||
int getnode() {
|
||||
int NodeIndexToBeReturned = avail;
|
||||
avail = AvailArray[avail].next;
|
||||
return NodeIndexToBeReturned;
|
||||
}
|
||||
|
||||
/** This function when called will delete the node with
|
||||
* the index presented as an argument, and will put
|
||||
* back that node into the array.
|
||||
*/
|
||||
void freeNode(int nodeToBeDeleted) {
|
||||
AvailArray[nodeToBeDeleted].next = avail;
|
||||
avail = nodeToBeDeleted;
|
||||
}
|
||||
|
||||
/** The function will insert the given data
|
||||
* into the front of the linked list.
|
||||
*/
|
||||
void insertAtTheBeginning(int data) {
|
||||
int newNode = getnode();
|
||||
AvailArray[newNode].data = data;
|
||||
AvailArray[newNode].next = head;
|
||||
head = newNode;
|
||||
}
|
||||
|
||||
void insertAtTheEnd(int data) {
|
||||
int newNode = getnode();
|
||||
int temp = head;
|
||||
while (AvailArray[temp].next != -1) {
|
||||
temp = AvailArray[temp].next;
|
||||
}
|
||||
// temp is now pointing to the end node.
|
||||
AvailArray[newNode].data = data;
|
||||
AvailArray[newNode].next = -1;
|
||||
AvailArray[temp].next = newNode;
|
||||
}
|
||||
|
||||
void display() {
|
||||
int temp = head;
|
||||
while (temp != -1) {
|
||||
std::cout << AvailArray[temp].data << "->";
|
||||
temp = AvailArray[temp].next;
|
||||
}
|
||||
std::cout << "-1" << std::endl;
|
||||
}
|
||||
|
||||
/** Main function */
|
||||
int main() {
|
||||
initialise_list();
|
||||
int x, y, z;
|
||||
for (;;) {
|
||||
std::cout << "1. Insert At The Beginning" << std::endl;
|
||||
std::cout << "2. Insert At The End" << std::endl;
|
||||
std::cout << "3. Display" << std::endl;
|
||||
std::cout << "4.Exit" << std::endl;
|
||||
std::cout << "Enter Your choice" << std::endl;
|
||||
std::cin >> z;
|
||||
switch (z) {
|
||||
case 1:
|
||||
std::cout << "Enter the number you want to enter" << std::endl;
|
||||
std::cin >> x;
|
||||
insertAtTheBeginning(x);
|
||||
break;
|
||||
case 2:
|
||||
std::cout << "Enter the number you want to enter" << std::endl;
|
||||
std::cin >> y;
|
||||
insertAtTheEnd(y);
|
||||
break;
|
||||
case 3:
|
||||
std::cout
|
||||
<< "The linked list contains the following element in order"
|
||||
<< std::endl;
|
||||
display();
|
||||
break;
|
||||
case 4:
|
||||
return 0;
|
||||
default:
|
||||
std::cout << "The entered choice is not correct" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief [Dynamic Array](https://en.wikipedia.org/wiki/Dynamic_array)
|
||||
*
|
||||
* @details
|
||||
* The list_array is the implementation of list represented using array.
|
||||
* We can perform basic CRUD operations as well as other operations like sorting
|
||||
* etc.
|
||||
*
|
||||
* ### Algorithm
|
||||
* It implements various method like insert, sort, search etc. efficiently.
|
||||
* You can select the operation and methods will do the rest work for you.
|
||||
* You can insert element, sort them in order, search efficiently, delete values
|
||||
* and print the list.
|
||||
*/
|
||||
|
||||
#include <array> /// for std::array
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for io operations
|
||||
|
||||
/**
|
||||
* @namespace data_structures
|
||||
* @brief Algorithms with data structures
|
||||
*/
|
||||
namespace data_structures {
|
||||
/**
|
||||
* @namespace list_array
|
||||
* @brief Functions for [Dynamic
|
||||
* Array](https://en.wikipedia.org/wiki/Dynamic_array) algorithm
|
||||
*/
|
||||
namespace list_array {
|
||||
/**
|
||||
* @brief Structure of List with supporting methods.
|
||||
*/
|
||||
template <uint64_t N>
|
||||
struct list {
|
||||
std::array<uint64_t, N> data{}; // Array that implement list
|
||||
uint64_t top = 0; // Pointer to the last element
|
||||
bool isSorted = false; // indicator whether list is sorted or not
|
||||
/**
|
||||
* @brief Search an element in the list using binarySearch.
|
||||
* @param dataArr list
|
||||
* @param first pointer to the first element in the remaining list
|
||||
* @param last pointer to the last element in the remaining list
|
||||
* @param val element that will be searched
|
||||
* @return index of element in the list if present else -1
|
||||
*/
|
||||
uint64_t BinarySearch(const std::array<uint64_t, N> &dataArr,
|
||||
const uint64_t &first, const uint64_t &last,
|
||||
const uint64_t &val) {
|
||||
// If both pointer cross each other means no element present in the list
|
||||
// which is equal to the val
|
||||
if (last < first) {
|
||||
return -1;
|
||||
}
|
||||
uint64_t mid = (first + last) / 2;
|
||||
// check whether current mid pointer value is equal to element or not
|
||||
if (dataArr[mid] == val)
|
||||
return mid;
|
||||
// if current mid value is greater than element we have to search in
|
||||
// first half
|
||||
else if (val < dataArr[mid])
|
||||
return (BinarySearch(dataArr, first, mid - 1, val));
|
||||
// if current mid value is greater than element we have to search in
|
||||
// second half
|
||||
else if (val > dataArr[mid])
|
||||
return (BinarySearch(dataArr, mid + 1, last, val));
|
||||
|
||||
std::cerr << __func__ << ":" << __LINE__ << ": Undefined condition\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Search an element using linear search
|
||||
* @param dataArr list
|
||||
* @param val element that will be searched
|
||||
* @return index of element in the list if present else -1
|
||||
*/
|
||||
uint64_t LinearSearch(const std::array<uint64_t, N> &dataArr,
|
||||
const uint64_t &val) const {
|
||||
// Going through each element in the list
|
||||
for (uint64_t i = 0; i < top; i++) {
|
||||
if (dataArr[i] == val) {
|
||||
return i; // element found at ith index
|
||||
}
|
||||
}
|
||||
// element is not present in the list
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* @brief Parent function of binarySearch and linearSearch methods
|
||||
* @param val element that will be searched
|
||||
* @return index of element in the list if present else -1
|
||||
*/
|
||||
uint64_t search(const uint64_t &val) {
|
||||
uint64_t pos; // pos variable to store index value of element.
|
||||
// if list is sorted, binary search works efficiently else linear search
|
||||
// is the only option
|
||||
if (isSorted) {
|
||||
pos = BinarySearch(data, 0, top - 1, val);
|
||||
} else {
|
||||
pos = LinearSearch(data, val);
|
||||
}
|
||||
// if index is equal to -1 means element does not present
|
||||
// else print the index of that element
|
||||
if (pos != -1) {
|
||||
std::cout << "\nElement found at position : " << pos;
|
||||
} else {
|
||||
std::cout << "\nElement not found";
|
||||
}
|
||||
// return the index of element or -1.
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sort the list
|
||||
* @returns void
|
||||
*/
|
||||
void sort() {
|
||||
// Going through each element in the list
|
||||
for (uint64_t i = 0; i < top; i++) {
|
||||
uint64_t min_idx = i; // Initialize the min variable
|
||||
for (uint64_t j = i + 1; j < top; j++) {
|
||||
// check whether any element less than current min value
|
||||
if (data[j] < data[min_idx]) {
|
||||
min_idx = j; // update index accordingly
|
||||
}
|
||||
}
|
||||
// swap min value and element at the ith index
|
||||
std::swap(data[min_idx], data[i]);
|
||||
}
|
||||
// mark isSorted variable as true
|
||||
isSorted = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Insert the new element in the list
|
||||
* @param val element that will be inserted
|
||||
* @returns void
|
||||
*/
|
||||
void insert(const uint64_t &val) {
|
||||
// overflow check
|
||||
if (top == N) {
|
||||
std::cout << "\nOverflow";
|
||||
return;
|
||||
}
|
||||
// if list is not sorted, insert at the last
|
||||
// otherwise place it to correct position
|
||||
if (!isSorted) {
|
||||
data[top] = val;
|
||||
top++;
|
||||
} else {
|
||||
uint64_t pos = 0; // Initialize the index variable
|
||||
// Going through each element and find correct position for element
|
||||
for (uint64_t i = 0; i < top - 1; i++) {
|
||||
// check for the correct position
|
||||
if (data[i] <= val && val <= data[i + 1]) {
|
||||
pos = i + 1; // assign correct pos to the index var
|
||||
break; // to get out from the loop
|
||||
}
|
||||
}
|
||||
// if all elements are smaller than the element
|
||||
if (pos == 0) {
|
||||
pos = top - 1;
|
||||
}
|
||||
// shift all element to make a room for new element
|
||||
for (uint64_t i = top; i > pos; i--) {
|
||||
data[i] = data[i - 1];
|
||||
}
|
||||
top++; // Increment the value of top.
|
||||
data[pos] =
|
||||
val; // Assign the value to the correct index in the array
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief To remove the element from the list
|
||||
* @param val element that will be removed
|
||||
* @returns void
|
||||
*/
|
||||
void remove(const uint64_t &val) {
|
||||
uint64_t pos = search(val); // search the index of the value
|
||||
// if search returns -1, element does not present in the list
|
||||
if (pos == -1) {
|
||||
std::cout << "\n Element does not present in the list ";
|
||||
return;
|
||||
}
|
||||
std::cout << "\n"
|
||||
<< data[pos] << " deleted"; // print the appropriate message
|
||||
// shift all the element 1 left to fill vacant space
|
||||
for (uint64_t i = pos; i < top; i++) {
|
||||
data[i] = data[i + 1];
|
||||
}
|
||||
top--; // decrement the top variable to maintain last index
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility function to print array
|
||||
* @returns void
|
||||
*/
|
||||
void show() {
|
||||
// Going through each element in the list
|
||||
std::cout << '\n';
|
||||
for (uint64_t i = 0; i < top; i++) {
|
||||
std::cout << data[i] << " "; // print the element
|
||||
}
|
||||
}
|
||||
}; // structure list
|
||||
} // namespace list_array
|
||||
} // namespace data_structures
|
||||
|
||||
/**
|
||||
* @brief Test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
data_structures::list_array::list<50> L;
|
||||
|
||||
// Insert testing
|
||||
L.insert(11);
|
||||
L.insert(12);
|
||||
assert(L.top == 2);
|
||||
L.insert(15);
|
||||
L.insert(10);
|
||||
L.insert(12);
|
||||
L.insert(20);
|
||||
L.insert(18);
|
||||
assert(L.top == 7);
|
||||
L.show(); // To print the array
|
||||
|
||||
// Remove testing
|
||||
L.remove(12); // Remove Duplicate value in the list
|
||||
L.remove(15); // Remove the existing value in the list
|
||||
assert(L.top == 5);
|
||||
L.remove(50); // Try to remove the non-existing value in the list
|
||||
assert(L.top == 5);
|
||||
|
||||
// LinearSearch testing
|
||||
assert(L.search(11) == 0); // search for the existing element
|
||||
assert(L.search(12) == 2);
|
||||
assert(L.search(50) == -1); // search for the non-existing element
|
||||
|
||||
// Sort testing
|
||||
L.sort();
|
||||
assert(L.isSorted == true);
|
||||
L.show();
|
||||
|
||||
// BinarySearch testing
|
||||
assert(L.search(11) == 1); // search for the existing element
|
||||
assert(L.search(12) == 2);
|
||||
assert(L.search(50) == -1); // search for the non-existing element
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // Execute the tests
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
|
||||
/**************************
|
||||
@author shrutisheoran
|
||||
**************************/
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct Btree {
|
||||
int data;
|
||||
struct Btree *left; // Pointer to left subtree
|
||||
struct Btree *right; // Pointer to right subtree
|
||||
};
|
||||
|
||||
void insert(Btree **root, int d) {
|
||||
Btree *nn = new Btree(); // Creating new node
|
||||
nn->data = d;
|
||||
nn->left = NULL;
|
||||
nn->right = NULL;
|
||||
if (*root == NULL) {
|
||||
*root = nn;
|
||||
return;
|
||||
} else {
|
||||
queue<Btree *> q;
|
||||
// Adding root node to queue
|
||||
q.push(*root);
|
||||
while (!q.empty()) {
|
||||
Btree *node = q.front();
|
||||
// Removing parent node from queue
|
||||
q.pop();
|
||||
if (node->left)
|
||||
// Adding left child of removed node to queue
|
||||
q.push(node->left);
|
||||
else {
|
||||
// Adding new node if no left child is present
|
||||
node->left = nn;
|
||||
return;
|
||||
}
|
||||
if (node->right)
|
||||
// Adding right child of removed node to queue
|
||||
q.push(node->right);
|
||||
else {
|
||||
// Adding new node if no right child is present
|
||||
node->right = nn;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void morrisInorder(Btree *root) {
|
||||
Btree *curr = root;
|
||||
Btree *temp;
|
||||
while (curr) {
|
||||
if (curr->left == NULL) {
|
||||
cout << curr->data << " ";
|
||||
// If left of current node is NULL then curr is shifted to right
|
||||
curr = curr->right;
|
||||
} else {
|
||||
// Left of current node is stored in temp
|
||||
temp = curr->left;
|
||||
// Moving to extreme right of temp
|
||||
while (temp->right && temp->right != curr) temp = temp->right;
|
||||
// If extreme right is null it is made to point to currrent node
|
||||
// (will be used for backtracking)
|
||||
if (temp->right == NULL) {
|
||||
temp->right = curr;
|
||||
// current node is made to point its left subtree
|
||||
curr = curr->left;
|
||||
}
|
||||
// If extreme right already points to currrent node it it set to
|
||||
// null
|
||||
else if (temp->right == curr) {
|
||||
cout << curr->data << " ";
|
||||
temp->right = NULL;
|
||||
// current node is made to point its right subtree
|
||||
curr = curr->right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void deleteAll(const Btree *const root) {
|
||||
if (root) {
|
||||
deleteAll(root->left);
|
||||
deleteAll(root->right);
|
||||
delete root;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
// Testing morrisInorder funtion
|
||||
Btree *root = NULL;
|
||||
int i;
|
||||
for (i = 1; i <= 7; i++) insert(&root, i);
|
||||
cout << "Morris Inorder: ";
|
||||
morrisInorder(root);
|
||||
deleteAll(root);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Provides Node class and related utilities
|
||||
**/
|
||||
#ifndef DATA_STRUCTURES_NODE_HPP_
|
||||
#define DATA_STRUCTURES_NODE_HPP_
|
||||
|
||||
#include <iostream> /// for std::cout
|
||||
#include <memory> /// for std::shared_ptr
|
||||
#include <vector> /// for std::vector
|
||||
|
||||
/** Definition of the node as a linked-list
|
||||
* \tparam ValueType type of data nodes of the linked list should contain
|
||||
*/
|
||||
template <class ValueType>
|
||||
struct Node {
|
||||
using value_type = ValueType;
|
||||
ValueType data = {};
|
||||
std::shared_ptr<Node<ValueType>> next = {};
|
||||
};
|
||||
|
||||
template <typename Node, typename Action>
|
||||
void traverse(const Node* const inNode, const Action& action) {
|
||||
if (inNode) {
|
||||
action(*inNode);
|
||||
traverse(inNode->next.get(), action);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
void display_all(const Node* const inNode) {
|
||||
traverse(inNode,
|
||||
[](const Node& curNode) { std::cout << curNode.data << " "; });
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
std::vector<typename Node::value_type> push_all_to_vector(
|
||||
const Node* const inNode, const std::size_t expected_size = 0) {
|
||||
std::vector<typename Node::value_type> res;
|
||||
res.reserve(expected_size);
|
||||
traverse(inNode,
|
||||
[&res](const Node& curNode) { res.push_back(curNode.data); });
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif // DATA_STRUCTURES_NODE_HPP_
|
||||
@@ -0,0 +1,104 @@
|
||||
/* This class specifies the basic operation on a queue as a linked list */
|
||||
#ifndef DATA_STRUCTURES_QUEUE_HPP_
|
||||
#define DATA_STRUCTURES_QUEUE_HPP_
|
||||
|
||||
#include "node.hpp"
|
||||
|
||||
/** Definition of the queue class */
|
||||
template <class ValueType>
|
||||
class queue {
|
||||
using node_type = Node<ValueType>;
|
||||
|
||||
public:
|
||||
using value_type = ValueType;
|
||||
/**
|
||||
* @brief prints the queue into the std::cout
|
||||
*/
|
||||
void display() const {
|
||||
std::cout << "Front --> ";
|
||||
display_all(this->queueFront.get());
|
||||
std::cout << '\n';
|
||||
std::cout << "Size of queue: " << size << '\n';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief converts the queue into the std::vector
|
||||
* @return std::vector containning all of the elements of the queue in the
|
||||
* same order
|
||||
*/
|
||||
std::vector<value_type> toVector() const {
|
||||
return push_all_to_vector(this->queueFront.get(), this->size);
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief throws an exception if queue is empty
|
||||
* @exception std::invalid_argument if queue is empty
|
||||
*/
|
||||
void ensureNotEmpty() const {
|
||||
if (isEmptyQueue()) {
|
||||
throw std::invalid_argument("Queue is empty.");
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief checks if the queue has no elements
|
||||
* @return true if the queue is empty, false otherwise
|
||||
*/
|
||||
bool isEmptyQueue() const { return (queueFront == nullptr); }
|
||||
|
||||
/**
|
||||
* @brief inserts a new item into the queue
|
||||
*/
|
||||
void enQueue(const value_type& item) {
|
||||
auto newNode = std::make_shared<node_type>();
|
||||
newNode->data = item;
|
||||
newNode->next = nullptr;
|
||||
if (isEmptyQueue()) {
|
||||
queueFront = newNode;
|
||||
queueRear = newNode;
|
||||
} else {
|
||||
queueRear->next = newNode;
|
||||
queueRear = queueRear->next;
|
||||
}
|
||||
++size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the first element of the queue
|
||||
* @exception std::invalid_argument if queue is empty
|
||||
*/
|
||||
value_type front() const {
|
||||
ensureNotEmpty();
|
||||
return queueFront->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief removes the first element from the queue
|
||||
* @exception std::invalid_argument if queue is empty
|
||||
*/
|
||||
void deQueue() {
|
||||
ensureNotEmpty();
|
||||
queueFront = queueFront->next;
|
||||
--size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief removes all elements from the queue
|
||||
*/
|
||||
void clear() {
|
||||
queueFront = nullptr;
|
||||
queueRear = nullptr;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<node_type> queueFront =
|
||||
{}; /**< Pointer to the front of the queue */
|
||||
std::shared_ptr<node_type> queueRear =
|
||||
{}; /**< Pointer to the rear of the queue */
|
||||
std::size_t size = 0;
|
||||
};
|
||||
|
||||
#endif // DATA_STRUCTURES_QUEUE_HPP_
|
||||
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of Linear [Queue using array]
|
||||
* (https://www.geeksforgeeks.org/array-implementation-of-queue-simple/).
|
||||
* @details
|
||||
* The Linear Queue is a data structure used for holding a sequence of
|
||||
* values, which can be added to the end line (enqueue), removed from
|
||||
* head of line (dequeue) and displayed.
|
||||
* ### Algorithm
|
||||
* Values can be added by increasing the `rear` variable by 1 (which points to
|
||||
* the end of the array), then assigning new value to `rear`'s element of the
|
||||
* array.
|
||||
*
|
||||
* Values can be removed by increasing the `front` variable by 1 (which points
|
||||
* to the first of the array), so it cannot reached any more.
|
||||
*
|
||||
* @author [Pooja](https://github.com/pooja-git11)
|
||||
* @author [Farbod Ahmadian](https://github.com/farbodahm)
|
||||
*/
|
||||
#include <array> /// for std::array
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for io operations
|
||||
|
||||
constexpr uint16_t max_size{10}; ///< Maximum size of the queue
|
||||
|
||||
/**
|
||||
* @namespace data_structures
|
||||
* @brief Algorithms with data structures
|
||||
*/
|
||||
namespace data_structures {
|
||||
|
||||
/**
|
||||
* @namespace queue_using_array
|
||||
* @brief Functions for [Queue using Array]
|
||||
* (https://www.geeksforgeeks.org/array-implementation-of-queue-simple/)
|
||||
* implementation.
|
||||
*/
|
||||
namespace queue_using_array {
|
||||
|
||||
/**
|
||||
* @brief Queue_Array class containing the main data and also index of head and
|
||||
* tail of the array.
|
||||
*/
|
||||
class Queue_Array {
|
||||
public:
|
||||
void enqueue(const int16_t&); ///< Add element to the first of the queue
|
||||
int dequeue(); ///< Delete element from back of the queue
|
||||
void display() const; ///< Show all saved data
|
||||
private:
|
||||
int8_t front{-1}; ///< Index of head of the array
|
||||
int8_t rear{-1}; ///< Index of tail of the array
|
||||
std::array<int16_t, max_size> arr{}; ///< All stored data
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Adds new element to the end of the queue
|
||||
* @param ele to be added to the end of the queue
|
||||
*/
|
||||
void Queue_Array::enqueue(const int16_t& ele) {
|
||||
if (rear == arr.size() - 1) {
|
||||
std::cout << "\nStack is full";
|
||||
} else if (front == -1 && rear == -1) {
|
||||
front = 0;
|
||||
rear = 0;
|
||||
arr[rear] = ele;
|
||||
} else if (rear < arr.size()) {
|
||||
++rear;
|
||||
arr[rear] = ele;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove element that is located at the first of the queue
|
||||
* @returns data that is deleted if queue is not empty
|
||||
*/
|
||||
int Queue_Array::dequeue() {
|
||||
int8_t d{0};
|
||||
if (front == -1) {
|
||||
std::cout << "\nstack is empty ";
|
||||
return 0;
|
||||
} else if (front == rear) {
|
||||
d = arr.at(front);
|
||||
front = rear = -1;
|
||||
} else {
|
||||
d = arr.at(front++);
|
||||
}
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility function to show all elements in the queue
|
||||
*/
|
||||
void Queue_Array::display() const {
|
||||
if (front == -1) {
|
||||
std::cout << "\nStack is empty";
|
||||
} else {
|
||||
for (int16_t i{front}; i <= rear; ++i) std::cout << arr.at(i) << " ";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace queue_using_array
|
||||
} // namespace data_structures
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @details
|
||||
* Allows the user to add and delete values from the queue.
|
||||
* Also allows user to display values in the queue.
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
int op{0}, data{0};
|
||||
data_structures::queue_using_array::Queue_Array ob;
|
||||
|
||||
std::cout << "\n1. enqueue(Insertion) ";
|
||||
std::cout << "\n2. dequeue(Deletion)";
|
||||
std::cout << "\n3. Display";
|
||||
std::cout << "\n4. Exit";
|
||||
while (true) {
|
||||
std::cout << "\nEnter your choice ";
|
||||
std::cin >> op;
|
||||
if (op == 1) {
|
||||
std::cout << "Enter data ";
|
||||
std::cin >> data;
|
||||
ob.enqueue(data);
|
||||
} else if (op == 2) {
|
||||
data = ob.dequeue();
|
||||
std::cout << "\ndequeue element is:\t" << data;
|
||||
} else if (op == 3) {
|
||||
ob.display();
|
||||
} else if (op == 4) {
|
||||
exit(0);
|
||||
} else {
|
||||
std::cout << "\nWrong choice ";
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#include <iostream>
|
||||
|
||||
int queue[10];
|
||||
int front = 0;
|
||||
int rear = 0;
|
||||
|
||||
void Enque(int x) {
|
||||
if (rear == 10) {
|
||||
std::cout << "\nOverflow";
|
||||
} else {
|
||||
queue[rear++] = x;
|
||||
}
|
||||
}
|
||||
|
||||
void Deque() {
|
||||
if (front == rear) {
|
||||
std::cout << "\nUnderflow";
|
||||
}
|
||||
|
||||
else {
|
||||
std::cout << "\n" << queue[front++] << " deleted";
|
||||
for (int i = front; i < rear; i++) {
|
||||
queue[i - front] = queue[i];
|
||||
}
|
||||
rear = rear - front;
|
||||
front = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void show() {
|
||||
for (int i = front; i < rear; i++) {
|
||||
std::cout << queue[i] << "\t";
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
int ch, x;
|
||||
do {
|
||||
std::cout << "\n1. Enque";
|
||||
std::cout << "\n2. Deque";
|
||||
std::cout << "\n3. Print";
|
||||
std::cout << "\nEnter Your Choice : ";
|
||||
std::cin >> ch;
|
||||
if (ch == 1) {
|
||||
std::cout << "\nInsert : ";
|
||||
std::cin >> x;
|
||||
Enque(x);
|
||||
} else if (ch == 2) {
|
||||
Deque();
|
||||
} else if (ch == 3) {
|
||||
show();
|
||||
}
|
||||
} while (ch != 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
struct node {
|
||||
int val;
|
||||
node *next;
|
||||
};
|
||||
|
||||
node *front, *rear;
|
||||
|
||||
void Enque(int x) {
|
||||
if (rear == NULL) {
|
||||
node *n = new node;
|
||||
n->val = x;
|
||||
n->next = NULL;
|
||||
rear = n;
|
||||
front = n;
|
||||
}
|
||||
|
||||
else {
|
||||
node *n = new node;
|
||||
n->val = x;
|
||||
n->next = NULL;
|
||||
rear->next = n;
|
||||
rear = n;
|
||||
}
|
||||
}
|
||||
|
||||
void Deque() {
|
||||
if (rear == NULL && front == NULL) {
|
||||
cout << "\nUnderflow";
|
||||
} else {
|
||||
node *t = front;
|
||||
cout << "\n" << t->val << " deleted";
|
||||
front = front->next;
|
||||
delete t;
|
||||
if (front == NULL)
|
||||
rear = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void show() {
|
||||
node *t = front;
|
||||
while (t != NULL) {
|
||||
cout << t->val << "\t";
|
||||
t = t->next;
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
int ch, x;
|
||||
do {
|
||||
cout << "\n1. Enque";
|
||||
cout << "\n2. Deque";
|
||||
cout << "\n3. Print";
|
||||
cout << "\nEnter Your Choice : ";
|
||||
cin >> ch;
|
||||
if (ch == 1) {
|
||||
cout << "\nInsert : ";
|
||||
cin >> x;
|
||||
Enque(x);
|
||||
} else if (ch == 2) {
|
||||
Deque();
|
||||
} else if (ch == 3) {
|
||||
show();
|
||||
}
|
||||
} while (ch != 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
Write a program to implement Queue using linkedlist.
|
||||
*/
|
||||
#include <iostream>
|
||||
|
||||
struct linkedlist {
|
||||
int data;
|
||||
linkedlist *next;
|
||||
};
|
||||
class stack_linkedList {
|
||||
public:
|
||||
linkedlist *front;
|
||||
linkedlist *rear;
|
||||
|
||||
stack_linkedList() { front = rear = NULL; }
|
||||
void enqueue(int);
|
||||
int dequeue();
|
||||
void display();
|
||||
};
|
||||
void stack_linkedList::enqueue(int ele) {
|
||||
linkedlist *temp = new linkedlist();
|
||||
temp->data = ele;
|
||||
temp->next = NULL;
|
||||
|
||||
if (front == NULL)
|
||||
front = rear = temp;
|
||||
else {
|
||||
rear->next = temp;
|
||||
rear = temp;
|
||||
}
|
||||
}
|
||||
int stack_linkedList::dequeue() {
|
||||
linkedlist *temp;
|
||||
int ele;
|
||||
if (front == NULL)
|
||||
std::cout << "\nStack is empty";
|
||||
else {
|
||||
temp = front;
|
||||
ele = temp->data;
|
||||
if (front == rear) // if length of queue is 1;
|
||||
rear = rear->next;
|
||||
front = front->next;
|
||||
delete (temp);
|
||||
}
|
||||
return ele;
|
||||
}
|
||||
void stack_linkedList::display() {
|
||||
if (front == NULL)
|
||||
std::cout << "\nStack is empty";
|
||||
|
||||
else {
|
||||
linkedlist *temp;
|
||||
temp = front;
|
||||
while (temp != NULL) {
|
||||
std::cout << temp->data << " ";
|
||||
temp = temp->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
int op, data;
|
||||
stack_linkedList ob;
|
||||
std::cout << "\n1. enqueue(Insertion) ";
|
||||
std::cout << "\n2. dequeue(Deletion)";
|
||||
std::cout << "\n3. Display";
|
||||
std::cout << "\n4. Exit";
|
||||
|
||||
while (1) {
|
||||
std::cout << "\nEnter your choice ";
|
||||
std::cin >> op;
|
||||
if (op == 1) {
|
||||
std::cout << "Enter data ";
|
||||
std::cin >> data;
|
||||
ob.enqueue(data);
|
||||
} else if (op == 2)
|
||||
data = ob.dequeue();
|
||||
else if (op == 3)
|
||||
ob.display();
|
||||
else if (op == 4)
|
||||
exit(0);
|
||||
else
|
||||
std::cout << "\nWrong choice ";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* @author [shoniavika](https://github.com/shoniavika)
|
||||
* @file
|
||||
*
|
||||
* Implementation of a Queue using two Stacks.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <stack>
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* @brief Queue data structure. Stores elements in FIFO
|
||||
* (first-in-first-out) manner.
|
||||
* @tparam T datatype to store in the queue
|
||||
*/
|
||||
template <typename T>
|
||||
class MyQueue {
|
||||
private:
|
||||
std::stack<T> s1, s2;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructor for queue.
|
||||
*/
|
||||
MyQueue() = default;
|
||||
|
||||
/**
|
||||
* Pushes x to the back of queue.
|
||||
*/
|
||||
void push(T x);
|
||||
|
||||
/**
|
||||
* Removes an element from the front of the queue.
|
||||
*/
|
||||
const T& pop();
|
||||
|
||||
/**
|
||||
* Returns first element, without removing it.
|
||||
*/
|
||||
const T& peek() const;
|
||||
|
||||
/**
|
||||
* Returns whether the queue is empty.
|
||||
*/
|
||||
bool empty() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Appends element to the end of the queue
|
||||
*/
|
||||
template <typename T>
|
||||
void MyQueue<T>::push(T x) {
|
||||
while (!s2.empty()) {
|
||||
s1.push(s2.top());
|
||||
s2.pop();
|
||||
}
|
||||
s2.push(x);
|
||||
while (!s1.empty()) {
|
||||
s2.push(s1.top());
|
||||
s1.pop();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes element from the front of the queue
|
||||
*/
|
||||
template <typename T>
|
||||
const T& MyQueue<T>::pop() {
|
||||
const T& temp = MyQueue::peek();
|
||||
s2.pop();
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns element in the front.
|
||||
* Does not remove it.
|
||||
*/
|
||||
template <typename T>
|
||||
const T& MyQueue<T>::peek() const {
|
||||
if (!empty()) {
|
||||
return s2.top();
|
||||
}
|
||||
std::cerr << "Queue is empty" << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether a queue is empty
|
||||
*/
|
||||
template <typename T>
|
||||
bool MyQueue<T>::empty() const {
|
||||
return s2.empty() && s1.empty();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* Testing function
|
||||
*/
|
||||
void queue_test() {
|
||||
MyQueue<int> que;
|
||||
std::cout << "Test #1\n";
|
||||
que.push(2);
|
||||
que.push(5);
|
||||
que.push(0);
|
||||
assert(que.peek() == 2);
|
||||
assert(que.pop() == 2);
|
||||
assert(que.peek() == 5);
|
||||
assert(que.pop() == 5);
|
||||
assert(que.peek() == 0);
|
||||
assert(que.pop() == 0);
|
||||
assert(que.empty() == true);
|
||||
std::cout << "PASSED\n";
|
||||
|
||||
std::cout << "Test #2\n";
|
||||
que.push(-1);
|
||||
assert(que.empty() == false);
|
||||
assert(que.peek() == -1);
|
||||
assert(que.pop() == -1);
|
||||
std::cout << "PASSED\n";
|
||||
|
||||
MyQueue<double> que2;
|
||||
std::cout << "Test #3\n";
|
||||
que2.push(2.31223);
|
||||
que2.push(3.1415926);
|
||||
que2.push(2.92);
|
||||
|
||||
assert(que2.peek() == 2.31223);
|
||||
assert(que2.pop() == 2.31223);
|
||||
assert(que2.peek() == 3.1415926);
|
||||
assert(que2.pop() == 3.1415926);
|
||||
assert(que2.peek() == 2.92);
|
||||
assert(que2.pop() == 2.92);
|
||||
std::cout << "PASSED\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function, calls testing function
|
||||
*/
|
||||
int main() {
|
||||
queue_test();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,505 @@
|
||||
#include<iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
struct node
|
||||
{
|
||||
int key;
|
||||
node *parent;
|
||||
char color;
|
||||
node *left;
|
||||
node *right;
|
||||
};
|
||||
class RBtree
|
||||
{
|
||||
node *root;
|
||||
node *q;
|
||||
public:
|
||||
RBtree()
|
||||
{
|
||||
q = NULL;
|
||||
root = NULL;
|
||||
}
|
||||
void insert();
|
||||
void insertfix(node *);
|
||||
void leftrotate(node *);
|
||||
void rightrotate(node *);
|
||||
void del();
|
||||
node* successor(node *);
|
||||
void delfix(node *);
|
||||
void disp();
|
||||
void display(node *);
|
||||
void search();
|
||||
};
|
||||
void RBtree::insert()
|
||||
{
|
||||
int z;
|
||||
cout << "\nEnter key of the node to be inserted: ";
|
||||
cin >> z;
|
||||
node *p, *q;
|
||||
node *t = new node;
|
||||
t->key = z;
|
||||
t->left = NULL;
|
||||
t->right = NULL;
|
||||
t->color = 'r';
|
||||
p = root;
|
||||
q = NULL;
|
||||
if (root == NULL)
|
||||
{
|
||||
root = t;
|
||||
t->parent = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (p != NULL)
|
||||
{
|
||||
q = p;
|
||||
if (p->key < t->key)
|
||||
p = p->right;
|
||||
else
|
||||
p = p->left;
|
||||
}
|
||||
t->parent = q;
|
||||
if (q->key < t->key)
|
||||
q->right = t;
|
||||
else
|
||||
q->left = t;
|
||||
}
|
||||
insertfix(t);
|
||||
}
|
||||
void RBtree::insertfix(node *t)
|
||||
{
|
||||
node *u;
|
||||
if (root == t)
|
||||
{
|
||||
t->color = 'b';
|
||||
return;
|
||||
}
|
||||
while (t->parent != NULL && t->parent->color == 'r')
|
||||
{
|
||||
node *g = t->parent->parent;
|
||||
if (g->left == t->parent)
|
||||
{
|
||||
if (g->right != NULL)
|
||||
{
|
||||
u = g->right;
|
||||
if (u->color == 'r')
|
||||
{
|
||||
t->parent->color = 'b';
|
||||
u->color = 'b';
|
||||
g->color = 'r';
|
||||
t = g;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (t->parent->right == t)
|
||||
{
|
||||
t = t->parent;
|
||||
leftrotate(t);
|
||||
}
|
||||
t->parent->color = 'b';
|
||||
g->color = 'r';
|
||||
rightrotate(g);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g->left != NULL)
|
||||
{
|
||||
u = g->left;
|
||||
if (u->color == 'r')
|
||||
{
|
||||
t->parent->color = 'b';
|
||||
u->color = 'b';
|
||||
g->color = 'r';
|
||||
t = g;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (t->parent->left == t)
|
||||
{
|
||||
t = t->parent;
|
||||
rightrotate(t);
|
||||
}
|
||||
t->parent->color = 'b';
|
||||
g->color = 'r';
|
||||
leftrotate(g);
|
||||
}
|
||||
}
|
||||
root->color = 'b';
|
||||
}
|
||||
}
|
||||
|
||||
void RBtree::del()
|
||||
{
|
||||
if (root == NULL)
|
||||
{
|
||||
cout << "\nEmpty Tree.";
|
||||
return;
|
||||
}
|
||||
int x;
|
||||
cout << "\nEnter the key of the node to be deleted: ";
|
||||
cin >> x;
|
||||
node *p;
|
||||
p = root;
|
||||
node *y = NULL;
|
||||
node *q = NULL;
|
||||
int found = 0;
|
||||
while (p != NULL && found == 0)
|
||||
{
|
||||
if (p->key == x)
|
||||
found = 1;
|
||||
if (found == 0)
|
||||
{
|
||||
if (p->key < x)
|
||||
p = p->right;
|
||||
else
|
||||
p = p->left;
|
||||
}
|
||||
}
|
||||
if (found == 0)
|
||||
{
|
||||
cout << "\nElement Not Found.";
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "\nDeleted Element: " << p->key;
|
||||
cout << "\nColour: ";
|
||||
if (p->color == 'b')
|
||||
cout << "Black\n";
|
||||
else
|
||||
cout << "Red\n";
|
||||
|
||||
if (p->parent != NULL)
|
||||
cout << "\nParent: " << p->parent->key;
|
||||
else
|
||||
cout << "\nThere is no parent of the node. ";
|
||||
if (p->right != NULL)
|
||||
cout << "\nRight Child: " << p->right->key;
|
||||
else
|
||||
cout << "\nThere is no right child of the node. ";
|
||||
if (p->left != NULL)
|
||||
cout << "\nLeft Child: " << p->left->key;
|
||||
else
|
||||
cout << "\nThere is no left child of the node. ";
|
||||
cout << "\nNode Deleted.";
|
||||
if (p->left == NULL || p->right == NULL)
|
||||
y = p;
|
||||
else
|
||||
y = successor(p);
|
||||
if (y->left != NULL)
|
||||
q = y->left;
|
||||
else
|
||||
{
|
||||
if (y->right != NULL)
|
||||
q = y->right;
|
||||
else
|
||||
q = NULL;
|
||||
}
|
||||
if (q != NULL)
|
||||
q->parent = y->parent;
|
||||
if (y->parent == NULL)
|
||||
root = q;
|
||||
else
|
||||
{
|
||||
if (y == y->parent->left)
|
||||
y->parent->left = q;
|
||||
else
|
||||
y->parent->right = q;
|
||||
}
|
||||
if (y != p)
|
||||
{
|
||||
p->color = y->color;
|
||||
p->key = y->key;
|
||||
}
|
||||
if (y->color == 'b')
|
||||
delfix(q);
|
||||
}
|
||||
}
|
||||
|
||||
void RBtree::delfix(node *p)
|
||||
{
|
||||
node *s;
|
||||
while (p != root && p->color == 'b')
|
||||
{
|
||||
if (p->parent->left == p)
|
||||
{
|
||||
s = p->parent->right;
|
||||
if (s->color == 'r')
|
||||
{
|
||||
s->color = 'b';
|
||||
p->parent->color = 'r';
|
||||
leftrotate(p->parent);
|
||||
s = p->parent->right;
|
||||
}
|
||||
if (s->right->color == 'b'&&s->left->color == 'b')
|
||||
{
|
||||
s->color = 'r';
|
||||
p = p->parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s->right->color == 'b')
|
||||
{
|
||||
s->left->color = 'b';
|
||||
s->color = 'r';
|
||||
rightrotate(s);
|
||||
s = p->parent->right;
|
||||
}
|
||||
s->color = p->parent->color;
|
||||
p->parent->color = 'b';
|
||||
s->right->color = 'b';
|
||||
leftrotate(p->parent);
|
||||
p = root;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
s = p->parent->left;
|
||||
if (s->color == 'r')
|
||||
{
|
||||
s->color = 'b';
|
||||
p->parent->color = 'r';
|
||||
rightrotate(p->parent);
|
||||
s = p->parent->left;
|
||||
}
|
||||
if (s->left->color == 'b'&&s->right->color == 'b')
|
||||
{
|
||||
s->color = 'r';
|
||||
p = p->parent;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s->left->color == 'b')
|
||||
{
|
||||
s->right->color = 'b';
|
||||
s->color = 'r';
|
||||
leftrotate(s);
|
||||
s = p->parent->left;
|
||||
}
|
||||
s->color = p->parent->color;
|
||||
p->parent->color = 'b';
|
||||
s->left->color = 'b';
|
||||
rightrotate(p->parent);
|
||||
p = root;
|
||||
}
|
||||
}
|
||||
p->color = 'b';
|
||||
root->color = 'b';
|
||||
}
|
||||
}
|
||||
|
||||
void RBtree::leftrotate(node *p)
|
||||
{
|
||||
if (p->right == NULL)
|
||||
return;
|
||||
else
|
||||
{
|
||||
node *y = p->right;
|
||||
if (y->left != NULL)
|
||||
{
|
||||
p->right = y->left;
|
||||
y->left->parent = p;
|
||||
}
|
||||
else
|
||||
p->right = NULL;
|
||||
if (p->parent != NULL)
|
||||
y->parent = p->parent;
|
||||
if (p->parent == NULL)
|
||||
root = y;
|
||||
else
|
||||
{
|
||||
if (p == p->parent->left)
|
||||
p->parent->left = y;
|
||||
else
|
||||
p->parent->right = y;
|
||||
}
|
||||
y->left = p;
|
||||
p->parent = y;
|
||||
}
|
||||
}
|
||||
void RBtree::rightrotate(node *p)
|
||||
{
|
||||
if (p->left == NULL)
|
||||
return;
|
||||
else
|
||||
{
|
||||
node *y = p->left;
|
||||
if (y->right != NULL)
|
||||
{
|
||||
p->left = y->right;
|
||||
y->right->parent = p;
|
||||
}
|
||||
else
|
||||
p->left = NULL;
|
||||
if (p->parent != NULL)
|
||||
y->parent = p->parent;
|
||||
if (p->parent == NULL)
|
||||
root = y;
|
||||
else
|
||||
{
|
||||
if (p == p->parent->left)
|
||||
p->parent->left = y;
|
||||
else
|
||||
p->parent->right = y;
|
||||
}
|
||||
y->right = p;
|
||||
p->parent = y;
|
||||
}
|
||||
}
|
||||
|
||||
node* RBtree::successor(node *p)
|
||||
{
|
||||
node *y = NULL;
|
||||
if (p->left != NULL)
|
||||
{
|
||||
y = p->left;
|
||||
while (y->right != NULL)
|
||||
y = y->right;
|
||||
}
|
||||
else
|
||||
{
|
||||
y = p->right;
|
||||
while (y->left != NULL)
|
||||
y = y->left;
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
void RBtree::disp()
|
||||
{
|
||||
display(root);
|
||||
}
|
||||
void RBtree::display(node *p)
|
||||
{
|
||||
if (root == NULL)
|
||||
{
|
||||
cout << "\nEmpty Tree.";
|
||||
return;
|
||||
}
|
||||
if (p != NULL)
|
||||
{
|
||||
cout << "\n\t NODE: ";
|
||||
cout << "\n Key: " << p->key;
|
||||
cout << "\n Colour: ";
|
||||
if (p->color == 'b')
|
||||
cout << "Black";
|
||||
else
|
||||
cout << "Red";
|
||||
if (p->parent != NULL)
|
||||
cout << "\n Parent: " << p->parent->key;
|
||||
else
|
||||
cout << "\n There is no parent of the node. ";
|
||||
if (p->right != NULL)
|
||||
cout << "\n Right Child: " << p->right->key;
|
||||
else
|
||||
cout << "\n There is no right child of the node. ";
|
||||
if (p->left != NULL)
|
||||
cout << "\n Left Child: " << p->left->key;
|
||||
else
|
||||
cout << "\n There is no left child of the node. ";
|
||||
cout << endl;
|
||||
if (p->left)
|
||||
{
|
||||
cout << "\n\nLeft:\n";
|
||||
display(p->left);
|
||||
}
|
||||
/*else
|
||||
cout<<"\nNo Left Child.\n";*/
|
||||
if (p->right)
|
||||
{
|
||||
cout << "\n\nRight:\n";
|
||||
display(p->right);
|
||||
}
|
||||
/*else
|
||||
cout<<"\nNo Right Child.\n"*/
|
||||
}
|
||||
}
|
||||
void RBtree::search()
|
||||
{
|
||||
if (root == NULL)
|
||||
{
|
||||
cout << "\nEmpty Tree\n";
|
||||
return;
|
||||
}
|
||||
int x;
|
||||
cout << "\n Enter key of the node to be searched: ";
|
||||
cin >> x;
|
||||
node *p = root;
|
||||
int found = 0;
|
||||
while (p != NULL && found == 0)
|
||||
{
|
||||
if (p->key == x)
|
||||
found = 1;
|
||||
if (found == 0)
|
||||
{
|
||||
if (p->key < x)
|
||||
p = p->right;
|
||||
else
|
||||
p = p->left;
|
||||
}
|
||||
}
|
||||
if (found == 0)
|
||||
cout << "\nElement Not Found.";
|
||||
else
|
||||
{
|
||||
cout << "\n\t FOUND NODE: ";
|
||||
cout << "\n Key: " << p->key;
|
||||
cout << "\n Colour: ";
|
||||
if (p->color == 'b')
|
||||
cout << "Black";
|
||||
else
|
||||
cout << "Red";
|
||||
if (p->parent != NULL)
|
||||
cout << "\n Parent: " << p->parent->key;
|
||||
else
|
||||
cout << "\n There is no parent of the node. ";
|
||||
if (p->right != NULL)
|
||||
cout << "\n Right Child: " << p->right->key;
|
||||
else
|
||||
cout << "\n There is no right child of the node. ";
|
||||
if (p->left != NULL)
|
||||
cout << "\n Left Child: " << p->left->key;
|
||||
else
|
||||
cout << "\n There is no left child of the node. ";
|
||||
cout << endl;
|
||||
|
||||
}
|
||||
}
|
||||
int main()
|
||||
{
|
||||
int ch, y = 0;
|
||||
RBtree obj;
|
||||
do
|
||||
{
|
||||
cout << "\n\t RED BLACK TREE ";
|
||||
cout << "\n 1. Insert in the tree ";
|
||||
cout << "\n 2. Delete a node from the tree";
|
||||
cout << "\n 3. Search for an element in the tree";
|
||||
cout << "\n 4. Display the tree ";
|
||||
cout << "\n 5. Exit ";
|
||||
cout << "\nEnter Your Choice: ";
|
||||
cin >> ch;
|
||||
switch (ch)
|
||||
{
|
||||
case 1: obj.insert();
|
||||
cout << "\nNode Inserted.\n";
|
||||
break;
|
||||
case 2: obj.del();
|
||||
break;
|
||||
case 3: obj.search();
|
||||
break;
|
||||
case 4: obj.disp();
|
||||
break;
|
||||
case 5: y = 1;
|
||||
break;
|
||||
default: cout << "\nEnter a Valid Choice.";
|
||||
}
|
||||
cout << endl;
|
||||
|
||||
} while (y != 1);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,306 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of [Reversing
|
||||
* a single linked list](https://simple.wikipedia.org/wiki/Linked_list)
|
||||
* @details
|
||||
* The linked list is a data structure used for holding a sequence of
|
||||
* values, which can be added, displayed, reversed, or removed.
|
||||
* ### Algorithm
|
||||
* Values can be added by iterating to the end of a list (by following
|
||||
* the pointers) starting from the first link. Whichever link points to null
|
||||
* is considered the last link and is pointed to the new value.
|
||||
*
|
||||
* Linked List can be reversed by using 3 pointers: current, previous, and
|
||||
* next_node; we keep iterating until the last node. Meanwhile, before changing
|
||||
* to the next of current, we store it in the next_node pointer, now we store
|
||||
* the prev pointer in the current of next, this is where the actual reversal
|
||||
* happens. And then we move the prev and current pointers one step forward.
|
||||
* Then the head node is made to point to the last node (prev pointer) after
|
||||
* completion of an iteration.
|
||||
|
||||
* [A graphic explanation and view of what's happening behind the
|
||||
*scenes](https://drive.google.com/file/d/1pM5COF0wx-wermnNy_svtyZquaCUP2xS/view?usp=sharing)
|
||||
*/
|
||||
|
||||
#include <cassert> /// for assert
|
||||
#include <iostream> /// for I/O operations
|
||||
#include <new> /// for managing dynamic storage
|
||||
|
||||
/**
|
||||
* @namespace data_structures
|
||||
* @brief Data Structures algorithms
|
||||
*/
|
||||
namespace data_structures {
|
||||
/**
|
||||
* @namespace linked_list
|
||||
* @brief Functions for singly linked list algorithm
|
||||
*/
|
||||
namespace linked_list {
|
||||
/**
|
||||
* A Node class containing a value and pointer to another link
|
||||
*/
|
||||
class Node {
|
||||
public:
|
||||
int32_t val; /// value of the current link
|
||||
Node* next; /// pointer to the next value on the list
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief creates a deep copy of a list starting at the input node
|
||||
* @param[in] node pointer to the first node/head of the list to be copied
|
||||
* @return pointer to the first node/head of the copied list or nullptr
|
||||
*/
|
||||
Node* copy_all_nodes(const Node* const node) {
|
||||
if (node) {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
|
||||
Node* res = new Node();
|
||||
res->val = node->val;
|
||||
res->next = copy_all_nodes(node->next);
|
||||
return res;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* A list class containing a sequence of links
|
||||
*/
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
|
||||
class list {
|
||||
private:
|
||||
Node* head = nullptr; // link before the actual first element
|
||||
void delete_all_nodes();
|
||||
void copy_all_nodes_from_list(const list& other);
|
||||
|
||||
public:
|
||||
bool isEmpty() const;
|
||||
void insert(int32_t new_elem);
|
||||
void reverseList();
|
||||
void display() const;
|
||||
int32_t top() const;
|
||||
int32_t last() const;
|
||||
int32_t traverse(int32_t index) const;
|
||||
~list();
|
||||
list() = default;
|
||||
list(const list& other);
|
||||
list& operator=(const list& other);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Utility function that checks if the list is empty
|
||||
* @returns true if the list is empty
|
||||
* @returns false if the list is not empty
|
||||
*/
|
||||
bool list::isEmpty() const { return head == nullptr; }
|
||||
|
||||
/**
|
||||
* @brief Utility function that adds a new element at the end of the list
|
||||
* @param new_elem element be added at the end of the list
|
||||
*/
|
||||
void list::insert(int32_t n) {
|
||||
try {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
|
||||
Node* new_node = new Node();
|
||||
Node* temp = nullptr;
|
||||
new_node->val = n;
|
||||
new_node->next = nullptr;
|
||||
if (isEmpty()) {
|
||||
head = new_node;
|
||||
} else {
|
||||
temp = head;
|
||||
while (temp->next != nullptr) {
|
||||
temp = temp->next;
|
||||
}
|
||||
temp->next = new_node;
|
||||
}
|
||||
} catch (std::bad_alloc& exception) {
|
||||
std::cerr << "bad_alloc detected: " << exception.what() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility function for reversing a list
|
||||
* @brief Using the current, previous, and next pointer.
|
||||
* @returns void
|
||||
*/
|
||||
void list::reverseList() {
|
||||
Node* curr = head;
|
||||
Node* prev = nullptr;
|
||||
Node* next_node = nullptr;
|
||||
while (curr != nullptr) {
|
||||
next_node = curr->next;
|
||||
curr->next = prev;
|
||||
prev = curr;
|
||||
curr = next_node;
|
||||
}
|
||||
head = prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Utility function to find the top element of the list
|
||||
* @returns the top element of the list
|
||||
*/
|
||||
int32_t list::top() const {
|
||||
if (!isEmpty()) {
|
||||
return head->val;
|
||||
} else {
|
||||
throw std::logic_error("List is empty");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Utility function to find the last element of the list
|
||||
* @returns the last element of the list
|
||||
*/
|
||||
int32_t list::last() const {
|
||||
if (!isEmpty()) {
|
||||
Node* t = head;
|
||||
while (t->next != nullptr) {
|
||||
t = t->next;
|
||||
}
|
||||
return t->val;
|
||||
} else {
|
||||
throw std::logic_error("List is empty");
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Utility function to find the i th element of the list
|
||||
* @returns the i th element of the list
|
||||
*/
|
||||
int32_t list::traverse(int32_t index) const {
|
||||
Node* current = head;
|
||||
|
||||
int count = 0;
|
||||
while (current != nullptr) {
|
||||
if (count == index) {
|
||||
return (current->val);
|
||||
}
|
||||
count++;
|
||||
current = current->next;
|
||||
}
|
||||
|
||||
/* if we get to this line,the caller was asking for a non-existent element
|
||||
so we assert fail */
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief calls delete operator on every node in the represented list
|
||||
*/
|
||||
void list::delete_all_nodes() {
|
||||
while (head != nullptr) {
|
||||
const auto tmp_node = head->next;
|
||||
delete head;
|
||||
head = tmp_node;
|
||||
}
|
||||
}
|
||||
|
||||
list::~list() { delete_all_nodes(); }
|
||||
|
||||
void list::copy_all_nodes_from_list(const list& other) {
|
||||
assert(isEmpty());
|
||||
head = copy_all_nodes(other.head);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief copy constructor creating a deep copy of every node of the input
|
||||
*/
|
||||
list::list(const list& other) { copy_all_nodes_from_list(other); }
|
||||
|
||||
/**
|
||||
* @brief assignment operator creating a deep copy of every node of the input
|
||||
*/
|
||||
list& list::operator=(const list& other) {
|
||||
if (this == &other) {
|
||||
return *this;
|
||||
}
|
||||
delete_all_nodes();
|
||||
|
||||
copy_all_nodes_from_list(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace linked_list
|
||||
} // namespace data_structures
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
data_structures::linked_list::list L;
|
||||
// 1st test
|
||||
L.insert(11);
|
||||
L.insert(12);
|
||||
L.insert(15);
|
||||
L.insert(10);
|
||||
L.insert(-12);
|
||||
L.insert(-20);
|
||||
L.insert(18);
|
||||
assert(L.top() == 11);
|
||||
assert(L.last() == 18);
|
||||
L.reverseList();
|
||||
// Reversal Testing
|
||||
assert(L.top() == 18);
|
||||
assert(L.traverse(1) == -20);
|
||||
assert(L.traverse(2) == -12);
|
||||
assert(L.traverse(3) == 10);
|
||||
assert(L.traverse(4) == 15);
|
||||
assert(L.traverse(5) == 12);
|
||||
assert(L.last() == 11);
|
||||
std::cout << "All tests have successfully passed!" << std::endl;
|
||||
}
|
||||
|
||||
void test_copy_constructor() {
|
||||
data_structures::linked_list::list L;
|
||||
L.insert(10);
|
||||
L.insert(20);
|
||||
L.insert(30);
|
||||
data_structures::linked_list::list otherList(L);
|
||||
otherList.insert(40);
|
||||
|
||||
L.insert(400);
|
||||
|
||||
assert(L.top() == 10);
|
||||
assert(otherList.top() == 10);
|
||||
assert(L.traverse(1) == 20);
|
||||
assert(otherList.traverse(1) == 20);
|
||||
|
||||
assert(L.traverse(2) == 30);
|
||||
assert(otherList.traverse(2) == 30);
|
||||
|
||||
assert(L.last() == 400);
|
||||
assert(otherList.last() == 40);
|
||||
}
|
||||
|
||||
void test_assignment_operator() {
|
||||
data_structures::linked_list::list L;
|
||||
data_structures::linked_list::list otherList;
|
||||
L.insert(10);
|
||||
L.insert(20);
|
||||
L.insert(30);
|
||||
otherList = L;
|
||||
|
||||
otherList.insert(40);
|
||||
L.insert(400);
|
||||
|
||||
assert(L.top() == 10);
|
||||
assert(otherList.top() == 10);
|
||||
assert(L.traverse(1) == 20);
|
||||
assert(otherList.traverse(1) == 20);
|
||||
|
||||
assert(L.traverse(2) == 30);
|
||||
assert(otherList.traverse(2) == 30);
|
||||
|
||||
assert(L.last() == 400);
|
||||
assert(otherList.last() == 40);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
test_copy_constructor();
|
||||
test_assignment_operator();
|
||||
return 0;
|
||||
}
|
||||
Executable
+133
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief A data structure to quickly do operations on ranges: the [Segment Tree](https://en.wikipedia.org/wiki/Segment_tree) algorithm implementation
|
||||
* @details
|
||||
* Implementation of the segment tree data structre
|
||||
*
|
||||
* Can do point updates (updates the value of some position)
|
||||
* and range queries, where it gives the value of some associative
|
||||
* opperation done on a range
|
||||
*
|
||||
* Both of these operations take O(log N) time
|
||||
* @author [Nishant Chatterjee](https://github.com/nishantc1527)
|
||||
*/
|
||||
|
||||
#include <iostream> /// For IO operations
|
||||
#include <vector> /// For std::vector
|
||||
#include <algorithm> /// For std::min and std::max
|
||||
#include <cassert> /// For assert
|
||||
|
||||
/*
|
||||
* @namespace
|
||||
* @brief Data structures
|
||||
*/
|
||||
namespace data_structures {
|
||||
/**
|
||||
* @brief class representation of the segment tree
|
||||
* @tparam T The type of the class that goes in the datastructure
|
||||
*/
|
||||
template <class T>
|
||||
class SegmentTree {
|
||||
private:
|
||||
const T ID = 0; ///< Comb(ID, x) = x
|
||||
std::vector<T> t; ///< Vector to represent the tree
|
||||
int size = 0; ///< Number of elements available for querying in the tree
|
||||
private:
|
||||
/**
|
||||
* @brief Any associative function that combines x and y
|
||||
* @param x The first operand
|
||||
* @param y The second operand
|
||||
* @return Some associative operation applied to these two values. In this case, I used addition
|
||||
*/
|
||||
T comb(T x, T y) {
|
||||
return x + y;
|
||||
}
|
||||
/**
|
||||
* @brief Gives the midpoint between two integers
|
||||
* @param l The left endpoint
|
||||
* @param r The right endpoint
|
||||
* @return the middle point between them
|
||||
*/
|
||||
int mid(int l, int r) {
|
||||
return l + (r - l) / 2;
|
||||
}
|
||||
/**
|
||||
* @brief Helper method for update method below
|
||||
* @param i The index of the current node
|
||||
* @param l The leftmost node of the current node
|
||||
* @param r The rightmost node of the current node
|
||||
* @param pos The position to update
|
||||
* @param val The value to update it to
|
||||
*/
|
||||
void update(int i, int l, int r, int pos, T val) {
|
||||
if(l == r) t[i] = val;
|
||||
else {
|
||||
int m = mid(l, r);
|
||||
if(pos <= m) update(i * 2, l, m, pos, val);
|
||||
else update(i * 2 + 1, m + 1, r, pos, val);
|
||||
t[i] = comb(t[i * 2], t[i * 2 + 1]);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Helper method for range_comb method below
|
||||
* @param i The current node
|
||||
* @param l The leftmost node of the current node
|
||||
* @param r The rightmost node of the current node
|
||||
* @param tl The left endpoint of the range
|
||||
* @param tr The right endpoint of the range
|
||||
* @return The comb operation applied to all values between tl and tr
|
||||
*/
|
||||
T range_comb(int i, int l, int r, int tl, int tr) {
|
||||
if(l == tl && r == tr) return t[i];
|
||||
if(tl > tr) return 0;
|
||||
int m = mid(l, r);
|
||||
return comb(range_comb(i * 2, l, m, tl, std::min(tr, m)), range_comb(i * 2 + 1, m + 1, r, std::max(tl, m + 1), tr));
|
||||
}
|
||||
public:
|
||||
SegmentTree(int n) : t(n * 4, ID), size(n) {}
|
||||
/**
|
||||
* @brief Updates a value at a certain position
|
||||
* @param pos The position to update
|
||||
* @param val The value to update it to
|
||||
*/
|
||||
void update(int pos, T val) {
|
||||
update(1, 1, size, pos, val);
|
||||
}
|
||||
/**
|
||||
* @brief Returns comb across all values between l and r
|
||||
* @param l The left endpoint of the range
|
||||
* @param r The right endpoint of the range
|
||||
* @return The value of the comb operations
|
||||
*/
|
||||
T range_comb(int l, int r) {
|
||||
return range_comb(1, 1, size, l, r);
|
||||
}
|
||||
};
|
||||
} // namespace data_structures
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
data_structures::SegmentTree<int> t(5);
|
||||
t.update(1, 1);
|
||||
t.update(2, 2);
|
||||
t.update(3, 3);
|
||||
t.update(4, 4);
|
||||
t.update(5, 5);
|
||||
assert(t.range_comb(1, 3) == 6); // 1 + 2 + 3 = 6
|
||||
t.update(1, 3);
|
||||
assert(t.range_comb(1, 3) == 8); // 3 + 2 + 3 = 8
|
||||
|
||||
std::cout << "All tests have successfully passed!\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
/**
|
||||
* @file skip_list.cpp
|
||||
* @brief Data structure for fast searching and insertion in \f$O(\log n)\f$
|
||||
* time
|
||||
* @details
|
||||
* A skip list is a data structure that is used for storing a sorted list of
|
||||
* items with a help of hierarchy of linked lists that connect increasingly
|
||||
* sparse subsequences of the items
|
||||
*
|
||||
* References used: [GeeksForGeek](https://www.geeksforgeeks.org/skip-list/),
|
||||
* [OpenGenus](https://iq.opengenus.org/skip-list) for PseudoCode and Code
|
||||
* @author [enqidu](https://github.com/enqidu)
|
||||
* @author [Krishna Vedala](https://github.com/kvedala)
|
||||
*/
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
/** \namespace data_structures
|
||||
* \brief Data-structure algorithms
|
||||
*/
|
||||
namespace data_structures {
|
||||
constexpr int MAX_LEVEL = 2; ///< Maximum level of skip list
|
||||
constexpr float PROBABILITY = 0.5; ///< Current probability for "coin toss"
|
||||
|
||||
/**
|
||||
* Node structure [Key][Node*, Node*...]
|
||||
*/
|
||||
struct Node {
|
||||
int key; ///< key integer
|
||||
void* value; ///< pointer of value
|
||||
std::vector<std::shared_ptr<Node>>
|
||||
forward; ///< nodes of the given one in all levels
|
||||
|
||||
/**
|
||||
* Creates node with provided key, level and value
|
||||
* @param key is number that is used for comparision
|
||||
* @param level is the maximum level node's going to added
|
||||
*/
|
||||
Node(int key, int level, void* value = nullptr) : key(key), value(value) {
|
||||
// Initialization of forward vector
|
||||
for (int i = 0; i < (level + 1); i++) {
|
||||
forward.push_back(nullptr);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* SkipList class implementation with basic methods
|
||||
*/
|
||||
class SkipList {
|
||||
int level; ///< Maximum level of the skiplist
|
||||
std::shared_ptr<Node> header; ///< Pointer to the header node
|
||||
|
||||
public:
|
||||
/**
|
||||
* Skip List constructor. Initializes header, start
|
||||
* Node for searching in the list
|
||||
*/
|
||||
SkipList() {
|
||||
level = 0;
|
||||
// Header initialization
|
||||
header = std::make_shared<Node>(-1, MAX_LEVEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns random level of the skip list.
|
||||
* Every higher level is 2 times less likely.
|
||||
* @return random level for skip list
|
||||
*/
|
||||
int randomLevel() {
|
||||
int lvl = 0;
|
||||
while (static_cast<float>(std::rand()) / RAND_MAX < PROBABILITY &&
|
||||
lvl < MAX_LEVEL) {
|
||||
lvl++;
|
||||
}
|
||||
return lvl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts elements with given key and value;
|
||||
* It's level is computed by randomLevel() function.
|
||||
* @param key is number that is used for comparision
|
||||
* @param value pointer to a value, that can be any type
|
||||
*/
|
||||
void insertElement(int key, void* value) {
|
||||
std::cout << "Inserting" << key << "...";
|
||||
std::shared_ptr<Node> x = header;
|
||||
std::array<std::shared_ptr<Node>, MAX_LEVEL + 1> update;
|
||||
update.fill(nullptr);
|
||||
|
||||
for (int i = level; i >= 0; i--) {
|
||||
while (x->forward[i] != nullptr && x->forward[i]->key < key) {
|
||||
x = x->forward[i];
|
||||
}
|
||||
update[i] = x;
|
||||
}
|
||||
|
||||
x = x->forward[0];
|
||||
|
||||
bool doesnt_exist = (x == nullptr || x->key != key);
|
||||
if (doesnt_exist) {
|
||||
int rlevel = randomLevel();
|
||||
|
||||
if (rlevel > level) {
|
||||
for (int i = level + 1; i < rlevel + 1; i++) update[i] = header;
|
||||
|
||||
// Update current level
|
||||
level = rlevel;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> n =
|
||||
std::make_shared<Node>(key, rlevel, value);
|
||||
for (int i = 0; i <= rlevel; i++) {
|
||||
n->forward[i] = update[i]->forward[i];
|
||||
update[i]->forward[i] = n;
|
||||
}
|
||||
std::cout << "Inserted" << std::endl;
|
||||
|
||||
} else {
|
||||
std::cout << "Exists" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an element by key and prints if has been removed successfully
|
||||
* @param key is number that is used for comparision.
|
||||
*/
|
||||
void deleteElement(int key) {
|
||||
std::shared_ptr<Node> x = header;
|
||||
|
||||
std::array<std::shared_ptr<Node>, MAX_LEVEL + 1> update;
|
||||
update.fill(nullptr);
|
||||
|
||||
for (int i = level; i >= 0; i--) {
|
||||
while (x->forward[i] != nullptr && x->forward[i]->key < key) {
|
||||
x = x->forward[i];
|
||||
}
|
||||
update[i] = x;
|
||||
}
|
||||
|
||||
x = x->forward[0];
|
||||
|
||||
bool doesnt_exist = (x == nullptr || x->key != key);
|
||||
|
||||
if (!doesnt_exist) {
|
||||
for (int i = 0; i <= level; i++) {
|
||||
if (update[i]->forward[i] != x) {
|
||||
break;
|
||||
}
|
||||
update[i]->forward[i] = x->forward[i];
|
||||
}
|
||||
/* Remove empty levels*/
|
||||
while (level > 0 && header->forward[level] == nullptr) level--;
|
||||
std::cout << "Deleted" << std::endl;
|
||||
} else {
|
||||
std::cout << "Doesn't exist" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searching element in skip list structure
|
||||
* @param key is number that is used for comparision
|
||||
* @return pointer to the value of the node
|
||||
*/
|
||||
void* searchElement(int key) {
|
||||
std::shared_ptr<Node> x = header;
|
||||
std::cout << "Searching for " << key << std::endl;
|
||||
|
||||
for (int i = level; i >= 0; i--) {
|
||||
while (x->forward[i] && x->forward[i]->key < key) x = x->forward[i];
|
||||
}
|
||||
|
||||
x = x->forward[0];
|
||||
if (x && x->key == key) {
|
||||
std::cout << "Found" << std::endl;
|
||||
return x->value;
|
||||
} else {
|
||||
std::cout << "Not Found" << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display skip list level
|
||||
*/
|
||||
void displayList() {
|
||||
std::cout << "Displaying list:\n";
|
||||
for (int i = 0; i <= level; i++) {
|
||||
std::shared_ptr<Node> node = header->forward[i];
|
||||
std::cout << "Level " << (i) << ": ";
|
||||
while (node != nullptr) {
|
||||
std::cout << node->key << " ";
|
||||
node = node->forward[i];
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace data_structures
|
||||
|
||||
/**
|
||||
* Main function:
|
||||
* Creates and inserts random 2^[number of levels]
|
||||
* elements into the skip lists and than displays it
|
||||
*/
|
||||
int main() {
|
||||
std::srand(std::time(nullptr));
|
||||
|
||||
data_structures::SkipList lst;
|
||||
|
||||
for (int j = 0; j < (1 << (data_structures::MAX_LEVEL + 1)); j++) {
|
||||
int k = (std::rand() % (1 << (data_structures::MAX_LEVEL + 2)) + 1);
|
||||
lst.insertElement(k, &j);
|
||||
}
|
||||
|
||||
lst.displayList();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief Implementation of [Sparse
|
||||
* Table](https://brilliant.org/wiki/sparse-table/) for `min()` function.
|
||||
* @author [Mann Patel](https://github.com/manncodes)
|
||||
* @details
|
||||
* Sparse Table is a data structure, that allows answering range queries.
|
||||
* It can answer most range queries in O(logn), but its true power is answering
|
||||
* range minimum queries (or equivalent range maximum queries). For those
|
||||
* queries it can compute the answer in O(1) time. The only drawback of this
|
||||
* data structure is, that it can only be used on immutable arrays. This means,
|
||||
* that the array cannot be changed between two queries.
|
||||
*
|
||||
* If any element in the array changes, the complete data structure has to be
|
||||
* recomputed.
|
||||
*
|
||||
* @todo make stress tests.
|
||||
*
|
||||
* @warning
|
||||
* This sparse table is made for `min(a1,a2,...an)` duplicate invariant
|
||||
* function. This implementation can be changed to other functions like
|
||||
* `gcd()`, `lcm()`, and `max()` by changing a few lines of code.
|
||||
*/
|
||||
|
||||
#include <array> /// for std::array
|
||||
#include <cassert> /// for assert
|
||||
#include <cstdint>
|
||||
#include <iostream> /// for IO operations
|
||||
|
||||
/**
|
||||
* @namespace data_structures
|
||||
* @brief Data Structures algorithms
|
||||
*/
|
||||
namespace data_structures {
|
||||
|
||||
/**
|
||||
* @namespace sparse_table
|
||||
* @brief Functions for Implementation of [Sparse
|
||||
* Table](https://brilliant.org/wiki/sparse-table/)
|
||||
*/
|
||||
namespace sparse_table {
|
||||
|
||||
/**
|
||||
* @brief A struct to represent sparse table for `min()` as their invariant
|
||||
* function, for the given array `A`. The answer to queries are stored in the
|
||||
* array ST.
|
||||
*/
|
||||
constexpr uint32_t N = 12345; ///< the maximum size of the array.
|
||||
constexpr uint8_t M = 14; ///< ceil(log2(N)).
|
||||
|
||||
struct Sparse_table {
|
||||
size_t n = 0; ///< size of input array.
|
||||
|
||||
/** @warning check if `N` is not less than `n`. if so, manually increase the
|
||||
* value of N */
|
||||
|
||||
std::array<int64_t, N> A = {}; ///< input array to perform RMQ.
|
||||
std::array<std::array<int64_t, N>, M>
|
||||
ST{}; ///< the sparse table storing `min()` values for given interval.
|
||||
std::array<int64_t, N> LOG = {}; ///< where floor(log2(i)) are precomputed.
|
||||
|
||||
/**
|
||||
* @brief Builds the sparse table for computing min/max/gcd/lcm/...etc
|
||||
* for any contiguous sub-segment of the array.This is an example of
|
||||
* computing the index of the minimum value.
|
||||
* @return void
|
||||
* @complexity: O(n.log(n))
|
||||
*/
|
||||
void buildST() {
|
||||
LOG[0] = -1;
|
||||
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
ST[0][i] = static_cast<int64_t>(i);
|
||||
LOG[i + 1] = LOG[i] + !(i & (i + 1)); ///< precomputing `log2(i+1)`
|
||||
}
|
||||
|
||||
for (size_t j = 1; static_cast<size_t>(1 << j) <= n; ++j) {
|
||||
for (size_t i = 0; static_cast<size_t>(i + (1 << j)) <= n; ++i) {
|
||||
/**
|
||||
* @note notice how we deal with the range of length `pow(2,i)`,
|
||||
* and we can reuse the computation that we did for the range of
|
||||
* length `pow(2,i-1)`.
|
||||
*
|
||||
* So, ST[j][i] = min( ST[j-1][i], ST[j-1][i + pow(2,j-1)]).
|
||||
* @example ST[2][3] = min(ST[1][3], ST[1][5])
|
||||
*/
|
||||
|
||||
int64_t x = ST[j - 1][i]; ///< represents minimum value over
|
||||
///< the range [j,i]
|
||||
int64_t y =
|
||||
ST[j - 1]
|
||||
[i + (1 << (j - 1))]; ///< represents minimum value over
|
||||
///< the range [j,i + pow(2,j-1)]
|
||||
|
||||
ST[j][i] =
|
||||
(A[x] <= A[y] ? x : y); ///< represents minimum value over
|
||||
///< the range [j,i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Queries the sparse table for the value of the interval [l, r]
|
||||
* (i.e. from l to r inclusive).
|
||||
* @param l the left index of the range (inclusive).
|
||||
* @param r the right index of the range (inclusive).
|
||||
* @return the computed value of the given interval.
|
||||
* @complexity: O(1)
|
||||
*/
|
||||
int64_t query(int64_t l, int64_t r) {
|
||||
int64_t g = LOG[r - l + 1]; ///< smallest power of 2 covering [l,r]
|
||||
int64_t x = ST[g][l]; ///< represents minimum value over the range
|
||||
///< [g,l]
|
||||
int64_t y =
|
||||
ST[g][r - (1 << g) + 1]; ///< represents minimum value over the
|
||||
///< range [g, r - pow(2,g) + 1]
|
||||
|
||||
return (A[x] <= A[y] ? x : y); ///< represents minimum value over
|
||||
///< the whole range [l,r]
|
||||
}
|
||||
};
|
||||
} // namespace sparse_table
|
||||
} // namespace data_structures
|
||||
|
||||
/**
|
||||
* @brief Self-test implementations
|
||||
* @returns void
|
||||
*/
|
||||
static void test() {
|
||||
/* We take an array as an input on which we need to perform the ranged
|
||||
* minimum queries[RMQ](https://en.wikipedia.org/wiki/Range_minimum_query).
|
||||
*/
|
||||
std::array<int64_t, 10> testcase = {
|
||||
1, 2, 3, 4, 5,
|
||||
6, 7, 8, 9, 10}; ///< array on which RMQ will be performed.
|
||||
size_t testcase_size =
|
||||
sizeof(testcase) / sizeof(testcase[0]); ///< size of self test's array
|
||||
|
||||
data_structures::sparse_table::Sparse_table
|
||||
st{}; ///< declaring sparse tree
|
||||
|
||||
std::copy(std::begin(testcase), std::end(testcase),
|
||||
std::begin(st.A)); ///< copying array to the struct
|
||||
st.n = testcase_size; ///< passing the array's size to the struct
|
||||
|
||||
st.buildST(); ///< precomputing sparse tree
|
||||
|
||||
// pass queries of the form: [l,r]
|
||||
assert(st.query(1, 9) == 1); ///< as 1 is smallest from 1..9
|
||||
assert(st.query(2, 6) == 2); ///< as 2 is smallest from 2..6
|
||||
assert(st.query(3, 8) == 3); ///< as 3 is smallest from 3..8
|
||||
|
||||
std::cout << "Self-test implementations passed!" << std::endl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main function
|
||||
* @returns 0 on exit
|
||||
*/
|
||||
int main() {
|
||||
test(); // run self-test implementations
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @file
|
||||
* @author danghai
|
||||
* @author [Piotr Idzik](https://github.com/vil02)
|
||||
* @brief This class specifies the basic operation on a stack as a linked list
|
||||
**/
|
||||
#ifndef DATA_STRUCTURES_STACK_HPP_
|
||||
#define DATA_STRUCTURES_STACK_HPP_
|
||||
|
||||
#include <stdexcept> /// for std::invalid_argument
|
||||
|
||||
#include "node.hpp" /// for Node
|
||||
|
||||
/** Definition of the stack class
|
||||
* \tparam value_type type of data nodes of the linked list in the stack should
|
||||
* contain
|
||||
*/
|
||||
template <class ValueType>
|
||||
class stack {
|
||||
public:
|
||||
using value_type = ValueType;
|
||||
|
||||
/** Show stack */
|
||||
void display() const {
|
||||
std::cout << "Top --> ";
|
||||
display_all(this->stackTop.get());
|
||||
std::cout << '\n';
|
||||
std::cout << "Size of stack: " << size << std::endl;
|
||||
}
|
||||
|
||||
std::vector<value_type> toVector() const {
|
||||
return push_all_to_vector(this->stackTop.get(), this->size);
|
||||
}
|
||||
|
||||
private:
|
||||
void ensureNotEmpty() const {
|
||||
if (isEmptyStack()) {
|
||||
throw std::invalid_argument("Stack is empty.");
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/** Determine whether the stack is empty */
|
||||
bool isEmptyStack() const { return (stackTop == nullptr); }
|
||||
|
||||
/** Add new item to the stack */
|
||||
void push(const value_type& item) {
|
||||
auto newNode = std::make_shared<Node<value_type>>();
|
||||
newNode->data = item;
|
||||
newNode->next = stackTop;
|
||||
stackTop = newNode;
|
||||
size++;
|
||||
}
|
||||
|
||||
/** Return the top element of the stack */
|
||||
value_type top() const {
|
||||
ensureNotEmpty();
|
||||
return stackTop->data;
|
||||
}
|
||||
|
||||
/** Remove the top element of the stack */
|
||||
void pop() {
|
||||
ensureNotEmpty();
|
||||
stackTop = stackTop->next;
|
||||
size--;
|
||||
}
|
||||
|
||||
/** Clear stack */
|
||||
void clear() {
|
||||
stackTop = nullptr;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<Node<value_type>> stackTop =
|
||||
{}; /**< Pointer to the stack */
|
||||
std::size_t size = 0; ///< size of stack
|
||||
};
|
||||
|
||||
#endif // DATA_STRUCTURES_STACK_HPP_
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user