diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000000..2711cbb0b40 --- /dev/null +++ b/.clang-format @@ -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: '^' + 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 +... + diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 00000000000..99d867ab450 --- /dev/null +++ b/.clang-tidy @@ -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 }' diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000000..55cadc285f2 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @Panquesito7 @realstealthninja diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000000..7eaf8e3f49c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -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 diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..875cc4efab0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -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 diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000000..46cc9a391cf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -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 diff --git a/.github/ISSUE_TEMPLATE/other.yml b/.github/ISSUE_TEMPLATE/other.yml new file mode 100644 index 00000000000..d6dc0cfe9f8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/other.yml @@ -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 diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000000..268098beecd --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,21 @@ +#### Description of Change + + +#### Checklist + + +- [ ] 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: diff --git a/.github/workflows/approved-label.yml b/.github/workflows/approved-label.yml new file mode 100644 index 00000000000..9fbc5ed0ae8 --- /dev/null +++ b/.github/workflows/approved-label.yml @@ -0,0 +1,14 @@ +on: pull_request_review +name: Add "approved" label when approved +jobs: + add_label: + name: Add "approved" label when approved + runs-on: ubuntu-latest + steps: + - name: Add "approved" label when approved + uses: pullreminders/label-when-approved-action@master + env: + APPROVALS: "1" + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ADD_LABEL: "approved" + REMOVE_LABEL: "" diff --git a/.github/workflows/awesome_workflow.yml b/.github/workflows/awesome_workflow.yml new file mode 100644 index 00000000000..70dd717fa33 --- /dev/null +++ b/.github/workflows/awesome_workflow.yml @@ -0,0 +1,75 @@ +name: Awesome CI Workflow +on: [push, pull_request] +permissions: + 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'] + }) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000000..2b40ac59304 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -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@v2 + # 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@v2 + + # ℹ️ 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@v2 diff --git a/.github/workflows/directory_writer.yml b/.github/workflows/directory_writer.yml new file mode 100644 index 00000000000..bb3b8395607 --- /dev/null +++ b/.github/workflows/directory_writer.yml @@ -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/ diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml new file mode 100644 index 00000000000..b9c3fe03f52 --- /dev/null +++ b/.github/workflows/gh-pages.yml @@ -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 diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 00000000000..0018600db57 --- /dev/null +++ b/.github/workflows/stale.yml @@ -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 diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000000..c4951fe97b1 --- /dev/null +++ b/.gitignore @@ -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 diff --git a/.gitpod.dockerfile b/.gitpod.dockerfile new file mode 100644 index 00000000000..f3891405372 --- /dev/null +++ b/.gitpod.dockerfile @@ -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/* diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 00000000000..4b0332719c9 --- /dev/null +++ b/.gitpod.yml @@ -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 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000000..f6d76514ffb --- /dev/null +++ b/.vscode/settings.json @@ -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" + } +} diff --git a/Backtracking/Graph Coloring.cpp b/Backtracking/Graph Coloring.cpp deleted file mode 100644 index fdf50b28897..00000000000 --- a/Backtracking/Graph Coloring.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include - -// Number of vertices in the graph -#define V 4 - -void printSolution(int color[]); - -/* A utility function to check if the current color assignment - is safe for vertex v */ -bool isSafe (int v, bool graph[V][V], int color[], int c) -{ - for (int i = 0; i < V; i++) - if (graph[v][i] && c == color[i]) - return false; - return true; -} - -/* A recursive utility function to solve m coloring problem */ -void graphColoring(bool graph[V][V], int m, int color[], int v) -{ - /* base case: If all vertices are assigned a color then - return true */ - if (v == V){ - printSolution(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, graph, color, c)) - { - color[v] = c; - - /* recur to assign colors to rest of the vertices */ - graphColoring (graph, m, color, v+1); - - - /* If assigning color c doesn't lead to a solution - then remove it */ - color[v] = 0; - } - } - -} - -/* A utility function to print solution */ -void printSolution(int color[]) -{ - printf(" Following are the assigned colors \n"); - for (int i = 0; i < V; i++) - printf(" %d ", color[i]); - printf("\n"); -} - -// driver program to test above function -int main() -{ - /* Create following graph and test whether it is 3 colorable - (3)---(2) - | / | - | / | - | / | - (0)---(1) - */ - bool graph[V][V] = {{0, 1, 1, 1}, - {1, 0, 1, 0}, - {1, 1, 0, 1}, - {1, 0, 1, 0}, - }; - int m = 3; // Number of colors - - int color[V]; - - for (int i = 0; i < V; i++) - color[i] = 0; - - graphColoring(graph, m, color, 0); - return 0; -} diff --git a/Backtracking/N Queens.cpp b/Backtracking/N Queens.cpp deleted file mode 100644 index f070c5803ee..00000000000 --- a/Backtracking/N Queens.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include -#define N 4 -using namespace std; - -void printSolution(int board[N][N]) -{ - cout<<"\n"; - for (int i = 0; i < N; i++) - { - for (int j = 0; j < N; j++) - cout<<""<=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){ - printSolution(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(board, i, col) ) - { - /* Place this queen in board[i][col] */ -// cout<<"\n"< -#define size 4 - -using namespace std; - -int solveMaze(int currposrow,int currposcol,int maze[size][size],int soln[size][size]) -{ - if((currposrow==size-1) && (currposcol==size-1)) - { - soln[currposrow][currposcol]=1; - for(int i=0;i -using namespace std; -///N=9; -int n=9; - - -bool isPossible(int mat[][9],int i,int j,int no){ - ///Row or col nahin hona chahiye - for(int x=0;x arr = {5, 3, 8, 12, 14, 16, 28, 96, 2, 5977}; +std::vector 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 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 /// for IO operations +#include /// for std::vector +#include /// 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 +bool is_number_on_array(const std::vector &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 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 /// for assert +#include /// for `some function here` + +/** + * @namespace + * @brief + */ +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 +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 + * @param argc commandline argument count (ignored) + * @param argv commandline array of arguments (ignored) + * @returns 0 on exit + */ +int main(int argc, char *argv[]) { + 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/") # 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() +``` + +#### 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 [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](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. + +![GitHub Actions](https://user-images.githubusercontent.com/51391473/94609466-6e925100-0264-11eb-9d6f-3706190eab2b.png) + +- 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! diff --git a/CodingGuidelines.md b/CodingGuidelines.md new file mode 100644 index 00000000000..da38708b5b9 --- /dev/null +++ b/CodingGuidelines.md @@ -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! diff --git a/Computer Oriented Statistical Methods/Bisection_method.CPP b/Computer Oriented Statistical Methods/Bisection_method.CPP deleted file mode 100644 index b178f0f5224..00000000000 --- a/Computer Oriented Statistical Methods/Bisection_method.CPP +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include -#include - -float eq(float i) -{ - return (pow(i,3)-(4*i)-9); // original equation -} - -void main() -{ - float a,b,x,z; - clrscr(); - for(int i=0;i<100;i++) - { - z=eq(i); - if(z>=0) - { - b=i; - a=--i; - goto START; - } - } - - START: - - cout<<"\nFirst initial: "< 0 && z<0.0009) // stoping criteria - { - goto END; - } - } - - END: - cout<<"\n\nRoot: "< -using namespace std; - -int main() -{ - int mat_size,i,j,step; - - cout<<"Matrix size: "; - cin>>mat_size; - - double mat[mat_size+1][mat_size+1], x[mat_size][mat_size+1]; - - cout<>mat[i][j]; //Enter (mat_size*mat_size) value of the matrix. - } - } - - for(step=0;step=0;i--) - { - double sum = 0; - for(j=mat_size-1;j>i;j--) - { - x[i][j] = x[j][j] * x[i][j]; - sum = x[i][j] + sum; - } - if(x[i][i]==0) - x[i][i] = 0; - else - x[i][i] = (x[i][mat_size] - sum)/(x[i][i]); - - cout<<"x"< -#include -#include - -float eq(float i) -{ - return (pow(i,3)-(4*i)-9); // original equation -} -float eq_der(float i) -{ - return ((3*pow(i,2))-4); // derivative of equation -} - -void main() -{ - float a,b,z,c,m,n; - clrscr(); - for(int i=0;i<100;i++) - { - z=eq(i); - if(z>=0) - { - b=i; - a=--i; - goto START; - } - } - - START: - - cout<<"\nFirst initial: "< 0 && m<0.009) // stoping criteria - { - goto END; - } - } - - END: - cout<<"\n\nRoot: "< -#include -#include - -float eq(float i) -{ - return (pow(i,3)-(4*i)-9); // original equation -} - -void main() -{ - float a,b,z,c,m,n; - clrscr(); - for(int i=0;i<100;i++) - { - z=eq(i); - if(z>=0) - { - b=i; - a=--i; - goto START; - } - } - - START: - - cout<<"\nFirst initial: "< 0 && z<0.09) // stoping criteria - { - goto END; - } - } - - END: - cout<<"\n\nRoot: "< -#include -#include - -float eq(float i) -{ - return (pow(i,3)-(4*i)-9); // origial equation -} - -void main() -{ - float a,b,z,c,m,n; - clrscr(); - for(int i=0;i<100;i++) - { - z=eq(i); - if(z>=0) - { - b=i; - a=--i; - goto START; - } - } - - START: - - cout<<"\nFirst initial: "< 0 && z<0.09) // stoping criteria - { - goto END; - } - } - - END: - cout<<"\n\nRoot: "< -#include -#include -float eq(float y) -{ - return((3*y)-(cos(y))-2); -} -float eqd(float y) -{ - return((0.5)*((cos(y))+2)); -} - -void main() -{ - float y,x1,x2,x3,sum,s,a,f1,f2,gd; - int i,n; - - clrscr(); - for(i=0;i<10;i++) - { - sum=eq(y); - cout<<"value of equation at "<"; - cin>>x1; - cout<<"enter the no iteration to perform->\n"; - cin>>n; - - for(i=0;i<=n;i++) - { - x2=eqd(x1); - cout<<"\nenter the x2->"< -#include - -using namespace std; - -typedef struct node { - int data; - int height; - struct node* left; - struct node* right; -}node; - -int max(int a, int b) { - return a > b ? a : b; -} - -// Returns a new Node - -node* createNode(int data) { - node *nn = new node(); - nn->data = data; - nn->height = 0; - nn->left = NULL; - nn->right = NULL; - return nn; -} - -// Returns height of tree - -int height(node *root) { - if(root==NULL) - return 0; - return 1 + max(height(root->left), height(root->right)); -} - -// Returns difference between height of left and right subtree - -int getBalance(node *root) { - return height(root->left) - height(root->right); -} - -// Returns Node after Right Rotation - -node* rightRotate(node *root) { - node *t = root->left; - node *u = t->right; - t->right = root; - root->left = u; - return t; -} - -// Returns Node after Left Rotation - -node* leftRotate(node *root) { - node *t = root->right; - node *u = t->left; - t->left = root; - root->right = u; - return t; -} - -// Returns node with minimum value in the tree - -node* minValue(node* root) { - if(root->left==NULL) - return root; - return minValue(root->left); -} - -// Balanced Insertion - -node* insert(node* root, int item) { - node *nn = createNode(item); - if(root == NULL) - return nn; - if(itemdata) - 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; -} - -// Balanced Deletion - -node* deleteNode(node *root, int key) { - if(root == NULL) - return root; - if(key < root->data) - root->left = deleteNode(root->left, key); - else if(key > root->data) - root->right = deleteNode(root->right, key); - - else { - // Node to be deleted is leaf node or have only one Child - if(!root->right) { - node* temp = root->left; - delete(root); - root = NULL; - return temp; - } - else if(!root->left) { - node* temp = root->right; - delete(root); - root = NULL; - 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; -} - - -// LevelOrder (Breadth First Search) - -void levelOrder(node* root) { - queue q; - q.push(root); - while(!q.empty()) { - root = q.front(); - cout<data<<" "; - q.pop(); - if(root->left) - q.push(root->left); - if(root->right) - q.push(root->right); - } -} - -int main() { - // Testing AVL Tree - node *root = NULL; - int i; - for(i = 1 ; i <= 7 ; i++) - root = insert(root, i); - cout<<"LevelOrder: "; - levelOrder(root); - root = deleteNode(root, 1); // Deleting key with value 1 - cout<<"\nLevelOrder: "; - levelOrder(root); - root = deleteNode(root, 4); // Deletin key with value 4 - cout<<"\nLevelOrder: "; - levelOrder(root); - return 0; -} diff --git a/Data Structure/Binary Search Tree.cpp b/Data Structure/Binary Search Tree.cpp deleted file mode 100644 index 5b83263bc05..00000000000 --- a/Data Structure/Binary Search Tree.cpp +++ /dev/null @@ -1,232 +0,0 @@ -#include -using namespace std; - - -struct node -{ - int val; - node *left; - node *right; -}; - -struct queue -{ - node *t[100]; - int front; - int rear; -}; - -queue q; - - -void enqueue(node *n) -{ - q.t[q.rear++]=n; -} - -node * dequeue() -{ - return (q.t[q.front++]); -} - - - -void Insert(node *n, int x) -{ - if (xval) - { - 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->left=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 (xval) - { - p->right=NULL; - } - else - { - p->left=NULL; - } - } - else if (n->right==NULL) - { - if (xval) - { - p->right=n->left; - } - else - { - p->left=n->left; - } - } - else if (n->left==NULL) - { - if (xval) - { - 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 (xval) - { - Remove(n, n->left, x); - } - else - { - Remove(n, n->right, x); - } -} - - - - -void BFT(node *n) -{ - if(n!=NULL) - { - cout<val<<" "; - enqueue(n->left); - enqueue(n->right); - BFT(dequeue()); - } -} - -void Pre(node *n) -{ - if (n!=NULL) - { - cout<val<<" "; - Pre(n->left); - Pre(n->right); - } -} - -void In(node *n) -{ - if (n!=NULL) - { - In(n->left); - cout<val<<" "; - In(n->right); - } -} - - -void Post(node *n) -{ - if (n!=NULL) - { - Post(n->left); - Post(n->right); - cout<val<<" "; - } -} - - - -int main() -{ - q.front=0; - q.rear=0; - int value; - int ch; - node *root=new node; - cout<<"\nEnter the value of root node :"; - cin>>value; - root->val=value; - root->left=NULL; - root->right=NULL; - do - { - cout<<"\n1. Insert"; - cout<<"\n2. Delete"; - cout<<"\n3. Breadth First"; - cout<<"\n4. Preorder Depth First"; - cout<<"\n5. Inorder Depth First"; - cout<<"\n6. Postorder Depth First"; - - cout<<"\nEnter Your Choice : "; - cin>>ch; - int x; - switch(ch) - { - case 1: - cout<<"\nEnter the value to be Inserted : "; - cin>>x; - Insert(root, x); - break; - case 2: - cout<<"\nEnter the value to be Deleted : "; - 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); -} diff --git a/Data Structure/Binaryheap.cpp b/Data Structure/Binaryheap.cpp deleted file mode 100644 index 92bcb275a44..00000000000 --- a/Data Structure/Binaryheap.cpp +++ /dev/null @@ -1,159 +0,0 @@ -// A C++ program to demonstrate common Binary Heap Operations -#include -#include -using namespace std; - -// Prototype of a utility function to swap two integers -void swap(int *x, int *y); - -// 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 - MinHeap(int capacity); - - // 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); -}; - -// Constructor: Builds a heap from a given array a[] of given size -MinHeap::MinHeap(int cap) -{ - heap_size = 0; - capacity = cap; - harr = new int[cap]; -} - -// Inserts a new key 'k' -void MinHeap::insertKey(int k) -{ - if (heap_size == capacity) - { - 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]) - { - 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]) - { - 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) - { - swap(&harr[i], &harr[smallest]); - MinHeapify(smallest); - } -} - -// A utility function to swap two elements -void swap(int *x, int *y) -{ - int temp = *x; - *x = *y; - *y = temp; -} - -// 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); - cout << h.extractMin() << " "; - cout << h.getMin() << " "; - h.decreaseKey(2, 1); - cout << h.getMin(); - return 0; -} diff --git a/Data Structure/Doubly Linked List.cpp b/Data Structure/Doubly Linked List.cpp deleted file mode 100644 index db550d4225b..00000000000 --- a/Data Structure/Doubly Linked List.cpp +++ /dev/null @@ -1,125 +0,0 @@ -#include -using namespace std; - -struct node -{ - int val; - node *prev; - node *next; -}; - -node *start; - -void 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 remove(int x) -{ - node *t=start; - while(t->val!=x) - { - t=t->next; - } - t->prev->next=t->next; - t->next->prev=t->prev; - delete t; -} - -void search(int x) -{ - node *t= start; - int found =0; - while(t!=NULL) - { - if(t->val==x) - { - cout<<"\nFound"; - found=1; - break; - } - t=t->next; - } - if(found==0) - { - cout<<"\nNot Found"; - } -} - -void show() -{ - node *t=start; - while(t!=NULL) - { - cout<val<<"\t"; - t=t->next; - } - -} - -void reverseShow() -{ - node *t=start; - while(t->next!=NULL) - { - t=t->next; - } - while(t!=NULL) - { - cout<val<<"\t"; - t=t->prev; - } -} - -int main() -{ - int choice, x; - do - { - cout<<"\n1. Insert"; - cout<<"\n2. Delete"; - cout<<"\n3. Search"; - cout<<"\n4. Forward print"; - cout<<"\n5. Reverse print"; - cout<<"\n\nEnter you choice : "; - cin>>choice; - switch (choice) - { - case 1 : cout<<"\nEnter the element to be inserted : "; - cin>>x;; - insert(x); break; - case 2 : cout<<"\nEnter the element to be removed : "; - cin>>x; - remove(x); break; - case 3 : cout<<"\nEnter the element to be searched : "; - cin>>x; - search(x); break; - case 4 : show(); break; - case 5 : reverseShow(); break; - } - } - while(choice!=0); - - return 0; -} diff --git a/Data Structure/Linked List.cpp b/Data Structure/Linked List.cpp deleted file mode 100644 index 5abebd58458..00000000000 --- a/Data Structure/Linked List.cpp +++ /dev/null @@ -1,125 +0,0 @@ -#include -using namespace std; - -struct node -{ - int val; - node *next; -}; - -node *start; - -void insert(int x) -{ - node *t=start; - if (start!=NULL) - { - while(t->next!=NULL) - { - t=t->next; - } - node *n= new node; - t->next=n; - n->val=x; - n->next=NULL; - } - else - { - node *n= new node; - n->val=x; - n->next=NULL; - start=n; - } -} - -void remove(int x){ - - if( start == NULL ){ - cout<<"\nLinked List is empty\n"; - return ; - } - else if( start->val == x ){ - node *temp = start; - start = start->next; - delete temp; - return ; - } - - node *temp = start, *parent = start; - - while( temp != NULL && temp->val != x ){ - parent = temp; - temp = temp->next; - } - - if( temp == NULL ){ - cout <next = temp->next; - delete temp; -} - -void search(int x) -{ - node *t= start; - int found =0; - while(t!=NULL) - { - if(t->val==x) - { - cout<<"\nFound"; - found=1; - break; - } - t=t->next; - } - if(found==0) - { - cout<<"\nNot Found"; - } -} - -void show() -{ - node *t=start; - while(t!=NULL) - { - cout<val<<"\t"; - t=t->next; - } - -} - -int main() -{ - int choice, x; - do - { - cout<<"\n1. Insert"; - cout<<"\n2. Delete"; - cout<<"\n3. Search"; - cout<<"\n4. Print"; - cout<<"\n0. Exit"; - cout<<"\n\nEnter you choice : "; - cin>>choice; - switch (choice) - { - case 1 : cout<<"\nEnter the element to be inserted : "; - cin>>x;; - insert(x); break; - case 2 : cout<<"\nEnter the element to be removed : "; - cin>>x; - remove(x); break; - case 3 : cout<<"\nEnter the element to be searched : "; - cin>>x; - search(x); break; - case 4 : show(); - cout<<"\n"; break; - } - } - while(choice!=0); - - return 0; -} diff --git a/Data Structure/List Array.cpp b/Data Structure/List Array.cpp deleted file mode 100644 index 21f5c6ae53c..00000000000 --- a/Data Structure/List Array.cpp +++ /dev/null @@ -1,185 +0,0 @@ -#include -using namespace std; - -struct list -{ - int data[50]; - int top=0; - bool isSorted=false; - - int BinarySearch(int *array, int first, int last, int x) - { - if(lastarray[mid]) - return (BinarySearch(array, mid+1, last, x)); - } - - int LinarSearch(int *array, int x) - { - for (int i = 0; i < top; i++) - { - if (array[i]==x) - { - return i; - } - } - - return -1; - } - - int Search(int x) - { - int pos=-1; - - if (isSorted) - { - pos=BinarySearch(data, 0, top-1, x); - } - - else - { - pos=LinarSearch(data, x); - } - - if (pos!=-1) - { - cout<<"\nElement found at position : "< pos; i--) - { - data[i]=data[i-1]; - } - top++; - data[pos]=x; - } - } - - void Remove(int x) - { - int pos=Search(x); - cout<<"\n"<>choice; - switch (choice) - { - case 1: cout<<"\nEnter the element to be inserted : "; - cin>>x; - L.insert(x); - break; - case 2: cout<<"\nEnter the element to be removed : "; - cin>>x; - L.Remove(x); - break; - case 3: cout<<"\nEnter the element to be searched : "; - cin>>x; - L.Search(x); - break; - case 4: L.Sort(); - break; - case 5: L.Show(); - break; - } - } - while(choice!=0); - return 0; -} diff --git a/Data Structure/MorrisInorder.cpp b/Data Structure/MorrisInorder.cpp deleted file mode 100644 index 5ea630fac0a..00000000000 --- a/Data Structure/MorrisInorder.cpp +++ /dev/null @@ -1,94 +0,0 @@ -#include -#include - -/************************** - @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 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<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<data<<" "; - temp->right = NULL; - // current node is made to point its right subtree - curr = curr->right; - } - } - } -} - -int main() { - // Testing morrisInorder funtion - Btree *root = NULL; - int i; - for(i = 1 ; i <= 7 ; i++) - insert(&root, i); - cout<<"Morris Inorder: "; - morrisInorder(root); - return 0; -} diff --git a/Data Structure/Queue Using Array.cpp b/Data Structure/Queue Using Array.cpp deleted file mode 100644 index 7b5816f84b5..00000000000 --- a/Data Structure/Queue Using Array.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include -using namespace std; - -int queue[10]; -int front=0; -int rear=0; - -void Enque(int x) -{ - if(rear==10) - { - cout<<"\nOverflow"; - } - else - { - queue[rear++]=x; - } -} - -void Deque() -{ - if (front==rear) - { - cout<<"\nUnderflow"; - } - - else - { - cout<<"\n"<>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; -} - diff --git a/Data Structure/Queue Using Linked List.cpp b/Data Structure/Queue Using Linked List.cpp deleted file mode 100644 index acf32ebd503..00000000000 --- a/Data Structure/Queue Using Linked List.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include -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==front) - { - cout<<"\nUnderflow"; - } - else - { - node *t = front; - cout<<"\n"<val<<" deleted"; - front=front->next; - delete t; - } -} - -void show() -{ - node *t=front; - while(t!=NULL) - { - cout<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; -} - diff --git a/Data Structure/Stack Using Array.cpp b/Data Structure/Stack Using Array.cpp deleted file mode 100644 index c5ad146cb40..00000000000 --- a/Data Structure/Stack Using Array.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include -using namespace std; - -int *stack; -int top=0, size; - -void push(int x) -{ - if(top==size) - { - cout<<"\nOverflow"; - } - else - { - stack[top++]=x; - } -} - -void pop() -{ - if (top==0) - { - cout<<"\nUnderflow"; - } - else - { - cout<<"\n"<>size; - stack = new int[size]; - int ch, x; - do - { - cout<<"\n1. Push"; - cout<<"\n2. Pop"; - cout<<"\n3. Print"; - cout<<"\n4. Print topmost element:"; - cout<<"\nEnter Your Choice : "; - cin>>ch; - if (ch==1) - { - cout<<"\nInsert : "; - cin>>x; - push(x); - } - else if (ch==2) - { - pop(); - } - else if (ch==3) - { - show(); - } - else if(ch==4) - { - topmost(); - } - } - while(ch!=0); - - return 0; -} - diff --git a/Data Structure/Stack Using Linked List.cpp b/Data Structure/Stack Using Linked List.cpp deleted file mode 100644 index 753fda8ed9e..00000000000 --- a/Data Structure/Stack Using Linked List.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include -using namespace std; - -struct node -{ - int val; - node *next; -}; - - -node *top; - -void push(int x) -{ - node *n = new node; - n->val=x; - n->next=top; - top=n; -} - -void pop() -{ - if (top==NULL) - { - cout<<"\nUnderflow"; - } - else - { - node *t = top; - cout<<"\n"<val<<" deleted"; - top=top->next; - delete t; - } -} - -void show() -{ - node *t=top; - while(t!=NULL) - { - cout<val<<"\n"; - t=t->next; - } -} - -int main() -{ - int ch, x; - do - { - cout<<"\n1. Push"; - cout<<"\n2. Pop"; - cout<<"\n3. Print"; - cout<<"\nEnter Your Choice : "; - cin>>ch; - if (ch==1) - { - cout<<"\nInsert : "; - cin>>x; - push(x); - } - else if (ch==2) - { - pop(); - } - else if (ch==3) - { - show(); - } - } - while(ch!=0); - - return 0; -} - diff --git a/Data Structure/Tree.cpp b/Data Structure/Tree.cpp deleted file mode 100644 index 963779abe6a..00000000000 --- a/Data Structure/Tree.cpp +++ /dev/null @@ -1,160 +0,0 @@ -#include -using namespace std; - - -struct node -{ - int val; - node *left; - node *right; -}; - -struct queue -{ - node *t[100]; - int front; - int rear; -}; - -queue q; - - -void enqueue(node *n) -{ - q.t[q.rear++]=n; -} - -node * dequeue() -{ - return (q.t[q.front++]); -} - - - -void CreateTree(node *curr, node *n, int x, char pos) -{ - if(n!=NULL) - { - char ch; - cout<<"\nLeft or Right of "<val<<" : "; - cin>>ch; - if(ch=='l') - CreateTree(n, n->left, x, ch); - else if(ch=='r') - CreateTree(n, n->right, x, ch); - } - - else - { - node *t=new node; - t->val=x; - t->left=NULL; - t->right=NULL; - if (pos=='l') - { - curr->left=t; - } - else if(pos=='r') - { - curr->right=t; - } - } -} - - -void BFT(node *n) -{ - if(n!=NULL) - { - cout<val<<" "; - enqueue(n->left); - enqueue(n->right); - BFT(dequeue()); - } -} - -void Pre(node *n) -{ - if (n!=NULL) - { - cout<val<<" "; - Pre(n->left); - Pre(n->right); - } -} - -void In(node *n) -{ - if (n!=NULL) - { - In(n->left); - cout<val<<" "; - In(n->right); - } -} - - -void Post(node *n) -{ - if (n!=NULL) - { - Post(n->left); - Post(n->right); - cout<val<<" "; - } -} - - - -int main() -{ - q.front=0; - q.rear=0; - int value; - int ch; - node *root=new node; - cout<<"\nEnter the value of root node :"; - cin>>value; - root->val=value; - root->left=NULL; - root->right=NULL; - do - { - cout<<"\n1. Insert : "; - cout<<"\n2. Breadth First"; - cout<<"\n3. Preorder Depth First"; - cout<<"\n4. Inorder Depth First"; - cout<<"\n5. Postorder Depth First"; - - cout<<"\nEnter Your Choice : "; - cin>>ch; - switch(ch) - { - case 1: - int x; - char pos; - cout<<"\nEnter the value to be Inserted : "; - cin>>x; - cout<<"\nLeft or Right of Root : "; - cin>>pos; - if(pos=='l') - CreateTree(root, root->left, x, pos); - else if(pos=='r') - CreateTree(root, root->right, x, pos); - break; - case 2: - BFT(root); - break; - case 3: - Pre(root); - break; - case 4: - In(root); - break; - case 5: - Post(root); - break; - } - } - while(ch!=0); -} diff --git a/Data Structure/TrieTree.cpp b/Data Structure/TrieTree.cpp deleted file mode 100644 index 866087d8734..00000000000 --- a/Data Structure/TrieTree.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include -#include -#include -using namespace std; -// structure definition -typedef struct trie -{ - struct trie *arr[26]; - bool isEndofWord; -} trie; -// create a new node for trie -trie *createNode() -{ - trie *nn = new trie(); - for (int i = 0; i < 26; i++) - nn->arr[i] = NULL; - nn->isEndofWord = false; - return nn; -} - -// insert string into the trie -void insert(trie *root, char* str) -{ - for (int i = 0; i < strlen(str); i++) - { - int j = str[i] - 'a'; - if (root->arr[j]) - { - root = root->arr[j]; - } - else - { - root->arr[j] = createNode(); - root = root->arr[j]; - } - } - root->isEndofWord = true; -} - -// search a string exists inside the trie -bool search(trie *root, char* str, int index) -{ - if (index == strlen(str)) - { - if (!root->isEndofWord) - return false; - return true; - } - int j = str[index] - 'a'; - if (!root->arr[j]) - return false; - return search(root->arr[j], str, index + 1); -} -/* removes the string if it is not a prefix of any other - string, if it is then just sets the endofword to false, else - removes the given string*/ -bool deleteString (trie *root, char* str, int index) -{ - if (index == strlen(str)) - { - if (!root->isEndofWord) - return false; - root->isEndofWord = false; - for (int i = 0; i < 26; i++) - return false; - return true; - } - int j = str[index] - 'a'; - if (!root->arr[j]) - return false; - bool var = deleteString (root, str, index + 1); - if (var) - { - root->arr[j] = NULL; - if (root->isEndofWord) - return false; - else - { - int i; - for (i = 0; i < 26; i++) - if (root->arr[i]) - return false; - return true; - } - } -} - -int main() -{ - trie *root = createNode(); - insert(root, "hello"); - insert(root, "world"); - int a = search(root, "hello", 0); - int b = search(root, "word", 0); - printf("%d %d ", a, b); - return 0; -} \ No newline at end of file diff --git a/Data Structure/circular_Queue_using_Linked_List.cpp b/Data Structure/circular_Queue_using_Linked_List.cpp deleted file mode 100644 index bf700ae8b9a..00000000000 --- a/Data Structure/circular_Queue_using_Linked_List.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include -using namespace std; - -struct node{ - int data; - struct node *next; -}; -class Queue{ - node *front; - node *rear; -public: - Queue(){ - front = NULL; - rear = NULL; - } - void createNode(int val){ - node *ptr; - node *nn; - nn = new node; - ptr = front; - nn->data = val; - nn->next = NULL; - front=nn; - rear=nn; - } - void enqueue(int val){ - if(front==NULL || rear==NULL){ - createNode(val); - } - else{ - node *ptr; - node *nn; - ptr=front; - nn = new node; - nn->data = val; - rear->next = nn; - nn->next = front; - rear = nn; - } - } - void dequeue(){ - node *n; - n = front; - front = front->next; - delete(n); - } - void traverse(){ - node *ptr; - ptr=front; - do{ - cout<data<<" "; - ptr=ptr->next; - }while(ptr!=rear->next); - cout<data; - cout< -using namespace std; -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. - -} - -int getnode() //This will return the index of the first free node present in the avail list -{ - int NodeIndexToBeReturned=avail; - avail=AvailArray[avail].next; - return NodeIndexToBeReturned; -} - -void freeNode(int nodeToBeDeleted) //This function when called will delete the node with the index presented as an argument, and will put back that node into the array. -{ - AvailArray[nodeToBeDeleted].next=avail; - avail=nodeToBeDeleted; -} - -void insertAtTheBeginning(int data) //The function will insert the given data into the front of the linked list. -{ - 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) - { - cout<"; - temp=AvailArray[temp].next; - } - cout<<"-1"<>z; - switch(z) - { - case 1: - cout<<"Enter the number you want to enter"<>x; - insertAtTheBeginning(x); - break; - case 2: - cout<<"Enter the number you want to enter"<>y; - insertAtTheEnd(y); - break; - case 3: - cout<<"The linked list contains the following element in order"< -#include -using namespace std; - -//void Print(int res[20][20], int i, int j, int capacity) -//{ -// if(i==0 || j==0) -// { -// return; -// } -// if(res[i-1][j]==res[i][j-1]) -// { -// if(i<=capacity) -// { -// cout<res[i][j-1]) -// { -// Print(res, i-1,j, capacity); -// } -// else if(res[i][j-1]>res[i-1][j]) -// { -// Print(res, i,j-1, capacity); -// } -//} - -int Knapsack(int capacity,int n,int weight[],int value[]){ - int res[20][20]; - for (int i = 0; i < n+1; ++i) - { - for (int j = 0; j < capacity+1; ++j) - { - if(i==0||j==0) - res[i][j] = 0; - else if(weight[i-1]<=j) - res[i][j] = max(value[i-1]+res[i-1][j-weight[i-1]], res[i-1][j]); - else - res[i][j] = res[i-1][j]; - } - } -// Print(res, n, capacity, capacity); -// cout<<"\n"; - return res[n][capacity]; -} -int main() -{ - int n; - cout<<"Enter number of items: "; - cin>>n; - int weight[n], value[n]; - cout<<"Enter weights: "; - for (int i = 0; i < n; ++i) - { - cin>>weight[i]; - } - cout<<"Enter values: "; - for (int i = 0; i < n; ++i) - { - cin>>value[i]; - } - int capacity; - cout<<"Enter capacity: "; - cin>>capacity; - cout< -#include -int main() -{ - int n,k,d,s=0; - cout<<"Enter a number:"; - cin>>n; - k=n; - while(k!=0) - { - d=k%10; - s+=(int)pow(d,3); - k/=10; - } - if(s==n) - cout< -#include - -using namespace std; - -//Wrapper class for storing an edge -class Edge{ - public: int src,dst,weight; -}; - -//Wrapper class for storing a graph -class Graph{ - public: - int vertexNum,edgeNum; - Edge* edges; - - //Constructs a graph with V vertices and E edges - Graph(int V,int E){ - this->vertexNum = V; - this->edgeNum = E; - this->edges =(Edge*) malloc(E * sizeof(Edge)); - } - - //Adds the given edge to the graph - void addEdge(int src, int dst, int weight){ - static int edgeInd = 0; - if(edgeInd < this->edgeNum){ - Edge newEdge; - newEdge.src = src; - newEdge.dst = dst; - newEdge.weight = weight; - this->edges[edgeInd++] = newEdge; - } - - } - -}; - -//Utility function to print distances -void print(int dist[], int V){ - cout<<"\nVertex Distance"<>V; - cout<<"Enter number of edges: "; - cin>>E; - Graph G(V,E); - for(int i=0; i>src; - cout<<"Enter destination: "; - cin>>dst; - cout<<"Enter weight: "; - cin>>weight; - G.addEdge(src, dst, weight); - } - cout<<"\nEnter source: "; - cin>>gsrc; - BellmanFord(G,gsrc); - - return 0; -} diff --git a/Dynamic Programming/Catalan-Numbers.cpp b/Dynamic Programming/Catalan-Numbers.cpp deleted file mode 100644 index a086ae6c181..00000000000 --- a/Dynamic Programming/Catalan-Numbers.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/** Print all the Catalan numbers from 0 to n, n being the user input. - - * A Catalan number satifies the following two properties: - * C(0) = C(1) = 1; C(n) = sum(C(i).C(n-i-1)), from i = 0 to n-1 - * Read more about Catalan numbers here: - https://en.wikipedia.org/wiki/Catalan_number - */ - -#include -using namespace std; - -int *cat; // global array to hold catalan numbers - -unsigned long int catalan_dp(int n) -{ - /** Using the tabulation technique in dynamic programming, - this function computes the first `n+1` Catalan numbers - - Parameter - --------- - n: The number of catalan numbers to be computed. - - Returns - ------- - cat[n]: An array containing the first `n+1` Catalan numbers - */ - - // By definition, the first two Catalan numbers are 1 - cat[0] = cat[1] = 1; - - // Compute the remaining numbers from index 2 to index n, using tabulation - for (int i = 2; i <= n; i++) - { - cat[i] = 0; - for (int j = 0; j < i; j++) - cat[i] += cat[j] * cat[i-j-1]; // applying the definition here - } - - // Return the result - return cat[n]; -} - -int main(int argc, char *argv[]) -{ - int n; - cout << "Enter n: "; - cin >> n; - - cat = new int[n+1]; - - cout << "Catalan numbers from 0 to " << n << " are:\n"; - for (int i = 0; i <= n; i++) - { - cout << "catalan (" << i << ") = " << catalan_dp(i) << endl; - // NOTE: Since `cat` is a global array, calling `catalan_dp` - // repeatedly will not recompute the the values already computed - // as in case of pre-computed values, the array will simply return them, - // instead of recomputing them. - } - - return 0; -} - -/** Sample Test Case: - -$ cd "Dynamic Programming" -$ g++ Catalan-Numbers.cpp -$ ./a.exe - -Enter n: 5 -Catalan numbers from 0 to 5 are: -catalan (0) = 1 -catalan (1) = 1 -catalan (2) = 2 -catalan (3) = 5 -catalan (4) = 14 -catalan (5) = 42 - -*/ diff --git a/Dynamic Programming/Cut Rod.cpp b/Dynamic Programming/Cut Rod.cpp deleted file mode 100644 index 90e12a53242..00000000000 --- a/Dynamic Programming/Cut Rod.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/*Given a rod of length n inches and an array of prices that -contains prices of all pieces of size smaller than n. Determine -the maximum value obtainable by cutting up the rod and selling -the pieces.*/ - -#include -using namespace std; -int cutrod(int p[],int n) -{ - int r[n+1]; - r[0]=0; - for(int j=0;j -#include -using namespace std; - -int min(int x, int y, int z){ - return min(min(x,y), z); -} - -/* A Naive recursive C++ program to find - * minimum number of operations to convert - * str1 to str2. - * O(3^m) - */ -int editDist(string str1, string str2, int m, int n) { - if(m == 0) return n; - if(n == 0) return m; - - //If last characters are same then continue - //for the rest of them. - if(str1[m-1] == str2[n-1]) - return editDist(str1, str2, m-1, n-1); - - //If last not same, then 3 possibilities - //a.Insert b.Remove c. Replace - //Get min of three and continue for rest. - return 1 + min ( editDist(str1, str2, m, n-1), - editDist(str1, str2, m-1, n), - editDist(str1, str2, m-1, n-1) - ); -} - -/* A DP based program - * O(m x n) - */ -int editDistDP(string str1, string str2, int m, int n) { - - //Create Table for SubProblems - int dp[m+1][n+1]; - - //Fill d[][] in bottom up manner - for(int i=0; i<=m; i++) { - for(int j=0; j<=n; j++) { - //If str1 empty. Then add all of str2 - if(i==0) - dp[i][j] = j; - - //If str2 empty. Then add all of str1 - else if(j==0) - dp[i][j] = i; - - //If character same. Recur for remaining - else if(str1[i-1] == str2[j-1]) - dp[i][j] = dp[i-1][j-1]; - - else - dp[i][j] = 1 + min(dp[i][j-1],//Insert - dp[i-1][j],//Remove - dp[i-1][j-1]//Replace - ); - } - } - - return dp[m][n]; -} - -int main() { - string str1 = "sunday"; - string str2 = "saturday"; - - cout << editDist(str1, str2, str1.length(), str2.length()) << endl; - cout << editDistDP(str1, str2, str1.length(), str2.length()) << endl; - - return 0; -} diff --git a/Dynamic Programming/Fibonacci_Bottom_Up.cpp b/Dynamic Programming/Fibonacci_Bottom_Up.cpp deleted file mode 100644 index cbd0912e8fe..00000000000 --- a/Dynamic Programming/Fibonacci_Bottom_Up.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include -using namespace std; -int fib(int n){ - int res[n+1]; - res[0] = 0; res[1] = 1; - for(int i=2;i<=n;i++){ - res[i] = res[i-1] + res[i-2]; - } - return res[n]; -} -int main(int argc, char const *argv[]) -{ - int n; - cout<<"Enter n: "; - cin>>n; - cout<<"Fibonacci number is "; - cout< -using namespace std; -int arr[1000000]; -int fib(int n){ - if(arr[n]==-1){ - if(n<=1) - arr[n] = n; - else - arr[n] = fib(n-1) + fib(n-2); - } - return arr[n]; -} -int main(int argc, char const *argv[]) -{ - int n; - cout<<"Enter n: "; - cin>>n; - for (int i = 0; i < n+1; ++i) - { - arr[i] = -1; - } - cout<<"Fibonacci number is "< -#include -#include - -using namespace std; - -//Wrapper class for storing a graph -class Graph{ - public: - int vertexNum; - int** edges; - - //Constructs a graph with V vertices and E edges - Graph(int V){ - this->vertexNum = V; - this->edges =(int**) malloc(V * sizeof(int*)); - for(int i=0; iedges[i] = (int*) malloc(V * sizeof(int)); - for(int j=0; jedges[i][j] = INT_MAX; - this->edges[i][i] = 0; - } - } - - //Adds the given edge to the graph - void addEdge(int src, int dst, int weight){ - this->edges[src][dst] = weight; - } - - -}; - - -//Utility function to print distances -void print(int dist[], int V){ - cout<<"\nThe Distance matrix for Floyd - Warshall"<>V; - cout<<"Enter number of edges: "; - cin>>E; - Graph G(V); - for(int i=0; i>src; - cout<<"Enter destination: "; - cin>>dst; - cout<<"Enter weight: "; - cin>>weight; - G.addEdge(src, dst, weight); - } - FloydWarshall(G); - - return 0; -} diff --git a/Dynamic Programming/Longest Common Subsequence.cpp b/Dynamic Programming/Longest Common Subsequence.cpp deleted file mode 100644 index aba1eeb5478..00000000000 --- a/Dynamic Programming/Longest Common Subsequence.cpp +++ /dev/null @@ -1,87 +0,0 @@ -//Longest common subsequence - Dynamic Programming -#include -using namespace std; - -void Print(int trace[20][20], int m, int n, string a) -{ - if (m==0 || n==0) - { - return; - } - if (trace[m][n]==1) - { - Print(trace, m-1, n-1, a); - cout<res[i][j-1]) - { - res[i][j]=res[i-1][j]; - trace[i][j]=2; // 2 means trace the matrix in upwards direction. - } - else - { - res[i][j]=res[i][j-1]; - trace[i][j]=3; // means trace the matrix in left direction. - } - } - } - } - Print(trace, m, n, a); - return res[m][n]; -} - - - - -int main() -{ - string a,b; - cin>>a>>b; - cout< -using namespace std; -int LIS(int a[],int n){ - int lis[n]; - for (int i = 0; i < n; ++i) - { - lis[i] = 1; - } - for (int i = 0; i < n; ++i) - { - for (int j = 0; j < i; ++j) - { - if(a[i]>a[j] && lis[i]>n; - int a[n]; - cout<<"Enter array elements: "; - for (int i = 0; i < n; ++i) - { - cin>>a[i]; - } - cout< -using namespace std; -class graph{ - int v; - list *adj; - public: - graph(int v); - void addedge(int src,int dest); - void printgraph(); - void bfs(int s); -}; -graph::graph(int v){ - this->v = v; - this->adj = new list[v]; -} -void graph::addedge(int src,int dest){ - src--;dest--; - adj[src].push_back(dest); - //adj[dest].push_back(src); -} -void graph::printgraph(){ - for(int i=0;iv;i++){ - cout<<"Adjacency list of vertex "<::iterator it; - for(it=adj[i].begin();it!=adj[i].end();++it){ - cout<<*it+1<<" "; - } - cout<v+1]; - memset(visited,false,sizeof(bool)*(this->v+1)); - visited[s]=true; - list q; - q.push_back(s); - list::iterator it; - while(!q.empty()){ - int u = q.front(); - cout< -using namespace std; -int v = 4; -void DFSUtil_(int graph[4][4],bool visited[],int s){ - visited[s] = true; - cout< -#include -#include - - -#define WHITE 0 -#define GREY 1 -#define BLACK 2 -#define INF 99999 - -using namespace std; - -int checked[999] = {WHITE}; - -void dfs(const list lista[], int start) { - stack stack; - - int checked[999] = {WHITE}; - - stack.push(start); - - checked[start] = GREY; - while(!stack.empty()) { - int act = stack.top(); - stack.pop(); - - if(checked[act] == GREY) { - cout << act << ' '; - for(auto it = lista[act].begin(); it != lista[act].end(); ++it) { - stack.push(*it); - if(checked[*it] != BLACK) - checked[*it] = GREY; - } - checked[act] = BLACK; //nodo controllato - } - } -} - -int main() { - int u, w; - int n; - cin >> n; - list lista[INF]; - for(int i = 0; i < n; ++i) { - cin >> u >> w; - lista[u].push_back(w); - } - - dfs(lista, 0); - - - return 0; -} diff --git a/Graph/Dijkstra.cpp b/Graph/Dijkstra.cpp deleted file mode 100644 index c395cd52745..00000000000 --- a/Graph/Dijkstra.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include -#include -using namespace std; -#define INF 10000010 -vector < pair > graph[5*100001]; -int dis[5*100001]; -int dij(vector > * v,int s,int * dis) { - priority_queue < pair , vector < pair >,greater < pair > > pq; - // source distance to zero. - pq.push(make_pair(0,s)); - dis[s] = 0; - int u; - while(!pq.empty()) { - u = (pq.top()).second; - pq.pop(); - for( vector > :: iterator it = v[u].begin(); it != v[u].end();it++) { - if(dis[u] + it->first < dis[it->second]) { - dis[it->second] = dis[u] + it->first; - pq.push(make_pair(dis[it->second],it->second)); - } - } - } -} -int main() { - int m,n,l,x,y,s; - // n--> number of nodes , m --> number of edges - cin>>n>>m; - for(int i = 0;i < m;i++) { - // input edges. - scanf("%d%d%d",&x,&y,&l); - graph[x].push_back(make_pair(l,y)); - graph[y].push_back(make_pair(l,x)); // comment this line for directed graph - } - // start node. - scanf("%d",&s); - // intialise all distances to infinity. - for(int i = 1;i <= n;i++) - dis[i] = INF; - dij(graph,s,dis); - - for(int i = 1;i <= n;i++) - if(dis[i] == INF) - cout<<"-1 "; - else - cout< -//using namespace boost::multiprecision; -const int mx = 1e6+5; -const long int inf = 2e9; -typedef long long ll; -#define rep(i,n) for(i=0;i -#define vpii vector< pii > -#define vi vector -#define vll vector -#define r(x) scanf("%d",&x) -#define rs(s) scanf("%s",s) -#define gc getchar_unlocked -#define pc putchar_unlocked -#define mp make_pair -#define pb push_back -#define lb lower_bound -#define ub upper_bound -#define endl "\n" -#define fast ios_base::sync_with_stdio(false); cin.tie(NULL); cout.tie(NULL); -using namespace std; -void in(int &x) -{ - register int c = gc(); x = 0; int neg = 0; - for(;((c<48 || c>57) && c != '-');c = gc());if(c=='-') {neg=1;c=gc();} for(;c>47 && c<58;c = gc()) {x = (x<<1) + (x<<3) + c - 48;} - if(neg) x=-x; -} -void out (int n) { int N = n, rev, count = 0;rev = N; if (N == 0) { pc('0'); return ;} while ((rev % 10) == 0) { count++; rev /= 10;} rev = 0;while (N != 0) { rev = (rev<<3) + (rev<<1) + N % 10; N /= 10;}while (rev != 0) { pc(rev % 10 + '0'); rev /= 10;} -while (count--) pc('0'); -} -ll parent[mx],arr[mx],node,edge; -vector>>v; -void initial() -{ - int i; - rep(i,node+edge) - parent[i] = i; -} -int root(int i) -{ - while(parent[i] != i) - { - parent[i] = parent[parent[i]]; - i = parent[i]; - } - return i; -} -void join(int x,int y) -{ - int root_x = root(x); //Disjoint set union by rank - int root_y = root(y); - parent[root_x] = root_y; -} -ll kruskal() -{ - ll mincost=0,i,x,y; - rep(i,edge) - { - x = v[i].second.first; - y = v[i].second.second; - if(root(x) != root(y)) - { - mincost += v[i].first; - join(x,y); - } - } - return mincost; -} -int main(){ - fast; - while(1) - { - int i,j,from,to,cost,totalcost=0; - cin>>node>>edge; //Enter the nodes and edges - if(node==0 && edge==0) break; //Enter 0 0 to break out - initial(); //Initialise the parent array - rep(i,edge) - { - cin>>from>>to>>cost; - v.pb(mp(cost,mp(from,to))); - totalcost += cost; - } - sort(v.begin(),v.end()); - // rep(i,v.size()) - // cout< -#include -#include - using namespace std; - -int n , m; // For number of Vertices (V) and number of edges (E) -vector< vector > G; -vector visited; -vector ans; - -void dfs(int v) { - visited[v] = true; - for (int u : G[v]) { - if (!visited[u]) - dfs(u); - } - ans.push_back(v); -} - -void topological_sort() { - visited.assign(n, false); - ans.clear(); - for (int i = 0; i < n; ++i) { - if (!visited[i]) - dfs(i); - } - reverse(ans.begin(), ans.end()); -} -int main(){ - cout << "Enter the number of vertices and the number of directed edges\n"; - cin >> n >> m; - int x , y; - G.resize(n , vector()); - for(int i = 0 ; i < n ; ++i) { - cin >> x >> y; - x-- , y--; // to convert 1-indexed to 0-indexed - G[x].push_back(y); - } - topological_sort(); - cout << "Topological Order : \n"; - for(int v : ans) { - cout << v + 1 << ' '; // converting zero based indexing back to one based. - } - cout << '\n'; - return 0; -} diff --git a/Greedy Algorithms/.DS_Store b/Greedy Algorithms/.DS_Store deleted file mode 100644 index 20f69ade7c9..00000000000 Binary files a/Greedy Algorithms/.DS_Store and /dev/null differ diff --git a/Greedy Algorithms/Dijkstra.cpp b/Greedy Algorithms/Dijkstra.cpp deleted file mode 100644 index 05191a27955..00000000000 --- a/Greedy Algorithms/Dijkstra.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include -#include - -using namespace std; - -//Wrapper class for storing a graph -class Graph -{ -public: - int vertexNum; - int **edges; - - //Constructs a graph with V vertices and E edges - Graph(const int V) - { - - // initializes the array edges. - this->edges = new int*[V]; - for (int i = 0; i < V; i++) - { - edges[i] = new int[V]; - } - - // fills the array with zeros. - for (int i = 0; i < V; i++) - { - for (int j = 0; j < V; j++) - { - edges[i][j] = 0; - } - } - - this->vertexNum = V; - - } - - //Adds the given edge to the graph - void addEdge(int src, int dst, int weight) - { - this->edges[src][dst] = weight; - } - - -}; -//Utility function to find minimum distance vertex in mdist -int minDistance(int mdist[], bool vset[], int V) -{ - int minVal = INT_MAX, minInd = 0; - for(int i=0; i>V; - cout<<"Enter number of edges: "; - cin>>E; - Graph G(V); - for(int i=0; i>src; - cout<<"Enter destination: "; - cin>>dst; - cout<<"Enter weight: "; - cin>>weight; - - // makes sure source and destionation are in the proper bounds. - if (src >= 0 && src < V && dst >= 0 && dst < V) - { - G.addEdge(src, dst, weight); - } - else - { - cout << "source and/or destination out of bounds" << endl; - i--; - continue; - } - } - cout<<"\nEnter source:"; - cin>>gsrc; - Dijkstra(G,gsrc); - - return 0; -} diff --git a/Greedy Algorithms/Knapsack.cpp b/Greedy Algorithms/Knapsack.cpp deleted file mode 100644 index 41ce4cc9b31..00000000000 --- a/Greedy Algorithms/Knapsack.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include -using namespace std; - -struct Item -{ - int weight; - int profit; -}; - - -float profitPerUnit(Item x) -{ - return (float)x.profit/(float)x.weight; -} - -int partition (Item arr[], int low, int high) -{ - Item pivot = arr[high]; // pivot - int i = (low - 1); // Index of smaller element - - for (int j = low; j >capacity; - cout<<"\n Enter the number of Items : "; - int n; - cin>>n; - Item itemArray[n]; - for (int i = 0; i < n; i++) - { - cout<<"\nEnter the weight and profit of item "<>itemArray[i].weight; - cin>>itemArray[i].profit; - } - - quickSort(itemArray, 0, n-1); - - // show(itemArray, n); - - float maxProfit=0; - int i=n; - while(capacity>0 && --i>=0) - { - if(capacity>=itemArray[i].weight) - { - maxProfit+=itemArray[i].profit; - capacity-=itemArray[i].weight; - cout<<"\n\t"< -using namespace std; - -#define V 6 -#define INFINITY 99999 - -int graph[V][V] ={ - {0, 4, 1, 4, INFINITY, INFINITY}, - {4, 0, 3, 8, 3, INFINITY}, - {1, 3, 0, INFINITY, 1, INFINITY}, - {4, 8, INFINITY, 0, 5, 7}, - {INFINITY, 3, 1, 5, 0, INFINITY}, - {INFINITY, INFINITY, INFINITY, 7, INFINITY, 0} -}; - - -void findMinimumEdge() -{ - for (int i = 0; i < V; i++) - { - int min=INFINITY; - int minIndex=0; - for (int j = 0; j < V; j++) - { - if(graph[i][j]!=0 && graph[i][j] -using namespace std; - -#define V 4 -#define INFINITY 99999 - -int graph[V][V] = { - {0, 5, 1, 2}, - {5, 0, 3, 3}, - {1, 3, 0, 4}, - {2, 3, 4, 0} -}; - - -struct mst -{ - bool visited; - int key; - int near; -}; - -mst MST_Array[V]; - -void initilize() -{ - for (int i = 0; i < V; i++) - { - MST_Array[i].visited=false; - MST_Array[i].key=INFINITY; // considering INFINITY as inifinity - MST_Array[i].near=i; - } - - MST_Array[0].key=0; -} - -void updateNear() -{ - for (int v = 0; v < V; v++) - { - int min=INFINITY; - int minIndex=0; - for (int i = 0; i < V; i++) - { - if (MST_Array[i].key -#include -using namespace std; - -struct Node { - int data; - struct Node *next; -} *head[100],*curr; - -void init() { - for(int i=0;i<100;i++) - head[i]=NULL; -} - -void add(int x,int h) { - struct Node *temp = new Node; - temp->data = x; - temp->next = NULL; - if(!head[h]) { - head[h] = temp; - curr = head[h]; - } - else { - curr=head[h]; - while(curr->next) - curr = curr->next; - curr->next = temp; - } -} - -void display(int mod) { - struct Node *temp; - int i; - for(i=0;inext; - } - cout<data; - cout<data !=x && temp->next) - temp=temp->next; - if(temp->next) - cout<<"Element found"; - else{ - if(temp->data == x) - cout<<"Element found"; - else - cout<< "Element not found"; - } -} - -int main(void) { - init(); - int c,x,mod,h; - cout<<"Enter the size of Hash Table. = "; - cin>>mod; - bool loop = true; - while(loop) { - cout<>c; - switch(c) { - case 1: - cout<<"Enter element to add = "; - cin>>x; - h = hash(x,mod); - h = fabs(h); - add(x,h); - break; - case 2: - cout<<"Enter element to search = "; - cin>>x; - h = hash(x,mod); - find(x,h); - break; - case 3: - cout<<"Enter element to generate hash = "; - cin>>x; - cout<<"Hash of "< -using namespace std; - -// Maximum number of digits in output -// x^n where 1 <= x, n <= 10000 and overflow may happen -#define MAX 100000 - -// This function multiplies x -// with the number represented by res[]. -// res_size is size of res[] or -// number of digits in the number -// represented by res[]. This function -// uses simple school mathematics -// for multiplication. -// This function may value of res_size -// and returns the new value of res_size -int multiply(int x, int res[], int res_size) { - - // Initialize carry - int carry = 0; - - // One by one multiply n with - // individual digits of res[] - for (int i = 0; i < res_size; i++) { - int prod = res[i] * x + carry; - - // Store last digit of - // 'prod' in res[] - res[i] = prod % 10; - - // Put rest in carry - carry = prod / 10; - } - - // Put carry in res and - // increase result size - while (carry) { - res[res_size] = carry % 10; - carry = carry / 10; - res_size++; - } - return res_size; -} - -// This function finds -// power of a number x -void power(int x, int n) -{ - - //printing value "1" for power = 0 - if(n == 0 ){ - cout<<"1"; - return; - } - - - int res[MAX]; - int res_size = 0; - int temp = x; - - // Initialize result - while (temp != 0) { - res[res_size++] = temp % 10; - temp = temp / 10; - } - - // Multiply x n times - // (x^n = x*x*x....n times) - for (int i = 2; i <= n; i++) - res_size = multiply(x, res, res_size); - - cout << x << "^" << n << " = "; - for (int i = res_size - 1; i >= 0; i--) - cout << res[i]; -} - -// Driver program -int main() { - int exponent, base; - printf("Enter base "); - scanf("%id \n", &base); - printf("Enter exponent "); - scanf("%id", &exponent); - power(base, exponent); - return 0; -} diff --git a/Math/Prime_Factorization/primefactorization.cpp b/Math/Prime_Factorization/primefactorization.cpp deleted file mode 100644 index b903a166a62..00000000000 --- a/Math/Prime_Factorization/primefactorization.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include -#include -#include -using namespace std; - -// Declaring variables for maintaing prime numbers and to check whether a number is prime or not -bool isprime[1000006]; -vector prime_numbers; -vector > factors; - -// Calculating prime number upto a given range -void SieveOfEratosthenes(int N) -{ - // initializes the array isprime - memset(isprime, true, sizeof isprime); - - for(int i=2; i<=N ; i++) - { - if(isprime[i]) - { - for(int j=2*i; j<=N; j+=i) - isprime[j]=false; - } - } - - for(int i=2; i<=N; i++) - { - if(isprime[i]) - prime_numbers.push_back(i); - } - -} - -// Prime factorization of a number -void prime_factorization(int num) -{ - - int number = num; - - for(int i=0; prime_numbers[i]<=num; i++) - { - int count=0; - - // termination condition - if (number == 1) - { - break; - } - - while(number%prime_numbers[i] == 0) - { - count++; - number = number/prime_numbers[i]; - } - - if(count) - factors.push_back(make_pair(prime_numbers[i],count)); - } - - -} - -/* - I added a simple UI. -*/ -int main() -{ - int num; - cout << "\t\tComputes the prime factorization\n\n"; - cout << "Type in a number: "; - cin>>num; - - SieveOfEratosthenes(num); - - prime_factorization(num); - - // Prime factors with their powers in the given number in new line - for(auto it: factors) - { - cout< -using namespace std; - -#define MAX 10000000 - -int isprime[MAX]; - -/* - * This is the function that finds the primes and eliminates - * the multiples. - */ -void sieve(int N) { - isprime[0] = 0; - isprime[1] = 0; - for (int i = 2; i <= N; i++) { - if (isprime[i]) { - for (int j = i * 2; j <= N; j += i) { - isprime[j] = 0; - } - } - } -} - -/* - * This function prints out the primes to STDOUT - */ -void print(int N) { - for (int i = 1; i <= N; i++) { - if (isprime[i] == 1) { - cout << i << ' '; - } - } - cout << '\n'; -} - -/* - * NOTE: This function is important for the - * initialization of the array. - */ -void init() { - for (int i = 1; i < MAX; i++) { - isprime[i] = 1; - } -} - -int main() { - int N = 100; - init(); - sieve(N); - print(N); -} diff --git a/Operations on Datastructures/Array Left Rotation.cpp b/Operations on Datastructures/Array Left Rotation.cpp deleted file mode 100644 index 177dada01bf..00000000000 --- a/Operations on Datastructures/Array Left Rotation.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include -using namespace std; -int main(){ - int n,k; - cout<<"Enter size of array=\t"; - cin>>n; - cout<<"Enter Number of indeces u want to rotate the array to left=\t"; - cin>>k; - int a[n]; - cout<<"Enter elements of array=\t"; - for(int i=0;i>a[i]; - } - int temp=0; - for(int i=0;i -using namespace std; -int main(){ - int n,k; - cout<<"Enter size of array=\t"; - cin>>n; - cout<<"Enter Number of indices u want to rotate the array to right=\t"; -cin>>k; -int a[n]; -cout<<"Enter elements of array=\t"; - for(int i=0;i>a[i]; - int temp=0; - for(int i=0;i=0;j--){ - if(j==0){ - a[j]=temp; - } - else{ - a[j]=a[j-1];} - - } - - } - cout<<"Your rotated array is=\t"; - for(int i=0;i -using namespace std; - -struct node -{ - int val; - node *next; -}; - -node *start; - -void insert(int x) -{ - node *t=start; - - if (start!=NULL) - { - while(t->next!=start) - { - t=t->next; - } - node *n= new node; - t->next=n; - n->val=x; - n->next=start; - } - else - { - node *n= new node; - n->val=x; - start=n; - n->next=start; - } -} - -void remove(int x) -{ - node *t=start; - node *p; - while(t->val!=x) - { - p=t; - t=t->next; - } - p->next=t->next; - delete t; -} - -void search(int x) -{ - node *t= start; - int found =0; - while(t->next!=start) - { - if(t->val==x) - { - cout<<"\nFound"; - found=1; - break; - } - t=t->next; - } - if(found==0) - { - cout<<"\nNot Found"; - } -} - -void show() -{ - node *t=start; - do - { - cout<val<<"\t"; - t=t->next; - } - while(t!=start); - -} - -int main() -{ - int choice, x; - do - { - cout<<"\n1. Insert"; - cout<<"\n2. Delete"; - cout<<"\n3. Search"; - cout<<"\n4. Print"; - cout<<"\n\nEnter you choice : "; - cin>>choice; - switch (choice) - { - case 1 : cout<<"\nEnter the element to be inserted : "; - cin>>x; - insert(x); break; - case 2 : cout<<"\nEnter the element to be removed : "; - cin>>x; - remove(x); break; - case 3 : cout<<"\nEnter the element to be searched : "; - cin>>x; - search(x); break; - case 4 : show(); break; - } - } - while(choice!=0); - - return 0; -} diff --git a/Operations on Datastructures/Circular Queue Using Array.cpp b/Operations on Datastructures/Circular Queue Using Array.cpp deleted file mode 100644 index d91f31af3dc..00000000000 --- a/Operations on Datastructures/Circular Queue Using Array.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include -using namespace std; - -int queue[10]; -int front=0; -int rear=0; -int count=0; - -void Enque(int x) -{ - if(count==10) - { - cout<<"\nOverflow"; - } - else - { - queue[rear]=x; - rear=(rear+1)%10; - count++; - } -} - -void Deque() -{ - if (front==rear) - { - cout<<"\nUnderflow"; - } - - else - { - cout<<"\n"<>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; -} - diff --git a/Operations on Datastructures/Intersection_of_2_arrays.cpp b/Operations on Datastructures/Intersection_of_2_arrays.cpp deleted file mode 100644 index e2c064e1ba1..00000000000 --- a/Operations on Datastructures/Intersection_of_2_arrays.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include -int main() -{ - int i,j,m,n; - cout <<"Enter size of array 1:"; - cin >> m; - cout <<"Enter size of array 2:"; - cin >> n; - int a[m]; - int b[n]; - cout <<"Enter elements of array 1:"; - for(i=0;i> a[i]; - for(i=0;i> b[i]; - i=0;j=0; - while((ib[j]) - j++; - else - { - cout << a[i++]<<" "; - j++; - } - } - return 0; -} diff --git a/Operations on Datastructures/Reverse a Linked List using Recusion.cpp b/Operations on Datastructures/Reverse a Linked List using Recusion.cpp deleted file mode 100644 index daefa18e85a..00000000000 --- a/Operations on Datastructures/Reverse a Linked List using Recusion.cpp +++ /dev/null @@ -1,80 +0,0 @@ -#include -using namespace std; - -struct node -{ - int val; - node *next; -}; - -node *start; - -void insert(int x) -{ - node *t=start; - if (start!=NULL) - { - while(t->next!=NULL) - { - t=t->next; - } - node *n= new node; - t->next=n; - n->val=x; - n->next=NULL; - } - else - { - node *n= new node; - n->val=x; - n->next=NULL; - start=n; - } -} - -void reverse(node *p, node *q) -{ - if (q->next == NULL) - { - q->next=p; - p->next=NULL; - start=q; - return; - } - else - { - reverse(q, q->next); - q->next=p; - p->next=NULL; - } - -} - - -void show() -{ - node *t=start; - while(t!=NULL) - { - cout<val<<"\t"; - t=t->next; - } - -} - -int main() -{ - insert(1); - insert(2); - insert(3); - insert(4); - insert(5); - insert(6); - - reverse(start, start->next); - - show(); - - - return 0; -} diff --git a/Operations on Datastructures/Union_of_2_arrays.cpp b/Operations on Datastructures/Union_of_2_arrays.cpp deleted file mode 100644 index 4046e1ae8b9..00000000000 --- a/Operations on Datastructures/Union_of_2_arrays.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include -int main() -{ - int m,n,i=0,j=0; - cout << "Enter size of both arrays:"; - cin >> m >> n; - int a[m]; - int b[n]; - cout << "Enter elements of array 1:"; - for(i=0;i>a[i]; - cout << "Enter elements of array 2:"; - for(i=0;i> b[i]; - i=0;j=0; - while((ib[j]) - cout << b[j++] <<" "; - else - { - cout << a[i++]; - j++; - } - } - while(i -using namespace std; - - -//node defined -class node -{ -public: - int data; - node* link; - node(int d) - { - data = d; - link = NULL; - } - -}; - -//printing the linked list -void print(node* head) -{ - node* current = head; - while (current != NULL) - { - cout << current->data << " "; - current = current-> link; - } - cout << endl; -} - -//creating the linked list with 'n' nodes -node* createlist(int n) -{ - node* head = NULL; - node* t = NULL; - for (int i = 0; i < n; i++) - { - node* temp = NULL; - int num; - cin >> num; - temp = new node(num); - if (head == NULL) - { - head = temp; - t = temp; - continue; - } - if (t->link == NULL) t->link = temp; - t = temp; - } - return head; -} - - -//performing selection sort on the linked list in an iterative manner -void my_selection_sort_linked_list(node* &head) -{ - node* min = head; //throughout the algorithm 'min' is used to denote the node with min value out of all the nodes left for scanning - //while scanning if we find a node 'X' with value lesser than min, - //then we update the pointers in such a way that 'X' becomes the predecessor of 'min' - node* current = min->link; // 'current' refers to the current node we are scanning - node* previous = min; //'previous' refers to the node that is previous to the current node - node* temp = NULL; // 'temp' in this algo is used to point to the last node of the sorted part of the linked list. - //eg. If at any time instance the state of the linked list is suppose 1->2->5->3->8->NULL - //then, we see that "1->2" is the sorted part of the LL, and therefore temp will be pointing to the last node of the sorted part,i.e,'2' - //We keep on arranging the Linked list in such a way that after each iteration the node with 'min' value is placed at its correct position. - //Eg. Let suppose initially we have 5->4->1->3->2->NULL - //After 1st iteration : 1->4->5->3->2->NULL and so on - - while (min->link != NULL) //so that all the nodes are scanned or until there exists a node - { - //pick the first node from the unsorted part and assume that it is the minimum and then start scanning from the next node - - while (current != NULL) //suppose you choose the min node to be X, then scan starts from the (X+1)th node until its NULL. current = (X+1)th node and min = X - { - if (current->data < min->data) //if the current node is smaller than the presumed node 'min' - { - if (temp == NULL) //temp stays null for the first iteration, therefore it symbolizes that we are scanning for the first time - { - if (previous == min) //if the 'previous' is pointing to the 'min' node - { - //Update the pointers - head = current; //update the head pointer with the current node - min->link = current->link; - current->link = previous; - min = current; - current = previous->link; - } - else //if the 'previous' is not pointing to the 'min' node - { - //Update the pointers - head = current; //update the head pointer with the current node - previous->link = current->link; - current->link = min; - min = current; - current = previous->link; - } - } - else //if 'temp' is not NULL, i.e., its not the 1st iteration - { - temp->link = current; - previous->link = current->link; - current->link = min; - min = current; - current = previous->link; - } - } - else //if the current node is greater than min, just move the previous and the current pointer a step further - { - previous = previous->link; - current = current->link; - } - } - - //update the pointers. Set 'temp' to the last node in the sorted part. Make 'min' move a step further so that 'min' points to the 1st node of the unsorted part - //start the iteration again - temp = min; - min = min->link; - previous = min; - current = min->link; - } -} - -// Test cases: - -// enter the no. of nodes : 5 -// 8 9 3 1 4 -// original list is : 8 9 3 1 4 -// sorted list is : 1 3 4 8 9 - -// enter the no. of nodes : 3 -// -1 -2 -3 -// original list is : -1 -2 -3 -// sorted list is : -3 -2 -1 - - -// enter the no. of nodes : 8 -// 8 7 6 5 4 3 2 1 -// original list is : 8 7 6 5 4 3 2 1 -// sorted list is : 1 2 3 4 5 6 7 8 - -// enter the no. of nodes : 6 -// 5 3 4 1 -2 -4 -// original list is : 5 3 4 1 -2 -4 -// sorted list is : -4 -2 1 3 4 5 - - -int main() -{ - node* head = NULL; - int n; - cout << "enter the no. of nodes : "; //taking input from user about the number of nodes in linked list - cin >> n; - if (n == 0) return 0; - head = createlist(n); //creating the list - cout << "original list is : "; - print(head); //printing the original linked list - my_selection_sort_linked_list(head); //applying selection sort - cout << "sorted list is : "; - print(head); //printing the sorted linked list - return 0; -} \ No newline at end of file diff --git a/Others/Buzz_number.cpp b/Others/Buzz_number.cpp deleted file mode 100644 index 3d39c50f63c..00000000000 --- a/Others/Buzz_number.cpp +++ /dev/null @@ -1,17 +0,0 @@ -//A buzz number is a number that is either divisble by 7 or has last digit as 7. -#include -using namespace std; -int main() -{ - int n,t; - cin >> t; - while(t--) - { - cin >> n; - if((n%7==0)||(n%10==7)) - cout << n << " is a buzz number" << endl; - else - cout << n << " is not a buzz number" << endl; - } - return 0; -} diff --git a/Others/Decimal To Binary.cpp b/Others/Decimal To Binary.cpp deleted file mode 100644 index b8eaba1f154..00000000000 --- a/Others/Decimal To Binary.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// This function convert decimal to binary number -// -#include -using namespace std; - -int main() -{ - int number; - cout << "Enter a number:"; - cin >> number; - int remainder, binary = 0, var = 1; - - do { - remainder = number % 2; - number = number / 2; - binary = binary + (remainder*var); - var = var * 10; - - } while (number>0); - cout << "the binary is :"; - cout << binary; - cout << endl; - return 0; -} diff --git a/Others/Decimal To Hexadecimal .cpp b/Others/Decimal To Hexadecimal .cpp deleted file mode 100644 index 39333ca00f5..00000000000 --- a/Others/Decimal To Hexadecimal .cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include - -using namespace std; - -int main(void){ - int valueToConvert = 0; //Holds user input - int hexArray[8]; //Contains hex values backwards - int i = 0; //counter - char HexValues[] = "0123456789ABCDEF"; - - cout << "Enter a Decimal Value" << endl; //Displays request to stdout - cin >> valueToConvert; //Stores value into valueToConvert via user input - - while (valueToConvert > 15){ //Dec to Hex Algorithm - hexArray[i++] = valueToConvert % 16; //Gets remainder - valueToConvert /= 16; - } - hexArray[i] = valueToConvert; //Gets last value - - cout << "Hex Value: "; - while (i >= 0) - cout< -#include -#include -#include -using namespace std; - -//This functions fills a string with character c, n times and returns it -string fill( char c, int n ) -{ - string s = ""; - while( n-- ) s += c; - return s; -} - -//to convert to lowercase Roman Numeral -// the function works recursively -string tolowerRoman( int n ) -{ - if( n < 4 ) return fill( 'i', n ); - if( n < 6 ) return fill( 'i', 5 - n ) + "v"; - if( n < 9 ) return string( "v" ) + fill( 'i', n - 5 ); - if( n < 11 ) return fill( 'i', 10 - n ) + "x"; - if( n < 40 ) return fill( 'x', n / 10 ) + tolowerRoman( n % 10 ); - if( n < 60 ) return fill( 'x', 5 - n / 10 ) + 'l' + tolowerRoman( n % 10 ); - if( n < 90 ) return string( "l" ) + fill( 'x', n / 10 - 5 ) + tolowerRoman( n % 10 ); - if( n < 110 ) return fill( 'x', 10 - n / 10 ) + "c" + tolowerRoman( n % 10 ); - if( n < 400 ) return fill( 'c', n / 100 ) + tolowerRoman( n % 100 ); - if( n < 600 ) return fill( 'c', 5 - n / 100 ) + 'd' + tolowerRoman( n % 100 ); - if( n < 900 ) return string( "d" ) + fill( 'c', n / 100 - 5 ) + tolowerRoman( n % 100 ); - if( n < 1100 ) return fill( 'c', 10 - n / 100 ) + "m" + tolowerRoman( n % 100 ); - if( n < 4000 ) return fill( 'm', n / 1000 ) + tolowerRoman( n % 1000 ); - return "?"; -} - -//to convert to uppercase Roman Numeral -// the function works recursively -string toupperRoman( int n ) -{ - if( n < 4 ) return fill( 'I', n ); - if( n < 6 ) return fill( 'I', 5 - n ) + "V"; - if( n < 9 ) return string( "V" ) + fill( 'I', n - 5 ); - if( n < 11 ) return fill( 'I', 10 - n ) + "X"; - if( n < 40 ) return fill( 'X', n / 10 ) + toupperRoman( n % 10 ); - if( n < 60 ) return fill( 'X', 5 - n / 10 ) + 'L' + toupperRoman( n % 10 ); - if( n < 90 ) return string( "L" ) + fill( 'X', n / 10 - 5 ) + toupperRoman( n % 10 ); - if( n < 110 ) return fill( 'X', 10 - n / 10 ) + "C" + toupperRoman( n % 10 ); - if( n < 400 ) return fill( 'C', n / 100 ) + toupperRoman( n % 100 ); - if( n < 600 ) return fill( 'C', 5 - n / 100 ) + 'D' + toupperRoman( n % 100 ); - if( n < 900 ) return string( "D" ) + fill( 'C', n / 100 - 5 ) + toupperRoman( n % 100 ); - if( n < 1100 ) return fill( 'C', 10 - n / 100 ) + "M" + toupperRoman( n % 100 ); - if( n < 4000 ) return fill( 'M', n / 1000 ) + toupperRoman( n % 1000 ); - return "?"; -} - -//main function - -int main() -{ - -int n; -cout << "\t\tRoman numbers converter\n\n"; -cout << "Type in decimal number between 0 up to 4000 (exclusive): "; -cin >> n; -cout << n << " in Upper Roman Numerals is " << toupperRoman(n) << "\n"; -cout << n << " in Lower Roman Numerals is " << tolowerRoman(n) << "\n"; -return 0; -} diff --git a/Others/GCD_of_n_numbers.cpp b/Others/GCD_of_n_numbers.cpp deleted file mode 100644 index 3e9e9ce170e..00000000000 --- a/Others/GCD_of_n_numbers.cpp +++ /dev/null @@ -1,23 +0,0 @@ -//This program aims at calculating the GCD of n numbers by division method -#include -using namepsace std; -int main() -{ - cout <<"Enter value of n:"<> n; - int a[n]; - int i,j,gcd; - cout << "Enter the n numbers:" << endl; - for(i=0;i> a[i]; - j=1; //to access all elements of the array starting from 1 - gcd=a[0]; - while(j -using namespace std; - -int main() -{ - int n,k,s=0,d; - cout << "Enter a number:"; - cin >> n; - s=0;k=n; - while(k>9) - { - while(k!=0) - { - d=k%10; - s+=d; - k/=10; - } - k=s; - s=0; - } - if(k==1) - cout << n << " is a happy number" << endl; - else - cout << n << " is not a happy number" << endl; - return 0; -} diff --git a/Others/Palindromeofnumber.cpp b/Others/Palindromeofnumber.cpp deleted file mode 100644 index 8bfdfb07371..00000000000 --- a/Others/Palindromeofnumber.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include - -using namespace std; - -int main() -{ - int num; - cout << "Enter number = "; - cin >> num; - - string s1 = to_string(num); - string s2 = s1; - - reverse(s1.begin(),s1.end()); - - if(s1 == s2) - cout<<"true"; - else - cout<<"false"; - - return 0; -} diff --git a/Others/Paranthesis Matching.cpp b/Others/Paranthesis Matching.cpp deleted file mode 100644 index 25ee7287b87..00000000000 --- a/Others/Paranthesis Matching.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include - -using namespace std; - -#define MAX 100 - -// -------------- stack -------------- - -char stack[MAX]; -int top = -1; - -void push(char ch){ - stack[ ++top ] = ch; -} - -char pop(){ - return stack[ top-- ]; -} - -// -------------- end stack ----------- - -char opening(char ch){ - switch(ch){ - case '}': - return '{'; - case ']': - return '['; - case ')': - return '('; - case '>': - return '<'; - } -} - -int main(){ - - string exp; - int valid = 1, i = 0; - cout<<"Enter The Expression : "; - cin >> exp; - - while (valid == 1 && i < exp.length()){ - if (exp[i] == '(' || exp[i] == '{' || exp[i] == '[' || exp[i] == '<'){ - push(exp[i]); - } - else if (top >= 0 && stack[top] == opening(exp[i])){ - pop(); - } - else{ - valid = 0; - } - i++; - } - - // makes sure the stack is empty after processsing (above) - if (valid == 1 && top == -1){ - cout<<"\nCorrect Expression"; - } - else{ - cout<<"\nWrong Expression"; - } - - return 0; -} diff --git a/Others/Primality Test.cpp b/Others/Primality Test.cpp deleted file mode 100644 index 0b4bb67de1c..00000000000 --- a/Others/Primality Test.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include -using namespace std; - - - //A simple and efficient implementation of a function to test if a number is prime, based on the fact that - //Every Prime number, except 2 and 3 are of the form 6*k+1 or 6*k-1 for integer values of k. - - bool IsPrime( int number ) - { - if ( ( (!(number & 1)) && number != 2 ) || (number < 2) || (number % 3 == 0 && number != 3) ) - return false; - - for( int k = 1; 36*k*k-12*k < number;++k) - { - if ( (number % (6*k+1) == 0) || (number % (6*k-1) == 0) ) - return false; - } - return true; - } - - int main() - { - //Main Function - cout <<"Enter the value of n to check if Prime\n"; - int n; - cin >> n; - if(IsPrime(n)) - cout << n << " is Prime" < -using namespace std; - -int main() -{ - int m,n; - int counterZeros=0; - cout << "Enter dimensions of matrix (seperated with space): "; - cin >> m >> n; - int a[m][n]; - cout << "Enter matrix elements:"; - cout << "\n"; - - // reads the matrix from stdin - for(int i=0;i> a[i][j]; - } - } - - // counts the zero's - for(int i=0;i((m*n)/2)) //Checking for sparse matrix - cout << "Sparse matrix"; - else - cout << "Not a sparse matrix"; -} diff --git a/Others/Strassen Matrix Multiplication.cpp b/Others/Strassen Matrix Multiplication.cpp deleted file mode 100644 index 1cb398a62e3..00000000000 --- a/Others/Strassen Matrix Multiplication.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include -using namespace std; - -Multiply(int A[][], int B[][], int n) -{ - if (n==2) - { - int p1= (a[0][0] + a[1][1])*(b[0][0]+b[1][1]); - int p2= (a[1][0]+a[1][1])*b[0][0]; - int p3= a[0][0]*(b[0][1]-b[1][1]); - int p4= a[1][1]*(b[1][0]-b[0][0]); - int p5= (a[0][0]+a[0][1])*b[1][1]; - int p6= (a[1][0]-a[0][0])*(b[0][0]+b[0][1]); - int p7= (a[0][1]-a[1][1])*(b[1][0]+b[1][1]); - - - int c[n][n]; - c[0][0]=p1+p4-p5+p7; - c[0][1]=p3+p5; - c[1][0]=p2+p4; - c[1][1]=p1-p2+p3+p6; - - return c[][]; - } - else - { - - } - -} - -int main() -{ - int p,q,r,s; - cout<<"Enter the dimensions of Matrices"; - cin>>n; - int A[n][n],; - int B[n][n],; - cout<<"Enter the elements of Matrix A"; - for (int i = 0; i < n; i++) - { - for (int j = 0; j >A[i][j]; - } - } - - - cout<<"Enter the elements of Matrix B"; - for (int i = 0; i < n; i++) - { - for (int j = 0; j >B[i][j]; - } - } - - Multiply(A, B, n); - return 0; -} \ No newline at end of file diff --git a/Others/String Fibonacci.cpp b/Others/String Fibonacci.cpp deleted file mode 100644 index 8027b966859..00000000000 --- a/Others/String Fibonacci.cpp +++ /dev/null @@ -1,85 +0,0 @@ -//This Programme returns the Nth fibonacci as a string. -//The method used is manual addition with carry and placing it in a string which is called string addition -//This makes it have no bounds or limits - - -#include -#include - -using namespace std; - -string add(string a, string b) -{ - string temp = ""; - - // carry flag - int carry = 0; - - // fills up with zeros - while ((int)a.length() < (int)b.length()) - { - a = "0" + a; - } - - // fills up with zeros - while ((int)b.length() < (int)a.length()) - { - b = "0" + b; - } - - // adds the numbers a and b - for (int i = a.length() - 1; i >= 0; i--) - { - char val = (char)(((a[i] - 48) + (b[i] - 48)) + 48 + carry); - if (val > 57) - { - carry = 1; - val -= 10; - } - else - { - carry = 0; - } - temp = val + temp; - } - - // processes the carry flag - if (carry == 1) - { - temp = "1" + temp; - } - - // removes leading zeros. - while (temp[0] == '0' && temp.length() > 1) - { - temp = temp.substr(1); - } - - return temp; -} - -void fib_Accurate(long long n) -{ - string tmp = ""; - string fibMinus1 = "1"; - string fibMinus2 = "0"; - for (long long i = 0; i < n; i++) - { - tmp = add(fibMinus1, fibMinus2); - fibMinus2 = fibMinus1; - fibMinus1 = tmp; - } - cout << fibMinus2; -} - - -int main() -{ - int n; - cout << "Enter whatever number N you want to find the fibonacci of\n"; - cin >> n; - cout << n << " th Fibonacci is \n"; - fib_Accurate(n); - - return 0; -} diff --git a/Others/Tower of Hanoi.cpp b/Others/Tower of Hanoi.cpp deleted file mode 100644 index f9b3637844b..00000000000 --- a/Others/Tower of Hanoi.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#include -using namespace std; - -struct tower -{ - int values[10]; - int top; -}F, U, T; - - - -void show() -{ - cout<<"\n\n\tF : "; - for(int i=0; i> no; - - for (int i = no; i >0; i--) - { - F.values[F.top++]=i; - }; - - - - - - show(); - TH(no, F, U, T); - - - - - - return 0; -} diff --git a/Others/fibonacci.cpp b/Others/fibonacci.cpp deleted file mode 100644 index 82b1fd3227b..00000000000 --- a/Others/fibonacci.cpp +++ /dev/null @@ -1,47 +0,0 @@ -//An efficient way to calculate nth fibonacci number faster and simpler than O(nlogn) method of matrix exponentiation -//This works by using both recursion and dynamic programming. -//as 93rd fibonacci exceeds 19 digits, which cannot be stored in a single long long variable, we can only use it till 92nd fibonacci -//we can use it for 10000th fibonacci etc, if we implement bigintegers. -//This algorithm works with the fact that nth fibonacci can easily found if we have already found n/2th or (n+1)/2th fibonacci -//It is a property of fibonacci similar to matrix exponentiation. - -#include -#include -using namespace std; - -const long long MAX = 93; - - -long long f[MAX] = {0}; - - -long long fib(long long n) -{ - - if (n == 0) - return 0; - if (n == 1 || n == 2) - return (f[n] = 1); - - - if (f[n]) - return f[n]; - - long long k = (n%2!=0)? (n+1)/2 : n/2; - - f[n] = (n%2!=0)? (fib(k)*fib(k) + fib(k-1)*fib(k-1)) - : (2*fib(k-1) + fib(k))*fib(k); - return f[n]; -} - - -int main() -{ - //Main Function - for(long long i=1;i<93;i++) - { - cout << i << " th fibonacci number is " << fib(i) << "\n"; - } - return 0; -} - diff --git a/Others/sieve_of_Eratosthenes.cpp b/Others/sieve_of_Eratosthenes.cpp deleted file mode 100644 index e20aec6ae85..00000000000 --- a/Others/sieve_of_Eratosthenes.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Sieve of Eratosthenes is an algorithm to find the primes - * that is between 2 to N (as defined in main). - * - * Time Complexity : O(N) - * Space Complexity : O(N) - */ - -#include -using namespace std; - -#define MAX 10000000 - -int primes[MAX]; - - -/* - * This is the function that finds the primes and eliminates - * the multiples. - */ -void sieve(int N) -{ - primes[0] = 1; - primes[1] = 1; - for(int i=2;i<=N;i++) - { - if(primes[i] == 1) continue; - for(int j=i+i;j<=N;j+=i) - primes[j] = 1; - } -} - -/* - * This function prints out the primes to STDOUT - */ -void print(int N) -{ - for(int i=0;i<=N;i++) - if(primes[i] == 0) - cout << i << ' '; - cout << '\n'; -} - -/* - * NOTE: This function is important for the - * initialization of the array. - */ -void init() -{ - for(int i=0;i -#include -#include - -using namespace std; - -struct Point { - double x, y; - Point(double a = 0.0, double b = 0.0) - { - x = a; - y = b; - } -}; - -double LenghtLine(Point A, Point B) -{ - return sqrt(abs((B.x - A.x)*(B.x - A.x)) + abs((B.y - A.y)*(B.y - A.y))); -} - -double TriangleArea(Point A, Point B, Point C) -{ - double a = LenghtLine(A, B); - double b = LenghtLine(B, C); - double c = LenghtLine(C, A); - double p = (a + b + c) / 2; - return sqrt(p*(p - a)*(p - b)*(p - c)); -} - -bool PointInCircle(vector &P, Point Center, double R) -{ - for (size_t i = 0; i < P.size(); i++) - { - if (LenghtLine(P[i], Center) > R) - return false; - } - return true; -} - -double circle(vector P) -{ - double minR = INT8_MAX; - double R; - Point C; - Point minC; - for (size_t i = 0; i < P.size() - 2; i++) - for (size_t j = i+1; j < P.size(); j++) - for (size_t k = j+1; k < P.size(); k++) - { - C.x = -0.5 * ((P[i].y*(P[j].x*P[j].x + P[j].y*P[j].y - P[k].x*P[k].x - P[k].y*P[k].y) + P[j].y*(P[k].x*P[k].x + P[k].y*P[k].y - P[i].x*P[i].x - P[i].y*P[i].y) + P[k].y*(P[i].x*P[i].x + P[i].y*P[i].y - P[j].x*P[j].x - P[j].y*P[j].y)) / (P[i].x*(P[j].y - P[k].y) + P[j].x*(P[k].y - P[i].y) + P[k].x*(P[i].y - P[j].y) )); - C.y = 0.5 * ((P[i].x*(P[j].x*P[j].x + P[j].y*P[j].y - P[k].x*P[k].x - P[k].y*P[k].y) + P[j].x*(P[k].x*P[k].x + P[k].y*P[k].y - P[i].x*P[i].x - P[i].y*P[i].y) + P[k].x*(P[i].x*P[i].x + P[i].y*P[i].y - P[j].x*P[j].x - P[j].y*P[j].y)) / (P[i].x*(P[j].y - P[k].y) + P[j].x*(P[k].y - P[i].y) + P[k].x*(P[i].y - P[j].y) )); - R = (LenghtLine(P[i], P[j]) * LenghtLine(P[j], P[k]) * LenghtLine(P[k], P[i])) / (4 * TriangleArea(P[i], P[j], P[k])); - if (!PointInCircle(P, C, R)) - { - continue; - } - if (R <= minR) - { - minR = R; - minC = C; - } - - } - for (size_t i = 0; i < P.size() - 1; i++) - for (size_t j = i + 1; j < P.size(); j++) - { - C.x = (P[i].x + P[j].x) / 2; - C.y = (P[i].y + P[j].y) / 2; - R = LenghtLine(C, P[i]); - if (!PointInCircle(P, C, R)) - { - continue; - } - if (R <= minR) - { - minR = R; - minC = C; - } - } - cout << minC.x << " " << minC.y << endl; - return minR; -} - -void test() -{ - vector Pv(5); - Pv.push_back(Point(0,0)); - Pv.push_back(Point(1,3)); - Pv.push_back(Point(4,1)); - Pv.push_back(Point(5,4)); - Pv.push_back(Point(3,-2)); - cout << circle(Pv) << endl; -} - -void test2() -{ - vector Pv(4); - Pv.push_back(Point(0,0)); - Pv.push_back(Point(0,2)); - Pv.push_back(Point(2,2)); - Pv.push_back(Point(2,0)); - cout << circle(Pv) << endl; -} - -void test3() -{ - vector Pv(3); - Pv.push_back(Point(0.5,1)); - Pv.push_back(Point(3.5,3)); - Pv.push_back(Point(2.5,0)); - cout << circle(Pv) << endl; -} -int main() -{ - test(); - cout << endl; - test2(); - cout << endl; - test3(); - return 0; -} diff --git a/Others/spiral_print.cpp b/Others/spiral_print.cpp deleted file mode 100644 index 03ea074e98d..00000000000 --- a/Others/spiral_print.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include -using namespace std; - -void genArray(int a[][10],int r,int c){ - - int value=1; - for(int i=0;i=startCol;i--,cnt++){ - cout<=startRow;i--,cnt++){ - cout<>r>>c; - genArray(a,r,c); - spiralPrint(a,r,c); - - -return 0; -} diff --git a/README.md b/README.md index 81367fcb4f3..9f32c07b70e 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,39 @@ -# C++ +# The Algorithms - C++ # {#mainpage} + -This repository contains some useful algorithms and data structures. +[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/TheAlgorithms/C-Plus-Plus) +[![CodeQL CI](https://github.com/TheAlgorithms/C-Plus-Plus/actions/workflows/codeql.yml/badge.svg)](https://github.com/TheAlgorithms/C-Plus-Plus/actions/workflows/codeql.yml) +[![Gitter chat](https://img.shields.io/badge/Chat-Gitter-ff69b4.svg?label=Chat&logo=gitter&style=flat-square)](https://gitter.im/TheAlgorithms) +[![contributions welcome](https://img.shields.io/static/v1.svg?label=Contributions&message=Welcome&color=0059b3&style=flat-square)](https://github.com/TheAlgorithms/C-Plus-Plus/blob/master/CONTRIBUTING.md) +![GitHub repo size](https://img.shields.io/github/repo-size/TheAlgorithms/C-Plus-Plus?color=red&style=flat-square) +[![Doxygen CI](https://github.com/TheAlgorithms/C-Plus-Plus/workflows/Doxygen%20CI/badge.svg)](https://TheAlgorithms.github.io/C-Plus-Plus) +[![Awesome CI](https://github.com/TheAlgorithms/C-Plus-Plus/workflows/Awesome%20CI%20Workflow/badge.svg)](https://github.com/TheAlgorithms/C-Plus-Plus/actions?query=workflow%3A%22Awesome+CI+Workflow%22) +[![Income](https://img.shields.io/liberapay/receives/TheAlgorithms.svg?logo=liberapay)](https://liberapay.com/TheAlgorithms) +[![Discord chat](https://img.shields.io/discord/808045925556682782.svg?logo=discord&colorB=5865F2)](https://the-algorithms.com/discord/) +[![Donate](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/TheAlgorithms/donate) -### Contribute +## Overview -How you can contribute? See this small guide. +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. -* Use the directory structure of the repository. -* Please describe your pull requests. -* Don't use **bits/stdc++.h** because this is quite Linux specific and slows down the compiler process. -* Put comments in your code. -* Avoid **struct**. Instead use the **class** keyword. -* Add some test cases in the main-function. -* Can suggest any change in present algorithms(if needed). \ No newline at end of file +## 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 14.0.0, and GNU 11.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)
+Creative Commons LicenseCredit must be given to the creatorAdaptations must be shared under the same terms + +## 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). diff --git a/REVIEWER_CODE.md b/REVIEWER_CODE.md new file mode 100644 index 00000000000..933d43e6853 --- /dev/null +++ b/REVIEWER_CODE.md @@ -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. diff --git a/Range queries/MO.cpp b/Range queries/MO.cpp deleted file mode 100644 index 2a2cbfffdd5..00000000000 --- a/Range queries/MO.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "bits/stdc++.h" -using namespace std; -const int N = 1e6+5; -int a[N],bucket[N],cnt[N]; -int bucket_size; -struct query{ - int l,r,i; -}q[N]; -int ans=0; - -void add(int index) -{ - cnt[a[index]]++; - if(cnt[a[index]] == 1) - ans++; -} -void remove(int index) -{ - cnt[a[index]]--; - if(cnt[a[index]] == 0) - ans--; -} - - -bool mycmp(query x, query y) -{ - if(x.l/bucket_size != y.l/bucket_size) - return x.l/bucket_size < y.l/bucket_size; - return x.rL) - { - add(left-1); - left--; - } - while(right<=R) - { - add(right); - right++; - } - while(right>R+1) - { - remove(right-1); - right--; - } - bucket[q[i].i] = ans; - } - for(i=0;i -#define MAX 4000000 -using namespace std; -typedef long long ll; -void ConsTree(ll arr[],ll segtree[],ll low,ll high,ll pos) -{ - if(low == high) - { - segtree[pos] = arr[low]; - return; - } - ll mid = (low+high)/2; - ConsTree(arr,segtree,low,mid,2*pos+1); - ConsTree(arr,segtree,mid+1,high,2*pos+2); - segtree[pos] = segtree[2*pos+1] + segtree[2*pos+2]; -} -ll query(ll segtree[],ll lazy[],ll qlow,ll qhigh,ll low,ll high,ll pos) -{ - if(low > high) - return 0; - if(qlow>high || qhigh=high) - return segtree[pos]; - ll mid = (low+high)/2; - return query(segtree,lazy,qlow,qhigh,low,mid,2*pos+1) + query(segtree,lazy,qlow,qhigh,mid+1,high,2*pos+2); -} -void update(ll segtree[],ll lazy[],ll start,ll end,ll delta,ll low,ll high,ll pos) -{ - if(low>high) - return; - if(lazy[pos] != 0) - { - segtree[pos] += lazy[pos]*(high-low+1); - if(low!=high) - { - lazy[2*pos+1] += lazy[pos]; - lazy[2*pos+2] += lazy[pos]; - } - lazy[pos] = 0; - } - if(start > high || end < low) - return; - if(start <= low && end >= high) - { - segtree[pos] += delta*(high-low+1); - if(low != high) - { - lazy[2*pos+1] += delta; - lazy[2*pos+2] += delta; - } - return; - } - ll mid = (low+high)/2; - update(segtree,lazy,start,end,delta,low,mid,2*pos+1); - update(segtree,lazy,start,end,delta,mid+1,high,2*pos+2); - segtree[pos] = segtree[2*pos+1] + segtree[2*pos+2]; -} -int main() { - ll n,c; - scanf("%lld %lld",&n,&c); - ll arr[n]={0},p,q,v,choice; - ll segtree[MAX],lazy[MAX]={0}; - ConsTree(arr,segtree,0,n-1,0); - while(c--) - { - scanf("%lld",&choice); - if(choice == 0) - { - scanf("%lld %lld %lld",&p,&q,&v); - update(segtree,lazy,p-1,q-1,v,0,n-1,0); - } - else - { - scanf("%lld %lld",&p,&q); - printf("%lld\n",query(segtree,lazy,p-1,q-1,0,n-1,0)); - } - } - return 0; -} diff --git a/Search/Binary Search.cpp b/Search/Binary Search.cpp deleted file mode 100644 index cb67e3a077f..00000000000 --- a/Search/Binary Search.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include -using namespace std; -int binary_search(int a[],int l,int r,int key){ - while(l<=r){ - int m = l+(r-l)/2; - if(key==a[m]) - return m; - else if(key>n; - cout<<"Enter array elements: "; - int a[n]; - for (int i = 0; i < n; ++i) - { - cin>>a[i]; - } - cout<<"Enter search key: "; - cin>>key; - int res = binary_search(a,0,n-1,key); - if(res != -1) - cout< -using namespace std; - -int LinearSearch(int *array, int size, int key) -{ - for (int i = 0; i < size; ++i) - { - if (array[i]==key) - { - return i; - } - } - - return -1; -} - - -int main() -{ - int size; - cout<<"\nEnter the size of the Array : "; - cin >> size; - - int array[size]; - int key; - - //Input array - cout<<"\nEnter the Array of " << size << " numbers : "; - for (int i = 0; i < size; i++) - { - cin>>array[i]; - } - - cout<<"\nEnter the number to be searched : "; - cin>>key; - - int index=LinearSearch(array, size, key); - if (index!=-1) - { - cout<<"\nNumber found at index : "< -#include -#include - -using namespace std; -char paragraph; - -int main() -{ - string paragraph; - cout << "Please enter your paragraph: \n"; - getline (cin,paragraph); - cout << "\nHello, your paragraph is:\n " << paragraph << "!\n"; - cout << "\nThe size of your paragraph = " << paragraph.size() << " characters. \n\n"; - - if (paragraph.empty()) - { - cout << "\nThe paragraph is empty" << endl; - } - else - { - while (true) { - string word; - cout << "Please enter the word you are searching for: "; - getline (cin,word); - cout << "Hello, your word is " << word << "!\n"; - if (paragraph.find(word) == string::npos) - { - cout << word << " does not exist in the sentence" << endl; - } - else - { - cout << "The word " << word << " is now found at location " << paragraph.find(word) << endl << endl; - } - system("pause"); - } - - } -} diff --git a/Search/ternary_search.cpp b/Search/ternary_search.cpp deleted file mode 100644 index 4d126f09d5c..00000000000 --- a/Search/ternary_search.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * This is a divide and conquer algorithm. - * It does this by dividing the search space by 3 parts and - * using its property (usually monotonic property) to find - * the desired index. - * - * Time Complexity : O(log3 n) - * Space Complexity : O(1) (without the array) - */ - -#include -using namespace std; - -/* - * The absolutePrecision can be modified to fit preference but - * it is recommended to not go lower than 10 due to errors that - * may occur. - * - * The value of _target should be decided or can be decided later - * by using the variable of the function. - */ - -#define _target 10 -#define absolutePrecision 10 -#define MAX 10000000 - -int N = 21; -int A[MAX] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,3,4,10}; - -/* - * get_input function is to receive input from standard IO - */ -void get_input() -{ - // TODO: Get input from STDIO or write input to memory as done above. -} - - -/* - * This is the iterative method of the ternary search which returns the index of the element. - */ -int it_ternary_search(int left, int right, int A[],int target) -{ - while (1) - { - if(left A[twoThird]) left = twoThird+1; - else if(target < A[oneThird]) right = oneThird-1; - - else left = oneThird+1, right = twoThird-1; - } - else return -1; - } -} - -/* - * This is the recursive method of the ternary search which returns the index of the element. - */ -int rec_ternary_search(int left, int right, int A[],int target) -{ - if(left A[twoThird]) return rec_ternary_search(twoThird+1, right, A, target); - - return rec_ternary_search(oneThird+1, twoThird-1, A, target); - } - else return -1; -} - -/* - * ternary_search is a template function - * You could either use it_ternary_search or rec_ternary_search according to preference. - */ -void ternary_search(int N,int A[],int target) -{ - cout << it_ternary_search(0,N-1,A,target) << '\t'; - cout << rec_ternary_search(0,N-1,A,target) << '\t'; - cout << '\n'; -} - -int main() -{ - get_input(); - ternary_search(N,A,_target); - return 0; -} diff --git a/Sorting/BitonicSort.cpp b/Sorting/BitonicSort.cpp deleted file mode 100644 index e03e4fc14c2..00000000000 --- a/Sorting/BitonicSort.cpp +++ /dev/null @@ -1,76 +0,0 @@ -// Source : https://www.geeksforgeeks.org/bitonic-sort/ - -/* C++ Program for Bitonic Sort. Note that this program - works only when size of input is a power of 2. */ - -#include -#include -using namespace std; - -/*The parameter dir indicates the sorting direction, ASCENDING - or DESCENDING; if (a[i] > a[j]) agrees with the direction, - then a[i] and a[j] are interchanged.*/ -void compAndSwap(int a[], int i, int j, int dir) -{ - if (dir==(a[i]>a[j])) - swap(a[i],a[j]); -} - -/*It recursively sorts a bitonic sequence in ascending order, - if dir = 1, and in descending order otherwise (means dir=0). - The sequence to be sorted starts at index position low, - the parameter cnt is the number of elements to be sorted.*/ -void bitonicMerge(int a[], int low, int cnt, int dir) -{ - if (cnt>1) - { - int k = cnt/2; - for (int i=low; i1) - { - int k = cnt/2; - - // sort in ascending order since dir here is 1 - bitonicSort(a, low, k, 1); - - // sort in descending order since dir here is 0 - bitonicSort(a, low+k, k, 0); - - // Will merge wole sequence in ascending order - // since dir=1. - bitonicMerge(a,low, cnt, dir); - } -} - -/* Caller of bitonicSort for sorting the entire array of - length N in ASCENDING order */ -void sort(int a[], int N, int up) -{ - bitonicSort(a,0, N, up); -} - -// Driver code -int main() -{ - int a[]= {3, 7, 4, 8, 6, 2, 1, 5}; - int N = sizeof(a)/sizeof(a[0]); - - int up = 1; // means sort in ascending order - sort(a, N, up); - - printf("Sorted array: \n"); - for (int i=0; i -#include -using namespace std; - -int main() -{ - int n; - short swap_check=0; - cout << "Enter the amount of numbers to sort: "; - cin >> n; - vector numbers; - cout << "Enter " << n << " numbers: "; - int num; - - //Input - for(int i=0; i> num; - numbers.push_back(num); - } - - //Bubble Sorting - for(int i=0; inumbers[j+1]) - { - swap_check=1; - swap(numbers[j], numbers[j+1]); - } - } - if(swap_check == 0) - { - break; - } - } - - //Output - cout<<"\nSorted Array : "; - for(int i=0; i -using namespace std; - -//Iterative Version - -void CocktailSelectionSort(vector &vec,int low,int high) -{ - while(low<=high) - { - int minimum=vec[low]; - int minimumindex=low; - int maximum=vec[high]; - int maximumindex=high; - - for(int i=low;i<=high;i++) - { - if(vec[i]>=maximum) - { - maximum=vec[i]; - maximumindex=i; - } - if(vec[i]<=minimum) - { - minimum=vec[i]; - minimumindex=i; - } - } - if(low!=maximumindex||high!=minimumindex) - { - swap(vec[low],vec[minimumindex]); - swap(vec[high],vec[maximumindex]); - } - else - { - swap(vec[low],vec[high]); - } - - low++; - high--; -} - -} - - -//Recursive Version - -void CocktailSelectionSort(vector &vec,int low,int high) -{ - - if(low>=high) - return; - - int minimum=vec[low]; - int minimumindex=low; - int maximum=vec[high]; - int maximumindex=high; - - for(int i=low;i<=high;i++) - { - if(vec[i]>=maximum) - { - maximum=vec[i]; - maximumindex=i; - } - if(vec[i]<=minimum) - { - minimum=vec[i]; - minimumindex=i; - } - } - if(low!=maximumindex||high!=minimumindex) - { - swap(vec[low],vec[minimumindex]); - swap(vec[high],vec[maximumindex]); - } - else - { - swap(vec[low],vec[high]); - } - - CocktailSelectionSort(vec,low+1,high-1); - - -} - - -//main function, select any one of iterative or recursive version - -int main() -{ - - int n; - cout << "Enter number of elements\n"; - cin >> n; - std::vector v(n); - cout << "Enter all the elements\n"; - for (int i = 0; i < n; ++i) - { - cin >> v[i]; - } - - CocktailSelectionSort(v,0,n-1); - cout << "Sorted elements are\n"; - for (int i = 0; i < n; ++i) - { - cout << v[i] << " "; - } - - - return 0; -} diff --git a/Sorting/CountingSortString.cpp b/Sorting/CountingSortString.cpp deleted file mode 100644 index 2dbf499e760..00000000000 --- a/Sorting/CountingSortString.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// C++ Program for counting sort -#include - -using namespace std; - -void countSort(string arr) -{ - - string output; - - int count[256], i; - for(int i=0;i<256;i++) - count[i]=0; - - - for(i = 0; arr[i]; ++i) - ++count[arr[i]]; - - - for (i = 1; i <= 256; ++i) - count[i] += count[i-1]; - - for (i = 0; arr[i]; ++i) - { - output[count[arr[i]]-1] = arr[i]; - --count[arr[i]]; - } - - for (i = 0; arr[i]; ++i) - arr[i] = output[i]; - - cout<<"Sorted character array is "<>arr; - - countSort(arr); - - return 0; -} diff --git a/Sorting/Counting_Sort.cpp b/Sorting/Counting_Sort.cpp deleted file mode 100644 index bea604a982d..00000000000 --- a/Sorting/Counting_Sort.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include -using namespace std; - -int Max(int Arr[], int N){ - int max = Arr[0]; - for(int i=1; i max) - max = Arr[i]; - return max; -} - -int Min(int Arr[], int N){ - int min = Arr[0]; - for(int i=1; i=0; i--){ - Sorted_Arr[Count[Arr[i]-min]-1] = Arr[i]; - Count[Arr[i]-min]--; - } - - return Sorted_Arr; -} - -int main(){ - - int Arr[] = {47, 65, 20, 66, 25, 53, 64, 69, 72, 22, 74, 25, 53, 15, 42, 36, 4, 69, 86, 19}, N = 20; - int *Sorted_Arr; - - cout<<"\n\tOrignal Array = ";Print(Arr, N); - Sorted_Arr = Counting_Sort(Arr, N); - cout<<"\n\t Sorted Array = ";Print(Sorted_Arr, N); - cout< -#include -using namespace std; -void max_heapify(int *a, int i, int n) -{ - int j, temp; - temp = a[i]; - j = 2 * i; - while (j <= n) - { - if (j < n && a[j + 1] > a[j]) - j = j + 1; - if (temp > a[j]) - break; - else if (temp <= a[j]) - { - a[j / 2] = a[j]; - j = 2 * j; - } - } - a[j / 2] = temp; - return; -} -void heapsort(int *a, int n) -{ - int i, temp; - for (i = n; i >= 2; i--) - { - temp = a[i]; - a[i] = a[1]; - a[1] = temp; - max_heapify(a, 1, i - 1); - } -} -void build_maxheap(int *a, int n) -{ - int i; - for (i = n / 2; i >= 1; i--) - { - max_heapify(a, i, n); - } -} -int main() -{ - int n, i, x; - cout << "Enter number of elements of array\n"; - cin >> n; - int a[20]; - for (i = 1; i <= n; i++) - { - cout << "Enter Element " << (i) << endl; - cin >> a[i]; - } - build_maxheap(a, n); - heapsort(a, n); - cout << "Sorted Output\n"; - for (i = 1; i <= n; i++) - { - cout << a[i] << endl; - } - getch(); -} diff --git a/Sorting/Insertion Sort.cpp b/Sorting/Insertion Sort.cpp deleted file mode 100644 index af66550ec99..00000000000 --- a/Sorting/Insertion Sort.cpp +++ /dev/null @@ -1,41 +0,0 @@ -//Insertion Sort - -#include -using namespace std; - -int main() -{ - int n; - cout<<"\nEnter the length of your array : "; - cin>>n; - int Array[n]; - cout<<"\nEnter any "<>Array[i]; - } - - //Sorting - for(int i=1; i=0 && temp -using namespace std; - -void merge(int arr[], int l, int m, int r) -{ - int i, j, k; - int n1 = m - l + 1; - int n2 = r - m; - - int L[n1], R[n2]; - - - for (i = 0; i < n1; i++) - L[i] = arr[l + i]; - for (j = 0; j < n2; j++) - R[j] = arr[m + 1+ j]; - - i = 0; - j = 0; - k = l; - while (i < n1 && j < n2) - { - if (L[i] <= R[j]) - { - arr[k] = L[i]; - i++; - } - else - { - arr[k] = R[j]; - j++; - } - k++; - } - - while (i < n1) - { - arr[k] = L[i]; - i++; - k++; - } - - - while (j < n2) - { - arr[k] = R[j]; - j++; - k++; - } -} - - -void mergeSort(int arr[], int l, int r) -{ - if (l < r) - { - - int m = l+(r-l)/2; - - - mergeSort(arr, l, m); - mergeSort(arr, m+1, r); - - merge(arr, l, m, r); - } -} - - -void show(int A[], int size) -{ - int i; - for (i=0; i < size; i++) - cout<>size; - - int arr[size]; - - cout<<"\nEnter the unsorted elements : "; - - for (int i = 0; i < size; ++i) - { - cout<<"\n"; - cin>>arr[i]; - } - - mergeSort(arr, 0, size); - - cout<<"Sorted array\n"; - show(arr, size); - return 0; -} diff --git a/Sorting/NumericStringSort.cpp b/Sorting/NumericStringSort.cpp deleted file mode 100644 index 726377ebe12..00000000000 --- a/Sorting/NumericStringSort.cpp +++ /dev/null @@ -1,64 +0,0 @@ -//Using general algorithms to sort a collection of strings results in alphanumeric sort. -//If it is a numeric string, it leads to unnatural sorting - -//eg, an array of strings 1,10,100,2,20,200,3,30,300 -//would be sorted in that same order by using conventional sorting, -//even though we know the correct sorting order is 1,2,3,10,20,30,100,200,300 - -//This Programme uses a comparator to sort the array in Numerical order instead of Alphanumeric order - - -#include -#include -#include -using namespace std; - -bool NumericSort(string a,string b) -{ - while(a[0]=='0') - { - a.erase(a.begin()); - } - while(b[0]=='0') - { - b.erase(b.begin()); - } - int n=a.length(); - int m=b.length(); - if(n==m) - return a> n; - -vector v(n); -cout << "Enter the string of Numbers\n"; -for(int i=0;i> v[i]; -} - -sort(v.begin(),v.end()); -cout << "Elements sorted normally \n"; -for(int i=0;i -#include - -using namespace std; - -void oddEven(vector &arr, int size) -{ - bool sorted = false; - while( ! sorted ) - { - sorted = true; - for(int i = 1; i < size-1; i += 2)//Odd - { - if(arr[i] > arr[i+1]) - { - swap(arr[i], arr[i+1]); - sorted = false; - } - } - - for(int i = 0; i < size-1; i += 2)//Even - { - if(arr[i] > arr[i+1]) - { - swap(arr[i], arr[i+1]); - sorted = false; - } - } - } -} - -void show(vector A, int size) -{ - int i; - for (i = 0; i < size; i++) - cout << A[i] << "\n"; -} - - -int main() -{ - int size, temp; - cout << "\nEnter the number of elements : "; - cin >> size; - - vector arr; - - cout<<"\nEnter the unsorted elements : \n"; - - for (int i = 0; i < size; ++i) - { - cin >> temp; - arr.push_back(temp); - } - - oddEven(arr, size); - - cout<<"Sorted array\n"; - show(arr, size); - return 0; -} diff --git a/Sorting/Quick Sort.cpp b/Sorting/Quick Sort.cpp deleted file mode 100644 index b2bb21a7737..00000000000 --- a/Sorting/Quick Sort.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* C implementation QuickSort */ -#include -using namespace std; - -int partition (int arr[], int low, int high) -{ - int pivot = arr[high]; // pivot - int i = (low - 1); // Index of smaller element - - for (int j = low; j >size; - - int arr[size]; - - cout<<"\nEnter the unsorted elements : "; - - for (int i = 0; i < size; ++i) - { - cout<<"\n"; - cin>>arr[i]; - } - quickSort(arr, 0, size); - cout<<"Sorted array\n"; - show(arr, size); - return 0; -} diff --git a/Sorting/Radix Sort.cpp b/Sorting/Radix Sort.cpp deleted file mode 100644 index eb3f12a575a..00000000000 --- a/Sorting/Radix Sort.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include -#include -#include -using namespace std; -void radixsort(int a[],int n){ - int count[10]; - int output[n]; - memset(output,0,sizeof(output)); - memset(count,0,sizeof(count)); - int max = 0; - for (int i = 0; i < n; ++i) - { - if (a[i]>max) - { - max = a[i]; - } - } - int maxdigits = 0; - while(max){ - maxdigits++; - max/=10; - } - for(int j=0;j -using namespace std; - -int main() -{ - int Array[6]; - cout<<"\nEnter any 6 Numbers for Unsorted Array : "; - - //Input - for(int i=0; i<6; i++) - { - cin>>Array[i]; - } - - //Selection Sorting - for(int i=0; i<6; i++) - { - int min=i; - for(int j=i+1; j<6; j++) - { - if(Array[j] -using namespace std; - -int main() -{ - int size=10; - int array[size]; - // Input - cout<<"\nHow many numbers do want to enter in unsorted array : "; - cin>>size; - cout<<"\nEnter the numbers for unsorted array : "; - for (int i = 0; i < size; i++) - { - cin>>array[i]; - } - - // Sorting - for (int i = size/2; i>0 ; i=i/2) - { - for (int j = i; j =0; k=k-i) - { - if (array[k] -using namespace std; - -void SlowSort(int a[], int i, int j) -{ - if(i>=j) - return; - int m=i+(j-i)/2; //midpoint, implemented this way to avoid overflow - int temp; - SlowSort(a, i, m); - SlowSort(a, m + 1, j); - if(a[j]>size; - - int arr[size]; - - cout<<"\nEnter the unsorted elements : "; - - for (int i = 0; i < size; ++i) - { - cout<<"\n"; - cin>>arr[i]; - } - - SlowSort(arr, 0, size); - - cout<<"Sorted array\n"; - - for (int i = 0; i < size; ++i) - { - cout << arr[i] << " "; - } - return 0; -} diff --git a/Sorting/Tim Sort.cpp b/Sorting/Tim Sort.cpp deleted file mode 100644 index a97a123a1a3..00000000000 --- a/Sorting/Tim Sort.cpp +++ /dev/null @@ -1,116 +0,0 @@ -// C++ program to perform TimSort. -#include -using namespace std; -const int RUN = 32; - -// this function sorts array from left index to to right index which is of size atmost RUN -void insertionSort(int arr[], int left, int right) -{ - for (int i = left + 1; i <= right; i++) - { - int temp = arr[i]; - int j = i - 1; - while (arr[j] > temp && j >= left) - { - arr[j+1] = arr[j]; - j--; - } - arr[j+1] = temp; - } -} - -// merge function merges the sorted runs -void merge(int arr[], int l, int m, int r) -{ - // original array is broken in two parts, left and right array - int len1 = m - l + 1, len2 = r - m; - int left[len1], right[len2]; - for (int i = 0; i < len1; i++) - left[i] = arr[l + i]; - for (int i = 0; i < len2; i++) - right[i] = arr[m + 1 + i]; - - int i = 0; - int j = 0; - int k = l; - - // after comparing, we merge those two array in larger sub array - while (i < len1 && j < len2) - { - if (left[i] <= right[j]) - { - arr[k] = left[i]; - i++; - } - else - { - arr[k] = right[j]; - j++; - } - k++; - } - - // copy remaining elements of left, if any - while (i < len1) - { - arr[k] = left[i]; - k++; - i++; - } - - // copy remaining element of right, if any - while (j < len2) - { - arr[k] = right[j]; - k++; - j++; - } -} - -// iterative Timsort function to sort the array[0...n-1] (similar to merge sort) -void timSort(int arr[], int n) -{ - // Sort individual subarrays of size RUN - for (int i = 0; i < n; i+=RUN) - insertionSort(arr, i, min((i+31), (n-1))); - - // start merging from size RUN (or 32). It will merge to form size 64, then 128, 256 and so on .... - for (int size = RUN; size < n; size = 2*size) - { - // pick starting point of left sub array. We are going to merge arr[left..left+size-1] and arr[left+size, left+2*size-1] - // After every merge, we increase left by 2*size - for (int left = 0; left < n; left += 2*size) - { - // find ending point of left sub array - // mid+1 is starting point of right sub array - int mid = left + size - 1; - int right = min((left + 2*size - 1), (n-1)); - - // merge sub array arr[left.....mid] & arr[mid+1....right] - merge(arr, left, mid, right); - } - } -} - -// utility function to print the Array -void printArray(int arr[], int n) -{ - for (int i = 0; i < n; i++) - printf("%d ", arr[i]); - printf("\n"); -} - -// Driver program to test above function -int main() -{ - int arr[] = {5, 21, 7, 23, 19}; - int n = sizeof(arr)/sizeof(arr[0]); - printf("Given Array is\n"); - printArray(arr, n); - - timSort(arr, n); - - printf("After Sorting Array is\n"); - printArray(arr, n); - return 0; -} diff --git a/Sorting/combsort.cpp b/Sorting/combsort.cpp deleted file mode 100644 index 7aa65ab80c2..00000000000 --- a/Sorting/combsort.cpp +++ /dev/null @@ -1,51 +0,0 @@ -//Kind of better version of Bubble sort. -//While Bubble sort is comparering adjacent value, Combsort is using gap larger than 1 -//Best case: O(n) -//Worst case: O(n ^ 2) - -#include - -using namespace std; - -int a[100005]; -int n; - -int FindNextGap(int x) { - x = (x * 10) / 13; - - return max(1, x); -} - -void CombSort(int a[], int l, int r) { - //Init gap - int gap = n; - - //Initialize swapped as true to make sure that loop runs - bool swapped = true; - - //Keep running until gap = 1 or none elements were swapped - while (gap != 1 || swapped) { - //Find next gap - gap = FindNextGap(gap); - - swapped = false; - - // Compare all elements with current gap - for(int i = l; i <= r - gap; ++i) { - if (a[i] > a[i + gap]) { - swap(a[i], a[i + gap]); - swapped = true; - } - } - } -} - -int main() { - cin >> n; - for(int i = 1; i <= n; ++i) cin >> a[i]; - - CombSort(a, 1, n); - - for(int i = 1; i <= n; ++i) cout << a[i] << ' '; - return 0; -} diff --git a/backtracking/CMakeLists.txt b/backtracking/CMakeLists.txt new file mode 100644 index 00000000000..f636edae503 --- /dev/null +++ b/backtracking/CMakeLists.txt @@ -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} ) diff --git a/backtracking/generate_parentheses.cpp b/backtracking/generate_parentheses.cpp new file mode 100644 index 00000000000..8a9e3b3301d --- /dev/null +++ b/backtracking/generate_parentheses.cpp @@ -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 /// for assert +#include /// for I/O operation +#include /// for vector container + +/** + * @brief Backtracking algorithms + * @namespace backtracking + */ +namespace backtracking { +/** + * @brief generate_parentheses class + */ +class generate_parentheses { + private: + std::vector res; ///< Contains all possible valid patterns + + void makeStrings(std::string str, int n, int closed, int open); + + public: + std::vector 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 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 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; +} diff --git a/backtracking/graph_coloring.cpp b/backtracking/graph_coloring.cpp new file mode 100644 index 00000000000..e5fada991bb --- /dev/null +++ b/backtracking/graph_coloring.cpp @@ -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 /// for std::array +#include /// 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 +void printSolution(const std::array& 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 +bool isSafe(int v, const std::array, V>& graph, + const std::array& 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 +void graphColoring(const std::array, V>& graph, int m, + std::array color, int v) { + // base case: + // If all vertices are assigned a color then return true + if (v == V) { + printSolution(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, graph, color, c)) { + color[v] = c; + + // recur to assign colors to rest of the vertices + graphColoring(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, V> graph = { + std::array({0, 1, 1, 1}), std::array({1, 0, 1, 0}), + std::array({1, 1, 0, 1}), std::array({1, 0, 1, 0})}; + + int m = 3; // Number of colors + std::array color{}; + + backtracking::graph_coloring::graphColoring(graph, m, color, 0); + return 0; +} diff --git a/backtracking/knight_tour.cpp b/backtracking/knight_tour.cpp new file mode 100644 index 00000000000..0223462db7b --- /dev/null +++ b/backtracking/knight_tour.cpp @@ -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 /// for std::array +#include /// 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 +bool issafe(int x, int y, const std::array, 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 +bool solve(int x, int y, int mov, std::array, V> &sol, + const std::array &xmov, std::array &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(xnext, ynext, sol)) { + sol[xnext][ynext] = mov; + + if (solve(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, 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 xmov = {2, 1, -1, -2, -2, -1, 1, 2}; + std::array ymov = {1, 2, 2, 1, -1, -2, -2, -1}; + + sol[0][0] = 0; + + bool flag = backtracking::knight_tour::solve(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; +} diff --git a/backtracking/magic_sequence.cpp b/backtracking/magic_sequence.cpp new file mode 100644 index 00000000000..478dd28dc6f --- /dev/null +++ b/backtracking/magic_sequence.cpp @@ -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 /// for std::count +#include /// for assert +#include /// for IO operations +#include /// for std::list +#include /// for std::accumulate +#include /// 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; ///< 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(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* 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 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; +} diff --git a/backtracking/minimax.cpp b/backtracking/minimax.cpp new file mode 100644 index 00000000000..b27c85e1047 --- /dev/null +++ b/backtracking/minimax.cpp @@ -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 /// for std::max, std::min +#include /// for std::array +#include /// for log2 +#include /// 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 +int minimax(int depth, int node_index, bool is_max, + const std::array &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 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; +} diff --git a/backtracking/n_queens.cpp b/backtracking/n_queens.cpp new file mode 100644 index 00000000000..f9742eb7a53 --- /dev/null +++ b/backtracking/n_queens.cpp @@ -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 +#include + +/** + * @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 +void printSolution(const std::array, 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 +bool isSafe(const std::array, 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 +void solveNQ(std::array, n> board, const int &col) { + if (col >= n) { + printSolution(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(board, i, col)) { + // Place this queen in matrix + board[i][col] = 1; + + // Recursive to place rest of the queens + solveNQ(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, n> board = { + std::array({0, 0, 0, 0}), std::array({0, 0, 0, 0}), + std::array({0, 0, 0, 0}), std::array({0, 0, 0, 0})}; + + backtracking::n_queens::solveNQ(board, 0); + return 0; +} diff --git a/backtracking/n_queens_all_solution_optimised.cpp b/backtracking/n_queens_all_solution_optimised.cpp new file mode 100644 index 00000000000..525d4c2db18 --- /dev/null +++ b/backtracking/n_queens_all_solution_optimised.cpp @@ -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 +#include + +/** + * @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 +void PrintSol(const std::array, 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 +bool CanIMove(const std::array, 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 +void NQueenSol(std::array, 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_optimized +} // namespace backtracking + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + const int n = 4; + std::array, 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; +} diff --git a/backtracking/nqueen_print_all_solutions.cpp b/backtracking/nqueen_print_all_solutions.cpp new file mode 100644 index 00000000000..8824cf0a828 --- /dev/null +++ b/backtracking/nqueen_print_all_solutions.cpp @@ -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 /// for std::array +#include /// 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 +void PrintSol(const std::array, 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 +bool CanIMove(const std::array, 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 +void NQueenSol(std::array, 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, n> board{0}; + + backtracking::n_queens_all_solutions::NQueenSol(board, 0); +} diff --git a/backtracking/rat_maze.cpp b/backtracking/rat_maze.cpp new file mode 100644 index 00000000000..60bc521c88f --- /dev/null +++ b/backtracking/rat_maze.cpp @@ -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 /// for std::array +#include /// for assert +#include /// 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 +bool solveMaze(int currposrow, int currposcol, + const std::array, size> &maze, + std::array, 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, size> maze = { + std::array{1, 0, 1, 0}, std::array{1, 0, 1, 1}, + std::array{1, 0, 0, 1}, std::array{1, 1, 1, 1}}; + + std::array, 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(currposrow, currposcol, maze, + soln) == 1); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} diff --git a/backtracking/subarray_sum.cpp b/backtracking/subarray_sum.cpp new file mode 100644 index 00000000000..ba9834e87a6 --- /dev/null +++ b/backtracking/subarray_sum.cpp @@ -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 /// for assert +#include +#include /// for IO operations +#include /// for unordered_map +#include /// 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 &in_arr) { + int64_t nelement = in_arr.size(); + int64_t count_of_subset = 0; + int64_t current_sum = 0; + std::unordered_map + 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 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 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 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 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 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; +} diff --git a/backtracking/subset_sum.cpp b/backtracking/subset_sum.cpp new file mode 100644 index 00000000000..8551a66e0ca --- /dev/null +++ b/backtracking/subset_sum.cpp @@ -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 /// for assert +#include +#include /// for IO operations +#include /// 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 &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 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 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 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 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 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; +} diff --git a/backtracking/sudoku_solver.cpp b/backtracking/sudoku_solver.cpp new file mode 100644 index 00000000000..38ccfa0b4dc --- /dev/null +++ b/backtracking/sudoku_solver.cpp @@ -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 /// for assert +#include /// 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 +bool isPossible(const std::array, 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 +void printMat(const std::array, V> &mat, + const std::array, 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 +bool solveSudoku(std::array, V> &mat, + const std::array, V> &starting_mat, int i, + int j) { + /// Base Case + if (i == 9) { + /// Solved for 9 rows already + printMat(mat, starting_mat, 9); + return true; + } + + /// Crossed the last Cell in the row + if (j == 9) { + return solveSudoku(mat, starting_mat, i + 1, 0); + } + + /// Blue Cell - Skip + if (mat[i][j] != 0) { + return solveSudoku(mat, starting_mat, i, j + 1); + } + /// White Cell + /// Try to place every possible no + for (int no = 1; no <= 9; no++) { + if (isPossible(mat, i, j, no, 9)) { + /// Place the 'no' - assuming a solution will exist + mat[i][j] = no; + bool solution_found = solveSudoku(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, V> mat = { + std::array{5, 3, 0, 0, 7, 0, 0, 0, 0}, + std::array{6, 0, 0, 1, 9, 5, 0, 0, 0}, + std::array{0, 9, 8, 0, 0, 0, 0, 6, 0}, + std::array{8, 0, 0, 0, 6, 0, 0, 0, 3}, + std::array{4, 0, 0, 8, 0, 3, 0, 0, 1}, + std::array{7, 0, 0, 0, 2, 0, 0, 0, 6}, + std::array{0, 6, 0, 0, 0, 0, 2, 8, 0}, + std::array{0, 0, 0, 4, 1, 9, 0, 0, 5}, + std::array{0, 0, 0, 0, 8, 0, 0, 7, 9}}; + + backtracking::sudoku_solver::printMat(mat, mat, 9); + std::cout << "Solution " << std::endl; + std::array, V> starting_mat = mat; + backtracking::sudoku_solver::solveSudoku(mat, starting_mat, 0, 0); + + return 0; +} diff --git a/backtracking/wildcard_matching.cpp b/backtracking/wildcard_matching.cpp new file mode 100644 index 00000000000..cd0bd72ad8c --- /dev/null +++ b/backtracking/wildcard_matching.cpp @@ -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 /// for assert +#include +#include /// for IO operations +#include /// 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> dpTable(1000, std::vector(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; +} diff --git a/bit_manipulation/CMakeLists.txt b/bit_manipulation/CMakeLists.txt new file mode 100644 index 00000000000..f5e304cfbd7 --- /dev/null +++ b/bit_manipulation/CMakeLists.txt @@ -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} ) diff --git a/bit_manipulation/count_bits_flip.cpp b/bit_manipulation/count_bits_flip.cpp new file mode 100644 index 00000000000..2ab2ce31c15 --- /dev/null +++ b/bit_manipulation/count_bits_flip.cpp @@ -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 /// for assert +#include +#include /// 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; +} diff --git a/bit_manipulation/count_of_set_bits.cpp b/bit_manipulation/count_of_set_bits.cpp new file mode 100644 index 00000000000..dd29fd8bf19 --- /dev/null +++ b/bit_manipulation/count_of_set_bits.cpp @@ -0,0 +1,83 @@ +/** + * @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 /// for assert +#include +#include /// 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 ::int64_t n) { // int64_t is preferred over int so that + // no Overflow can be there. + + int count = 0; // "count" variable is used to count number of set-bits('1') + // in binary representation of number 'n' + 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; +} diff --git a/bit_manipulation/count_of_trailing_ciphers_in_factorial_n.cpp b/bit_manipulation/count_of_trailing_ciphers_in_factorial_n.cpp new file mode 100644 index 00000000000..c1c57d0a617 --- /dev/null +++ b/bit_manipulation/count_of_trailing_ciphers_in_factorial_n.cpp @@ -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 /// for assert +#include +#include /// 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(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; +} diff --git a/bit_manipulation/find_non_repeating_number.cpp b/bit_manipulation/find_non_repeating_number.cpp new file mode 100644 index 00000000000..cc63d29cc70 --- /dev/null +++ b/bit_manipulation/find_non_repeating_number.cpp @@ -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 /// for assert +#include /// for IO operations +#include /// 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& 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 nums_one{1, 1, 2, 2, 4, 5, 5}; + std::vector nums_two{203, 3434, 4545, 3434, 4545}; + std::vector 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; +} diff --git a/bit_manipulation/gray_code.cpp b/bit_manipulation/gray_code.cpp new file mode 100644 index 00000000000..952758dea23 --- /dev/null +++ b/bit_manipulation/gray_code.cpp @@ -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 /// for gray code representation +#include /// for assert +#include /// for IO operations +#include /// 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> gray_code_generation(int n) { + std::vector> 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> gray_code_negative_1 = {}; + + std::vector> gray_code_0 = {}; + + std::vector> gray_code_1 = { + std::bitset<32>(0), std::bitset<32>(1) + }; + + std::vector> gray_code_2 = { + std::bitset<32>(0), std::bitset<32>(1), std::bitset<32>(3), std::bitset<32>(2) + }; + + std::vector> 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> 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> 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; +} diff --git a/bit_manipulation/hamming_distance.cpp b/bit_manipulation/hamming_distance.cpp new file mode 100644 index 00000000000..ca4e9fc5b36 --- /dev/null +++ b/bit_manipulation/hamming_distance.cpp @@ -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 /// for assert +#include +#include /// 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; +} diff --git a/bit_manipulation/next_higher_number_with_same_number_of_set_bits.cpp b/bit_manipulation/next_higher_number_with_same_number_of_set_bits.cpp new file mode 100644 index 00000000000..f6d840f91bd --- /dev/null +++ b/bit_manipulation/next_higher_number_with_same_number_of_set_bits.cpp @@ -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 /// for assert +#include +#include /// 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(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; +} diff --git a/bit_manipulation/power_of_2.cpp b/bit_manipulation/power_of_2.cpp new file mode 100644 index 00000000000..f35361c8a9d --- /dev/null +++ b/bit_manipulation/power_of_2.cpp @@ -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 /// for assert +#include +#include /// 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; +} diff --git a/bit_manipulation/set_kth_bit.cpp b/bit_manipulation/set_kth_bit.cpp new file mode 100644 index 00000000000..d3d50e6cb28 --- /dev/null +++ b/bit_manipulation/set_kth_bit.cpp @@ -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 /// for assert +#include +#include /// 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; +} diff --git a/bit_manipulation/travelling_salesman_using_bit_manipulation.cpp b/bit_manipulation/travelling_salesman_using_bit_manipulation.cpp new file mode 100644 index 00000000000..9858b8107a3 --- /dev/null +++ b/bit_manipulation/travelling_salesman_using_bit_manipulation.cpp @@ -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 /// for std::min +#include /// for assert +#include +#include /// for IO operations +#include /// for limits of integral types +#include /// 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> + 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> + &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> dist = { + {0, 20, 42, 35}, {20, 0, 30, 34}, {42, 30, 0, 12}, {35, 34, 12, 0}}; + uint32_t V = dist.size(); + std::vector> dp(1 << V, std::vector(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> dp1(1 << V, + std::vector(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> dp2(1 << V, + std::vector(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; +} diff --git a/ciphers/CMakeLists.txt b/ciphers/CMakeLists.txt new file mode 100644 index 00000000000..1efde308787 --- /dev/null +++ b/ciphers/CMakeLists.txt @@ -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} ) diff --git a/ciphers/a1z26_cipher.cpp b/ciphers/a1z26_cipher.cpp new file mode 100644 index 00000000000..82a3d3bb4e0 --- /dev/null +++ b/ciphers/a1z26_cipher.cpp @@ -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 /// for std::transform and std::replace +#include /// for assert +#include /// for uint8_t +#include /// for IO operations +#include /// for std::map +#include /// for std::stringstream +#include /// for std::string +#include /// 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 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 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 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 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; +} diff --git a/ciphers/atbash_cipher.cpp b/ciphers/atbash_cipher.cpp new file mode 100644 index 00000000000..4f0d793f237 --- /dev/null +++ b/ciphers/atbash_cipher.cpp @@ -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 /// for assert +#include /// for IO operations +#include /// for std::map +#include /// 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 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; +} diff --git a/ciphers/base64_encoding.cpp b/ciphers/base64_encoding.cpp new file mode 100644 index 00000000000..81459408a8e --- /dev/null +++ b/ciphers/base64_encoding.cpp @@ -0,0 +1,201 @@ +/** + * @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 /// for `std::array` +#include /// for `assert` operations +#include +#include /// 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( + (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(((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(((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; +} diff --git a/ciphers/caesar_cipher.cpp b/ciphers/caesar_cipher.cpp new file mode 100644 index 00000000000..6c5bba15fea --- /dev/null +++ b/ciphers/caesar_cipher.cpp @@ -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 +#include +#include + +/** \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; +} diff --git a/ciphers/elliptic_curve_key_exchange.cpp b/ciphers/elliptic_curve_key_exchange.cpp new file mode 100644 index 00000000000..0a9ce3cd0e3 --- /dev/null +++ b/ciphers/elliptic_curve_key_exchange.cpp @@ -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 /// for assert +#include /// 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; +} diff --git a/ciphers/hill_cipher.cpp b/ciphers/hill_cipher.cpp new file mode 100644 index 00000000000..d77a51c22b3 --- /dev/null +++ b/ciphers/hill_cipher.cpp @@ -0,0 +1,544 @@ +/** + * @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 +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef _OPENMP +#include +#endif + +#include "../numerical_methods/lu_decomposition.h" + +/** + * operator to print a matrix + */ +template +static std::ostream &operator<<(std::ostream &out, matrix 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 + static const T2 rand_range(T1 a, T1 b) { + // generate random number between 0 and 1 + long double r = static_cast(std::rand()) / RAND_MAX; + + // scale and return random number as integer + return static_cast(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 + static double rand_range(matrix *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(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 + 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 mat_mul( + const std::valarray &vector, const matrix &key) { + std::valarray 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(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 &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 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 + static matrix get_inverse(matrix const &A) { + // Assuming A is square matrix + size_t N = A.size(); + + matrix inverse(N, std::valarray(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 temp(N, std::valarray(N)); + for (size_t row = 0; row < N; row++) { + for (size_t col = 0; col < N; col++) + temp[row][col] = static_cast(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 generate_encryption_key(size_t size, int limit1 = 0, + int limit2 = 10) { + matrix encrypt_key(size, std::valarray(size)); + matrix 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(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 generate_decryption_key(matrix const &encrypt_key) { + size_t size = encrypt_key.size(); + int L = std::strlen(STRKEY); + + matrix decrypt_key(size, std::valarray(size)); + int det_encrypt = static_cast(determinant_lu(encrypt_key)); + + int mat_determinant = det_encrypt < 0 ? det_encrypt % L : det_encrypt; + + matrix tmp_inverse = get_inverse(encrypt_key); + double d2 = determinant_lu(decrypt_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> encryption and decryption + * keys as a pair + * + * @see ::generate_encryption_key + */ + static std::pair, matrix> generate_keys(size_t size, + int limit1 = 0, + int limit2 = 10) { + matrix encrypt_key = generate_encryption_key(size); + matrix 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 &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 &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> p = + ciphers::HillCipher::generate_keys(3, 0, 100); + matrix ekey = p.first; + matrix dkey = p.second; + + // matrix 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 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> p = + ciphers::HillCipher::generate_keys(8, 0, 3); + matrix ekey = p.first; + matrix 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; +} diff --git a/ciphers/morse_code.cpp b/ciphers/morse_code.cpp new file mode 100644 index 00000000000..f8ff51c5c1d --- /dev/null +++ b/ciphers/morse_code.cpp @@ -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 +#include +#include +#include + +/** \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 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; +} diff --git a/ciphers/uint128_t.hpp b/ciphers/uint128_t.hpp new file mode 100644 index 00000000000..7abffb08a61 --- /dev/null +++ b/ciphers/uint128_t.hpp @@ -0,0 +1,1107 @@ +/** + * @file + * + * @details Implementation of 128-bit unsigned integers. + * @note The implementation can be flagged as not completed. This header is used + * with enough operations as a part of bigger integer types 256-bit integer. + * @author [Ashish Daulatabad](https://github.com/AshishYUO) + */ + +#include /// for `std::reverse` and other operations +#include +#include /// for `std::cout` overload +#include /// for `std::string` +#include /// for `std::pair` library + +#ifdef _MSC_VER +#include /// for _BitScanForward64 and __BitScanReverse64 operation +#endif + +#ifndef CIPHERS_UINT128_T_HPP_ +#define CIPHERS_UINT128_T_HPP_ +class uint128_t; + +template <> +struct std::is_integral : std::true_type {}; +template <> +struct std::is_arithmetic : std::true_type {}; +template <> +struct std::is_unsigned : std::true_type {}; + +/** + * @brief Adding two string + * @details Adds two long integer, only used for printing numbers + * @param first First integer string + * @param second Second integer string + * @returns string denoting the addition of both the strings + */ +std::string add(const std::string &first, const std::string &second) { + std::string third; + int16_t sum = 0, carry = 0; + for (int32_t i = static_cast(first.size()) - 1, + j = static_cast(second.size()) - 1; + i >= 0 || j >= 0; --i, --j) { + sum = ((i >= 0 ? first[i] - '0' : 0) + (j >= 0 ? second[j] - '0' : 0) + + carry); + carry = sum / 10; + sum %= 10; + third.push_back(sum + '0'); + } + if (carry) { + third.push_back('1'); + } + std::reverse(third.begin(), third.end()); + return third; +} +/** + * @class uint128_t + * @brief class for 128-bit unsigned integer + */ +class uint128_t { + uint64_t f{}, s{}; /// First and second half of 128 bit number + + /** + * @brief Get integer from given string. + * @details Create an integer from a given string + * @param str integer string, can be hexadecimal (starting on 0x... or + * number) + * @returns void + */ + void __get_integer_from_string(const std::string &str) { + this->f = this->s = 0; + if (str.size() > 1 && str[1] == 'x') { // if hexadecimal + for (auto i = 2; i < str.size(); ++i) { + *this *= 16LL; + if (str[i] >= '0' && str[i] <= '9') { + *this += (str[i] - '0'); + } else if (str[i] >= 'A' && str[i] <= 'F') { + *this += (str[i] - 'A' + 10); + } else if (str[i] >= 'a' && str[i] <= 'f') { + *this += (str[i] - 'a' + 10); + } + } + } else { // if decimal + for (auto &x : str) { + *this *= 10LL; + *this += (x - '0'); + } + } + } + + public: + uint128_t() = default; + + /** + * @brief Parameterized constructor + * @tparam T integral type + * @param low lower part 8-bit unisgned integer + */ + template ::value, T>::type> + explicit uint128_t(T low) : s(low) {} + + /** + * @brief Parameterized constructor + * @param str Integer string (hexadecimal starting with 0x.. or decimal) + */ + explicit uint128_t(const std::string &str) { + __get_integer_from_string(str); + } + + /** + * @brief Parameterized constructor + * @param high higher part 64-bit unsigned integer + * @param low lower part 64-bit unsigned integer + */ + uint128_t(const uint64_t high, const uint64_t low) : f(high), s(low) {} + + /** + * @brief Copy constructor + * @param num 128-bit unsigned integer + */ + uint128_t(const uint128_t &num) = default; + + /** + * @brief Move constructor + * @param num 128-bit unsigned integer + */ + uint128_t(uint128_t &&num) noexcept : f(num.f), s(num.s) {} + + /** + * @brief Destructor for uint128_t + */ + ~uint128_t() = default; + + /** + * @brief Leading zeroes in binary + * @details Calculates leading zeros in 128-bit integer + * @returns Integer denoting leading zeroes + */ + inline uint32_t _lez() { +#ifndef _MSC_VER + if (f) { + return __builtin_clzll(f); + } + return 64 + __builtin_clzll(s); +#else + unsigned long r = 0; + _BitScanForward64(&r, f); + if (r == 64) { + unsigned long l = 0; + _BitScanForward64(&l, s); + return 64 + l; + } + return r; +#endif + } + + /** + * @brief Trailing zeroes in binary + * @details Calculates leading zeros in 128-bit integer + * @returns Integer denoting Trailing zeroes + */ + inline uint32_t _trz() { +#ifndef _MSC_VER + if (f) { + return __builtin_ctzll(f); + } + return 64 + __builtin_ctzll(s); +#else + unsigned long r = 0; + _BitScanReverse64(&r, s); + if (r == 64) { + unsigned long l = 0; + _BitScanReverse64(&l, f); + return 64 + l; + } + return r; +#endif + } + + /** + * @brief casting operator to boolean value + * @returns true if value of this is non-zero, else false + */ + inline explicit operator bool() const { return (f || s); } + + /** + * @brief casting operator to any integer valu + * @tparam T any integer type + * @returns integer value casted to mentioned type + */ + template ::value, T>::type> + inline explicit operator T() const { + return static_cast(s); + } + + /** + * @brief returns lower 64-bit integer part + * @returns returns lower 64-bit integer part + */ + inline uint64_t lower() const { return s; } + + /** + * @brief returns upper 64-bit integer part + * @returns returns upper 64-bit integer part + */ + inline uint64_t upper() const { return f; } + + /** + * @brief operator = for other types + * @tparam T denoting any integer type + * @param p an integer to assign it's value + * @returns this pointer with it's value equal to `p` + */ + template ::value, T>::type> + inline uint128_t &operator=(const T &p) { + this->s = p; + return *this; + } + + /** + * @brief operator = for type string + * @param p a string to assign it's value to equivalent integer + * @returns this pointer with it's value equal to `p` + */ + inline uint128_t &operator=(const std::string &p) { + this->__get_integer_from_string(p); + return *this; + } + + /** + * @brief operator = for uint128_t + * @param p an 128-bit integer to assign it's value + * @returns this pointer with it's value equal to `p` + */ + inline uint128_t &operator=(const uint128_t &p) = default; + + /** + * @brief Move assignment operator + */ + inline uint128_t &operator=(uint128_t &&p) = default; + + /** + * @brief operator + for uint128_t and other integer types. + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns addition of this and p, returning uint128_t integer + */ + template ::value, T>::type> + inline uint128_t operator+(const T p) { + return uint128_t(f + (p + s < s), p + s); + } + + /** + * @brief operator + for uint128_t and other integer types. + * @param p 128-bit unsigned integer + * @returns addition of this and p, returning uint128_t integer + */ + inline uint128_t operator+(const uint128_t &p) { + return uint128_t(f + (p.s + s < s) + p.f, p.s + s); + } + + /** + * @brief operator += for uint128_t and other integer types. + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns addition of this and p, returning this + */ + template ::value, T>::type> + inline uint128_t &operator+=(const T p) { + bool app = p + s < s; + this->f += app; + this->s += p; + return *this; + } + + /** + * @brief operator += for uint128_t + * @param p 128-bit unsigned integer + * @returns addition of this and p, returning this + */ + uint128_t &operator+=(const uint128_t &p) { + bool app = p.s + s < s; + f = f + app + p.f; + s = p.s + s; + return *this; + } + + /** + * @brief pre-increment operator + * @returns incremented value of this. + */ + inline uint128_t &operator++() { + *this += 1; + return *this; + } + + /** + * @brief post-increment operator + * @returns incremented value of this. + */ + inline uint128_t operator++(int) { + ++*this; + return *this; + } + + /** + * @brief operator - for uint128_t and other integer types. + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns subtraction of this and p, returning uint128_t integer + */ + template ::value, T>::type> + inline uint128_t operator-(const T &p) { + bool app = p > s; + return uint128_t(f - app, s - p); + } + + /** + * @brief operator - for uint128_t + * @param p a type of integer variable + * @returns subtraction of this and p, returning uint128_t integer + */ + inline uint128_t operator-(const uint128_t &p) { + bool app = p.s > s; + return uint128_t(f - p.f - app, s - p.s); + } + + /** + * @brief operator - using twos complement + * @returns 2's complement of this. + */ + inline uint128_t operator-() { return ~*this + uint128_t(1); } + + /** + * @brief operator -- (pre-decrement) + * @returns decremented value of this + */ + inline uint128_t &operator--() { + *this -= 1; + return *this; + } + + /** + * @brief operator -- (post-decrement) + * @returns decremented value of this + */ + inline uint128_t operator--(int p) { + --*this; + return *this; + } + + /** + * @brief operator -= for uint128_t and other integer types. + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns subtraction of this and p, returning this + */ + template ::value, T>::type> + uint128_t &operator-=(const T &p) { + bool app = p > s; + f -= app; + s -= p; + return *this; + } + + /** + * @brief operator -= for uint128_t + * @param p 128-bit unsigned integer + * @returns subtraction of this and p, returning this + */ + uint128_t &operator-=(const uint128_t &p) { + bool app = p.s > s; + f = f - p.f - app; + s = s - p.s; + return *this; + } + + /** + * @brief operator * for uint128_t and other integer types. + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns multiplication of this and p, returning uint128_t integer + */ + template ::value, T>::type> + inline uint128_t operator*(const T p) { + return *this * uint128_t(p); + } + + /** + * @brief operator * for uint128_t and other integer types. + * @param p 128-bit unsigned integer + * @returns multiplication of this and p, returning uint128_t integer + */ + uint128_t operator*(const uint128_t &p) { + uint64_t f_first = s >> 32, f_second = s & 0xFFFFFFFF, + s_first = p.s >> 32, s_second = p.s & 0xFFFFFFFF; + uint64_t fi = f_first * s_first, se = f_first * s_second, + th = s_first * f_second, fo = s_second * f_second; + uint64_t tmp = ((se & 0xFFFFFFFF) << 32), tmp2 = (th & 0xFFFFFFFF) + << 32; + int cc = (tmp + tmp2 < tmp); + tmp += tmp2; + cc += (tmp + fo < tmp); + uint64_t carry = fi + (se >> 32) + (th >> 32); + return uint128_t(this->f * p.s + this->s * p.f + carry + cc, tmp + fo); + } + + /** + * @brief operator *= for uint128_t and other integer types. + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns multiplication of this and p, returning this + */ + template ::value, T>::type> + inline uint128_t &operator*=(const T p) { + *this *= uint128_t(p); + return *this; + } + + /** + * @brief operator *= for uint128_t and other integer types. + * @param p 128-bit unsigned integer + * @returns multiplication of this and p, returning this + */ + uint128_t &operator*=(const uint128_t &p) { + uint64_t f_first = s >> 32, f_second = s & 0xFFFFFFFF, + s_first = p.s >> 32, s_second = p.s & 0xFFFFFFFF; + uint64_t fi = f_first * s_first, se = f_first * s_second, + th = s_first * f_second, fo = s_second * f_second; + uint64_t tmp = (se << 32), tmp2 = (th << 32); + int cc = (tmp + tmp2 < tmp); + tmp += tmp2; + cc += (tmp + fo < tmp); + uint64_t carry = fi + (se >> 32) + (th >> 32); + f = this->f * p.s + this->s * p.f + carry + cc; + s = tmp + fo; + return *this; + } + + /** + * @brief divide function for uint128_t and other integer types. + * @details divide this value and + * @param p 128-bit unsigned integer + * @returns pair denoting quotient and remainder. + */ + std::pair divide(const uint128_t &p) { + if (*this < p) { // if this is less than divisor + return {uint128_t(0), *this}; + } else if (*this == p) { // if this is equal to divisor + return {uint128_t(1), uint128_t(0)}; + } + uint128_t tmp = p, tmp2 = *this; + uint16_t left = tmp._lez() - _lez(); + tmp <<= left; + uint128_t quotient(0); + uint128_t zero(0); + while (tmp2 >= p) { + uint16_t shf = tmp2._lez() - tmp._lez(); + if (shf) { + tmp >>= shf; + quotient <<= shf; + left -= shf; + } + if (tmp2 < tmp) { + tmp >>= 1; + quotient <<= 1; + --left; + } + tmp2 -= tmp; + ++quotient; + } + return {quotient << left, tmp2}; + } + + /** + * @brief operator / for uint128_t and other integer types. + * @param p 128-bit unsigned integer + * @returns unsigned 128-bit quotient. + */ + inline uint128_t operator/(const uint128_t &p) { return divide(p).first; } + + /** + * @brief operator / for uint128_t and other integer types. + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns unsigned 128-bit quotient. + */ + template ::value, T>::type> + inline uint128_t operator/(const T p) { + uint128_t tmp = *this; + tmp /= uint128_t(0, p); + return tmp; + } + + /** + * @brief operator /= for uint128_t + * @param p 128-bit unsigned integer + * @returns this set as unsigned 128-bit quotient. + */ + inline uint128_t &operator/=(const uint128_t &p) { + *this = divide(p).first; + return *this; + } + + /** + * @brief operator /= for uint128_t and other integer types. + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns this set as unsigned 128-bit quotient. + */ + template ::value, T>::type> + inline uint128_t &operator/=(const T p) { + *this /= uint128_t(0, p); + return *this; + } + + /** + * @brief operator % for uint128_t + * @param p 128-bit unsigned integer + * @returns unsigned 128-bit remainder. + */ + inline uint128_t operator%(const uint128_t &p) { return divide(p).second; } + + /** + * @brief operator % for uint128_t and other integer types. + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns unsigned 128-bit remainder. + */ + template ::value, T>::type> + inline uint128_t operator%(const T &p) { + return *this % uint128_t(p); + } + + /** + * @brief operator %= for uint128_t + * @param p 128-bit unsigned integer + * @returns this set as unsigned 128-bit remainder. + */ + inline uint128_t &operator%=(const uint128_t &p) { + *this = divide(p).second; + return *this; + } + + /** + * @brief operator %= for uint128_t + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns this set as unsigned 128-bit remainder. + */ + template ::value, T>::type> + inline uint128_t &operator%=(const T &p) { + *this %= uint128_t(p); + return *this; + } + + /** + * @brief operator < for uint128_t + * @param other number to be compared with this + * @returns true if this is less than other, else false + */ + inline bool operator<(const uint128_t &other) { + return f < other.f || (f == other.f && s < other.s); + } + + /** + * @brief operator <= for uint128_t + * @param other number to be compared with this + * @returns true if this is less than or equal to other, else false + */ + inline bool operator<=(const uint128_t &other) { + return f < other.f || (f == other.f && s <= other.s); + } + + /** + * @brief operator > for uint128_t + * @param other number to be compared with this + * @returns true if this is greater than other, else false + */ + inline bool operator>(const uint128_t &other) { + return f > other.f || (f == other.f && s > other.s); + } + + /** + * @brief operator >= for uint128_t + * @param other number to be compared with this + * @returns true if this is greater than or equal than other, else false + */ + inline bool operator>=(const uint128_t &other) { + return (f > other.f) || (f == other.f && s >= other.s); + } + + /** + * @brief operator == for uint128_t + * @param other number to be compared with this + * @returns true if this is equal than other, else false + */ + inline bool operator==(const uint128_t &other) { + return f == other.f && s == other.s; + } + + /** + * @brief operator != for uint128_t + * @param other number to be compared with this + * @returns true if this is not equal than other, else false + */ + inline bool operator!=(const uint128_t &other) { + return f != other.f || s != other.s; + } + + /** + * @brief operator ! for uint128_t + * @returns true if this has zero value, else false + */ + inline bool operator!() { return !f && !s; } + + /** + * @brief operator && for uint128_t + * @param b number to be compared with this + * @returns true if both of the values are not zero, else false + */ + inline bool operator&&(const uint128_t &b) { + return (s || f) && (b.s || b.f); + } + + /** + * @brief operator || for uint128_t + * @param b number to be compared with this + * @returns true if one of the values are not zero, else false + */ + inline bool operator||(const uint128_t &b) { + return (s || f) || (b.s || b.f); + } + + /** + * @brief operator () for uint128_t + * @returns true if this value is non-zero, else false + */ + inline bool operator()() { return s || f; } + + /** + * @brief operator < for other types + * @tparam T integral type + * @param other number to be compared with this + * @returns true if this is less than other, else false + */ + template ::value, T>::type> + inline bool operator<(const T other) { + return *this < uint128_t(other); + } + + /** + * @brief operator <= for other types + * @tparam T integral type + * @param other number to be compared with this + * @returns true if this is less than or equal to other, else false + */ + template ::value, T>::type> + inline bool operator<=(const T other) { + return *this <= uint128_t(other); + } + + /** + * @brief operator > for other types + * @tparam T integral type + * @param other number to be compared with this + * @returns true if this is greater than other, else false + */ + template ::value, T>::type> + inline bool operator>(const T other) { + return *this > uint128_t(other); + } + + /** + * @brief operator >= for other types + * @tparam T integral type + * @param other number to be compared with this + * @returns true if this is greater than or equal other, else false + */ + template ::value, T>::type> + inline bool operator>=(const T other) { + return *this >= uint128_t(other); + } + + /** + * @brief operator == for other types + * @tparam T integral type + * @param other number to be compared with this + * @returns true if this is equal to other, else false + */ + template ::value, T>::type> + inline bool operator==(const T other) { + return *this == uint128_t(other); + } + + /** + * @brief operator != for other types + * @tparam T integral type + * @param other number to be compared with this + * @returns true if this is not equal to other, else false + */ + template ::value, T>::type> + inline bool operator!=(const T other) { + return *this != uint128_t(other); + } + + /** + * @brief operator && for other types + * @tparam T integral type + * @param other number to be compared with this + * @returns true if this is both values are non-zero, else false + */ + template ::value, T>::type> + inline bool operator&&(const T b) { + return (f || s) && b; + } + + /** + * @brief operator || for other types + * @tparam T integral type + * @param other number to be compared with this + * @returns true if this is either one of the values are non-zero, else + * false + */ + template ::value, T>::type> + inline bool operator||(const T b) { + return (f || s) || b; + } + + /** + * @brief operator ~ for uint128_t + * @returns 1's complement of this number + */ + uint128_t operator~() { return uint128_t(~this->f, ~this->s); } + + /** + * @brief operator << for uint128_t + * @tparam T integral type + * @param p number denoting number of shifts + * @returns value of this shifted by p to left + */ + template ::value, T>::type> + uint128_t operator<<(const T p) { + if (!p) { + return uint128_t(f, s); + } else if (p >= 64 && p <= 128) { + return uint128_t((this->s << (p - 64)), 0); + } else if (p < 64 && p > 0) { + return uint128_t((this->f << p) + ((this->s >> (64 - p))), + this->s << p); + } + return uint128_t(0); + } + + /** + * @brief operator <<= for uint128_t + * @tparam T integral type + * @param p number denoting number of shifts + * @returns this shifted by p to left + */ + template ::value, T>::type> + uint128_t &operator<<=(const T p) { + if (p) { + if (p >= 64 && p <= 128) { + this->f = (this->s << (p - 64)); + this->s = 0; + } else { + f = ((this->f << p) + (this->s >> (64 - p))); + s = (this->s << p); + } + } + return *this; + } + + /** + * @brief operator >> for uint128_t + * @tparam T integral type + * @param p number denoting number of shifts + * @returns value of this shifted by p to right + */ + template ::value, T>::type> + uint128_t operator>>(const T p) { + if (!p) { + return uint128_t(this->f, this->s); + } else if (p >= 64 && p <= 128) { + return uint128_t(0, (this->f >> (p - 64))); + } else if (p < 64 && p > 0) { + return uint128_t((this->f >> p), + (this->s >> p) + (this->f << (64 - p))); + } + return uint128_t(0); + } + + /** + * @brief operator >>= for uint128_t + * @tparam T integral type + * @param p number denoting number of shifts + * @returns this shifted by p to right + */ + template ::value, T>::type> + uint128_t &operator>>=(const T p) { + if (p) { + if (p >= 64) { + f = 0; + s = (this->f >> (p - 64)); + } else { + s = (this->s >> p) + (this->f << (64 - p)); + f = (this->f >> p); + } + } + return *this; + } + + /** + * @brief operator & for uint128_t (bitwise operator) + * @param p number to be operated + * @returns value of this & p (& is bit-wise operator) + */ + inline uint128_t operator&(const uint128_t &p) { + return uint128_t(this->f & p.f, this->s & p.s); + } + + /** + * @brief operator & for other types (bitwise operator) + * @tparam T integral type + * @param p number to be operated + * @returns value of this & p (& is bit-wise operator) + */ + template ::value, T>::type> + uint128_t operator&(const T p) { + uint128_t tmp = *this; + return tmp & uint128_t(p); + } + + /** + * @brief operator &= for uint128_t (bitwise operator) + * @param p number to be operated + * @returns this = this & p (& is bit-wise operator) + */ + uint128_t &operator&=(const uint128_t &p) { + this->f &= p.f; + this->s &= p.s; + return *this; + } + + /** + * @brief operator &= for other types (bitwise operator) + * @tparam T integral type + * @param p number to be operated + * @returns this = this & p (& is bit-wise operator) + */ + template ::value, T>::type> + uint128_t &operator&=(const T p) { + *this &= uint128_t(p); + return *this; + } + + /** + * @brief operator | for other types (bitwise operator) + * @tparam T integral type + * @param p number to be operated + * @returns value of this | p (| is bit-wise operator) + */ + template ::value, T>::type> + inline uint128_t operator|(const T p) { + return uint128_t(p | s); + } + + /** + * @brief operator | for uint128_t (bitwise operator) + * @param p number to be operated + * @returns value of this | p (| is bit-wise OR operator) + */ + inline uint128_t operator|(const uint128_t &p) { + return uint128_t(this->f | p.f, this->s | p.s); + } + + /** + * @brief operator |= for uint128_t (bitwise operator) + * @param p number to be operated + * @returns this = this | p (| is bit-wise OR operator) + */ + uint128_t &operator|=(const uint128_t &p) { + f |= p.f; + s |= p.s; + return *this; + } + + /** + * @brief operator |= for other types (bitwise operator) + * @tparam T integral type + * @param p number to be operated + * @returns this = this | p (| is bit-wise OR operator) + */ + template ::value, T>::type> + inline uint128_t &operator|=(const T p) { + s |= p.s; + return *this; + } + + /** + * @brief operator ^ for other types (bitwise operator) + * @tparam T integral type + * @param p number to be operated + * @returns value of this ^ p (^ is bit-wise XOR operator) + */ + template ::value, T>::type> + inline uint128_t operator^(const T p) { + return uint128_t(this->f, this->s ^ p); + } + + /** + * @brief operator ^ for uint128_t (bitwise operator) + * @param p number to be operated + * @returns value of this ^ p (^ is bit-wise XOR operator) + */ + inline uint128_t operator^(const uint128_t &p) { + return uint128_t(this->f ^ p.f, this->s ^ p.s); + } + + /** + * @brief operator ^= for uint128_t (bitwise operator) + * @param p number to be operated + * @returns this = this ^ p (^ is bit-wise XOR operator) + */ + uint128_t &operator^=(const uint128_t &p) { + f ^= p.f; + s ^= p.s; + return *this; + } + + /** + * @brief operator ^= for other types (bitwise operator) + * @tparam T integral type + * @param p number to be operated + * @returns this = this ^ p (^ is bit-wise XOR operator) + */ + template ::value, T>::type> + inline uint128_t &operator^=(const T &p) { + s ^= p; + return *this; + } + + /** + * @brief operator << for printing uint128_t integer + * @details Prints the uint128_t integer in decimal form + * @note Note that this operator is costly since it uses strings to print + * the value + * @param op ostream object + * @param p 128-bit integer + * @returns op, ostream object. + */ + friend std::ostream &operator<<(std::ostream &op, const uint128_t &p) { + if (!p.f) { + op << p.s; + } else { + std::string out = "0", p_2 = "1"; + for (int i = 0; i < 64; ++i) { + if (p.s & (1LL << i)) { + out = add(out, p_2); + } + p_2 = add(p_2, p_2); + } + for (int i = 0; i < 64; ++i) { + if (p.f & (1LL << i)) { + out = add(out, p_2); + } + p_2 = add(p_2, p_2); + } + op << out; + } + return op; + } +}; + +// Arithmetic operators +template ::value, T>::type> +inline uint128_t operator+(const T &p, const uint128_t &q) { + return uint128_t(p) + q; +} + +template ::value, T>::type> +inline uint128_t operator-(const T p, const uint128_t &q) { + return uint128_t(p) - q; +} + +template ::value, T>::type> +inline uint128_t operator*(const T p, const uint128_t &q) { + return uint128_t(p) * q; +} + +template ::value, T>::type> +inline uint128_t operator/(const T p, const uint128_t &q) { + return uint128_t(p) / q; +} + +template ::value, T>::type> +inline uint128_t operator%(const T p, const uint128_t &q) { + return uint128_t(p) % q; +} + +// Bitwise operators +template ::value, T>::type> +inline uint128_t operator&(const T &p, const uint128_t &q) { + return uint128_t(p) & q; +} + +template ::value, T>::type> +inline uint128_t operator|(const T p, const uint128_t &q) { + return uint128_t(p) | q; +} + +template ::value, T>::type> +inline uint128_t operator^(const T p, const uint128_t &q) { + return uint128_t(p) ^ q; +} + +// Boolean operators +template ::value, T>::type> +inline bool operator&&(const T p, const uint128_t &q) { + return uint128_t(p) && q; +} + +template ::value, T>::type> +inline bool operator||(const T p, const uint128_t &q) { + return uint128_t(p) || q; +} + +// Comparison operators +template ::value, T>::type> +inline bool operator==(const T p, const uint128_t &q) { + return uint128_t(p) == q; +} + +template ::value, T>::type> +inline bool operator!=(const T p, const uint128_t &q) { + return uint128_t(p) != q; +} + +template ::value, T>::type> +inline bool operator<(const T p, const uint128_t &q) { + return uint128_t(p) < q; +} + +template ::value, T>::type> +inline bool operator<=(const T p, const uint128_t &q) { + return uint128_t(p) <= q; +} + +template ::value, T>::type> +inline bool operator>(const T p, const uint128_t &q) { + return uint128_t(p) > q; +} + +template ::value, T>::type> +inline bool operator>=(const T p, const uint128_t &q) { + return uint128_t(p) >= q; +} + +#endif // CIPHERS_UINT128_T_HPP_ diff --git a/ciphers/uint256_t.hpp b/ciphers/uint256_t.hpp new file mode 100644 index 00000000000..a776d4cb0e4 --- /dev/null +++ b/ciphers/uint256_t.hpp @@ -0,0 +1,1074 @@ +/** + * @file + * + * @details Implementation of 256-bit unsigned integers. + * @note The implementation can be flagged as not completed. This header is used + * with enough operations to demonstrate the usage of ECDH (Elliptic Curve + * Diffie-Hellman) Key exchange. + * @author [Ashish Daulatabad](https://github.com/AshishYUO) + */ +#include /// for `std::string` +#include /// for `std::pair` library + +#include "uint128_t.hpp" /// for uint128_t integer + +#ifndef CIPHERS_UINT256_T_HPP_ +#define CIPHERS_UINT256_T_HPP_ + +class uint256_t; + +template <> +struct std::is_integral : std::true_type {}; + +template <> +struct std::is_arithmetic : std::true_type {}; + +template <> +struct std::is_unsigned : std::true_type {}; + +/** + * @class uint256_t + * @brief class for 256-bit unsigned integer + */ +class uint256_t { + uint128_t f{}, s{}; /// First and second half of 256 bit number + + /** + * @brief Get integer from given string. + * @details Create an integer from a given string + * @param str integer string, can be hexadecimal (starting on 0x... or + * number) + * @returns void + */ + void __get_integer_from_string(const std::string &str) { + this->f = this->s = uint128_t(0); + if (str.size() > 1 && str[1] == 'x') { + for (auto i = 2; i < str.size(); ++i) { + *this *= 16LL; + if (str[i] >= '0' && str[i] <= '9') { + *this += (str[i] - '0'); + } else if (str[i] >= 'A' && str[i] <= 'F') { + *this += (str[i] - 'A' + 10); + } else if (str[i] >= 'a' && str[i] <= 'f') { + *this += (str[i] - 'a' + 10); + } + } + } else { + for (auto &x : str) { + *this *= 10LL; + *this += (x - '0'); + } + } + } + + public: + // Constructors + uint256_t() = default; + + /** + * @brief Parameterized constructor + * @tparam T template for integer types + * @param low Integer denoting lower 128-bits + */ + template ::value, T>::type> + explicit uint256_t(T low) : s(low), f(0) {} + + /** + * @brief Parameterized constructor + * @param str Integer string (hexadecimal starting with 0x.. or decimal) + */ + explicit uint256_t(const std::string &str) { + __get_integer_from_string(str); + } + + /** + * @brief Copy constructor + * @param num 256-bit unsigned integer + */ + uint256_t(const uint256_t &num) = default; + + /** + * @brief Move constructor + * @param num 256-bit unsigned integer + */ + uint256_t(uint256_t &&num) noexcept + : f(std::move(num.f)), s(std::move(num.s)) {} + + /** + * @brief Parameterized constructor + * @param high higher part 128-bit unsigned integer + * @param low lower part 128-bit unsigned integer + */ + uint256_t(uint128_t high, uint128_t low) + : f(std::move(high)), s(std::move(low)) {} + + /** + * @brief Parameterized constructor + * @param high higher part 64-bit unsigned integer + * @param low lower part 64-bit unsigned integer + */ + uint256_t(const uint64_t high, const uint64_t low) : f(high), s(low) {} + + /** + * @brief Destructor for uint256_t + */ + ~uint256_t() = default; + + /** + * @brief Leading zeroes in binary + * @details Calculates leading zeros in 256-bit integer + * @returns Integer denoting leading zeroes + */ + inline uint32_t _lez() { + if (f) { + return f._lez(); + } + return 128 + s._lez(); + } + + /** + * @brief Trailing zeroes in binary + * @details Calculates leading zeros in 256-bit integer + * @returns Integer denoting Trailing zeroes + */ + inline uint32_t _trz() { + if (s) { + return s._trz(); + } + return 128 + f._trz(); + } + + /** + * @brief casting operator to boolean value + * @returns true if value of this is non-zero, else false + */ + inline explicit operator bool() const { return f || s; } + + /** + * @brief casting operator to any integer value + * @tparam T any integer type + * @returns integer value casted to mentioned type + */ + template ::value, T>::type> + inline explicit operator T() const { + return static_cast(s); + } + + /** + * @brief casting operator to uint128_t + * @returns returns lower 128-bit integer part + */ + inline explicit operator uint128_t() const { return s; } + + /** + * @brief returns lower 128-bit integer part + * @returns returns lower 128-bit integer part + */ + inline uint128_t lower() const { return s; } + + /** + * @brief returns upper 128-bit integer part + * @returns returns upper 128-bit integer part + */ + inline uint128_t upper() const { return f; } + + /** + * @brief operator = for uint256_t + * @param p an 256-bit integer to assign it's value + * @returns this pointer with it's value equal to `p` + */ + inline uint256_t &operator=(const uint256_t &p) = default; + + /** + * @brief operator = for other types + * @tparam T denoting any integer type + * @param p an integer to assign it's value + * @returns this pointer with it's value equal to `p` + */ + template ::value, T>::type> + inline uint256_t &operator=(const T &p) { + this->s = p; + return *this; + } + + /** + * @brief operator = for type string + * @param p a string to assign it's value to equivalent integer + * @returns this pointer with it's value equal to `p` + */ + inline uint256_t &operator=(const std::string &p) { + __get_integer_from_string(p); + return *this; + } + + /** + * @brief Move assignment operator + */ + inline uint256_t &operator=(uint256_t &&p) = default; + + /** + * @brief operator + for uint256_t and other integer types. + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns addition of this and p, returning uint256_t integer + */ + template ::value, T>::type> + inline uint256_t operator+(const T &p) { + bool app = s + p < s; + return uint256_t(f + app, s + p); + } + + /** + * @brief operator + for uint256_t and other integer types. + * @param p 256-bit unsigned integer + * @returns addition of this and p, returning uint256_t integer + */ + inline uint256_t operator+(const uint256_t &p) { + bool app = (s + p.s < s); + return {f + app + p.f, s + p.s}; + } + + /** + * @brief operator += for uint256_t and other integer types. + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns addition of this and p, returning this + */ + template ::value, T>::type> + inline uint256_t &operator+=(const T &p) { + bool app = (p + s < s); + this->f += app; + this->s += p; + return *this; + } + + /** + * @brief operator += for uint256_t + * @param p 256-bit unsigned integer + * @returns addition of this and p, returning this + */ + inline uint256_t &operator+=(const uint256_t &p) { + bool app = (s + p.s < s); + f = f + app + p.f; + s = s + p.s; + return *this; + } + + /** + * @brief pre-increment operator + * @returns incremented value of this. + */ + inline uint256_t &operator++() { + *this += 1; + return *this; + } + + /** + * @brief post-increment operator + * @returns incremented value of this. + */ + inline uint256_t operator++(int) { + ++*this; + return *this; + } + + /** + * @brief operator - for uint256_t and other integer types. + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns subtraction of this and p, returning uint256_t integer + */ + template ::value, T>::type> + inline uint256_t operator-(const T &p) { + bool app = (p > s); + return uint256_t(f - app, s - p); + } + + /** + * @brief operator - for uint256_t + * @param p a type of integer variable + * @returns subtraction of this and p, returning uint256_t integer + */ + inline uint256_t operator-(const uint256_t &p) { + bool app = s < p.s; + return {f - p.f - app, s - p.s}; + } + + /** + * @brief operator - using twos complement + * @returns 2's complement of this. + */ + inline uint256_t operator-() { return ~*this + uint256_t(1); } + + /** + * @brief operator -- (pre-decrement) + * @returns decremented value of this + */ + inline uint256_t &operator--() { + *this -= 1; + return *this; + } + + /** + * @brief operator -- (post-decrement) + * @returns decremented value of this + */ + inline uint256_t operator--(int p) { + --*this; + return *this; + } + + /** + * @brief operator -= for uint256_t and other integer types. + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns subtraction of this and p, returning this + */ + template ::value, T>::type> + inline uint256_t operator-=(const T p) { + bool app = (p > s); + f = f - app; + s = s - p; + return *this; + } + + /** + * @brief operator -= for uint256_t + * @param p 256-bit unsigned integer + * @returns subtraction of this and p, returning this + */ + inline uint256_t &operator-=(const uint256_t &p) { + bool app = s < p.s; + f = f - app - p.f; + s = s - p.s; + return *this; + } + + /** + * @brief operator * for uint256_t and other integer types. + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns multiplication of this and p, returning uint256_t integer + */ + template ::value, T>::type> + inline uint256_t operator*(const T &p) { + return *this * uint256_t(p); + } + + /** + * @brief operator * for uint256_t and other integer types. + * @param p 256-bit unsigned integer + * @returns multiplication of this and p, returning uint256_t integer + */ + uint256_t operator*(const uint256_t &p) { + uint128_t f_first(s.upper()), f_second(s.lower()), s_first(p.s.upper()), + s_second(p.s.lower()); + uint128_t fi = f_first * s_first, se = f_first * s_second, + th = s_first * f_second, fo = s_second * f_second; + uint128_t tmp = se << 64, tmp2 = th << 64; + int cc = (tmp + tmp2 < tmp); + tmp += tmp2; + cc += (tmp + fo < tmp); + return {f * p.s + s * p.f + fi + se.upper() + th.upper() + cc, + tmp + fo}; + } + + /** + * @brief operator *= for uint256_t and other integer types. + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns multiplication of this and p, returning this + */ + template ::value, T>::type> + inline uint256_t &operator*=(const T &p) { + return (*this *= uint256_t(p)); + } + + /** + * @brief operator *= for uint256_t and other integer types. + * @param p 256-bit unsigned integer + * @returns multiplication of this and p, returning this + */ + uint256_t &operator*=(const uint256_t &p) { + uint128_t f_first(s.upper()), f_second(s.lower()), s_first(p.s.upper()), + s_second(p.s.lower()); + uint128_t fi = f_first * s_first, se = f_first * s_second, + th = s_first * f_second, fo = s_second * f_second; + uint128_t tmp = se << 64, tmp2 = th << 64; + int cc = (tmp + tmp2 < tmp); + tmp += tmp2; + cc += (tmp + fo < tmp); + f = f * p.s + s * p.f + fi + se.upper() + th.upper() + cc; + s = tmp + fo; + return *this; + } + + /** + * @brief divide function for uint256_t and other integer types. + * @details divide this value and + * @param p 256-bit unsigned integer + * @returns pair denoting quotient and remainder. + */ + std::pair divide(const uint256_t &p) { + if (*this < p) { // if this is less than divisor + return {uint256_t(0), *this}; + } else if (*this == p) { // if this is equal to divisor + return {uint256_t(1), uint256_t(0)}; + } + uint256_t tmp = p, tmp2 = *this; + uint16_t left = tmp._lez() - _lez(); + tmp <<= left; + uint256_t quotient(0); + uint256_t zero(0); + while (tmp2 >= p) { + uint16_t shf = tmp2._lez() - tmp._lez(); + if (shf) { + tmp >>= shf; + quotient <<= shf; + left -= shf; + } + if (tmp2 < tmp) { + tmp >>= 1; + quotient <<= 1; + --left; + } + tmp2 -= tmp; + ++quotient; + } + return {quotient << left, tmp2}; + } + + /** + * @brief operator / for uint256_t and other integer types. + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns unsigned 256-bit quotient. + */ + template ::value, T>::type> + inline uint256_t operator/(const T &p) { + uint256_t tmp = *this; + tmp /= uint256_t(p); + return tmp; + } + + /** + * @brief operator / for uint256_t and other integer types. + * @param p 256-bit unsigned integer + * @returns unsigned 256-bit quotient. + */ + inline uint256_t operator/(const uint256_t &p) { return divide(p).first; } + + /** + * @brief operator /= for uint256_t + * @param p 256-bit unsigned integer + * @returns this set as unsigned 256-bit quotient. + */ + inline uint256_t &operator/=(const uint256_t &p) { + *this = divide(p).first; + return *this; + } + + /** + * @brief operator /= for uint256_t and other integer types. + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns this set as unsigned 256-bit quotient. + */ + template ::value, T>::type> + inline uint256_t &operator/=(const T &p) { + *this /= uint256_t(p); + return *this; + } + + /** + * @brief operator % for uint256_t + * @param p 256-bit unsigned integer + * @returns unsigned 256-bit remainder. + */ + inline uint256_t operator%(const uint256_t &p) { return divide(p).second; } + + /** + * @brief operator % for uint256_t and other integer types. + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns unsigned 256-bit remainder. + */ + template ::value, T>::type> + inline uint256_t operator%(const T &p) { + uint256_t tmp = *this; + tmp %= uint256_t(p); + return tmp; + } + + /** + * @brief operator %= for uint256_t + * @param p 256-bit unsigned integer + * @returns this set as unsigned 256-bit remainder. + */ + inline uint256_t &operator%=(const uint256_t &p) { + *this = divide(p).second; + return *this; + } + + /** + * @brief operator %= for uint256_t + * @tparam T denoting integral type + * @param p a type of integer variable + * @returns this set as unsigned 256-bit remainder. + */ + template ::value, T>::type> + inline uint256_t &operator%=(const T &p) { + *this %= uint256_t(p); + return *this; + } + + /** + * @brief operator < for uint256_t + * @param other number to be compared with this + * @returns true if this is less than other, else false + */ + inline bool operator<(const uint256_t &other) { + return f < other.f || (f == other.f && s < other.s); + } + + /** + * @brief operator <= for uint256_t + * @param other number to be compared with this + * @returns true if this is less than or equal to other, else false + */ + inline bool operator<=(const uint256_t &other) { + return f < other.f || (f == other.f && s <= other.s); + } + + /** + * @brief operator > for uint256_t + * @param other number to be compared with this + * @returns true if this is greater than other, else false + */ + inline bool operator>(const uint256_t &other) { + return f > other.f || (f == other.f && s > other.s); + } + + /** + * @brief operator >= for uint256_t + * @param other number to be compared with this + * @returns true if this is greater than or equal than other, else false + */ + inline bool operator>=(const uint256_t &other) { + return (f > other.f) || (f == other.f && s >= other.s); + } + + /** + * @brief operator == for uint256_t + * @param other number to be compared with this + * @returns true if this is equal than other, else false + */ + inline bool operator==(const uint256_t &other) { + return f == other.f && s == other.s; + } + + /** + * @brief operator != for uint256_t + * @param other number to be compared with this + * @returns true if this is not equal than other, else false + */ + inline bool operator!=(const uint256_t &other) { + return !((*this) == other); + } + + /** + * @brief operator ! for uint256_t + * @returns true if this has zero value, else false + */ + inline bool operator!() { return !f && !s; } + + /** + * @brief operator && for uint256_t + * @param b number to be compared with this + * @returns true if both of the values are not zero, else false + */ + inline bool operator&&(const uint256_t &b) { + return (s || f) && (b.s || b.f); + } + + /** + * @brief operator || for uint256_t + * @param b number to be compared with this + * @returns true if one of the values are not zero, else false + */ + inline bool operator||(const uint256_t &b) { + return (s || f) || (b.s || b.f); + } + + /** + * @brief operator () for uint256_t + * @returns true if this value is non-zero, else false + */ + inline bool operator()() { return s || f; } + + /** + * @brief operator < for other types + * @tparam T integral type + * @param other number to be compared with this + * @returns true if this is less than other, else false + */ + template ::value, T>::type> + bool operator<(const T &other) { + return *this < uint256_t(other); + } + + /** + * @brief operator <= for other types + * @tparam T integral type + * @param other number to be compared with this + * @returns true if this is less than or equal to other, else false + */ + template ::value, T>::type> + bool operator<=(const T &other) { + return *this <= uint256_t(other); + } + + /** + * @brief operator > for other types + * @tparam T integral type + * @param other number to be compared with this + * @returns true if this is greater than other, else false + */ + template ::value, T>::type> + bool operator>(const T &other) { + return *this > uint256_t(other); + } + + /** + * @brief operator >= for other types + * @tparam T integral type + * @param other number to be compared with this + * @returns true if this is greater than or equal other, else false + */ + template ::value, T>::type> + bool operator>=(const T &other) { + return *this >= uint256_t(other); + } + + /** + * @brief operator == for other types + * @tparam T integral type + * @param other number to be compared with this + * @returns true if this is equal to other, else false + */ + template ::value, T>::type> + bool operator==(const T &other) { + return *this == uint256_t(other); + } + + /** + * @brief operator != for other types + * @tparam T integral type + * @param other number to be compared with this + * @returns true if this is not equal to other, else false + */ + template ::value, T>::type> + bool operator!=(const T &other) { + return *this != uint256_t(other); + } + + /** + * @brief operator && for other types + * @tparam T integral type + * @param other number to be compared with this + * @returns true if this is both values are non-zero, else false + */ + template ::value, T>::type> + inline bool operator&&(const T &b) { + return (s || f) && (b); + } + + /** + * @brief operator || for other types + * @tparam T integral type + * @param other number to be compared with this + * @returns true if this is either one of the values are non-zero, else + * false + */ + template ::value, T>::type> + inline bool operator||(const T &b) { + return (s || f) || (b); + } + + /** + * @brief operator ~ for uint256_t + * @returns 1's complement of this number + */ + inline uint256_t operator~() { return {~f, ~s}; } + + /** + * @brief operator << for uint256_t + * @tparam T integral type + * @param p number denoting number of shifts + * @returns value of this shifted by p to left + */ + template ::value, T>::type> + uint256_t operator<<(const T &p) { + if (!p) { + return {this->f, this->s}; + } else if (p >= 128) { + return uint256_t((this->s << (p - 128)), uint128_t(0)); + } + return uint256_t((this->f << p) + (this->s >> (128 - p)), + (this->s << p)); + } + + /** + * @brief operator <<= for uint256_t + * @tparam T integral type + * @param p number denoting number of shifts + * @returns this shifted by p to left + */ + template ::value, T>::type> + uint256_t &operator<<=(const T &p) { + if (p) { + if (p >= 128) { + this->f = (this->s << (p - 128)); + this->s = uint128_t(0); + } else { + f = ((this->s >> (128 - p)) + (this->f << p)); + s = (this->s << p); + } + } + return *this; + } + + /** + * @brief operator >> for uint256_t + * @tparam T integral type + * @param p number denoting number of shifts + * @returns value of this shifted by p to right + */ + template ::value, T>::type> + uint256_t operator>>(const T &p) { + if (!p) { + return {this->f, this->s}; + } else if (p >= 128) { + return uint256_t(uint128_t(0), (this->f >> (p - 128))); + } + return uint256_t((this->f >> p), + (this->s >> p) + (this->f << (128 - p))); + } + + /** + * @brief operator >>= for uint256_t + * @tparam T integral type + * @param p number denoting number of shifts + * @returns this shifted by p to right + */ + template ::value, T>::type> + uint256_t &operator>>=(const T &p) { + if (p) { + if (p >= 128) { + f = uint128_t(0); + s = (this->f >> (p - 128)); + } else { + s = (this->s >> p) + (this->f << (128 - p)); + f = (this->f >> p); + } + } + return *this; + } + + /** + * @brief operator & for other types (bitwise operator) + * @tparam T integral type + * @param p number to be operated + * @returns value of this & p (& is bit-wise operator) + */ + template ::value, T>::type> + inline uint256_t operator&(const T &p) { + return *this & uint256_t(p); + } + + /** + * @brief operator & for uint256_t (bitwise operator) + * @param p number to be operated + * @returns value of this & p (& is bit-wise operator) + */ + inline uint256_t operator&(const uint256_t &p) { + return {f & p.f, s & p.s}; + } + + /** + * @brief operator &= for uint256_t (bitwise operator) + * @param p number to be operated + * @returns this = this & p (& is bit-wise operator) + */ + inline uint256_t &operator&=(const uint256_t &p) { + f &= p.f; + s &= p.s; + return *this; + } + + /** + * @brief operator &= for other types (bitwise operator) + * @tparam T integral type + * @param p number to be operated + * @returns this = this & p (& is bit-wise operator) + */ + template ::value, T>::type> + inline uint256_t &operator&=(const T p) { + s &= p.s; + return *this; + } + + /** + * @brief operator | for other types (bitwise operator) + * @tparam T integral type + * @param p number to be operated + * @returns value of this | p (| is bit-wise operator) + */ + template ::value, T>::type> + inline uint256_t operator|(const T &p) { + return *this | uint256_t(p); + } + + /** + * @brief operator | for uint256_t (bitwise operator) + * @param p number to be operated + * @returns value of this | p (| is bit-wise OR operator) + */ + inline uint256_t operator|(const uint256_t &p) { + return {this->f | p.f, this->s | p.s}; + } + + /** + * @brief operator |= for other types (bitwise operator) + * @tparam T integral type + * @param p number to be operated + * @returns this = this | p (| is bit-wise OR operator) + */ + template ::value, T>::type> + inline uint256_t &operator|=(const T &p) { + s |= p; + return *this; + } + + /** + * @brief operator |= for uint256_t (bitwise operator) + * @param p number to be operated + * @returns this = this | p (| is bit-wise OR operator) + */ + inline uint256_t &operator|=(const uint256_t &p) { + f |= p.f; + s |= p.s; + return *this; + } + + /** + * @brief operator ^ for other types (bitwise operator) + * @tparam T integral type + * @param p number to be operated + * @returns value of this ^ p (^ is bit-wise XOR operator) + */ + template ::value, T>::type> + inline uint256_t operator^(const T &p) { + return uint256_t(f, s ^ p); + } + + /** + * @brief operator ^ for uint256_t (bitwise operator) + * @param p number to be operated + * @returns value of this ^ p (^ is bit-wise XOR operator) + */ + inline uint256_t operator^(const uint256_t &p) { + return {this->f ^ p.f, this->s ^ p.s}; + } + + /** + * @brief operator ^= for uint256_t (bitwise operator) + * @param p number to be operated + * @returns this = this ^ p (^ is bit-wise XOR operator) + */ + inline uint256_t &operator^=(const uint256_t &p) { + f ^= p.f; + s ^= p.s; + return *this; + } + + /** + * @brief operator ^= for other types (bitwise operator) + * @tparam T integral type + * @param p number to be operated + * @returns this = this ^ p (^ is bit-wise XOR operator) + */ + template ::value, T>::type> + inline uint256_t &operator^=(const T &p) { + s ^= p; + return *this; + } + + /** + * @brief operator << for printing uint256_t integer + * @details Prints the uint256_t integer in decimal form + * @note Note that this operator is costly since it uses strings to print + * the value + * @param op ostream object + * @param p 256-bit integer + * @returns op, ostream object. + */ + friend std::ostream &operator<<(std::ostream &op, uint256_t p) { + if (!p.f) { + op << p.s; + } else { + std::string out = "0", p_2 = "1"; + uint128_t L(1); + for (uint64_t i = 0; i < 128; ++i) { + if ((p.s & L)) { + out = add(out, p_2); + } + p_2 = add(p_2, p_2); + L <<= 1; + } + L = uint128_t(1); + for (int i = 0; i < 128; ++i) { + if ((p.f & L)) { + out = add(out, p_2); + } + p_2 = add(p_2, p_2); + L <<= 1; + } + op << out; + } + return op; + } +}; + +// Artihmetic +template ::value, T>::type> +inline uint256_t operator+(const T p, const uint256_t &q) { + return uint256_t(p) + q; +} + +template ::value, T>::type> +inline uint256_t operator-(const T p, const uint256_t &q) { + return (uint256_t(p) - q); +} + +template ::value, T>::type> +inline uint256_t operator*(const T p, const uint256_t &q) { + return uint256_t(p) * q; +} + +template ::value, T>::type> +inline uint256_t operator/(const T p, const uint256_t &q) { + return uint256_t(p) / q; +} + +template ::value, T>::type> +inline uint256_t operator%(const T p, const uint256_t &q) { + return uint256_t(p) % q; +} + +// Bitwise operators +template ::value, T>::type> +inline uint256_t operator&(const T &p, const uint256_t &q) { + return uint256_t(p) & q; +} + +template ::value, T>::type> +inline uint256_t operator|(const T p, const uint256_t &q) { + return uint256_t(p) | q; +} + +template ::value, T>::type> +inline uint256_t operator^(const T p, const uint256_t &q) { + return uint256_t(p) ^ q; +} + +// Boolean operators +template ::value, T>::type> +inline bool operator&&(const T p, const uint256_t &q) { + return uint256_t(p) && q; +} + +template ::value, T>::type> +inline bool operator||(const T p, const uint256_t &q) { + return uint256_t(p) || q; +} + +// Comparison operators +template ::value, T>::type> +inline bool operator==(const T p, const uint256_t &q) { + return uint256_t(p) == q; +} + +template ::value, T>::type> +inline bool operator!=(const T p, const uint256_t &q) { + return uint256_t(p) != q; +} + +template ::value, T>::type> +inline bool operator<(const T p, const uint256_t &q) { + return uint256_t(p) < q; +} + +template ::value, T>::type> +inline bool operator<=(const T p, const uint256_t &q) { + return uint256_t(p) <= q; +} + +template ::value, T>::type> +inline bool operator>(const T p, const uint256_t &q) { + return uint256_t(p) > q; +} + +template ::value, T>::type> +inline bool operator>=(const T p, const uint256_t &q) { + return uint256_t(p) >= q; +} + +#endif // CIPHERS_UINT256_T_HPP_ diff --git a/ciphers/vigenere_cipher.cpp b/ciphers/vigenere_cipher.cpp new file mode 100644 index 00000000000..4efd56c0013 --- /dev/null +++ b/ciphers/vigenere_cipher.cpp @@ -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 +#include +#include + +/** \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; +} diff --git a/ciphers/xor_cipher.cpp b/ciphers/xor_cipher.cpp new file mode 100644 index 00000000000..18cbdd61f60 --- /dev/null +++ b/ciphers/xor_cipher.cpp @@ -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 +#include +#include + +/** \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; +} diff --git a/cpu_scheduling_algorithms/CMakeLists.txt b/cpu_scheduling_algorithms/CMakeLists.txt new file mode 100644 index 00000000000..ce93cef26e3 --- /dev/null +++ b/cpu_scheduling_algorithms/CMakeLists.txt @@ -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} ) diff --git a/cpu_scheduling_algorithms/fcfs_scheduling.cpp b/cpu_scheduling_algorithms/fcfs_scheduling.cpp new file mode 100644 index 00000000000..5c5e2fa3c58 --- /dev/null +++ b/cpu_scheduling_algorithms/fcfs_scheduling.cpp @@ -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 /// for sorting +#include /// for assert +#include +#include /// random number generation +#include /// for time +#include /// for formatting the output +#include /// for IO operations +#include /// for std::priority_queue +#include /// for std::unordered_set +#include /// 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 +bool sortcol(tuple& t1, tuple& 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 +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& t1, + tuple& 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 +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, + vector>, + Compare> + schedule; + + // Stores final status of all the processes after completing the execution. + vector> result; + + // Stores process IDs. Used for confirming absence of a process while adding + // it. + unordered_set 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 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> scheduleForFcfs() { + // Variable to keep track of time elapsed so far + double timeElapsed = 0; + + while (!schedule.empty()) { + tuple 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 +vector> get_final_status( + vector> input) { + sort(input.begin(), input.end(), sortcol); + vector> 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 readyQueue; + vector> 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> + res = get_final_status(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; +} diff --git a/cpu_scheduling_algorithms/non_preemptive_sjf_scheduling.cpp b/cpu_scheduling_algorithms/non_preemptive_sjf_scheduling.cpp new file mode 100644 index 00000000000..e7d9d370960 --- /dev/null +++ b/cpu_scheduling_algorithms/non_preemptive_sjf_scheduling.cpp @@ -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. + * + * detailed description on SJF scheduling + * Author : Lakshmi Srikumar + */ + +#include /// for sorting +#include /// for assert +#include /// for formatting the output +#include /// for IO operations +#include /// for std::priority_queue +#include /// random number generation +#include /// for std::unordered_set +#include /// 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 tuplet1 + * @param t2 Second tuplet2 + * @returns true if t1 and t2 are in the CORRECT order + * @returns false if t1 and t2 are in the INCORRECT order + */ +template +bool sortcol(tuple& t1, tuple& 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 +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. + * + * detailed description of comparator + * @returns true if the tuples SHOULD be swapped + * @returns false if the tuples SHOULDN'T be swapped + */ + bool operator()(tuple& t1, + tuple& 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 +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, + vector>, + Compare> + schedule; + + // Stores final status of all the processes after completing the execution. + vector> result; + + // Stores process IDs. Used for confirming absence of a process while it. + unordered_set 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 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> scheduleForSJF() { + // Variable to keep track of time elapsed so far + double timeElapsed = 0; + + while (!schedule.empty()) { + tuple 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>& 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 +vector> get_final_status( + vector> input) { + // Sort the processes based on Arrival time and then Burst time + sort(input.begin(), input.end(), sortcol); + + // Result vector to hold the final status of each process + vector> 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> + 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 readyQueue; + vector> + 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; +} diff --git a/data_structures/CMakeLists.txt b/data_structures/CMakeLists.txt new file mode 100644 index 00000000000..6c0555148be --- /dev/null +++ b/data_structures/CMakeLists.txt @@ -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) diff --git a/data_structures/avltree.cpp b/data_structures/avltree.cpp new file mode 100644 index 00000000000..707841c0dba --- /dev/null +++ b/data_structures/avltree.cpp @@ -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 /// for std::max +#include /// for std::cout +#include /// 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 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; +} diff --git a/data_structures/binary_search_tree.cpp b/data_structures/binary_search_tree.cpp new file mode 100644 index 00000000000..86057c6c507 --- /dev/null +++ b/data_structures/binary_search_tree.cpp @@ -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 + +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; +} diff --git a/data_structures/binary_search_tree2.cpp b/data_structures/binary_search_tree2.cpp new file mode 100644 index 00000000000..55ae3a43877 --- /dev/null +++ b/data_structures/binary_search_tree2.cpp @@ -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 +#include +#include +#include +#include + +/** + * @brief The Binary Search Tree class. + * + * @tparam T The type of the binary search tree key. + */ +template +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 left; /**< Pointer to left subtree. */ + std::unique_ptr 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 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& 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& 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& node, T new_value) { + if (root_ == node && !root_) { + root_ = std::unique_ptr(new bst_node(new_value)); + return true; + } + + if (new_value < node->value) { + if (!node->left) { + node->left = std::unique_ptr(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(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& parent, + std::unique_ptr& 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& 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& 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 callback, + std::unique_ptr& 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 callback, + std::unique_ptr& 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 callback, + std::unique_ptr& 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 List of values, sorted in in-order order. + */ + std::vector get_elements_inorder() { + std::vector 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 List of values, sorted in pre-order order. + */ + std::vector get_elements_preorder() { + std::vector 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 List of values, sorted in post-order order. + */ + std::vector get_elements_postorder() { + std::vector 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 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 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 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 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 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 tree; + tree.insert(5); + tree.insert(4); + tree.insert(3); + tree.insert(6); + + std::vector expected = {3, 4, 5, 6}; + std::vector 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 tree; + tree.insert(5); + tree.insert(4); + tree.insert(3); + tree.insert(6); + + std::vector expected = {5, 4, 3, 6}; + std::vector 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 tree; + tree.insert(5); + tree.insert(4); + tree.insert(3); + tree.insert(6); + + std::vector expected = {3, 4, 6, 5}; + std::vector 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(); +} diff --git a/data_structures/binaryheap.cpp b/data_structures/binaryheap.cpp new file mode 100644 index 00000000000..483bd7c0275 --- /dev/null +++ b/data_structures/binaryheap.cpp @@ -0,0 +1,142 @@ +/** + * \file + * \brief A C++ program to demonstrate common Binary Heap Operations + */ +#include +#include +#include + +/** 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; +} diff --git a/data_structures/bloom_filter.cpp b/data_structures/bloom_filter.cpp new file mode 100644 index 00000000000..e2f7372e0c4 --- /dev/null +++ b/data_structures/bloom_filter.cpp @@ -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 /// for assert +#include /// for list of hash functions for bloom filter constructor +#include /// for initializer_list for bloom filter constructor +#include /// for testing on strings +#include /// for std::vector +#include /// 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 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 +class BloomFilter { + private: + Bitset set; ///< inner bitset for elements + std::vector> + hashFunks; ///< hash functions for T type + + public: + BloomFilter(std::size_t, + std::initializer_list>); + 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 +BloomFilter::BloomFilter( + std::size_t size, + std::initializer_list> 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 +void BloomFilter::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 +bool BloomFilter::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(x); + y = (y ^ (y >> 30)) * static_cast(0xbf58476d1ce4e5b9); + y = (y ^ (y >> 27)) * static_cast(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 filter( + 10, {data_structures::hashDJB2, data_structures::hashStr}); + std::vector toCheck{"hello", "world", "!"}; + std::vector 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 filter( + 20, {data_structures::hashInt_1, data_structures::hashInt_2}); + std::vector toCheck{100, 200, 300, 50}; + std::vector 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 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; +} diff --git a/data_structures/circular_queue_using_linked_list.cpp b/data_structures/circular_queue_using_linked_list.cpp new file mode 100644 index 00000000000..41b55926430 --- /dev/null +++ b/data_structures/circular_queue_using_linked_list.cpp @@ -0,0 +1,82 @@ +#include + +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; +} \ No newline at end of file diff --git a/data_structures/cll/CMakeLists.txt b/data_structures/cll/CMakeLists.txt new file mode 100644 index 00000000000..cb18eb3475f --- /dev/null +++ b/data_structures/cll/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable( cll + cll.cpp + main_cll.cpp +) +install(TARGETS cll DESTINATION "bin/data_structures") diff --git a/data_structures/cll/cll.cpp b/data_structures/cll/cll.cpp new file mode 100644 index 00000000000..42bc9067e20 --- /dev/null +++ b/data_structures/cll/cll.cpp @@ -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--; +} diff --git a/data_structures/cll/cll.h b/data_structures/cll/cll.h new file mode 100644 index 00000000000..a1a9b4d925d --- /dev/null +++ b/data_structures/cll/cll.h @@ -0,0 +1,43 @@ +/* + * Simple data structure CLL (Cicular Linear Linked List) + * */ +#include +#include +#include +#include + +#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 diff --git a/data_structures/cll/main_cll.cpp b/data_structures/cll/main_cll.cpp new file mode 100644 index 00000000000..0b6bfd3edef --- /dev/null +++ b/data_structures/cll/main_cll.cpp @@ -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; +} diff --git a/data_structures/disjoint_set.cpp b/data_structures/disjoint_set.cpp new file mode 100644 index 00000000000..bd4599603eb --- /dev/null +++ b/data_structures/disjoint_set.cpp @@ -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 +#include + +using std::cout; +using std::endl; +using std::vector; + +vector root, rank; + +/** + * + * Function to create a set + * @param n number of element + * + */ +void CreateSet(int n) { + root = vector(n + 1); + rank = vector(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; +} diff --git a/data_structures/doubly_linked_list.cpp b/data_structures/doubly_linked_list.cpp new file mode 100644 index 00000000000..30cc257d84f --- /dev/null +++ b/data_structures/doubly_linked_list.cpp @@ -0,0 +1,136 @@ +#include +#include +#include + +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; +} diff --git a/data_structures/dsu_path_compression.cpp b/data_structures/dsu_path_compression.cpp new file mode 100644 index 00000000000..c08040570dd --- /dev/null +++ b/data_structures/dsu_path_compression.cpp @@ -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 /// for assert +#include +#include /// for IO operations +#include /// 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 p; ///< keeps track of the parent of ith element + vector depth; ///< tracks the depth(rank) of i in the tree + vector setSize; ///< size of each chunk(set) + vector maxElement; ///< maximum of each set to which i belongs to + vector 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 get(uint64_t i) { + vector 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 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 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; +} diff --git a/data_structures/dsu_union_rank.cpp b/data_structures/dsu_union_rank.cpp new file mode 100644 index 00000000000..16e1d3275bf --- /dev/null +++ b/data_structures/dsu_union_rank.cpp @@ -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 /// for assert +#include +#include /// for IO operations +#include /// 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 p; ///< keeps track of the parent of ith element + vector depth; ///< tracks the depth(rank) of i in the tree + vector 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 getParents(uint64_t i) { + vector 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 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 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; +} diff --git a/data_structures/linked_list.cpp b/data_structures/linked_list.cpp new file mode 100644 index 00000000000..08bfe68b1e9 --- /dev/null +++ b/data_structures/linked_list.cpp @@ -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 +#include +#include + +/** + * @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 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& 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 first; ///< link before the actual first element + std::shared_ptr last; ///< last link on the list + public: + /** + * List constructor. Initializes the first and last link. + */ + list() { + // Initialize the first link + first = std::make_shared(); + // 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 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(new_elem); + last = first->succ(); + } else { + last->succ() = std::make_shared(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(new_elem); + last = first->succ(); + } else { + std::shared_ptr t = std::make_shared(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 t = first; + std::shared_ptr 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 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 list::search(int find_elem) { + if (isEmpty()) { + std::cout << "List is Empty!"; + return nullptr; + } + std::shared_ptr 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 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; +} diff --git a/data_structures/linkedlist_implentation_usingarray.cpp b/data_structures/linkedlist_implentation_usingarray.cpp new file mode 100644 index 00000000000..75d400d72ea --- /dev/null +++ b/data_structures/linkedlist_implentation_usingarray.cpp @@ -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 + +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; +} diff --git a/data_structures/list_array.cpp b/data_structures/list_array.cpp new file mode 100644 index 00000000000..0c8099f5788 --- /dev/null +++ b/data_structures/list_array.cpp @@ -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 /// for std::array +#include /// for assert +#include +#include /// 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 +struct list { + std::array 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 &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 &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; +} diff --git a/data_structures/morrisinorder.cpp b/data_structures/morrisinorder.cpp new file mode 100644 index 00000000000..c667ccf13fa --- /dev/null +++ b/data_structures/morrisinorder.cpp @@ -0,0 +1,101 @@ +#include +#include + +/************************** + @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 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; +} diff --git a/data_structures/node.hpp b/data_structures/node.hpp new file mode 100644 index 00000000000..ff920299b77 --- /dev/null +++ b/data_structures/node.hpp @@ -0,0 +1,46 @@ +/** + * @file + * @brief Provides Node class and related utilities + **/ +#ifndef DATA_STRUCTURES_NODE_HPP_ +#define DATA_STRUCTURES_NODE_HPP_ + +#include /// for std::cout +#include /// for std::shared_ptr +#include /// for std::vector + +/** Definition of the node as a linked-list + * \tparam ValueType type of data nodes of the linked list should contain + */ +template +struct Node { + using value_type = ValueType; + ValueType data = {}; + std::shared_ptr> next = {}; +}; + +template +void traverse(const Node* const inNode, const Action& action) { + if (inNode) { + action(*inNode); + traverse(inNode->next.get(), action); + } +} + +template +void display_all(const Node* const inNode) { + traverse(inNode, + [](const Node& curNode) { std::cout << curNode.data << " "; }); +} + +template +std::vector push_all_to_vector( + const Node* const inNode, const std::size_t expected_size = 0) { + std::vector res; + res.reserve(expected_size); + traverse(inNode, + [&res](const Node& curNode) { res.push_back(curNode.data); }); + return res; +} + +#endif // DATA_STRUCTURES_NODE_HPP_ diff --git a/data_structures/queue.hpp b/data_structures/queue.hpp new file mode 100644 index 00000000000..cd358a6ef13 --- /dev/null +++ b/data_structures/queue.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 queue { + using node_type = Node; + + 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 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(); + 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 queueFront = + {}; /**< Pointer to the front of the queue */ + std::shared_ptr queueRear = + {}; /**< Pointer to the rear of the queue */ + std::size_t size = 0; +}; + +#endif // DATA_STRUCTURES_QUEUE_HPP_ diff --git a/data_structures/queue_using_array.cpp b/data_structures/queue_using_array.cpp new file mode 100644 index 00000000000..c2437258328 --- /dev/null +++ b/data_structures/queue_using_array.cpp @@ -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 /// for std::array +#include +#include /// 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 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; +} diff --git a/data_structures/queue_using_array2.cpp b/data_structures/queue_using_array2.cpp new file mode 100644 index 00000000000..13f7d8e17f8 --- /dev/null +++ b/data_structures/queue_using_array2.cpp @@ -0,0 +1,57 @@ +#include +using namespace std; + +int queue[10]; +int front = 0; +int rear = 0; + +void Enque(int x) { + if (rear == 10) { + cout << "\nOverflow"; + } else { + queue[rear++] = x; + } +} + +void Deque() { + if (front == rear) { + cout << "\nUnderflow"; + } + + else { + 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++) { + cout << queue[i] << "\t"; + } +} + +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; +} diff --git a/data_structures/queue_using_linked_list.cpp b/data_structures/queue_using_linked_list.cpp new file mode 100644 index 00000000000..7b44d240c74 --- /dev/null +++ b/data_structures/queue_using_linked_list.cpp @@ -0,0 +1,70 @@ +#include +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; +} diff --git a/data_structures/queue_using_linkedlist.cpp b/data_structures/queue_using_linkedlist.cpp new file mode 100644 index 00000000000..f1bf18123f9 --- /dev/null +++ b/data_structures/queue_using_linkedlist.cpp @@ -0,0 +1,86 @@ +/* + Write a program to implement Queue using linkedlist. +*/ +#include + +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; +} diff --git a/data_structures/queue_using_two_stacks.cpp b/data_structures/queue_using_two_stacks.cpp new file mode 100644 index 00000000000..a096446865a --- /dev/null +++ b/data_structures/queue_using_two_stacks.cpp @@ -0,0 +1,144 @@ +/** + * @author [shoniavika](https://github.com/shoniavika) + * @file + * + * Implementation of a Queue using two Stacks. + */ + +#include +#include +#include + +namespace { +/** + * @brief Queue data structure. Stores elements in FIFO + * (first-in-first-out) manner. + * @tparam T datatype to store in the queue + */ +template +class MyQueue { + private: + std::stack 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 +void MyQueue::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 +const T& MyQueue::pop() { + const T& temp = MyQueue::peek(); + s2.pop(); + return temp; +} + +/** + * Returns element in the front. + * Does not remove it. + */ +template +const T& MyQueue::peek() const { + if (!empty()) { + return s2.top(); + } + std::cerr << "Queue is empty" << std::endl; + exit(0); +} + +/** + * Checks whether a queue is empty + */ +template +bool MyQueue::empty() const { + return s2.empty() && s1.empty(); +} +} // namespace + +/** + * Testing function + */ +void queue_test() { + MyQueue 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 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; +} diff --git a/data_structures/rb_tree.cpp b/data_structures/rb_tree.cpp new file mode 100644 index 00000000000..f2a51a30c20 --- /dev/null +++ b/data_structures/rb_tree.cpp @@ -0,0 +1,505 @@ +#include + +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, i = 0; + 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; +} diff --git a/data_structures/reverse_a_linked_list.cpp b/data_structures/reverse_a_linked_list.cpp new file mode 100644 index 00000000000..d8315b4bb47 --- /dev/null +++ b/data_structures/reverse_a_linked_list.cpp @@ -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 /// for assert +#include /// for I/O operations +#include /// 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; +} diff --git a/data_structures/segment_tree.cpp b/data_structures/segment_tree.cpp new file mode 100755 index 00000000000..71d85f0b1a5 --- /dev/null +++ b/data_structures/segment_tree.cpp @@ -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 /// For IO operations +#include /// For std::vector +#include /// For std::min and std::max +#include /// 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 SegmentTree { +private: + const T ID = 0; ///< Comb(ID, x) = x + std::vector 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 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; +} diff --git a/data_structures/skip_list.cpp b/data_structures/skip_list.cpp new file mode 100644 index 00000000000..9cf8c430f4a --- /dev/null +++ b/data_structures/skip_list.cpp @@ -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 +#include +#include +#include +#include +#include + +/** \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> + 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 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(-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(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 x = header; + std::array, 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 n = + std::make_shared(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 x = header; + + std::array, 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 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 = 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; +} diff --git a/data_structures/sparse_table.cpp b/data_structures/sparse_table.cpp new file mode 100644 index 00000000000..7b3d74b90c3 --- /dev/null +++ b/data_structures/sparse_table.cpp @@ -0,0 +1,165 @@ +/** + * @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 /// for std::array +#include /// for assert +#include +#include /// 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 A = {}; ///< input array to perform RMQ. + std::array, M> + ST{}; ///< the sparse table storing `min()` values for given interval. + std::array 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(i); + LOG[i + 1] = LOG[i] + !(i & (i + 1)); ///< precomputing `log2(i+1)` + } + + for (size_t j = 1; static_cast(1 << j) <= n; ++j) { + for (size_t i = 0; static_cast(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 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 + * @param argc commandline argument count (ignored) + * @param argv commandline array of arguments (ignored) + * @returns 0 on exit + */ +int main(int argc, char *argv[]) { + test(); // run self-test implementations + return 0; +} diff --git a/data_structures/stack.hpp b/data_structures/stack.hpp new file mode 100644 index 00000000000..84336453a4c --- /dev/null +++ b/data_structures/stack.hpp @@ -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 /// 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 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 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>(); + 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> stackTop = + {}; /**< Pointer to the stack */ + std::size_t size = 0; ///< size of stack +}; + +#endif // DATA_STRUCTURES_STACK_HPP_ diff --git a/data_structures/stack_using_array.cpp b/data_structures/stack_using_array.cpp new file mode 100644 index 00000000000..73feaf445cc --- /dev/null +++ b/data_structures/stack_using_array.cpp @@ -0,0 +1,179 @@ +#include /// For std::assert +#include /// For std::cout +#include /// For std::unique_ptr +#include /// For std::out_of_range + +/** + * @namespace + * @brief data_structures + */ +namespace data_structures { +/** + * @brief Class representation of a stack + * @tparam T The type of the elements in the stack + */ +template +class Stack { + private: + std::unique_ptr stack; ///< Smart pointer to the stack array + int stackSize; ///< Maximum size of the stack + int stackIndex; ///< Index pointing to the top element of the stack + + public: + /** + * @brief Constructs a new Stack object + * + * @param size Maximum size of the stack + */ + Stack(int size) : stackSize(size), stackIndex(-1), stack(new T[size]) {} + + /** + * @brief Checks if the stack is full + * + * @return true if the stack is full, false otherwise + */ + bool full() const { return stackIndex == stackSize - 1; } + + /** + * @brief Checks if the stack is empty + * @return true if the stack is empty, false otherwise + */ + bool empty() const { return stackIndex == -1; } + + /** + * @brief Pushes an element onto the stack + * + * @param element Element to push onto the stack + */ + void push(T element) { + if (full()) { + throw std::out_of_range("Stack overflow"); + } else { + stack[++stackIndex] = element; + } + } + + /** + * @brief Pops an element from the stack + * + * @return The popped element + * @throws std::out_of_range if the stack is empty + */ + T pop() { + if (empty()) { + throw std::out_of_range("Stack underflow"); + } + return stack[stackIndex--]; + } + + /** + * @brief Displays all elements in the stack + */ + void show() const { + for (int i = 0; i <= stackIndex; i++) { + std::cout << stack[i] << "\n"; + } + } + + /** + * @brief Displays the topmost element of the stack + * + * @return The topmost element of the stack + * @throws std::out_of_range if the stack is empty + */ + T topmost() const { + if (empty()) { + throw std::out_of_range("Stack underflow"); + } + return stack[stackIndex]; + } + + /** + * @brief Displays the bottom element of the stack + * + * @return The bottom element of the stack + * @throws std::out_of_range if the stack is empty + */ + T bottom() const { + if (empty()) { + throw std::out_of_range("Stack underflow"); + } + return stack[0]; + } +}; +} // namespace data_structures + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + data_structures::Stack stack(5); + + // Test empty and full operations + assert(stack.empty()); + assert(!stack.full()); + + // Test pushing elements and checking topmost + stack.push(10); + assert(stack.topmost() == 10); + + stack.push(20); + assert(stack.topmost() == 20); + + stack.push(30); + stack.push(40); + stack.push(50); + assert(stack.full()); + + // Test stack overflow + try { + stack.push(60); + } catch (const std::out_of_range& e) { + assert(std::string(e.what()) == "Stack overflow"); + } + + // Test popping elements + assert(stack.pop() == 50); + assert(stack.pop() == 40); + assert(stack.pop() == 30); + + // Check topmost and bottom elements + assert(stack.topmost() == 20); + assert(stack.bottom() == 10); + + assert(stack.pop() == 20); + assert(stack.pop() == 10); + + assert(stack.empty()); + assert(!stack.full()); + + // Test stack underflow + try { + stack.pop(); + } catch (const std::out_of_range& e) { + assert(std::string(e.what()) == "Stack underflow"); + } + + try { + stack.topmost(); + } catch (const std::out_of_range& e) { + assert(std::string(e.what()) == "Stack underflow"); + } + + try { + stack.bottom(); + } catch (const std::out_of_range& e) { + assert(std::string(e.what()) == "Stack underflow"); + } +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + std::cout << "All tests passed!" << std::endl; + return 0; +} diff --git a/data_structures/stack_using_linked_list.cpp b/data_structures/stack_using_linked_list.cpp new file mode 100644 index 00000000000..a87e6efb024 --- /dev/null +++ b/data_structures/stack_using_linked_list.cpp @@ -0,0 +1,66 @@ +#include + +struct node { + int val; + node *next; +}; + +node *top_var; + +void push(int x) { + node *n = new node; + n->val = x; + n->next = top_var; + top_var = n; +} + +void pop() { + if (top_var == nullptr) { + std::cout << "\nUnderflow"; + } else { + node *t = top_var; + std::cout << "\n" << t->val << " deleted"; + top_var = top_var->next; + delete t; + } +} + +void show() { + node *t = top_var; + while (t != nullptr) { + std::cout << t->val << "\n"; + t = t->next; + } +} + +int main() { + int ch = 0, x = 0; + do { + std::cout << "\n0. Exit or Ctrl+C"; + std::cout << "\n1. Push"; + std::cout << "\n2. Pop"; + std::cout << "\n3. Print"; + std::cout << "\nEnter Your Choice: "; + std::cin >> ch; + switch (ch) { + case 0: + break; + case 1: + std::cout << "\nInsert : "; + std::cin >> x; + push(x); + break; + case 2: + pop(); + break; + case 3: + show(); + break; + default: + std::cout << "Invalid option!\n"; + break; + } + } while (ch != 0); + + return 0; +} diff --git a/data_structures/stack_using_queue.cpp b/data_structures/stack_using_queue.cpp new file mode 100644 index 00000000000..c5fc55a3e61 --- /dev/null +++ b/data_structures/stack_using_queue.cpp @@ -0,0 +1,119 @@ +/** + * @brief Stack Data Structure Using the Queue Data Structure + * @details + * Using 2 Queues inside the Stack class, we can easily implement Stack + * data structure with heavy computation in push function. + * + * References used: + * [StudyTonight](https://www.studytonight.com/data-structures/stack-using-queue) + * @author [tushar2407](https://github.com/tushar2407) + */ +#include /// for assert +#include +#include /// for IO operations +#include /// for queue data structure + +/** + * @namespace data_structures + * @brief Data structures algorithms + */ +namespace data_structures { +/** + * @namespace stack_using_queue + * @brief Functions for the [Stack Using + * Queue](https://www.studytonight.com/data-structures/stack-using-queue) + * implementation + */ +namespace stack_using_queue { +/** + * @brief Stack Class implementation for basic methods of Stack Data Structure. + */ +struct Stack { + std::queue main_q; ///< stores the current state of the stack + std::queue auxiliary_q; ///< used to carry out intermediate + ///< operations to implement stack + uint32_t current_size = 0; ///< stores the current size of the stack + + /** + * Returns the top most element of the stack + * @returns top element of the queue + */ + int top() { return main_q.front(); } + + /** + * @brief Inserts an element to the top of the stack. + * @param val the element that will be inserted into the stack + * @returns void + */ + void push(int val) { + auxiliary_q.push(val); + while (!main_q.empty()) { + auxiliary_q.push(main_q.front()); + main_q.pop(); + } + swap(main_q, auxiliary_q); + current_size++; + } + + /** + * @brief Removes the topmost element from the stack + * @returns void + */ + void pop() { + if (main_q.empty()) { + return; + } + main_q.pop(); + current_size--; + } + + /** + * @brief Utility function to return the current size of the stack + * @returns current size of stack + */ + int size() { return current_size; } +}; +} // namespace stack_using_queue +} // namespace data_structures + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + data_structures::stack_using_queue::Stack s; + s.push(1); /// insert an element into the stack + s.push(2); /// insert an element into the stack + s.push(3); /// insert an element into the stack + + assert(s.size() == 3); /// size should be 3 + + assert(s.top() == 3); /// topmost element in the stack should be 3 + + s.pop(); /// remove the topmost element from the stack + assert(s.top() == 2); /// topmost element in the stack should now be 2 + + s.pop(); /// remove the topmost element from the stack + assert(s.top() == 1); + + s.push(5); /// insert an element into the stack + assert(s.top() == 5); /// topmost element in the stack should now be 5 + + s.pop(); /// remove the topmost element from the stack + assert(s.top() == 1); /// topmost element in the stack should now be 1 + + assert(s.size() == 1); /// size should be 1 +} + +/** + * @brief Main function + * Creates a stack and pushed some value into it. + * Through a series of push and pop functions on stack, + * it demostrates the functionality of the custom stack + * declared above. + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} diff --git a/data_structures/student.txt b/data_structures/student.txt new file mode 100644 index 00000000000..b7e3b9e7911 --- /dev/null +++ b/data_structures/student.txt @@ -0,0 +1,17 @@ +3.4 Tom +3.2 Kathy +2.5 Hoang +3.4 Tom +3.8 Randy +3.9 Kingston +3.8 Mickey +3.6 Peter +3.5 Donald +3.8 Cindy +3.7 Dome +3.9 Andy +3.8 Hai +3.9 Minnie +2.7 Gilda +3.9 Vinay +3.4 Hiral diff --git a/data_structures/test_queue.cpp b/data_structures/test_queue.cpp new file mode 100644 index 00000000000..d0fa3502ece --- /dev/null +++ b/data_structures/test_queue.cpp @@ -0,0 +1,93 @@ +#include /// for assert +#include /// for std::cout + +#include "./queue.hpp" + +template +void testConstructedQueueIsEmpty() { + const queue curQueue; + assert(curQueue.isEmptyQueue()); +} + +void testEnQueue() { + queue curQueue; + curQueue.enQueue(10); + assert(curQueue.toVector() == std::vector({10})); + curQueue.enQueue(20); + assert(curQueue.toVector() == std::vector({10, 20})); + curQueue.enQueue(30); + curQueue.enQueue(40); + assert(curQueue.toVector() == std::vector({10, 20, 30, 40})); +} + +void testDeQueue() { + queue curQueue; + curQueue.enQueue(10); + curQueue.enQueue(20); + curQueue.enQueue(30); + + curQueue.deQueue(); + assert(curQueue.toVector() == std::vector({20, 30})); + + curQueue.deQueue(); + assert(curQueue.toVector() == std::vector({30})); + + curQueue.deQueue(); + assert(curQueue.isEmptyQueue()); +} + +void testFront() { + queue curQueue; + curQueue.enQueue(10); + assert(curQueue.front() == 10); + curQueue.enQueue(20); + assert(curQueue.front() == 10); +} + +void testQueueAfterClearIsEmpty() { + queue curQueue; + curQueue.enQueue(10); + curQueue.enQueue(20); + curQueue.enQueue(30); + curQueue.clear(); + assert(curQueue.isEmptyQueue()); +} + +void testFrontThrowsAnInvalidArgumentWhenQueueEmpty() { + const queue curQueue; + bool wasException = false; + try { + curQueue.front(); + } catch (const std::invalid_argument&) { + wasException = true; + } + assert(wasException); +} + +void testDeQueueThrowsAnInvalidArgumentWhenQueueEmpty() { + queue curQueue; + bool wasException = false; + try { + curQueue.deQueue(); + } catch (const std::invalid_argument&) { + wasException = true; + } + assert(wasException); +} + +int main() { + testConstructedQueueIsEmpty(); + testConstructedQueueIsEmpty(); + testConstructedQueueIsEmpty>(); + + testEnQueue(); + testDeQueue(); + + testQueueAfterClearIsEmpty(); + + testFrontThrowsAnInvalidArgumentWhenQueueEmpty(); + testDeQueueThrowsAnInvalidArgumentWhenQueueEmpty(); + + std::cout << "All tests pass!\n"; + return 0; +} diff --git a/data_structures/test_stack.cpp b/data_structures/test_stack.cpp new file mode 100644 index 00000000000..81039e7962c --- /dev/null +++ b/data_structures/test_stack.cpp @@ -0,0 +1,203 @@ +#include /// for assert +#include /// for std::cout +#include /// std::invalid_argument +#include /// for std::vector + +#include "./stack.hpp" + +template +void testConstructedStackIsEmpty() { + const stack curStack; + assert(curStack.isEmptyStack()); +} + +void testPush() { + using valueType = int; + stack curStack; + curStack.push(10); + curStack.push(20); + curStack.push(30); + curStack.push(40); + const auto expectedData = std::vector({40, 30, 20, 10}); + assert(curStack.toVector() == expectedData); +} + +void testTop() { + using valueType = unsigned; + stack curStack; + curStack.push(1); + curStack.push(2); + curStack.push(3); + curStack.push(4); + assert(curStack.top() == static_cast(4)); +} + +void testPop() { + using valueType = int; + stack curStack; + curStack.push(100); + curStack.push(200); + curStack.push(300); + + assert(curStack.top() == static_cast(300)); + curStack.pop(); + assert(curStack.top() == static_cast(200)); + curStack.pop(); + assert(curStack.top() == static_cast(100)); + curStack.pop(); + assert(curStack.isEmptyStack()); +} + +void testClear() { + stack curStack; + curStack.push(1000); + curStack.push(2000); + curStack.clear(); + assert(curStack.isEmptyStack()); +} + +void testCopyOfStackHasSameData() { + stack stackA; + stackA.push(10); + stackA.push(200); + stackA.push(3000); + const auto stackB(stackA); + assert(stackA.toVector() == stackB.toVector()); +} + +void testPushingToCopyDoesNotChangeOriginal() { + using valueType = int; + stack stackA; + stackA.push(10); + stackA.push(20); + stackA.push(30); + auto stackB(stackA); + stackB.push(40); + + const auto expectedDataA = std::vector({30, 20, 10}); + const auto expectedDataB = std::vector({40, 30, 20, 10}); + + assert(stackA.toVector() == expectedDataA); + assert(stackB.toVector() == expectedDataB); +} + +void testPoppingFromCopyDoesNotChangeOriginal() { + using valueType = int; + stack stackA; + stackA.push(10); + stackA.push(20); + stackA.push(30); + auto stackB(stackA); + stackB.pop(); + + const auto expectedDataA = std::vector({30, 20, 10}); + const auto expectedDataB = std::vector({20, 10}); + + assert(stackA.toVector() == expectedDataA); + assert(stackB.toVector() == expectedDataB); +} + +void testPushingToOrginalDoesNotChangeCopy() { + using valueType = int; + stack stackA; + stackA.push(10); + stackA.push(20); + stackA.push(30); + const auto stackB(stackA); + stackA.push(40); + + const auto expectedDataA = std::vector({40, 30, 20, 10}); + const auto expectedDataB = std::vector({30, 20, 10}); + + assert(stackA.toVector() == expectedDataA); + assert(stackB.toVector() == expectedDataB); +} + +void testPoppingFromOrginalDoesNotChangeCopy() { + using valueType = int; + stack stackA; + stackA.push(10); + stackA.push(20); + stackA.push(30); + const auto stackB(stackA); + stackA.pop(); + + const auto expectedDataA = std::vector({20, 10}); + const auto expectedDataB = std::vector({30, 20, 10}); + + assert(stackA.toVector() == expectedDataA); + assert(stackB.toVector() == expectedDataB); +} + +void testAssign() { + using valueType = int; + stack stackA; + stackA.push(10); + stackA.push(20); + stackA.push(30); + stack stackB = stackA; + stackA.pop(); + stackB.push(40); + + const auto expectedDataA = std::vector({20, 10}); + const auto expectedDataB = std::vector({40, 30, 20, 10}); + + assert(stackA.toVector() == expectedDataA); + assert(stackB.toVector() == expectedDataB); + + stackB = stackA; + stackA.pop(); + stackB.push(5); + stackB.push(6); + + const auto otherExpectedDataA = std::vector({10}); + const auto otherExpectedDataB = std::vector({6, 5, 20, 10}); + + assert(stackA.toVector() == otherExpectedDataA); + assert(stackB.toVector() == otherExpectedDataB); +} + +void testTopThrowsAnInvalidArgumentWhenStackEmpty() { + const stack curStack; + bool wasException = false; + try { + curStack.top(); + } catch (const std::invalid_argument&) { + wasException = true; + } + assert(wasException); +} + +void testPopThrowsAnInvalidArgumentWhenStackEmpty() { + stack curStack; + bool wasException = false; + try { + curStack.pop(); + } catch (const std::invalid_argument&) { + wasException = true; + } + assert(wasException); +} + +int main() { + testConstructedStackIsEmpty(); + testConstructedStackIsEmpty(); + + testPush(); + testPop(); + testClear(); + + testCopyOfStackHasSameData(); + testPushingToCopyDoesNotChangeOriginal(); + testPoppingFromCopyDoesNotChangeOriginal(); + testPushingToOrginalDoesNotChangeCopy(); + testPoppingFromOrginalDoesNotChangeCopy(); + + testAssign(); + + testTopThrowsAnInvalidArgumentWhenStackEmpty(); + testPopThrowsAnInvalidArgumentWhenStackEmpty(); + + std::cout << "All tests pass!\n"; + return 0; +} diff --git a/data_structures/test_stack_students.cpp b/data_structures/test_stack_students.cpp new file mode 100644 index 00000000000..dc3514bcb1b --- /dev/null +++ b/data_structures/test_stack_students.cpp @@ -0,0 +1,53 @@ +/* + * This program reads a data file consisting of students' GPAs + * followed by their names. The program then prints the highest + * GPA and the names of the students with the highest GPA. + * It uses stack to store the names of the students + * Run: + * make all + * ./main student.txt + ************************************************************ + * */ +#include +#include +#include +#include +#include +#include + +#include "./stack.hpp" + +int main(int argc, char* argv[]) { + double GPA = NAN; + double highestGPA = NAN; + std::string name; + + assert(argc == 2); + std::ifstream infile; + stack stk; + + infile.open(argv[1]); + std::cout << std::fixed << std::showpoint; + std::cout << std::setprecision(2); + infile >> GPA >> name; + highestGPA = GPA; + + while (infile) { + if (GPA > highestGPA) { + stk.clear(); + stk.push(name); + highestGPA = GPA; + } else if (GPA == highestGPA) { + stk.push(name); + } + infile >> GPA >> name; + } + std::cout << "Highest GPA: " << highestGPA << std::endl; + std::cout << "Students the highest GPA are: " << std::endl; + while (!stk.isEmptyStack()) { + std::cout << stk.top() << std::endl; + stk.pop(); + } + std::cout << std::endl; + return 0; +} diff --git a/data_structures/treap.cpp b/data_structures/treap.cpp new file mode 100644 index 00000000000..592f49e7dfb --- /dev/null +++ b/data_structures/treap.cpp @@ -0,0 +1,258 @@ +/** + * @file + * @brief A balanced binary search tree (BST) on the basis of binary search tree + * and heap: the [Treap](https://en.wikipedia.org/wiki/Treap) algorithm + * implementation + * + * @details + * Implementation of the treap data structre + * + * Support operations including insert, erase, and query (the rank of specified + * element or the element ranked x) as the same as BST + * + * But these operations take O(log N) time, since treap keeps property of heap + * using rotate operation, and the desired depth of the tree is O(log N). + * There's very little chance that it will degenerate into a chain like BST + * + * @author [Kairao ZHENG](https://github.com/fgmn) + */ + +#include /// For array +#include /// For assert +#include +#include /// For IO operations + +/** + * @namespace + * @brief Data Structures + */ +namespace data_structures { +/** + * @namespace + * @brief Functions for the [Treap](https://en.wikipedia.org/wiki/Treap) + * algorithm implementation + */ +namespace treap { +const int maxNode = 1e5 + 5; ///< maximum number of nodes +/** + * @brief Struct representation of the treap + */ +struct Treap { + int root = 0; ///< root of the treap + int treapCnt = 0; ///< Total number of current nodes in the treap + std::array key = {}; ///< Node identifier + std::array priority = {}; ///< Random priority + std::array, maxNode> childs = { + {}}; ///< [i][0] represents the + ///< left child of node i, and + ///[i][1] represents the right + std::array cnt = + {}; ///< Maintains the subtree size for ranking query + std::array size = {}; ///< The number of copies per node + /** + * @brief Initialization + */ + Treap() : treapCnt(1) { + priority[0] = INT32_MAX; + size[0] = 0; + } + /** + * @brief Update the subtree size of the node + * @param x The node to update + */ + void update(int x) { + size[x] = size[childs[x][0]] + cnt[x] + size[childs[x][1]]; + } + /** + * @brief Rotate without breaking the property of BST + * @param x The node to rotate + * @param t 0 represent left hand, while 1 right hand + */ + void rotate(int &x, int t) { + int y = childs[x][t]; + childs[x][t] = childs[y][1 - t]; + childs[y][1 - t] = x; + // The rotation will only change itself and its son nodes + update(x); + update(y); + x = y; + } + /** + * @brief Insert a value into the specified subtree (internal method) + * @param x Insert into the subtree of node x (Usually x=root) + * @param k Key to insert + */ + void _insert(int &x, int k) { + if (x) { + if (key[x] == k) { + cnt[x]++; + } // If the node already exists, the number of copies is ++ + else { + int t = (key[x] < k); // Insert according to BST properties + _insert(childs[x][t], k); + // After insertion, the heap properties are retained by rotation + if (priority[childs[x][t]] < priority[x]) { + rotate(x, t); + } + } + } else { // Create a new node + x = treapCnt++; + key[x] = k; + cnt[x] = 1; + priority[x] = rand(); // Random priority + childs[x][0] = childs[x][1] = 0; + } + update(x); + } + /** + * @brief Erase a value from the specified subtree (internal method) + * @param x Erase from the subtree of node x (Usually x=root) + * @param k Key to erase + */ + void _erase(int &x, int k) { + if (key[x] == k) { + if (cnt[x] > 1) { + cnt[x]--; + } // If the node has more than one copy, the number of copies -- + else { + if (childs[x][0] == 0 && childs[x][1] == 0) { + x = 0; + return; + } // If there are no children, delete and return + // Otherwise, we need to rotate the sons and delete them + // recursively + int t = (priority[childs[x][0]] > priority[childs[x][1]]); + rotate(x, t); + _erase(x, k); + } + } else { // Find the target value based on BST properties + _erase(childs[x][key[x] < k], k); + } + update(x); + } + /** + * @brief Find the KTH largest value (internal method) + * @param x Query the subtree of node x (Usually x=root) + * @param k The queried rank + * @return The element ranked number k + */ + int _get_k_th(int &x, int k) { + if (k <= size[childs[x][0]]) { + return _get_k_th(childs[x][0], k); + } + k -= size[childs[x][0]] + cnt[x]; + if (k <= 0) { + return key[x]; + } + return _get_k_th(childs[x][1], k); + } + /** + * @brief Query the rank of specified element (internal method) + * @param x Query the subtree of node x (Usually x=root) + * @param k The queried element + * @return The rank of element k + */ + int _get_rank(int x, int k) { + if (!x) { + return 0; + } + if (k == key[x]) { + return size[childs[x][0]] + 1; + } else if (k < key[x]) { + return _get_rank(childs[x][0], k); + } else { + return size[childs[x][0]] + cnt[x] + _get_rank(childs[x][1], k); + } + } + /** + * @brief Get the predecessor node of element k + * @param k The queried element + * @return The predecessor + */ + int get_predecessor(int k) { + int x = root, pre = -1; + while (x) { + if (key[x] < k) { + pre = key[x], x = childs[x][1]; + } else { + x = childs[x][0]; + } + } + return pre; + } + /** + * @brief Get the successor node of element k + * @param k The queried element + * @return The successor + */ + int get_next(int k) { + int x = root, next = -1; + while (x) { + if (key[x] > k) { + next = key[x], x = childs[x][0]; + } else { + x = childs[x][1]; + } + } + return next; + } + /** + * @brief Insert element (External method) + * @param k Key to insert + */ + void insert(int k) { _insert(root, k); } + /** + * @brief Erase element (External method) + * @param k Key to erase + */ + void erase(int k) { _erase(root, k); } + /** + * @brief Get the KTH largest value (External method) + * @param k The queried rank + * @return The element ranked number x + */ + int get_k_th(int k) { return _get_k_th(root, k); } + /** + * @brief Get the rank of specified element (External method) + * @param k The queried element + * @return The rank of element k + */ + int get_rank(int k) { return _get_rank(root, k); } +}; +} // namespace treap +} // namespace data_structures + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + data_structures::treap::Treap mTreap; ///< Treap object instance + + mTreap.insert(1); + mTreap.insert(2); + mTreap.insert(3); + assert(mTreap.get_k_th(2) == 2); + mTreap.insert(4); + mTreap.insert(5); + mTreap.insert(6); + assert(mTreap.get_next(4) == 5); + mTreap.insert(7); + assert(mTreap.get_predecessor(7) == 6); + mTreap.erase(4); + assert(mTreap.get_k_th(4) == 5); + assert(mTreap.get_rank(5) == 4); + mTreap.insert(10); + assert(mTreap.get_rank(10) == 7); + assert(mTreap.get_predecessor(10) == 7); + + std::cout << "All tests have successfully passed!\n"; +} +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} diff --git a/data_structures/tree.cpp b/data_structures/tree.cpp new file mode 100644 index 00000000000..f46c31ff22a --- /dev/null +++ b/data_structures/tree.cpp @@ -0,0 +1,119 @@ +#include +#include +using namespace std; + +struct node { + int val; + node *left; + node *right; +}; + +void CreateTree(node *curr, node *n, int x, char pos) { + if (n != NULL) { + char ch; + cout << "\nLeft or Right of " << n->val << " : "; + cin >> ch; + if (ch == 'l') + CreateTree(n, n->left, x, ch); + else if (ch == 'r') + CreateTree(n, n->right, x, ch); + } else { + node *t = new node; + t->val = x; + t->left = NULL; + t->right = NULL; + if (pos == 'l') { + curr->left = t; + } else if (pos == 'r') { + curr->right = t; + } + } +} + +void BFT(node *n) { + list queue; + + queue.push_back(n); + + while (!queue.empty()) { + n = queue.front(); + cout << n->val << " "; + queue.pop_front(); + + if (n->left != NULL) + queue.push_back(n->left); + if (n->right != NULL) + queue.push_back(n->right); + } +} + +void Pre(node *n) { + if (n != NULL) { + cout << n->val << " "; + Pre(n->left); + Pre(n->right); + } +} + +void In(node *n) { + if (n != NULL) { + In(n->left); + cout << n->val << " "; + In(n->right); + } +} + +void Post(node *n) { + if (n != NULL) { + Post(n->left); + Post(n->right); + cout << n->val << " "; + } +} + +int main() { + int value; + int ch; + node *root = new node; + cout << "\nEnter the value of root node :"; + cin >> value; + root->val = value; + root->left = NULL; + root->right = NULL; + do { + cout << "\n1. Insert"; + cout << "\n2. Breadth First"; + cout << "\n3. Preorder Depth First"; + cout << "\n4. Inorder Depth First"; + cout << "\n5. Postorder Depth First"; + + cout << "\nEnter Your Choice : "; + cin >> ch; + switch (ch) { + case 1: + int x; + char pos; + cout << "\nEnter the value to be Inserted : "; + cin >> x; + cout << "\nLeft or Right of Root : "; + cin >> pos; + if (pos == 'l') + CreateTree(root, root->left, x, pos); + else if (pos == 'r') + CreateTree(root, root->right, x, pos); + break; + case 2: + BFT(root); + break; + case 3: + Pre(root); + break; + case 4: + In(root); + break; + case 5: + Post(root); + break; + } + } while (ch != 0); +} diff --git a/data_structures/tree_234.cpp b/data_structures/tree_234.cpp new file mode 100644 index 00000000000..46de03bfaef --- /dev/null +++ b/data_structures/tree_234.cpp @@ -0,0 +1,1306 @@ +/** + * @file + * @brief A demo 2-3-4 tree implementation + * @details + * 2–3–4 tree is a self-balancing data structure that is an isometry of + * red–black trees. Though we seldom use them in practice, we study them + * to understand the theory behind Red-Black tree. Please read following + * links for more infomation. + * [2–3–4 tree](https://en.wikipedia.org/wiki/2%E2%80%933%E2%80%934_tree) + * [2-3-4 Trees: A Visual +Introduction](https://www.educative.io/page/5689413791121408/80001) + * We Only implement some basic and complicated operations in this demo. + * Other operations should be easy to be added. + * @author [liuhuan](https://github.com/fedom) + */ +#include /// for std::array +#include /// for assert +#include /// for std::ofstream +#include /// for std::cout +#include /// for std::unique_ptr +#include /// for std::queue +#include /// for std::to_string + +/** + * @namespace data_structures + * @brief Algorithms with data structures + */ +namespace data_structures { +/** + * @namespace tree_234 + * @brief Functions for [2–3–4 tree](https://en.wikipedia.org/wiki/2%E2%80%933%E2%80%934_tree) + */ +namespace tree_234 { +/** @brief 2-3-4 tree node class */ +class Node { + public: + /** + * @brief Node constructor + * @param item the first value we insert to the node + */ + explicit Node(int64_t item) + : count(1), + items({{item, 0, 0}}), + children({{nullptr, nullptr, nullptr, nullptr}}) {} + + /** + * @brief Get the item count that current saved in the node + * @return item count + */ + int8_t GetCount() { return count; } + + /** + * @brief Set the item count of the node + * + * This is only used when we spliting and merging node where we need to do + * some raw operation manually. In common inserting and removing operation + * the count is maintained automatically. + * + * @param c the count to set + */ + void SetCount(int8_t c) { count = c; } + + /** + * @brief Check if node is a leaf + * @return true if node is leaf, false otherwise + */ + bool IsLeaf() { return children[0] == nullptr; } + + /** + * @brief Check if node is a full (4-node) + * @return true if node is full (4-node), false otherwise + */ + bool IsFull() { return count == 3; } + + /** + * @brief Check if node is a 2-node + * @return true if node is 2-node, otherwise false + */ + bool Is2Node() { return count == 1; } + + /** @brief Check if node is a 3-node or 4-node, this is useful when we + * delete item from 2-3-4 tree + * @return true if node is 3-node or 4-node, false otherwise + */ + bool Is34Node() { return count == 2 || count == 3; } + + /** + * @brief Check if item is in the node + * @param item item to check + * @return true if item in the node, otherwise false + */ + bool Contains(int64_t item) { + for (int8_t i = 0; i < count; i++) { + if (item == items[i]) { + return true; + } + } + return false; + } + + /** + * @brief Get the index of the item in the node, 0-based + * @param item item to check + * @return 0-based index of the item in the node, if not in the node, -1 is + * returned + */ + int8_t GetItemIndex(int64_t item) { + for (int8_t i = 0; i < count; i++) { + if (items[i] == item) { + return i; + } + } + return -1; + } + + /** + * @brief Get max item (rightmost) in the current node + * @return max item + */ + int64_t GetMaxItem() { return items[count - 1]; } + + /** + * @brief get min item (leftmost) in the current node + * @return min item + */ + int64_t GetMinItem() { return items[0]; } + + /** + * @brief Get item of the \index index + * @param index the item index to get + * @return the item + */ + int64_t GetItem(int8_t index) { return items[index]; } + + /** + * @brief Set item value at position of index + * @param index the index of the item to set + * @param new_item item value + */ + void SetItem(int8_t index, int64_t new_item) { + assert(index >= 0 && index <= 2); + + items[index] = new_item; + } + + /** + * @brief Insert item to the proper position of the node and return the + * position index. + * + * This is a helper function we use during insertion. Please mind that when + * insert a item, we aslo need to take care of two child pointers. One is + * the original child pointer at the insertion position. It can be placed as + * new item's either left child or right child. And the other is the new + * child that should be added. For our dedicated situation here, we choose + * to use the original child as the new item's left child, and add a null + * pointer to its right child. So after use the function, please update + * these two children pointer manually. + * + * @param item value to be inserted to the node + * @return index where item is inserted, caller can use this + * index to update its left and right child + */ + int InsertItem(int item) { + assert(!IsFull()); + + if (Contains(item)) { + return -1; + } + + int8_t i = 0; + for (i = 0; i < count; i++) { + if (items[i] > item) { + break; + } + } + + InsertItemByIndex(i, item, nullptr, true); + return i; + } + + /** + * @brief Insert a value to the index position + * @param index index where to insert item + * @param item value to insert + * @param with_child new added child pointer + * @param to_left true indicate adding with_child to new item's left child, + * otherwise to right child + */ + void InsertItemByIndex(int8_t index, int64_t item, Node *with_child, + bool to_left = true) { + assert(count < 3 && index >= 0 && index < 3); + + for (int8_t i = count - 1; i >= index; i--) { + items[i + 1] = items[i]; + } + + items[index] = item; + + int8_t start_index = to_left ? index : index + 1; + + for (int8_t i = count; i >= start_index; i--) { + children[i + 1] = children[i]; + } + + children[start_index] = with_child; + + count++; + } + + /** + * @brief Insert a value to the index position + * @param index index of the item to remove + * @param keep_left which child of the item to keep, true keep the left + * child, false keep the right child + * @return the removed child pointer + */ + Node *RemoveItemByIndex(int8_t index, bool keep_left) { + assert(index >= 0 && index < count); + Node *removed_child = keep_left ? children[index + 1] : children[index]; + for (int8_t i = index; i < count - 1; i++) { + items[i] = items[i + 1]; + } + + for (int8_t i = keep_left ? index + 1 : index; i < count; i++) { + children[i] = children[i + 1]; + } + + count--; + return removed_child; + } + + /** + * @brief Get the child's index of the children array + * @param child child pointer of which to get the index + * @return the index of child + */ + int8_t GetChildIndex(Node *child) { + for (int8_t i = 0; i < count + 1; i++) { + if (children[i] == child) { + return i; + } + } + + return -1; + } + + /** + * @brief Get the child pointer at position of index + * @param index index of child to get + * @return the child pointer + */ + Node *GetChild(int8_t index) { return children[index]; } + + /** + * @brief Set child pointer to the position of index + * @param index children index + * @param child pointer to set + */ + void SetChild(int8_t index, Node *child) { children[index] = child; } + + /** + * @brief Get rightmose child of the current node + * @return the rightmost child + */ + Node *GetRightmostChild() { return children[count]; } + + /** + * @brief Get leftmose child of the current node + * @return the leftmost child + */ + Node *GetLeftmostChild() { return children[0]; } + + /** + * @brief Get left child of item at item_index + * @param item_index index of the item whose left child to be get + * @return left child of items[index]'s + */ + Node *GetItemLeftChild(int8_t item_index) { + if (item_index < 0 || item_index > count - 1) { + return nullptr; + } + + return children[item_index]; + } + + /** + * @brief Get right child of item at item_index + * @param item_index index of the item whose right child to be get + * @return right child of items[index]'s + */ + Node *GetItemRightChild(int8_t item_index) { + if (item_index < 0 || item_index > count - 1) { + return nullptr; + } + + return children[item_index + 1]; + } + + /** + * @brief Get next node which is possibly contains item + * @param item item to search + * @return the next node that possibly contains item + */ + Node *GetNextPossibleChild(int64_t item) { + int i = 0; + for (i = 0; i < count; i++) { + if (items[i] > item) { + break; + } + } + return children[i]; + } + + private: + std::array items; ///< store items + + std::array children; ///< store the children pointers + + int8_t count = 0; ///< track the current item count +}; + +/** @brief 2-3-4 tree class */ +class Tree234 { + public: + Tree234() = default; + Tree234(const Tree234 &) = delete; + Tree234(const Tree234 &&) = delete; + Tree234 &operator=(const Tree234 &) = delete; + Tree234 &operator=(const Tree234 &&) = delete; + + ~Tree234(); + + /** + * @brief Insert item to tree + * @param item item to insert + */ + void Insert(int64_t item); + + /** + * @brief Remove item from tree + * @param item item to remove + * @return true if item found and removed, false otherwise + */ + bool Remove(int64_t item); + + /** @brief In-order traverse */ + void Traverse(); + + /** + * @brief Print tree into a dot file + * @param file_name output file name, if nullptr then use "out.dot" as + * default + */ + void Print(const char *file_name = nullptr); + + private: + /** + * @brief A insert implementation of pre-split + * @param item item to insert + */ + void InsertPreSplit(int64_t item); + + /** + * @brief A insert implementation of post-merge + * @param item item to insert + */ + void InsertPostMerge(int64_t item); + + /** + * @brief A helper function used by post-merge insert + * @param tree tree where to insert item + * @param item item to insert + * @return the node that split as the parent when overflow happen + */ + Node *Insert(Node *tree, int64_t item); + + /** + * @brief A helper function used during post-merge insert + * + * When the inserting leads to overflow, it will split the node to 1 parent + * and 2 children. The parent will be merged to its origin parent after + * that. This is the function to complete this task. So the param node is + * always a 2-node. + * + * @param dst_node the target node we will merge node to, can be type of + * 2-node, 3-node or 4-node + * @param node the source node we will merge from, type must be 2-node + * @return overflow node of this level + */ + Node *MergeNode(Node *dst_node, Node *node); + + /** + * @brief Merge node to a not-full target node + * + * Since the target node is not-full, no overflow will happen. So we have + * nothing to return. + * + * @param dst_node the target not-full node, that is the type is either + * 2-node or 3-node, but not 4-node + * @param node the source node we will merge from, type must be 2-node + */ + void MergeNodeNotFull(Node *dst_node, Node *node); + + /** + * @brief Split a 4-node to 1 parent and 2 children, and return the parent + * node + * @param node the node to split, it must be a 4-node + * @return split parent node + */ + Node *SplitNode(Node *node); + + /** + * @brief Get the max item of the tree + * @param tree the tree we will get item from + * @return max item of the tree + */ + int64_t GetTreeMaxItem(Node *tree); + + /** + * @brief Get the min item of the tree + * @param tree the tree we will get item from + * @return min item of the tree + */ + int64_t GetTreeMinItem(Node *tree); + + /** + * @brief A handy function to try if we can do a left rotate to the target + * node + * + * Given two node, the parent and the target child, the left rotate + * operation is uniquely identified. The source node must be the right + * sibling of the target child. The operation can be successfully done if + * the to_child has a right sibling and its right sibling is not 2-node. + * + * @param parent the parent node in this left rotate operation + * @param to_child the target child of this left rotate operation. In our + * case, this node is always 2-node + * @return true if we successfully do the rotate. false if the + * requirements are not fulfilled. + */ + bool TryLeftRotate(Node *parent, Node *to_child); + + /** + * @brief A handy function to try if we can do a right rotate to the target + * node + * + * Given two node, the parent and the target child, the right rotate + * operation is uniquely identified. The source node must be the left + * sibling of the target child. The operation can be successfully done if + * the to_child has a left sibling and its left sibling is not 2-node. + * + * @param parent the parent node in this right rotate operation + * @param to_child the target child of this right rotate operation. In our + * case, it is always 2-node + * @return true if we successfully do the rotate. false if the + * requirements are not fulfilled. + */ + bool TryRightRotate(Node *parent, Node *to_child); + + /** + * @brief Do the actual right rotate operation + * + * Given parent node, and the pivot item index, the right rotate operation + * is uniquely identified. The function assume the requirements are + * fulfilled and won't do any extra check. This function is call by + * TryRightRotate(), and the condition checking should be done before call + * it. + * + * @param parent the parent node in this right rotate operation + * @param index the pivot item index of this right rotate operation. + */ + void RightRotate(Node *parent, int8_t index); + + /** + * @brief Do the actual left rotate operation + * + * Given parent node, and the pivot item index, the left rotate operation is + * uniquely identified. The function assume the requirements are fulfilled + * and won't do any extra check. This function is call by TryLeftRotate(), + * and the condition checking should be done before call it. + * + * @param parent the parent node in this right rotate operation + * @param index the pivot item index of this right rotate operation. + */ + void LeftRotate(Node *parent, int8_t index); + + /** + * @brief Main function implement the pre-merge remove operation + * @param node the tree to remove item from + * @param item item to remove + * @return true if remove success, false otherwise + * */ + bool RemovePreMerge(Node *node, int64_t item); + + /** + * @brief Merge the item at index of the parent node, and its left and right + * child + * + * the left and right child node must be 2-node. The 3 items will be merged + * into a 4-node. In our case the parent can be a 2-node iff it is the root. + * Otherwise, it must be 3-node or 4-node. + * + * @param parent the parent node in the merging operation + * @param index the item index of the parent node that involved in the + * merging + * @return the merged 4-node + */ + Node *Merge(Node *parent, int8_t index); + + /** + * @brief Recursive release the tree + * @param tree root node of the tree to delete + */ + void DeleteNode(Node *tree); + + /** + * @brief In-order traverse the tree, print items + * @param tree tree to traverse + */ + void Traverse(Node *tree); + + /** + * @brief Print the tree to a dot file. You can convert it to picture with + * graphviz + * @param ofs output file stream to print to + * @param node current node to print + * @param parent_index current node's parent node index, this is used to + * draw the link from parent to current node + * @param index current node's index of level order which is used to name + * the node in dot file + * @param parent_child_index the index that current node in parent's + * children array, range in [0,4), help to locate the start position of the + * link between nodes + */ + void PrintNode(std::ofstream &ofs, Node *node, int64_t parent_index, + int64_t index, int8_t parent_child_index); + + Node *root_{nullptr}; ///< root node of the tree +}; + +Tree234::~Tree234() { DeleteNode(root_); } + +/** + * @brief Recursive release the tree + * @param tree root node of the tree to delete + */ +void Tree234::DeleteNode(Node *tree) { + if (!tree) { + return; + } + for (int8_t i = 0; i <= tree->GetCount(); i++) { + DeleteNode(tree->GetChild(i)); + } + + delete tree; +} + +/** + * @brief In-order traverse the tree, print items + * @param tree tree to traverse + */ +void Tree234::Traverse() { + Traverse(root_); + std::cout << std::endl; +} + +void Tree234::Traverse(Node *node) { + if (!node) { + return; + } + + int8_t i = 0; + for (i = 0; i < node->GetCount(); i++) { + Traverse(node->GetChild(i)); + std::cout << node->GetItem(i) << ", "; + } + + Traverse(node->GetChild(i)); +} + +/** + * @brief A insert implementation of pre-split + * @param item item to insert + */ +void Tree234::InsertPreSplit(int64_t item) { + if (!root_) { + root_ = new Node(item); + return; + } + + Node *parent = nullptr; + Node *node = root_; + + while (true) { + if (!node) { + std::unique_ptr tmp(new Node(item)); + MergeNodeNotFull(parent, tmp.get()); + return; + } + + if (node->Contains(item)) { + return; + } + + if (node->IsFull()) { + node = SplitNode(node); + + Node *cur_node = nullptr; + + if (item < node->GetItem(0)) { + cur_node = node->GetChild(0); + } else { + cur_node = node->GetChild(1); + } + + if (!parent) { + // for the root node parent is nullptr, we simply assign the + // split parent to root_ + root_ = node; + } else { + // merge the split parent to its origin parent + MergeNodeNotFull(parent, node); + } + + node = cur_node; + } + + parent = node; + node = parent->GetNextPossibleChild(item); + } +} + +/** + * @brief A insert implementation of post-merge + * @param item item to insert + */ +void Tree234::InsertPostMerge(int64_t item) { + if (!root_) { + root_ = new Node(item); + return; + } + + Node *split_node = Insert(root_, item); + + // if root has split, then update root_ + if (split_node) { + root_ = split_node; + } +} + +/** + * @brief Insert item to tree + * @param item item to insert + */ +void Tree234::Insert(int64_t item) { InsertPreSplit(item); } + +/** + * @brief A helper function used by post-merge insert + * @param tree tree where to insert item + * @param item item to insert + * @return the node that split as the parent when overflow happen + */ +Node *Tree234::Insert(Node *tree, int64_t item) { + assert(tree != nullptr); + + std::unique_ptr split_node; + + if (tree->Contains(item)) { + // return nullptr indicate current node not overflow + return nullptr; + } + + Node *next_node = tree->GetNextPossibleChild(item); + if (next_node) { + split_node.reset(Insert(next_node, item)); + } else { + split_node.reset(new Node(item)); + } + + if (split_node) { + return MergeNode(tree, split_node.get()); + } + + return nullptr; +} + +/** + * @brief A helper function used during post-merge insert + * + * When the inserting leads to overflow, it will split the node to 1 parent + * and 2 children. The parent will be merged to its origin parent after + * that. This is the function to complete this task. So the param node is + * always a 2-node. + * + * @param dst_node the target node we will merge node to, can be type of + * 2-node, 3-node or 4-node + * @param node the source node we will merge from, type must be 2-node + * @return overflow node of this level + */ +Node *Tree234::MergeNode(Node *dst_node, Node *node) { + assert(dst_node != nullptr && node != nullptr); + + if (!dst_node->IsFull()) { + MergeNodeNotFull(dst_node, node); + return nullptr; + } + + dst_node = SplitNode(dst_node); + + if (node->GetItem(0) < dst_node->GetItem(0)) { + MergeNodeNotFull(dst_node->GetChild(0), node); + + } else { + MergeNodeNotFull(dst_node->GetChild(1), node); + } + + return dst_node; +} + +/** + * @brief Merge node to a not-full target node + * + * Since the target node is not-full, no overflow will happen. So we have + * nothing to return. + * + * @param dst_node the target not-full node, that is the type is either + * 2-node or 3-node, but not 4-node + * @param node the source node we will merge from, type must be 2-node + */ +void Tree234::MergeNodeNotFull(Node *dst_node, Node *node) { + assert(dst_node && node && !dst_node->IsFull() && node->Is2Node()); + + int8_t i = dst_node->InsertItem(node->GetItem(0)); + + dst_node->SetChild(i, node->GetChild(0)); + dst_node->SetChild(i + 1, node->GetChild(1)); +} + +/** + * @brief Split a 4-node to 1 parent and 2 children, and return the parent + * node + * @param node the node to split, it must be a 4-node + * @return split parent node + */ +Node *Tree234::SplitNode(Node *node) { + assert(node->GetCount() == 3); + + Node *left = node; + + Node *right = new Node(node->GetItem(2)); + right->SetChild(0, node->GetChild(2)); + right->SetChild(1, node->GetChild(3)); + + Node *parent = new Node(node->GetItem(1)); + parent->SetChild(0, left); + parent->SetChild(1, right); + + left->SetCount(1); + + return parent; +} + +/** + * @brief A handy function to try if we can do a left rotate to the target + * node + * + * Given two node, the parent and the target child, the left rotate + * operation is uniquely identified. The source node must be the right + * sibling of the target child. The operation can be successfully done if + * the to_child has a right sibling and its right sibling is not 2-node. + * + * @param parent the parent node in this left rotate operation + * @param to_child the target child of this left rotate operation. In our + * case, this node is always 2-node + * @return true if we successfully do the rotate. false if the + * requirements are not fulfilled. + */ +bool Tree234::TryLeftRotate(Node *parent, Node *to_child) { + int to_child_index = parent->GetChildIndex(to_child); + + // child is right most, can not do left rotate to it + if (to_child_index >= parent->GetCount()) { + return false; + } + + Node *right_sibling = parent->GetChild(to_child_index + 1); + + // right sibling is 2-node. can not do left rotate. + if (right_sibling->Is2Node()) { + return false; + } + + LeftRotate(parent, to_child_index); + + return true; +} + +/** + * @brief A handy function to try if we can do a right rotate to the target + * node + * + * Given two node, the parent and the target child, the right rotate + * operation is uniquely identified. The source node must be the left + * sibling of the target child. The operation can be successfully done if + * the to_child has a left sibling and its left sibling is not 2-node. + * + * @param parent the parent node in this right rotate operation + * @param to_child the target child of this right rotate operation. In our + * case, it is always 2-node + * @return true if we successfully do the rotate. false if the + * requirements are not fulfilled. + */ +bool Tree234::TryRightRotate(Node *parent, Node *to_child) { + int8_t to_child_index = parent->GetChildIndex(to_child); + + // child is left most, can not do right rotate to it + if (to_child_index <= 0) { + return false; + } + + Node *left_sibling = parent->GetChild(to_child_index - 1); + + // right sibling is 2-node. can not do left rotate. + if (left_sibling->Is2Node()) { + return false; + } + + RightRotate(parent, to_child_index - 1); + + return true; +} + +/** + * @brief Do the actual right rotate operation + * + * Given parent node, and the pivot item index, the right rotate operation + * is uniquely identified. The function assume the requirements are + * fulfilled and won't do any extra check. This function is call by + * TryRightRotate(), and the condition checking should be done before call + * it. + * + * @param parent the parent node in this right rotate operation + * @param index the pivot item index of this right rotate operation. + */ +void Tree234::RightRotate(Node *parent, int8_t index) { + Node *left = parent->GetItemLeftChild(index); + Node *right = parent->GetItemRightChild(index); + + assert(left && left->Is34Node()); + assert(right && right->Is2Node()); + + right->InsertItemByIndex(0, parent->GetItem(index), + left->GetRightmostChild(), true); + parent->SetItem(index, left->GetMaxItem()); + left->RemoveItemByIndex(left->GetCount() - 1, true); +} + +/** + * @brief Do the actual left rotate operation + * + * Given parent node, and the pivot item index, the left rotate operation is + * uniquely identified. The function assume the requirements are fulfilled + * and won't do any extra check. This function is call by TryLeftRotate(), + * and the condition checking should be done before call it. + * + * @param parent the parent node in this right rotate operation + * @param index the pivot item index of this right rotate operation. + */ +void Tree234::LeftRotate(Node *parent, int8_t index) { + Node *left = parent->GetItemLeftChild(index); + Node *right = parent->GetItemRightChild(index); + + assert(right && right->Is34Node()); + assert(left && left->Is2Node()); + + left->InsertItemByIndex(left->GetCount(), parent->GetItem(index), + right->GetLeftmostChild(), false); + parent->SetItem(index, right->GetMinItem()); + right->RemoveItemByIndex(0, false); +} + +/** + * @brief Merge the item at index of the parent node, and its left and right + * child + * + * the left and right child node must be 2-node. The 3 items will be merged + * into a 4-node. In our case the parent can be a 2-node iff it is the root. + * Otherwise, it must be 3-node or 4-node. + * + * @param parent the parent node in the merging operation + * @param index the item index of the parent node that involved in the + * merging + * @return the merged 4-node + */ +Node *Tree234::Merge(Node *parent, int8_t index) { + assert(parent); + + // bool is_parent_2node = parent->Is2Node(); + + Node *left_child = parent->GetItemLeftChild(index); + Node *right_child = parent->GetItemRightChild(index); + + assert(left_child->Is2Node() && right_child->Is2Node()); + + int64_t item = parent->GetItem(index); + + // 1. merge parent's item and right child to left child + left_child->SetItem(1, item); + left_child->SetItem(2, right_child->GetItem(0)); + left_child->SetChild(2, right_child->GetChild(0)); + left_child->SetChild(3, right_child->GetChild(1)); + + left_child->SetCount(3); + + // 2. remove the parent's item + parent->RemoveItemByIndex(index, true); + + // 3. delete the unused right child + delete right_child; + + return left_child; +} + +/** + * @brief Remove item from tree + * @param item item to remove + * @return true if item found and removed, false otherwise + */ +bool Tree234::Remove(int64_t item) { return RemovePreMerge(root_, item); } + +/** + * @brief Main function implement the pre-merge remove operation + * @param node the tree to remove item from + * @param item item to remove + * @return true if remove success, false otherwise + */ +bool Tree234::RemovePreMerge(Node *node, int64_t item) { + while (node) { + if (node->IsLeaf()) { + if (node->Contains(item)) { + if (node->Is2Node()) { + // node must be root + delete node; + root_ = nullptr; + } else { + node->RemoveItemByIndex(node->GetItemIndex(item), true); + } + return true; + } + return false; + } + + // node is internal + if (node->Contains(item)) { + int8_t index = node->GetItemIndex(item); + + // Here is important!!! What we do next depend on its children's + // state. Why? + Node *left_child = node->GetItemLeftChild(index); + Node *right_child = node->GetItemRightChild(index); + assert(left_child && right_child); + + if (left_child->Is2Node() && right_child->Is2Node()) { + // both left and right child are 2-node,we should not modify + // current node in this situation. Because we are going to do + // merge with its children which will move target item to next + // layer. so if we replace the item with successor or + // predecessor now, when we do the recursive remove with + // successor or predecessor, we will result in removing the just + // replaced one in the merged node. That's not what we want. + + // we need to convert the child 2-node to 3-node or 4-node + // first. First we try to see if any of them can convert to + // 3-node by rotate. By using rotate we keep the empty house for + // the future insertion which will be more efficient than merge. + // + // | ? | node | ? | + // / | | \ + // / | | \ + // / | | \ + // / | | \ + // / | | \ + // / | | \ + // ? left_child right_child ? + // + + // node must be the root + if (node->Is2Node()) { + // this means we can't avoid merging the target item into + // next layer, and this will cause us do different process + // compared with other cases + Node *new_root = Merge(node, index); + delete root_; + root_ = new_root; + node = root_; + + // now node point to the + continue; + } + + // here means we can avoid merging the target item into next + // layer. So we convert one of its left or right child to 3-node + // and then do the successor or predecessor swap and recursive + // remove the next layer will successor or predecessor. + do { + if (index > 0) { + // left_child has left-sibling, we check if we can do a + // rotate + Node *left_sibling = node->GetItemLeftChild(index - 1); + if (left_sibling->Is34Node()) { + RightRotate(node, index - 1); + break; + } + } + + if (index < node->GetCount() - 1) { + // right_child has right-sibling, we check if we can do + // a rotate + Node *right_sibling = + node->GetItemRightChild(index + 1); + if (right_sibling->Is34Node()) { + LeftRotate(node, index + 1); + break; + } + } + + // we do a merge. We avoid merging the target item, which + // may trigger another merge in the recursion process. + if (index > 0) { + Merge(node, index - 1); + break; + } + + Merge(node, index + 1); + + } while (false); + } + + // refresh the left_child and right_child since they may be invalid + // because of merge + left_child = node->GetItemLeftChild(index); + right_child = node->GetItemRightChild(index); + + if (left_child->Is34Node()) { + int64_t predecessor_item = GetTreeMaxItem(left_child); + node->SetItem(node->GetItemIndex(item), predecessor_item); + + node = left_child; + item = predecessor_item; + continue; + } + + if (right_child->Is34Node()) { + int64_t successor_item = GetTreeMinItem(right_child); + node->SetItem(node->GetItemIndex(item), successor_item); + node = right_child; + item = successor_item; + continue; + } + } + + Node *next_node = node->GetNextPossibleChild(item); + + if (next_node->Is34Node()) { + node = next_node; + continue; + } + + if (TryRightRotate(node, next_node)) { + node = next_node; + continue; + } + + if (TryLeftRotate(node, next_node)) { + node = next_node; + continue; + } + + // get here means both left sibling and right sibling of next_node is + // 2-node, so we do merge + int8_t child_index = node->GetChildIndex(next_node); + if (child_index > 0) { + node = Merge(node, child_index - 1); + } else { + node = Merge(node, child_index); + } + + } // while + + return false; +} + +/** + * @brief Get the max item of the tree + * @param tree the tree we will get item from + * @return max item of the tree + */ +int64_t Tree234::GetTreeMaxItem(Node *tree) { + assert(tree); + int64_t max = 0; + + while (tree) { + max = tree->GetMaxItem(); + tree = tree->GetRightmostChild(); + } + + return max; +} + +/** + * @brief Get the min item of the tree + * @param tree the tree we will get item from + * @return min item of the tree + */ +int64_t Tree234::GetTreeMinItem(Node *tree) { + assert(tree); + int64_t min = 0; + + while (tree) { + min = tree->GetMinItem(); + tree = tree->GetLeftmostChild(); + } + + return min; +} + +/** + * @brief Print tree into a dot file + * @param file_name output file name, if nullptr then use "out.dot" as default + */ +void Tree234::Print(const char *file_name) { + if (!file_name) { + file_name = "out.dot"; + } + + std::ofstream ofs; + + ofs.open(file_name); + if (!ofs) { + std::cout << "create tree dot file failed, " << file_name << std::endl; + return; + } + + ofs << "digraph G {\n"; + ofs << "node [shape=record]\n"; + + int64_t index = 0; + + /** @brief This is a helper structure to do a level order traversal to print + * the tree. */ + struct NodeInfo { + Node *node; ///< tree node + int64_t index; ///< node index of level order that used when draw the + ///< link between child and parent + }; + + std::queue q; + + if (root_) { + // print root node + PrintNode(ofs, root_, -1, index, 0); + + NodeInfo ni{}; + ni.node = root_; + ni.index = index; + + q.push(ni); + + while (!q.empty()) { + NodeInfo node_info = q.front(); + q.pop(); + + assert(node_info.node->GetCount() > 0); + + if (!node_info.node->IsLeaf()) { + if (node_info.node->GetCount() > 0) { + PrintNode(ofs, node_info.node->GetChild(0), node_info.index, + ++index, 0); + ni.node = node_info.node->GetChild(0); + ni.index = index; + q.push(ni); + + PrintNode(ofs, node_info.node->GetChild(1), node_info.index, + ++index, 1); + ni.node = node_info.node->GetChild(1); + ni.index = index; + q.push(ni); + } + + if (node_info.node->GetCount() > 1) { + PrintNode(ofs, node_info.node->GetChild(2), node_info.index, + ++index, 2); + ni.node = node_info.node->GetChild(2); + ni.index = index; + q.push(ni); + } + + if (node_info.node->GetCount() > 2) { + PrintNode(ofs, node_info.node->GetChild(3), node_info.index, + ++index, 3); + ni.node = node_info.node->GetChild(3); + ni.index = index; + q.push(ni); + } + } + } + } + + ofs << "}\n"; + ofs.close(); +} + +/** + * @brief Print the tree to a dot file. You can convert it to picture with + * graphviz + * @param ofs output file stream to print to + * @param node current node to print + * @param parent_index current node's parent node index, this is used to draw + * the link from parent to current node + * @param index current node's index of level order which is used to name the + * node in dot file + * @param parent_child_index the index that current node in parent's children + * array, range in [0,4), help to locate the start position of the link between + * nodes + */ +void Tree234::PrintNode(std::ofstream &ofs, Node *node, int64_t parent_index, + int64_t index, int8_t parent_child_index) { + assert(node); + + switch (node->GetCount()) { + case 1: + ofs << "node_" << index << " [label=\" " << node->GetItem(0) + << "\"]\n"; + break; + case 2: + ofs << "node_" << index << " [label=\" " << node->GetItem(0) + << " | " << node->GetItem(1) << "\"]\n"; + break; + case 3: + ofs << "node_" << index << " [label=\" " << node->GetItem(0) + << " | " << node->GetItem(1) << "| " + << node->GetItem(2) << "\"]\n"; + break; + + default: + break; + } + + // draw the edge + if (parent_index >= 0) { + ofs << "node_" << parent_index << ":f" + << (parent_child_index == 0 ? 0 : parent_child_index - 1) << ":" + << (parent_child_index == 0 ? "sw" : "se") << " -> node_" << index + << "\n"; + } +} +} // namespace tree_234 +} // namespace data_structures + + +/** @brief simple test to insert a given array and delete some item, and print + * the tree*/ +static void test1() { + std::array arr = {3, 1, 5, 4, 2, 9, 10, 8, 7, 6, 16, 13, 14}; + data_structures::tree_234::Tree234 tree; + + for (auto i : arr) { + tree.Insert(i); + } + + // tree.Remove(10); + tree.Remove(5); + tree.Print(); +} + +/** + * @brief simple test to insert continuous number of range [0, n), and print + * the tree + * @param n upper bound of the range number to insert + */ +static void test2(int64_t n) { + data_structures::tree_234::Tree234 tree; + + for (int64_t i = 0; i < n; i++) { + tree.Insert(i); + } + + tree.Traverse(); + tree.Print((std::to_string(n) + ".dot").c_str()); +} + +/** + * @brief Main function + * @param argc commandline argument count (ignored) + * @param argv commandline array of arguments (ignored) + * @returns 0 on exit + */ +int main(int argc, char *argv[]) { + if (argc < 2) { + test1(); // execute 1st test + } else { + test2(std::stoi(argv[1])); // execute 2nd test + } + + return 0; +} diff --git a/data_structures/trie_modern.cpp b/data_structures/trie_modern.cpp new file mode 100644 index 00000000000..470af07a456 --- /dev/null +++ b/data_structures/trie_modern.cpp @@ -0,0 +1,168 @@ +/** + * @file + * + * @author Anmol3299 + * \brief A basic implementation of trie class to store only lower-case strings. + */ +#include // for io operations +#include // for std::shared_ptr<> +#include // for std::string class + +/** + * A basic implementation of trie class to store only lower-case strings. + * You can extend the implementation to all the ASCII characters by changing the + * value of @ ALPHABETS to 128. + */ +class Trie { + private: + static constexpr size_t ALPHABETS = 26; + + /** + * Structure of trie node. + * This struct doesn't need a constructor as we are initializing using + * intializer list which is more efficient than if we had done so with + * constructor. + */ + struct TrieNode { + // An array of pointers of size 26 which tells if a character of word is + // present or not. + std::shared_ptr character[ALPHABETS]{nullptr}; + + bool isEndOfWord{false}; + }; + + /** + * Function to check if a node has some children which can form words. + * @param node whose character array of pointers need to be checked for + * children. + * @return `true` if a child is found + * @return `false` if a child is not found + */ + inline static bool hasChildren(std::shared_ptr node) { + for (size_t i = 0; i < ALPHABETS; i++) { + if (node->character[i]) { + return true; + } + } + return false; + } + + /** + * A recursive helper function to remove a word from the trie. First, it + * recursively traverses to the location of last character of word in the + * trie. However, if the word is not found, the function returns a runtime + * error. Upon successfully reaching the last character of word in trie, if + * sets the isEndOfWord to false and deletes the node if and only if it has + * no children, else it returns the current node. + * @param word is the string which needs to be removed from trie. + * @param curr is the current node we are at. + * @param index is the index of the @word we are at. + * @return if current node has childern, it returns @ curr, else it returns + * nullptr. + * @throw a runtime error in case @ word is not found in the trie. + */ + std::shared_ptr removeWordHelper(const std::string& word, + std::shared_ptr curr, + size_t index) { + if (word.size() == index) { + if (curr->isEndOfWord) { + curr->isEndOfWord = false; + } + if (hasChildren(curr)) { + return curr; + } + return nullptr; + } + + size_t idx = word[index] - 'a'; + + // Throw a runtime error in case the user enters a word which is not + // present in the trie. + if (!curr->character[idx]) { + throw std::runtime_error(std::move(std::string("Word not found."))); + } + + curr->character[idx] = + removeWordHelper(word, curr->character[idx], index + 1); + + // This if condition checks if the node has some childern. + // The 1st if check, i.e. (curr->character[idx]) is checked specifically + // because if the older string is a prefix of some other string, then, + // there would be no need to check all 26 characters. Example- str1 = + // abbey, str2 = abbex and we want to delete string "abbey", then in + // this case, there would be no need to check all characters for the + // chars a,b,b. + if (curr->character[idx] || hasChildren(curr)) { + return curr; + } + return nullptr; + } + + public: + /// constructor to initialise the root of the trie. + Trie() : m_root(std::make_shared()) {} + + /** + * Insert a word into the trie. + * @param word which needs to be inserted into the string. + */ + void insert(const std::string& word) { + auto curr = m_root; + for (char ch : word) { + size_t index = ch - 'a'; + + // if a node for current word is not already present in trie, create + // a new node for it. + if (!curr->character[index]) { + curr->character[index] = std::make_shared(); + } + + curr = curr->character[index]; + } + curr->isEndOfWord = true; + } + + /** + * Search if a word is present in trie or not. + * @param word which is needed to be searched in the trie. + * @return True if the word is found in trie and isEndOfWord is set to true. + * @return False if word is not found in trie or isEndOfWord is set to + * false. + */ + bool search(const std::string& word) { + auto curr = m_root; + for (char ch : word) { + size_t index = ch - 'a'; + + // if any node for a character is not found, then return that the + // word cannot be formed. + if (!curr->character[index]) { + return false; + } + curr = curr->character[index]; + } + return curr->isEndOfWord; + } + + // Function to remove the word which calls the helper function. + void removeWord(const std::string& word) { + m_root = removeWordHelper(word, m_root, 0); + } + + private: + // data member to store the root of the trie. + std::shared_ptr m_root; +}; + +/** + * Main function + */ +int main() { + Trie trie; + trie.insert("hel"); + trie.insert("hello"); + trie.removeWord("hel"); + std::cout << trie.search("hello") << '\n'; + + return 0; +} diff --git a/data_structures/trie_tree.cpp b/data_structures/trie_tree.cpp new file mode 100644 index 00000000000..c0b6e4fad43 --- /dev/null +++ b/data_structures/trie_tree.cpp @@ -0,0 +1,208 @@ +/** + * @file + * @author [@Arctic2333](https://github.com/Arctic2333) + * @author [Krishna Vedala](https://github.com/kvedala) + * @brief Implementation of [Trie](https://en.wikipedia.org/wiki/Trie) data + * structure for English alphabets in small characters. + * @note the function ::data_structure::trie::deleteString might be erroneous + * @see trie_modern.cpp + */ +#include +#include +#include +#include +#include + +/** \namespace data_structures + * \brief Data-structure algorithms + */ +namespace data_structures { +/** + * @brief [Trie](https://en.wikipedia.org/wiki/Trie) implementation for + * small-case English alphabets `a-z` + */ +class trie { + private: + static constexpr uint8_t NUM_CHARS = 26; ///< Number of alphabets + /** @brief Recursive tree nodes as an array of shared-pointers */ + std::array, NUM_CHARS << 1> arr; + bool isEndofWord = false; ///< identifier if a node is terminal node + + /** + * @brief Convert a character to integer for indexing + * + * @param ch character to index + * @return unsigned integer index + */ + uint8_t char_to_int(const char& ch) const { + if (ch >= 'A' && ch <= 'Z') { + return ch - 'A'; + } else if (ch >= 'a' && ch <= 'z') { + return ch - 'a' + NUM_CHARS; + } + + std::cerr << "Invalid character present. Exiting..."; + std::exit(EXIT_FAILURE); + return 0; + } + + /** search a string exists inside a given root trie + * @param str string to search for + * @param index start index to search from + * @returns `true` if found + * @returns `false` if not found + */ + bool search(const std::shared_ptr& root, const std::string& str, + int index) { + if (index == str.length()) { + if (!root->isEndofWord) { + return false; + } + return true; + } + int j = char_to_int(str[index]); + if (!root->arr[j]) { + return false; + } + return search(root->arr[j], str, index + 1); + } + + public: + trie() = default; ///< Class default constructor + + /** insert string into the trie + * @param str String to insert in the tree + */ + void insert(const std::string& str) { + std::shared_ptr root(nullptr); + + for (const char& ch : str) { + int j = char_to_int(ch); + if (root) { + if (root->arr[j]) { + root = root->arr[j]; + } else { + std::shared_ptr temp(new trie()); + root->arr[j] = temp; + root = temp; + } + } else if (arr[j]) { + root = arr[j]; + } else { + std::shared_ptr temp(new trie()); + arr[j] = temp; + root = temp; + } + } + root->isEndofWord = true; + } + + /** search a string exists inside the trie + * @param str string to search for + * @param index start index to search from + * @returns `true` if found + * @returns `false` if not found + */ + bool search(const std::string& str, int index) { + if (index == str.length()) { + if (!isEndofWord) { + return false; + } + return true; + } + int j = char_to_int(str[index]); + if (!arr[j]) { + return false; + } + return search(arr[j], str, index + 1); + } + + /** + * removes the string if it is not a prefix of any other + * string, if it is then just sets the ::data_structure::trie::isEndofWord + * to false, else removes the given string + * @note the function ::data_structure::trie::deleteString might be + * erroneous + * @todo review the function ::data_structure::trie::deleteString and the + * commented lines + * @param str string to remove + * @param index index to remove from + * @returns `true` if successful + * @returns `false` if unsuccessful + */ + bool deleteString(const std::string& str, int index) { + if (index == str.length()) { + if (!isEndofWord) { + return false; + } + isEndofWord = false; + // following lines - possible source of error? + // for (int i = 0; i < NUM_CHARS; i++) + // if (!arr[i]) + // return false; + return true; + } + int j = char_to_int(str[index]); + if (!arr[j]) { + return false; + } + bool var = deleteString(str, index + 1); + if (var) { + arr[j].reset(); + if (isEndofWord) { + return false; + } else { + int i = 0; + for (i = 0; i < NUM_CHARS; i++) { + if (arr[i]) { + return false; + } + } + return true; + } + } + + /* should not return here */ + std::cout << __func__ << ":" << __LINE__ + << "Should not reach this line\n"; + return false; + } +}; +} // namespace data_structures + +/** + * @brief Testing function + * @returns void + */ +static void test() { + data_structures::trie root; + root.insert("Hello"); + root.insert("World"); + + assert(!root.search("hello", 0)); + std::cout << "hello - " << root.search("hello", 0) << "\n"; + + assert(root.search("Hello", 0)); + std::cout << "Hello - " << root.search("Hello", 0) << "\n"; + + assert(!root.search("Word", 0)); + std::cout << "Word - " << root.search("Word", 0) << "\n"; + + assert(root.search("World", 0)); + std::cout << "World - " << root.search("World", 0) << "\n"; + + // Following lines of code give erroneous output + // root.deleteString("hello", 0); + // assert(!root.search("hello", 0)); + // std::cout << "hello - " << root.search("world", 0) << "\n"; +} + +/** + * @brief Main function + * @return 0 on exit + */ +int main() { + test(); + + return 0; +} diff --git a/data_structures/trie_using_hashmap.cpp b/data_structures/trie_using_hashmap.cpp new file mode 100644 index 00000000000..5fb9602a9bb --- /dev/null +++ b/data_structures/trie_using_hashmap.cpp @@ -0,0 +1,345 @@ +/** + * @file + * @author [Venkata Bharath](https://github.com/bharath000) + * @brief Implementation of [Trie](https://en.wikipedia.org/wiki/Trie) data + * structure using HashMap for different characters and method for predicting + * words based on prefix. + * @details The Trie data structure is implemented using unordered map to use + * memory optimally, predict_words method is developed to recommend words based + * on a given prefix along with other methods insert, delete, search, startwith + * in trie. + * @see trie_modern.cpp for difference + */ +#include /// for assert +#include /// for IO operations +#include /// for std::shared_ptr +#include /// for std::stack +#include /// for std::unordered_map +#include /// for std::vector + +/** + * @namespace data_structures + * @brief Data structures algorithms + */ +namespace data_structures { + +/** + * @namespace trie_using_hashmap + * @brief Functions for [Trie](https://en.wikipedia.org/wiki/Trie) data + * structure using hashmap implementation + */ +namespace trie_using_hashmap { + +/** + * @brief Trie class, implementation of trie using hashmap in each trie node + * for all the characters of char16_t(UTF-16)type with methods to insert, + * delete, search, start with and to recommend words based on a given + * prefix. + */ +class Trie { + private: + /** + * @brief struct representing a trie node. + */ + struct Node { + std::unordered_map> + children; ///< unordered map with key type char16_t and value is a + ///< shared pointer type of Node + bool word_end = false; ///< boolean variable to represent the node end + }; + + std::shared_ptr root_node = + std::make_shared(); ///< declaring root node of trie + + public: + ///< Constructor + Trie() = default; + + /** + * @brief insert the string into the trie + * @param word string to insert in the trie + */ + void insert(const std::string& word) { + std::shared_ptr curr = root_node; + for (char ch : word) { + if (curr->children.find(ch) == curr->children.end()) { + curr->children[ch] = std::make_shared(); + } + curr = curr->children[ch]; + } + + if (!curr->word_end && curr != root_node) { + curr->word_end = true; + } + } + + /** + * @brief search a word/string inside the trie + * @param word string to search for + * @returns `true` if found + * @returns `false` if not found + */ + bool search(const std::string& word) { + std::shared_ptr curr = root_node; + for (char ch : word) { + if (curr->children.find(ch) == curr->children.end()) { + return false; + } + curr = curr->children[ch]; + if (!curr) { + return false; + } + } + + if (curr->word_end) { + return true; + } else { + return false; + } + } + + /** + * @brief search a word/string that starts with a given prefix + * @param prefix string to search for + * @returns `true` if found + * @returns `false` if not found + */ + bool startwith(const std::string& prefix) { + std::shared_ptr curr = root_node; + for (char ch : prefix) { + if (curr->children.find(ch) == curr->children.end()) { + return false; + } + curr = curr->children[ch]; + } + return true; + } + + /** + * @brief delete a word/string from a trie + * @param word string to delete from trie + */ + void delete_word(std::string word) { + std::shared_ptr curr = root_node; + std::stack> nodes; + int cnt = 0; + for (char ch : word) { + if (curr->children.find(ch) == curr->children.end()) { + return; + } + if (curr->word_end) { + cnt++; + } + + nodes.push(curr->children[ch]); + curr = curr->children[ch]; + } + // Delete only when it's a word, and it has children after + // or prefix in the line + if (nodes.top()->word_end) { + nodes.top()->word_end = false; + } + // Delete only when it has no children after + // and also no prefix in the line + while (!(nodes.top()->word_end) && nodes.top()->children.empty()) { + nodes.pop(); + nodes.top()->children.erase(word.back()); + word.pop_back(); + } + } + + /** + * @brief helper function to predict/recommend words that starts with a + * given prefix from the end of prefix's node iterate through all the child + * nodes by recursively appending all the possible words below the trie + * @param prefix string to recommend the words + * @param element node at the end of the given prefix + * @param results list to store the all possible words + * @returns list of recommended words + */ + std::vector get_all_words(std::vector results, + const std::shared_ptr& element, + std::string prefix) { + if (element->word_end) { + results.push_back(prefix); + } + if (element->children.empty()) { + return results; + } + for (auto const& x : element->children) { + std::string key = ""; + key = x.first; + prefix += key; + + results = + get_all_words(results, element->children[x.first], prefix); + + prefix.pop_back(); + } + + return results; + } + + /** + * @brief predict/recommend a word that starts with a given prefix + * @param prefix string to search for + * @returns list of recommended words + */ + std::vector predict_words(const std::string& prefix) { + std::vector result; + std::shared_ptr curr = root_node; + // traversing until the end of the given prefix in trie + + for (char ch : prefix) { + if (curr->children.find(ch) == curr->children.end()) { + return result; + } + + curr = curr->children[ch]; + } + + // if the given prefix is the only word without children + if (curr->word_end && curr->children.empty()) { + result.push_back(prefix); + return result; + } + + result = get_all_words( + result, curr, + prefix); ///< iteratively and recursively get the recommended words + + return result; + } +}; +} // namespace trie_using_hashmap +} // namespace data_structures + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + data_structures::trie_using_hashmap::Trie obj; + // Inserting data into trie using the insert + // method and testing it with search method + obj.insert("app"); + obj.insert("abscond"); + obj.insert("about"); + obj.insert("apps"); + obj.insert("apen"); + obj.insert("apples"); + obj.insert("apple"); + obj.insert("approach"); + obj.insert("bus"); + obj.insert("buses"); + obj.insert("Apple"); + obj.insert("Bounce"); + + assert(!obj.search("appy")); + std::cout << "appy is not a word in trie" << std::endl; + + assert(!obj.search("car")); + std::cout << "car is not a word in trie" << std::endl; + assert(obj.search("app")); + assert(obj.search("apple")); + assert(obj.search("apples")); + assert(obj.search("apps")); + assert(obj.search("apen")); + assert(obj.search("approach")); + assert(obj.search("about")); + assert(obj.search("abscond")); + assert(obj.search("bus")); + assert(obj.search("buses")); + assert(obj.search("Bounce")); + assert(obj.search("Apple")); + + std::cout << "All the Inserted words are present in the trie" << std::endl; + + // test for startwith prefix method + assert(!obj.startwith("approachs")); + assert(obj.startwith("approach")); + assert(obj.startwith("about")); + assert(!obj.startwith("appy")); + assert(obj.startwith("abscond")); + assert(obj.startwith("bus")); + assert(obj.startwith("buses")); + assert(obj.startwith("Bounce")); + assert(obj.startwith("Apple")); + assert(obj.startwith("abs")); + assert(obj.startwith("b")); + assert(obj.startwith("bus")); + assert(obj.startwith("Bo")); + assert(obj.startwith("A")); + assert(!obj.startwith("Ca")); + + assert(!obj.startwith("C")); + + std::cout << "All the tests passed for startwith method" << std::endl; + + // test for predict_words/recommendation of words based on a given prefix + + std::vector pred_words = obj.predict_words("a"); + + for (const std::string& str : obj.predict_words("a")) { + std::cout << str << std::endl; + } + assert(pred_words.size() == 8); + std::cout << "Returned all words that start with prefix a " << std::endl; + pred_words = obj.predict_words("app"); + + for (const std::string& str : pred_words) { + std::cout << str << std::endl; + } + + assert(pred_words.size() == 5); + std::cout << "Returned all words that start with prefix app " << std::endl; + pred_words = obj.predict_words("A"); + + for (const std::string& str : pred_words) { + std::cout << str << std::endl; + } + + assert(pred_words.size() == 1); + std::cout << "Returned all words that start with prefix A " << std::endl; + pred_words = obj.predict_words("bu"); + + for (const std::string& str : pred_words) { + std::cout << str << std::endl; + } + + assert(pred_words.size() == 2); + std::cout << "Returned all words that start with prefix bu " << std::endl; + + // tests for delete method + + obj.delete_word("app"); + assert(!obj.search("app")); + std::cout << "word app is deleted sucessful" << std::endl; + + pred_words = obj.predict_words("app"); + for (const std::string& str : pred_words) { + std::cout << str << std::endl; + } + assert(pred_words.size() == 4); + std::cout << "app is deleted sucessful" << std::endl; + + // test case for Chinese language + + obj.insert("苹果"); + assert(obj.startwith("苹")); + pred_words = obj.predict_words("h"); + + assert(pred_words.size() == 0); + std::cout << "No word starts with prefix h in trie" << std::endl; + + std::cout << "All tests passed" << std::endl; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementaions + return 0; +} diff --git a/divide_and_conquer/CMakeLists.txt b/divide_and_conquer/CMakeLists.txt new file mode 100644 index 00000000000..4d6204325cb --- /dev/null +++ b/divide_and_conquer/CMakeLists.txt @@ -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/divide_and_conquer") + +endforeach( testsourcefile ${APP_SOURCES} ) diff --git a/divide_and_conquer/karatsuba_algorithm_for_fast_multiplication.cpp b/divide_and_conquer/karatsuba_algorithm_for_fast_multiplication.cpp new file mode 100644 index 00000000000..a4b5be22e31 --- /dev/null +++ b/divide_and_conquer/karatsuba_algorithm_for_fast_multiplication.cpp @@ -0,0 +1,183 @@ +/** + * @file + * @brief Implementation of the [Karatsuba algorithm for fast + * multiplication](https://en.wikipedia.org/wiki/Karatsuba_algorithm) + * @details + * Given two strings in binary notation we want to multiply them and return the + * value. Simple approach is to multiply bits one by one which will give the time + * complexity of around O(n^2). To make it more efficient we will be using + * Karatsuba algorithm to find the product which will solve the problem + * O(nlogn) of time. + * @author [Swastika Gupta](https://github.com/Swastyy) + * @author [Ameer Carlo Lubang](https://github.com/poypoyan) + */ + +#include /// for assert +#include /// for string +#include /// for IO operations + +/** + * @namespace divide_and_conquer + * @brief Divide and Conquer algorithms + */ +namespace divide_and_conquer { +/** + * @namespace karatsuba_algorithm + * @brief Functions for the [Karatsuba algorithm for fast + * multiplication](https://en.wikipedia.org/wiki/Karatsuba_algorithm) implementation + */ +namespace karatsuba_algorithm { +/** + * @brief Binary addition + * @param first, the input string 1 + * @param second, the input string 2 + * @returns the sum binary string + */ +std::string add_strings(std::string first, std::string second) { + std::string result; // to store the resulting sum bits + + // make the string lengths equal + int64_t len1 = first.size(); + int64_t len2 = second.size(); + std::string zero = "0"; + if (len1 < len2) { + for (int64_t i = 0; i < len2 - len1; i++) { + zero += first; + first = zero; + zero = "0"; // Prevents CI from failing + } + } else if (len1 > len2) { + for (int64_t i = 0; i < len1 - len2; i++) { + zero += second; + second = zero; + zero = "0"; // Prevents CI from failing + } + } + + int64_t length = std::max(len1, len2); + int64_t carry = 0; + for (int64_t i = length - 1; i >= 0; i--) { + int64_t firstBit = first.at(i) - '0'; + int64_t secondBit = second.at(i) - '0'; + + int64_t sum = (char(firstBit ^ secondBit ^ carry)) + '0'; // sum of 3 bits + result.insert(result.begin(), sum); + + carry = char((firstBit & secondBit) | (secondBit & carry) | + (firstBit & carry)); // sum of 3 bits + } + + if (carry) { + result.insert(result.begin(), '1'); // adding 1 incase of overflow + } + return result; +} + +/** + * @brief Wrapper function for substr that considers leading zeros. + * @param str, the binary input string. + * @param x1, the substr parameter integer 1 + * @param x2, the substr parameter integer 2 + * @param n, is the length of the "whole" string: leading zeros + str + * @returns the "safe" substring for the algorithm *without* leading zeros + * @returns "0" if substring spans to leading zeros only + */ +std::string safe_substr(const std::string &str, int64_t x1, int64_t x2, int64_t n) { + int64_t len = str.size(); + + if (len >= n) { + return str.substr(x1, x2); + } + + int64_t y1 = x1 - (n - len); // index in str of first char of substring of "whole" string + int64_t y2 = (x1 + x2 - 1) - (n - len); // index in str of last char of substring of "whole" string + + if (y2 < 0) { + return "0"; + } else if (y1 < 0) { + return str.substr(0, y2 + 1); + } else { + return str.substr(y1, x2); + } +} + +/** + * @brief The main function implements Karatsuba's algorithm for fast + * multiplication + * @param str1 the input string 1 + * @param str2 the input string 2 + * @returns the product number value + */ +int64_t karatsuba_algorithm(std::string str1, std::string str2) { + int64_t len1 = str1.size(); + int64_t len2 = str2.size(); + int64_t n = std::max(len1, len2); + + if (n == 0) { + return 0; + } + if (n == 1) { + return (str1[0] - '0') * (str2[0] - '0'); + } + + int64_t fh = n / 2; // first half of string + int64_t sh = n - fh; // second half of string + + std::string Xl = divide_and_conquer::karatsuba_algorithm::safe_substr(str1, 0, fh, n); // first half of first string + std::string Xr = divide_and_conquer::karatsuba_algorithm::safe_substr(str1, fh, sh, n); // second half of first string + + std::string Yl = divide_and_conquer::karatsuba_algorithm::safe_substr(str2, 0, fh, n); // first half of second string + std::string Yr = divide_and_conquer::karatsuba_algorithm::safe_substr(str2, fh, sh, n); // second half of second string + + // calculating the three products of inputs of size n/2 recursively + int64_t product1 = karatsuba_algorithm(Xl, Yl); + int64_t product2 = karatsuba_algorithm(Xr, Yr); + int64_t product3 = karatsuba_algorithm( + divide_and_conquer::karatsuba_algorithm::add_strings(Xl, Xr), + divide_and_conquer::karatsuba_algorithm::add_strings(Yl, Yr)); + + return product1 * (1 << (2 * sh)) + + (product3 - product1 - product2) * (1 << sh) + + product2; // combining the three products to get the final result. +} +} // namespace karatsuba_algorithm +} // namespace divide_and_conquer + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // 1st test + std::string s11 = "1"; // 1 + std::string s12 = "1010"; // 10 + std::cout << "1st test... "; + assert(divide_and_conquer::karatsuba_algorithm::karatsuba_algorithm( + s11, s12) == 10); + std::cout << "passed" << std::endl; + + // 2nd test + std::string s21 = "11"; // 3 + std::string s22 = "1010"; // 10 + std::cout << "2nd test... "; + assert(divide_and_conquer::karatsuba_algorithm::karatsuba_algorithm( + s21, s22) == 30); + std::cout << "passed" << std::endl; + + // 3rd test + std::string s31 = "110"; // 6 + std::string s32 = "1010"; // 10 + std::cout << "3rd test... "; + assert(divide_and_conquer::karatsuba_algorithm::karatsuba_algorithm( + s31, s32) == 60); + std::cout << "passed" << std::endl; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} diff --git a/divide_and_conquer/strassen_matrix_multiplication.cpp b/divide_and_conquer/strassen_matrix_multiplication.cpp new file mode 100644 index 00000000000..47498c966b1 --- /dev/null +++ b/divide_and_conquer/strassen_matrix_multiplication.cpp @@ -0,0 +1,471 @@ +/** + * @brief [Strassen's + * algorithm](https://en.wikipedia.org/wiki/Strassen_algorithm) is one of the + * methods for multiplying two matrices. It is one of the faster algorithms for + * larger matrices than naive multiplication method. + * + * It involves dividing each matrices into 4 blocks, given they are evenly + * divisible, and are combined with new defined matrices involving 7 matrix + * multiplications instead of eight, yielding O(n^2.8073) complexity. + * + * @author [AshishYUO](https://github.com/AshishYUO) + */ +#include /// For assert operation +#include /// For std::chrono; time measurement +#include /// For I/O operations +#include /// For std::tuple +#include /// For creating dynamic arrays + +/** + * @namespace divide_and_conquer + * @brief Divide and Conquer algorithms + */ +namespace divide_and_conquer { + +/** + * @namespace strassens_multiplication + * @brief Namespace for performing strassen's multiplication + */ +namespace strassens_multiplication { + +/// Complement of 0 is a max integer. +constexpr size_t MAX_SIZE = ~0ULL; +/** + * @brief Matrix class. + */ +template ::value || std::is_floating_point::value, + bool>::type> +class Matrix { + std::vector> _mat; + + public: + /** + * @brief Constructor + * @tparam Integer ensuring integers are being evaluated and not other + * data types. + * @param size denoting the size of Matrix as size x size + */ + template ::value, Integer>::type> + explicit Matrix(const Integer size) { + for (size_t i = 0; i < size; ++i) { + _mat.emplace_back(std::vector(size, 0)); + } + } + + /** + * @brief Constructor + * @tparam Integer ensuring integers are being evaluated and not other + * data types. + * @param rows denoting the total rows of Matrix + * @param cols denoting the total elements in each row of Matrix + */ + template ::value, Integer>::type> + Matrix(const Integer rows, const Integer cols) { + for (size_t i = 0; i < rows; ++i) { + _mat.emplace_back(std::vector(cols, 0)); + } + } + + /** + * @brief Get the matrix shape + * @returns pair of integer denoting total rows and columns + */ + inline std::pair size() const { + return {_mat.size(), _mat[0].size()}; + } + + /** + * @brief returns the address of the element at ith place + * (here ith row of the matrix) + * @tparam Integer any valid integer + * @param index index which is requested + * @returns the address of the element (here ith row or array) + */ + template ::value, Integer>::type> + inline std::vector &operator[](const Integer index) { + return _mat[index]; + } + + /** + * @brief Creates a new matrix and returns a part of it. + * @param row_start start of the row + * @param row_end end of the row + * @param col_start start of the col + * @param col_end end of the column + * @returns A slice of (row_end - row_start) x (col_end - col_start) size of + * array starting from row_start row and col_start column + */ + Matrix slice(const size_t row_start, const size_t row_end = MAX_SIZE, + const size_t col_start = MAX_SIZE, + const size_t col_end = MAX_SIZE) const { + const size_t h_size = + (row_end != MAX_SIZE ? row_end : _mat.size()) - row_start; + const size_t v_size = (col_end != MAX_SIZE ? col_end : _mat[0].size()) - + (col_start != MAX_SIZE ? col_start : 0); + Matrix result = Matrix(h_size, v_size); + + const size_t v_start = (col_start != MAX_SIZE ? col_start : 0); + for (size_t i = 0; i < h_size; ++i) { + for (size_t j = 0; j < v_size; ++j) { + result._mat[i][j] = _mat[i + row_start][j + v_start]; + } + } + return result; + } + + /** + * @brief Horizontally stack the matrix (one after the other) + * @tparam Number any type of number + * @param other the other matrix: note that this array is not modified + * @returns void, but modifies the current array + */ + template ::value || + std::is_floating_point::value, + Number>::type> + void h_stack(const Matrix &other) { + assert(_mat.size() == other._mat.size()); + for (size_t i = 0; i < other._mat.size(); ++i) { + for (size_t j = 0; j < other._mat[i].size(); ++j) { + _mat[i].push_back(other._mat[i][j]); + } + } + } + + /** + * @brief Horizontally stack the matrix (current matrix above the other) + * @tparam Number any type of number (Integer or floating point) + * @param other the other matrix: note that this array is not modified + * @returns void, but modifies the current array + */ + template ::value || + std::is_floating_point::value, + Number>::type> + void v_stack(const Matrix &other) { + assert(_mat[0].size() == other._mat[0].size()); + for (size_t i = 0; i < other._mat.size(); ++i) { + _mat.emplace_back(std::vector(other._mat[i].size())); + for (size_t j = 0; j < other._mat[i].size(); ++j) { + _mat.back()[j] = other._mat[i][j]; + } + } + } + + /** + * @brief Add two matrices and returns a new matrix + * @tparam Number any real value to add + * @param other Other matrix to add to this + * @returns new matrix + */ + template ::value || + std::is_floating_point::value, + bool>::type> + Matrix operator+(const Matrix &other) const { + assert(this->size() == other.size()); + Matrix C = Matrix(_mat.size(), _mat[0].size()); + for (size_t i = 0; i < _mat.size(); ++i) { + for (size_t j = 0; j < _mat[i].size(); ++j) { + C._mat[i][j] = _mat[i][j] + other._mat[i][j]; + } + } + return C; + } + + /** + * @brief Add another matrices to current matrix + * @tparam Number any real value to add + * @param other Other matrix to add to this + * @returns reference of current matrix + */ + template ::value || + std::is_floating_point::value, + bool>::type> + Matrix &operator+=(const Matrix &other) const { + assert(this->size() == other.size()); + for (size_t i = 0; i < _mat.size(); ++i) { + for (size_t j = 0; j < _mat[i].size(); ++j) { + _mat[i][j] += other._mat[i][j]; + } + } + return this; + } + + /** + * @brief Subtract two matrices and returns a new matrix + * @tparam Number any real value to multiply + * @param other Other matrix to subtract to this + * @returns new matrix + */ + template ::value || + std::is_floating_point::value, + bool>::type> + Matrix operator-(const Matrix &other) const { + assert(this->size() == other.size()); + Matrix C = Matrix(_mat.size(), _mat[0].size()); + for (size_t i = 0; i < _mat.size(); ++i) { + for (size_t j = 0; j < _mat[i].size(); ++j) { + C._mat[i][j] = _mat[i][j] - other._mat[i][j]; + } + } + return C; + } + + /** + * @brief Subtract another matrices to current matrix + * @tparam Number any real value to Subtract + * @param other Other matrix to Subtract to this + * @returns reference of current matrix + */ + template ::value || + std::is_floating_point::value, + bool>::type> + Matrix &operator-=(const Matrix &other) const { + assert(this->size() == other.size()); + for (size_t i = 0; i < _mat.size(); ++i) { + for (size_t j = 0; j < _mat[i].size(); ++j) { + _mat[i][j] -= other._mat[i][j]; + } + } + return this; + } + + /** + * @brief Multiply two matrices and returns a new matrix + * @tparam Number any real value to multiply + * @param other Other matrix to multiply to this + * @returns new matrix + */ + template ::value || + std::is_floating_point::value, + bool>::type> + inline Matrix operator*(const Matrix &other) const { + assert(_mat[0].size() == other._mat.size()); + auto size = this->size(); + const size_t row = size.first, col = size.second; + // Main condition for applying strassen's method: + // 1: matrix should be a square matrix + // 2: matrix should be of even size (mat.size() % 2 == 0) + return (row == col && (row & 1) == 0) + ? this->strassens_multiplication(other) + : this->naive_multiplication(other); + } + + /** + * @brief Multiply matrix with a number and returns a new matrix + * @tparam Number any real value to multiply + * @param other Other real number to multiply to current matrix + * @returns new matrix + */ + template ::value || + std::is_floating_point::value, + bool>::type> + inline Matrix operator*(const Number other) const { + Matrix C = Matrix(_mat.size(), _mat[0].size()); + for (size_t i = 0; i < _mat.size(); ++i) { + for (size_t j = 0; j < _mat[i].size(); ++j) { + C._mat[i][j] = _mat[i][j] * other; + } + } + return C; + } + + /** + * @brief Multiply a number to current matrix + * @tparam Number any real value to multiply + * @param other Other matrix to multiply to this + * @returns reference of current matrix + */ + template ::value || + std::is_floating_point::value, + bool>::type> + Matrix &operator*=(const Number other) const { + for (size_t i = 0; i < _mat.size(); ++i) { + for (size_t j = 0; j < _mat[i].size(); ++j) { + _mat[i][j] *= other; + } + } + return this; + } + + /** + * @brief Naive multiplication performed on this + * @tparam Number any real value to multiply + * @param other Other matrix to multiply to this + * @returns new matrix + */ + template ::value || + std::is_floating_point::value, + bool>::type> + Matrix naive_multiplication(const Matrix &other) const { + Matrix C = Matrix(_mat.size(), other._mat[0].size()); + + for (size_t i = 0; i < _mat.size(); ++i) { + for (size_t k = 0; k < _mat[0].size(); ++k) { + for (size_t j = 0; j < other._mat[0].size(); ++j) { + C._mat[i][j] += _mat[i][k] * other._mat[k][j]; + } + } + } + return C; + } + + /** + * @brief Strassens method of multiplying two matrices + * References: https://en.wikipedia.org/wiki/Strassen_algorithm + * @tparam Number any real value to multiply + * @param other Other matrix to multiply to this + * @returns new matrix + */ + template ::value || + std::is_floating_point::value, + bool>::type> + Matrix strassens_multiplication(const Matrix &other) const { + const size_t size = _mat.size(); + // Base case: when a matrix is small enough for faster naive + // multiplication, or the matrix is of odd size, then go with the naive + // multiplication route; + // else; go with the strassen's method. + if (size <= 64ULL || (size & 1ULL)) { + return this->naive_multiplication(other); + } else { + const Matrix + A = this->slice(0ULL, size >> 1, 0ULL, size >> 1), + B = this->slice(0ULL, size >> 1, size >> 1, size), + C = this->slice(size >> 1, size, 0ULL, size >> 1), + D = this->slice(size >> 1, size, size >> 1, size), + E = other.slice(0ULL, size >> 1, 0ULL, size >> 1), + F = other.slice(0ULL, size >> 1, size >> 1, size), + G = other.slice(size >> 1, size, 0ULL, size >> 1), + H = other.slice(size >> 1, size, size >> 1, size); + + Matrix P1 = A.strassens_multiplication(F - H); + Matrix P2 = (A + B).strassens_multiplication(H); + Matrix P3 = (C + D).strassens_multiplication(E); + Matrix P4 = D.strassens_multiplication(G - E); + Matrix P5 = (A + D).strassens_multiplication(E + H); + Matrix P6 = (B - D).strassens_multiplication(G + H); + Matrix P7 = (A - C).strassens_multiplication(E + F); + + // Building final matrix C11 would be + // [ | ] + // [ C11 | C12 ] + // C = [ ____ | ____ ] + // [ | ] + // [ C21 | C22 ] + // [ | ] + + Matrix C11 = P5 + P4 - P2 + P6; + Matrix C12 = P1 + P2; + Matrix C21 = P3 + P4; + Matrix C22 = P1 + P5 - P3 - P7; + + C21.h_stack(C22); + C11.h_stack(C12); + C11.v_stack(C21); + + return C11; + } + } + + /** + * @brief Compares two matrices if each of them are equal or not + * @param other other matrix to compare + * @returns whether they are equal or not + */ + bool operator==(const Matrix &other) const { + if (_mat.size() != other._mat.size() || + _mat[0].size() != other._mat[0].size()) { + return false; + } + for (size_t i = 0; i < _mat.size(); ++i) { + for (size_t j = 0; j < _mat[i].size(); ++j) { + if (_mat[i][j] != other._mat[i][j]) { + return false; + } + } + } + return true; + } + + friend std::ostream &operator<<(std::ostream &out, const Matrix &mat) { + for (auto &row : mat._mat) { + for (auto &elem : row) { + out << elem << " "; + } + out << "\n"; + } + return out << "\n"; + } +}; + +} // namespace strassens_multiplication + +} // namespace divide_and_conquer + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + const size_t s = 512; + auto matrix_demo = + divide_and_conquer::strassens_multiplication::Matrix(s, s); + + for (size_t i = 0; i < s; ++i) { + for (size_t j = 0; j < s; ++j) { + matrix_demo[i][j] = i + j; + } + } + + auto matrix_demo2 = + divide_and_conquer::strassens_multiplication::Matrix(s, s); + for (size_t i = 0; i < s; ++i) { + for (size_t j = 0; j < s; ++j) { + matrix_demo2[i][j] = 2 + i + j; + } + } + + auto start = std::chrono::system_clock::now(); + auto Mat3 = matrix_demo2 * matrix_demo; + auto end = std::chrono::system_clock::now(); + + std::chrono::duration time = (end - start); + std::cout << "Strassen time: " << time.count() << "s" << std::endl; + + start = std::chrono::system_clock::now(); + auto conf = matrix_demo2.naive_multiplication(matrix_demo); + end = std::chrono::system_clock::now(); + + time = end - start; + std::cout << "Normal time: " << time.count() << "s" << std::endl; + + // std::cout << Mat3 << conf << std::endl; + assert(Mat3 == conf); +} + +/** + * @brief main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementation + return 0; +} diff --git a/doc/Doxyfile b/doc/Doxyfile new file mode 100644 index 00000000000..14101f4c753 --- /dev/null +++ b/doc/Doxyfile @@ -0,0 +1,2926 @@ +# Doxyfile 1.12.0 + +# This file describes the settings to be used by the documentation system +# Doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use Doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use Doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "TheAlgorithms/C++" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = 1.0.0 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = All the algorithms implemented in C++ + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = doc/assets/project_logo.png + +# With the PROJECT_ICON tag one can specify an icon that is included in the tabs +# when the HTML document is shown. Doxygen will copy the logo to the output +# directory. + +PROJECT_ICON = doc/assets/favicon.svg + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where Doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = build/ + +# If the CREATE_SUBDIRS tag is set to YES then Doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this +# option can be useful when feeding Doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. +# The default value is: NO. + +CREATE_SUBDIRS = YES + +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# number of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + +# If the ALLOW_UNICODE_NAMES tag is set to YES, Doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by Doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, Doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, Doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, Doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, Doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which Doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where Doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, Doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then Doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by Doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# By default Python docstrings are displayed as preformatted text and Doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# Doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as Doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then Doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:^^" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by Doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make Doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by Doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then Doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by Doxygen, so you can +# mix Doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 6. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 6 + +# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to +# generate identifiers for the Markdown headings. Note: Every identifier is +# unique. +# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a +# sequence number starting at 0 and GITHUB use the lower case version of title +# with any whitespace replaced by '-' and punctuation characters removed. +# The default value is: DOXYGEN. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +MARKDOWN_ID_STYLE = DOXYGEN + +# When enabled Doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let Doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also makes the inheritance and +# collaboration diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software) sources only. Doxygen will parse +# them like normal C++ but will assume all classes use public instead of private +# inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# Doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then Doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, Doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# Doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run Doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +# The NUM_PROC_THREADS specifies the number of threads Doxygen is allowed to use +# during processing. When set to 0 Doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + +# If the TIMESTAMP tag is set different from NO then each generated page will +# contain the date or date and time when the page was generated. Setting this to +# NO can help when comparing the output of multiple runs. +# Possible values are: YES, NO, DATETIME and DATE. +# The default value is: NO. + +TIMESTAMP = NO + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, Doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# will also hide undocumented C++ concepts if enabled. This option has no effect +# if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# With the correct setting of option CASE_SENSE_NAMES Doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and macOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. + +CASE_SENSE_NAMES = SYSTEM + +# If the HIDE_SCOPE_NAMES tag is set to NO then Doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then Doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE = NO + +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES then Doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then Doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then Doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then Doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then Doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and Doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING Doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# Doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by Doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by Doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents Doxygen's defaults, run Doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. +# +# Note that if you run Doxygen from a directory containing a file called +# DoxygenLayout.xml, Doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +# The EXTERNAL_TOOL_PATH tag can be used to extend the search path (PATH +# environment variable) so that external tools such as latex and gs can be +# found. +# Note: Directories specified with EXTERNAL_TOOL_PATH are added in front of the +# path already specified by the PATH variable, and are added in the order +# specified. +# Note: This option is particularly useful for macOS version 14 (Sonoma) and +# higher, when running Doxygen from Doxywizard, because in this case any user- +# defined changes to the PATH are ignored. A typical example on macOS is to set +# EXTERNAL_TOOL_PATH = /Library/TeX/texbin /usr/local/bin +# together with the standard path, the full search path used by doxygen when +# launching external tools will then become +# PATH=/Library/TeX/texbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin + +EXTERNAL_TOOL_PATH = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by Doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by Doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then Doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, Doxygen will generate warnings for +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# If WARN_IF_INCOMPLETE_DOC is set to YES, Doxygen will warn about incomplete +# function parameter documentation. If set to NO, Doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, Doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC +# The default value is: NO. + +WARN_NO_PARAMDOC = YES + +# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, Doxygen will warn about +# undocumented enumeration values. If set to NO, Doxygen will accept +# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: NO. + +WARN_IF_UNDOC_ENUM_VAL = YES + +# If the WARN_AS_ERROR tag is set to YES then Doxygen will immediately stop when +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then Doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the Doxygen process Doxygen will return with a non-zero status. +# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then Doxygen behaves +# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined Doxygen will not +# write the warning messages in between other messages but write them at the end +# of a run, in case a WARN_LOGFILE is defined the warning messages will be +# besides being in the defined file also be shown at the end of a run, unless +# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case +# the behavior will remain as with the setting FAIL_ON_WARNINGS. +# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that Doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of Doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = + +# This tag can be used to specify the character encoding of the source files +# that Doxygen parses. Internally Doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# This tag can be used to specify the character encoding of the source files +# that Doxygen parses The INPUT_FILE_ENCODING tag can be used to specify +# character encoding on a per file pattern basis. Doxygen will compare the file +# name with each pattern and apply the encoding instead of the default +# INPUT_ENCODING) if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). +# See also: INPUT_ENCODING for further information on supported encodings. + +INPUT_FILE_ENCODING = + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by Doxygen. +# +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm, +# *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, +# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d, +# *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to +# be provided as Doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cxxm \ + *.cpp \ + *.cppm \ + *.ccm \ + *.c++ \ + *.c++m \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.ixx \ + *.l \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f18 \ + *.f \ + *.for \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which Doxygen is +# run. + +EXCLUDE = + + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = */build/* \ + */doc/* \ + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# ANamespace::AClass, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that Doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that Doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by Doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by Doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the Doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +FORTRAN_COMMENT_AFTER = 72 + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# multi-line macros, enums or list initialized variables directly into the +# documentation. +# The default value is: NO. + +INLINE_SOURCES = YES + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct Doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of Doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by Doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then Doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then Doxygen will use the +# clang parser (see: +# http://clang.llvm.org/) for more accurate parsing at the cost of reduced +# performance. This can be particularly helpful with template rich C++ code for +# which Doxygen's built-in parser lacks the necessary type information. +# Note: The availability of this option depends on whether or not Doxygen was +# generated with the -Duse_libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS +# tag is set to YES then Doxygen will add the directory of each input to the +# include path. +# The default value is: YES. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_ADD_INC_PATHS = YES + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by Doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the directory containing a file called compile_commands.json. This +# file is the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the +# options used when the source files were built. This is equivalent to +# specifying the -p option to a clang tool, such as clang-check. These options +# will then be passed to the parser. Any options specified with CLANG_OPTIONS +# will be added as well. +# Note: The availability of this option depends on whether or not Doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) +# that should be ignored while generating the index headers. The IGNORE_PREFIX +# tag works for classes, function and member names. The entity will be placed in +# the alphabetical list under the first letter of the entity name that remains +# after removing the prefix. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, Doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank Doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that Doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that Doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of Doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = doc/html/header.html + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank Doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that Doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank Doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that Doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by Doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# Note: Since the styling of scrollbars can currently not be overruled in +# Webkit/Chromium, the styling will be left out of the default doxygen.css if +# one or more extra stylesheets have been specified. So if scrollbar +# customization is desired it has to be added explicitly. For an example see the +# documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = doc/styles/doxygen-awesome.css + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. +# Possible values are: LIGHT always generates light mode output, DARK always +# generates dark mode output, AUTO_LIGHT automatically sets the mode according +# to the user preference, uses light mode if no preference is set (the default), +# AUTO_DARK automatically sets the mode according to the user preference, uses +# dark mode if no preference is set and TOGGLE allows a user to switch between +# light and dark mode via a button. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = LIGHT + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a color-wheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use gray-scales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be +# dynamically folded and expanded in the generated HTML source code. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_CODE_FOLDING = YES + +# If the HTML_COPY_CLIPBOARD tag is set to YES then Doxygen will show an icon in +# the top right corner of code and text fragments that allows the user to copy +# its content to the clipboard. Note this only works if supported by the browser +# and the web page is served via a secure context (see: +# https://www.w3.org/TR/secure-contexts/), i.e. using the https: or file: +# protocol. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COPY_CLIPBOARD = YES + +# Doxygen stores a couple of settings persistently in the browser (via e.g. +# cookies). By default these settings apply to all HTML pages generated by +# Doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store +# the settings under a project specific key, such that the user preferences will +# be stored separately. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_PROJECT_COOKIE = + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, Doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then Doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by Doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# Doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the main .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# The SITEMAP_URL tag is used to specify the full URL of the place where the +# generated documentation will be placed on the server by the user during the +# deployment of the documentation. The generated sitemap is called sitemap.xml +# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL +# is specified no sitemap is generated. For information about the sitemap +# protocol see https://www.sitemaps.org +# This tag requires that the tag GENERATE_HTML is set to YES. + +SITEMAP_URL = + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty Doxygen will try to +# run qhelpgenerator on the generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by Doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# Doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# When the SHOW_ENUM_VALUES tag is set doxygen will show the specified +# enumeration values besides the enumeration mnemonics. +# The default value is: NO. + +SHOW_ENUM_VALUES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, Doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = YES + +# If the OBFUSCATE_EMAILS tag is set to YES, Doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + +# If the HTML_FORMULA_FORMAT option is set to svg, Doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# Doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = YES + +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_3 + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for MathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@3 + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = ams + +# The MATHJAX_CODEFILE tag can be used to specify a file with JavaScript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled Doxygen will generate a search box for +# the HTML output. The underlying search engine uses JavaScript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the JavaScript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /