diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..777c247dd4 --- /dev/null +++ b/.clang-format @@ -0,0 +1,167 @@ +--- +Language: Cpp +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: false +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: true + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Allman +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: false +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 0000000000..1a6c0a4749 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,6 @@ +--- +Checks: '-*,google-*,clang-diagnostic-*,clang-analyzer-*,-clang-analyzer-security.insecureAPI.*,openmp-*,performance-*,portability-*,modernize-*' +WarningsAsErrors: '*,-clang-diagnostic-implicitly-unsigned-literal,-google-readability-*,-google-explicit-constructor,-modernize-*,modernize-avoid-c-arrays,-google-explicit-constructor,-performance-move-const-arg,-performance-noexcept-move-constructor,' +HeaderFilterRegex: '' +AnalyzeTemporaryDtors: false +FormatStyle: '{ BasedOnStyle: Google, UseTab: Never, IndentWidth: 4, TabWidth: 4, BreakBeforeBraces: Allman, AllowShortIfStatementsOnASingleLine: false, IndentCaseLabels: false, ColumnLimit: 80, AccessModifierOffset: -4 }' diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000000..dda50c14f8 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @Panquesito7 @tjgurwara99 @alexpantyukhin diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000000..2febec1d50 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,65 @@ +name: Bug report +description: Create a report to help us improve. Report bugs found while using the project +title: "[BUG]" +labels: [bug] +body: + - type: markdown + attributes: + value: "Provide a general summary of the issue in the Title above" + - type: textarea + id: description + attributes: + label: Description + description: Provide a general summary of the issue in the Title above + validations: + required: true + - type: input + id: expectedbhv + attributes: + label: Expected behavior + description: Tell us what should happen + validations: + required: true + - type: input + id: actualbhv + attributes: + label: Actual behavior + description: Tell us what happens instead + validations: + required: true + - type: input + id: possiblefix + attributes: + label: Possible fix + description: Not obligatory, but suggest a fix or reason for the bug + validations: + required: false + - 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: true + - 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 0000000000..875cc4efab --- /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 0000000000..46cc9a391c --- /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 0000000000..d6dc0cfe9f --- /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/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000000..caabb2d152 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,2 @@ +Leetcode folder changes: +- leetcode/**/* diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..882d005a50 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,24 @@ +#### Description of Change + + + +#### References + + +#### Checklist + + +- [ ] Added description of change +- [ ] Added file name matches [File name guidelines](https://github.com/TheAlgorithms/C/blob/master/CONTRIBUTING.md#File-Name-guidelines) +- [ ] Added tests and example, test must pass +- [ ] Relevant documentation/comments is changed or added +- [ ] PR title follows semantic [commit guidelines](https://github.com/TheAlgorithms/C/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 0000000000..9fbc5ed0ae --- /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 0000000000..d57946e53c --- /dev/null +++ b/.github/workflows/awesome_workflow.yml @@ -0,0 +1,73 @@ +name: Awesome CI Workflow +on: [push, pull_request] +permissions: + contents: write + +jobs: + MainSequence: + name: Code Formatter + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + 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@users.noreply.github.com' + - name: Filename Formatter + uses: TheAlgorithms/scripts/formatter@main + with: + filetypes: .c,.h + - 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 }} + permissions: + pull-requests: write + needs: [MainSequence] + strategy: + matrix: + os: [windows-latest, ubuntu-latest, macOS-latest] + steps: + - uses: actions/checkout@v3 + with: + submodules: true + - run: | + cmake -B ./build -S . + cmake --build build --config Release + - 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: ['Autochecks are failing'] + }) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000000..16da8867bf --- /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@v3 + + # 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 0000000000..527a55e27d --- /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' # We only need this to run in our repository. + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Build directory + uses: TheAlgorithms/scripts/directory_md@main + with: + language: C + working-directory: . + filetypes: .c,.h + ignored-directories: leetcode/,scripts/ diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml new file mode 100644 index 0000000000..134c04bb13 --- /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@v3 + with: + submodules: true + - name: Install requirements + run: | + brew install graphviz ninja doxygen + - name: configure + run: cmake -G Ninja -B ./build -S . + - name: build + run: cmake --build build -t doc + - name: gh-pages + uses: actions/checkout@v3 + with: + ref: "gh-pages" + clean: false + - name: Move & Commit files + run: | + git config --global user.name github-actions + 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 && rm *.css + 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/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 0000000000..fe3f22d579 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,14 @@ +name: "Pull Request Labeler" +on: +- pull_request_target + +jobs: + triage: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v4 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/leetcode_directory_writer.yml b/.github/workflows/leetcode_directory_writer.yml new file mode 100644 index 0000000000..9d4ab38b89 --- /dev/null +++ b/.github/workflows/leetcode_directory_writer.yml @@ -0,0 +1,45 @@ +# The objective of this GitHub Action is to update the leetcode DIRECTORY.md file (if needed) +# when doing a git push +name: leetcode_directory_writer +on: + push: + paths: + - "leetcode/src/**.c" + branches: + - master +jobs: + build: + if: github.repository == 'TheAlgorithms/C' # We only need this to run in our repository. + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - uses: actions/setup-python@v4 + with: + python-version: 3.x + - name: Add python dependencies + run: | + pip install requests + - name: Write LeetCode DIRECTORY.md + run: | + python3 scripts/leetcode_directory_md.py 2>&1 | tee leetcode/DIRECTORY.md + - name: Setup Git configurations + shell: bash + run: | + git config --global user.name github-actions[bot] + git config --global user.email 'github-actions@users.noreply.github.com' + - name: Committing changes + shell: bash + run: | + git checkout -b leetcode-directory-${{ github.sha }} + git commit -m "docs: updating `leetcode/DIRECTORY.md`" + git push origin leetcode-directory-${{ github.sha }}:leetcode-directory-${{ github.sha }} + - name: Creating the pull request + shell: bash + run: | + if [[ $(git log --branches --not --remotes) ]]; then + gh pr create --base ${GITHUB_REF##*/} --head leetcode-directory-${{ github.sha }} --title 'docs: updating `leetcode/DIRECTORY.md`' --body 'Updated LeetCode directory (see the diff. for changes).' || true + fi + env: + GH_TOKEN: ${{ github.token }} diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000000..0018600db5 --- /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 0000000000..8b6b444d53 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.swp +*.exe +*.out +.vscode/ +build/ +git_diff.txt diff --git a/.gitpod.dockerfile b/.gitpod.dockerfile new file mode 100644 index 0000000000..f389140537 --- /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 0000000000..4b0332719c --- /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 0000000000..3668b6b6ef --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "C_Cpp.clang_format_style": "{ BasedOnStyle: Google, UseTab: Never, IndentWidth: 4, TabWidth: 4, BreakBeforeBraces: Allman, AllowShortIfStatementsOnASingleLine: false, IndentCaseLabels: false, ColumnLimit: 80, AccessModifierOffset: -4 }", + "editor.formatOnSave": true, + "editor.formatOnPaste": true, + "editor.formatOnType": true, + "files.insertFinalNewline": true, +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..01a43e6617 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,115 @@ +cmake_minimum_required(VERSION 3.22) +project(Algorithms_in_C + LANGUAGES C + VERSION 1.0.0 + DESCRIPTION "Set of algorithms implemented in C." + ) + +# Set compilation standards +set(CMAKE_C_STANDARD 11) +set(CMAKE_C_STANDARD_REQUIRED YES) +if (MSVC) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) + # add_compile_options(/Za) +endif (MSVC) + +# check for math library +# addresses a bug when linking on OSX +find_library(MATH_LIBRARY m) + +# Optional flag - can be set by user +# Default "ON" +option(USE_OPENMP "flag to use OpenMP for multithreading" ON) +if(USE_OPENMP) + find_package(OpenMP) + if (OpenMP_C_FOUND) + message(STATUS "Building with OpenMP Multithreading.") + else() + message(STATUS "No OpenMP found, no multithreading.") + endif() +endif() + +## Check for some required header files +include(CheckIncludeFile) +include(CheckSymbolExists) +check_include_file(stdbool.h HAS_STDBOOL_H) +check_include_file(inttypes.h HAS_INTTYPES_H) +check_include_file(complex.h HAS_COMPLEX_H) +if(HAS_COMPLEX_H) + check_symbol_exists(complex complex.h HAS_COMPLEX_TYPE) +endif(HAS_COMPLEX_H) +if (NOT HAS_STDBOOL_H) + message(FATAL_ERROR "Missing required header: 'stdbool.h'") +endif() +if (NOT HAS_INTTYPES_H) + message(FATAL_ERROR "Missing required header: 'inttypes.h'") +endif() + +## Add subdirectories containing CMakeLists.txt +# to configure and compile files in the respective folders +add_subdirectory(developer_tools) +add_subdirectory(hash) +add_subdirectory(misc) +add_subdirectory(games) +add_subdirectory(audio) +add_subdirectory(sorting) +add_subdirectory(geometry) +add_subdirectory(graphics) +add_subdirectory(searching) +add_subdirectory(conversions) +add_subdirectory(client_server) +add_subdirectory(project_euler) +add_subdirectory(machine_learning) +add_subdirectory(process_scheduling_algorithms) +add_subdirectory(numerical_methods) +add_subdirectory(math) +add_subdirectory(cipher) +add_subdirectory(dynamic_programming) + +## Configure Doxygen documentation system +cmake_policy(SET CMP0054 NEW) +cmake_policy(SET CMP0057 NEW) +find_package(Doxygen OPTIONAL_COMPONENTS dot dia) +if(DOXYGEN_FOUND) + set(DOXYGEN_GENERATE_MAN NO) + set(DOXYGEN_USE_MATHJAX YES) + set(DOXYGEN_GENERATE_HTML YES) + # set(DOXYGEN_HTML_TIMESTAMP YES) + set(DOXYGEN_EXTRACT_STATIC YES) + set(DOXYGEN_INLINE_SOURCES YES) + set(DOXYGEN_CREATE_SUBDIRS YES) + set(DOXYGEN_GENERATE_TREEVIEW YES) + set(DOXYGEN_JAVADOC_AUTOBRIEF YES) + set(DOXYGEN_STRIP_CODE_COMMENTS NO) + set(DOXYGEN_ENABLE_PREPROCESSING YES) + set(DOXYGEN_EXT_LINKS_IN_WINDOW YES) + set(DOXYGEN_OPTIMIZE_OUTPUT_FOR_C YES) + set(DOXYGEN_CLANG_ASSISTED_PARSING YES) + set(DOXYGEN_FILE_PATTERNS *.c *.h *.md) + set(DOXYGEN_MATHJAX_EXTENSIONS TeX/AMSmath TeX/AMSsymbols) + set(DOXYGEN_TAGFILES "doc/cppreference-doxygen-web.tag.xml=http://en.cppreference.com/w/") + set(DOXYGEN_MATHJAX_RELPATH "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=TeX-MML-AM_CHTML") + if(Doxygen_dot_FOUND) + set(DOXYGEN_HAVE_DOT YES) + set(DOXYGEN_CALL_GRAPH YES) + set(DOXYGEN_INTERACTIVE_SVG YES) + set(DOXYGEN_DOT_IMAGE_FORMAT "svg") + endif() + if(OPENMP_FOUND) + set(DOXYGEN_PREDEFINED "_OPENMP=1") + endif() + if(GLUT_FOUND) + set(DOXYGEN_PREDEFINED ${DOXYGEN_PREDEFINED} "GLUT_FOUND=1") + endif() + + doxygen_add_docs( + doc + ${PROJECT_SOURCE_DIR} + COMMENT "Generate documentation" + ) +endif() + +## Enable tool to generate binary distribution files +set(CPACK_PROJECT_NAME ${PROJECT_NAME}) +set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) +include(CPack) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..c89771e8fe --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,132 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +hello@the-algorithms.com. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..01638a59c4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,360 @@ +# CONTRIBUTION GUIDELINES + +## Before contributing + +Welcome to [TheAlgorithms/C](https://github.com/TheAlgorithms/C)! Before submitting pull requests, please make sure that you have **read the whole guidelines**. If you have any doubts about this contribution guide, please open [an issue](https://github.com/TheAlgorithms/C/issues/new/choose) or ask on our [Discord server](https://the-algorithms.com/discord/), and clearly state your concerns. + +## Contributing + +### Maintainer/reviewer + +**Please check the [reviewer code](https://github.com/TheAlgorithms/C/blob/master/REVIEWER_CODE.md) file for maintainers and reviewers.** + +### Contributor + +Being a contributor at The Algorithms, we request you to follow the points mentioned below: + +- You did your own work. + - No plagiarism is allowed. Any plagiarized work will not be merged. +- Your work will be distributed under the [GNU General Public License v3.0](https://github.com/TheAlgorithms/C/blob/master/LICENSE) once your pull request has been merged. +- Please follow the repository guidelines and standards mentioned below. + +**New implementation** New implementations are welcome! + +You can add new algorithms or data structures that are **not present in the repository** or that can **improve** the old implementations (**documentation**, **improving test cases**, removing bugs, or in any other reasonable sense) + +**Issues** Please avoid opening issues asking to be "assigned” to a particular algorithm. This merely creates unnecessary noise for maintainers. Instead, please submit your implementation in a pull request, and it will be evaluated by project maintainers. + +### LeetCode solutions + +For LeetCode solutions, please check its [**guide**](https://github.com/TheAlgorithms/C/blob/master/leetcode/README.md) to make a proper solution file. + +### Making Changes + +#### Code + +- Please use the directory structure of the repository. +- Make sure the file extensions should be `*.h` `*.c` +- Organize your code using the **`struct`** keyword +- If an implementation of the algorithm already exists, please refer to the [file-name section below](#file-name-guidelines). +- You can suggest reasonable changes to existing algorithms. +- Strictly use snake_case (underscore_separated) in filenames. +- If you have added or modified code, please make sure the code compiles before submitting. +- Our automated testing runs [**CMake**](https://cmake.org/) on all the pull requests, so please be sure that your code passes before submitting. +- Please conform to [Doxygen](https://www.doxygen.nl/manual/docblocks.html) standards and document the code as much as possible. This not only facilitates the readers but also generates the correct info on the website. +- **Be consistent in the use of these guidelines.** + +#### Documentation + +- Make sure you put useful comments in your code. Do not comment on obvious things. +- Please avoid creating new directories if at all possible. Try to fit your work into the existing directory structure. If you want to create a new directory, then please check if a similar category has been recently suggested or created by other pull requests. +- If you have modified/added documentation, please ensure that your language is concise and must not contain grammatical errors. +- Do not update [`README.md`](https://github.com/TheAlgorithms/C/blob/master/README.md) along with other changes. First, create an issue and then link to that issue in your pull request to suggest specific changes required to [`README.md`](https://github.com/TheAlgorithms/C/blob/master/README.md). +- The repository follows [Doxygen](https://www.doxygen.nl/manual/docblocks.html) standards and auto-generates the [repository website](https://thealgorithms.github.io/C). Please ensure the code is documented in this structure. A sample implementation is given below. + +#### Test + +- Make sure to add examples and test cases in your `main()` function. +- If you find an algorithm or document without tests, please feel free to create a pull request or issue describing suggested changes. +- Please try to add one or more `test()` functions that will invoke the algorithm implementation on random test data with the expected output. Use the `assert()` function to confirm that the tests will pass. Requires including the `assert.h` library. +- Test cases should fully verify that your program works as expected. Rather than asking the user for input, it's best to make sure the given output is the correct output. + +##### Self-test examples + +1. [ROT13 Cipher](https://github.com/TheAlgorithms/C/blob/master/cipher/rot13.c) (complex). + +```c + // NOTE: the `rot13` function is defined in another part of the code. + + char test_01[] = "The more I C, the less I see."; + rot13(test_01); + assert(strcmp(test_01, "Gur zber V P, gur yrff V frr.") == 0); + + char test_02[] = "Which witch switched the Swiss wristwatches?"; + rot13(test_02); + assert(strcmp(test_02, "Juvpu jvgpu fjvgpurq gur Fjvff jevfgjngpurf?") == 0); + + char test_03[] = "Juvpu jvgpu fjvgpurq gur Fjvff jevfgjngpurf?"; + rot13(test_03); + assert(strcmp(test_03, "Which witch switched the Swiss wristwatches?") == 0); +``` + +2. [Sudoku Solver](https://github.com/TheAlgorithms/C/blob/master/misc/sudoku_solver.c) (medium). + +```c + uint8_t test_array[] = {3, 0, 6, 5, 0, 8, 4, 0, 0, 5, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 8, 7, 0, 0, 0, 0, 3, 1, 0, 0, 3, 0, 1, 0, 0, + 8, 0, 9, 0, 0, 8, 6, 3, 0, 0, 5, 0, 5, 0, 0, 9, 0, + 6, 0, 0, 1, 3, 0, 0, 0, 0, 2, 5, 0, 0, 0, 0, 0, 0, + 0, 0, 7, 4, 0, 0, 5, 2, 0, 6, 3, 0, 0}; + struct sudoku a = {.N = 9, .N2 = 3, .a = test_array}; + assert(solve(&a)); // ensure that solution is obtained + // NOTE: `solve` is defined in another part of the code. + + uint8_t expected[] = {3, 1, 6, 5, 7, 8, 4, 9, 2, 5, 2, 9, 1, 3, 4, 7, 6, + 8, 4, 8, 7, 6, 2, 9, 5, 3, 1, 2, 6, 3, 4, 1, 5, 9, + 8, 7, 9, 7, 4, 8, 6, 3, 1, 2, 5, 8, 5, 1, 7, 9, 2, + 6, 4, 3, 1, 3, 8, 9, 4, 7, 2, 5, 6, 6, 9, 2, 3, 5, + 1, 8, 7, 4, 7, 4, 5, 2, 8, 6, 3, 1, 9}; + for (int i = 0; i < a.N; i++) + for (int j = 0; j < a.N; j++) + assert(a.a[i * a.N + j] == expected[i * a.N + j]); +``` + +3. Small C program that showcases and explains the use of tests. + +```c +#include /// for IO operations +#include /// for assert +#include /// for bool + +/** + * @brief Verifies if the given array + * contains the given number on it. + * @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 + */ +bool is_number_on_array(const int *arr, const int number) { + for (int i = 0; i < sizeof(arr); 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() { + int arr[] = { 9, 14, 21, 98, 67 }; + + assert(is_number_on_array(arr, 9) == true); + assert(is_number_on_array(arr, 4) == false); + assert(is_number_on_array(arr, 98) == true); + assert(is_number_on_array(arr, 512) == false); + + printf("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 + +```c +/** + * @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.c, another_file.c + */ + +#include /// for assert +#include /// for `some function here` + +/** + * @brief Struct documentation + */ +struct struct_name { + int variable; ///< short info of this variable + char message; ///< short info +}; + +/** + * @brief Function documentation + * @param param1 one-line info about param1 + * @param param2 one-line info about param2 + * @returns `true` if ... + * @returns `false` if ... + */ +bool func(int param1, int param2) { + // function statements here + if (/*something bad*/) { + return false; + } + + return true; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + /* desciptions 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 passed + printf("All tests have successfully passed!\n"); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + // code here + return 0; +} +``` + +#### File name guidelines + +- Use lowercase words with ``"_"`` as a separator +- For instance + +```markdown +MyNewCStruct.C is incorrect +my_new_c_struct.c 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 an incremental numeric digit as a suffix. For example: if `median_search.c` already exists in the `search` folder, and you are contributing a new implementation, the filename should be `median_search2.c`. For a third implementation, `median_search3.c`, and so on. + +#### Directory guidelines + +- We recommend adding files to existing directories as much as possible. +- Use lowercase words with ``"_"`` as a 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} *.c ) +foreach( testsourcefile ${APP_SOURCES} ) + string( REPLACE ".c" "" testname ${testsourcefile} ) # File type. Example: `.c` + add_executable( ${testname} ${testsourcefile} ) + + if(OpenMP_C_FOUND) + target_link_libraries(${testname} OpenMP::OpenMP_C) + endif() + if(MATH_LIBRARY) + target_link_libraries(${testname} ${MATH_LIBRARY}) + 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(numerical_methods) +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.c +git commit -m "your message" +``` + +Examples of commit messages with semantic prefixes: + +```markdown +fix: xyz algorithm bug +feat: add xyx algorithm, struct xyz +test: add test for xyz algorithm +docs: add comments and explanation to xyz algorithm +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/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) 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`](.clang-tidy). + +```bash +clang-tidy --fix --quiet -p build subfolder/file_to_check.c -- +``` + +#### 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.c` + +#### 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/DIRECTORY.md b/DIRECTORY.md new file mode 100644 index 0000000000..1339bc6ffc --- /dev/null +++ b/DIRECTORY.md @@ -0,0 +1,361 @@ + +## Audio + * [Alaw](https://github.com/TheAlgorithms/C/blob/HEAD/audio/alaw.c) + +## Cipher + * [Affine](https://github.com/TheAlgorithms/C/blob/HEAD/cipher/affine.c) + * [Rot13](https://github.com/TheAlgorithms/C/blob/HEAD/cipher/rot13.c) + +## Client Server + * [Bool](https://github.com/TheAlgorithms/C/blob/HEAD/client_server/bool.h) + * [Client](https://github.com/TheAlgorithms/C/blob/HEAD/client_server/client.c) + * [Fork](https://github.com/TheAlgorithms/C/blob/HEAD/client_server/fork.h) + * [Remote Command Exec Udp Client](https://github.com/TheAlgorithms/C/blob/HEAD/client_server/remote_command_exec_udp_client.c) + * [Remote Command Exec Udp Server](https://github.com/TheAlgorithms/C/blob/HEAD/client_server/remote_command_exec_udp_server.c) + * [Server](https://github.com/TheAlgorithms/C/blob/HEAD/client_server/server.c) + * [Tcp Full Duplex Client](https://github.com/TheAlgorithms/C/blob/HEAD/client_server/tcp_full_duplex_client.c) + * [Tcp Full Duplex Server](https://github.com/TheAlgorithms/C/blob/HEAD/client_server/tcp_full_duplex_server.c) + * [Tcp Half Duplex Client](https://github.com/TheAlgorithms/C/blob/HEAD/client_server/tcp_half_duplex_client.c) + * [Tcp Half Duplex Server](https://github.com/TheAlgorithms/C/blob/HEAD/client_server/tcp_half_duplex_server.c) + * [Udp Client](https://github.com/TheAlgorithms/C/blob/HEAD/client_server/udp_client.c) + * [Udp Server](https://github.com/TheAlgorithms/C/blob/HEAD/client_server/udp_server.c) + +## Conversions + * [Binary To Decimal](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/binary_to_decimal.c) + * [Binary To Hexadecimal](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/binary_to_hexadecimal.c) + * [Binary To Octal](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/binary_to_octal.c) + * [C Atoi Str To Integer](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/c_atoi_str_to_integer.c) + * [Celsius To Fahrenheit](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/celsius_to_fahrenheit.c) + * [Decimal To Any Base](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/decimal_to_any_base.c) + * [Decimal To Binary](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/decimal_to_binary.c) + * [Decimal To Binary Recursion](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/decimal_to_binary_recursion.c) + * [Decimal To Hexa](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/decimal_to_hexa.c) + * [Decimal To Octal](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/decimal_to_octal.c) + * [Decimal To Octal Recursion](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/decimal_to_octal_recursion.c) + * [Hexadecimal To Octal](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/hexadecimal_to_octal.c) + * [Hexadecimal To Octal2](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/hexadecimal_to_octal2.c) + * [Infix To Postfix](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/infix_to_postfix.c) + * [Infix To Postfix2](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/infix_to_postfix2.c) + * [Int To String](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/int_to_string.c) + * [Octal To Binary](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/octal_to_binary.c) + * [Octal To Decimal](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/octal_to_decimal.c) + * [Octal To Hexadecimal](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/octal_to_hexadecimal.c) + * [Roman Numerals To Decimal](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/roman_numerals_to_decimal.c) + * [To Decimal](https://github.com/TheAlgorithms/C/blob/HEAD/conversions/to_decimal.c) + +## Data Structures + * Array + * [Carray](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/array/carray.c) + * [Carray](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/array/carray.h) + * [Carray Tests](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/array/carray_tests.c) + * Binary Trees + * [Avl Tree](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/binary_trees/avl_tree.c) + * [Binary Search Tree](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/binary_trees/binary_search_tree.c) + * [Create Node](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/binary_trees/create_node.c) + * [Recursive Traversals](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/binary_trees/recursive_traversals.c) + * [Red Black Tree](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/binary_trees/red_black_tree.c) + * [Segment Tree](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/binary_trees/segment_tree.c) + * [Threaded Binary Trees](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/binary_trees/threaded_binary_trees.c) + * [Words Alphabetical](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/binary_trees/words_alphabetical.c) + * Dictionary + * [Dict](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/dictionary/dict.c) + * [Dict](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/dictionary/dict.h) + * [Test Program](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/dictionary/test_program.c) + * Dynamic Array + * [Dynamic Array](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/dynamic_array/dynamic_array.c) + * [Dynamic Array](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/dynamic_array/dynamic_array.h) + * [Main](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/dynamic_array/main.c) + * Graphs + * [Bellman Ford](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/graphs/bellman_ford.c) + * [Bfs](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/graphs/bfs.c) + * [Bfs Queue](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/graphs/bfs_queue.c) + * [Dfs](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/graphs/dfs.c) + * [Dfs Recursive](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/graphs/dfs_recursive.c) + * [Dijkstra](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/graphs/dijkstra.c) + * [Euler](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/graphs/euler.c) + * [Floyd Warshall](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/graphs/floyd_warshall.c) + * [Graph](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/graphs/graph.c) + * [Graph](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/graphs/graph.h) + * [Hamiltonian](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/graphs/hamiltonian.c) + * [Kruskal](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/graphs/kruskal.c) + * [Queue](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/graphs/queue.c) + * [Queue](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/graphs/queue.h) + * [Strongly Connected Components](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/graphs/strongly_connected_components.c) + * [Topological Sort](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/graphs/topological_sort.c) + * [Transitive Closure](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/graphs/transitive_closure.c) + * Hash Set + * [Hash Set](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/hash_set/hash_set.c) + * [Hash Set](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/hash_set/hash_set.h) + * [Main](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/hash_set/main.c) + * Heap + * [Max Heap](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/heap/max_heap.c) + * [Min Heap](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/heap/min_heap.c) + * Linked List + * [Ascending Priority Queue](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/linked_list/ascending_priority_queue.c) + * [Circular Doubly Linked List](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/linked_list/circular_doubly_linked_list.c) + * [Circular Linked List](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/linked_list/circular_linked_list.c) + * [Doubly Linked List](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/linked_list/doubly_linked_list.c) + * [Merge Linked Lists](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/linked_list/merge_linked_lists.c) + * [Middle Element In List](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/linked_list/middle_element_in_list.c) + * [Queue Linked List](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/linked_list/queue_linked_list.c) + * [Singly Link List Deletion](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/linked_list/singly_link_list_deletion.c) + * [Stack Using Linked Lists](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/linked_list/stack_using_linked_lists.c) + * List + * [List](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/list/list.c) + * [List](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/list/list.h) + * [Main](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/list/main.c) + * Queue + * [Include](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/queue/include.h) + * [Queue](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/queue/queue.c) + * [Stack](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/stack.c) + * Stack + * [Dynamic Stack](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/stack/dynamic_stack.c) + * [Main](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/stack/main.c) + * [Parenthesis](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/stack/parenthesis.c) + * [Stack](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/stack/stack.c) + * [Stack](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/stack/stack.h) + * Stack Linked List + * [Main](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/stack/stack_linked_list/main.c) + * [Stack](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/stack/stack_linked_list/stack.c) + * [Stack](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/stack/stack_linked_list/stack.h) + * Trie + * [Trie](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/trie/trie.c) + * [Vector](https://github.com/TheAlgorithms/C/blob/HEAD/data_structures/vector.c) + +## Developer Tools + * [Malloc Dbg](https://github.com/TheAlgorithms/C/blob/HEAD/developer_tools/malloc_dbg.c) + * [Malloc Dbg](https://github.com/TheAlgorithms/C/blob/HEAD/developer_tools/malloc_dbg.h) + * [Min Printf](https://github.com/TheAlgorithms/C/blob/HEAD/developer_tools/min_printf.h) + * [Test Malloc Dbg](https://github.com/TheAlgorithms/C/blob/HEAD/developer_tools/test_malloc_dbg.c) + * [Test Min Printf](https://github.com/TheAlgorithms/C/blob/HEAD/developer_tools/test_min_printf.c) + +## Dynamic Programming + * [Lcs](https://github.com/TheAlgorithms/C/blob/HEAD/dynamic_programming/lcs.c) + * [Matrix Chain Order](https://github.com/TheAlgorithms/C/blob/HEAD/dynamic_programming/matrix_chain_order.c) + +## Exercism + * Acronym + * [Acronym](https://github.com/TheAlgorithms/C/blob/HEAD/exercism/acronym/acronym.c) + * [Acronym](https://github.com/TheAlgorithms/C/blob/HEAD/exercism/acronym/acronym.h) + * Hello World + * [Hello World](https://github.com/TheAlgorithms/C/blob/HEAD/exercism/hello_world/hello_world.c) + * [Hello World](https://github.com/TheAlgorithms/C/blob/HEAD/exercism/hello_world/hello_world.h) + * Isogram + * [Isogram](https://github.com/TheAlgorithms/C/blob/HEAD/exercism/isogram/isogram.c) + * [Isogram](https://github.com/TheAlgorithms/C/blob/HEAD/exercism/isogram/isogram.h) + * Rna Transcription + * [Rna Transcription](https://github.com/TheAlgorithms/C/blob/HEAD/exercism/rna_transcription/rna_transcription.c) + * [Rna Transcription](https://github.com/TheAlgorithms/C/blob/HEAD/exercism/rna_transcription/rna_transcription.h) + * Word Count + * [Word Count](https://github.com/TheAlgorithms/C/blob/HEAD/exercism/word_count/word_count.c) + * [Word Count](https://github.com/TheAlgorithms/C/blob/HEAD/exercism/word_count/word_count.h) + +## Games + * [Hangman](https://github.com/TheAlgorithms/C/blob/HEAD/games/hangman.c) + * [Naval Battle](https://github.com/TheAlgorithms/C/blob/HEAD/games/naval_battle.c) + * [Tic Tac Toe](https://github.com/TheAlgorithms/C/blob/HEAD/games/tic_tac_toe.c) + +## Geometry + * [Geometry Datatypes](https://github.com/TheAlgorithms/C/blob/HEAD/geometry/geometry_datatypes.h) + * [Quaternions](https://github.com/TheAlgorithms/C/blob/HEAD/geometry/quaternions.c) + * [Vectors 3D](https://github.com/TheAlgorithms/C/blob/HEAD/geometry/vectors_3d.c) + +## Graphics + * [Spirograph](https://github.com/TheAlgorithms/C/blob/HEAD/graphics/spirograph.c) + +## Greedy Approach + * [Dijkstra](https://github.com/TheAlgorithms/C/blob/HEAD/greedy_approach/dijkstra.c) + * [Prim](https://github.com/TheAlgorithms/C/blob/HEAD/greedy_approach/prim.c) + +## Hash + * [Hash Adler32](https://github.com/TheAlgorithms/C/blob/HEAD/hash/hash_adler32.c) + * [Hash Blake2B](https://github.com/TheAlgorithms/C/blob/HEAD/hash/hash_blake2b.c) + * [Hash Crc32](https://github.com/TheAlgorithms/C/blob/HEAD/hash/hash_crc32.c) + * [Hash Djb2](https://github.com/TheAlgorithms/C/blob/HEAD/hash/hash_djb2.c) + * [Hash Sdbm](https://github.com/TheAlgorithms/C/blob/HEAD/hash/hash_sdbm.c) + * [Hash Xor8](https://github.com/TheAlgorithms/C/blob/HEAD/hash/hash_xor8.c) + +## Machine Learning + * [Adaline Learning](https://github.com/TheAlgorithms/C/blob/HEAD/machine_learning/adaline_learning.c) + * [K Means Clustering](https://github.com/TheAlgorithms/C/blob/HEAD/machine_learning/k_means_clustering.c) + * [Kohonen Som Topology](https://github.com/TheAlgorithms/C/blob/HEAD/machine_learning/kohonen_som_topology.c) + * [Kohonen Som Trace](https://github.com/TheAlgorithms/C/blob/HEAD/machine_learning/kohonen_som_trace.c) + +## Math + * [Armstrong Number](https://github.com/TheAlgorithms/C/blob/HEAD/math/armstrong_number.c) + * [Cantor Set](https://github.com/TheAlgorithms/C/blob/HEAD/math/cantor_set.c) + * [Cartesian To Polar](https://github.com/TheAlgorithms/C/blob/HEAD/math/cartesian_to_polar.c) + * [Catalan](https://github.com/TheAlgorithms/C/blob/HEAD/math/catalan.c) + * [Collatz](https://github.com/TheAlgorithms/C/blob/HEAD/math/collatz.c) + * [Euclidean Algorithm Extended](https://github.com/TheAlgorithms/C/blob/HEAD/math/euclidean_algorithm_extended.c) + * [Factorial](https://github.com/TheAlgorithms/C/blob/HEAD/math/factorial.c) + * [Factorial Large Number](https://github.com/TheAlgorithms/C/blob/HEAD/math/factorial_large_number.c) + * [Factorial Trailing Zeroes](https://github.com/TheAlgorithms/C/blob/HEAD/math/factorial_trailing_zeroes.c) + * [Fibonacci](https://github.com/TheAlgorithms/C/blob/HEAD/math/fibonacci.c) + * [Fibonacci Dp](https://github.com/TheAlgorithms/C/blob/HEAD/math/fibonacci_dp.c) + * [Fibonacci Fast](https://github.com/TheAlgorithms/C/blob/HEAD/math/fibonacci_fast.c) + * [Fibonacci Formula](https://github.com/TheAlgorithms/C/blob/HEAD/math/fibonacci_formula.c) + * [Gcd](https://github.com/TheAlgorithms/C/blob/HEAD/math/gcd.c) + * [Is Armstrong](https://github.com/TheAlgorithms/C/blob/HEAD/math/is_armstrong.c) + * [Large Factorials](https://github.com/TheAlgorithms/C/blob/HEAD/math/large_factorials.c) + * [Lcm](https://github.com/TheAlgorithms/C/blob/HEAD/math/lcm.c) + * [Lerp](https://github.com/TheAlgorithms/C/blob/HEAD/math/lerp.c) + * [Palindrome](https://github.com/TheAlgorithms/C/blob/HEAD/math/palindrome.c) + * [Prime](https://github.com/TheAlgorithms/C/blob/HEAD/math/prime.c) + * [Prime Factoriziation](https://github.com/TheAlgorithms/C/blob/HEAD/math/prime_factoriziation.c) + * [Prime Sieve](https://github.com/TheAlgorithms/C/blob/HEAD/math/prime_sieve.c) + * [Strong Number](https://github.com/TheAlgorithms/C/blob/HEAD/math/strong_number.c) + +## Misc + * [Demonetization](https://github.com/TheAlgorithms/C/blob/HEAD/misc/demonetization.c) + * [Hamming Distance](https://github.com/TheAlgorithms/C/blob/HEAD/misc/hamming_distance.c) + * [Lexicographic Permutations](https://github.com/TheAlgorithms/C/blob/HEAD/misc/lexicographic_permutations.c) + * [Longest Subsequence](https://github.com/TheAlgorithms/C/blob/HEAD/misc/longest_subsequence.c) + * [Mcnaughton Yamada Thompson](https://github.com/TheAlgorithms/C/blob/HEAD/misc/mcnaughton_yamada_thompson.c) + * [Mirror](https://github.com/TheAlgorithms/C/blob/HEAD/misc/mirror.c) + * [Pid](https://github.com/TheAlgorithms/C/blob/HEAD/misc/pid.c) + * [Poly Add](https://github.com/TheAlgorithms/C/blob/HEAD/misc/poly_add.c) + * [Postfix Evaluation](https://github.com/TheAlgorithms/C/blob/HEAD/misc/postfix_evaluation.c) + * [Quartile](https://github.com/TheAlgorithms/C/blob/HEAD/misc/quartile.c) + * [Rselect](https://github.com/TheAlgorithms/C/blob/HEAD/misc/rselect.c) + * [Run Length Encoding](https://github.com/TheAlgorithms/C/blob/HEAD/misc/run_length_encoding.c) + * [Shunting Yard](https://github.com/TheAlgorithms/C/blob/HEAD/misc/shunting_yard.c) + * [Sudoku Solver](https://github.com/TheAlgorithms/C/blob/HEAD/misc/sudoku_solver.c) + * [Tower Of Hanoi](https://github.com/TheAlgorithms/C/blob/HEAD/misc/tower_of_hanoi.c) + * [Union Find](https://github.com/TheAlgorithms/C/blob/HEAD/misc/union_find.c) + +## Numerical Methods + * [Bisection Method](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/bisection_method.c) + * [Durand Kerner Roots](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/durand_kerner_roots.c) + * [Gauss Elimination](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/gauss_elimination.c) + * [Gauss Seidel Method](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/gauss_seidel_method.c) + * [Lagrange Theorem](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/lagrange_theorem.c) + * [Lu Decompose](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/lu_decompose.c) + * [Mean](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/mean.c) + * [Median](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/median.c) + * [Newton Raphson Root](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/newton_raphson_root.c) + * [Ode Forward Euler](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/ode_forward_euler.c) + * [Ode Midpoint Euler](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/ode_midpoint_euler.c) + * [Ode Semi Implicit Euler](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/ode_semi_implicit_euler.c) + * [Qr Decompose](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/qr_decompose.h) + * [Qr Decomposition](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/qr_decomposition.c) + * [Qr Eigen Values](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/qr_eigen_values.c) + * [Realtime Stats](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/realtime_stats.c) + * [Secant Method](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/secant_method.c) + * [Simpsons 1 3Rd Rule](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/simpsons_1_3rd_rule.c) + * [Variance](https://github.com/TheAlgorithms/C/blob/HEAD/numerical_methods/variance.c) + +## Process Scheduling Algorithms + * [Non Preemptive Priority Scheduling](https://github.com/TheAlgorithms/C/blob/HEAD/process_scheduling_algorithms/non_preemptive_priority_scheduling.c) + +## Project Euler + * Problem 1 + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_1/sol1.c) + * [Sol2](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_1/sol2.c) + * [Sol3](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_1/sol3.c) + * [Sol4](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_1/sol4.c) + * Problem 10 + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_10/sol1.c) + * [Sol2](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_10/sol2.c) + * Problem 12 + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_12/sol1.c) + * Problem 13 + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_13/sol1.c) + * Problem 14 + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_14/sol1.c) + * Problem 15 + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_15/sol1.c) + * Problem 16 + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_16/sol1.c) + * Problem 19 + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_19/sol1.c) + * Problem 2 + * [So1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_2/so1.c) + * Problem 20 + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_20/sol1.c) + * Problem 21 + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_21/sol1.c) + * Problem 22 + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_22/sol1.c) + * Problem 23 + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_23/sol1.c) + * [Sol2](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_23/sol2.c) + * Problem 25 + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_25/sol1.c) + * Problem 26 + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_26/sol1.c) + * Problem 3 + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_3/sol1.c) + * [Sol2](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_3/sol2.c) + * Problem 4 + * [Sol](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_4/sol.c) + * Problem 401 + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_401/sol1.c) + * Problem 5 + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_5/sol1.c) + * [Sol2](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_5/sol2.c) + * [Sol3](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_5/sol3.c) + * Problem 6 + * [Sol](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_6/sol.c) + * Problem 7 + * [Sol](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_7/sol.c) + * [Sol2](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_7/sol2.c) + * Problem 8 + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_8/sol1.c) + * [Sol2](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_8/sol2.c) + * Problem 9 + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_9/sol1.c) + * [Sol2](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_9/sol2.c) + +## Searching + * [Binary Search](https://github.com/TheAlgorithms/C/blob/HEAD/searching/binary_search.c) + * [Exponential Search](https://github.com/TheAlgorithms/C/blob/HEAD/searching/exponential_search.c) + * [Fibonacci Search](https://github.com/TheAlgorithms/C/blob/HEAD/searching/fibonacci_search.c) + * [Floyd Cycle Detection Algorithm](https://github.com/TheAlgorithms/C/blob/HEAD/searching/floyd_cycle_detection_algorithm.c) + * [Interpolation Search](https://github.com/TheAlgorithms/C/blob/HEAD/searching/interpolation_search.c) + * [Jump Search](https://github.com/TheAlgorithms/C/blob/HEAD/searching/jump_search.c) + * [Linear Search](https://github.com/TheAlgorithms/C/blob/HEAD/searching/linear_search.c) + * [Modified Binary Search](https://github.com/TheAlgorithms/C/blob/HEAD/searching/modified_binary_search.c) + * [Other Binary Search](https://github.com/TheAlgorithms/C/blob/HEAD/searching/other_binary_search.c) + * Pattern Search + * [Boyer Moore Search](https://github.com/TheAlgorithms/C/blob/HEAD/searching/pattern_search/boyer_moore_search.c) + * [Naive Search](https://github.com/TheAlgorithms/C/blob/HEAD/searching/pattern_search/naive_search.c) + * [Rabin Karp Search](https://github.com/TheAlgorithms/C/blob/HEAD/searching/pattern_search/rabin_karp_search.c) + * [Sentinel Linear Search](https://github.com/TheAlgorithms/C/blob/HEAD/searching/sentinel_linear_search.c) + * [Ternary Search](https://github.com/TheAlgorithms/C/blob/HEAD/searching/ternary_search.c) + +## Sorting + * [Bead Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/bead_sort.c) + * [Binary Insertion Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/binary_insertion_sort.c) + * [Bogo Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/bogo_sort.c) + * [Bubble Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/bubble_sort.c) + * [Bubble Sort 2](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/bubble_sort_2.c) + * [Bubble Sort Recursion](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/bubble_sort_recursion.c) + * [Bucket Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/bucket_sort.c) + * [Cocktail Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/cocktail_sort.c) + * [Comb Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/comb_sort.c) + * [Counting Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/counting_sort.c) + * [Cycle Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/cycle_sort.c) + * [Gnome Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/gnome_sort.c) + * [Heap Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/heap_sort.c) + * [Heap Sort 2](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/heap_sort_2.c) + * [Insertion Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/insertion_sort.c) + * [Insertion Sort Recursive](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/insertion_sort_recursive.c) + * [Merge Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/merge_sort.c) + * [Merge Sort Nr](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/merge_sort_nr.c) + * [Multikey Quick Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/multikey_quick_sort.c) + * [Odd Even Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/odd_even_sort.c) + * [Pancake Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/pancake_sort.c) + * [Partition Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/partition_sort.c) + * [Patience Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/patience_sort.c) + * [Pigeonhole Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/pigeonhole_sort.c) + * [Quick Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/quick_sort.c) + * [Radix Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/radix_sort.c) + * [Radix Sort 2](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/radix_sort_2.c) + * [Random Quick Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/random_quick_sort.c) + * [Selection Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/selection_sort.c) + * [Selection Sort Recursive](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/selection_sort_recursive.c) + * [Shaker Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/shaker_sort.c) + * [Shell Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/shell_sort.c) + * [Shell Sort2](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/shell_sort2.c) + * [Stooge Sort](https://github.com/TheAlgorithms/C/blob/HEAD/sorting/stooge_sort.c) diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000000..cc06df4806 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,277 @@ +# +# DO NOT EDIT! THIS FILE WAS GENERATED BY CMAKE! +# + +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = Algorithms_in_C +PROJECT_NUMBER = 1.0.0 +PROJECT_BRIEF = "Set of algorithms implemented in C." +PROJECT_LOGO = +OUTPUT_DIRECTORY = /Users/kvedala/GitHub/C/build +CREATE_SUBDIRS = NO +ALLOW_UNICODE_NAMES = NO +OUTPUT_LANGUAGE = English +OUTPUT_TEXT_DIRECTION = None +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" "The $name widget" "The $name file" is provides specifies contains represents a an the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +JAVADOC_BANNER = NO +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 4 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +OPTIMIZE_OUTPUT_SLICE = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +TOC_INCLUDE_HEADINGS = 5 +AUTOLINK_SUPPORT = YES +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +GROUP_NESTED_COMPOUNDS = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +LOOKUP_CACHE_SIZE = 0 +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_PRIV_VIRTUAL = NO +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +HIDE_COMPOUND_REFERENCE= NO +SHOW_INCLUDE_FILES = YES +SHOW_GROUPED_MEMB_INC = NO +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_AS_ERROR = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +INPUT = /Users/kvedala/GitHub/C +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.idl *.ddl *.odl *.h *.hh *.hxx *.hpp *.h++ *.cs *.d *.php *.php4 *.php5 *.phtml *.inc *.m *.markdown *.md *.mm *.dox *.doc *.txt *.py *.pyw *.f90 *.f95 *.f03 *.f08 *.f18 *.f *.for *.vhd *.vhdl *.ucf *.qsf *.ice +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = */.git/* */.svn/* */.hg/* */CMakeFiles/* */_CPack_Packages/* DartConfiguration.tcl CMakeLists.txt CMakeCache.txt +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +FILTER_SOURCE_PATTERNS = +USE_MDFILE_AS_MAINPAGE = +SOURCE_BROWSER = NO +INLINE_SOURCES = YES +STRIP_CODE_COMMENTS = NO +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +SOURCE_TOOLTIPS = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = NO +HTML_DYNAMIC_MENUS = YES +HTML_DYNAMIC_SECTIONS = NO +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = NO +ENUM_VALUES_PER_LINE = 4 +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +HTML_FORMULA_FORMAT = png +FORMULA_FONTSIZE = 10 +FORMULA_TRANSPARENT = YES +FORMULA_MACROFILE = +USE_MATHJAX = YES +MATHJAX_FORMAT = HTML-CSS +MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2 +MATHJAX_EXTENSIONS = +MATHJAX_CODEFILE = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +EXTERNAL_SEARCH = NO +SEARCHENGINE_URL = +SEARCHDATA_FILE = searchdata.xml +EXTERNAL_SEARCH_ID = +EXTRA_SEARCH_MAPPINGS = +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = +MAKEINDEX_CMD_NAME = makeindex +LATEX_MAKEINDEX_CMD = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4 +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +LATEX_EXTRA_STYLESHEET = +LATEX_EXTRA_FILES = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO +LATEX_BIB_STYLE = plain +LATEX_TIMESTAMP = NO +LATEX_EMOJI_DIRECTORY = +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +RTF_SOURCE_CODE = NO +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_SUBDIR = +MAN_LINKS = NO +GENERATE_XML = NO +XML_OUTPUT = xml +XML_PROGRAMLISTING = YES +XML_NS_MEMB_FILE_SCOPE = NO +GENERATE_DOCBOOK = NO +DOCBOOK_OUTPUT = docbook +DOCBOOK_PROGRAMLISTING = NO +GENERATE_AUTOGEN_DEF = NO +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +EXTERNAL_PAGES = YES +CLASS_DIAGRAMS = YES +DIA_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +DOT_NUM_THREADS = 0 +DOT_FONTNAME = Helvetica +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +UML_LIMIT_NUM_FIELDS = 10 +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = svg +INTERACTIVE_SVG = YES +DOT_PATH = /Users/kvedala/anaconda3/bin +DOTFILE_DIRS = +MSCFILE_DIRS = +DIAFILE_DIRS = +PLANTUML_JAR_PATH = +PLANTUML_CFG_FILE = +PLANTUML_INCLUDE_PATH = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = YES +GENERATE_LEGEND = YES +DOT_CLEANUP = YES diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..1e132df443 --- /dev/null +++ b/LICENSE @@ -0,0 +1,676 @@ +Copyright (C) 2016-2023 TheAlgorithms and contributors + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md index fd17f7de6a..9670d2bb07 100644 --- a/README.md +++ b/README.md @@ -1,88 +1,39 @@ -# C +# The Algorithms - C # {#mainpage} + -## Computer Oriented Statistical Methods - - Gauss_Elimination - - Lagrange_Theorem - - Mean - - Median - - Seidal - - Simpson's_1-3rd_rule.c - - Variance - - statistic (C Lib) +[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/TheAlgorithms/C) +[![CodeQL CI](https://github.com/TheAlgorithms/C/actions/workflows/codeql.yml/badge.svg)](https://github.com/TheAlgorithms/C/actions/workflows/codeql_analysis.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/blob/master/CONTRIBUTING.md) +![GitHub repo size](https://img.shields.io/github/repo-size/TheAlgorithms/C?color=red&style=flat-square) +[![Doxygen CI](https://github.com/TheAlgorithms/C/workflows/Doxygen%20CI/badge.svg)](https://TheAlgorithms.github.io/C) +[![Awesome CI](https://github.com/TheAlgorithms/C/workflows/Awesome%20CI%20Workflow/badge.svg)](https://github.com/TheAlgorithms/C/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) -## Conversions - - binary_to_decimal - - decimal _to_binary - - decimal_to_hexa - - decimal_to_octal - - to_decimal +## Overview -## Data Structures - - stack - - queue - - dictionary - linked_list - - singly_link_list_deletion - - stack_using_linkedlists - binary_trees - - create_node - - recursive_traversals - trie - - trie +The repository is a collection of open-source implementations of a variety of algorithms implemented in C and licensed under [GPLv3 License](https://github.com/TheAlgorithms/C/blob/master/LICENSE). The algorithms span a variety of topics from computer science, mathematics and statistics, data science, machine learning, engineering, etc.. The implementations and their associated documentations 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 different algorithm strategies and optimizations. +## Features -## Searching - - Binary_Search - - Other_Binary_Search - - Jump_Search +* The repository provides implementations of various algorithms in one of the most fundamental general purpose languages - [C](https://en.wikipedia.org/wiki/C_(programming_language)). +* Well documented source code with detailed explanations provide a valuable resource for educators and students alike. +* Each source code is atomic using standard C library [`libc`](https://en.wikipedia.org/wiki/C_standard_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/actions?query=workflow%3A%22Awesome+CI+Workflow%22) for every commit on the latest versions of two major operating systems viz., MacOS and Ubuntu (Linux) using AppleClang 14.0.0 and GNU 11.3.0 respectively. +* Strict adherence to [C11](https://en.wikipedia.org/wiki/C11_(C_standard_revision)) standard ensures portability of code to embedded systems as well like ESP32, ARM Cortex, 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 -## Sorting - - BinaryInsertionSort - - BubbleSort - - BogoSort - - InsertionSort - - MergeSort - - OtherBubbleSort - - QuickSort - - SelectionSort - - ShakerSort - - HeapSort - -## Hashing - - sdbm - - djb2 - - xor8 (8 bit) - - adler_32 (32 bit) +[Online Documentation](https://TheAlgorithms.github.io/C) 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. +Click on [Files menu](https://TheAlgorithms.github.io/C/files.html) to see the list of all the files documented with the code. +[Documentation of Algorithms in C](https://thealgorithms.github.io/C) by [The Algorithms Contributors](https://github.com/TheAlgorithms/C/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 -## Misc - - Binning - - Factorial - - Fibonacci - - isArmstrong - - LongestSubSequence - - palindrome - - QUARTILE - - rselect - - strongNumber - - TowerOfHanoi - - Greatest Common Divisor - - Sudoku Solver - - prime factorization +## Contributions - -## exercism -In this directory you will find (in the right order): -* hello-world -* isogram -* acronym -* word-count -* rna-transcription - -## Simple Client Server Implementation -This directory contains -* client.c -* server.c - -First execute server.c in a terminal and then client.c in a different terminal. Enables communication between two terminals. +As a community developed and maintained repository, we welcome new un-plagiarized quality contributions. Please read our [Contribution Guidelines](https://github.com/TheAlgorithms/C/blob/master/CONTRIBUTING.md). diff --git a/REVIEWER_CODE.md b/REVIEWER_CODE.md new file mode 100644 index 0000000000..933d43e685 --- /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/Simple Client Server/client.c b/Simple Client Server/client.c deleted file mode 100644 index bd208362b0..0000000000 --- a/Simple Client Server/client.c +++ /dev/null @@ -1,66 +0,0 @@ - -// Write CPP code here -#include -#include -#include -#include -#include -#include -#define MAX 80 -#define PORT 8080 -#define SA struct sockaddr -void func(int sockfd) -{ - char buff[MAX]; - int n; - for (;;) { - bzero(buff, sizeof(buff)); - printf("Enter the string : "); - n = 0; - while ((buff[n++] = getchar()) != '\n') - ; - write(sockfd, buff, sizeof(buff)); - bzero(buff, sizeof(buff)); - read(sockfd, buff, sizeof(buff)); - printf("From Server : %s", buff); - if ((strncmp(buff, "exit", 4)) == 0) { - printf("Client Exit...\n"); - break; - } - } -} - -int main() -{ - int sockfd, connfd; - struct sockaddr_in servaddr, cli; - - // socket create and varification - sockfd = socket(AF_INET, SOCK_STREAM, 0); - if (sockfd == -1) { - printf("socket creation failed...\n"); - exit(0); - } - else - printf("Socket successfully created..\n"); - bzero(&servaddr, sizeof(servaddr)); - - // assign IP, PORT - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); - servaddr.sin_port = htons(PORT); - - // connect the client socket to server socket - if (connect(sockfd, (SA*)&servaddr, sizeof(servaddr)) != 0) { - printf("connection with the server failed...\n"); - exit(0); - } - else - printf("connected to the server..\n"); - - // function for chat - func(sockfd); - - // close the socket - close(sockfd); -} diff --git a/Simple Client Server/server.c b/Simple Client Server/server.c deleted file mode 100644 index d3ea7e2c94..0000000000 --- a/Simple Client Server/server.c +++ /dev/null @@ -1,96 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include -#include -#define MAX 80 -#define PORT 8080 -#define SA struct sockaddr - -// Function designed for chat between client and server. -void func(int sockfd) -{ - char buff[MAX]; - int n; - // infinite loop for chat - for (;;) { - bzero(buff, MAX); - - // read the message from client and copy it in buffer - read(sockfd, buff, sizeof(buff)); - // print buffer which contains the client contents - printf("From client: %s\t To client : ", buff); - bzero(buff, MAX); - n = 0; - // copy server message in the buffer - while ((buff[n++] = getchar()) != '\n') - ; - - // and send that buffer to client - write(sockfd, buff, sizeof(buff)); - - // if msg contains "Exit" then server exit and chat ended. - if (strncmp("exit", buff, 4) == 0) { - printf("Server Exit...\n"); - break; - } - } -} - -// Driver function -int main() -{ - int sockfd, connfd, len; - struct sockaddr_in servaddr, cli; - - // socket create and verification - sockfd = socket(AF_INET, SOCK_STREAM, 0); - if (sockfd == -1) { - printf("socket creation failed...\n"); - exit(0); - } - else - printf("Socket successfully created..\n"); - bzero(&servaddr, sizeof(servaddr)); - - // assign IP, PORT - servaddr.sin_family = AF_INET; - servaddr.sin_addr.s_addr = htonl(INADDR_ANY); - servaddr.sin_port = htons(PORT); - - // Binding newly created socket to given IP and verification - if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) { - printf("socket bind failed...\n"); - exit(0); - } - else - printf("Socket successfully binded..\n"); - - // Now server is ready to listen and verification - if ((listen(sockfd, 5)) != 0) { - printf("Listen failed...\n"); - exit(0); - } - else - printf("Server listening..\n"); - len = sizeof(cli); - - // Accept the data packet from client and verification - connfd = accept(sockfd, (SA*)&cli, &len); - if (connfd < 0) { - printf("server acccept failed...\n"); - exit(0); - } - else - printf("server acccept the client...\n"); - - // Function for chatting between client and server - func(connfd); - - // After chatting close the socket - close(sockfd); -} diff --git a/audio/CMakeLists.txt b/audio/CMakeLists.txt new file mode 100644 index 0000000000..671d5c663b --- /dev/null +++ b/audio/CMakeLists.txt @@ -0,0 +1,14 @@ +# 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} *.c ) +# 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 ".c" "" testname ${testsourcefile} ) + add_executable( ${testname} ${testsourcefile} ) + + install(TARGETS ${testname} DESTINATION "bin/audio") + +endforeach( testsourcefile ${APP_SOURCES} ) diff --git a/audio/alaw.c b/audio/alaw.c new file mode 100644 index 0000000000..5cf0018557 --- /dev/null +++ b/audio/alaw.c @@ -0,0 +1,216 @@ +/** + * @file + * @author [sunzhenliang](https://github.com/HiSunzhenliang) + * @brief A-law algorithm for encoding and decoding (16bit pcm <=> a-law). + * This is the implementation of [G.711](https://en.wikipedia.org/wiki/G.711) + * in C. + **/ + +/** + * Linear input code | Compressed code | Linear output code + * ------------------+-----------------+------------------- + * s0000000abcdx | s000abcd | s0000000abcd1 + * s0000001abcdx | s001abcd | s0000001abcd1 + * s000001abcdxx | s010abcd | s000001abcd10 + * s00001abcdxxx | s011abcd | s00001abcd100 + * s0001abcdxxxx | s100abcd | s0001abcd1000 + * s001abcdxxxxx | s101abcd | s001abcd10000 + * s01abcdxxxxxx | s110abcd | s01abcd100000 + * s1abcdxxxxxxx | s111abcd | s1abcd1000000 + * + * Compressed code: (s | eee | abcd) + **/ +#include /// for assert +#include /// for appropriate size int types +#include /// for IO operations + +/* length of test inputs */ +#define LEN ((size_t)8) + +/* input pcm for test */ +int16_t pcm[LEN] = {1000, -1000, 1234, 3200, -1314, 0, 32767, -32768}; + +/* result coded alaw for test */ +uint8_t r_coded[LEN] = {250, 122, 230, 156, 97, 213, 170, 42}; + +/* result decoded for test */ +int16_t r_decoded[LEN] = {1008, -1008, 1248, 3264, -1312, 8, 32256, -32256}; + +/** + * @brief 16bit pcm to 8bit alaw + * @param out unsigned 8bit alaw array + * @param in signed 16bit pcm array + * @param len length of pcm array + * @returns void + */ +void encode(uint8_t *out, int16_t *in, size_t len) +{ + uint8_t alaw = 0; + int16_t pcm = 0; + int32_t sign = 0; + int32_t abcd = 0; + int32_t eee = 0; + int32_t mask = 0; + for (size_t i = 0; i < len; i++) + { + pcm = *in++; + /* 0-7 kinds of quantization level from the table above */ + eee = 7; + mask = 0x4000; /* 0x4000: '0b0100 0000 0000 0000' */ + + /* Get sign bit */ + sign = (pcm & 0x8000) >> 8; + + /* Turn negative pcm to positive */ + /* The absolute value of a negative number may be larger than the size + * of the corresponding positive number, so here needs `-pcm -1` after + * taking the opposite number. */ + pcm = sign ? (-pcm - 1) : pcm; + + /* Get eee and abcd bit */ + /* Use mask to locate the first `1` bit and quantization level at the + * same time */ + while ((pcm & mask) == 0 && eee > 0) + { + eee--; + mask >>= 1; + } + + /* The location of abcd bits is related with quantization level. Check + * the table above to determine how many bits to `>>` to get abcd */ + abcd = (pcm >> (eee ? (eee + 3) : 4)) & 0x0f; + + /* Put the quantization level number at right bit location to get eee + * bits */ + eee <<= 4; + + /* Splice results */ + alaw = (sign | eee | abcd); + + /* The standard specifies that all resulting even bits (LSB + * is even) are inverted before the octet is transmitted. This is to + * provide plenty of 0/1 transitions to facilitate the clock recovery + * process in the PCM receivers. Thus, a silent A-law encoded PCM + * channel has the 8 bit samples coded 0xD5 instead of 0x80 in the + * octets. (Reference from wiki above) */ + *out++ = alaw ^ 0xD5; + } +} + +/** + * @brief 8bit alaw to 16bit pcm + * @param out signed 16bit pcm array + * @param in unsigned 8bit alaw array + * @param len length of alaw array + * @returns void + */ +void decode(int16_t *out, uint8_t *in, size_t len) +{ + uint8_t alaw = 0; + int32_t pcm = 0; + int32_t sign = 0; + int32_t eee = 0; + for (size_t i = 0; i < len; i++) + { + alaw = *in++; + + /* Re-toggle toggled bits */ + alaw ^= 0xD5; + + /* Get sign bit */ + sign = alaw & 0x80; + + /* Get eee bits */ + eee = (alaw & 0x70) >> 4; + + /* Get abcd bits and add 1/2 quantization step */ + pcm = (alaw & 0x0f) << 4 | 8; + + /* If quantization level > 0, there need `1` bit before abcd bits */ + pcm += eee ? 0x100 : 0x0; + + /* Left shift according quantization level */ + pcm <<= eee > 1 ? (eee - 1) : 0; + + /* Use the right sign */ + *out++ = sign ? -pcm : pcm; + } +} + +/** + * @brief Self-test implementations + * @param pcm signed 16bit pcm array + * @param coded unsigned 8bit alaw array + * @param decoded signed 16bit pcm array + * @param len length of test array + * @returns void + */ +static void test(int16_t *pcm, uint8_t *coded, int16_t *decoded, size_t len) +{ + /* run encode */ + encode(coded, pcm, len); + + /* check encode result */ + for (size_t i = 0; i < len; i++) + { + assert(coded[i] == r_coded[i]); + } + + /* run decode */ + decode(decoded, coded, len); + + /* check decode result */ + for (size_t i = 0; i < len; i++) + { + assert(decoded[i] == r_decoded[i]); + } +} + +/** + * @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[]) +{ + /* output alaw encoded by encode() */ + uint8_t coded[LEN]; + + /* output pcm decoded by decode() from coded[LEN] */ + int16_t decoded[LEN]; + + test(pcm, coded, decoded, LEN); // run self-test implementations + + /* print test pcm inputs */ + printf("inputs: "); + for (size_t i = 0; i < LEN; i++) + { + printf("%d ", pcm[i]); + } + printf("\n"); + + /* print encoded alaw */ + printf("encode: "); + for (size_t i = 0; i < LEN; i++) + { + printf("%u ", coded[i]); + } + printf("\n"); + + /* print decoded pcm */ + printf("decode: "); + for (size_t i = 0; i < LEN; i++) + { + printf("%d ", decoded[i]); + } + printf("\n"); + + /* It can be seen that the encoded alaw is smaller than the input PCM, so + * the purpose of compression is achieved. And the decoded PCM is almost the + * same as the original input PCM, which verifies the correctness of the + * decoding. The reason why it is not exactly the same is that there is + * precision loss during encode / decode. */ + + return 0; +} diff --git a/cipher/CMakeLists.txt b/cipher/CMakeLists.txt new file mode 100644 index 0000000000..c1d93bbc91 --- /dev/null +++ b/cipher/CMakeLists.txt @@ -0,0 +1,18 @@ +# 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} *.c ) +foreach( testsourcefile ${APP_SOURCES} ) + string( REPLACE ".c" "" testname ${testsourcefile} ) # File type. Example: `.c` + add_executable( ${testname} ${testsourcefile} ) + + if(OpenMP_C_FOUND) + target_link_libraries(${testname} OpenMP::OpenMP_C) + endif() + if(MATH_LIBRARY) + target_link_libraries(${testname} ${MATH_LIBRARY}) + endif() + install(TARGETS ${testname} DESTINATION "bin/cipher") # Folder name. Do NOT include `<>` + +endforeach( testsourcefile ${APP_SOURCES} ) diff --git a/cipher/affine.c b/cipher/affine.c new file mode 100644 index 0000000000..49a91cd799 --- /dev/null +++ b/cipher/affine.c @@ -0,0 +1,207 @@ +/** + * @file + * @brief An [affine cipher](https://en.wikipedia.org/wiki/Affine_cipher) is a + * letter substitution cipher that uses a linear transformation to substitute + * letters in a message. + * @details Given an alphabet of length M with characters with numeric values + * 0-(M-1), an arbitrary character x can be transformed with the expression (ax + * + b) % M into our ciphertext character. The only caveat is that a must be + * relatively prime with M in order for this transformation to be invertible, + * i.e., gcd(a, M) = 1. + * @author [Daniel Murrow](https://github.com/dsmurrow) + */ + +#include /// for assertions +#include /// for IO +#include /// for div function and div_t struct as well as malloc and free +#include /// for strlen, strcpy, and strcmp + +/** + * @brief number of characters in our alphabet (printable ASCII characters) + */ +#define ALPHABET_SIZE 95 + +/** + * @brief used to convert a printable byte (32 to 126) to an element of the + * group Z_95 (0 to 94) + */ +#define Z95_CONVERSION_CONSTANT 32 + +/** + * @brief a structure representing an affine cipher key + */ +typedef struct +{ + int a; ///< what the character is being multiplied by + int b; ///< what is being added after the multiplication with `a` +} affine_key_t; + +/** + * @brief finds the value x such that (a * x) % m = 1 + * + * @param a number we are finding the inverse for + * @param m the modulus the inversion is based on + * + * @returns the modular multiplicative inverse of `a` mod `m` + */ +int modular_multiplicative_inverse(unsigned int a, unsigned int m) +{ + int x[2] = {1, 0}; + div_t div_result; + + if (m == 0) { + return 0; + } + a %= m; + if (a == 0) { + return 0; + } + + div_result.rem = a; + + while (div_result.rem > 0) + { + div_result = div(m, a); + + m = a; + a = div_result.rem; + + // Calculate value of x for this iteration + int next = x[1] - (x[0] * div_result.quot); + + x[1] = x[0]; + x[0] = next; + } + + return x[1]; +} + +/** + * @brief Given a valid affine cipher key, this function will produce the + * inverse key. + * + * @param key They key to be inverted + * + * @returns inverse of key + */ +affine_key_t inverse_key(affine_key_t key) +{ + affine_key_t inverse; + + inverse.a = modular_multiplicative_inverse(key.a, ALPHABET_SIZE); + + // Turn negative results positive + inverse.a += ALPHABET_SIZE; + inverse.a %= ALPHABET_SIZE; + + inverse.b = -(key.b % ALPHABET_SIZE) + ALPHABET_SIZE; + + return inverse; +} + +/** + * @brief Encrypts character string `s` with key + * + * @param s string to be encrypted + * @param key affine key used for encryption + * + * @returns void + */ +void affine_encrypt(char *s, affine_key_t key) +{ + for (int i = 0; s[i] != '\0'; i++) + { + int c = (int)s[i] - Z95_CONVERSION_CONSTANT; + + c *= key.a; + c += key.b; + c %= ALPHABET_SIZE; + + s[i] = (char)(c + Z95_CONVERSION_CONSTANT); + } +} + +/** + * @brief Decrypts an affine ciphertext + * + * @param s string to be decrypted + * @param key Key used when s was encrypted + * + * @returns void + */ +void affine_decrypt(char *s, affine_key_t key) +{ + affine_key_t inverse = inverse_key(key); + + for (int i = 0; s[i] != '\0'; i++) + { + int c = (int)s[i] - Z95_CONVERSION_CONSTANT; + + c += inverse.b; + c *= inverse.a; + c %= ALPHABET_SIZE; + + s[i] = (char)(c + Z95_CONVERSION_CONSTANT); + } +} + +/** + * @brief Tests a given string + * + * @param s string to be tested + * @param a value of key.a + * @param b value of key.b + * + * @returns void + */ +void test_string(const char *s, const char *ciphertext, int a, int b) +{ + char *copy = malloc((strlen(s) + 1) * sizeof(char)); + strcpy(copy, s); + + affine_key_t key = {a, b}; + + affine_encrypt(copy, key); + assert(strcmp(copy, ciphertext) == 0); // assert that the encryption worked + + affine_decrypt(copy, key); + assert(strcmp(copy, s) == + 0); // assert that we got the same string we started with + + free(copy); +} + +/** + * @brief Test multiple strings + * + * @returns void + */ +static void tests() +{ + test_string("Hello!", "&3ddy2", 7, 11); + test_string("TheAlgorithms/C", "DNC}=jHS2zN!7;E", 67, 67); + test_string("0123456789", "840,($ {ws", 91, 88); + test_string("7W@;cdeRT9uL", "JDfa*we?z&bL", 77, 76); + test_string("~Qr%^-+++$leM", "r'qC0$sss;Ahf", 8, 90); + test_string("The quick brown fox jumps over the lazy dog", + "K7: .*6<4 =-0(1 90' 5*2/, 0):- +7: 3>%& ;08", 94, 0); + test_string( + "One-1, Two-2, Three-3, Four-4, Five-5, Six-6, Seven-7, Eight-8, " + "Nine-9, Ten-10", + "H&60>\\2*uY0q\\2*p4660E\\2XYn40x\\2XDB60L\\2VDI0 " + "\\2V6B6&0S\\2%D=p;0'\\2tD&60Z\\2*6&0>j", + 51, 18); + + printf("All tests have successfully passed!\n"); +} + +/** + * @brief main function + * + * @returns 0 upon successful program exit + */ +int main() +{ + tests(); + return 0; +} diff --git a/cipher/rot13.c b/cipher/rot13.c new file mode 100644 index 0000000000..1a6022f40e --- /dev/null +++ b/cipher/rot13.c @@ -0,0 +1,60 @@ +/** + * @file + * @brief [ROT13](https://en.wikipedia.org/wiki/ROT13) is a simple letter + * substitution cipher that replaces a letter with the 13th letter after it in + * the alphabet. + * @details ROT13 transforms a piece of text by examining its alphabetic + * characters and replacing each one with the letter 13 places further along in + * the alphabet, wrapping back to the beginning if necessary. A becomes N, B + * becomes O, and so on up to M, which becomes Z, then the sequence continues at + * the beginning of the alphabet: N becomes A, O becomes B, and so on to Z, + * which becomes M. + * @author [Jeremias Moreira Gomes](https://github.com/j3r3mias) + */ + +#include /// for IO operations +#include /// for string operations +#include /// for assert + +/** + * @brief Apply the ROT13 cipher + * @param s contains the string to be processed + */ +void rot13(char *s) { + for (int i = 0; s[i]; i++) { + if (s[i] >= 'A' && s[i] <= 'Z') { + s[i] = 'A' + ((s[i] - 'A' + 13) % 26); + } else if (s[i] >= 'a' && s[i] <= 'z') { + s[i] = 'a' + ((s[i] - 'a' + 13) % 26); + } + } +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + char test_01[] = "The more I C, the less I see."; + rot13(test_01); + assert(strcmp(test_01, "Gur zber V P, gur yrff V frr.") == 0); + + char test_02[] = "Which witch switched the Swiss wristwatches?"; + rot13(test_02); + assert(strcmp(test_02, "Juvpu jvgpu fjvgpurq gur Fjvff jevfgjngpurf?") == 0); + + char test_03[] = "Juvpu jvgpu fjvgpurq gur Fjvff jevfgjngpurf?"; + rot13(test_03); + assert(strcmp(test_03, "Which witch switched the Swiss wristwatches?") == 0); + + printf("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/client_server/CMakeLists.txt b/client_server/CMakeLists.txt new file mode 100644 index 0000000000..58d0aeb87c --- /dev/null +++ b/client_server/CMakeLists.txt @@ -0,0 +1,52 @@ +include(CheckIncludeFile) + +if(WIN32) + CHECK_INCLUDE_FILE(winsock2.h WINSOCK_HEADER) +else() + CHECK_INCLUDE_FILE(arpa/inet.h ARPA_HEADERS) +endif() + +include(CheckSymbolExists) +if(ARPA_HEADERS OR WINSOCK_HEADER) + # 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} *.c ) + # 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 ".c" "" testname ${testsourcefile}) + + if(NOT WIN32) + if(${testname} STREQUAL "fork" OR ${testname} STREQUAL "bool") + continue() + endif() + endif() + add_executable(${testname} ${testsourcefile}) + + if (OpenMP_C_FOUND) + target_link_libraries(${testname} PRIVATE OpenMP::OpenMP_C) + endif () + if (MATH_LIBRARY) + target_link_libraries(${testname} PRIVATE ${MATH_LIBRARY}) + endif () + # if(HAS_UNISTD) + # target_compile_definitions(${testname} PRIVATE HAS_UNISTD) + # endif() + # if(ARPA_HEADERS) + # target_compile_definitions(${testname} PRIVATE ARPA_HEADERS) + # else() + # target_compile_definitions(${testname} PRIVATE WINSOCK_HEADER) + # endif() + + if (WINSOCK_HEADER) + target_link_libraries(${testname} PRIVATE ws2_32) # link winsock library on windows + endif() + + install(TARGETS ${testname} DESTINATION "bin/client_server") + + endforeach( testsourcefile ${APP_SOURCES} ) +else() + message(WARNING "socket headers not found in system.") +endif(ARPA_HEADERS OR WINSOCK_HEADER) diff --git a/client_server/bool.h b/client_server/bool.h new file mode 100644 index 0000000000..25cc9a72df --- /dev/null +++ b/client_server/bool.h @@ -0,0 +1,55 @@ +/* + * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab + * Copyright (C) 2007 - INRIA + * + * Copyright (C) 2012 - 2016 - Scilab Enterprises + * + * This file is hereby licensed under the terms of the GNU GPL v2.0, + * pursuant to article 5.3.4 of the CeCILL v.2.1. + * This file was originally licensed under the terms of the CeCILL v2.1, + * and continues to be available under such terms. + * For more information, see the COPYING file which you should have received + * along with this program. + * + */ +#ifndef __BOOL_H__ +#define __BOOL_H__ + +/* define boolean type */ +#ifdef BOOL +#undef BOOL +#endif + +#ifdef TRUE +#undef TRUE +#endif + +#ifdef FALSE +#undef FALSE +#endif + + +#ifndef _MSC_VER +typedef enum +{ + FALSE = 0, + TRUE = 1 +} BOOL; + +#else +/* Please notice that BOOL is defined in */ +/* BUT windef.h includes all others windows include */ +/* it is better to redefine as */ +typedef int BOOL; +#define FALSE 0 +#define TRUE 1 + +#endif +/* converts BOOL to bool */ +#define BOOLtobool(w) ((w != FALSE) ? true : false) + +/* converts bool to BOOL */ +#define booltoBOOL(w) ((w == true) ? TRUE : FALSE) + +#endif /* __BOOL_H__ */ +/*--------------------------------------------------------------------------*/ diff --git a/client_server/client.c b/client_server/client.c new file mode 100644 index 0000000000..c34c93f7b8 --- /dev/null +++ b/client_server/client.c @@ -0,0 +1,122 @@ +/** + * @file + * @author [Nairit11](https://github.com/Nairit11) + * @author [Krishna Vedala](https://github.com/kvedala) + * @brief Client side implementation of Server-Client system. + * @see client_server/server.c + */ +#include +#include +#include + +#ifdef _WIN32 // if compiling for Windows +#define _WINSOCK_DEPRECATED_NO_WARNINGS // will make the code invalid for next + // MSVC compiler versions +#include +#define bzero(b, len) \ + (memset((b), '\0', (len)), (void)0) /**< BSD name not in windows */ +#define read(a, b, c) recv(a, b, c, 0) /**< map BSD name to Winsock */ +#define write(a, b, c) send(a, b, c, 0) /**< map BSD name to Winsock */ +#define close closesocket /**< map BSD name to Winsock */ +#else // if not windows platform +#include +#include +#include +#include +#endif + +#define MAX 80 /**< max. characters per message */ +#define PORT 8080 /**< port number to connect to */ +#define SA struct sockaddr /**< shortname for sockaddr */ + +/** + * Continuous loop to send and receive over the socket. + * Exits when "exit" is sent from commandline. + * @param sockfd socket handle number + */ +void func(int sockfd) +{ + char buff[MAX]; + int n; + for (;;) + { + bzero(buff, sizeof(buff)); + printf("Enter the string : "); + n = 0; + while ((buff[n++] = getchar()) != '\n') + { + ; + } + write(sockfd, buff, sizeof(buff)); + bzero(buff, sizeof(buff)); + read(sockfd, buff, sizeof(buff)); + printf("From Server : %s", buff); + if ((strncmp(buff, "exit", 4)) == 0) + { + printf("Client Exit...\n"); + break; + } + } +} + +#ifdef _WIN32 +/** Cleanup function will be automatically called on program exit */ +void cleanup() { WSACleanup(); } +#endif + +/** + * @brief Driver code + */ +int main() +{ +#ifdef _WIN32 + // when using winsock2.h, startup required + WSADATA wsData; + if (WSAStartup(MAKEWORD(2, 2), &wsData) != 0) + { + perror("WSA Startup error: \n"); + return 0; + } + + atexit(cleanup); // register at-exit function +#endif + + int sockfd, connfd; + struct sockaddr_in servaddr, cli; + + // socket create and verification + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd == -1) + { + printf("socket creation failed...\n"); + exit(0); + } + else + { + printf("Socket successfully created..\n"); + } + bzero(&servaddr, sizeof(servaddr)); + + // assign IP, PORT + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); + servaddr.sin_port = htons(PORT); + + // connect the client socket to server socket + if (connect(sockfd, (SA *)&servaddr, sizeof(servaddr)) != 0) + { + printf("connection with the server failed...\n"); + exit(0); + } + else + { + printf("connected to the server..\n"); + } + + // function for chat + func(sockfd); + + // close the socket + close(sockfd); + return 0; +} diff --git a/client_server/fork.h b/client_server/fork.h new file mode 100644 index 0000000000..3221d20454 --- /dev/null +++ b/client_server/fork.h @@ -0,0 +1,298 @@ +/* + * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab + * Copyright (C) DIGITEO - 2010 - Allan CORNET + * + * Copyright (C) 2012 - 2016 - Scilab Enterprises + * + * This file is hereby licensed under the terms of the GNU GPL v2.0, + * pursuant to article 5.3.4 of the CeCILL v.2.1. + * This file was originally licensed under the terms of the CeCILL v2.1, + * and continues to be available under such terms. + * For more information, see the COPYING file which you should have received + * along with this program. + * + */ +/*--------------------------------------------------------------------------*/ +#ifndef __FORK_H__ +#define __FORK_H__ + +/* http://technet.microsoft.com/en-us/library/bb497007.aspx */ +/* http://undocumented.ntinternals.net/ */ + +#include +#include + +#include "bool.h" + +/** + * simulate fork on Windows + */ +int fork(void); + +/** + * check if symbols to simulate fork are present + * and load these symbols + */ +BOOL haveLoadedFunctionsForFork(void); + +/*--------------------------------------------------------------------------*/ +typedef LONG NTSTATUS; +/*--------------------------------------------------------------------------*/ +typedef struct _SYSTEM_HANDLE_INFORMATION +{ + ULONG ProcessId; + UCHAR ObjectTypeNumber; + UCHAR Flags; + USHORT Handle; + PVOID Object; + ACCESS_MASK GrantedAccess; +} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION; +/*--------------------------------------------------------------------------*/ +typedef struct _OBJECT_ATTRIBUTES +{ + ULONG Length; + HANDLE RootDirectory; + PVOID /* really PUNICODE_STRING */ ObjectName; + ULONG Attributes; + PVOID SecurityDescriptor; /* type SECURITY_DESCRIPTOR */ + PVOID SecurityQualityOfService; /* type SECURITY_QUALITY_OF_SERVICE */ +} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES; +/*--------------------------------------------------------------------------*/ +typedef enum _MEMORY_INFORMATION_ +{ + MemoryBasicInformation, + MemoryWorkingSetList, + MemorySectionName, + MemoryBasicVlmInformation +} MEMORY_INFORMATION_CLASS; +/*--------------------------------------------------------------------------*/ +typedef struct _CLIENT_ID +{ + HANDLE UniqueProcess; + HANDLE UniqueThread; +} CLIENT_ID, *PCLIENT_ID; +/*--------------------------------------------------------------------------*/ +typedef struct _USER_STACK +{ + PVOID FixedStackBase; + PVOID FixedStackLimit; + PVOID ExpandableStackBase; + PVOID ExpandableStackLimit; + PVOID ExpandableStackBottom; +} USER_STACK, *PUSER_STACK; +/*--------------------------------------------------------------------------*/ +typedef LONG KPRIORITY; +typedef ULONG_PTR KAFFINITY; +typedef KAFFINITY *PKAFFINITY; +/*--------------------------------------------------------------------------*/ +typedef struct _THREAD_BASIC_INFORMATION +{ + NTSTATUS ExitStatus; + PVOID TebBaseAddress; + CLIENT_ID ClientId; + KAFFINITY AffinityMask; + KPRIORITY Priority; + KPRIORITY BasePriority; +} THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION; +/*--------------------------------------------------------------------------*/ +typedef enum _SYSTEM_INFORMATION_CLASS +{ + SystemHandleInformation = 0x10 +} SYSTEM_INFORMATION_CLASS; +/*--------------------------------------------------------------------------*/ +typedef NTSTATUS(NTAPI *ZwWriteVirtualMemory_t)( + IN HANDLE ProcessHandle, IN PVOID BaseAddress, IN PVOID Buffer, + IN ULONG NumberOfBytesToWrite, OUT PULONG NumberOfBytesWritten OPTIONAL); +/*--------------------------------------------------------------------------*/ +typedef NTSTATUS(NTAPI *ZwCreateProcess_t)( + OUT PHANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE InheriteFromProcessHandle, + IN BOOLEAN InheritHandles, IN HANDLE SectionHandle OPTIONAL, + IN HANDLE DebugPort OPTIONAL, IN HANDLE ExceptionPort OPTIONAL); +/*--------------------------------------------------------------------------*/ +typedef NTSTATUS(WINAPI *ZwQuerySystemInformation_t)( + SYSTEM_INFORMATION_CLASS SystemInformationClass, PVOID SystemInformation, + ULONG SystemInformationLength, PULONG ReturnLength); +typedef NTSTATUS(NTAPI *ZwQueryVirtualMemory_t)( + IN HANDLE ProcessHandle, IN PVOID BaseAddress, + IN MEMORY_INFORMATION_CLASS MemoryInformationClass, + OUT PVOID MemoryInformation, IN ULONG MemoryInformationLength, + OUT PULONG ReturnLength OPTIONAL); +/*--------------------------------------------------------------------------*/ +typedef NTSTATUS(NTAPI *ZwGetContextThread_t)(IN HANDLE ThreadHandle, + OUT PCONTEXT Context); +typedef NTSTATUS(NTAPI *ZwCreateThread_t)( + OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, + IN POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE ProcessHandle, + OUT PCLIENT_ID ClientId, IN PCONTEXT ThreadContext, + IN PUSER_STACK UserStack, IN BOOLEAN CreateSuspended); +/*--------------------------------------------------------------------------*/ +typedef NTSTATUS(NTAPI *ZwResumeThread_t)(IN HANDLE ThreadHandle, + OUT PULONG SuspendCount OPTIONAL); +typedef NTSTATUS(NTAPI *ZwClose_t)(IN HANDLE ObjectHandle); +typedef NTSTATUS(NTAPI *ZwQueryInformationThread_t)( + IN HANDLE ThreadHandle, IN THREAD_INFORMATION_CLASS ThreadInformationClass, + OUT PVOID ThreadInformation, IN ULONG ThreadInformationLength, + OUT PULONG ReturnLength OPTIONAL); +/*--------------------------------------------------------------------------*/ +static ZwCreateProcess_t ZwCreateProcess = NULL; +static ZwQuerySystemInformation_t ZwQuerySystemInformation = NULL; +static ZwQueryVirtualMemory_t ZwQueryVirtualMemory = NULL; +static ZwCreateThread_t ZwCreateThread = NULL; +static ZwGetContextThread_t ZwGetContextThread = NULL; +static ZwResumeThread_t ZwResumeThread = NULL; +static ZwClose_t ZwClose = NULL; +static ZwQueryInformationThread_t ZwQueryInformationThread = NULL; +static ZwWriteVirtualMemory_t ZwWriteVirtualMemory = NULL; +/*--------------------------------------------------------------------------*/ +#define NtCurrentProcess() ((HANDLE)-1) +#define NtCurrentThread() ((HANDLE)-2) +/* we use really the Nt versions - so the following is just for completeness */ +#define ZwCurrentProcess() NtCurrentProcess() +#define ZwCurrentThread() NtCurrentThread() +#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) +#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) +/*--------------------------------------------------------------------------*/ +/* setjmp env for the jump back into the fork() function */ +static jmp_buf jenv; +/*--------------------------------------------------------------------------*/ +/* entry point for our child thread process - just longjmp into fork */ +static int child_entry(void) +{ + longjmp(jenv, 1); + return 0; +} +/*--------------------------------------------------------------------------*/ +static BOOL haveLoadedFunctionsForFork(void) +{ + HMODULE ntdll = GetModuleHandle("ntdll"); + if (ntdll == NULL) + { + return FALSE; + } + + if (ZwCreateProcess && ZwQuerySystemInformation && ZwQueryVirtualMemory && + ZwCreateThread && ZwGetContextThread && ZwResumeThread && + ZwQueryInformationThread && ZwWriteVirtualMemory && ZwClose) + { + return TRUE; + } + + ZwCreateProcess = + (ZwCreateProcess_t)GetProcAddress(ntdll, "ZwCreateProcess"); + ZwQuerySystemInformation = (ZwQuerySystemInformation_t)GetProcAddress( + ntdll, "ZwQuerySystemInformation"); + ZwQueryVirtualMemory = + (ZwQueryVirtualMemory_t)GetProcAddress(ntdll, "ZwQueryVirtualMemory"); + ZwCreateThread = (ZwCreateThread_t)GetProcAddress(ntdll, "ZwCreateThread"); + ZwGetContextThread = + (ZwGetContextThread_t)GetProcAddress(ntdll, "ZwGetContextThread"); + ZwResumeThread = (ZwResumeThread_t)GetProcAddress(ntdll, "ZwResumeThread"); + ZwQueryInformationThread = (ZwQueryInformationThread_t)GetProcAddress( + ntdll, "ZwQueryInformationThread"); + ZwWriteVirtualMemory = + (ZwWriteVirtualMemory_t)GetProcAddress(ntdll, "ZwWriteVirtualMemory"); + ZwClose = (ZwClose_t)GetProcAddress(ntdll, "ZwClose"); + + if (ZwCreateProcess && ZwQuerySystemInformation && ZwQueryVirtualMemory && + ZwCreateThread && ZwGetContextThread && ZwResumeThread && + ZwQueryInformationThread && ZwWriteVirtualMemory && ZwClose) + { + return TRUE; + } + else + { + ZwCreateProcess = NULL; + ZwQuerySystemInformation = NULL; + ZwQueryVirtualMemory = NULL; + ZwCreateThread = NULL; + ZwGetContextThread = NULL; + ZwResumeThread = NULL; + ZwQueryInformationThread = NULL; + ZwWriteVirtualMemory = NULL; + ZwClose = NULL; + } + return FALSE; +} +/*--------------------------------------------------------------------------*/ +int fork(void) +{ + HANDLE hProcess = 0, hThread = 0; + OBJECT_ATTRIBUTES oa = {sizeof(oa)}; + MEMORY_BASIC_INFORMATION mbi; + CLIENT_ID cid; + USER_STACK stack; + PNT_TIB tib; + THREAD_BASIC_INFORMATION tbi; + + CONTEXT context = {CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | + CONTEXT_FLOATING_POINT}; + + if (setjmp(jenv) != 0) + { + return 0; /* return as a child */ + } + + /* check whether the entry points are initilized and get them if necessary + */ + if (!ZwCreateProcess && !haveLoadedFunctionsForFork()) + { + return -1; + } + + /* create forked process */ + ZwCreateProcess(&hProcess, PROCESS_ALL_ACCESS, &oa, NtCurrentProcess(), + TRUE, 0, 0, 0); + + /* set the Eip for the child process to our child function */ + ZwGetContextThread(NtCurrentThread(), &context); + + /* In x64 the Eip and Esp are not present, their x64 counterparts are Rip + and Rsp respectively. + */ +#if _WIN64 + context.Rip = (ULONG)child_entry; +#else + context.Eip = (ULONG)child_entry; +#endif + +#if _WIN64 + ZwQueryVirtualMemory(NtCurrentProcess(), (PVOID)context.Rsp, + MemoryBasicInformation, &mbi, sizeof mbi, 0); +#else + ZwQueryVirtualMemory(NtCurrentProcess(), (PVOID)context.Esp, + MemoryBasicInformation, &mbi, sizeof mbi, 0); +#endif + + stack.FixedStackBase = 0; + stack.FixedStackLimit = 0; + stack.ExpandableStackBase = (PCHAR)mbi.BaseAddress + mbi.RegionSize; + stack.ExpandableStackLimit = mbi.BaseAddress; + stack.ExpandableStackBottom = mbi.AllocationBase; + + /* create thread using the modified context and stack */ + ZwCreateThread(&hThread, THREAD_ALL_ACCESS, &oa, hProcess, &cid, &context, + &stack, TRUE); + + /* copy exception table */ + ZwQueryInformationThread(NtCurrentThread(), ThreadMemoryPriority, &tbi, + sizeof tbi, 0); + tib = (PNT_TIB)tbi.TebBaseAddress; + ZwQueryInformationThread(hThread, ThreadMemoryPriority, &tbi, sizeof tbi, + 0); + ZwWriteVirtualMemory(hProcess, tbi.TebBaseAddress, &tib->ExceptionList, + sizeof tib->ExceptionList, 0); + + /* start (resume really) the child */ + ZwResumeThread(hThread, 0); + + /* clean up */ + ZwClose(hThread); + ZwClose(hProcess); + + /* exit with child's pid */ + return (int)cid.UniqueProcess; +} + +#endif /* __FORK_H__ */ +/*--------------------------------------------------------------------------*/ diff --git a/client_server/remote_command_exec_udp_client.c b/client_server/remote_command_exec_udp_client.c new file mode 100644 index 0000000000..6669919f5a --- /dev/null +++ b/client_server/remote_command_exec_udp_client.c @@ -0,0 +1,156 @@ +/** + * @file + * @author [NVombat](https://github.com/NVombat) + * @brief Client-side implementation of [Remote Command + * Execution Using + * UDP](https://www.imperva.com/learn/ddos/udp-user-datagram-protocol/) + * @see remote_command_exec_udp_server.c + * + * @details + * The algorithm is based on the simple UDP client and server model. It + * runs an infinite loop which takes user input and sends it to the server + * for execution. The server receives the commands and executes them + * until the user exits the loop. In this way, Remote Command Execution + * using UDP is shown using the server-client model & socket programming + */ + +#ifdef _WIN32 +#define bzero(b, len) \ + (memset((b), '\0', (len)), (void)0) /**< BSD name not in windows */ +#define close _close +#include +#include +#include /// For the type in_addr_t and in_port_t +#else +#include /// For the type in_addr_t and in_port_t +#include /// For structures returned by the network database library - formatted internet addresses and port numbers +#include /// For in_addr and sockaddr_in structures +#include /// For macro definitions related to the creation of sockets +#include /// For definitions to allow for the porting of BSD programs +#include +#endif +#include /// To indicate what went wrong if an error occurs +#include /// For specific bit size values of variables +#include /// Variable types, several macros, and various functions for performing input and output +#include /// Variable types, several macros, and various functions for performing general functions +#include /// Various functions for manipulating arrays of characters + +#define PORT 10000 /// Define port over which communication will take place + +/** + * @brief Utility function used to print an error message to `stderr`. + * It prints `str` and an implementation-defined error + * message corresponding to the global variable `errno`. + * @returns void + */ +void error() +{ + perror("Socket Creation Failed"); + exit(EXIT_FAILURE); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + /** Variable Declarations */ + uint32_t + sockfd; ///< socket descriptors - Like file handles but for sockets + char send_msg[1024], + recv_msg[1024]; ///< character arrays to read and store string data + /// for communication + + struct sockaddr_in + server_addr; ///< basic structures for all syscalls and functions that + /// deal with internet addresses. Structures for handling + /// internet addresses + socklen_t serverLength = sizeof(server_addr); ///< length of socket + + /** + * The UDP socket is created using the socket function. + * + * AF_INET (Family) - it is an address family that is used to designate the + * type of addresses that your socket can communicate with + * + * SOCK_DGRAM (Type) - Indicates UDP Connection - UDP does not require the + * source and destination to establish a three-way handshake before + * transmission takes place. Additionally, there is no need for an + * end-to-end connection + * + * 0 (Protocol) - Specifies a particular protocol to be used with the + * socket. Specifying a protocol of 0 causes socket() to use an unspecified + * default protocol appropriate for the requested socket type. + */ + if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + error(); + } + + /** + * Server Address Information + * + * The bzero() function erases the data in the n bytes of the memory + * starting at the location pointed to, by writing zeros (bytes + * containing '\0') to that area. + * + * We bind the server_addr to the internet address and port number thus + * giving our socket an identity with an address and port where it can + * listen for connections + * + * htons - The htons() function translates a short integer from host byte + * order to network byte order + * + * htonl - The htonl() function translates a long integer from host byte + * order to network byte order + * + * These functions are necessary so that the binding of address and port + * takes place with data in the correct format + */ + bzero(&server_addr, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(PORT); + server_addr.sin_addr.s_addr = htonl(INADDR_ANY); + + printf("Client is running...\n"); + + /** + * Connects the client to the server address using the socket descriptor + * This enables the two to communicate and exchange data + */ + connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); + + printf("Client is Connected Successfully...\n"); + + /** + * Communication between client and server + * + * The client sends data to the server after taking the input + * from the user + * + * The client then receives a response from the server when the + * command has been executed + * + * The server and client can communicate indefinitely till one of them + * exits the connection + * + * The client sends the server a command which it executes thus showing + * remote command execution using UDP + */ + while (1) + { + printf("\nEnter Command To Be Executed Remotely: \n"); + fgets(send_msg, sizeof(send_msg), stdin); + sendto(sockfd, send_msg, sizeof(send_msg), 0, + (struct sockaddr *)&server_addr, serverLength); + recvfrom(sockfd, recv_msg, sizeof(recv_msg), 0, + (struct sockaddr *)&server_addr, &serverLength); + printf("Server Reply: %s\n", recv_msg); + } + + /// Close Socket + close(sockfd); + printf("Client is offline...\n"); + return 0; +} diff --git a/client_server/remote_command_exec_udp_server.c b/client_server/remote_command_exec_udp_server.c new file mode 100644 index 0000000000..67d623904e --- /dev/null +++ b/client_server/remote_command_exec_udp_server.c @@ -0,0 +1,166 @@ +/** + * @file + * @author [NVombat](https://github.com/NVombat) + * @brief Server-side implementation of [Remote Command + * Execution Using + * UDP](https://www.imperva.com/learn/ddos/udp-user-datagram-protocol/) + * @see remote_command_exec_udp_server.c + * + * @details + * The algorithm is based on the simple UDP client and server model. It + * runs an infinite loop which takes user input and sends it to the server + * for execution. The server receives the commands and executes them + * until the user exits the loop. In this way, Remote Command Execution + * using UDP is shown using the server-client model & socket programming + */ + +#ifdef _WIN32 +#define bzero(b, len) \ + (memset((b), '\0', (len)), (void)0) /**< BSD name not in windows */ +#define close _close +#include +#include +#include /// For the type in_addr_t and in_port_t +#else +#include /// For the type in_addr_t and in_port_t +#include /// For structures returned by the network database library - formatted internet addresses and port numbers +#include /// For in_addr and sockaddr_in structures +#include /// For macro definitions related to the creation of sockets +#include /// For definitions to allow for the porting of BSD programs +#include +#endif +#include /// To indicate what went wrong if an error occurs +#include /// For specific bit size values of variables +#include /// Variable types, several macros, and various functions for performing input and output +#include /// Variable types, several macros, and various functions for performing general functions +#include /// Various functions for manipulating arrays of characters + +#define PORT 10000 /// Define port over which communication will take place + +/** + * @brief Utility function used to print an error message to `stderr`. + * It prints `str` and an implementation-defined error + * message corresponding to the global variable `errno`. + * @returns void + */ +void error() +{ + perror("Socket Creation Failed"); + exit(EXIT_FAILURE); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + /** Variable Declarations */ + uint32_t + sockfd; ///< socket descriptors - Like file handles but for sockets + char recv_msg[1024], + success_message[] = + "Command Executed Successfully!\n"; ///< character arrays to read + /// and store string data + /// for communication & Success + /// message + + struct sockaddr_in server_addr, + client_addr; ///< basic structures for all syscalls and functions that + /// deal with internet addresses. Structures for handling + /// internet addresses + socklen_t clientLength = sizeof(client_addr); /// size of address + + /** + * The UDP socket is created using the socket function. + * + * AF_INET (Family) - it is an address family that is used to designate the + * type of addresses that your socket can communicate with + * + * SOCK_DGRAM (Type) - Indicates UDP Connection - UDP does not require the + * source and destination to establish a three-way handshake before + * transmission takes place. Additionally, there is no need for an + * end-to-end connection + * + * 0 (Protocol) - Specifies a particular protocol to be used with the + * socket. Specifying a protocol of 0 causes socket() to use an unspecified + * default protocol appropriate for the requested socket type. + */ + if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + error(); + } + + /** + * Server Address Information + * + * The bzero() function erases the data in the n bytes of the memory + * starting at the location pointed to, by writing zeros (bytes + * containing '\0') to that area. + * + * We bind the server_addr to the internet address and port number thus + * giving our socket an identity with an address and port where it can + * listen for connections + * + * htons - The htons() function translates a short integer from host byte + * order to network byte order + * + * htonl - The htonl() function translates a long integer from host byte + * order to network byte order + * + * These functions are necessary so that the binding of address and port + * takes place with data in the correct format + */ + bzero(&server_addr, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(PORT); + server_addr.sin_addr.s_addr = htonl(INADDR_ANY); + + /** + * This binds the socket descriptor to the server thus enabling the server + * to listen for connections and communicate with other clients + */ + if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) + { + error(); /// If binding is unsuccessful + } + + printf("Server is Connected Successfully...\n"); + + /** + * Communication between client and server + * + * The bzero() function erases the data in the n bytes of the memory + * starting at the location pointed to, by writing zeros (bytes + * containing '\0') to that area. The variables are emptied and then + * ready for use + * + * The server receives data from the client which is a command. It then + * executes the command. + * + * The client then receives a response from the server when the + * command has been executed + * + * The server and client can communicate indefinitely till one of them + * exits the connection + * + * The client sends the server a command which it executes thus showing + * remote command execution using UDP + */ + while (1) + { + bzero(recv_msg, sizeof(recv_msg)); + recvfrom(sockfd, recv_msg, sizeof(recv_msg), 0, + (struct sockaddr *)&client_addr, &clientLength); + printf("Command Output: \n"); + system(recv_msg); + printf("Command Executed\n"); + sendto(sockfd, success_message, sizeof(success_message), 0, + (struct sockaddr *)&client_addr, clientLength); + } + + /// Close socket + close(sockfd); + printf("Server is offline...\n"); + return 0; +} diff --git a/client_server/server.c b/client_server/server.c new file mode 100644 index 0000000000..e01af32862 --- /dev/null +++ b/client_server/server.c @@ -0,0 +1,158 @@ +/** + * @file + * @author [Nairit11](https://github.com/Nairit11) + * @author [Krishna Vedala](https://github.com/kvedala) + * @brief Server side implementation of Server-Client system. + * @see client_server/client.c + */ +#include +#include +#include + +// #ifdef HAS_UNISTD +// #include +// #endif + +#ifdef _WIN32 +#define _WINSOCK_DEPRECATED_NO_WARNINGS // will make the code invalid for next + // MSVC compiler versions +#include +#define bzero(b, len) \ + (memset((b), '\0', (len)), (void)0) /**< BSD name not in windows */ +#define read(a, b, c) recv(a, b, c, 0) /**< map BSD name to Winsock */ +#define write(a, b, c) send(a, b, c, 0) /**< map BSD name to Winsock */ +#define close closesocket /**< map BSD name to Winsock */ +#else +// if not windows platform +#include +#include +#include +#include +#endif + +#define MAX 80 /**< max. characters per message */ +#define PORT 8080 /**< port number to connect to */ +#define SA struct sockaddr /**< shortname for sockaddr */ + +#ifdef _WIN32 +/** Cleanup function will be automatically called on program exit */ +void cleanup() { WSACleanup(); } +#endif + +/** + * Continuous loop to send and receive over the socket. + * Exits when "exit" is sent from commandline. + * @param sockfd socket handle number + */ +void func(int sockfd) +{ + char buff[MAX]; + int n; + // infinite loop for chat + for (;;) + { + bzero(buff, MAX); + + // read the message from client and copy it in buffer + read(sockfd, buff, sizeof(buff)); + // print buffer which contains the client contents + printf("From client: %s\t To client : ", buff); + bzero(buff, MAX); + n = 0; + // copy server message in the buffer + while ((buff[n++] = getchar()) != '\n') + { + ; + } + + // and send that buffer to client + write(sockfd, buff, sizeof(buff)); + + // if msg contains "Exit" then server exit and chat ended. + if (strncmp("exit", buff, 4) == 0) + { + printf("Server Exit...\n"); + break; + } + } +} + +/** Driver code */ +int main() +{ +#ifdef _WIN32 + // when using winsock2.h, startup required + WSADATA wsData; + if (WSAStartup(MAKEWORD(2, 2), &wsData) != 0) + { + perror("WSA Startup error: \n"); + return 0; + } + + atexit(cleanup); // register at-exit function +#endif + + int sockfd, connfd; + unsigned int len; + struct sockaddr_in servaddr, cli; + + // socket create and verification + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd == -1) + { + perror("socket creation failed...\n"); + exit(0); + } + else + { + printf("Socket successfully created..\n"); + } + bzero(&servaddr, sizeof(servaddr)); + + // assign IP, PORT + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + servaddr.sin_port = htons(PORT); + + // Binding newly created socket to given IP and verification + if ((bind(sockfd, (SA *)&servaddr, sizeof(servaddr))) != 0) + { + perror("socket bind failed...\n"); + exit(0); + } + else + { + printf("Socket successfully binded..\n"); + } + + // Now server is ready to listen and verification + if ((listen(sockfd, 5)) != 0) + { + perror("Listen failed...\n"); + exit(0); + } + else + { + printf("Server listening..\n"); + } + len = sizeof(cli); + + // Accept the data packet from client and verification + connfd = accept(sockfd, (SA *)&cli, &len); + if (connfd < 0) + { + perror("server acccept failed...\n"); + exit(0); + } + else + { + printf("server acccept the client...\n"); + } + + // Function for chatting between client and server + func(connfd); + + // After chatting close the socket + close(sockfd); + return 0; +} diff --git a/client_server/tcp_full_duplex_client.c b/client_server/tcp_full_duplex_client.c new file mode 100644 index 0000000000..12836c598e --- /dev/null +++ b/client_server/tcp_full_duplex_client.c @@ -0,0 +1,187 @@ +/** + * @file + * @author [NVombat](https://github.com/NVombat) + * @brief Client-side implementation of [TCP Full Duplex + * Communication](http://www.tcpipguide.com/free/t_SimplexFullDuplexandHalfDuplexOperation.htm) + * @see tcp_full_duplex_server.c + * + * @details + * The algorithm is based on the simple TCP client and server model. However, + * instead of the server only sending and the client only receiving data, + * The server and client can both send and receive data simultaneously. This is + * implemented by using the `fork` function call so that in the server the child + * process can receive data and parent process can send data, and in the client + * the child process can send data and the parent process can receive data. It + * runs an infinite loop and can send and receive messages indefinitely until + * the user exits the loop. In this way, the Full Duplex Form of communication + * can be represented using the TCP server-client model & socket programming + */ + +#ifdef _WIN32 +#define bzero(b, len) \ + (memset((b), '\0', (len)), (void)0) /**< BSD name not in windows */ +#define pid_t int +#define close _close +#include +#include +#include +#include +#include "fork.h" +#define sleep(a) Sleep(a * 1000) +#else +#include /// For the type in_addr_t and in_port_t +#include /// For structures returned by the network database library - formatted internet addresses and port numbers +#include /// For in_addr and sockaddr_in structures +#include /// For macro definitions related to the creation of sockets +#include /// For definitions to allow for the porting of BSD programs +#include +#endif +#include /// For specific bit size values of variables +#include /// Variable types, several macros, and various functions for performing input and output +#include /// Variable types, several macros, and various functions for performing general functions +#include /// Various functions for manipulating arrays of characters + +#define PORT 10000 /// Define port over which communication will take place + +/** + * @brief Utility function used to print an error message to `stderr`. + * It prints `str` and an implementation-defined error + * message corresponding to the global variable `errno`. + * @returns void + */ +void error() +{ + perror("Socket Creation Failed"); + exit(EXIT_FAILURE); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + /** Variable Declarations */ + uint32_t + sockfd; ///< socket descriptors - Like file handles but for sockets + char sendbuff[1024], + recvbuff[1024]; ///< character arrays to read and store string data + /// for communication + + struct sockaddr_in + server_addr; ///< basic structures for all syscalls and functions that + /// deal with internet addresses. Structures for handling + /// internet addresses + + /** + * The TCP socket is created using the socket function. + * + * AF_INET (Family) - it is an address family that is used to designate the + * type of addresses that your socket can communicate with + * + * SOCK_STREAM (Type) - Indicates TCP Connection - A stream socket provides + * for the bidirectional, reliable, sequenced, and unduplicated flow of data + * without record boundaries. Aside from the bidirectionality of data flow, + * a pair of connected stream sockets provides an interface nearly identical + * to pipes. + * + * 0 (Protocol) - Specifies a particular protocol to be used with the + * socket. Specifying a protocol of 0 causes socket() to use an unspecified + * default protocol appropriate for the requested socket type. + */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + error(); + } + + /** + * Server Address Information + * + * The bzero() function erases the data in the n bytes of the memory + * starting at the location pointed to, by writing zeros (bytes + * containing '\0') to that area. + * + * We bind the server_addr to the internet address and port number thus + * giving our socket an identity with an address and port where it can + * listen for connections + * + * htons - The htons() function translates a short integer from host byte + * order to network byte order + * + * htonl - The htonl() function translates a long integer from host byte + * order to network byte order + * + * These functions are necessary so that the binding of address and port + * takes place with data in the correct format + */ + bzero(&server_addr, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(PORT); + server_addr.sin_addr.s_addr = htonl(INADDR_ANY); + + printf("Client is running...\n"); + + /** + * Connects the client to the server address using the socket descriptor + * This enables the two to communicate and exchange data + */ + connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); + + printf("Client is connected...\n"); + + /** + * Communication between client and server + * + * The bzero() function erases the data in the n bytes of the memory + * starting at the location pointed to, by writing zeros (bytes + * containing '\0') to that area. The variables are emptied and then + * ready for use + * + * The fork function call is used to create a child and parent process + * which run and execute code simultaneously + * + * The child process is used to send data and after doing so + * sleeps for 5 seconds to wait for the parent to receive data + * + * The parent process is used to receive data and after doing so + * sleeps for 5 seconds to wait for the child to send data + * + * The server and client can communicate indefinitely till one of them + * exits the connection + * + * Since the exchange of information between the server and client takes + * place simultaneously this represents FULL DUPLEX COMMUNICATION + */ + pid_t pid; + pid = fork(); + + if (pid == 0) /// Value of 0 is for child process + { + while (1) + { + bzero(&sendbuff, sizeof(sendbuff)); + printf("\nType message here: "); + fgets(sendbuff, 1024, stdin); + send(sockfd, sendbuff, strlen(sendbuff) + 1, 0); + printf("\nMessage sent!\n"); + sleep(5); + // break; + } + } + else /// Parent Process + { + while (1) + { + bzero(&recvbuff, sizeof(recvbuff)); + recv(sockfd, recvbuff, sizeof(recvbuff), 0); + printf("\nSERVER: %s\n", recvbuff); + sleep(5); + // break; + } + } + + /// Close Socket + close(sockfd); + printf("Client is offline...\n"); + return 0; +} diff --git a/client_server/tcp_full_duplex_server.c b/client_server/tcp_full_duplex_server.c new file mode 100644 index 0000000000..aab2ea8dfa --- /dev/null +++ b/client_server/tcp_full_duplex_server.c @@ -0,0 +1,216 @@ +/** + * @file + * @author [NVombat](https://github.com/NVombat) + * @brief Server-side implementation of [TCP Full Duplex + * Communication](http://www.tcpipguide.com/free/t_SimplexFullDuplexandHalfDuplexOperation.htm) + * @see tcp_full_duplex_client.c + * + * @details + * The algorithm is based on the simple TCP client and server model. However, + * instead of the server only sending and the client only receiving data, + * The server and client can both send and receive data simultaneously. This is + * implemented by using the `fork` function call so that in the server the child + * process can receive data and parent process can send data, and in the client + * the child process can send data and the parent process can receive data. It + * runs an infinite loop and can send and receive messages indefinitely until + * the user exits the loop. In this way, the Full Duplex Form of communication + * can be represented using the TCP server-client model & socket programming + */ + +#ifdef _WIN32 +#define bzero(b, len) \ + (memset((b), '\0', (len)), (void)0) /**< BSD name not in windows */ +#define pid_t int +#define close _close +#include +#include +#include +#include +#include "fork.h" +#define sleep(a) Sleep(a * 1000) +#else +#include /// For the type in_addr_t and in_port_t +#include /// For structures returned by the network database library - formatted internet addresses and port numbers +#include /// For in_addr and sockaddr_in structures +#include /// For macro definitions related to the creation of sockets +#include /// For definitions to allow for the porting of BSD programs +#include +#endif +#include /// For specific bit size values of variables +#include /// Variable types, several macros, and various functions for performing input and output +#include /// Variable types, several macros, and various functions for performing general functions +#include /// Various functions for manipulating arrays of characters + +#define PORT 10000 /// Define port over which communication will take place + +/** + * @brief Utility function used to print an error message to `stderr`. + * It prints `str` and an implementation-defined error + * message corresponding to the global variable `errno`. + * @returns void + */ +void error() +{ + perror("Socket Creation Failed"); + exit(EXIT_FAILURE); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + /** Variable Declarations */ + uint32_t sockfd, + conn; ///< socket descriptors - Like file handles but for sockets + char recvbuff[1024], + sendbuff[1024]; ///< character arrays to read and store string data + /// for communication + + struct sockaddr_in server_addr, + client_addr; ///< basic structures for all syscalls and functions that + /// deal with internet addresses. Structures for handling + /// internet addresses + socklen_t ClientLen; /// size of address + + /** + * The TCP socket is created using the socket function + * + * AF_INET (Family) - it is an address family that is used to designate the + * type of addresses that your socket can communicate with + * + * SOCK_STREAM (Type) - Indicates TCP Connection - A stream socket provides + * for the bidirectional, reliable, sequenced, and unduplicated flow of data + * without record boundaries. Aside from the bidirectionality of data flow, + * a pair of connected stream sockets provides an interface nearly identical + * to pipes + * + * 0 (Protocol) - Specifies a particular protocol to be used with the + * socket. Specifying a protocol of 0 causes socket() to use an unspecified + * default protocol appropriate for the requested socket type + */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + error(); ///< Error if the socket descriptor has a value lower than 0 - + /// socket wasnt created + } + + /** + * Server Address Information + * + * The bzero() function erases the data in the n bytes of the memory + * starting at the location pointed to, by writing zeros (bytes + * containing '\0') to that area + * + * We bind the server_addr to the internet address and port number thus + * giving our socket an identity with an address and port where it can + * listen for connections + * + * htons - The htons() function translates a short integer from host byte + * order to network byte order + * + * htonl - The htonl() function translates a long integer from host byte + * order to network byte order + * + * These functions are necessary so that the binding of address and port + * takes place with data in the correct format + */ + bzero(&server_addr, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(PORT); + server_addr.sin_addr.s_addr = htonl(INADDR_ANY); + + printf("Server is running...\n"); + + /** + * This binds the socket descriptor to the server thus enabling the server + * to listen for connections and communicate with other clients + */ + if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) + { + error(); /// If binding is unsuccessful + } + /** + * This is to listen for clients or connections made to the server + * + * The limit is currently at 5 but can be increased to listen for + * more connections + * + * It listens to connections through the socket descriptor + */ + listen(sockfd, 5); + + printf("Server is listening...\n"); + + /** + * When a connection is found, a socket is created and connection is + * accepted and established through the socket descriptor + */ + conn = accept(sockfd, (struct sockaddr *)NULL, NULL); + + printf("Server is connected...\n"); + + /** + * Communication between client and server + * + * The bzero() function erases the data in the n bytes of the memory + * starting at the location pointed to, by writing zeros (bytes + * containing '\0') to that area. The variables are emptied and then + * ready for use + * + * The fork function call is used to create a child and parent process + * which run and execute code simultaneously + * + * The child process is used to receive data and after doing so + * sleeps for 5 seconds to wait for the parent to send data + * + * The parent process is used to send data and after doing so + * sleeps for 5 seconds to wait for the child to receive data + * + * The server and client can communicate indefinitely till one of them + * exits the connection + * + * Since the exchange of information between the server and client takes + * place simultaneously this represents FULL DUPLEX COMMUNICATION + */ + pid_t pid; + + #ifdef _WIN32 + #ifdef FORK_WINDOWS + pid = fork(); + #endif + #else + pid = fork(); + #endif + + if (pid == 0) /// Value of 0 is for child process + { + while (1) + { + bzero(&recvbuff, sizeof(recvbuff)); + recv(conn, recvbuff, sizeof(recvbuff), 0); + printf("\nCLIENT : %s\n", recvbuff); + sleep(5); + // break; + } + } + else /// Parent process + { + while (1) + { + bzero(&sendbuff, sizeof(sendbuff)); + printf("\nType message here: "); + fgets(sendbuff, 1024, stdin); + send(conn, sendbuff, strlen(sendbuff) + 1, 0); + printf("\nMessage Sent!\n"); + sleep(5); + // break; + } + } + + /// Close socket + close(sockfd); + printf("Server is offline...\n"); + return 0; +} diff --git a/client_server/tcp_half_duplex_client.c b/client_server/tcp_half_duplex_client.c new file mode 100644 index 0000000000..0d77dedc17 --- /dev/null +++ b/client_server/tcp_half_duplex_client.c @@ -0,0 +1,162 @@ +/** + * @file + * @author [Nikhill Vombatkere](https://github.com/NVombat) + * @brief Client-side implementation of [TCP Half Duplex + * Communication](http://www.tcpipguide.com/free/t_SimplexFullDuplexandHalfDuplexOperation.htm) + * @see tcp_half_duplex_server.c + * + * @details + * The algorithm is based on the simple TCP client and server model. However, + * instead of the server only sending and the client only receiving data, + * the server and client can both send data but only one at a time. This is + * implemented by using a particular ordering of the `send()` and `recv()` + * functions. When one of the clients or servers is sending, the other can only + * receive and vice-versa. In this way, the Half Duplex Form of communication + * can be represented using the TCP server-client model & socket programming + */ + +#ifdef _WIN32 +#define bzero(b, len) \ + (memset((b), '\0', (len)), (void)0) /**< BSD name not in windows */ +#define close _close +#include +#include +#include +#else +#include /// For structures returned by the network database library - formatted internet addresses and port numbers +#include /// For macro definitions related to the creation of sockets +#include /// For definitions to allow for the porting of BSD programs +#include +#endif +// #include /// For in_addr and sockaddr_in structures +#include /// For specific bit size values of variables +#include /// Variable types, several macros, and various functions for performing input and output +#include /// Variable types, several macros, and various functions for performing general functions +#include /// Various functions for manipulating arrays of characters + +#define PORT 8100 /// Define port over which communication will take place + +/** + * @brief Utility function used to print an error message to `stderr`. + * It prints `str` and an implementation-defined error + * message corresponding to the global variable `errno`. + * @returns void + */ +void error() +{ + perror("Socket Creation Failed"); + exit(EXIT_FAILURE); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + /** Variable Declarations */ + uint32_t + sockfd; ///< socket descriptors - Like file handles but for sockets + struct sockaddr_in + server_addr; ///< basic structures for all syscalls and functions that + /// deal with internet addresses. Structures for handling + /// internet addresses + char serverResponse[10000], + clientResponse[10000]; ///< Character arrays to read and store string + /// data for communication + + /** + * The TCP socket is created using the socket function. + * + * AF_INET (Family) - it is an address family that is used to designate the + * type of addresses that your socket can communicate with + * + * SOCK_STREAM (Type) - Indicates TCP Connection - A stream socket provides + * for the bidirectional, reliable, sequenced, and unduplicated flow of data + * without record boundaries. Aside from the bidirectionality of data flow, + * a pair of connected stream sockets provides an interface nearly identical + * to pipes. + * + * 0 (Protocol) - Specifies a particular protocol to be used with the + * socket. Specifying a protocol of 0 causes socket() to use an unspecified + * default protocol appropriate for the requested socket type. + */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + error(); + } + + /** + * Server Address Information + * + * The bzero() function erases the data in the n bytes of the memory + * starting at the location pointed to, by writing zeros (bytes + * containing '\0') to that area. + * + * We bind the server_addr to the internet address and port number thus + * giving our socket an identity with an address and port where it can + * listen for connections + * + * htons - The htons() function translates a short integer from host byte + * order to network byte order + * + * htonl - The htonl() function translates a long integer from host byte + * order to network byte order + * + * These functions are necessary so that the binding of address and port + * takes place with data in the correct format + */ + bzero(&server_addr, sizeof(server_addr)); + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(PORT); + server_addr.sin_addr.s_addr = htonl(INADDR_ANY); + + printf("Client is running...\n"); + + /** + * Connects the client to the server address using the socket descriptor + * This enables the two to communicate and exchange data + */ + connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)); + + printf("Client is connected...\n"); + + /** + * Communication between client and server + * + * The bzero() function erases the data in the n bytes of the memory + * starting at the location pointed to, by writing zeros (bytes + * containing '\0') to that area. The variables are emptied and then + * ready for use + * + * First the CLIENT receives the servers message and displays it (recv()) + * + * The CLIENT is then prompted to type in a message and send it to the + * server. (send()) + * + * The server and client can communicate till one of them exits the + * connection + * + * Since the exchange of information between the server and client take + * place one at a time this represents HALF DUPLEX COMMUNICATION + */ + while (1) + { + bzero(&serverResponse, sizeof(serverResponse)); + bzero(&clientResponse, sizeof(clientResponse)); + + /// Receive Message + recv(sockfd, serverResponse, sizeof(serverResponse), 0); + printf("\nServer message: %s \n", serverResponse); + + /// Send Message + printf("\nEnter message here: "); + fgets(clientResponse, 10000, stdin); + send(sockfd, clientResponse, strlen(clientResponse) + 1, 0); + } + + /// Close Socket + close(sockfd); + printf("Client is offline...\n"); + return 0; +} diff --git a/client_server/tcp_half_duplex_server.c b/client_server/tcp_half_duplex_server.c new file mode 100644 index 0000000000..266d9896bc --- /dev/null +++ b/client_server/tcp_half_duplex_server.c @@ -0,0 +1,186 @@ +/** + * @file + * @author [NVombat](https://github.com/NVombat) + * @brief Server-side implementation of [TCP Half Duplex + * Communication](http://www.tcpipguide.com/free/t_SimplexFullDuplexandHalfDuplexOperation.htm) + * @see tcp_half_duplex_server.c + * + * @details + * The algorithm is based on the simple TCP client and server model. However, + * instead of the server only sending and the client only receiving data, + * The server and client can both send data but only one at a time. This is + * implemented by using a particular ordering of the `send()` and `recv()` + * functions. When one of the clients or servers is sending, the other can only + * receive and vice-versa. In this way, the Half Duplex Form of communication + * can be represented using the TCP server-client model & socket programming + */ + +#ifdef _WIN32 +#define bzero(b, len) \ + (memset((b), '\0', (len)), (void)0) /**< BSD name not in windows */ +#define close _close +#include +#include +#include +#else +#include /// For structures returned by the network database library - formatted internet addresses and port numbers +#include /// For macro definitions related to the creation of sockets +#include /// For definitions to allow for the porting of BSD programs +#include +#endif +// #include /// For in_addr and sockaddr_in structures +#include /// For specific bit size values of variables +#include /// Variable types, several macros, and various functions for performing input and output +#include /// Variable types, several macros, and various functions for performing general functions +#include /// Various functions for manipulating arrays of characters + +#define PORT 8100 /// Define port over which communication will take place + +/** + * @brief Utility function used to print an error message to `stderr`. + * It prints `str` and an implementation-defined error + * message corresponding to the global variable `errno`. + * @returns void + */ +void error() +{ + perror("Socket Creation Failed"); + exit(EXIT_FAILURE); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + /** Variable Declarations */ + uint32_t sockfd, + conn; ///< socket descriptors - Like file handles but for sockets + char server_msg[10000], + client_msg[10000]; ///< character arrays to read and store string data + /// for communication + struct sockaddr_in server_addr, + client_addr; ///< asic structures for all syscalls and functions that + /// deal with internet addresses. Structures for handling + /// internet addresses + + /** + * The TCP socket is created using the socket function + * + * AF_INET (Family) - it is an address family that is used to designate the + * type of addresses that your socket can communicate with + * + * SOCK_STREAM (Type) - Indicates TCP Connection - A stream socket provides + * for the bidirectional, reliable, sequenced, and unduplicated flow of data + * without record boundaries. Aside from the bidirectionality of data flow, + * a pair of connected stream sockets provides an interface nearly identical + * to pipes + * + * 0 (Protocol) - Specifies a particular protocol to be used with the + * socket. Specifying a protocol of 0 causes socket() to use an unspecified + * default protocol appropriate for the requested socket type + */ + if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + error(); ///< Error if the socket descriptor has a value lower than 0 - + /// socket wasnt created + } + + /** + * Server Address Information + * + * The bzero() function erases the data in the n bytes of the memory + * starting at the location pointed to, by writing zeros (bytes + * containing '\0') to that area + * + * We bind the server_addr to the internet address and port number thus + * giving our socket an identity with an address and port where it can + * listen for connections + * + * htons - The htons() function translates a short integer from host byte + * order to network byte order + * + * htonl - The htonl() function translates a long integer from host byte + * order to network byte order + * + * These functions are necessary so that the binding of address and port + * takes place with data in the correct format + */ + bzero(&server_addr, sizeof(server_addr)); + server_addr.sin_family = AF_INET; /// Domain/Family to be used + server_addr.sin_port = htons(PORT); /// Port to be used + server_addr.sin_addr.s_addr = htonl(INADDR_ANY); + + printf("Server is running...\n"); + + /** + * This binds the socket descriptor to the server thus enabling the server + * to listen for connections and communicate with other clients + */ + if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) + { + error(); /// If binding is unsuccessful + } + + /** + * This is to listen for clients or connections made to the server + * + * The limit is currently at 5 but can be increased to listen for + * more connections + * + * It listens to connections through the socket descriptor + */ + listen(sockfd, 5); + + printf("Server is listening...\n"); + + /** + * When a connection is found, a socket is created and connection is + * accepted and established through the socket descriptor + */ + conn = accept(sockfd, (struct sockaddr *)NULL, NULL); + + printf("Server is connected...\n"); + + /** + * Communication between client and server + * + * The bzero() function erases the data in the n bytes of the memory + * starting at the location pointed to, by writing zeros (bytes + * containing '\0') to that area. The variables are emptied and then + * ready for use + * + * First the SERVER is prompted to type a message which is read from + * stdin and then sent over the connection that was established - the socket + * - to be received by the client (send()) + * + * The SERVER then waits for the client to reply. It then receives the reply + * in the string variable and displays it (recv()) + * + * The server and client can communicate till one of them exits the + * connection + * + * Since the exchange of information between the server and client take + * place one at a time this represents HALF DUPLEX COMMUNICATION + */ + while (1) + { + bzero(&server_msg, sizeof(server_msg)); + bzero(&client_msg, sizeof(client_msg)); + + /// Send message + printf("\nEnter message here: "); + fgets(server_msg, 10000, stdin); + send(conn, server_msg, strlen(server_msg) + 1, 0); + + /// Receive Message + recv(conn, client_msg, sizeof(client_msg), 0); + printf("\nClient Message: %s\n", client_msg); + } + + /// Close socket + close(sockfd); + printf("Server is offline...\n"); + return 0; +} diff --git a/client_server/udp_client.c b/client_server/udp_client.c new file mode 100644 index 0000000000..2659e86b3a --- /dev/null +++ b/client_server/udp_client.c @@ -0,0 +1,82 @@ +/** + * @file + * @author [TheShubham99](https://github.com/TheShubham99) + * @author [Krishna Vedala](https://github.com/kvedala) + * @brief Client side implementation of UDP client-server model + * @see client_server/udp_server.c + */ +#ifdef _WIN32 // if compiling for Windows +#define _WINSOCK_DEPRECATED_NO_WARNINGS // will make the code invalid for next + // MSVC compiler versions +#include +#define close closesocket /**< map BSD name to Winsock */ +#else // if not windows platform +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include + +#define PORT 8080 /**< port number to connect to */ +#define MAXLINE 1024 /**< maximum characters per line */ + +#ifdef _WIN32 +/** Cleanup function will be automatically called on program exit */ +void cleanup() { WSACleanup(); } +#endif + +/** Driver code */ +int main() +{ +#ifdef _WIN32 + // when using winsock2.h, startup required + WSADATA wsData; + if (WSAStartup(MAKEWORD(2, 2), &wsData) != 0) + { + perror("WSA Startup error: \n"); + return 0; + } + + atexit(cleanup); // register at-exit function +#endif + + int sockfd; + char buffer[MAXLINE]; + char *hello = "Hello from client"; + struct sockaddr_in servaddr; + + // Creating socket file descriptor + if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + perror("socket creation failed"); + exit(EXIT_FAILURE); + } + + memset(&servaddr, 0, sizeof(servaddr)); + + // Filling server information + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(PORT); + servaddr.sin_addr.s_addr = INADDR_ANY; + + int n; + unsigned int len; + + sendto(sockfd, (const char *)hello, strlen(hello), 0, + (const struct sockaddr *)&servaddr, sizeof(servaddr)); + printf("Hello message sent.\n"); + + n = recvfrom(sockfd, (char *)buffer, MAXLINE, MSG_WAITALL, + (struct sockaddr *)&servaddr, &len); + buffer[n] = '\0'; + printf("Server : %s\n", buffer); + + close(sockfd); + return 0; +} diff --git a/client_server/udp_server.c b/client_server/udp_server.c new file mode 100644 index 0000000000..7dbe323be5 --- /dev/null +++ b/client_server/udp_server.c @@ -0,0 +1,89 @@ +/** + * @file + * @author [TheShubham99](https://github.com/TheShubham99) + * @author [Krishna Vedala](https://github.com/kvedala) + * @brief Server side implementation of UDP client-server model + * @see client_server/udp_client.c + */ +#ifdef _WIN32 // if compiling for Windows +#define _WINSOCK_DEPRECATED_NO_WARNINGS // will make the code invalid for next + // MSVC compiler versions +#define close closesocket /**< map BSD name to Winsock */ +#include +#else // if not windows platform +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include + +#define PORT 8080 /**< port number to connect to */ +#define MAXLINE 1024 /**< maximum characters per line */ + +#ifdef _WIN32 +/** Cleanup function will be automatically called on program exit */ +void cleanup() { WSACleanup(); } +#endif + +/** Driver code */ +int main() +{ +#ifdef _WIN32 + // when using winsock2.h, startup required + WSADATA wsData; + if (WSAStartup(MAKEWORD(2, 2), &wsData) != 0) + { + perror("WSA Startup error: \n"); + return 0; + } + + atexit(cleanup); // register at-exit function +#endif + + int sockfd; + char buffer[MAXLINE]; + char *hello = "Hello from server"; + struct sockaddr_in servaddr, cliaddr; + + // Creating socket file descriptor + if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + perror("socket creation failed"); + exit(EXIT_FAILURE); + } + + memset(&servaddr, 0, sizeof(servaddr)); + memset(&cliaddr, 0, sizeof(cliaddr)); + + // Filling server information + servaddr.sin_family = AF_INET; // IPv4 + servaddr.sin_addr.s_addr = INADDR_ANY; + servaddr.sin_port = htons(PORT); + + // Bind the socket with the server address + if (bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) + { + perror("bind failed"); + exit(EXIT_FAILURE); + } + + unsigned int len; + int n; + n = recvfrom(sockfd, (char *)buffer, MAXLINE, MSG_WAITALL, + (struct sockaddr *)&cliaddr, &len); + buffer[n] = '\0'; + printf("Client : %s\n", buffer); + sendto(sockfd, (const char *)hello, strlen(hello), 0, + (const struct sockaddr *)&cliaddr, len); + printf("Hello message sent.\n"); + + close(sockfd); + + return 0; +} diff --git a/computer_oriented_statistical_methods/Gauss_Elimination.c b/computer_oriented_statistical_methods/Gauss_Elimination.c deleted file mode 100644 index e35fa7baca..0000000000 --- a/computer_oriented_statistical_methods/Gauss_Elimination.c +++ /dev/null @@ -1,100 +0,0 @@ -#include -#include -void display(float a[20][20],int n) -{ - int i,j; - for(i=0;i>>\n",i+1); - for(j=0;j<=n;j++) - { - printf("r%d%d : ",i,j); - scanf("%f",&m[i][j]); - } - printf("\n"); - } - printf(":::::::::::: Current Matrix ::::::::::::\n\n"); - display(m,n); - - for(i=0;i>>>>>>>>>>>>>>>>>>>>>>>-------- %d\n",i+1); - m[20][20]=interchange(m,i,n); - display(m,n); - printf("\n_______________________________________\n"); - m[20][20]=eliminate(m,i,n); - display(m,n); - } - printf("\n\n Values are : \n"); - for(i=n-1;i>=0;i--) - { - l=n-1; - mul=0; - for(j=0;j -#include -#include -void main() -{ - int a[10],n,i,j,temp,sum=0; - float mean; - clrscr(); - printf("Enter no. for Random Numbers :"); - scanf("%d",&n); - for(i=0;i -//#include -#include - -void main() -{ - int a[10],n,i,j,temp; - float mean,median; - clrscr(); - printf("Enter no. for Random Numbers :"); - scanf("%d",&n); - for(i=0;i -#include -#include -void main() -{ - float a,b,c,a1,a2,a3,b1,b2,b3,c1,c2,c3,d1,d2,d3,x1,x2,x3; - clrscr(); - printf("Enter values of eq1:"); - scanf("%f%f%f%f",&a1,&a2,&a3,&d1); - printf("Enter values of eq2:"); - scanf("%f%f%f%f",&b1,&b2,&b3,&d2); - printf("Enter values of eq3:"); - scanf("%f%f%f%f",&c1,&c2,&c3,&d3); - x1=x2=x3=0.0; - do - { - a=x1; - b=x2; - c=x3; - x1=(1/a1)*(d1-(a2*x2)-(a3*x3)); - x2=(1/b2)*(d2-(b1*x1)-(b3*x3)); - x3=(1/c3)*(d3-(c1*x1)-(c2*x2)); - }while(fabs(x1-a)>0.0001&&fabs(x2-b)>0.0001&&fabs(x3-c)>0.0001); - printf("x1=%f\nx2=%f\nx3=%f",x1,x2,x3); - getch(); -} \ No newline at end of file diff --git a/computer_oriented_statistical_methods/lagrange_theorem.C b/computer_oriented_statistical_methods/lagrange_theorem.C deleted file mode 100644 index 1b4694bbc5..0000000000 --- a/computer_oriented_statistical_methods/lagrange_theorem.C +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include -#include -#include -void main() -{ - float x[20],y[20],a,sum,p; - int n,i,j; - clrscr(); - printf("Enter the no of entry to insert->"); - scanf("%d",&n); - - for(i=0;i",i); - scanf("%f",&x[i]); - printf("enter the value of y%d->",i); - scanf("%f",&y[i]); - } - printf("\n X \t\t Y \n"); - printf("----------------------------\n"); - for(i=0;i%f",sum); - getch(); - -}} \ No newline at end of file diff --git a/computer_oriented_statistical_methods/simpson's 1-3rd rule.c b/computer_oriented_statistical_methods/simpson's 1-3rd rule.c deleted file mode 100644 index fe083b89ce..0000000000 --- a/computer_oriented_statistical_methods/simpson's 1-3rd rule.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include - -float f(float x) -{ - return 1.0+x*x*x; //This is the expresion of the function to integrate? -} - -void main() -{ - int i,n; - float a,b,h,x,s2,s3,sum,integral; - - printf("enter the lower limit of the integration:"); - scanf("%f",&a); - printf("enter the upper limit of the integration:"); - scanf("%f",&b); - printf("enter the number of intervals:"); - scanf("%d",&n); - - h=(b-a)/n; - sum=f(a)+f(b); - s2=s3=0.0; - - for(i=1;i -#include -#include - -int main() { - - int *ARRAY=NULL,ARRAY_LENGTH,i,TEMPORARY_ELEMENT,isSorted=0; - float MEAN=0,VARIANCE=0,STAND; - - - printf("Enter no. for Random Numbers :"); - scanf("%d",&ARRAY_LENGTH); - ARRAY=(int *)realloc(ARRAY,ARRAY_LENGTH*(sizeof(int))); //We allocate the dedicated memory - for(i=0;iARRAY[i+1]){ // if the two elements aren't sorted - isSorted=0; //it means that the array is not sorted - TEMPORARY_ELEMENT=ARRAY[i]; //and we switch these elements using TEMPORARY_ELEMENT - ARRAY[i]=ARRAY[i+1]; - ARRAY[i+1]=TEMPORARY_ELEMENT; - } - } - } - for(i=0;i +#include /// for IO operations +#include /// for assert +#include /// for pow +#include /// for uint64_t -int main() { +/** + * @brief Converts the given binary number + * to its equivalent decimal number/value. + * @param number The binary number to be converted + * @returns The decimal equivalent of the binary number +*/ +int convert_to_decimal(uint64_t number) { + int decimal_number = 0, i = 0; + + while (number > 0) { + decimal_number += (number % 10) * pow(2, i); + number = number / 10; + i++; + } - int remainder, number = 0, decimal_number = 0, temp = 1; - printf("/n Enter any binary number= "); - scanf("%d", &number); + return decimal_number; +} - // Iterate over the number until the end. - while(number > 0) { - - remainder = number % 10; - number = number / 10; - decimal_number += remainder * temp; - temp = temp*2; //used as power of 2 - - } +/** + * @brief Self-test implementations + * @returns void +*/ +static void tests() { + assert(convert_to_decimal(111) == 7); + assert(convert_to_decimal(101) == 5); + assert(convert_to_decimal(1010) == 10); + assert(convert_to_decimal(1101) == 13); + assert(convert_to_decimal(100001) == 33); + assert(convert_to_decimal(10101001) == 169); + assert(convert_to_decimal(111010) == 58); + assert(convert_to_decimal(100000000) == 256); + assert(convert_to_decimal(10000000000) == 1024); + assert(convert_to_decimal(101110111) == 375); - printf("%d\n", decimal_number); + printf("All tests have successfully passed!\n"); +} + +/** + * @brief Main function + * @returns 0 on exit +*/ +int main() +{ + tests(); // run self-test implementations + return 0; } diff --git a/conversions/binary_to_hexa.c b/conversions/binary_to_hexadecimal.c similarity index 71% rename from conversions/binary_to_hexa.c rename to conversions/binary_to_hexadecimal.c index 44d8942933..4235a07b30 100644 --- a/conversions/binary_to_hexa.c +++ b/conversions/binary_to_hexadecimal.c @@ -1,12 +1,12 @@ /* - * C Program to Convert Binary to Hexadecimal + * C Program to Convert Binary to Hexadecimal */ #include - + int main() { long int binary, hexa = 0, i = 1, remainder; - + printf("Enter the binary number: "); scanf("%ld", &binary); while (binary != 0) @@ -16,6 +16,6 @@ int main() i = i * 2; binary = binary / 10; } - printf("THe Equivalent hexadecimal value: %lX", hexa); + printf("The equivalent hexadecimal value: %lX", hexa); return 0; } diff --git a/conversions/binary2octal.c b/conversions/binary_to_octal.c similarity index 55% rename from conversions/binary2octal.c rename to conversions/binary_to_octal.c index 1b85eff791..edcb04617c 100644 --- a/conversions/binary2octal.c +++ b/conversions/binary_to_octal.c @@ -1,14 +1,14 @@ // Binary number to octal number conversion -#include +#include -//Function that returns the last three digits +// Function that returns the last three digits int three_digits(int n) { - int r, d = 0, p=1; + int r, d = 0, p = 1; - for(int i=0; i<3; i++) + for (int i = 0; i < 3; i++) { - r = n%10; + r = n % 10; d += r * p; p *= 10; n /= 10; @@ -18,24 +18,26 @@ int three_digits(int n) int main(void) { - int binary_num, d=0, base=1, remainder, td, res=0, ord=1; + int binary_num, d = 0, base = 1, remainder, td, res = 0, ord = 1; printf("Enter the binary no: "); scanf("%d", &binary_num); - while(binary_num > 0) + while (binary_num > 0) { - if(binary_num > 111) //Checking if binary number is greater than three digits + if (binary_num > + 111) // Checking if binary number is greater than three digits td = three_digits(binary_num); - else td = binary_num; + else + td = binary_num; binary_num /= 1000; - d = 0, base =1; + d = 0, base = 1; // Converting the last three digits to decimal - while(td > 0) + while (td > 0) { remainder = td % 10; td /= 10; @@ -43,7 +45,7 @@ int main(void) base *= 2; } - res += d * ord; // Calculating the octal value + res += d * ord; // Calculating the octal value ord *= 10; } diff --git a/conversions/c_atoi_str_to_integer.c b/conversions/c_atoi_str_to_integer.c new file mode 100644 index 0000000000..fce10cc987 --- /dev/null +++ b/conversions/c_atoi_str_to_integer.c @@ -0,0 +1,89 @@ +/** + * \file + * \brief Recoding the original atoi function in stdlib.h + * \author [Mohammed YMIK](https://github.com/medymik)W + * The function convert a string passed to an integer + */ +#include +#include +#include +#include + +/** + * the function take a string and return an integer + * \param[out] str pointer to a char address + */ +int c_atoi(const char *str) +{ + int i; + int sign; + long value; + long prev; + + i = 0; + sign = 1; + value = 0; + + /* skipping the spaces */ + while (((str[i] <= 13 && str[i] >= 9) || str[i] == 32) && str[i] != '\0') + i++; + + /* store the sign if it is negative sign */ + if (str[i] == '-') + { + sign = -1; + i++; + } + else if (str[i] == '+') + { + sign = 1; + i++; + } + + /* converting char by char to a numeric value */ + while (str[i] >= 48 && str[i] <= 57 && str[i] != '\0') + { + prev = value; + value = value * 10 + sign * (str[i] - '0'); + + /* managing the overflow */ + if (sign == 1 && prev > value) + return (-1); + else if (sign == -1 && prev < value) + return (0); + i++; + } + return (value); +} + +/** + * test the function implementation + */ +void test_c_atoi() +{ + printf("<<<< TEST FUNCTION >>>>\n"); + assert(c_atoi("123") == atoi("123")); + assert(c_atoi("-123") == atoi("-123")); + assert(c_atoi("") == atoi("")); + assert(c_atoi("-h23") == atoi("-h23")); + assert(c_atoi(" 23") == atoi(" 23")); + assert(c_atoi("999999999") == atoi("999999999")); + printf("<<<< TEST DONE >>>>\n"); +} + +/** + * the main function take one argument of type char* + * example : ./program 123 + */ +int main(int argc, char **argv) +{ + test_c_atoi(); + + if (argc == 2) + { + printf("Your number + 5 is %d\n", c_atoi(argv[1]) + 5); + return (0); + } + printf("wrong number of parmeters\n"); + return (1); +} diff --git a/conversions/celsius_to_fahrenheit.c b/conversions/celsius_to_fahrenheit.c new file mode 100644 index 0000000000..3c1bda9e09 --- /dev/null +++ b/conversions/celsius_to_fahrenheit.c @@ -0,0 +1,74 @@ +/** + * @file + * @brief Conversion of temperature in degrees from [Celsius](https://en.wikipedia.org/wiki/Celsius) + * to [Fahrenheit](https://en.wikipedia.org/wiki/Fahrenheit). + * + * @author [Focusucof](https://github.com/Focusucof) + */ + +#include /// for assert +#include /// for IO operations + +/** + * @brief Convert celsius to Fahrenheit + * @param celsius Temperature in degrees celsius double + * @returns Double of temperature in degrees Fahrenheit + */ + double celcius_to_fahrenheit(double celsius) { + return (celsius * 9.0 / 5.0) + 32.0; + } + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // 1st test + double input = 0.0; + double expected = 32.0; + + double output = celcius_to_fahrenheit(input); + + // 1st test + printf("TEST 1\n"); + printf("Input: %f\n", input); + printf("Expected Output: %f\n", expected); + printf("Output: %f\n", output); + assert(output == expected); + printf("== TEST PASSED ==\n\n"); + + // 2nd test + input = 100.0; + expected = 212.0; + + output = celcius_to_fahrenheit(input); + + printf("TEST 2\n"); + printf("Input: %f\n", input); + printf("Expected Output: %f\n", expected); + printf("Output: %f\n", output); + assert(output == expected); + printf("== TEST PASSED ==\n\n"); + + // 3rd test + input = 22.5; + expected = 72.5; + + output = celcius_to_fahrenheit(input); + + printf("TEST 3\n"); + printf("Input: %f\n", input); + printf("Expected Output: %f\n", expected); + printf("Output: %f\n", output); + assert(output == expected); + printf("== TEST PASSED ==\n\n"); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} diff --git a/conversions/decimal_to_any_base.c b/conversions/decimal_to_any_base.c new file mode 100644 index 0000000000..80c7cead11 --- /dev/null +++ b/conversions/decimal_to_any_base.c @@ -0,0 +1,169 @@ +/** + * @file + * @author [jucollet972](https://github.com/jucollet972) + * @brief [Decimal to any-base](http://codeofthedamned.com/index.php/number-base-conversion) is a C function wich convert positive decimal + * integer to any positive ascii base with the base's alphabet given in input and return it in a dynamically allocated string(recursive way) + */ + +#include /// for IO operations +#include /// for strchr and strlen +#include /// for CPU arch's optimized int types +#include /// for boolean types +#include /// for assert +#include /// for malloc and free + +/** + * @brief Checking if alphabet is valid + * @param base alphabet inputed by user + * @return int64_t as success or not + */ +bool isbad_alphabet(const char* alphabet) { + uint64_t len = strlen(alphabet); + + /* Checking th lenght */ + if (len < 2) { + return true; + } + /* Browse the alphabet */ + for (int i = 0; i < len ; i++) { + /* Searching for duplicates */ + if (strchr(alphabet + i + 1, alphabet[i])) + return true; + } + return false; +} + +/** + * @brief Calculate the final length of the converted number + * @param nb to convert + * @param base calculated from alphabet + * @return Converted nb string length + */ +uint64_t converted_len(uint64_t nb, short base) { + /* Counting the number of characters translated to the base*/ + if (nb > base - 1) { + return (converted_len(nb/base, base) + 1); + } + return 1; +} + +/** + * @brief Convert positive decimal integer into anybase recursively + * @param nb to convert + * @param alphabet inputed by user used for base convertion + * @param base calculated from alphabet + * @param converted string filled with the convertion's result + * @return void + */ +void convertion(uint64_t nb, const char* alphabet, short base, char* converted) { + /* Recursive convertion */ + *(converted) = *(alphabet + nb%base); + if (nb > base - 1) { + convertion(nb/base, alphabet, base, --converted); + } +} + +/** + * @brief decimal_to_anybase ensure the validity of the parameters and convert any unsigned integers into any ascii positive base + * @param nb to convert + * @param base's alphabet + * @returns nb converted on success + * @returns NULL on error + */ +char* decimal_to_anybase(uint64_t nb, const char* alphabet) { + char* converted; + + /* Verify that alphabet is valid */ + if (isbad_alphabet(alphabet)) { + return NULL; + } + /* Convertion */ + uint64_t base = strlen(alphabet); + uint64_t final_len = converted_len(nb, base); + converted = malloc(sizeof(char) * (final_len + 1)); + converted[final_len] = 0; + convertion(nb, alphabet, base, converted + final_len - 1); + return converted; +} + + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() +{ + char* ret = NULL; + char* reference = NULL; + + /* min dec*/ + reference = "0"; + ret = decimal_to_anybase(0, "0123456789"); + for (int i = 0; i < strlen(reference) && i < strlen(ret); i++) { + assert(ret[i] == reference[i]); + } + if (ret != NULL) { + free(ret); + } + + /* max dec*/ + reference = "18446744073709551615"; + ret = decimal_to_anybase(18446744073709551615, "0123456789"); + for (int i = 0; i < strlen(reference) && i < strlen(ret); i++) { + assert(ret[i] == reference[i]); + } + if (ret != NULL) { + free(ret); + } + + /* negative dec*/ + reference = "18446744073709551615"; + ret = decimal_to_anybase(-1, "0123456789"); + for (int i = 0; i < strlen(reference) && i < strlen(ret); i++) { + assert(ret[i] == reference[i]); + } + if (ret != NULL) { + free(ret); + } + + /* bin */ + reference = "101010"; + ret = decimal_to_anybase(42, "01"); + for (int i = 0; i < strlen(reference) && i < strlen(ret); i++) { + assert(ret[i] == reference[i]); + } + if (ret != NULL) { + free(ret); + } + + /* octal */ + reference = "52"; + ret = decimal_to_anybase(42, "01234567"); + for (int i = 0; i < strlen(reference) && i < strlen(ret); i++) { + assert(ret[i] == reference[i]); + } + if (ret != NULL) { + free(ret); + } + + /* hexa */ + reference = "2A"; + ret = decimal_to_anybase(42, "0123456789ABCDEF"); + for (int i = 0; i < strlen(reference) && i < strlen(ret); i++) { + assert(ret[i] == reference[i]); + } + if (ret != NULL) { + free(ret); + } + printf("[+] 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/conversions/decimal _to_binary.c b/conversions/decimal_to_binary.c similarity index 87% rename from conversions/decimal _to_binary.c rename to conversions/decimal_to_binary.c index e27d18f7dc..27032b2cb6 100644 --- a/conversions/decimal _to_binary.c +++ b/conversions/decimal_to_binary.c @@ -5,7 +5,6 @@ int main() { - // input of the user int inputNumber; @@ -17,13 +16,13 @@ int main() // for the loops int j; - int i=0; + int i = 0; printf("\t\tConverter decimal --> binary\n\n"); // reads a decimal number from the user. printf("\nenter a positive integer number: "); - scanf("%d",&inputNumber); + scanf("%d", &inputNumber); // make sure the input number is a positive integer. if (inputNumber < 0) @@ -33,9 +32,8 @@ int main() } // actual processing - while(inputNumber>0) + while (inputNumber > 0) { - // computes the remainder by modulo 2 re = inputNumber % 2; @@ -44,15 +42,14 @@ int main() bits[i] = re; i++; - } printf("\n the number in binary is: "); // iterates backwards over all bits - for(j=i-1; j>=0; j--) + for (j = i - 1; j >= 0; j--) { - printf("%d",bits[j]); + printf("%d", bits[j]); } // for the case the input number is 0 @@ -63,4 +60,3 @@ int main() return 0; } - diff --git a/conversions/decimal_to_binary_recursion.c b/conversions/decimal_to_binary_recursion.c new file mode 100644 index 0000000000..f1548b9c53 --- /dev/null +++ b/conversions/decimal_to_binary_recursion.c @@ -0,0 +1,38 @@ +/** + * @file + * @brief Convert decimal to binary using recursion algorithm + */ +#include + +/** + * Decimal to binary using recursion algorithm. + * For example, if number = 5, the function returns the decimal integer 101. + * @param number positive integer number to convert + * @returns integer with digits representing binary value representation of + * number. + */ +int decimal_to_binary(unsigned int number) +{ + return number == 0 ? 0 : number % 2 + 10 * decimal_to_binary(number / 2); +} + +/** Test function */ +void test() +{ + const int sets[][2] = { + {0, 0}, {1, 1}, {2, 10}, {3, 11}, {4, 100}, {6, 110}, {7, 111}, + /* add more data sets to test */ + }; + + for (int i = 0, size = sizeof(sets) / sizeof(sets[0]); i < size; ++i) + { + assert(decimal_to_binary(sets[i][0]) == sets[i][1]); + } +} + +/** Driver Code */ +int main() +{ + test(); + return 0; +} diff --git a/conversions/decimal_to_hexa.c b/conversions/decimal_to_hexa.c index 079b818379..89de596237 100644 --- a/conversions/decimal_to_hexa.c +++ b/conversions/decimal_to_hexa.c @@ -2,45 +2,47 @@ #include void decimal2Hexadecimal(long num); - -int main(){ - - long decimalnum; - - printf("Enter decimal number: "); - scanf("%ld", &decimalnum); - - decimal2Hexadecimal(decimalnum); - -return 0; -} +int main() +{ + long decimalnum; -/********function for convert decimal number to hexadecimal number****************/ -void decimal2Hexadecimal(long num){ + printf("Enter decimal number: "); + scanf("%ld", &decimalnum); -long decimalnum=num; -long quotient, remainder; -int i, j = 0; -char hexadecimalnum[100]; + decimal2Hexadecimal(decimalnum); - quotient = decimalnum; + return 0; +} - while (quotient != 0){ +/********function for convert decimal number to hexadecimal + * number****************/ +void decimal2Hexadecimal(long num) +{ + long decimalnum = num; + long quotient, remainder; + int i, j = 0; + char hexadecimalnum[100]; + quotient = decimalnum; + + while (quotient != 0) + { remainder = quotient % 16; - if (remainder < 10) + if (remainder < 10) hexadecimalnum[j++] = 48 + remainder; - else - hexadecimalnum[j++] = 55 + remainder; + else + hexadecimalnum[j++] = 55 + remainder; - quotient = quotient / 16;} + quotient = quotient / 16; + } // print the hexadecimal number - for (i = j; i >= 0; i--){ - printf("%c", hexadecimalnum[i]);} + for (i = j; i >= 0; i--) + { + printf("%c", hexadecimalnum[i]); + } - printf("\n"); + printf("\n"); } - diff --git a/conversions/decimal_to_octal.c b/conversions/decimal_to_octal.c index 2cc0d4c041..1d720a4320 100644 --- a/conversions/decimal_to_octal.c +++ b/conversions/decimal_to_octal.c @@ -1,35 +1,35 @@ /*****Decimal to octal conversion*******************/ #include void decimal2Octal(long decimalnum); - -int main(){ +int main() +{ long decimalnum; printf("Enter the decimal number: "); - scanf("%ld", &decimalnum); - + scanf("%ld", &decimalnum); + decimal2Octal(decimalnum); -return 0; + return 0; } - -/********function for convert decimal numbers to octal numbers************/ -void decimal2Octal(long decimalnum){ - long remainder, quotient; + +/********function for convert decimal numbers to octal numbers************/ +void decimal2Octal(long decimalnum) +{ + long remainder, quotient; int octalNumber[100], i = 1, j; quotient = decimalnum; - while (quotient != 0){ - octalNumber[i++] = quotient % 8; + while (quotient != 0) + { + octalNumber[i++] = quotient % 8; quotient = quotient / 8; - } - - for (j = i - 1; j > 0; j--) + } - printf("%d", octalNumber[j]); + for (j = i - 1; j > 0; j--) printf("%d", octalNumber[j]); - printf("\n"); + printf("\n"); } diff --git a/conversions/decimal_to_octal_recursion.c b/conversions/decimal_to_octal_recursion.c new file mode 100644 index 0000000000..937ba07202 --- /dev/null +++ b/conversions/decimal_to_octal_recursion.c @@ -0,0 +1,29 @@ +// Program to convert decimal number to octal (Using Reccursion) +// This program only works for integer decimals +// Created by Aromal Anil + +#include +int decimal_to_octal(int decimal) +{ + if ((decimal < 8) && (decimal > 0)) + { + return decimal; + } + else if (decimal == 0) + { + return 0; + } + else + { + return ((decimal_to_octal(decimal / 8) * 10) + decimal % 8); + } +} +int main() +{ + int octalNumber, decimalNumber; + printf("\nEnter your decimal number : "); + scanf("%d", &decimalNumber); + octalNumber = decimal_to_octal(decimalNumber); + printf("\nThe octal of %d is : %d", decimalNumber, octalNumber); + return 0; +} diff --git a/conversions/hexadecimal_to_octal.c b/conversions/hexadecimal_to_octal.c new file mode 100644 index 0000000000..7340dcd179 --- /dev/null +++ b/conversions/hexadecimal_to_octal.c @@ -0,0 +1,133 @@ +/* C program to convert Hexadecimal to Octal number system */ + +#include + +int main() +{ +#define MAX_STR_LEN 17 + char hex[MAX_STR_LEN]; + long long octal, bin, place; + int i = 0, rem, val; + + /* Input hexadecimal number from user */ + printf("Enter any hexadecimal number: "); + fgets(hex, MAX_STR_LEN, stdin); + + octal = 0ll; + bin = 0ll; + place = 0ll; + + /* Hexadecimal to binary conversion */ + for (i = 0; hex[i] != '\0'; i++) + { + bin = bin * place; + + switch (hex[i]) + { + case '0': + bin += 0; + break; + case '1': + bin += 1; + break; + case '2': + bin += 10; + break; + case '3': + bin += 11; + break; + case '4': + bin += 100; + break; + case '5': + bin += 101; + break; + case '6': + bin += 110; + break; + case '7': + bin += 111; + break; + case '8': + bin += 1000; + break; + case '9': + bin += 1001; + break; + case 'a': + case 'A': + bin += 1010; + break; + case 'b': + case 'B': + bin += 1011; + break; + case 'c': + case 'C': + bin += 1100; + break; + case 'd': + case 'D': + bin += 1101; + break; + case 'e': + case 'E': + bin += 1110; + break; + case 'f': + case 'F': + bin += 1111; + break; + default: + printf("Invalid hexadecimal input."); + } + + place = 10000; + } + + place = 1; + + /* Binary to octal conversion */ + while (bin > 0) + { + rem = bin % 1000; + + switch (rem) + { + case 0: + val = 0; + break; + case 1: + val = 1; + break; + case 10: + val = 2; + break; + case 11: + val = 3; + break; + case 100: + val = 4; + break; + case 101: + val = 5; + break; + case 110: + val = 6; + break; + case 111: + val = 7; + break; + } + + octal = (val * place) + octal; + bin /= 1000; + + place *= 10; + } + + printf("Hexadecimal number = %s\n", hex); + printf("Octal number = %lld", octal); + + return 0; +} diff --git a/conversions/hexadecimal_to_octal2.c b/conversions/hexadecimal_to_octal2.c new file mode 100644 index 0000000000..842e8e94f7 --- /dev/null +++ b/conversions/hexadecimal_to_octal2.c @@ -0,0 +1,119 @@ +/** + * @file + * @brief Convert hexadecimal number to octal number (with decimal intermediary) + * @details + * The input is valid from 0 to 0xFFFF_FFFF_FFFF_FFFF. + * + * At first, this program converts a hex string to an unsigned long long + * decimal, and then to an octal string. + * + * When there is an invalid character in input string, this program stops + * parsing and converts the string until that character. + * + * @see hexadecimal_to_octal.c + */ + +#include /// for printf() and fgets() +#include /// for memset() + +/** + * @brief Convert a hexadecimal number to octal number. + * @param hex Hexadecimal number to convert. + * @returns A pointer to the converted octal string. + */ +const char *hex_to_oct(const char *hex) +{ +#define MAX_OCT_STR_LEN 23 /* 17_7777_7777_7777_7777_7777 */ + static char octal[MAX_OCT_STR_LEN]; + memset(octal, '\0', MAX_OCT_STR_LEN); // Initialize as NULL string + + unsigned long long decimal = 0; + int i = 0; + int len; + + if (hex == NULL) + { + // Return an empty string + return octal; + } + + /* Hexadecimal to decimal conversion */ + while (*hex != '\n' && *hex != '\0') + { + char ch = *hex; + + if (ch >= '0' && ch <= '9') + { + ch -= '0'; + } + else if (ch >= 'a' && ch <= 'f') + { + ch = ch - 'a' + 10; + } + else if (ch >= 'A' && ch <= 'F') + { + ch = ch - 'A' + 10; + } + else + { + printf("Invalid hexadecimal input: %c\n", ch); + break; + } + + decimal *= 16; + decimal += ch; + hex++; + } + + /* Decimal to octal conversion */ + if (decimal == 0) + { + octal[0] = '0'; + len = 1; + } + else + { + i = 0; + while (decimal > 0) + { + octal[i] = '0' + decimal % 8; + i++; + decimal /= 8; + } + + len = i; + } + + octal[len] = '\0'; + + /* Reverse the octal string */ + for (i = 0; i < len / 2; i++) + { + char tmp = octal[i]; + octal[i] = octal[len - i - 1]; + octal[len - i - 1] = tmp; + } + + return octal; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ +#define MAX_HEX_STR_LEN 17 /* FFFF_FFFF_FFFF_FFFF */ + char hex[MAX_HEX_STR_LEN]; + + /* Input hexadecimal number from user */ + printf("Enter any hexadecimal number: "); + fgets(hex, MAX_HEX_STR_LEN, stdin); + + const char *octal = hex_to_oct(hex); + + printf("Hexadecimal number = %s\n", hex); + printf("Octal number = %s\n", octal); + + return 0; +} diff --git a/conversions/infix_to_postfix.c b/conversions/infix_to_postfix.c new file mode 100644 index 0000000000..8404917d55 --- /dev/null +++ b/conversions/infix_to_postfix.c @@ -0,0 +1,227 @@ +/** + * @file + * @brief [Infix to + * Postfix](https://condor.depaul.edu/ichu/csc415/notes/notes9/Infix.htm) + * Expression Conversion + * @details Convert Infixed expressions to Postfix expression. + * @author [Harsh Karande](https://github.com/harshcut) + */ + +// include header files +#include /// for printf() and scanf() + +/** + * @brief a globally declared structure with an array and an variable that + * points to the topmost index of the array + */ +struct Stack +{ + char arr[10]; ///> static array of integers + int tos; ///> stores index on topmost element in stack +}; + +// function headers +void push(struct Stack *p, char ch); // pust element in stack +char pop(struct Stack *p); // pop topmost element from the stack +int isOprnd(char ch); // check if element is operand or not +int isEmpty(struct Stack s); // check if stack is empty +int getPrecedence (char op1, char op2); // check operator precedence +void convert(char infix[], + char postfix[]); // convert infix to postfix expression + +/** + * @brief main function + * @returns 0 on exit + */ +int main() +{ + char infix[20], postfix[20]; // initialize empty infix and postfix array + + printf("Enter infix expression: "); // example : A+B-C*D/E$F + scanf("%s", infix); // get values for infix array + + convert(infix, postfix); + printf("Postfix expression is %s", postfix); // output : AB+CD*EF$/- + + return 0; +} + +/** + * @brief push function + * @param *p : used as a pointer variable of stack + * @param x : char to be pushed in stack + * @returns void + */ +void push(struct Stack *p, char x) +{ + if (p->tos == 9) // check if stack has reached its max limit + { + printf("Stack Overflow!"); + return; + } + + p->tos += 1; // increment tos + p->arr[p->tos] = x; // assign char x to index of stack pointed by tos +} + +/** + * @brief pop function + * @param *p : used as a pointer variable of stack + * @returns x or \0 on exit + */ +char pop(struct Stack *p) +{ + char x; + + if (p->tos == -1) + { + printf("Stack Underflow!"); + return '\0'; + } + + x = p->arr[p->tos]; // assign the value of stack at index tos to x + p->tos -= 1; // decrement tos + + return x; +} + +/** + * @brief isOprnd function + * @param ch : this is the element from the infix array + * @returns 1 or 0 on exit + */ +int isOprnd(char ch) +{ + if ((ch >= 65 && ch <= 90) || + (ch >= 97 && ch <= 122) || // check if ch is an operator or + (ch >= 48 && ch <= 57)) // operand using ASCII values + { + return 1; // return for true result + } + else + { + return 0; // return for false result + } +} + +/** + * @brief isEmpty function + * @param s : it is the object reference of stack + * @returns 1 or 0 on exit + */ +int isEmpty(struct Stack s) +{ + if (s.tos == -1) // check if stack is empty + { + return 1; // return for true result + } + else + { + return 0; // return for false result + } +} + +/** + * @brief convert function + * @param infix[] : infix array provided by user + * @param postfix[] : empty array to be given to convert() + * @returns postfixed expresion or \0 on exit + */ +void convert(char infix[], char postfix[]) +{ + struct Stack s; // initialze object reference of stack + s.tos = -1; // initalize the tos + + int i, j = 0, pr; + char ch, temp; + + for (i = 0; infix[i] != '\0'; i++) + { + ch = infix[i]; + + if (isOprnd(ch) == 1) // check if char is operand or operator + { + postfix[j] = ch; // assign ch to postfix array with index j + j++; // incement j + } + else + { + if (ch == '(') + { + push(&s, ch); + } + else + { + if (ch == ')') + { + while ((temp = pop(&s)) != '(') + { + postfix[j] = temp; + j++; + } + } + else + { + while (isEmpty(s) == 0) // check if stack is empty + { + pr = getPrecedence (ch, + s.arr[s.tos]); // check operator precedence + + if (pr == 1) + { + break; // if ch has a greater precedence than + // s.arr[s.top] + } + + postfix[j] = pop(&s); + j++; + } + + push(&s, ch); // push ch to stack + } + } + } + } + + while (isEmpty(s) == 0) // check if stack is empty + { + postfix[j] = pop(&s); + j++; + } + + postfix[j] = '\0'; +} + +/** + * @brief getPrecedence function returns the precedence after comparing two operators passed as parameter. + * @param op1 : first operator + * @param op2 : second operator + * @returns 1 or 0 on exit + */ +int getPrecedence (char op1, char op2) +{ + if (op2 == '$') + { + return 0; + } + else if (op1 == '$') + { + return 1; + } + else if (op2 == '*' || op2 == '/' || op2 == '%') + { + return 0; + } + else if (op1 == '*' || op1 == '/' || op1 == '%') + { + return 1; + } + else if (op2 == '+' || op2 == '-') + { + return 0; + } + else + { + return 1; + } +} diff --git a/conversions/infix_to_postfix2.c b/conversions/infix_to_postfix2.c new file mode 100644 index 0000000000..e0f584003b --- /dev/null +++ b/conversions/infix_to_postfix2.c @@ -0,0 +1,164 @@ +/** + * @file + * @brief [Infix to Postfix converter](https://www.includehelp.com/c/infix-to-postfix-conversion-using-stack-with-c-program.aspx) implementation + * @details + * The input infix expression is of type string upto 24 characters. + * Supported operations- '+', '-', '/', '*', '%' + * @author [Kumar Yash](https://github.com/kumaryash18) + * @see infix_to_postfix.c + */ + +#include /// for IO operations +#include /// for strlen(), strcmp() +#include /// for isalnum() +#include /// for exit() +#include /// for uint16_t, int16_t +#include /// for assert + +/** + * @brief array implementation of stack using structure + */ +struct Stack { + char stack[10]; ///< array stack + int top; ///< stores index of the top element +}; +struct Stack st; ///< global declaration of stack st + +/** + * @brief Function to push on the stack + * @param opd character to be pushed in the stack + * @returns void + */ +void push(char opd) { + if(st.top == 9) { // overflow condition + printf("Stack overflow..."); + exit(1); + } + st.top++; + st.stack[st.top] = opd; +} + +/** + * @brief Function to pop from the stack + * @returns popped character + */ +char pop() { + char item; ///< to store the popped value to be returned + if(st.top == -1) { // underflow condition + printf("Stack underflow..."); + exit(1); + } + item = st.stack[st.top]; + st.top--; + return item; +} + +/** + * @brief Function to check whether the stack is empty or not + * @returns 1 if the stack IS empty + * @returns 0 if the stack is NOT empty + */ +uint16_t isEmpty() { + if(st.top == -1) { + return 1; + } + return 0; +} + +/** + * @brief Function to get top of the stack + * @returns top of stack + */ +char Top() { + return st.stack[st.top]; +} + +/** + * @brief Function to check priority of operators + * @param opr operator whose priority is to be checked + * @returns 0 if operator is '+' or '-' + * @returns 1 if operator is '/' or '*' or '%' + * @returns -1 otherwise + */ +int16_t priority(char opr) { + if(opr == '+' || opr == '-') { + return 0; + } + else if(opr == '/' || opr == '*' || opr == '%') { + return 1; + } + else { + return -1; + } +} + +/** + * @brief Function to convert infix expression to postfix expression + * @param inf the input infix expression + * @returns output postfix expression + */ +char *convert(char inf[]) { + static char post[25]; ///< to store the postfix expression + int i; ///< loop iterator + int j = 0; ///< keeps track of end of postfix string + for(i = 0; i < strlen(inf); i++) { + if(isalnum(inf[i])) { // if scanned element is an alphabet or number + post[j] = inf[i]; // append in postfix expression + j++; + } + else if(inf[i] == '(') { // if scanned element is opening parentheses + push(inf[i]); // push on stack. + } + else if(inf[i] == ')') { // if scanned element is closing parentheses, + while(Top() != '(') { // pop elements from stack and append in postfix expression + post[j] = pop(); // until opening parentheses becomes top. + j++; + } + pop(); // pop opening parentheses + } + else { // if scanned element is an operator + while( (!isEmpty()) && (priority(inf[i]) <= priority(Top())) ) { // pop and append until stack becomes + post[j] = pop(); // empty or priority of top operator + j++; // becomes smaller than scanned operator + } // '(' has priority -1 + push(inf[i]); // push the scanned operator + } + } + while(!isEmpty()) { // pop and append residual operators from stack + post[j] = pop(); + j++; + } + post[j] = '\0'; // end postfix string with null character + return post; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + /* check sample test case + input- "(A/(B-C)*D+E)" + expected output- "ABC-/D*E+" + */ + assert(strcmp(convert("(A/(B-C)*D+E)"), "ABC-/D*E+") == 0); /// this ensures that the algorithm works as expected + /* input- "7-(2*3+5)*(8-4/2)" + expected output- "723*5+842/-*-" + */ + assert(strcmp(convert("7-(2*3+5)*(8-4/2)"), "723*5+842/-*-") == 0); /// this ensures that the algorithm works as expected + printf("All tests have successfully passed!\n"); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + st.top = -1; /// initialize + test(); /// run self-test implementations + char inf[25]; ///< to store input infix expression + printf("Enter infix: "); + scanf("%s", inf); + printf("Postfix: %s", convert(inf)); + return 0; +} diff --git a/conversions/int_to_string.c b/conversions/int_to_string.c new file mode 100644 index 0000000000..01828ea808 --- /dev/null +++ b/conversions/int_to_string.c @@ -0,0 +1,83 @@ +/** + * @file + * @brief Convert a positive integer to string (non-standard function) + * representation. + */ +#include +#include +#include +#include +#include +#include + +/** + * Converts an integer value to a null-terminated string using the specified + * base and stores the result in the array given by str parameter. + * @param value Value to be converted to a string. + * @param dest pointer to array in memory to store the resulting null-terminated + * string. + * @param base Numerical base used to represent the value as a string, between 2 + * and 16, where 10 means decimal base, 16 hexadecimal, 8 octal, and 2 binary. + * @returns A pointer to the resulting null-terminated string, same as parameter + * str. + * @note The destination array must be pre-allocated by the calling function. + */ +char *int_to_string(uint16_t value, char *dest, int base) +{ + const char hex_table[] = {'0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + int len = 0; + do + { + dest[len++] = hex_table[value % base]; + value /= base; + } while (value != 0); + + /* reverse characters */ + for (int i = 0, limit = len / 2; i < limit; ++i) + { + char t = dest[i]; + dest[i] = dest[len - 1 - i]; + dest[len - 1 - i] = t; + } + dest[len] = '\0'; + return dest; +} + +/** Test function + * @returns `void` + */ +static void test() +{ + const int MAX_SIZE = 100; + char *str1 = (char *)calloc(sizeof(char), MAX_SIZE); + char *str2 = (char *)calloc(sizeof(char), MAX_SIZE); + + for (int i = 1; i <= 100; ++i) /* test 100 random numbers */ + { + /* Generate value from 0 to 100 */ + int value = rand() % 100; + + // assert(strcmp(itoa(value, str1, 2), int_to_string(value, str2, 2)) == + // 0); + snprintf(str1, MAX_SIZE, "%o", value); //* standard C - to octal */ + assert(strcmp(str1, int_to_string(value, str2, 8)) == 0); + snprintf(str1, MAX_SIZE, "%d", value); /* standard C - to decimal */ + assert(strcmp(str1, int_to_string(value, str2, 10)) == 0); + snprintf(str1, MAX_SIZE, "%x", value); /* standard C - to hexadecimal */ + assert(strcmp(str1, int_to_string(value, str2, 16)) == 0); + } + + free(str1); + free(str2); +} + +/** Driver Code */ +int main() +{ + /* Intializes random number generator */ + srand(time(NULL)); + test(); + return 0; +} diff --git a/conversions/octal_to_binary.c b/conversions/octal_to_binary.c new file mode 100644 index 0000000000..aa01501733 --- /dev/null +++ b/conversions/octal_to_binary.c @@ -0,0 +1,62 @@ +/** + * @brief Octal to binay conversion by scanning user input + * @details + * The octalTobinary function take the octal number as long + * return a long binary nuber after conversion + * @author [Vishnu P](https://github.com/vishnu0pothan) + */ +#include +#include + +/** + * @brief Converet octal number to binary + * @param octalnum octal value that need to convert + * @returns A binary number after conversion + */ +long octalToBinary(int octalnum) +{ + int decimalnum = 0, i = 0; + long binarynum = 0; + + /* This loop converts octal number "octalnum" to the + * decimal number "decimalnum" + */ + while (octalnum != 0) + { + decimalnum = decimalnum + (octalnum % 10) * pow(8, i); + i++; + octalnum = octalnum / 10; + } + + // i is re-initialized + i = 1; + + /* This loop converts the decimal number "decimalnum" to the binary + * number "binarynum" + */ + while (decimalnum != 0) + { + binarynum = binarynum + (long)(decimalnum % 2) * i; + decimalnum = decimalnum / 2; + i = i * 10; + } + + // Returning the binary number that we got from octal number + return binarynum; +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + int octalnum; + + printf("Enter an octal number: "); + scanf("%d", &octalnum); + + // Calling the function octaltoBinary + printf("Equivalent binary number is: %ld", octalToBinary(octalnum)); + return 0; +} diff --git a/conversions/octal_to_decimal.c b/conversions/octal_to_decimal.c new file mode 100644 index 0000000000..b363abb3db --- /dev/null +++ b/conversions/octal_to_decimal.c @@ -0,0 +1,36 @@ +#include +#include + +// Converts octal number to decimal +int convertValue(int num, int i) { return num * pow(8, i); } + +long long toDecimal(int octal_value) +{ + int decimal_value = 0, i = 0; + + while (octal_value) + { + // Extracts right-most digit and then multiplies by 8^i + decimal_value += convertValue(octal_value % 10, i++); + + // Shift right in base 10 + octal_value /= 10; + } + + return decimal_value; +} + +int main() +{ + printf("Enter octal value: "); + + int octal_value; + + scanf("%d", &octal_value); + + long long result = toDecimal(octal_value); + + printf("%d in decimal is %lld\n", octal_value, result); + + return 0; +} diff --git a/conversions/octal_to_hexadecimal.c b/conversions/octal_to_hexadecimal.c new file mode 100644 index 0000000000..6c975810e8 --- /dev/null +++ b/conversions/octal_to_hexadecimal.c @@ -0,0 +1,79 @@ +/** + * @file + * @brief Octal to hexadecimal conversion by scanning user input + * @details + * The octalToHexadecimal function take the octal number as long + * return a string hexadecimal value after conversion + * @author [Rachit Bhalla](https://github.com/rachitbhalla) + */ +#include // for assert +#include // for pow function +#include // for scanf and printf functions +#include // for malloc and free functions +#include // for strcmp function + +/** + * @brief Convert octal number to decimal number + * @param octalValue is the octal number that needs to be converted + * @returns a decimal number after conversion + */ +long octalToDecimal(long octalValue){ + long decimalValue = 0; + int i = 0; + while (octalValue) { + // Extracts right-most digit, multiplies it with 8^i, and increment i by 1 + decimalValue += (long)(octalValue % 10) * pow(8, i++); + // Shift right in base 10 + octalValue /= 10; + } + return decimalValue; +} + +/** + * @brief Convert octal number to hexadecimal number + * dynamically allocated memory needs to be freed by the calling the function free + * @param octalValue is the octal number that needs to be converted + * @returns a hexadecimal value as a string after conversion + */ +char *octalToHexadecimal(long octalValue){ + char *hexadecimalValue = malloc(256 * sizeof(char)); + sprintf(hexadecimalValue, "%lX", octalToDecimal(octalValue)); + return hexadecimalValue; +} + +/** + * @brief Test function + * @returns void + */ +static void test() { + /* test that hexadecimal value of octal number 213 is 8B */ + assert(strcmp(octalToHexadecimal(213), "8B") == 0); + + /* test that hexadecimal value of octal number 174 is 7C */ + assert(strcmp(octalToHexadecimal(174), "7C") == 0); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + // execute the tests + test(); + + // get the value of octal number as input + int octalValue; + printf("Enter an octal number: "); + scanf("%d", &octalValue); + + // call the function octalToHexadecimal and print the hexadecimal value + char *hexadecimalValue = octalToHexadecimal(octalValue); + printf("Equivalent hexadecimal number is: %s", hexadecimalValue); + + // free the memory allocated dynamically in function octalToHexadecimal + free(hexadecimalValue); + + // return 0 and exit + return 0; +} diff --git a/conversions/roman_numerals_to_decimal.c b/conversions/roman_numerals_to_decimal.c new file mode 100644 index 0000000000..7cf8c9c78c --- /dev/null +++ b/conversions/roman_numerals_to_decimal.c @@ -0,0 +1,121 @@ +/** + * @file + * @brief Conversion of [roman numerals](https://en.wikipedia.org/wiki/Roman_numerals) to decimal + * @details Roman numerals are an ancient Roman numeral system consisting of the symbols I, V, X, L, C, D, and M + * + * @author [Focusucof](https://github.com/Focusucof) + */ + +#include /// for assert +#include /// for IO operations +#include /// for strlen() + +/** + * @brief Convert roman numeral symbol to a decimal value helper function + * @param symbol Roman numeral char + * @returns Integer of decimal value for given symbol + */ +int symbol(char symbol) { + int value = 0; + switch(symbol) { + case 'I': + value = 1; + break; + case 'V': + value = 5; + break; + case 'X': + value = 10; + break; + case 'L': + value = 50; + break; + case 'C': + value = 100; + break; + case 'D': + value = 500; + break; + case 'M': + value = 1000; + break; + } + return value; +} + +/** + * @brief Converts roman numerals into a decimal number + * @param input Input roman numeral as a C-string + * @returns The converted number in decimal form + */ +int roman_to_decimal(char input[]) { + int result = 0; // result in decimal + + for(int i = 0; i < strlen(input); i++) { + if(strlen(input) > i + 1) { + if(symbol(input[i]) >= symbol(input[i + 1])) { + result += symbol(input[i]); // add value to sum + } else { + result += symbol(input[i + 1]) - symbol(input[i]); // if the current symbol is smaller than the next (ex. IV), subtract it from the next symbol + i++; // skip over an extra symbol + } + } else { + result += symbol(input[i]); // add value to sum + } + } + return result; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + // 1st test + char input[] = "MCMIV"; + int expected = 1904; + + int output = roman_to_decimal(input); + + printf("TEST 1\n"); + printf("Input: %s\n", input); + printf("Expected Output: %d\n", expected); + printf("Output: %d\n", output); + assert(output == expected); + printf("== TEST PASSED ==\n\n"); + + // 2nd test + char input2[] = "MMMDCCXXIV"; + expected = 3724; + + output = roman_to_decimal(input2); + + printf("TEST 2\n"); + printf("Input: %s\n", input2); + printf("Expected Output: %d\n", expected); + printf("Output: %d\n", output); + assert(output == expected); + printf("== TEST PASSED ==\n\n"); + + // 3rd test + char input3[] = "III"; + expected = 3; + + output = roman_to_decimal(input3); + + printf("TEST 3\n"); + printf("Input: %s\n", input3); + printf("Expected Output: %d\n", expected); + printf("Output: %d\n", output); + assert(output == expected); + printf("== TEST PASSED ==\n\n"); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} diff --git a/conversions/toDecimal.c b/conversions/toDecimal.c deleted file mode 100644 index 3697e46429..0000000000 --- a/conversions/toDecimal.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * convert from any base to decimal - */ - -#include -#include - -int main(void) { - int base, i, j; - char number[100]; - unsigned long decimal = 0; - - printf("Enter the base: "); - scanf("%d", &base); - printf("Enter the number: "); - scanf("%s", &number[0]); - - for (i = 0; number[i] != '\0'; i++) { - if (isdigit(number[i])) - number[i] -= '0'; - else if (isupper(number[i])) - number[i] -= 'A' - 10; - else if (islower(number[i])) - number[i] -= 'a' - 10; - else - number[i] = base + 1; - - if (number[i] >= base){ - printf("invalid number\n"); - return 0; - } - } - - for (j = 0; j < i; j++) { - decimal *= base; - decimal += number[j]; - } - - printf("%lu\n", decimal); -} diff --git a/conversions/to_decimal.c b/conversions/to_decimal.c new file mode 100644 index 0000000000..28bd3ca62d --- /dev/null +++ b/conversions/to_decimal.c @@ -0,0 +1,44 @@ +/* + * convert from any base to decimal + */ + +#include +#include + +int main(void) +{ + int base, i, j; + char number[100]; + unsigned long decimal = 0; + + printf("Enter the base: "); + scanf("%d", &base); + printf("Enter the number: "); + scanf("%s", &number[0]); + + for (i = 0; number[i] != '\0'; i++) + { + if (isdigit(number[i])) + number[i] -= '0'; + else if (isupper(number[i])) + number[i] -= 'A' - 10; + else if (islower(number[i])) + number[i] -= 'a' - 10; + else + number[i] = base + 1; + + if (number[i] >= base) + { + printf("invalid number\n"); + return 0; + } + } + + for (j = 0; j < i; j++) + { + decimal *= base; + decimal += number[j]; + } + + printf("%lu\n", decimal); +} diff --git a/data_structures/Array/CArray.c b/data_structures/Array/CArray.c deleted file mode 100644 index ea71ec1088..0000000000 --- a/data_structures/Array/CArray.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * CArray.c - * - * Author: Leonardo Vencovsky - * Created on 19/03/2018 - * - * Modified by: Leonardo Vencovsky - * Last modified: 19/03/2018 - * - * Array Implementations in C - * - * Compiled in Visual Studio 2017 - * - */ - - /* - Return Codes - - -1 - Array Erased - 0 - Success - 1 - Invalid Position - 2 - Position already initialized (use update function) - 3 - Position not initialized (use insert function) - 4 - Position already empty - 5 - Array is full - - */ - -#include -#include -#include -#include "CArray.h" - -void swap(CArray *array, int position1, int position2); - -CArray * getCArray(int size) -{ - CArray *array = (CArray *) malloc(sizeof(CArray)); - array->array = (int *) malloc(sizeof(int) * size); - array->size = size; - int i; - for (i = 0; i < size; i++) { - array->array[i] = 0; - } - return array; -} - -int insertValueCArray(CArray *array, int position, int value) -{ - if (position >= 0 && position < array->size) { - if (array->array[position] == 0) { - array->array[position] = value; - return SUCCESS; - } - else return POSITION_INIT; - } - return INVALID_POSITION; -} - -int removeValueCArray(CArray *array, int position) -{ - if (position >= 0 && position < array->size) { - if (array->array[position] != 0) { - array->array[position] = 0; - } - else return POSITION_EMPTY; - } - return INVALID_POSITION; -} - -int pushValueCArray(CArray *array, int value) -{ - int i; - int ok = 0; - for (i = 0; i < array->size; i++) { - if (array->array[i] == 0) { - array->array[i] = value; - ok = 1; - break; - } - } - if (ok == 1) return SUCCESS; - else return ARRAY_FULL; -} - -int updateValueCArray(CArray *array, int position, int value) -{ - if (position >= 0 && position < array->size) { - if (array->array[position] != 0) { - - } - - else return POSITION_NOT_INIT; - } - return INVALID_POSITION; -} - -int eraseCArray(CArray *array) -{ - int i; - for (i = 0; i < array->size; i++) { - array->array[i] = 0; - } - return 0; -} - -int switchValuesCArray(CArray *array, int position1, int position2) -{ - if (position1 >= 0 && position1 < array->size - && position2 >= 0 && position2 < array->size) { - int temp = array->array[position1]; - array->array[position1] = array->array[position2]; - array->array[position2] = temp; - } - return INVALID_POSITION; -} - -int reverseCArray(CArray *array) -{ - int i; - for (i = 0; i < array->size / 2; i++) { - swap(array, i, array->size - i - 1); - } - return SUCCESS; -} - -int displayCArray(CArray *array) -{ - int i; - printf("\nC ARRAY\n"); - for (i = 0; i < array->size; i++) { - printf("%d ", array->array[i]); - } - printf("\n"); - return 0; -} - -int blenderCArray(CArray *array) -{ - srand(time(NULL) * array->size); - int i; - int total = array->size * 100; - for (i = 0; i < total; i++) { - swap(array, rand() % array->size, rand() % array->size); - } - return 0; -} - -CArray * getCopyCArray(CArray *arr) -{ - CArray *array = (CArray *)malloc(sizeof(CArray)); - array->array = (int *)malloc(sizeof(int) * arr->size); - array->size = arr->size; - int i; - for (i = 0; i < arr->size; i++) { - array->array[i] = arr->array[i]; - } - return array; -} - -void swap(CArray *array, int position1, int position2) -{ - int temp = array->array[position1]; - array->array[position1] = array->array[position2]; - array->array[position2] = temp; -} - -int bubbleSortCArray(CArray *array) -{ - int i, j; - for (i = 0; i < array->size - 1; i++) { - for (j = 0; j < array->size - i - 1; j++) { - if (array->array[j] > array->array[j + 1]) { - swap(array, j, j + 1); - } - } - } - return 0; -} - -int selectionSortCArray(CArray *array) -{ - int i, j, min; - for (i = 0; i < array->size - 1; i++) { - min = i; - for (j = i + 1; j < array->size; j++) - if (array->array[j] < array->array[min]) min = j; - swap(array, min, i); - } - return 0; -} - -int insertionSortCArray(CArray *array) -{ - int i, j, num; - for (i = 1; i < array->size; i++) { - num = array->array[i]; - j = i - 1; - while (j >= 0 && array->array[j] > num) - { - array->array[j + 1] = array->array[j]; - j--; - } - array->array[j + 1] = num; - } - return 0; -} - -int valueOcurranceCArray(CArray *array, int value) -{ - int i, total = 0; - for (i = 0; i < array->size; i++) { - if (array->array[i] == value) total++; - } - return total; -} - -CArray * valuePositionsCArray(CArray *array, int value) -{ - int i, j = 0; - int total = valueOcurranceCArray(array, value); - CArray *resultArray = getCArray(total); - for (i = 0; i < array->size; i++) { - if (array->array[i] == value) { - // Hopefully this won't overflow - resultArray->array[j] = i; - j++; - } - } - return resultArray; -} - -int findMinCArray(CArray *array) -{ - int i; - int min = array->array[0]; - for (i = 1; i < array->size; i++) { - if (array->array[i] < min) { - min = array->array[i]; - } - } - return min; -} - -int findMaxCArray(CArray *array) -{ - int i; - int max = array->array[0]; - for (i = 1; i < array->size; i++) { - if (array->array[i] > max) { - max = array->array[i]; - } - } - return max; -} diff --git a/data_structures/Array/CArray.h b/data_structures/Array/CArray.h deleted file mode 100644 index d85f161aa1..0000000000 --- a/data_structures/Array/CArray.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * CArray.h - * - * Author: Leonardo Vencovsky - * Created on 18/03/2018 - * - * Modified by: Leonardo Vencovsky - * Last modified: 19/03/2018 - * - * Header for Array in C - * - * Compiled in Visual Studio 2017 - * - */ - -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - - #define ARRAY_ERASED -1 - #define SUCCESS 0 - #define INVALID_POSITION 1 - #define POSITION_INIT 2 - #define POSITION_NOT_INIT 3 - #define POSITION_EMPTY 4 - #define ARRAY_FULL 5 - - typedef struct CArray { - int *array; - int size; - } CArray; - - // +-------------------------------------+ - // | Returns array | - // +-------------------------------------+ - CArray * getCArray(int size); - CArray * getCopyCArray(CArray *array); - - // +-------------------------------------+ - // | Input / Output | - // +-------------------------------------+ - int insertValueCArray(CArray *array, int position, int value); - int removeValueCArray(CArray *array, int position); - int pushValueCArray(CArray *array, int value); - int updateValueCArray(CArray *array, int position, int value); - - // +-------------------------------------+ - // | Erase | - // +-------------------------------------+ - int eraseCArray(CArray *array); - - // +-------------------------------------+ - // | Switching | - // +-------------------------------------+ - int switchValuesCArray(CArray *array, int position1, int position2); - int reverseCArray(CArray *array); - - // +-------------------------------------+ - // | Sorting | - // +-------------------------------------+ - int bubbleSortCArray(CArray *array); - int selectionSortCArray(CArray *array); - int insertionSortCArray(CArray *array); - int blenderCArray(CArray *array); - - // +-------------------------------------+ - // | Searching | - // +-------------------------------------+ - int valueOcurranceCArray(CArray *array, int value); - CArray * valuePositionsCArray(CArray *array, int value); - int findMaxCArray(CArray *array); - int findMinCArray(CArray *array); - - // +-------------------------------------+ - // | Display | - // +-------------------------------------+ - int displayCArray(CArray *array); - - -#ifdef __cplusplus -} -#endif diff --git a/data_structures/Array/CArrayTests.c b/data_structures/Array/CArrayTests.c deleted file mode 100644 index 3743fd3128..0000000000 --- a/data_structures/Array/CArrayTests.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * CArrayTests.c - * - * Author: Leonardo Vencovsky - * Created on 19/03/2018 - * - * Modified by: Leonardo Vencovsky - * Last modified: 19/03/2018 - * - * Test Cases for Array Implementations in C - * - * Compiled in Visual Studio 2017 - * - */ - -#include -#include -#include -#include "CArray.h" - -int CArrayTests() -{ - printf("\n"); - printf(" +-------------------------------------+\n"); - printf(" | |\n"); - printf(" | C Array |\n"); - printf(" | |\n"); - printf(" +-------------------------------------+\n"); - printf("\n"); - - CArray *array = getCArray(10); - - int i; - for (i = 0; i < array->size; i++) { - insertValueCArray(array, i, i+1); - } - - displayCArray(array); - printf("\nCode: %d\n", pushValueCArray(array, 11)); // 5 - - for (i = 0; i < array->size; i++) { - removeValueCArray(array, i); - } - - displayCArray(array); - - printf("\nCode: %d", removeValueCArray(array, -1)); // 1 - printf("\nCode: %d\n", insertValueCArray(array, -1, 1)); // 1 - - // Erase - for (i = 0; i < array->size; i++) { - insertValueCArray(array, i, i + 1); - } - eraseCArray(array); - displayCArray(array); // Should give all 0s - - // Switching - CArray *arr = getCArray(13); - for (i = 0; i < arr->size; i++) { - insertValueCArray(arr, i, i + 1); - } - displayCArray(arr); - for (i = 0; i < arr->size / 2; i++) { - switchValuesCArray(arr, i, arr->size - i - 1); - } - - displayCArray(arr); - - // Or simply... - reverseCArray(arr); - - displayCArray(arr); - - // Sorting - srand(time(NULL)); - CArray *barray = getCArray(20); - for (i = 0; i < barray->size; i++) { - insertValueCArray(barray, i, rand()); - } - CArray *carray = getCopyCArray(barray); - CArray *darray = getCopyCArray(barray); - printf("\nNot sorted Array:"); - displayCArray(barray); - - printf("\nBubble Sort:"); - clock_t begin1 = clock(); - // Timing bubble sort - bubbleSortCArray(barray); - clock_t end1 = clock(); - double time_spent1 = (double)(end1 - begin1) / CLOCKS_PER_SEC; - displayCArray(barray); - - printf("\nSelection Sort:"); - clock_t begin2 = clock(); - // Timing selection sort - selectionSortCArray(carray); - clock_t end2 = clock(); - double time_spent2 = (double)(end2 - begin2) / CLOCKS_PER_SEC; - displayCArray(carray); - - printf("\nInsertion Sort:"); - clock_t begin3 = clock(); - // Timing insertion sort - insertionSortCArray(darray); - clock_t end3 = clock(); - double time_spent3 = (double)(end3 - begin3) / CLOCKS_PER_SEC; - displayCArray(carray); - - // Descending order - reverseCArray(barray); - // displayCArray(barray); - -// printf("\nBlender:"); -// blenderCArray(barray); -// displayCArray(barray); - - printf("\nTotal time spent for bubble sort: %lf seconds", time_spent1); - printf("\nTotal time spent for selection sort: %lf seconds", time_spent2); - printf("\nTotal time spent for insertion sort: %lf seconds", time_spent3); - - // Searching - CArray *aarray = getCArray(1000); - for (i = 0; i < aarray->size; i++) { - insertValueCArray(aarray, i, rand() % 100); - } - - int j = 24; - printf("\nOccurrences of the number %d in the array: %d", j, - valueOcurranceCArray(aarray, j)); - printf("\nAnd its positions:\n"); - CArray *positions = valuePositionsCArray(aarray, j); - displayCArray(positions); - // This should all give value of j - printf("\nAll %d s", j); - for (i = 0; i < positions->size; i++) { - printf("\nPosition %d has a value of %d", - positions->array[i], aarray->array[positions->array[i]]); - } - printf("\nThe list has a minimum value of %d and a maximum value of %d", - findMinCArray(aarray), findMaxCArray(aarray)); - insertionSortCArray(aarray); - // displayCArray(aarray); - - free(arr); - free(array); - free(aarray); - free(barray); - free(carray); - free(darray); - printf("\n"); - return 0; -} \ No newline at end of file diff --git a/data_structures/Array/README.md b/data_structures/array/README.md similarity index 52% rename from data_structures/Array/README.md rename to data_structures/array/README.md index bb03741366..bf70cccb1a 100644 --- a/data_structures/Array/README.md +++ b/data_structures/array/README.md @@ -2,6 +2,10 @@ Simple array of integers. With I/O functions, Sort Functions and Search Functions. +## Sort Function + +The Sort function sorts the elements in the range in a particular order. The different types of sorting methods are Bubble Sort, Selection Sort, Merge Sort and Quick Sort. Bubble Sort repeatedly sorts the adjacent elements if they are in wrong order. + ## Structure ```C diff --git a/data_structures/array/carray.c b/data_structures/array/carray.c new file mode 100644 index 0000000000..7b812eb7ac --- /dev/null +++ b/data_structures/array/carray.c @@ -0,0 +1,291 @@ +/* + * CArray.c + * + * Author: Leonardo Vencovsky + * Created on 19/03/2018 + * + * Modified by: Leonardo Vencovsky + * Last modified: 19/03/2018 + * + * Array Implementations in C + * + * Compiled in Visual Studio 2017 + * + */ + +/* +Return Codes + +-1 - Array Erased +0 - Success +1 - Invalid Position +2 - Position already initialized (use update function) +3 - Position not initialized (use insert function) +4 - Position already empty +5 - Array is full + +*/ + +#include "carray.h" +#include +#include +#include + +void swap(CArray *array, int position1, int position2); + +CArray *getCArray(int size) +{ + CArray *array = (CArray *)malloc(sizeof(CArray)); + array->array = (int *)malloc(sizeof(int) * size); + array->size = size; + int i; + for (i = 0; i < size; i++) + { + array->array[i] = 0; + } + return array; +} + +int insertValueCArray(CArray *array, int position, int value) +{ + if (position >= 0 && position < array->size) + { + if (array->array[position] == 0) + { + array->array[position] = value; + return SUCCESS; + } + else + return POSITION_INIT; + } + return INVALID_POSITION; +} + +int removeValueCArray(CArray *array, int position) +{ + if (position >= 0 && position < array->size) + { + if (array->array[position] != 0) + { + array->array[position] = 0; + } + else + return POSITION_EMPTY; + } + return INVALID_POSITION; +} + +int pushValueCArray(CArray *array, int value) +{ + int i; + int ok = 0; + for (i = 0; i < array->size; i++) + { + if (array->array[i] == 0) + { + array->array[i] = value; + ok = 1; + break; + } + } + if (ok == 1) + return SUCCESS; + else + return ARRAY_FULL; +} + +int updateValueCArray(CArray *array, int position, int value) +{ + if (position >= 0 && position < array->size) + { + if (array->array[position] != 0) + { + array->array[position] = value; + return SUCCESS; + } + + else + return POSITION_NOT_INIT; + } + return INVALID_POSITION; +} + +int eraseCArray(CArray *array) +{ + int i; + for (i = 0; i < array->size; i++) + { + array->array[i] = 0; + } + return 0; +} + +int switchValuesCArray(CArray *array, int position1, int position2) +{ + if (position1 >= 0 && position1 < array->size && position2 >= 0 && + position2 < array->size) + { + int temp = array->array[position1]; + array->array[position1] = array->array[position2]; + array->array[position2] = temp; + return SUCCESS; + } + return INVALID_POSITION; +} + +int reverseCArray(CArray *array) +{ + int i; + for (i = 0; i < array->size / 2; i++) + { + swap(array, i, array->size - i - 1); + } + return SUCCESS; +} + +int displayCArray(CArray *array) +{ + int i; + printf("\nC ARRAY\n"); + for (i = 0; i < array->size; i++) + { + printf("%d ", array->array[i]); + } + printf("\n"); + return 0; +} + +int blenderCArray(CArray *array) +{ + srand(time(NULL) * array->size); + int i; + int total = array->size * 100; + for (i = 0; i < total; i++) + { + swap(array, rand() % array->size, rand() % array->size); + } + return 0; +} + +CArray *getCopyCArray(CArray *arr) +{ + CArray *array = (CArray *)malloc(sizeof(CArray)); + array->array = (int *)malloc(sizeof(int) * arr->size); + array->size = arr->size; + int i; + for (i = 0; i < arr->size; i++) + { + array->array[i] = arr->array[i]; + } + return array; +} + +void swap(CArray *array, int position1, int position2) +{ + int temp = array->array[position1]; + array->array[position1] = array->array[position2]; + array->array[position2] = temp; +} + +int bubbleSortCArray(CArray *array) +{ + int i, j; + for (i = 0; i < array->size - 1; i++) + { + for (j = 0; j < array->size - i - 1; j++) + { + if (array->array[j] > array->array[j + 1]) + { + swap(array, j, j + 1); + } + } + } + return 0; +} + +int selectionSortCArray(CArray *array) +{ + int i, j, min; + for (i = 0; i < array->size - 1; i++) + { + min = i; + for (j = i + 1; j < array->size; j++) + if (array->array[j] < array->array[min]) + min = j; + swap(array, min, i); + } + return 0; +} + +int insertionSortCArray(CArray *array) +{ + int i, j, num; + for (i = 1; i < array->size; i++) + { + num = array->array[i]; + j = i - 1; + while (j >= 0 && array->array[j] > num) + { + array->array[j + 1] = array->array[j]; + j--; + } + array->array[j + 1] = num; + } + return 0; +} + +int valueOcurranceCArray(CArray *array, int value) +{ + int i, total = 0; + for (i = 0; i < array->size; i++) + { + if (array->array[i] == value) + total++; + } + return total; +} + +CArray *valuePositionsCArray(CArray *array, int value) +{ + int i, j = 0; + int total = valueOcurranceCArray(array, value); + CArray *resultArray = getCArray(total); + for (i = 0; i < array->size; i++) + { + if (array->array[i] == value) + { + // Hopefully this won't overflow + resultArray->array[j] = i; + j++; + } + } + return resultArray; +} + +int findMinCArray(CArray *array) +{ + int i; + int min = array->array[0]; + for (i = 1; i < array->size; i++) + { + if (array->array[i] < min) + { + min = array->array[i]; + } + } + return min; +} + +int findMaxCArray(CArray *array) +{ + int i; + int max = array->array[0]; + for (i = 1; i < array->size; i++) + { + if (array->array[i] > max) + { + max = array->array[i]; + } + } + return max; +} diff --git a/data_structures/array/carray.h b/data_structures/array/carray.h new file mode 100644 index 0000000000..24fa2d85c6 --- /dev/null +++ b/data_structures/array/carray.h @@ -0,0 +1,85 @@ +/* + * CArray.h + * + * Author: Leonardo Vencovsky + * Created on 18/03/2018 + * + * Modified by: Leonardo Vencovsky + * Last modified: 19/03/2018 + * + * Header for Array in C + * + * Compiled in Visual Studio 2017 + * + */ + +#pragma once + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define ARRAY_ERASED -1 +#define SUCCESS 0 +#define INVALID_POSITION 1 +#define POSITION_INIT 2 +#define POSITION_NOT_INIT 3 +#define POSITION_EMPTY 4 +#define ARRAY_FULL 5 + + typedef struct CArray + { + int *array; + int size; + } CArray; + + // +-------------------------------------+ + // | Returns array | + // +-------------------------------------+ + CArray *getCArray(int size); + CArray *getCopyCArray(CArray *array); + + // +-------------------------------------+ + // | Input / Output | + // +-------------------------------------+ + int insertValueCArray(CArray *array, int position, int value); + int removeValueCArray(CArray *array, int position); + int pushValueCArray(CArray *array, int value); + int updateValueCArray(CArray *array, int position, int value); + + // +-------------------------------------+ + // | Erase | + // +-------------------------------------+ + int eraseCArray(CArray *array); + + // +-------------------------------------+ + // | Switching | + // +-------------------------------------+ + int switchValuesCArray(CArray *array, int position1, int position2); + int reverseCArray(CArray *array); + + // +-------------------------------------+ + // | Sorting | + // +-------------------------------------+ + int bubbleSortCArray(CArray *array); + int selectionSortCArray(CArray *array); + int insertionSortCArray(CArray *array); + int blenderCArray(CArray *array); + + // +-------------------------------------+ + // | Searching | + // +-------------------------------------+ + int valueOcurranceCArray(CArray *array, int value); + CArray *valuePositionsCArray(CArray *array, int value); + int findMaxCArray(CArray *array); + int findMinCArray(CArray *array); + + // +-------------------------------------+ + // | Display | + // +-------------------------------------+ + int displayCArray(CArray *array); + +#ifdef __cplusplus +} +#endif diff --git a/data_structures/array/carray_tests.c b/data_structures/array/carray_tests.c new file mode 100644 index 0000000000..d47a8d6529 --- /dev/null +++ b/data_structures/array/carray_tests.c @@ -0,0 +1,160 @@ +/* + * CArrayTests.c + * + * Author: Leonardo Vencovsky + * Created on 19/03/2018 + * + * Modified by: Leonardo Vencovsky + * Last modified: 19/03/2018 + * + * Test Cases for Array Implementations in C + * + * Compiled in Visual Studio 2017 + * + */ + +#include +#include +#include +#include "carray.h" + +int CArrayTests() +{ + printf("\n"); + printf(" +-------------------------------------+\n"); + printf(" | |\n"); + printf(" | C Array |\n"); + printf(" | |\n"); + printf(" +-------------------------------------+\n"); + printf("\n"); + + CArray *array = getCArray(10); + + int i; + for (i = 0; i < array->size; i++) + { + insertValueCArray(array, i, i + 1); + } + printf("Entered array is:\n"); + displayCArray(array); + printf("\nCode: %d\n", pushValueCArray(array, 11)); // 5 + + for (i = 0; i < array->size; i++) + { + removeValueCArray(array, i); + } + + displayCArray(array); + + printf("\nCode: %d", removeValueCArray(array, -1)); // 1 + printf("\nCode: %d\n", insertValueCArray(array, -1, 1)); // 1 + + // Erase + for (i = 0; i < array->size; i++) + { + insertValueCArray(array, i, i + 1); + } + eraseCArray(array); + displayCArray(array); // Should give all 0s + + // Switching + CArray *arr = getCArray(13); + for (i = 0; i < arr->size; i++) + { + insertValueCArray(arr, i, i + 1); + } + displayCArray(arr); + for (i = 0; i < arr->size / 2; i++) + { + switchValuesCArray(arr, i, arr->size - i - 1); + } + + displayCArray(arr); + + // Or simply... + reverseCArray(arr); + + displayCArray(arr); + + // Sorting + srand(time(NULL)); + CArray *barray = getCArray(20); + for (i = 0; i < barray->size; i++) + { + insertValueCArray(barray, i, rand()); + } + CArray *carray = getCopyCArray(barray); + CArray *darray = getCopyCArray(barray); + printf("\nNot sorted Array:"); + displayCArray(barray); + + printf("\nBubble Sort:"); + clock_t begin1 = clock(); + // Timing bubble sort + bubbleSortCArray(barray); + clock_t end1 = clock(); + double time_spent1 = (double)(end1 - begin1) / CLOCKS_PER_SEC; + displayCArray(barray); + + printf("\nSelection Sort:"); + clock_t begin2 = clock(); + // Timing selection sort + selectionSortCArray(carray); + clock_t end2 = clock(); + double time_spent2 = (double)(end2 - begin2) / CLOCKS_PER_SEC; + displayCArray(carray); + + printf("\nInsertion Sort:"); + clock_t begin3 = clock(); + // Timing insertion sort + insertionSortCArray(darray); + clock_t end3 = clock(); + double time_spent3 = (double)(end3 - begin3) / CLOCKS_PER_SEC; + displayCArray(carray); + + // Descending order + reverseCArray(barray); + // displayCArray(barray); + + // printf("\nBlender:"); + // blenderCArray(barray); + // displayCArray(barray); + + printf("\nTotal time spent for bubble sort: %lf seconds", time_spent1); + printf("\nTotal time spent for selection sort: %lf seconds", time_spent2); + printf("\nTotal time spent for insertion sort: %lf seconds", time_spent3); + + // Searching + CArray *aarray = getCArray(1000); + for (i = 0; i < aarray->size; i++) + { + insertValueCArray(aarray, i, rand() % 100); + } + + int j = 24; + printf("\nOccurrences of the number %d in the array: %d", j, + valueOcurranceCArray(aarray, j)); + printf("\nAnd its positions:\n"); + CArray *positions = valuePositionsCArray(aarray, j); + displayCArray(positions); + // This should all give value of j + printf("\nAll %d s", j); + for (i = 0; i < positions->size; i++) + { + printf("\nPosition %d has a value of %d", positions->array[i], + aarray->array[positions->array[i]]); + } + printf("\nThe list has a minimum value of %d and a maximum value of %d", + findMinCArray(aarray), findMaxCArray(aarray)); + insertionSortCArray(aarray); + // displayCArray(aarray); + + free(arr); + free(array); + free(aarray); + free(barray); + free(carray); + free(darray); + printf("\n"); + return 0; +} diff --git a/data_structures/binary_trees/avl_tree.c b/data_structures/binary_trees/avl_tree.c new file mode 100644 index 0000000000..604638735d --- /dev/null +++ b/data_structures/binary_trees/avl_tree.c @@ -0,0 +1,420 @@ +#include +#include + +struct AVLnode +{ + int key; + struct AVLnode *left; + struct AVLnode *right; + int height; +}; +typedef struct AVLnode avlNode; + +int max(int a, int b) { return (a > b) ? a : b; } + +avlNode *newNode(int key) +{ + avlNode *node = (avlNode *)malloc(sizeof(avlNode)); + + if (node == NULL) + printf("!! Out of Space !!\n"); + else + { + node->key = key; + node->left = NULL; + node->right = NULL; + node->height = 0; + } + + return node; +} + +int nodeHeight(avlNode *node) +{ + if (node == NULL) + return -1; + else + return (node->height); +} + +int heightDiff(avlNode *node) +{ + if (node == NULL) + return 0; + else + return (nodeHeight(node->left) - nodeHeight(node->right)); +} + +/* Returns the node with min key in the left subtree*/ +avlNode *minNode(avlNode *node) +{ + avlNode *temp = node; + + while (temp->left != NULL) temp = temp->left; + + return temp; +} + +void printAVL(avlNode *node, int level) +{ + int i; + if (node != NULL) + { + printAVL(node->right, level + 1); + printf("\n\n"); + + for (i = 0; i < level; i++) printf("\t"); + + printf("%d", node->key); + + printAVL(node->left, level + 1); + } +} + +avlNode *rightRotate(avlNode *z) +{ + avlNode *y = z->left; + avlNode *T3 = y->right; + + y->right = z; + z->left = T3; + + z->height = (max(nodeHeight(z->left), nodeHeight(z->right)) + 1); + y->height = (max(nodeHeight(y->left), nodeHeight(y->right)) + 1); + + return y; +} + +avlNode *leftRotate(avlNode *z) +{ + avlNode *y = z->right; + avlNode *T3 = y->left; + + y->left = z; + z->right = T3; + + z->height = (max(nodeHeight(z->left), nodeHeight(z->right)) + 1); + y->height = (max(nodeHeight(y->left), nodeHeight(y->right)) + 1); + + return y; +} + +avlNode *LeftRightRotate(avlNode *z) +{ + z->left = leftRotate(z->left); + + return (rightRotate(z)); +} + +avlNode *RightLeftRotate(avlNode *z) +{ + z->right = rightRotate(z->right); + + return (leftRotate(z)); +} + +avlNode *insert(avlNode *node, int key) +{ + if (node == NULL) + return (newNode(key)); + + /*Binary Search Tree insertion*/ + + if (key < node->key) + node->left = + insert(node->left, key); /*Recursive insertion in L subtree*/ + else if (key > node->key) + node->right = + insert(node->right, key); /*Recursive insertion in R subtree*/ + + /* Node Height as per the AVL formula*/ + node->height = (max(nodeHeight(node->left), nodeHeight(node->right)) + 1); + + /*Checking for the balance condition*/ + int balance = heightDiff(node); + + /*Left Left */ + if (balance > 1 && key < (node->left->key)) + return rightRotate(node); + + /*Right Right */ + if (balance < -1 && key > (node->right->key)) + return leftRotate(node); + + /*Left Right */ + if (balance > 1 && key > (node->left->key)) + { + node = LeftRightRotate(node); + } + + /*Right Left */ + if (balance < -1 && key < (node->right->key)) + { + node = RightLeftRotate(node); + } + + return node; +} + +avlNode *delete (avlNode *node, int queryNum) +{ + if (node == NULL) + return node; + + if (queryNum < node->key) + node->left = + delete (node->left, queryNum); /*Recursive deletion in L subtree*/ + else if (queryNum > node->key) + node->right = + delete (node->right, queryNum); /*Recursive deletion in R subtree*/ + else + { + /*Single or No Children*/ + if ((node->left == NULL) || (node->right == NULL)) + { + avlNode *temp = node->left ? node->left : node->right; + + /* No Children*/ + if (temp == NULL) + { + temp = node; + node = NULL; + } + else /*Single Child : copy data to the parent*/ + *node = *temp; + + free(temp); + } + else + { + /*Two Children*/ + + /*Get the smallest key in the R subtree*/ + avlNode *temp = minNode(node->right); + node->key = temp->key; /*Copy that to the root*/ + node->right = + delete (node->right, + temp->key); /*Delete the smallest in the R subtree.*/ + } + } + + /*single node in tree*/ + if (node == NULL) + return node; + + /*Update height*/ + node->height = (max(nodeHeight(node->left), nodeHeight(node->right)) + 1); + + int balance = heightDiff(node); + + /*Left Left */ + if ((balance > 1) && (heightDiff(node->left) >= 0)) + return rightRotate(node); + + /*Left Right */ + if ((balance > 1) && (heightDiff(node->left) < 0)) + { + node = LeftRightRotate(node); + } + + /*Right Right */ + if ((balance < -1) && (heightDiff(node->right) >= 0)) + return leftRotate(node); + + /*Right Left */ + if ((balance < -1) && (heightDiff(node->right) < 0)) + { + node = RightLeftRotate(node); + } + + return node; +} + +avlNode *findNode(avlNode *node, int queryNum) +{ + if (node != NULL) + { + if (queryNum < node->key) + node = findNode(node->left, queryNum); + else if (queryNum > node->key) + node = findNode(node->right, queryNum); + } + + return node; +} + +void printPreOrder(avlNode *node) +{ + if (node == NULL) + return; + + printf(" %d ", (node->key)); + printPreOrder(node->left); + printPreOrder(node->right); +} + +void printInOrder(avlNode *node) +{ + if (node == NULL) + return; + printInOrder(node->left); + printf(" %d ", (node->key)); + printInOrder(node->right); +} + +void printPostOrder(avlNode *node) +{ + if (node == NULL) + return; + printPostOrder(node->left); + printPostOrder(node->right); + printf(" %d ", (node->key)); +} + +int main() +{ + int choice; + int flag = 1; + int insertNum; + int queryNum; + + avlNode *root = NULL; + avlNode *tempNode; + + while (flag == 1) + { + printf("\n\nEnter the Step to Run : \n"); + + printf("\t1: Insert a node into AVL tree\n"); + printf("\t2: Delete a node in AVL tree\n"); + printf("\t3: Search a node into AVL tree\n"); + printf("\t4: printPreOrder (Ro L R) Tree\n"); + printf("\t5: printInOrder (L Ro R) Tree\n"); + printf("\t6: printPostOrder (L R Ro) Tree\n"); + printf("\t7: printAVL Tree\n"); + + printf("\t0: EXIT\n"); + scanf("%d", &choice); + + switch (choice) + { + case 0: + { + flag = 0; + printf("\n\t\tExiting, Thank You !!\n"); + break; + } + + case 1: + { + printf("\n\tEnter the Number to insert: "); + scanf("%d", &insertNum); + + tempNode = findNode(root, insertNum); + + if (tempNode != NULL) + printf("\n\t %d Already exists in the tree\n", insertNum); + else + { + printf("\n\tPrinting AVL Tree\n"); + printAVL(root, 1); + printf("\n"); + + root = insert(root, insertNum); + printf("\n\tPrinting AVL Tree\n"); + printAVL(root, 1); + printf("\n"); + } + + break; + } + + case 2: + { + printf("\n\tEnter the Number to Delete: "); + scanf("%d", &queryNum); + + tempNode = findNode(root, queryNum); + + if (tempNode == NULL) + printf("\n\t %d Does not exist in the tree\n", queryNum); + else + { + printf("\n\tPrinting AVL Tree\n"); + printAVL(root, 1); + printf("\n"); + root = delete (root, queryNum); + + printf("\n\tPrinting AVL Tree\n"); + printAVL(root, 1); + printf("\n"); + } + + break; + } + + case 3: + { + printf("\n\tEnter the Number to Search: "); + scanf("%d", &queryNum); + + tempNode = findNode(root, queryNum); + + if (tempNode == NULL) + printf("\n\t %d : Not Found\n", queryNum); + else + { + printf("\n\t %d : Found at height %d \n", queryNum, + tempNode->height); + + printf("\n\tPrinting AVL Tree\n"); + printAVL(root, 1); + printf("\n"); + } + + break; + } + + case 4: + { + printf("\nPrinting Tree preOrder\n"); + printPreOrder(root); + + break; + } + + case 5: + { + printf("\nPrinting Tree inOrder\n"); + printInOrder(root); + + break; + } + + case 6: + { + printf("\nPrinting Tree PostOrder\n"); + printPostOrder(root); + + break; + } + + case 7: + { + printf("\nPrinting AVL Tree\n"); + printAVL(root, 1); + + break; + } + + default: + { + flag = 0; + printf("\n\t\tExiting, Thank You !!\n"); + break; + } + } + } + + return 0; +} diff --git a/data_structures/binary_trees/binary_search_tree.c b/data_structures/binary_trees/binary_search_tree.c index f86ad9c3ca..9af1d5fa01 100644 --- a/data_structures/binary_trees/binary_search_tree.c +++ b/data_structures/binary_trees/binary_search_tree.c @@ -1,206 +1,308 @@ +/** + * @file + * @brief A basic unbalanced binary search tree implementation in C. + * @details The implementation has the following functionalities implemented: + * - Insertion + * - Deletion + * - Search by key value + * - Listing of node keys in order of value (from left to right) + */ #include #include -/* A basic unbalanced binary search tree implementation in C, with the following functionalities implemented: - - Insertion - - Deletion - - Search by key value - - Listing of node keys in order of value (from left to right) -*/ - -// Node, the basic data structure in the tree -typedef struct node{ - - // left child - struct node* left; - - // right child - struct node* right; - - // data of the node - int data; +/** Node, the basic data structure in the tree */ +typedef struct node +{ + struct node *left; /**< left child */ + struct node *right; /**< right child */ + int data; /**< data of the node */ } node; -// The node constructor, which receives the key value input and returns a node pointer -node* newNode(int data){ - +/** The node constructor, which receives the key value input and returns a node + * pointer + * @param data data to store in a new node + * @returns new node with the provided data + * @note the node must be deleted before program terminates to avoid memory + * leaks + */ +node *newNode(int data) +{ // creates a slug - node* tmp = (node*)malloc(sizeof(node)); + node *tmp = (node *)malloc(sizeof(node)); - // initializes the slug - tmp->data = data; - tmp->left = NULL; - tmp->right = NULL; + // initializes the slug + tmp->data = data; + tmp->left = NULL; + tmp->right = NULL; - return tmp; + return tmp; } -// Insertion procedure, which inserts the input key in a new node in the tree -node* insert(node* root, int data){ - // If the root of the subtree is null, insert key here - if (root == NULL) - root = newNode(data); - // If it isn't null and the input key is greater than the root key, insert in the right leaf - else if (data > root->data) - root->right = insert(root->right, data); - // If it isn't null and the input key is lower than the root key, insert in the left leaf - else if (data < root->data) - root->left = insert(root->left, data); - // Returns the modified tree - return root; +/** Insertion procedure, which inserts the input key in a new node in the tree + * @param root pointer to parent node + * @param data value to store int he new node + * @returns pointer to parent node + */ +node *insert(node *root, int data) +{ + // If the root of the subtree is null, insert key here + if (root == NULL) + { + root = newNode(data); + } + else if (data > root->data) + { + // If it isn't null and the input key is greater than the root key, + // insert in the right leaf + root->right = insert(root->right, data); + } + else if (data < root->data) + { // If it isn't null and the input key is lower than the root key, insert + // in the left leaf + root->left = insert(root->left, data); + } + // Returns the modified tree + return root; } -// Utilitary procedure to find the greatest key in the left subtree -node* getMax(node* root){ - // If there's no leaf to the right, then this is the maximum key value - if (root->right == NULL) - return root; - else - root->right = getMax(root->right); +/** Utilitary procedure to find the greatest key in the left subtree + * @param root pointer to parent node + * @returns pointer to parent node + */ +node *getMax(node *root) +{ + // If there's no leaf to the right, then this is the maximum key value + if (root->right != NULL) + { + return getMax(root->right); + } + return root; } -// Deletion procedure, which searches for the input key in the tree and removes it if present -node* delete(node* root, int data){ - // If the root is null, nothing to be done - if (root == NULL) - return root; - // If the input key is greater than the root's, search in the right subtree - else if (data > root->data) - root->right = delete(root->right, data); - // If the input key is lower than the root's, search in the left subtree - else if (data < root->data) - root->left = delete(root->left, data); - // If the input key matches the root's, check the following cases - // termination condition - else if (data == root->data){ - // Case 1: the root has no leaves, remove the node - if ((root->left == NULL) && (root->right == NULL)){ - free(root); - return NULL; - } - // Case 2: the root has one leaf, make the leaf the new root and remove the old root - else if (root->left == NULL){ - node* tmp = root; - root = root->right; - free(tmp); - return root; - } - else if (root->right == NULL){ - node* tmp = root; - root = root->left; - free(tmp); - return root; - } - // Case 3: the root has 2 leaves, find the greatest key in the left subtree and switch with the root's - else { +/** Deletion procedure, which searches for the input key in the tree and removes + * it if present + * @param root pointer to parent node + * @param data value to search for int the node + * @returns pointer to parent node + */ +node *delete (node *root, int data) +{ + // If the root is null, nothing to be done + if (root == NULL) + { + return root; + } + else if (data > root->data) + { // If the input key is greater than the root's, search in the right + // subtree + root->right = delete (root->right, data); + } + else if (data < root->data) + { // If the input key is lower than the root's, search in the left subtree + root->left = delete (root->left, data); + } + else if (data == root->data) + { + // If the input key matches the root's, check the following cases + // termination condition + if ((root->left == NULL) && (root->right == NULL)) + { // Case 1: the root has no leaves, remove the node + free(root); + return NULL; + } + else if (root->left == NULL) + { // Case 2: the root has one leaf, make the leaf the new root and + // remove + // the old root + node *tmp = root; + root = root->right; + free(tmp); + return root; + } + else if (root->right == NULL) + { + node *tmp = root; + root = root->left; + free(tmp); + return root; + } + else + { // Case 3: the root has 2 leaves, find the greatest key in the left + // subtree and switch with the root's // finds the biggest node in the left branch. - node* tmp = getMax(root->left); - - // sets the data of this node equal to the data of the biggest node (lefts) - root->data = tmp->data; - root->left = delete(root->left, tmp->data); - } - } - return root; -} + node *tmp = getMax(root->left); -// Search procedure, which looks for the input key in the tree and returns 1 if it's present or 0 if it's not in the tree -int find(node* root, int data){ - // If the root is null, the key's not present - if (root == NULL) - return 0; - // If the input key is greater than the root's, search in the right subtree - else if (data > root->data) - return find(root->right, data); - // If the input key is lower than the root's, search in the left subtree - else if (data < root->data) - return find(root->left, data); - // If the input and the root key match, return 1 - else if (data == root->data) - return 1; + // sets the data of this node equal to the data of the biggest node + // (lefts) + root->data = tmp->data; + root->left = delete (root->left, tmp->data); + } + } + return root; } -// Utilitary procedure to measure the height of the binary tree -int height(node* root){ - // If the root is null, this is the bottom of the tree (height 0) - if (root == NULL) - return 0; - else{ - // Get the height from both left and right subtrees to check which is the greatest - int right_h = height(root->right); - int left_h = height(root->left); - - // The final height is the height of the greatest subtree(left or right) plus 1(which is the root's level) - if (right_h > left_h) - return (right_h + 1); - else - return (left_h + 1); - } +/** Search procedure, which looks for the input key in the tree and returns 1 if + * it's present or 0 if it's not in the tree + * @param root pointer to parent node + * @param data value to store int he new node + * @returns 0 if value not found in the nodes + * @returns 1 if value was found + */ +int find(node *root, int data) +{ + // If the root is null, the key's not present + if (root == NULL) + { + return 0; + } + else if (data > root->data) + { + // If the input key is greater than the root's, search in the right + // subtree + return find(root->right, data); + } + else if (data < root->data) + { + // If the input key is lower than the root's, search in the left subtree + return find(root->left, data); + } + else if (data == root->data) + { + // If the input and the root key match, return 1 + return 1; + } + else + { // unknown result!! + return 0; + } } -// Utilitary procedure to free all nodes in a tree -void purge(node* root){ - if (root != NULL){ - if (root->left != NULL) - purge(root->left); - if (root->right != NULL) - purge(root->right); - free(root); - } +/** Utilitary procedure to measure the height of the binary tree + * @param root pointer to parent node + * @param data value to store int he new node + * @returns 0 if value not found in the nodes + * @returns height of nodes to get to data from parent node + */ +int height(node *root) +{ + // If the root is null, this is the bottom of the tree (height 0) + if (root == NULL) + { + return 0; + } + else + { + // Get the height from both left and right subtrees to check which is + // the greatest + int right_h = height(root->right); + int left_h = height(root->left); + + // The final height is the height of the greatest subtree(left or right) + // plus 1(which is the root's level) + if (right_h > left_h) + { + return (right_h + 1); + } + else + { + return (left_h + 1); + } + } } -// Traversal procedure to list the current keys in the tree in order of value (from the left to the right) -void inOrder(node* root){ - if(root != NULL){ - inOrder(root->left); - printf("\t[ %d ]\t", root->data); - inOrder(root->right); - } +/** Utilitary procedure to free all nodes in a tree + * @param root pointer to parent node + */ +void purge(node *root) +{ + if (root != NULL) + { + if (root->left != NULL) + { + purge(root->left); + } + if (root->right != NULL) + { + purge(root->right); + } + free(root); + root = NULL; // reset pointer + } } -void main(){ +/** Traversal procedure to list the current keys in the tree in order of value + * (from the left to the right) + * @param root pointer to parent node + */ +void inOrder(node *root) +{ + if (root != NULL) + { + inOrder(root->left); + printf("\t[ %d ]\t", root->data); + inOrder(root->right); + } +} +/** Main funcion */ +int main() +{ // this reference don't change. // only the tree changes. - node* root = NULL; - int opt = -1; - int data = 0; + node *root = NULL; + int opt = -1; + int data = 0; // event-loop. - while (opt != 0){ - printf("\n\n[1] Insert Node\n[2] Delete Node\n[3] Find a Node\n[4] Get current Height\n[5] Print Tree in Crescent Order\n[0] Quit\n"); - scanf("%d",&opt); // reads the choice of the user + while (opt != 0) + { + printf( + "\n\n[1] Insert Node\n[2] Delete Node\n[3] Find a Node\n[4] Get " + "current Height\n[5] Print Tree in Crescent Order\n[0] Quit\n"); + scanf("%d", &opt); // reads the choice of the user // processes the choice - switch(opt){ - case 1: printf("Enter the new node's value:\n"); - scanf("%d",&data); - root = insert(root,data); - break; - - case 2: printf("Enter the value to be removed:\n"); - if (root != NULL){ - scanf("%d",&data); - root = delete(root,data); - } - else - printf("Tree is already empty!\n"); - break; - - case 3: printf("Enter the searched value:\n"); - scanf("%d",&data); - find(root,data) ? printf("The value is in the tree.\n") : printf("The value is not in the tree.\n"); - break; - - case 4: printf("Current height of the tree is: %d\n", height(root)); - break; - - case 5: inOrder(root); - break; - } - } + switch (opt) + { + case 1: + printf("Enter the new node's value:\n"); + scanf("%d", &data); + root = insert(root, data); + break; + + case 2: + printf("Enter the value to be removed:\n"); + if (root != NULL) + { + scanf("%d", &data); + root = delete (root, data); + } + else + { + printf("Tree is already empty!\n"); + } + break; + + case 3: + printf("Enter the searched value:\n"); + scanf("%d", &data); + find(root, data) ? printf("The value is in the tree.\n") + : printf("The value is not in the tree.\n"); + break; + + case 4: + printf("Current height of the tree is: %d\n", height(root)); + break; + + case 5: + inOrder(root); + break; + } + } // deletes the tree from the heap. - purge(root); + purge(root); + + return 0; } diff --git a/data_structures/binary_trees/create_node.c b/data_structures/binary_trees/create_node.c index f1f59e4d85..fda592d8b7 100644 --- a/data_structures/binary_trees/create_node.c +++ b/data_structures/binary_trees/create_node.c @@ -1,5 +1,5 @@ /* Includes structure for a node and a newNode() function which - can be used to create a new node in the tree. + can be used to create a new node in the tree. It is assumed that the data in nodes will be an integer, though function can be modified according to the data type, easily. */ @@ -35,5 +35,5 @@ int main(void) nameOfNode->leftNode and so on. */ - return 0; + return 0; } \ No newline at end of file diff --git a/data_structures/binary_trees/recursive_traversals.c b/data_structures/binary_trees/recursive_traversals.c index aff5625586..d3dbfde319 100644 --- a/data_structures/binary_trees/recursive_traversals.c +++ b/data_structures/binary_trees/recursive_traversals.c @@ -7,7 +7,7 @@ void inOrderTraversal(struct node *node) { - if(node == NULL) //if tree is empty + if (node == NULL) // if tree is empty return; inOrderTraversal(node->leftNode); @@ -17,7 +17,7 @@ void inOrderTraversal(struct node *node) void preOrderTraversal(struct node *node) { - if(node == NULL) //if tree is empty + if (node == NULL) // if tree is empty return; printf("\t%d\t", node->data); @@ -27,12 +27,12 @@ void preOrderTraversal(struct node *node) void postOrderTraversal(struct node *node) { - if(node == NULL) //if tree is empty + if (node == NULL) // if tree is empty return; postOrderTraversal(node->leftNode); postOrderTraversal(node->rightNode); - printf("\t%d\t",node->data); + printf("\t%d\t", node->data); } int main(void) @@ -41,5 +41,5 @@ int main(void) function with a pointer to the root node. */ - return 0; + return 0; } \ No newline at end of file diff --git a/data_structures/binary_trees/red_black_tree.c b/data_structures/binary_trees/red_black_tree.c new file mode 100644 index 0000000000..6885122664 --- /dev/null +++ b/data_structures/binary_trees/red_black_tree.c @@ -0,0 +1,797 @@ +#include +#include +#include + +typedef struct node +{ + int val; + struct node *par; + struct node *left; + struct node *right; + int color; +} Node; + +// Create a new node +Node *newNode(int val, Node *par) +{ + Node *create = (Node *)(malloc(sizeof(Node))); + create->val = val; + create->par = par; + create->left = NULL; + create->right = NULL; + create->color = 1; +} + +// Check if the node is the leaf +int isLeaf(Node *n) +{ + if (n->left == NULL && n->right == NULL) + { + return 1; + } + return 0; +} + +// Left Rotate +Node *leftRotate(Node *node) +{ + Node *parent = node->par; + Node *grandParent = parent->par; + + parent->right = node->left; + if (node->left != NULL) + { + node->left->par = parent; + } + node->par = grandParent; + parent->par = node; + node->left = parent; + if (grandParent != NULL) + { + if (grandParent->right == parent) + { + grandParent->right = node; + } + else + { + grandParent->left = node; + } + } + return node; +} + +// Right Rotate +Node *rightRotate(Node *node) +{ + Node *parent = node->par; + Node *grandParent = parent->par; + + parent->left = node->right; + if (node->right != NULL) + { + node->right->par = parent; + } + node->par = grandParent; + parent->par = node; + node->right = parent; + if (grandParent != NULL) + { + if (grandParent->right == parent) + { + grandParent->right = node; + } + else + { + grandParent->left = node; + } + } + return node; +} + +// Check the node after the insertion step +void checkNode(Node *node) +{ + // If the node is the root + if (node == NULL || node->par == NULL) + { + return; + } + Node *child = node; + // If it is a black node or its parent is a black node + if (node->color == 0 || (node->par)->color == 0) + { + // Dont Do Anything + return; + } + + // Both parent and child are red + // Check For Uncle + Node *parent = node->par; + Node *grandParent = parent->par; + + // If grandParent is NULL, then parent is the root. + // Just make the root black. + if (grandParent == NULL) + { + parent->color = 0; + return; + } + + // If both the children of the grandParent are red + if (grandParent->right != NULL && (grandParent->right)->color == 1 && + grandParent->left != NULL && (grandParent->left)->color == 1) + { + // Make the grandParent red and both of its children black + (grandParent->right)->color = 0; + (grandParent->left)->color = 0; + grandParent->color = 1; + return; + } + else + { + // The only option left is rotation. + Node *greatGrandParent = grandParent->par; + // Right Case + if (grandParent->right == parent) + { + // Right Right Case + if (parent->right == node) + { + grandParent->right = parent->left; + if (parent->left != NULL) + { + (parent->left)->par = grandParent; + } + parent->left = grandParent; + grandParent->par = parent; + + // Attach to existing Tree; + parent->par = greatGrandParent; + if (greatGrandParent != NULL) + { + if (greatGrandParent->left != NULL && + greatGrandParent->left == grandParent) + { + greatGrandParent->left = parent; + } + else + { + greatGrandParent->right = parent; + } + } + + // Change the colors + parent->color = 0; + grandParent->color = 1; + } + else + { // Right Left Case + // First step -> Parent Child Rotation + parent->left = child->right; + if (child->right != NULL) + { + (child->right)->par = parent; + } + child->right = parent; + parent->par = child; + + // Second step -> Child and GrandParent Rotation + grandParent->right = child->left; + if (child->left != NULL) + { + (child->left)->par = grandParent; + } + child->left = grandParent; + grandParent->par = child; + + // Attach to the existing tree + child->par = greatGrandParent; + if (greatGrandParent != NULL) + { + if (greatGrandParent->left != NULL && + greatGrandParent->left == grandParent) + { + greatGrandParent->left = child; + } + else + { + greatGrandParent->right = child; + } + } + + // Change The Colors + child->color = 0; + grandParent->color = 1; + } + } + else + { // Left Case + // Left Left Case + if (parent->left == node) + { + grandParent->left = parent->right; + if (parent->right != NULL) + { + (parent->right)->par = grandParent; + } + parent->right = grandParent; + grandParent->par = parent; + + // Attach to existing Tree; + parent->par = greatGrandParent; + if (greatGrandParent != NULL) + { + if (greatGrandParent->left != NULL && + greatGrandParent->left == grandParent) + { + greatGrandParent->left = parent; + } + else + { + greatGrandParent->right = parent; + } + } + + // Change the colors + parent->color = 0; + grandParent->color = 1; + } + else + { // Left Right Case + + // First step -> Parent Child Rotation + parent->right = child->left; + if (child->left != NULL) + { + (child->left)->par = parent; + } + child->left = parent; + parent->par = child; + + // Second step -> Child and GrandParent Rotation + grandParent->left = child->right; + if (child->right != NULL) + { + (child->right)->par = grandParent; + } + child->right = grandParent; + grandParent->par = child; + + // Attach to the existing tree + child->par = greatGrandParent; + if (greatGrandParent != NULL) + { + if (greatGrandParent->left != NULL && + greatGrandParent->left == grandParent) + { + greatGrandParent->left = child; + } + else + { + greatGrandParent->right = child; + } + } + + // Change The Colors + child->color = 0; + grandParent->color = 1; + } + } + } +} + +// To insert a node in the existing tree +void insertNode(int val, Node **root) +{ + Node *buffRoot = *root; + while (buffRoot) + { + if (buffRoot->val > val) + { + // Go left + if (buffRoot->left != NULL) + { + buffRoot = buffRoot->left; + } + else + { + // Insert The Node + Node *toInsert = newNode(val, buffRoot); + buffRoot->left = toInsert; + buffRoot = toInsert; + + // Check For Double Red Problems + break; + } + } + else + { + // Go right + if (buffRoot->right != NULL) + { + buffRoot = buffRoot->right; + } + else + { + // Insert The Node + Node *toInsert = newNode(val, buffRoot); + buffRoot->right = toInsert; + buffRoot = toInsert; + + // Check For Double Red Problems + break; + } + } + } + + while (buffRoot != *root) + { + checkNode(buffRoot); + if (buffRoot->par == NULL) + { + *root = buffRoot; + break; + } + buffRoot = buffRoot->par; + if (buffRoot == *root) + { + buffRoot->color = 0; + } + } +} + +void checkForCase2(Node *toDelete, int delete, int fromDirection, Node **root) +{ + if (toDelete == (*root)) + { + (*root)->color = 0; + return; + } + + if (!delete &&toDelete->color == 1) + { + if (!fromDirection) + { + if (toDelete->right != NULL) + { + toDelete->right->color = 1; + } + } + else + { + if (toDelete->left != NULL) + { + toDelete->left->color = 1; + } + } + toDelete->color = 0; + return; + } + + // Get the sibling for further inspection + Node *sibling; + Node *parent = toDelete->par; + int locateChild = 0; // 0 if toDeleted is left of its parent else 1 + if (parent->right == toDelete) + { + sibling = parent->left; + locateChild = 1; + } + else + { + sibling = parent->right; + } + + // Case 2.1. i.e. if the any children of the sibling is red + if ((sibling->right != NULL && sibling->right->color == 1) || + (sibling->left != NULL && sibling->left->color == 1)) + { + if (sibling->right != NULL && sibling->right->color == 1) + { + // Sibling is left and child is right. i.e. LEFT RIGHT ROTATION + if (locateChild == 1) + { + int parColor = parent->color; + + // Step 1: Left rotate sibling + sibling = leftRotate(sibling->right); + + // Step 2: Right rotate updated sibling + parent = rightRotate(sibling); + + // Check if the root is rotated + if (parent->par == NULL) + { + *root = parent; + } + + // Step 3: Update the colors + parent->color = parColor; + parent->left->color = 0; + parent->right->color = 0; + + // Delete the node (present at parent->right->right) + if (delete) + { + if (toDelete->left != NULL) + { + toDelete->left->par = parent->right; + } + parent->right->right = toDelete->left; + free(toDelete); + } + } + else + { // Sibling is right and child is also right. i.e. LEFT LEFT + // ROTATION + + int parColor = parent->color; + + // Left Rotate the sibling + parent = leftRotate(sibling); + + // Check if the root is rotated + if (parent->par == NULL) + { + *root = parent; + } + + // Update Colors + parent->color = parColor; + parent->left->color = 0; + parent->right->color = 0; + + // Delete the node (present at parent->left->left) + if (delete) + { + if (toDelete->right != NULL) + { + toDelete->right->par = parent->left; + } + parent->left->left = toDelete->left; + free(toDelete); + } + } + } + else + { + // Sibling is right and child is left. i.e. RIGHT LEFT ROTATION + if (locateChild == 0) + { + int parColor = parent->color; + + // Step 1: Right rotate sibling + sibling = rightRotate(sibling->left); + + // printf("%d - reached\n", sibling->val); + // return; + + // Step 2: Left rotate updated sibling + parent = leftRotate(sibling); + + // Check if the root is rotated + if (parent->par == NULL) + { + *root = parent; + } + + // Step 3: Update the colors + parent->color = parColor; + parent->left->color = 0; + parent->right->color = 0; + + // Delete the node (present at parent->left->left) + if (delete) + { + if (toDelete->right != NULL) + { + toDelete->right->par = parent->left; + } + parent->left->left = toDelete->right; + free(toDelete); + } + } + else + { // Sibling is left and child is also left. i.e. RIGHT RIGHT + // ROTATION + + int parColor = parent->color; + + // Right Rotate the sibling + parent = rightRotate(sibling); + + // Check if the root is rotated + if (parent->par == NULL) + { + *root = parent; + } + + // Update Colors + parent->color = parColor; + parent->left->color = 0; + parent->right->color = 0; + + // Delete the node (present at parent->right->right) + if (delete) + { + if (toDelete->left != NULL) + { + toDelete->left->par = parent->right; + } + parent->right->right = toDelete->left; + free(toDelete); + } + } + } + } + else if (sibling->color == 0) + { // Make the sibling red and recur for its parent + + // Recolor the sibling + sibling->color = 1; + + // Delete if necessary + if (delete) + { + if (locateChild) + { + toDelete->par->right = toDelete->left; + if (toDelete->left != NULL) + { + toDelete->left->par = toDelete->par; + } + } + else + { + toDelete->par->left = toDelete->right; + if (toDelete->right != NULL) + { + toDelete->right->par = toDelete->par; + } + } + } + + checkForCase2(parent, 0, locateChild, root); + } + else + { // Bring the sibling on top and apply 2.1 or 2.2 accordingly + if (locateChild) + { // Right Rotate + + toDelete->par->right = toDelete->left; + if (toDelete->left != NULL) + { + toDelete->left->par = toDelete->par; + } + + parent = rightRotate(sibling); + + // Check if the root is rotated + if (parent->par == NULL) + { + *root = parent; + } + + parent->color = 0; + parent->right->color = 1; + checkForCase2(parent->right, 0, 1, root); + } + else + { // Left Rotate + + toDelete->par->left = toDelete->right; + if (toDelete->right != NULL) + { + toDelete->right->par = toDelete->par; + } + parent = leftRotate(sibling); + + // Check if the root is rotated + if (parent->par == NULL) + { + *root = parent; + } + + printf("\nroot - %d - %d\n", parent->val, parent->left->val); + + parent->color = 0; + parent->left->color = 1; + checkForCase2(parent->left, 0, 0, root); + } + } +} + +// To delete a node from the tree +void deleteNode(int val, Node **root) +{ + Node *buffRoot = *root; + + // Search for the element in the tree + while (1) + { + if (val == buffRoot->val) + { + // Node Found + break; + } + + if (val > buffRoot->val) + { + if (buffRoot->right != NULL) + { + buffRoot = buffRoot->right; + } + else + { + printf("Node Not Found!!!"); + return; + } + } + else + { + if (buffRoot->left != NULL) + { + buffRoot = buffRoot->left; + } + else + { + printf("Node Not Found!!!"); + return; + } + } + } + + Node *toDelete = buffRoot; + + // Look for the leftmost of right node or right most of left node + if (toDelete->left != NULL) + { + toDelete = toDelete->left; + while (toDelete->right != NULL) + { + toDelete = toDelete->right; + } + } + else if (toDelete->right != NULL) + { + toDelete = toDelete->right; + while (toDelete->left != NULL) + { + toDelete = toDelete->left; + } + } + + if (toDelete == *root) + { + *root = NULL; + return; + } + + // Swap the values + buffRoot->val = toDelete->val; + toDelete->val = val; + + // Checking for case 1 + if (toDelete->color == 1 || + (toDelete->left != NULL && toDelete->left->color == 1) || + (toDelete->right != NULL && toDelete->right->color == 1)) + { + // if it is a leaf + if (toDelete->left == NULL && toDelete->right == NULL) + { + // Delete instantly + if (toDelete->par->left == toDelete) + { + toDelete->par->left = NULL; + } + else + { + toDelete->par->right = NULL; + } + } + else + { // else its child should be red + + // Check for the exitstence of left node + if (toDelete->left != NULL) + { + // The node should be right to its parent + toDelete->par->right = toDelete->left; + toDelete->left->par = toDelete->par; + toDelete->left->color = 1; + } + else + { // else the right node should be red + toDelete->par->left = toDelete->right; + toDelete->right->par = toDelete->par; + toDelete->right->color = 1; + } + } + + // Remove the node from memory + free(toDelete); + } + else + { // Case 2 + checkForCase2(toDelete, 1, ((toDelete->par->right == toDelete)), root); + } +} + +void printInorder(Node *root) +{ + if (root != NULL) + { + printInorder(root->left); + printf("%d c-%d ", root->val, root->color); + printInorder(root->right); + } +} + +void checkBlack(Node *temp, int c) +{ + if (temp == NULL) + { + printf("%d ", c); + return; + } + if (temp->color == 0) + { + c++; + } + checkBlack(temp->left, c); + checkBlack(temp->right, c); +} + +int main() +{ + Node *root = NULL; + int scanValue, choice = 1; + printf( + "1 - Input\n2 - Delete\n3 - Inorder Traversel\n0 - Quit\n\nPlease " + "Enter the Choice - "); + scanf("%d", &choice); + while (choice) + { + switch (choice) + { + case 1: + printf("\n\nPlease Enter A Value to insert - "); + scanf("%d", &scanValue); + if (root == NULL) + { + root = newNode(scanValue, NULL); + root->color = 0; + } + else + { + insertNode(scanValue, &root); + } + printf("\nSuccessfully Inserted %d in the tree\n\n", scanValue); + break; + case 2: + printf("\n\nPlease Enter A Value to Delete - "); + scanf("%d", &scanValue); + deleteNode(scanValue, &root); + printf("\nSuccessfully Inserted %d in the tree\n\n", scanValue); + break; + case 3: + printf("\nInorder Traversel - "); + printInorder(root); + printf("\n\n"); + // checkBlack(root,0); + // printf("\n"); + break; + default: + if (root != NULL) + { + printf("Root - %d\n", root->val); + } + } + printf( + "1 - Input\n2 - Delete\n3 - Inorder Traversel\n0 - " + "Quit\n\nPlease Enter the Choice - "); + scanf("%d", &choice); + } +} + +// 32 12 50 53 1 2 3 4 5 6 7 8 9 diff --git a/data_structures/binary_trees/segment_tree.c b/data_structures/binary_trees/segment_tree.c new file mode 100644 index 0000000000..c50bae1853 --- /dev/null +++ b/data_structures/binary_trees/segment_tree.c @@ -0,0 +1,235 @@ +/** + * @file segment_tree.c + * @brief segment trees with only point updates + * @details + * This code implements segment trees. Segment trees are general structures + * which allow range based queries in a given array in logN time. + * Segment tree with point updates allow update of single element in the array + * in logN time. + * [Learn more about segment trees + * here](https://codeforces.com/blog/entry/18051) + * @author [Lakhan Nad](https://github.com/Lakhan-Nad) + */ + +#include /* for assert */ +#include /* for int32 */ +#include /* for scanf printf */ +#include /* for malloc, free */ +#include /* for memcpy, memset */ + +/** + * Function that combines two data to generate a new one + * The name of function might be misleading actually combine here signifies the + * fact that in segment trees we take partial result from two ranges and using + * partial results we derive the result for joint range of those two ranges + * For Example: array(1,2,3,4,5,6) sum of range [0,2] = 6 + * and sum of range [3,5] = 15 the combined sum of two range is 6+15=21 + * @note The function is same to binary function in Discrete Mathematics + * @param a pointer to first data + * @param b pointer to second data + * @param result pointer to memory location where result of combining a and b is + * to be stored + */ +typedef void (*combine_function)(const void *a, const void *b, void *result); + +/** + * This structures holds all the data that is required by a segment tree + */ +typedef struct segment_tree +{ + void *root; /**< the root of formed segment tree */ + void *identity; /**< identity element for combine function */ + size_t elem_size; /**< size in bytes of each data element */ + size_t length; /**< total size of array which segment tree represents*/ + /** the function to be used to combine two node's + * data to form parent's data + */ + combine_function combine; +} segment_tree; + +/** + * Builds a Segment tree + * It is assumed that leaves of tree already contains data. + * @param tree pointer to segment tree to be build + */ +void segment_tree_build(segment_tree *tree) +{ + size_t elem_size = tree->elem_size; + int index = (tree->length - 2); + size_t b, l, r; + char *ptr = (char *)tree->root; + for (; index >= 0; index--) + { + b = index * elem_size; + l = (2 * index + 1) * elem_size; + r = (2 * index + 2) * elem_size; + tree->combine(ptr + l, ptr + r, ptr + b); + } +} + +/** + * For point updates + * This function updates the element at given index and also updates segment + * tree accordingly + * + * @param tree pointer to segment tree + * @param index the index whose element is to be updated (0 based indexing used) + * @param val pointer to value that is to be replaced at given index + */ +void segment_tree_update(segment_tree *tree, size_t index, void *val) +{ + size_t elem_size = tree->elem_size; + index = index + tree->length - 1; + char *base = (char *)tree->root; + char *t = base + index * elem_size; + memcpy(t, val, elem_size); + while (index > 0) + { + index = ((index - 1) >> 1); + tree->combine(base + (2 * index + 1) * elem_size, + base + (2 * index + 2) * elem_size, + base + index * elem_size); + } +} + +/** + * Query the segment tree + * This function helps in range query of segment tree + * This function assumes that the given range is valid + * Performs the query in range [l,r] + * @param tree pointer to segment tree + * @param l the start of range + * @param r the end of range + * @param res the pointer to memory where result of query is stored + */ +void segment_tree_query(segment_tree *tree, long long l, long long r, void *res) +{ + size_t elem_size = tree->elem_size; + memcpy(res, tree->identity, elem_size); + elem_size = tree->elem_size; + char *root = (char *)tree->root; + l += tree->length - 1; + r += tree->length - 1; + while (l <= r) + { + if (!(l & 1)) + { + tree->combine(res, root + l * elem_size, res); + } + if (r & 1) + { + tree->combine(res, root + r * elem_size, res); + } + r = (r >> 1) - 1; + l = (l >> 1); + } +} + +/** + * Initializes Segment Tree + * Accquires memory for segment tree + * and fill the leaves of segment tree with data from array + * @param arr the array data upon which segment tree is build + * @param elem_size size of each element in segment tree + * @param len total no of elements in array + * @param identity the identity element for combine_function + * @param func the combine_function used to build segment tree + * + * @returns pointer to sgement tree build + */ +segment_tree *segment_tree_init(void *arr, size_t elem_size, size_t len, + void *identity, combine_function func) +{ + segment_tree *tree = malloc(sizeof(segment_tree)); + tree->elem_size = elem_size; + tree->length = len; + tree->combine = func; + tree->root = malloc(sizeof(char) * elem_size * (2 * len - 1)); + tree->identity = malloc(sizeof(char) * elem_size); + char *ptr = (char *)tree->root; + memset(ptr, 0, (len - 1) * elem_size); // Initializing memory + ptr = ptr + (len - 1) * elem_size; + memcpy(ptr, arr, elem_size * len); // copy the leaf nodes i.e. array data + memcpy(tree->identity, identity, elem_size); // copy identity element + return tree; +} + +/** + * Dispose Segment Tree + * Frees all heap memory accquired by segment tree + * @param tree pointer to segment tree + */ +void segment_tree_dispose(segment_tree *tree) +{ + free(tree->root); + free(tree->identity); +} + +/** + * Prints the data in segment tree + * The data should be of int type + * A utility to print segment tree + * with data type of int + * @param tree pointer to segment tree + */ +void segment_tree_print_int(segment_tree *tree) +{ + char *base = (char *)tree->root; + size_t i = 0; + for (; i < 2 * tree->length - 1; i++) + { + printf("%d ", *(int *)(base + i * tree->elem_size)); + } + printf("\n"); +} + +/** + * Utility for test + * A function compare for minimum between two integers + * This function is used as combine_function for RMQ + * @param a pointer to integer a + * @param b pointer to integer b + * @param c pointer where minimum of a and b is tored as result + */ +void minimum(const void *a, const void *b, void *c) +{ + *(int *)c = *(int *)a < *(int *)b ? *(int *)a : *(int *)b; +} + +/** + * Test RMQ + * Testing Segment tree using + * Range Minimum Queries + * @returns void + */ +static void test() +{ + int32_t arr[10] = {1, 0, 3, 5, 7, 2, 11, 6, -2, 8}; + int32_t identity = __INT32_MAX__; + segment_tree *tree = + segment_tree_init(arr, sizeof(*arr), 10, &identity, minimum); + segment_tree_build(tree); + int32_t result; + segment_tree_query(tree, 3, 6, &result); + assert(result == 2); + segment_tree_query(tree, 8, 9, &result); + assert(result == -2); + result = 12; + segment_tree_update(tree, 5, &result); + segment_tree_update(tree, 8, &result); + segment_tree_query(tree, 0, 3, &result); + assert(result == 0); + segment_tree_query(tree, 8, 9, &result); + assert(result == 8); + segment_tree_dispose(tree); +} + +/** + * @brief Main Function + * @returns 0 on exit + */ +int main() +{ + test(); + return 0; +} diff --git a/data_structures/binary_trees/threaded_binary_trees.c b/data_structures/binary_trees/threaded_binary_trees.c new file mode 100644 index 0000000000..6ef5f7280e --- /dev/null +++ b/data_structures/binary_trees/threaded_binary_trees.c @@ -0,0 +1,303 @@ +/** + * @file + * \brief This file is a simple implementation of a Threaded Binary Tree + * + * Threaded Binary Tree is a binary tree variant in which all left child + * pointers that are NULL (in Linked list representation) point to its + * in-order predecessor, and all right child pointers that are NULL + * (in Linked list representation) point to its in-order successor. + * It has the following functionalities: + * - Insertion + * - Search + * - Deletion + * - Listing of node keys inorder,preorder,postorder + * + * -see binary_search_tree.c + * + * \author [Amitha Nayak](https://github.com/amitnayakblr) + */ + +#include +#include + +/** + * Node, the basic data structure of the tree + */ +typedef struct Node +{ + int data; /**< stores the number */ + struct Node *llink; /**< link to left child */ + struct Node *rlink; /**< link to right child */ +} node; + +/** + * creates a new node + * param[in] data value to be inserted + * \returns a pointer to the new node + */ +node *create_node(int data) +{ + node *ptr = (node *)malloc(sizeof(node)); + ptr->rlink = ptr->llink = NULL; + ptr->data = data; + return ptr; +} + +/** + * inserts a node into the tree + * param[in,out] root pointer to node pointer to the topmost node of the tree + * param[in] data value to be inserted into the tree + */ +void insert_bt(node **root, int data) +{ + node *new_node = create_node(data); + node *temp; // to be deleted + node *prev; // keeps track of the parent of the element deleted + if (*root == NULL) + { + *root = new_node; + } + else + { + temp = *root; + prev = NULL; + while (temp != NULL) + { + if (new_node->data > temp->data) + { + prev = temp; + temp = temp->rlink; + } + else if (new_node->data < temp->data) + { + prev = temp; + temp = temp->llink; + } + else + { + return; + } + } + + if (new_node->data > prev->data) + { + prev->rlink = new_node; + } + else + { + prev->llink = new_node; + } + } +} + +/** + * searches for the element + * \param[in] root node pointer to the topmost node of the tree + * \param[in] ele value searched for + */ +void search(node *root, int ele) +{ + node *temp = root; + while (temp != NULL) + { + if (temp->data == ele) + { + break; + } + else if (ele > temp->data) + { + temp = temp->rlink; + } + else + { + temp = temp->llink; + } + } + + if (temp == NULL) + { + printf("%s\n", "Element not found."); + } + else + printf("%s\n", "Element found."); +} + +/** + * performs inorder traversal + * param[in] curr node pointer to the topmost node of the tree + */ +void inorder_display(node *curr) +{ + if (curr != NULL) + { + inorder_display(curr->llink); + printf("%d\t", curr->data); + inorder_display(curr->rlink); + } +} + +/** + * performs postorder traversal + * param[in] curr node pointer to the topmost node of the tree + */ +void postorder_display(node *curr) +{ + if (curr != NULL) + { + postorder_display(curr->llink); + postorder_display(curr->rlink); + printf("%d\t", curr->data); + } +} + +/** + * performs preorder traversal + * param[in] curr node pointer to the topmost node of the tree + */ +void preorder_display(node *curr) +{ + if (curr != NULL) + { + printf("%d\t", curr->data); + preorder_display(curr->llink); + preorder_display(curr->rlink); + } +} + +/** + * deletion of a node from the tree + * if the node isn't present in the tree, it takes no action. + * param[in,out] root pointer to node pointer to the topmost node of the tree + * param[in] ele value to be deleted from the tree + */ +void delete_bt(node **root, int ele) +{ + node *temp; + node *prev; + if (*root == NULL) + return; + else + { + temp = *root; + prev = NULL; + // search + while (temp != NULL) + { + if (temp->data == ele) + { + break; + } + else if (ele > temp->data) + { + prev = temp; + temp = temp->rlink; + } + else + { + prev = temp; + temp = temp->llink; + } + } + } + + if (temp == NULL) + return; + else + { + node *replacement; // deleted node's replacement + node *t; + if (temp->llink == NULL && temp->rlink == NULL) + { + replacement = NULL; + } + else if (temp->llink == NULL && temp->rlink != NULL) + { + replacement = temp->rlink; + } + else if (temp->llink != NULL && temp->rlink == NULL) + { + replacement = temp->llink; + } + else + { + replacement = temp->rlink; // replaced with inorder successor + t = replacement; + while (t->llink != NULL) + { + t = t->llink; + } + t->llink = + temp->llink; // leftmost node of the replacement is linked to + // the left child of the deleted node + } + + if (temp == *root) + { + free(*root); + *root = replacement; + } + else if (prev->llink == temp) + { + free(prev->llink); + prev->llink = replacement; + } + else if (prev->rlink == temp) + { + free(prev->rlink); + prev->rlink = replacement; + } + } +} + +/** + * main function + */ +int main() +{ + printf("BINARY THREADED TREE: \n"); + node *root = NULL; + int choice, n; + do + { + printf("%s\n", "1. Insert into BT"); + printf("%s\n", "2. Print BT - inorder"); + printf("%s\n", "3. Print BT - preorder"); + printf("%s\n", "4. print BT - postorder"); + printf("%s\n", "5. delete from BT"); + printf("%s\n", "6. search in BT"); + printf("%s\n", "Type 0 to exit"); + scanf("%d", &choice); + + switch (choice) + { + case 1: + printf("%s\n", "Enter a no:"); + scanf("%d", &n); + insert_bt(&root, n); + break; + case 2: + inorder_display(root); + printf("\n"); + break; + case 3: + preorder_display(root); + printf("\n"); + break; + case 4: + postorder_display(root); + printf("\n"); + break; + case 5: + printf("%s\n", "Enter a no:"); + scanf("%d", &n); + delete_bt(&root, n); + break; + case 6: + printf("%s\n", "Enter a no:"); + scanf("%d", &n); + search(root, n); + break; + } + } while (choice != 0); + return 0; +} diff --git a/data_structures/binary_trees/words_alphabetical.c b/data_structures/binary_trees/words_alphabetical.c new file mode 100644 index 0000000000..46508f48c2 --- /dev/null +++ b/data_structures/binary_trees/words_alphabetical.c @@ -0,0 +1,316 @@ +/** + * @file + * @brief Printing the [words contained in a + * file](http://www.dailyfreecode.com/Code/word-list-reads-text-file-makes-2050.aspx) + * named `file.txt` in alphabetical order and also their frequencies in to + * another file "wordcount.txt" + * @details + * Given a file (`file.txt`) containing words (like a publication or a novel), + * where words are separated by a space, newline, or underscore. + * This program prints (writes or outputs) to another file (`wordcount.txt`), + * the individual words contained in 'file.txt' with their frequencies (number + * of occurrences) each on a newline and in alphabetical order. This program uses + * the binary tree data structure to accomplish this task. + * @author [Randy Kwalar](https://github.com/RandyKdev) + */ + +#include /// for assert +#include /// for type checks +#include /// for uint64_t based types, int64_t based types +#include /// for boolean data type +#include /// for IO operations +#include /// for memory allocation +#include /// for string operations + +/** + * @brief structure defining a node in the binary tree + */ +struct Node +{ + char *word; ///< the word (value) of the node + uint64_t frequency; ///< number of occurrences of the word + struct Node *left; ///< pointer to the left child node + struct Node *right; ///< pointer to the right child node +}; + +/** + * @brief Ends program due to an error + * @param errorMessage the error message to be printed + * @returns void + */ +void endProgramAbruptly(char *errorMessage) +{ + fprintf(stderr, "%s\n", errorMessage); + exit(EXIT_FAILURE); +} + +/** + * @brief Frees memory when program is terminating + * @param node pointer to current node + * @returns void + */ +void freeTreeMemory(struct Node *node) +{ + if (node != NULL) + { + freeTreeMemory(node->left); + freeTreeMemory(node->right); + free(node->word); // freeing node->word because memory was allocated + // using malloc + free(node); // freeing node because memory was allocated using malloc + } +} + +/** + * @brief Stores word in memory + * @param word word to be stored in memory + * @returns a pointer to the newly allocated word if the word IS stored successfully + * @returns `NULL` if the word is NOT stored + */ +char *getPointerToWord(char *word) +{ + char *string = + (char *)malloc((strlen(word) + 1) * sizeof(char)); ///< pointer to string + // + 1 is for the '\0' character + if (string != NULL) + { + strcpy(string, word); + return string; + } + endProgramAbruptly( + "\nA problem occurred while reserving memory for the word\n"); + return NULL; +} + +/** + * @brief Closes the file after reading or writing + * @param file pointer to the file to be closed + * @returns void + */ +void closeFile(FILE *file) +{ + if (fclose(file)) { + endProgramAbruptly("\nA Problem Occurred while closing a file\n"); + } +} + +/** + * @brief Reserves memory for new node + * @returns a pointer to the newly allocated node if memory IS successfully reserved + * @returns `NULL` if memory is NOT reserved + */ +struct Node *allocateMemoryForNode() +{ + struct Node *node = + (struct Node *)malloc(sizeof(struct Node)); ///< pointer to the node + if (node != NULL) + { + return node; + } + endProgramAbruptly( + "\nA problem occurred while reserving memory for the structure\n"); + return NULL; +} + +/** + * @brief Writes contents of tree to another file alphabetically + * @param node pointer to current node + * @param file pointer to file + * @returns void + */ +void writeContentOfTreeToFile(struct Node *node, FILE *file) +{ + static uint64_t i = 1; ///< for word numbering in the write file + if (node != NULL) // checks if the node is valid + { + writeContentOfTreeToFile( + node->left, + file); // calls `writeContentOfTreeToFile` for left sub tree + fprintf(file, "%-5lu \t %-9lu \t %s \n", i++, node->frequency, + node->word); // prints the word number, word frequency and word + // in tabular format to the file + writeContentOfTreeToFile( + node->right, + file); // calls `writeContentOfTreeToFile` for right sub tree + } +} + +/** + * @brief Adds word (node) to the correct position in tree + * @param word word to be inserted in to the tree + * @param currentNode node which is being compared + * @returns a pointer to the root node + */ +struct Node *addWordToTree(char *word, struct Node *currentNode) +{ + if (currentNode == NULL) // checks if `currentNode` is `NULL` + { + struct Node *currentNode = + allocateMemoryForNode(); // allocates memory for new node + currentNode->word = getPointerToWord(word); // stores `word` in memory + currentNode->frequency = 1; // initializes the word frequency to 1 + currentNode->left = NULL; // sets left node to `NULL` + currentNode->right = NULL; // sets right node to `NULL` + return currentNode; // returns pointer to newly created node + } + + int64_t compared = strcmp(word, currentNode->word); ///< holds compare state + + if (compared > 0) { + currentNode->right = addWordToTree(word, + currentNode->right); // adds `word` to right sub tree if `word` is + // alphabetically greater than `currentNode->word` + } + else if (compared < 0) { + currentNode->left = addWordToTree(word, + currentNode->left); // adds `word` to left sub tree if `word` is + // alphabetically less than `currentNode->word` + } + else { + currentNode->frequency++; // increments `currentNode` frequency if `word` is the same as `currentNode->word` + } + + return currentNode; // returns pointer to current node +} + +/** + * @brief Reads words from file to tree + * @param file file to be read from + * @param root root node of tree + * @returns a pointer to the root node + */ +struct Node *readWordsInFileToTree(FILE *file, struct Node *root) +{ + // longest english word = 45 chars + // +1 for '\0' = 46 chars + char *inputString = + (char *)malloc(46 * sizeof(char)); ///< pointer to the input string + + char inputChar; ///< temp storage of characters + bool isPrevCharAlpha = false; ///< bool to mark the end of a word + uint8_t pos = 0; ///< position in inputString to place the inputChar + + while ((inputChar = fgetc(file)) != EOF) + { + if (pos > 0) + isPrevCharAlpha = isalpha(inputString[pos - 1]); + + // checks if character is letter + if (isalpha(inputChar)) + { + inputString[pos++] = tolower(inputChar); + continue; + } + + // checks if character is ' or - and if it is preceded by a letter eg + // yours-not, persons' (valid) + if ((inputChar == '\'' || inputChar == '-') && isPrevCharAlpha) + { + inputString[pos++] = inputChar; + continue; + } + + // makes sure that there is something valid in inputString + if (pos == 0) + continue; + + // if last character is not letter and is not ' then replace by \0 + if (!isPrevCharAlpha && inputString[pos - 1] != '\'') + pos--; + inputString[pos] = '\0'; + pos = 0; + isPrevCharAlpha = false; + root = addWordToTree(inputString, root); + } + + // this is to catch the case for the EOF being immediately after the last + // letter or ' + if (pos > 0) + { + if (!isPrevCharAlpha && inputString[pos - 1] != '\'') + pos--; + inputString[pos] = '\0'; + root = addWordToTree(inputString, root); + } + + free(inputString); + return root; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() +{ + struct Node *root = NULL; ///< pointer to the root node + FILE *file = NULL; ///< pointer to the file + + file = fopen("file.txt", "w"); // creates test file in write mode + + fprintf(file, + "hey_this, is a. test input \n to a_file"); // writes test data to + // test file + + closeFile(file); // closes test file + file = fopen("file.txt", "r"); // reopens test file in read mode + + root = readWordsInFileToTree(file, + root); // reads words from test file to tree + + // Tests to check if words were added to correct position in tree and also + // if their frequencies were added correctly + assert(strcmp(root->word, "hey") == 0); + assert(root->frequency == 1); + assert(strcmp(root->left->word, "a") == 0); + assert(root->left->frequency == 2); + assert(strcmp(root->right->word, "this") == 0); + assert(strcmp(root->left->right->word, "file") == 0); + assert(strcmp(root->right->left->word, "is") == 0); + + closeFile(file); // closes test file + remove("file.txt"); // deletes test file from storage + + file = fopen("wordcount.txt", "a"); // creates write file + fprintf(file, "%-5s \t %9s \t %s \n", "S/N", "FREQUENCY", + "WORD"); // prints the heading to `wordcount.txt` + writeContentOfTreeToFile( + root, file); // writes content of tree to file (`wordcount.txt`) + + // Here is how the output to `wordcount.txt` should look like + char *correctString = + "S/N FREQUENCY WORD \n" + "1 2 a \n" + "2 1 file \n" + "3 1 hey \n" + "4 1 input \n" + "5 1 is \n" + "6 1 n \n" + "7 1 test \n" + "8 1 this \n" + "9 1 to \n"; + + int16_t inputChar; // holds the current character in `wordcount.txt` + uint64_t i = 0; // holds the current index in `correctString` + + // Checks if the content in `wordcount.txt` is as expected (the same as in + // `correctString`) + while ((inputChar = fgetc(file)) != EOF) { + assert(inputChar == correctString[i++]); + } + + closeFile(file); // closes `wordcount.txt` + remove("wordcount.txt"); // deletes `wordcount.txt` + + freeTreeMemory(root); // frees memory taken up by the tree +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + test(); // run self-test implementations + return 0; +} diff --git a/data_structures/dictionary/dict.c b/data_structures/dictionary/dict.c index 8e8a646251..e0bc2a5062 100644 --- a/data_structures/dictionary/dict.c +++ b/data_structures/dictionary/dict.c @@ -1,32 +1,30 @@ +#include "dict.h" #include #include -#include "dict.h" - /* simple constructor */ -Dictionary * create_dict(void) +Dictionary *create_dict(void) { - Dictionary * p_dic = malloc(sizeof (Dictionary)); + Dictionary *p_dic = malloc(sizeof(Dictionary)); if (p_dic) { p_dic->number_of_elements = 0; /* initializes the elemens of the array with NULL-pointer */ - for (int i = 0; i < MAXELEMENTS; i++) + for (int i = 0; i < MAXELEMENTS; i++) { p_dic->elements[i] = NULL; } return p_dic; } - else + else { printf("unable to create a dictionary\n"); return NULL; } } - /* utility function sdbm hash algorithm @@ -37,18 +35,18 @@ int get_hash(char s[]) unsigned int hash_code = 0; /* iterates over string at each character */ - for (int counter = 0; s[counter]!='\0'; counter++) + for (int counter = 0; s[counter] != '\0'; counter++) { /* actual computing of the hash code */ - hash_code = s[counter] + (hash_code << 6) + (hash_code << 16) - hash_code; + hash_code = + s[counter] + (hash_code << 6) + (hash_code << 16) - hash_code; } /* % modulo is for fitting the index in array. */ return hash_code % MAXELEMENTS; } - -int add_item_label(Dictionary * dic,char label[],void * item) +int add_item_label(Dictionary *dic, char label[], void *item) { unsigned int index = get_hash(label); @@ -57,28 +55,26 @@ int add_item_label(Dictionary * dic,char label[],void * item) { dic->elements[index] = item; return 0; - } - + } + /* error case */ - return -1; + return -1; } - -int add_item_index(Dictionary * dic , int index, void * item) +int add_item_index(Dictionary *dic, int index, void *item) { /* make sure whether this place is already given */ if (!dic->elements[index]) { dic->elements[index] = item; return 0; - } - + } + /* error case */ return -1; } - -void * get_element_label(Dictionary * dict, char s[]) +void *get_element_label(Dictionary *dict, char s[]) { int index = get_hash(s); if (dict->elements[index]) @@ -90,20 +86,15 @@ void * get_element_label(Dictionary * dict, char s[]) return NULL; } - -void * get_element_index(Dictionary * dict, int index) +void *get_element_index(Dictionary *dict, int index) { if (index >= 0 && index < MAXELEMENTS) { return dict->elements[index]; } - + printf("index out of bounds!\n"); return NULL; } - -void destroy(Dictionary * dict) -{ - free(dict); -} \ No newline at end of file +void destroy(Dictionary *dict) { free(dict); } \ No newline at end of file diff --git a/data_structures/dictionary/dict.h b/data_structures/dictionary/dict.h index 175a4dac58..520b3295f4 100644 --- a/data_structures/dictionary/dict.h +++ b/data_structures/dictionary/dict.h @@ -1,6 +1,6 @@ /* author: Christian Bender - public interface for the dictionary. + public interface for the dictionary. The dictionary prepares space for 1000 elements. */ @@ -14,13 +14,13 @@ special data type called 'Dictionary' for generic use */ -typedef struct Dict +typedef struct Dict { - /* + /* void* array for generic use of the dictionary. there actual saves the entries. */ - void * elements[MAXELEMENTS]; + void *elements[MAXELEMENTS]; /* contains the number of elements in this dictionary */ int number_of_elements; @@ -28,41 +28,38 @@ typedef struct Dict } Dictionary; /* - create_dict: is a simple constructor for creating - a dictionary and setting up the + create_dict: is a simple constructor for creating + a dictionary and setting up the member field 'number_of_elements' and prepares the inner array 'elements' */ -Dictionary * create_dict(void); +Dictionary *create_dict(void); -/* - add_item_label: adds item (void*) to the dictionary at given label +/* + add_item_label: adds item (void*) to the dictionary at given label returns 0 if adding was sucessful otherwise -1 */ -int add_item_label(Dictionary *,char label[],void *); +int add_item_label(Dictionary *, char label[], void *); -/* - add_item_index: adds item (void*) to the dictionary at given index (int) +/* + add_item_index: adds item (void*) to the dictionary at given index (int) returns 0 if adding was sucessful otherwise -1 */ int add_item_index(Dictionary *, int index, void *); - /* - get_element: returns the element at given label + get_element: returns the element at given label */ -void * get_element_label(Dictionary *, char []); - +void *get_element_label(Dictionary *, char[]); /* - get_element: returns the element at given index + get_element: returns the element at given index */ -void * get_element_index(Dictionary *, int ); +void *get_element_index(Dictionary *, int); -/* +/* simple destrcutor function */ void destroy(Dictionary *); - #endif \ No newline at end of file diff --git a/data_structures/dictionary/test_program.c b/data_structures/dictionary/test_program.c index 39ba7296e7..dabf2e774d 100644 --- a/data_structures/dictionary/test_program.c +++ b/data_structures/dictionary/test_program.c @@ -10,32 +10,32 @@ int main(void) { - Dictionary * testObj1; - Dictionary * testObj2; + Dictionary *testObj1; + Dictionary *testObj2; - int value = 28; + int value = 28; testObj1 = create_dict(); testObj2 = create_dict(); - add_item_label(testObj1,"age",&value); - add_item_label(testObj2,"name","Christian"); - + add_item_label(testObj1, "age", &value); + add_item_label(testObj2, "name", "Christian"); /* test for function add_item_label - attention: - The void* pointer must be convert into an int* pointer. + attention: + The void* pointer must be convert into an int* pointer. After that you can dereference it. */ - printf("My age is %d\n",*((int *)get_element_label(testObj1,"age"))); - printf("My name is %s\n",get_element_label(testObj2,"name")); + printf("My age is %d\n", *((int *)get_element_label(testObj1, "age"))); + printf("My name is %s\n", get_element_label(testObj2, "name")); /* test for function add_item_index */ - if (!add_item_index(testObj1,0,&value)) + if (!add_item_index(testObj1, 0, &value)) { - printf("My age at index %d is %d\n",0,*((int *)get_element_index(testObj1,0))); + printf("My age at index %d is %d\n", 0, + *((int *)get_element_index(testObj1, 0))); } /* error scenario */ diff --git a/data_structures/dynamic_array/Makefile b/data_structures/dynamic_array/Makefile new file mode 100644 index 0000000000..949ce8f1ce --- /dev/null +++ b/data_structures/dynamic_array/Makefile @@ -0,0 +1,13 @@ +CC = gcc +CFLAGS = -g -Wall + +all: main + +main: main.o dynamic_array.o + $(CC) $(CFLAGS) $^ -o $@ + +dynamic_array.o: dynamic_array.c + $(CC) $(CFLAGS) -c $^ + +clean: + rm *.o main diff --git a/data_structures/dynamic_array/dynamic_array.c b/data_structures/dynamic_array/dynamic_array.c new file mode 100644 index 0000000000..19631cb1d1 --- /dev/null +++ b/data_structures/dynamic_array/dynamic_array.c @@ -0,0 +1,81 @@ +#include "dynamic_array.h" +#include +#include +#include + +dynamic_array_t *init_dynamic_array() +{ + dynamic_array_t *da = malloc(sizeof(dynamic_array_t)); + da->items = calloc(DEFAULT_CAPACITY, sizeof(void *)); + da->capacity = DEFAULT_CAPACITY; + + return da; +} + +void *add(dynamic_array_t *da, const void *value) +{ + if (da->size >= da->capacity) + { + void **newItems = + realloc(da->items, (da->capacity <<= 1) * sizeof(void **)); + + da->items = newItems; + } + + void *copy_value = retrive_copy_of_value(value); + da->items[da->size++] = copy_value; + + return copy_value; +} + +void *put(dynamic_array_t *da, const void *value, const unsigned index) +{ + if (!contains(da->size, index)) + return INDEX_OUT_OF_BOUNDS; + + free(da->items[index]); + void *copy_value = retrive_copy_of_value(value); + da->items[index] = copy_value; + + return copy_value; +} + +void *get(dynamic_array_t *da, const unsigned index) +{ + if (!contains(da->size, index)) + return INDEX_OUT_OF_BOUNDS; + + return da->items[index]; +} + +void delete (dynamic_array_t *da, const unsigned index) +{ + if (!contains(da->size, index)) + return; + + for (unsigned i = index; i < da->size; i++) + { + da->items[i] = da->items[i + 1]; + } + + da->size--; + + free(da->items[da->size]); +} + +unsigned contains(const unsigned size, const unsigned index) +{ + if (size >= 0 && index < size) + return 1; + + printf("index [%d] out of bounds!\n", index); + return 0; +} + +void *retrive_copy_of_value(const void *value) +{ + void *value_copy = malloc(sizeof(void *)); + memcpy(value_copy, value, sizeof(void *)); + + return value_copy; +} diff --git a/data_structures/dynamic_array/dynamic_array.h b/data_structures/dynamic_array/dynamic_array.h new file mode 100644 index 0000000000..dce4a519c8 --- /dev/null +++ b/data_structures/dynamic_array/dynamic_array.h @@ -0,0 +1,27 @@ +#ifndef __DYNAMIC_ARRAY__ +#define __DYNAMIC_ARRAY__ +#define DEFAULT_CAPACITY 1 << 4 +#define INDEX_OUT_OF_BOUNDS NULL + +typedef struct dynamic_array +{ + void **items; + unsigned size; + unsigned capacity; +} dynamic_array_t; + +extern dynamic_array_t *init_dynamic_array(); + +extern void *add(dynamic_array_t *da, const void *value); + +extern void *put(dynamic_array_t *da, const void *value, unsigned index); + +extern void *get(dynamic_array_t *da, const unsigned index); + +extern void delete (dynamic_array_t *da, const unsigned index); + +unsigned contains(const unsigned size, const unsigned index); + +extern void *retrive_copy_of_value(const void *value); + +#endif \ No newline at end of file diff --git a/data_structures/dynamic_array/main.c b/data_structures/dynamic_array/main.c new file mode 100644 index 0000000000..0feb79017d --- /dev/null +++ b/data_structures/dynamic_array/main.c @@ -0,0 +1,35 @@ +#include +#include +#include "dynamic_array.h" + +int main() +{ + dynamic_array_t *da = init_dynamic_array(); + + for (int i = 1; i <= 50; i++) + { + add(da, &i); + } + + delete (da, 10); + + int value = 1000; + + put(da, &value, 0); + + value = 5000; + + int another_value = 7000; + + add(da, &another_value); + + for (int i = 0; i < da->size; i++) + { + printf("value %d\n", *(int *)get(da, i)); + } + + int value_for_invalid_index = 10000; + + put(da, &value_for_invalid_index, 150); + return 0; +} \ No newline at end of file diff --git a/data_structures/graphs/Bellman-Ford.c b/data_structures/graphs/Bellman-Ford.c deleted file mode 100644 index 2d7e2a3d55..0000000000 --- a/data_structures/graphs/Bellman-Ford.c +++ /dev/null @@ -1,130 +0,0 @@ -#include -#include -#include -#include - -//Structure for storing edge -struct Edge{ -int src,dst,weight; -}; - -//Structure for storing a graph -struct Graph{ - int vertexNum; - int edgeNum; - struct Edge* edges; -}; - -//Constructs a graph with V vertices and E edges -void createGraph(struct Graph* G,int V,int E){ - G->vertexNum = V; - G->edgeNum = E; - G->edges = (struct Edge*) malloc(E * sizeof(struct Edge)); -} - -//Adds the given edge to the graph -void addEdge(struct Graph* G, int src, int dst, int weight){ - static int ind; - struct Edge newEdge; - newEdge.src = src; - newEdge.dst = dst; - newEdge.weight = weight; - G->edges[ind++]= newEdge; -} - - -//Utility function to find minimum distance vertex in mdist -int minDistance(int mdist[], int vset[], int V){ - int minVal = INT_MAX, minInd ; - for(int i=0; ivertexNum; - int E = graph->edgeNum; - int dist[V]; - - //Initialize distances array as INF for all except source - //Intialize source as zero - for(int i=0; iedges[j].src; - int v = graph->edges[j].dst; - int w = graph->edges[j].weight; - - if(dist[u]!=INT_MAX && dist[u] + w < dist[v]) - dist[v] = dist[u] + w; - } - - //Iterate inner loop once more to check for negative cycle - for(int j = 0; jedges[j].src; - int v = graph->edges[j].dst; - int w = graph->edges[j].weight; - - if(dist[u]!=INT_MAX && dist[u] + w < dist[v]){ - printf("Graph contains negative weight cycle. Hence, shortest distance not guaranteed."); - return; - } - } - - print(dist, V); - - return; -} - - - -//Driver Function -int main(){ - int V,E,gsrc; - int src,dst,weight; - struct Graph G; - printf("Enter number of vertices: "); - scanf("%d",&V); - printf("Enter number of edges: "); - scanf("%d",&E); - createGraph(&G,V,E); - for(int i=0; i -#include -#include -#include - - -//Structure for storing a graph -struct Graph{ - int vertexNum; - int** edges; -}; - -//Constructs a graph with V vertices and E edges -void createGraph(struct Graph* G,int V){ - G->vertexNum = V; - G->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; - G->edges[i][i] = 0; - } -} - -//Adds the given edge to the graph -void addEdge(struct Graph* G, int src, int dst, int weight){ - G->edges[src][dst] = weight; -} - - -//Utility function to find minimum distance vertex in mdist -int minDistance(int mdist[], int vset[], int V){ - int minVal = INT_MAX, minInd ; - for(int i=0; ivertexNum; - int mdist[V]; //Stores updated distances to vertex - int vset[V]; // vset[i] is true if the vertex i included - // in the shortest path tree - - //Initialise mdist and vset. Set distance of source as zero - for(int i=0; iedges[u][v]!=INT_MAX && mdist[u] + graph->edges[u][v] < mdist[v]) - mdist[v] = mdist[u] + graph->edges[u][v]; - - } - } - - print(mdist, V); - - return; -} - - - -//Driver Function -int main(){ - int V,E,gsrc; - int src,dst,weight; - struct Graph G; - printf("Enter number of vertices: "); - scanf("%d",&V); - printf("Enter number of edges: "); - scanf("%d",&E); - createGraph(&G,V); - for(int i=0; i -#include -#include -#include - - -//Structure for storing a graph -struct Graph{ - int vertexNum; - int** edges; -}; - -//Constructs a graph with V vertices and E edges -void createGraph(struct Graph* G,int V){ - G->vertexNum = V; - G->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; - G->edges[i][i] = 0; - } -} - -//Adds the given edge to the graph -void addEdge(struct Graph* G, int src, int dst, int weight){ - G->edges[src][dst] = weight; -} - - -//Utility function to print distances -void print(int dist[], int V){ - printf("\nThe Distance matrix for Floyd - Warshall\n"); - for(int i = 0; i < V; i++){ - for(int j=0; jvertexNum; - int dist[V][V]; - - //Initialise distance array - for(int i=0; iedges[i][j]; - - - //Calculate distances - for(int k=0; k +#include +#include +#include + +// Structure for storing edge +struct Edge +{ + int src, dst, weight; +}; + +// Structure for storing a graph +struct Graph +{ + int vertexNum; + int edgeNum; + struct Edge *edges; +}; + +// Constructs a graph with V vertices and E edges +void createGraph(struct Graph *G, int V, int E) +{ + G->vertexNum = V; + G->edgeNum = E; + G->edges = (struct Edge *)malloc(E * sizeof(struct Edge)); +} + +// Adds the given edge to the graph +void addEdge(struct Graph *G, int src, int dst, int weight) +{ + static int ind; + struct Edge newEdge; + newEdge.src = src; + newEdge.dst = dst; + newEdge.weight = weight; + G->edges[ind++] = newEdge; +} + +// Utility function to find minimum distance vertex in mdist +int minDistance(int mdist[], int vset[], int V) +{ + int minVal = INT_MAX, minInd; + for (int i = 0; i < V; i++) + if (vset[i] == 0 && mdist[i] < minVal) + { + minVal = mdist[i]; + minInd = i; + } + + return minInd; +} + +// Utility function to print distances +void print(int dist[], int V) +{ + printf("\nVertex Distance\n"); + for (int i = 0; i < V; i++) + { + if (dist[i] != INT_MAX) + printf("%d\t%d\n", i, dist[i]); + else + printf("%d\tINF", i); + } +} + +// The main function that finds the shortest path from given source +// to all other vertices using Bellman-Ford.It also detects negative +// weight cycle +void BellmanFord(struct Graph *graph, int src) +{ + int V = graph->vertexNum; + int E = graph->edgeNum; + int dist[V]; + + // Initialize distances array as INF for all except source + // Intialize source as zero + for (int i = 0; i < V; i++) dist[i] = INT_MAX; + dist[src] = 0; + + // Calculate shortest path distance from source to all edges + // A path can contain maximum (|V|-1) edges + for (int i = 0; i <= V - 1; i++) + for (int j = 0; j < E; j++) + { + int u = graph->edges[j].src; + int v = graph->edges[j].dst; + int w = graph->edges[j].weight; + + if (dist[u] != INT_MAX && dist[u] + w < dist[v]) + dist[v] = dist[u] + w; + } + + // Iterate inner loop once more to check for negative cycle + for (int j = 0; j < E; j++) + { + int u = graph->edges[j].src; + int v = graph->edges[j].dst; + int w = graph->edges[j].weight; + + if (dist[u] != INT_MAX && dist[u] + w < dist[v]) + { + printf( + "Graph contains negative weight cycle. Hence, shortest " + "distance not guaranteed."); + return; + } + } + + print(dist, V); + + return; +} + +// Driver Function +int main() +{ + int V, E, gsrc; + int src, dst, weight; + struct Graph G; + printf("Enter number of vertices: "); + scanf("%d", &V); + printf("Enter number of edges: "); + scanf("%d", &E); + createGraph(&G, V, E); + for (int i = 0; i < E; i++) + { + printf("\nEdge %d \nEnter source: ", i + 1); + scanf("%d", &src); + printf("Enter destination: "); + scanf("%d", &dst); + printf("Enter weight: "); + scanf("%d", &weight); + addEdge(&G, src, dst, weight); + } + printf("\nEnter source:"); + scanf("%d", &gsrc); + BellmanFord(&G, gsrc); + + return 0; +} diff --git a/data_structures/graphs/bfs.c b/data_structures/graphs/bfs.c new file mode 100644 index 0000000000..e53831b298 --- /dev/null +++ b/data_structures/graphs/bfs.c @@ -0,0 +1,195 @@ +#include +#include +#define SIZE 40 +// Assume max size of graph is 40 nodes +struct queue +{ + int items[SIZE]; + int front; + int rear; +}; + +// Some declarations +struct queue *createQueue(); +void enqueue(struct queue *q, int); +int dequeue(struct queue *q); +void display(struct queue *q); +int isEmpty(struct queue *q); +int pollQueue(struct queue *q); + +// Structure to create a graph node +struct node +{ + int vertex; + struct node *next; +}; + +struct node *createNode(int); + +// Graph data structure +struct Graph +{ + int numVertices; + struct node **adjLists; + int *visited; +}; +struct Graph *createGraph(int vertices); +void addEdge(struct Graph *graph, int src, int dest); +void printGraph(struct Graph *graph); +void bfs(struct Graph *graph, int startVertex); + +int main() +{ + int vertices, edges, source, i, src, dst; + printf("Enter the number of vertices\n"); + scanf("%d", &vertices); + struct Graph *graph = createGraph(vertices); + printf("Enter the number of edges\n"); + scanf("%d", &edges); + for (i = 0; i < edges; i++) + { + printf("Edge %d \nEnter source: ", i + 1); + scanf("%d", &src); + printf("Enter destination: "); + scanf("%d", &dst); + addEdge(graph, src, dst); + } + printf("Enter source of bfs\n"); + scanf("%d", &source); + bfs(graph, source); + + // Uncomment below part to get a ready-made example + /*struct Graph* graph = createGraph(6); + addEdge(graph, 0, 1); + addEdge(graph, 0, 2); + addEdge(graph, 1, 2); + addEdge(graph, 1, 4); + addEdge(graph, 1, 3); + addEdge(graph, 2, 4); + addEdge(graph, 3, 4); + bfs(graph,0);*/ + + return 0; +} +void bfs(struct Graph *graph, int startVertex) +{ + struct queue *q = createQueue(); + + // Add to visited list and put in queue + graph->visited[startVertex] = 1; + enqueue(q, startVertex); + printf("Breadth first traversal from vertex %d is:\n", startVertex); + + // Iterate while queue not empty + while (!isEmpty(q)) + { + printf("%d ", pollQueue(q)); + int currentVertex = dequeue(q); + + struct node *temp = graph->adjLists[currentVertex]; + // Add all unvisited neighbours of current vertex to queue to be printed + // next + while (temp) + { + int adjVertex = temp->vertex; + // Only add if neighbour is unvisited + if (graph->visited[adjVertex] == 0) + { + graph->visited[adjVertex] = 1; + enqueue(q, adjVertex); + } + temp = temp->next; + } + } +} +// Memory for a graph node +struct node *createNode(int v) +{ + struct node *newNode = malloc(sizeof(struct node)); + newNode->vertex = v; + newNode->next = NULL; + return newNode; +} +// Allocates memory for graph data structure, in adjacency list format +struct Graph *createGraph(int vertices) +{ + struct Graph *graph = malloc(sizeof(struct Graph)); + graph->numVertices = vertices; + + graph->adjLists = malloc(vertices * sizeof(struct node *)); + graph->visited = malloc(vertices * sizeof(int)); + + int i; + for (i = 0; i < vertices; i++) + { + graph->adjLists[i] = NULL; + graph->visited[i] = 0; + } + + return graph; +} +// Adds bidirectional edge to graph +void addEdge(struct Graph *graph, int src, int dest) +{ + // Add edge from src to dest + struct node *newNode = createNode(dest); + newNode->next = graph->adjLists[src]; + graph->adjLists[src] = newNode; + + // Add edge from dest to src; comment it out for directed graph + newNode = createNode(src); + newNode->next = graph->adjLists[dest]; + graph->adjLists[dest] = newNode; +} +// Allocates memory for our queue data structure +struct queue *createQueue() +{ + struct queue *q = malloc(sizeof(struct queue)); + q->front = -1; + q->rear = -1; + return q; +} +// Checks for empty queue +int isEmpty(struct queue *q) +{ + if (q->rear == -1) + return 1; + else + return 0; +} +// Inserts item at start of queue +void enqueue(struct queue *q, int value) +{ + if (q->rear == SIZE - 1) + printf("\nQueue is Full!!"); + else + { + if (q->front == -1) + q->front = 0; + q->rear++; + q->items[q->rear] = value; + } +} +// Returns item at front of queue and removes it from queue +int dequeue(struct queue *q) +{ + int item; + if (isEmpty(q)) + { + printf("Queue is empty"); + item = -1; + } + else + { + item = q->items[q->front]; + q->front++; + if (q->front > q->rear) + { + q->front = q->rear = -1; + } + } + return item; +} + +// Returns element at front of queue +int pollQueue(struct queue *q) { return q->items[q->front]; } diff --git a/data_structures/graphs/bfs_queue.c b/data_structures/graphs/bfs_queue.c new file mode 100644 index 0000000000..5612381b47 --- /dev/null +++ b/data_structures/graphs/bfs_queue.c @@ -0,0 +1,124 @@ +#include +#include +#include "Graph.h" +#include "queue.h" + +#define MAX_NODES 1000 + +int visited[MAX_NODES]; // array to store visiting order + // indexed by vertex 0..nV-1 + +bool findPathBFS(Graph g, int nV, Vertex src, Vertex dest) +{ + Vertex v; + for (v = 0; v < nV; v++) visited[v] = -1; + + visited[src] = src; + queue Q = newQueue(); + QueueEnqueue(Q, src); + while (!QueueIsEmpty(Q)) + { + v = QueueDequeue(Q); + Vertex w; + for (w = 0; w < nV; w++) + if (adjacent(g, v, w) && visited[w] == -1) + { + visited[w] = v; + if (w == dest) + return true; + else + QueueEnqueue(Q, w); + } + } + return false; +} + +int main(void) +{ + int V = 10; + Graph g = newGraph(V); + + Edge e; + e.v = 0; + e.w = 1; + insertEdge(g, e); + e.v = 0; + e.w = 2; + insertEdge(g, e); + e.v = 0; + e.w = 5; + insertEdge(g, e); + e.v = 1; + e.w = 5; + insertEdge(g, e); + e.v = 2; + e.w = 3; + insertEdge(g, e); + e.v = 3; + e.w = 4; + insertEdge(g, e); + e.v = 3; + e.w = 5; + insertEdge(g, e); + e.v = 3; + e.w = 8; + insertEdge(g, e); + e.v = 4; + e.w = 5; + insertEdge(g, e); + e.v = 4; + e.w = 7; + insertEdge(g, e); + e.v = 4; + e.w = 8; + insertEdge(g, e); + e.v = 5; + e.w = 6; + insertEdge(g, e); + e.v = 7; + e.w = 8; + insertEdge(g, e); + e.v = 7; + e.w = 9; + insertEdge(g, e); + e.v = 8; + e.w = 9; + insertEdge(g, e); + + int src = 0, dest = 6; + if (findPathBFS(g, V, src, dest)) + { + Vertex v = dest; + while (v != src) + { + printf("%d - ", v); + v = visited[v]; + } + printf("%d\n", src); + } + return 0; +} + +// By +// .----------------. .----------------. .----------------. +// .-----------------. .----------------. .----------------. +// | .--------------. || .--------------. || .--------------. || +// .--------------. | | .--------------. || .--------------. | | | _________ | +// || | _____ _____ | || | __ | || | ____ _____ | | | | ____ ____ +// | || | ____ | | | | | _ _ | | || ||_ _||_ _|| || | / \ +// | || ||_ \|_ _| | | | | |_ || _| | || | .' `. | | | | |_/ | | +// \_| | || | | | | | | || | / /\ \ | || | | \ | | | | | | | +// |__| | | || | / .--. \ | | | | | | | || | | ' ' | | || | +// / ____ \ | || | | |\ \| | | | | | | __ | | || | | | | | | | +// | | _| |_ | || | \ `--' / | || | _/ / \ \_ | || | _| |_\ |_ +// | | | | _| | | |_ | || | \ `--' / | | | | |_____| | || | `.__.' +// | || ||____| |____|| || ||_____|\____| | | | | |____||____| | || | `.____.' +// | | | | | || | | || | | || | | | | | +// | || | | | | '--------------' || '--------------' || +// '--------------' || '--------------' | | '--------------' || '--------------' +// | +// '----------------' '----------------' '----------------' +// '----------------' '----------------' '----------------' + +// Email : z5261243@unsw.edu.au +// hhoanhtuann@gmail.com diff --git a/data_structures/graphs/dfs.c b/data_structures/graphs/dfs.c new file mode 100644 index 0000000000..f711075949 --- /dev/null +++ b/data_structures/graphs/dfs.c @@ -0,0 +1,134 @@ +#include +#include + +// A vertex of the graph +struct node +{ + int vertex; + struct node *next; +}; +// Some declarations +struct node *createNode(int v); +struct Graph +{ + int numVertices; + int *visited; + struct node * + *adjLists; // we need int** to store a two dimensional array. Similary, + // we need struct node** to store an array of Linked lists +}; +struct Graph *createGraph(int); +void addEdge(struct Graph *, int, int); +void printGraph(struct Graph *); +void dfs(struct Graph *, int); + +int main() +{ + int vertices, edges, source, i, src, dst; + printf("Enter the number of vertices\n"); + scanf("%d", &vertices); + struct Graph *graph = createGraph(vertices); + printf("Enter the number of edges\n"); + scanf("%d", &edges); + for (i = 0; i < edges; i++) + { + printf("Edge %d \nEnter source: ", i + 1); + scanf("%d", &src); + printf("Enter destination: "); + scanf("%d", &dst); + addEdge(graph, src, dst); + } + printf("Enter source of DFS\n"); + scanf("%d", &source); + printf("DFS from %d is:\n", source); + dfs(graph, source); + printf("\n"); + + // Uncomment below part to get a ready-made example + /*struct Graph* graph = createGraph(4); + addEdge(graph, 0, 1); + addEdge(graph, 0, 2); + addEdge(graph, 1, 2); + addEdge(graph, 2, 3); + printf("DFS from 0 is:\n"); + dfs(graph,0); + printf("\n");*/ + + return 0; +} +// Recursive dfs approach +void dfs(struct Graph *graph, int vertex) +{ + struct node *adjList = graph->adjLists[vertex]; + struct node *temp = adjList; + + // Add vertex to visited list and print it + graph->visited[vertex] = 1; + printf("%d ", vertex); + + // Recursively call the dfs function on all unvisited neighbours + while (temp != NULL) + { + int connectedVertex = temp->vertex; + if (graph->visited[connectedVertex] == 0) + { + dfs(graph, connectedVertex); + } + temp = temp->next; + } +} +// Allocate memory for a node +struct node *createNode(int v) +{ + struct node *newNode = malloc(sizeof(struct node)); + newNode->vertex = v; + newNode->next = NULL; + return newNode; +} +// Allocate memory for the entire graph structure +struct Graph *createGraph(int vertices) +{ + struct Graph *graph = malloc(sizeof(struct Graph)); + graph->numVertices = vertices; + + graph->adjLists = malloc(vertices * sizeof(struct node *)); + + graph->visited = malloc(vertices * sizeof(int)); + + int i; + for (i = 0; i < vertices; i++) + { + graph->adjLists[i] = NULL; + graph->visited[i] = 0; + } + return graph; +} +// Creates a bidirectional graph +void addEdge(struct Graph *graph, int src, int dest) +{ + // Add edge from src to dest + struct node *newNode = createNode(dest); + newNode->next = graph->adjLists[src]; + graph->adjLists[src] = newNode; + + // Add edge from dest to src + newNode = createNode(src); + newNode->next = graph->adjLists[dest]; + graph->adjLists[dest] = newNode; +} +// Utility function to see state of graph at a given time +void printGraph(struct Graph *graph) +{ + int v; + for (v = 0; v < graph->numVertices; v++) + { + struct node *temp = graph->adjLists[v]; + printf("\n Adjacency list of vertex %d\n ", v); + while (temp) + { + printf("%d -> ", temp->vertex); + temp = temp->next; + } + printf("\n"); + } +} diff --git a/data_structures/graphs/dfs_recursive.c b/data_structures/graphs/dfs_recursive.c new file mode 100644 index 0000000000..d62f0c1d24 --- /dev/null +++ b/data_structures/graphs/dfs_recursive.c @@ -0,0 +1,103 @@ +#include +#include +#include "Graph.h" + +#define MAX_NODES 1000 + +int visited[MAX_NODES]; // array to store visiting order + // indexed by vertex 0..nV-1 + +bool dfsPathCheck(Graph g, int nV, Vertex v, Vertex dest) +{ + Vertex w; + for (w = 0; w < nV; w++) + if (adjacent(g, v, w) && visited[w] == -1) + { + visited[w] = v; + if (w == dest) + return true; + else if (dfsPathCheck(g, nV, w, dest)) + return true; + } + return false; +} + +bool findPathDFS(Graph g, int nV, Vertex src, Vertex dest) +{ + Vertex v; + for (v = 0; v < nV; v++) visited[v] = -1; + visited[src] = src; + return dfsPathCheck(g, nV, src, dest); +} + +int main(void) +{ + int V = 6; + Graph g = newGraph(V); + + Edge e; + e.v = 0; + e.w = 1; + insertEdge(g, e); + e.v = 0; + e.w = 4; + insertEdge(g, e); + e.v = 0; + e.w = 5; + insertEdge(g, e); + e.v = 5; + e.w = 4; + insertEdge(g, e); + e.v = 4; + e.w = 2; + insertEdge(g, e); + e.v = 4; + e.w = 3; + insertEdge(g, e); + e.v = 5; + e.w = 3; + insertEdge(g, e); + e.v = 1; + e.w = 2; + insertEdge(g, e); + e.v = 3; + e.w = 2; + insertEdge(g, e); + + int src = 0, dest = 5; + if (findPathDFS(g, V, src, dest)) + { + Vertex v = dest; + while (v != src) + { + printf("%d - ", v); + v = visited[v]; + } + printf("%d\n", src); + } + return 0; +} + +// By +// .----------------. .----------------. .----------------. +// .-----------------. .----------------. .----------------. +// | .--------------. || .--------------. || .--------------. || +// .--------------. | | .--------------. || .--------------. | | | _________ | +// || | _____ _____ | || | __ | || | ____ _____ | | | | ____ ____ +// | || | ____ | | | | | _ _ | | || ||_ _||_ _|| || | / \ +// | || ||_ \|_ _| | | | | |_ || _| | || | .' `. | | | | |_/ | | +// \_| | || | | | | | | || | / /\ \ | || | | \ | | | | | | | +// |__| | | || | / .--. \ | | | | | | | || | | ' ' | | || | +// / ____ \ | || | | |\ \| | | | | | | __ | | || | | | | | | | +// | | _| |_ | || | \ `--' / | || | _/ / \ \_ | || | _| |_\ |_ +// | | | | _| | | |_ | || | \ `--' / | | | | |_____| | || | `.__.' +// | || ||____| |____|| || ||_____|\____| | | | | |____||____| | || | `.____.' +// | | | | | || | | || | | || | | | | | +// | || | | | | '--------------' || '--------------' || +// '--------------' || '--------------' | | '--------------' || '--------------' +// | +// '----------------' '----------------' '----------------' +// '----------------' '----------------' '----------------' + +// Email : z5261243@unsw.edu.au +// hhoanhtuann@gmail.com diff --git a/data_structures/graphs/dijkstra.c b/data_structures/graphs/dijkstra.c new file mode 100644 index 0000000000..f15de53069 --- /dev/null +++ b/data_structures/graphs/dijkstra.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include + +// Structure for storing a graph +struct Graph +{ + int vertexNum; + int **edges; +}; + +// Constructs a graph with V vertices and E edges +void createGraph(struct Graph *G, int V) +{ + G->vertexNum = V; + G->edges = (int **)malloc(V * sizeof(int *)); + for (int i = 0; i < V; i++) + { + G->edges[i] = (int *)malloc(V * sizeof(int)); + for (int j = 0; j < V; j++) G->edges[i][j] = INT_MAX; + G->edges[i][i] = 0; + } +} + +// Adds the given edge to the graph +void addEdge(struct Graph *G, int src, int dst, int weight) +{ + G->edges[src][dst] = weight; +} + +// Utility function to find minimum distance vertex in mdist +int minDistance(int mdist[], int vset[], int V) +{ + int minVal = INT_MAX; + static int minInd = -1; //remembers the previous value if not modified in the loop + for (int i = 0; i < V; i++) + if (vset[i] == 0 && mdist[i] < minVal) + { + minVal = mdist[i]; + minInd = i; + } + + return minInd; +} + +// Utility function to print distances +void print(int dist[], int V) +{ + printf("\nVertex Distance\n"); + for (int i = 0; i < V; i++) + { + if (dist[i] != INT_MAX) + printf("%d\t%d\n", i, dist[i]); + else + printf("%d\tINF", i); + } +} + +// The main function that finds the shortest path from given source +// to all other vertices using Dijkstra's Algorithm.It doesn't work on negative +// weights +void Dijkstra(struct Graph *graph, int src) +{ + int V = graph->vertexNum; + int mdist[V]; // Stores updated distances to vertex + int vset[V]; // vset[i] is true if the vertex i included + // in the shortest path tree + + // Initialise mdist and vset. Set distance of source as zero + for (int i = 0; i < V; i++) mdist[i] = INT_MAX, vset[i] = 0; + + mdist[src] = 0; + + // iterate to find shortest path + for (int count = 0; count < V - 1; count++) + { + int u = minDistance(mdist, vset, V); + vset[u] = 1; + + for (int v = 0; v < V; v++) + { + if (!vset[v] && graph->edges[u][v] != INT_MAX && + mdist[u] + graph->edges[u][v] < mdist[v]) + mdist[v] = mdist[u] + graph->edges[u][v]; + } + } + + print(mdist, V); + + return; +} + +// Driver Function +int main() +{ + int V, E, gsrc; + int src, dst, weight; + struct Graph G; + printf("Enter number of vertices: "); + scanf("%d", &V); + printf("Enter number of edges: "); + scanf("%d", &E); + createGraph(&G, V); + for (int i = 0; i < E; i++) + { + printf("\nEdge %d \nEnter source: ", i + 1); + scanf("%d", &src); + printf("Enter destination: "); + scanf("%d", &dst); + printf("Enter weight: "); + scanf("%d", &weight); + addEdge(&G, src, dst, weight); + } + printf("\nEnter source:"); + scanf("%d", &gsrc); + Dijkstra(&G, gsrc); + + return 0; +} diff --git a/data_structures/graphs/euler.c b/data_structures/graphs/euler.c new file mode 100644 index 0000000000..32cfc2d19f --- /dev/null +++ b/data_structures/graphs/euler.c @@ -0,0 +1,95 @@ +#include +#include +#include "Graph.h" + +// Return the number of vertices that v is +// connected to +int degree(Graph g, int nV, Vertex v) +{ + int deg = 0; + Vertex w; + for (w = 0; w < nV; w++) + if (adjacent(g, v, w)) + deg++; + return deg; +} + +// If start from vertex v, decide if the +// graph has euler path +bool hasEulerPath(Graph g, int nV, Vertex v, Vertex w) +{ + if (v != w) + { + if (degree(g, nV, v) % 2 == 0 || degree(g, nV, w) % 2 == 0) + return false; + } + else if (degree(g, nV, v) % 2 != 0) + { + return false; + } + Vertex x; + for (x = 0; x < nV; x++) + if (x != v && x != w && degree(g, nV, x) % 2 != 0) + return false; + return true; +} + +int main(void) +{ + Edge e; + int n; + + printf("Enter the number of vertices: "); + scanf("%d", &n); + Graph g = newGraph(n); + + Vertex src, dest; + printf("Enter source node: "); + scanf("%d", &src); + printf("Enter destination node: "); + scanf("%d", &dest); + + printf("Enter an edge (from): "); + while (scanf("%d", &e.v) == 1) + { + printf("Enter an edge (to): "); + scanf("%d", &e.w); + insertEdge(g, e); + printf("Enter an edge (from): "); + } + printf("Finished.\n"); + + printf("The graph has "); + if (hasEulerPath(g, n, src, dest)) + printf("an"); + else + printf("no"); + printf(" Euler path from %d to %d.\n", src, dest); + + freeGraph(g); + return 0; +} + +// By +// .----------------. .----------------. .----------------. +// .-----------------. .----------------. .----------------. +// | .--------------. || .--------------. || .--------------. || +// .--------------. | | .--------------. || .--------------. | | | _________ | +// || | _____ _____ | || | __ | || | ____ _____ | | | | ____ ____ +// | || | ____ | | | | | _ _ | | || ||_ _||_ _|| || | / \ +// | || ||_ \|_ _| | | | | |_ || _| | || | .' `. | | | | |_/ | | +// \_| | || | | | | | | || | / /\ \ | || | | \ | | | | | | | +// |__| | | || | / .--. \ | | | | | | | || | | ' ' | | || | +// / ____ \ | || | | |\ \| | | | | | | __ | | || | | | | | | | +// | | _| |_ | || | \ `--' / | || | _/ / \ \_ | || | _| |_\ |_ +// | | | | _| | | |_ | || | \ `--' / | | | | |_____| | || | `.__.' +// | || ||____| |____|| || ||_____|\____| | | | | |____||____| | || | `.____.' +// | | | | | || | | || | | || | | | | | +// | || | | | | '--------------' || '--------------' || +// '--------------' || '--------------' | | '--------------' || '--------------' +// | +// '----------------' '----------------' '----------------' +// '----------------' '----------------' '----------------' + +// Email : z5261243@unsw.edu.au +// hhoanhtuann@gmail.com diff --git a/data_structures/graphs/floyd_warshall.c b/data_structures/graphs/floyd_warshall.c new file mode 100644 index 0000000000..19a86a0620 --- /dev/null +++ b/data_structures/graphs/floyd_warshall.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include + +// Structure for storing a graph +struct Graph +{ + int vertexNum; + int **edges; +}; + +// Constructs a graph with V vertices and E edges +void createGraph(struct Graph *G, int V) +{ + G->vertexNum = V; + G->edges = (int **)malloc(V * sizeof(int *)); + for (int i = 0; i < V; i++) + { + G->edges[i] = (int *)malloc(V * sizeof(int)); + for (int j = 0; j < V; j++) G->edges[i][j] = INT_MAX; + G->edges[i][i] = 0; + } +} + +// Adds the given edge to the graph +void addEdge(struct Graph *G, int src, int dst, int weight) +{ + G->edges[src][dst] = weight; +} + +// Utility function to print distances +void print(int dist[], int V) +{ + printf("\nThe Distance matrix for Floyd - Warshall\n"); + for (int i = 0; i < V; i++) + { + for (int j = 0; j < V; j++) + { + if (dist[i * V + j] != INT_MAX) + printf("%d\t", dist[i * V + j]); + else + printf("INF\t"); + } + printf("\n"); + } +} + +// The main function that finds the shortest path from a vertex +// to all other vertices using Floyd-Warshall Algorithm. +void FloydWarshall(struct Graph *graph) +{ + int V = graph->vertexNum; + int dist[V][V]; + + // Initialise distance array + for (int i = 0; i < V; i++) + for (int j = 0; j < V; j++) dist[i][j] = graph->edges[i][j]; + + // Calculate distances + for (int k = 0; k < V; k++) + // Choose an intermediate vertex + + for (int i = 0; i < V; i++) + // Choose a source vertex for given intermediate + + for (int j = 0; j < V; j++) + // Choose a destination vertex for above source vertex + + if (dist[i][k] != INT_MAX && dist[k][j] != INT_MAX && + dist[i][k] + dist[k][j] < dist[i][j]) + // If the distance through intermediate vertex is less than + // direct edge then update value in distance array + dist[i][j] = dist[i][k] + dist[k][j]; + + // Convert 2d array to 1d array for print + int dist1d[V * V]; + for (int i = 0; i < V; i++) + for (int j = 0; j < V; j++) dist1d[i * V + j] = dist[i][j]; + + print(dist1d, V); +} + +// Driver Function +int main() +{ + int V, E; + int src, dst, weight; + struct Graph G; + printf("Enter number of vertices: "); + scanf("%d", &V); + printf("Enter number of edges: "); + scanf("%d", &E); + createGraph(&G, V); + for (int i = 0; i < E; i++) + { + printf("\nEdge %d \nEnter source: ", i + 1); + scanf("%d", &src); + printf("Enter destination: "); + scanf("%d", &dst); + printf("Enter weight: "); + scanf("%d", &weight); + addEdge(&G, src, dst, weight); + } + FloydWarshall(&G); + + return 0; +} diff --git a/data_structures/graphs/graph.c b/data_structures/graphs/graph.c new file mode 100644 index 0000000000..f4c69faa8e --- /dev/null +++ b/data_structures/graphs/graph.c @@ -0,0 +1,117 @@ +// Graph ADT +// Adjacency Matrix Representation +#include "Graph.h" +#include +#include +#include + +typedef struct GraphRep +{ + int **edges; // adjacency matrix + int nV; // #vertices + int nE; // #edges +} GraphRep; + +Graph newGraph(int V) +{ + assert(V >= 0); + int i; + + Graph g = malloc(sizeof(GraphRep)); + assert(g != NULL); + g->nV = V; + g->nE = 0; + + // allocate memory for each row + g->edges = malloc(V * sizeof(int *)); + assert(g->edges != NULL); + // allocate memory for each column and initialise with 0 + for (i = 0; i < V; i++) + { + g->edges[i] = calloc(V, sizeof(int)); + assert(g->edges[i] != NULL); + } + + return g; +} + +// check if vertex is valid in a graph +bool validV(Graph g, Vertex v) { return (g != NULL && v >= 0 && v < g->nV); } + +void insertEdge(Graph g, Edge e) +{ + assert(g != NULL && validV(g, e.v) && validV(g, e.w)); + + if (!g->edges[e.v][e.w]) + { // edge e not in graph + g->edges[e.v][e.w] = 1; + g->edges[e.w][e.v] = 1; + g->nE++; + } +} + +void removeEdge(Graph g, Edge e) +{ + assert(g != NULL && validV(g, e.v) && validV(g, e.w)); + + if (g->edges[e.v][e.w]) + { // edge e in graph + g->edges[e.v][e.w] = 0; + g->edges[e.w][e.v] = 0; + g->nE--; + } +} + +bool adjacent(Graph g, Vertex v, Vertex w) +{ + assert(g != NULL && validV(g, v) && validV(g, w)); + + return (g->edges[v][w] != 0); +} + +void showGraph(Graph g) +{ + assert(g != NULL); + int i, j; + + printf("Number of vertices: %d\n", g->nV); + printf("Number of edges: %d\n", g->nE); + for (i = 0; i < g->nV; i++) + for (j = i + 1; j < g->nV; j++) + if (g->edges[i][j]) + printf("Edge %d - %d\n", i, j); +} + +void freeGraph(Graph g) +{ + assert(g != NULL); + + int i; + for (i = 0; i < g->nV; i++) free(g->edges[i]); + free(g->edges); + free(g); +} + +// By +// .----------------. .----------------. .----------------. +// .-----------------. .----------------. .----------------. +// | .--------------. || .--------------. || .--------------. || +// .--------------. | | .--------------. || .--------------. | | | _________ | +// || | _____ _____ | || | __ | || | ____ _____ | | | | ____ ____ +// | || | ____ | | | | | _ _ | | || ||_ _||_ _|| || | / \ +// | || ||_ \|_ _| | | | | |_ || _| | || | .' `. | | | | |_/ | | +// \_| | || | | | | | | || | / /\ \ | || | | \ | | | | | | | +// |__| | | || | / .--. \ | | | | | | | || | | ' ' | | || | +// / ____ \ | || | | |\ \| | | | | | | __ | | || | | | | | | | +// | | _| |_ | || | \ `--' / | || | _/ / \ \_ | || | _| |_\ |_ +// | | | | _| | | |_ | || | \ `--' / | | | | |_____| | || | `.__.' +// | || ||____| |____|| || ||_____|\____| | | | | |____||____| | || | `.____.' +// | | | | | || | | || | | || | | | | | +// | || | | | | '--------------' || '--------------' || +// '--------------' || '--------------' | | '--------------' || '--------------' +// | +// '----------------' '----------------' '----------------' +// '----------------' '----------------' '----------------' + +// Email : z5261243@unsw.edu.au +// hhoanhtuann@gmail.com diff --git a/data_structures/graphs/graph.h b/data_structures/graphs/graph.h new file mode 100644 index 0000000000..23faea8029 --- /dev/null +++ b/data_structures/graphs/graph.h @@ -0,0 +1,45 @@ +// Graph ADT interface ... COMP2521 +#include + +typedef struct GraphRep *Graph; + +// vertices are ints +typedef int Vertex; + +// edges are pairs of vertices (end-points) +typedef struct Edge +{ + Vertex v; + Vertex w; +} Edge; + +Graph newGraph(int); +void insertEdge(Graph, Edge); +void removeEdge(Graph, Edge); +bool adjacent(Graph, Vertex, Vertex); +void showGraph(Graph); +void freeGraph(Graph); + +// By +// .----------------. .----------------. .----------------. +// .-----------------. .----------------. .----------------. +// | .--------------. || .--------------. || .--------------. || +// .--------------. | | .--------------. || .--------------. | | | _________ | +// || | _____ _____ | || | __ | || | ____ _____ | | | | ____ ____ +// | || | ____ | | | | | _ _ | | || ||_ _||_ _|| || | / \ +// | || ||_ \|_ _| | | | | |_ || _| | || | .' `. | | | | |_/ | | +// \_| | || | | | | | | || | / /\ \ | || | | \ | | | | | | | +// |__| | | || | / .--. \ | | | | | | | || | | ' ' | | || | +// / ____ \ | || | | |\ \| | | | | | | __ | | || | | | | | | | +// | | _| |_ | || | \ `--' / | || | _/ / \ \_ | || | _| |_\ |_ +// | | | | _| | | |_ | || | \ `--' / | | | | |_____| | || | `.__.' +// | || ||____| |____|| || ||_____|\____| | | | | |____||____| | || | `.____.' +// | | | | | || | | || | | || | | | | | +// | || | | | | '--------------' || '--------------' || +// '--------------' || '--------------' | | '--------------' || '--------------' +// | +// '----------------' '----------------' '----------------' +// '----------------' '----------------' '----------------' + +// Email : z5261243@unsw.edu.au +// hhoanhtuann@gmail.com diff --git a/data_structures/graphs/hamiltonian.c b/data_structures/graphs/hamiltonian.c new file mode 100644 index 0000000000..00e70ea0dc --- /dev/null +++ b/data_structures/graphs/hamiltonian.c @@ -0,0 +1,103 @@ +#include +#include +#include "Graph.h" + +#define MAX_NODES 1000 + +bool visited[MAX_NODES]; + +bool hamiltonR(Graph g, int nV, Vertex v, Vertex dest, int d) +{ + // v = current vertex considered + // dest = destination vertex + // d = distance "remaining" until path found + + Vertex w; + if (v == dest) + { + return (d == 0); + } + else + { + visited[v] = true; + for (w = 0; w < nV; w++) + { + if (adjacent(g, v, w) && !visited[w]) + { + if (hamiltonR(g, nV, w, dest, d - 1)) + { + return true; + } + } + } + } + visited[v] = false; + return false; +} + +bool hasHamiltonianPath(Graph g, int nV, Vertex src, Vertex dest) +{ + Vertex v; + for (v = 0; v < nV; v++) visited[v] = false; + return hamiltonR(g, nV, src, dest, nV - 1); +} + +int main(void) +{ + Edge e; + int n; + + printf("Enter the number of vertices: "); + scanf("%d", &n); + Graph g = newGraph(n); + + Vertex src, dest; + printf("Enter source node: "); + scanf("%d", &src); + printf("Enter destination node: "); + scanf("%d", &dest); + + printf("Enter an edge (from): "); + while (scanf("%d", &e.v) == 1) + { + printf("Enter an edge (to): "); + scanf("%d", &e.w); + insertEdge(g, e); + printf("Enter an edge (from): "); + } + printf("Finished.\n"); + + printf("The graph has "); + if (hasHamiltonianPath(g, n, src, dest)) + printf("a"); + else + printf("no"); + printf(" Hamiltonian path from %d to %d.\n", src, dest); + + freeGraph(g); + return 0; +} + +// By +// .----------------. .----------------. .----------------. +// .-----------------. .----------------. .----------------. +// | .--------------. || .--------------. || .--------------. || +// .--------------. | | .--------------. || .--------------. | | | _________ | +// || | _____ _____ | || | __ | || | ____ _____ | | | | ____ ____ +// | || | ____ | | | | | _ _ | | || ||_ _||_ _|| || | / \ +// | || ||_ \|_ _| | | | | |_ || _| | || | .' `. | | | | |_/ | | +// \_| | || | | | | | | || | / /\ \ | || | | \ | | | | | | | +// |__| | | || | / .--. \ | | | | | | | || | | ' ' | | || | +// / ____ \ | || | | |\ \| | | | | | | __ | | || | | | | | | | +// | | _| |_ | || | \ `--' / | || | _/ / \ \_ | || | _| |_\ |_ +// | | | | _| | | |_ | || | \ `--' / | | | | |_____| | || | `.__.' +// | || ||____| |____|| || ||_____|\____| | | | | |____||____| | || | `.____.' +// | | | | | || | | || | | || | | | | | +// | || | | | | '--------------' || '--------------' || +// '--------------' || '--------------' | | '--------------' || '--------------' +// | +// '----------------' '----------------' '----------------' +// '----------------' '----------------' '----------------' + +// Email : z5261243@unsw.edu.au +// hhoanhtuann@gmail.com diff --git a/data_structures/graphs/kruskal.c b/data_structures/graphs/kruskal.c new file mode 100644 index 0000000000..0f72c6b52f --- /dev/null +++ b/data_structures/graphs/kruskal.c @@ -0,0 +1,187 @@ +// C program for Kruskal's algorithm to find Minimum Spanning Tree +// of a given connected, undirected and weighted graph +#include +#include +#include + +// a structure to represent a weighted edge in graph +struct Edge +{ + int src, dest, weight; +}; + +// a structure to represent a connected, undirected +// and weighted graph +struct Graph +{ + // V-> Number of vertices, E-> Number of edges + int V, E; + + // graph is represented as an array of edges. + // Since the graph is undirected, the edge + // from src to dest is also edge from dest + // to src. Both are counted as 1 edge here. + struct Edge *edge; +}; + +// Creates a graph with V vertices and E edges +struct Graph *createGraph(int V, int E) +{ + struct Graph* graph = (struct Graph*)(malloc(sizeof(struct Graph))); + graph->V = V; + graph->E = E; + + graph->edge = (struct Edge*)malloc(sizeof(struct Edge) * E); + + return graph; +} + +// A structure to represent a subset for union-find +struct subset +{ + int parent; + int rank; +}; + +// A utility function to find set of an element i +// (uses path compression technique) +int find(struct subset subsets[], int i) +{ + // find root and make root as parent of i + // (path compression) + if (subsets[i].parent != i) + subsets[i].parent = find(subsets, subsets[i].parent); + + return subsets[i].parent; +} + +// A function that does union of two sets of x and y +// (uses union by rank) +void Union(struct subset subsets[], int x, int y) +{ + int xroot = find(subsets, x); + int yroot = find(subsets, y); + + // Attach smaller rank tree under root of high + // rank tree (Union by Rank) + if (subsets[xroot].rank < subsets[yroot].rank) + subsets[xroot].parent = yroot; + else if (subsets[xroot].rank > subsets[yroot].rank) + subsets[yroot].parent = xroot; + + // If ranks are same, then make one as root and + // increment its rank by one + else + { + subsets[yroot].parent = xroot; + subsets[xroot].rank++; + } +} + +// Compare two edges according to their weights. +// Used in qsort() for sorting an array of edges +int myComp(const void *a, const void *b) +{ + struct Edge *a1 = (struct Edge *)a; + struct Edge *b1 = (struct Edge *)b; + return a1->weight > b1->weight; +} + +// The main function to construct MST using Kruskal's algorithm +void KruskalMST(struct Graph *graph) +{ + int V = graph->V; + struct Edge result[V]; // Tnis will store the resultant MST + int e = 0; // An index variable, used for result[] + int i = 0; // An index variable, used for sorted edges + + // Step 1: Sort all the edges in non-decreasing + // order of their weight. If we are not allowed to + // change the given graph, we can create a copy of + // array of edges + qsort(graph->edge, graph->E, sizeof(graph->edge[0]), myComp); + + // Allocate memory for creating V ssubsets + struct subset *subsets = (struct subset *)malloc(V * sizeof(struct subset)); + + // Create V subsets with single elements + for (int v = 0; v < V; ++v) + { + subsets[v].parent = v; + subsets[v].rank = 0; + } + + // Number of edges to be taken is equal to V-1 + while (e < V - 1 && i < graph->E) + { + // Step 2: Pick the smallest edge. And increment + // the index for next iteration + struct Edge next_edge = graph->edge[i++]; + + int x = find(subsets, next_edge.src); + int y = find(subsets, next_edge.dest); + + // If including this edge does't cause cycle, + // include it in result and increment the index + // of result for next edge + if (x != y) + { + result[e++] = next_edge; + Union(subsets, x, y); + } + // Else discard the next_edge + } + + // print the contents of result[] to display the + // built MST + printf("Following are the edges in the constructed MST\n"); + for (i = 0; i < e; ++i) + printf("%d -- %d == %d\n", result[i].src, result[i].dest, + result[i].weight); + return; +} + +// Driver program to test above functions +int main() +{ + /* Let us create following weighted graph + 10 + 0--------1 + | \ | + 6| 5\ |15 + | \ | + 2--------3 + 4 */ + int V = 4; // Number of vertices in graph + int E = 5; // Number of edges in graph + struct Graph *graph = createGraph(V, E); + + // add edge 0-1 + graph->edge[0].src = 0; + graph->edge[0].dest = 1; + graph->edge[0].weight = 10; + + // add edge 0-2 + graph->edge[1].src = 0; + graph->edge[1].dest = 2; + graph->edge[1].weight = 6; + + // add edge 0-3 + graph->edge[2].src = 0; + graph->edge[2].dest = 3; + graph->edge[2].weight = 5; + + // add edge 1-3 + graph->edge[3].src = 1; + graph->edge[3].dest = 3; + graph->edge[3].weight = 15; + + // add edge 2-3 + graph->edge[4].src = 2; + graph->edge[4].dest = 3; + graph->edge[4].weight = 4; + + KruskalMST(graph); + + return 0; +} diff --git a/data_structures/graphs/queue.c b/data_structures/graphs/queue.c new file mode 100644 index 0000000000..89ad6178fb --- /dev/null +++ b/data_structures/graphs/queue.c @@ -0,0 +1,104 @@ +// Queue ADT implementation ... COMP2521 + +#include "queue.h" +#include +#include + +typedef struct node +{ + int data; + struct node *next; +} NodeT; + +typedef struct QueueRep +{ + int length; + NodeT *head; + NodeT *tail; +} QueueRep; + +// set up empty queue +queue newQueue() +{ + queue Q = malloc(sizeof(QueueRep)); + Q->length = 0; + Q->head = NULL; + Q->tail = NULL; + return Q; +} + +// remove unwanted queue +void dropQueue(queue Q) +{ + NodeT *curr = Q->head; + while (curr != NULL) + { + NodeT *temp = curr->next; + free(curr); + curr = temp; + } + free(Q); +} + +// check whether queue is empty +int QueueIsEmpty(queue Q) { return (Q->length == 0); } + +// insert an int at end of queue +void QueueEnqueue(queue Q, int v) +{ + NodeT *new = malloc(sizeof(NodeT)); + assert(new != NULL); + new->data = v; + new->next = NULL; + if (Q->tail != NULL) + { + Q->tail->next = new; + Q->tail = new; + } + else + { + Q->head = new; + Q->tail = new; + } + Q->length++; +} + +// remove int from front of queue +int QueueDequeue(queue Q) +{ + assert(Q->length > 0); + NodeT *p = Q->head; + Q->head = Q->head->next; + if (Q->head == NULL) + { + Q->tail = NULL; + } + Q->length--; + int d = p->data; + free(p); + return d; +} + +// By +// .----------------. .----------------. .----------------. +// .-----------------. .----------------. .----------------. +// | .--------------. || .--------------. || .--------------. || +// .--------------. | | .--------------. || .--------------. | | | _________ | +// || | _____ _____ | || | __ | || | ____ _____ | | | | ____ ____ +// | || | ____ | | | | | _ _ | | || ||_ _||_ _|| || | / \ +// | || ||_ \|_ _| | | | | |_ || _| | || | .' `. | | | | |_/ | | +// \_| | || | | | | | | || | / /\ \ | || | | \ | | | | | | | +// |__| | | || | / .--. \ | | | | | | | || | | ' ' | | || | +// / ____ \ | || | | |\ \| | | | | | | __ | | || | | | | | | | +// | | _| |_ | || | \ `--' / | || | _/ / \ \_ | || | _| |_\ |_ +// | | | | _| | | |_ | || | \ `--' / | | | | |_____| | || | `.__.' +// | || ||____| |____|| || ||_____|\____| | | | | |____||____| | || | `.____.' +// | | | | | || | | || | | || | | | | | +// | || | | | | '--------------' || '--------------' || +// '--------------' || '--------------' | | '--------------' || '--------------' +// | +// '----------------' '----------------' '----------------' +// '----------------' '----------------' '----------------' + +// Email : z5261243@unsw.edu.au +// hhoanhtuann@gmail.com diff --git a/data_structures/graphs/queue.h b/data_structures/graphs/queue.h new file mode 100644 index 0000000000..2df425dc3c --- /dev/null +++ b/data_structures/graphs/queue.h @@ -0,0 +1,33 @@ +// Queue ADT header file ... COMP2521 + +typedef struct QueueRep *queue; + +queue newQueue(); // set up empty queue +void dropQueue(queue); // remove unwanted queue +int QueueIsEmpty(queue); // check whether queue is empty +void QueueEnqueue(queue, int); // insert an int at end of queue +int QueueDequeue(queue); // remove int from front of queue + +// By +// .----------------. .----------------. .----------------. +// .-----------------. .----------------. .----------------. +// | .--------------. || .--------------. || .--------------. || +// .--------------. | | .--------------. || .--------------. | | | _________ | +// || | _____ _____ | || | __ | || | ____ _____ | | | | ____ ____ +// | || | ____ | | | | | _ _ | | || ||_ _||_ _|| || | / \ +// | || ||_ \|_ _| | | | | |_ || _| | || | .' `. | | | | |_/ | | +// \_| | || | | | | | | || | / /\ \ | || | | \ | | | | | | | +// |__| | | || | / .--. \ | | | | | | | || | | ' ' | | || | +// / ____ \ | || | | |\ \| | | | | | | __ | | || | | | | | | | +// | | _| |_ | || | \ `--' / | || | _/ / \ \_ | || | _| |_\ |_ +// | | | | _| | | |_ | || | \ `--' / | | | | |_____| | || | `.__.' +// | || ||____| |____|| || ||_____|\____| | | | | |____||____| | || | `.____.' +// | | | | | || | | || | | || | | | | | +// | || | | | | '--------------' || '--------------' || +// '--------------' || '--------------' | | '--------------' || '--------------' +// | +// '----------------' '----------------' '----------------' +// '----------------' '----------------' '----------------' + +// Email : z5261243@unsw.edu.au +// hhoanhtuann@gmail.com diff --git a/data_structures/graphs/strongly_connected_components.c b/data_structures/graphs/strongly_connected_components.c new file mode 100644 index 0000000000..652ecf29a1 --- /dev/null +++ b/data_structures/graphs/strongly_connected_components.c @@ -0,0 +1,223 @@ +#include +#include +#define MAX_SIZE 40 // Assume 40 nodes at max in graph +#define INT_MIN 0 +// A vertex of the graph +struct node +{ + int vertex; + struct node *next; +}; +// Some declarations +struct node *createNode(int v); +struct Graph +{ + int numVertices; + int *visited; + struct node * + *adjLists; // we need int** to store a two dimensional array. Similary, + // we need struct node** to store an array of Linked lists +}; +// Structure to create a stack, necessary for topological sorting +struct Stack +{ + int arr[MAX_SIZE]; + int top; +}; +struct Graph *createGraph(int); +void addEdge(struct Graph *, int, int); +void printGraph(struct Graph *); +struct Graph *transpose(struct Graph *); +void fillOrder(int, struct Graph *, struct Stack *); +void scc(struct Graph *); +void dfs(struct Graph *, int); +struct Stack *createStack(); +void push(struct Stack *, int); +int pop(struct Stack *); + +int main() +{ + int vertices, edges, i, src, dst; + printf("Enter the number of vertices\n"); + scanf("%d", &vertices); + struct Graph *graph = createGraph(vertices); + printf("Enter the number of edges\n"); + scanf("%d", &edges); + for (i = 0; i < edges; i++) + { + printf("Edge %d \nEnter source: ", i + 1); + scanf("%d", &src); + printf("Enter destination: "); + scanf("%d", &dst); + addEdge(graph, src, dst); + } + printf("The strongly connected conponents are:\n"); + scc(graph); + printf("\n"); + + // Uncomment below part to get a ready-made example + /*struct Graph* graph2 = createGraph(4); + addEdge(graph2, 0, 1); + addEdge(graph2, 1, 2); + addEdge(graph2, 2, 0); + addEdge(graph2, 2, 3); + printf("The strongly connected components are:\n"); + scc(graph2); + printf("\n");*/ + return 0; +} +// Creates a topological sorting of the graph +void fillOrder(int vertex, struct Graph *graph, struct Stack *stack) +{ + graph->visited[vertex] = 1; + struct node *adjList = graph->adjLists[vertex]; + struct node *temp = adjList; + // First add all dependents (that is, children) to stack + while (temp != NULL) + { + int connectedVertex = temp->vertex; + if (graph->visited[connectedVertex] == 0) + { + fillOrder(connectedVertex, graph, stack); + } + temp = temp->next; + } + // and then add itself + push(stack, vertex); +} +// Transpose the adjacency list +struct Graph *transpose(struct Graph *g) +{ + struct Graph *graph = + createGraph(g->numVertices); // Number of vertices is same + int i = 0; + for (i = 0; i < g->numVertices; i++) + { + struct node *temp = g->adjLists[i]; + while (temp != NULL) + { + addEdge(graph, temp->vertex, i); // Reverse all edges + temp = temp->next; + } + } + return graph; +} +// Recursive dfs aproach +void dfs(struct Graph *graph, int vertex) +{ + struct node *adjList = graph->adjLists[vertex]; + struct node *temp = adjList; + + // Add vertex to visited list and print it + graph->visited[vertex] = 1; + printf("%d ", vertex); + + // Recursively call the dfs function on all unvisited neighbours + while (temp != NULL) + { + int connectedVertex = temp->vertex; + if (graph->visited[connectedVertex] == 0) + { + dfs(graph, connectedVertex); + } + temp = temp->next; + } +} + +// Strongly connected components +void scc(struct Graph *graph) +{ + // Step I: Create a topological sort of the graph and store it in a stack + struct Stack *stack = createStack(); + int i = 0; + for (i = 0; i < graph->numVertices; i++) + { + // Execute topological sort on all elements + if (graph->visited[i] == 0) + { + fillOrder(i, graph, stack); + } + } + // Step 2: Get the transpose graph + struct Graph *graphT = transpose(graph); + // Step 3: Perform a simple dfs by popping nodes from stack + while (stack->top != -1) + { + int v = pop(stack); + if (graphT->visited[v] == 0) + { + dfs(graphT, v); + printf("\n"); + } + } +} + +// Allocate memory for a node +struct node *createNode(int v) +{ + struct node *newNode = malloc(sizeof(struct node)); + newNode->vertex = v; + newNode->next = NULL; + return newNode; +} +// Allocate memory for the entire graph structure +struct Graph *createGraph(int vertices) +{ + struct Graph *graph = malloc(sizeof(struct Graph)); + graph->numVertices = vertices; + graph->adjLists = malloc(vertices * sizeof(struct node *)); + graph->visited = malloc(vertices * sizeof(int)); + + int i; + for (i = 0; i < vertices; i++) + { + graph->adjLists[i] = NULL; + graph->visited[i] = 0; + } + return graph; +} +// Creates a unidirectional graph +void addEdge(struct Graph *graph, int src, int dest) +{ + // Add edge from src to dest + struct node *newNode = createNode(dest); + newNode->next = graph->adjLists[src]; + graph->adjLists[src] = newNode; +} +// Utility function to see state of graph at a given time +void printGraph(struct Graph *graph) +{ + int v; + for (v = 0; v < graph->numVertices; v++) + { + struct node *temp = graph->adjLists[v]; + printf("\n Adjacency list of vertex %d\n ", v); + while (temp) + { + printf("%d -> ", temp->vertex); + temp = temp->next; + } + printf("\n"); + } +} +// Creates a stack +struct Stack *createStack() +{ + struct Stack *stack = malloc(sizeof(struct Stack)); + stack->top = -1; + return stack; +} +// Pushes element into stack +void push(struct Stack *stack, int element) +{ + stack->arr[++stack->top] = + element; // Increment then add, as we start from -1 +} +// Removes element from stack, or returns INT_MIN if stack empty +int pop(struct Stack *stack) +{ + if (stack->top == -1) + return INT_MIN; + else + return stack->arr[stack->top--]; +} diff --git a/data_structures/graphs/topological_sort.c b/data_structures/graphs/topological_sort.c new file mode 100644 index 0000000000..a9909cac39 --- /dev/null +++ b/data_structures/graphs/topological_sort.c @@ -0,0 +1,170 @@ +#include +#include +#define MAX_SIZE 40 // Assume 40 nodes at max in graph +#define INT_MIN 0 +// A vertex of the graph +struct node +{ + int vertex; + struct node *next; +}; +// Some declarations +struct node *createNode(int v); +struct Graph +{ + int numVertices; + int *visited; + struct node * + *adjLists; // we need int** to store a two dimensional array. Similary, + // we need struct node** to store an array of Linked lists +}; +// Structure to create a stack, necessary for topological sorting +struct Stack +{ + int arr[MAX_SIZE]; + int top; +}; +struct Graph *createGraph(int); +void addEdge(struct Graph *, int, int); +void printGraph(struct Graph *); +void topologicalSortHelper(int, struct Graph *, struct Stack *); +void topologicalSort(struct Graph *); +struct Stack *createStack(); +void push(struct Stack *, int); +int pop(struct Stack *); + +int main() +{ + int vertices, edges, i, src, dst; + printf("Enter the number of vertices\n"); + scanf("%d", &vertices); + struct Graph *graph = createGraph(vertices); + printf("Enter the number of edges\n"); + scanf("%d", &edges); + for (i = 0; i < edges; i++) + { + printf("Edge %d \nEnter source: ", i + 1); + scanf("%d", &src); + printf("Enter destination: "); + scanf("%d", &dst); + addEdge(graph, src, dst); + } + printf("One topological sort order is:\n"); + topologicalSort(graph); + printf("\n"); + + // Uncomment below part to get a ready-made example + /*struct Graph* graph2 = createGraph(4); + addEdge(graph2, 0, 1); + addEdge(graph2, 0, 2); + addEdge(graph2, 1, 2); + addEdge(graph2, 2, 3); + printf("One topological sort is:\n"); + topologicalSort(graph2); + printf("\n");*/ + return 0; +} + +void topologicalSortHelper(int vertex, struct Graph *graph, struct Stack *stack) +{ + graph->visited[vertex] = 1; + struct node *adjList = graph->adjLists[vertex]; + struct node *temp = adjList; + // First add all dependents (that is, children) to stack + while (temp != NULL) + { + int connectedVertex = temp->vertex; + if (graph->visited[connectedVertex] == 0) + { + topologicalSortHelper(connectedVertex, graph, stack); + } + temp = temp->next; + } + // and then add itself + push(stack, vertex); +} + +// Recursive topologial sort approach +void topologicalSort(struct Graph *graph) +{ + struct Stack *stack = createStack(); + int i = 0; + for (i = 0; i < graph->numVertices; i++) + { + // Execute topological sort on all elements + if (graph->visited[i] == 0) + { + topologicalSortHelper(i, graph, stack); + } + } + while (stack->top != -1) printf("%d ", pop(stack)); +} +// Allocate memory for a node +struct node *createNode(int v) +{ + struct node *newNode = malloc(sizeof(struct node)); + newNode->vertex = v; + newNode->next = NULL; + return newNode; +} +// Allocate memory for the entire graph structure +struct Graph *createGraph(int vertices) +{ + struct Graph *graph = malloc(sizeof(struct Graph)); + graph->numVertices = vertices; + graph->adjLists = malloc(vertices * sizeof(struct node *)); + graph->visited = malloc(vertices * sizeof(int)); + + int i; + for (i = 0; i < vertices; i++) + { + graph->adjLists[i] = NULL; + graph->visited[i] = 0; + } + return graph; +} +// Creates a unidirectional graph +void addEdge(struct Graph *graph, int src, int dest) +{ + // Add edge from src to dest + struct node *newNode = createNode(dest); + newNode->next = graph->adjLists[src]; + graph->adjLists[src] = newNode; +} +// Utility function to see state of graph at a given time +void printGraph(struct Graph *graph) +{ + int v; + for (v = 0; v < graph->numVertices; v++) + { + struct node *temp = graph->adjLists[v]; + printf("\n Adjacency list of vertex %d\n ", v); + while (temp) + { + printf("%d -> ", temp->vertex); + temp = temp->next; + } + printf("\n"); + } +} +// Creates a stack +struct Stack *createStack() +{ + struct Stack *stack = malloc(sizeof(struct Stack)); + stack->top = -1; + return stack; +} +// Pushes element into stack +void push(struct Stack *stack, int element) +{ + stack->arr[++stack->top] = + element; // Increment then add, as we start from -1 +} +// Removes element from stack, or returns INT_MIN if stack empty +int pop(struct Stack *stack) +{ + if (stack->top == -1) + return INT_MIN; + else + return stack->arr[stack->top--]; +} diff --git a/data_structures/graphs/transitive_closure.c b/data_structures/graphs/transitive_closure.c new file mode 100644 index 0000000000..32ceae03a9 --- /dev/null +++ b/data_structures/graphs/transitive_closure.c @@ -0,0 +1,60 @@ +#include +#include + +#define NODES 4 + +int digraph[NODES][NODES] = { + {0, 1, 1, 1}, {1, 0, 1, 0}, {0, 1, 0, 0}, {0, 0, 0, 0}}; +int tc[NODES][NODES]; + +void warshall() +{ + int i, s, t; + for (s = 0; s < NODES; s++) + for (t = 0; t < NODES; t++) tc[s][t] = digraph[s][t]; + + for (i = 0; i < NODES; i++) + for (s = 0; s < NODES; s++) + for (t = 0; t < NODES; t++) + if (tc[s][i] && tc[i][t]) + tc[s][t] = 1; +} + +int main(void) +{ + warshall(); + int i, j; + for (i = 0; i < NODES; i++) + { + for (j = 0; j < NODES; j++) + { + printf("%d ", tc[i][j]); + } + putchar('\n'); + } + return 0; +} + +// By +// .----------------. .----------------. .----------------. +// .-----------------. .----------------. .----------------. +// | .--------------. || .--------------. || .--------------. || +// .--------------. | | .--------------. || .--------------. | | | _________ | +// || | _____ _____ | || | __ | || | ____ _____ | | | | ____ ____ +// | || | ____ | | | | | _ _ | | || ||_ _||_ _|| || | / \ +// | || ||_ \|_ _| | | | | |_ || _| | || | .' `. | | | | |_/ | | +// \_| | || | | | | | | || | / /\ \ | || | | \ | | | | | | | +// |__| | | || | / .--. \ | | | | | | | || | | ' ' | | || | +// / ____ \ | || | | |\ \| | | | | | | __ | | || | | | | | | | +// | | _| |_ | || | \ `--' / | || | _/ / \ \_ | || | _| |_\ |_ +// | | | | _| | | |_ | || | \ `--' / | | | | |_____| | || | `.__.' +// | || ||____| |____|| || ||_____|\____| | | | | |____||____| | || | `.____.' +// | | | | | || | | || | | || | | | | | +// | || | | | | '--------------' || '--------------' || +// '--------------' || '--------------' | | '--------------' || '--------------' +// | +// '----------------' '----------------' '----------------' +// '----------------' '----------------' '----------------' + +// Email : z5261243@unsw.edu.au +// hhoanhtuann@gmail.com diff --git a/data_structures/hash_set/Makefile b/data_structures/hash_set/Makefile new file mode 100644 index 0000000000..275be8bdcb --- /dev/null +++ b/data_structures/hash_set/Makefile @@ -0,0 +1,13 @@ +CC = gcc +CFLAGS = -g -Wall + +all: main + +main: main.o hash_set.o + $(CC) $(CFLAGS) $^ -o $@ + +hash_set.o: hash_set.c + $(CC) $(CFLAGS) -c $^ + +clean: + rm *.o main \ No newline at end of file diff --git a/data_structures/hash_set/hash_set.c b/data_structures/hash_set/hash_set.c new file mode 100644 index 0000000000..f7ea46b44d --- /dev/null +++ b/data_structures/hash_set/hash_set.c @@ -0,0 +1,101 @@ +#include +#include + +#include "hash_set.h" + +extern hash_set_t *init_hash_set() +{ + hash_set_t *set = (hash_set_t *)malloc(sizeof(hash_set_t)); + set->keys = calloc(DEFAULT_HASH_SET_CAPACITY, sizeof(void **)); + set->values = calloc(DEFAULT_HASH_SET_CAPACITY, sizeof(void **)); + set->length = 0; + set->capacity = DEFAULT_HASH_SET_CAPACITY; + + return set; +} + +unsigned add(hash_set_t *set, void *value) +{ + return put(set, hash(value), value); +} + +unsigned put(hash_set_t *set, long long hash, void *value) +{ + if (contains_hash(set, hash)) + { + if (set->keys[retrieve_index_from_hash(hash, set->capacity)] == value) + { + return 0; + } + + // collision + resize(set); + + return put(set, hash, value); + } + + set->keys[retrieve_index_from_hash(hash, set->capacity)] = value; + set->values[set->length++] = value; + + return 1; +} + +int contains(hash_set_t *set, void *value) +{ + return set->keys[retrieve_index_from_hash(hash(value), set->capacity)] == + value + ? 1 + : 0; +} + +int contains_hash(hash_set_t *set, long long hash) +{ + return set->keys[retrieve_index_from_hash(hash, set->capacity)] ? 1 : 0; +} + +void delete (hash_set_t *set, void *value) +{ + set->keys[retrieve_index_from_hash(hash(value), set->capacity)] = NULL; +} + +// adler_32 hash +long long hash(void *value) +{ + char *str = value; + + int a = 1; + int b = 0; + const int MODADLER = 65521; + + for (int i = 0; str[i] != '\0'; i++) + { + a = (a + str[i]) % MODADLER; + b = (b + a) % MODADLER; + } + + return (b << 16) | a; +} + +unsigned retrieve_index_from_hash(const long long hash, const unsigned capacity) +{ + return (capacity - 1) & (hash ^ (hash >> 12)); +} + +void resize(hash_set_t *set) +{ + void **keys_resized = calloc((set->capacity <<= 1), sizeof(void **)); + + for (int i = 0; i < set->length; i++) + { + keys_resized[retrieve_index_from_hash(hash(set->values[i]), + set->capacity)] = set->values[i]; + } + + free(set->keys); + + set->keys = keys_resized; + + void **new_values = + (void **)realloc(set->values, set->capacity * sizeof(void **)); + set->values = new_values; +} diff --git a/data_structures/hash_set/hash_set.h b/data_structures/hash_set/hash_set.h new file mode 100644 index 0000000000..593c3251e1 --- /dev/null +++ b/data_structures/hash_set/hash_set.h @@ -0,0 +1,33 @@ +#ifndef __HASH_SET__ +#define __HASH_SET__ + +#define DEFAULT_HASH_SET_CAPACITY 1 << 10 + +typedef struct +{ + unsigned capacity; + unsigned length; + void **values; + void **keys; +} hash_set_t; + +extern hash_set_t *init_hash_set(); + +extern unsigned add(hash_set_t *set, void *value); + +unsigned put(hash_set_t *set, long long hash, void *value); + +extern int contains(hash_set_t *set, void *value); + +int contains_hash(hash_set_t *set, long long hash); + +extern void delete (hash_set_t *set, void *value); + +extern long long hash(void *value); + +extern unsigned retrieve_index_from_hash(const long long hash, + const unsigned capacity); + +extern void resize(hash_set_t *set); + +#endif \ No newline at end of file diff --git a/data_structures/hash_set/main.c b/data_structures/hash_set/main.c new file mode 100644 index 0000000000..badc1cf7c6 --- /dev/null +++ b/data_structures/hash_set/main.c @@ -0,0 +1,42 @@ +#include + +#include "hash_set.h" + +int main() +{ + hash_set_t *set = init_hash_set(); + + int v1 = 10, v2 = 20, v3 = 30, v4 = 40, v5 = 50, v6 = 60, v7 = 70; + + printf("Value %d was add ? %d\n", v1, add(set, &v1)); + printf("Value %d was add ? %d\n", v1, add(set, &v1)); + printf("contains %d ? %d\n", v1, contains(set, &v1)); + + printf("Value %d was add ? %d\n", v2, add(set, &v2)); + printf("Value %d was add ? %d\n", v2, add(set, &v2)); + printf("contains %d ? %d\n", v2, contains(set, &v2)); + + printf("Value %d was add ? %d\n", v3, add(set, &v3)); + printf("Value %d is add ? %d\n", v3, add(set, &v3)); + printf("contains %d ? %d\n", v3, contains(set, &v3)); + + printf("Value %d was add ? %d\n", v4, add(set, &v4)); + printf("Value %d was add ? %d\n", v4, add(set, &v4)); + printf("contains %d ? %d\n", v4, contains(set, &v4)); + + printf("Value %d was add ? %d\n", v5, add(set, &v5)); + printf("Value %d was add ? %d\n", v5, add(set, &v5)); + printf("contains %d ? %d\n", v5, contains(set, &v5)); + + printf("Value %d is add ? %d\n", v6, add(set, &v6)); + printf("Value %d is add ? %d\n", v6, add(set, &v6)); + printf("contains %d ? %d\n", v6, contains(set, &v6)); + + printf("contains %d ? %d\n", v7, contains(set, &v7)); + + delete (set, &v6); + + printf("contains %d ? %d\n", v6, contains(set, &v6)); + + return 0; +} \ No newline at end of file diff --git a/data_structures/heap/max_heap.c b/data_structures/heap/max_heap.c new file mode 100644 index 0000000000..97ec2dec94 --- /dev/null +++ b/data_structures/heap/max_heap.c @@ -0,0 +1,149 @@ +#include /// for INT_MIN +#include /// for IO operations +#include /// for dynamic memory allocation + +typedef struct max_heap +{ + int *p; + int size; + int count; +} Heap; + +Heap *create_heap(Heap *heap); /*Creates a max_heap structure and returns a + pointer to the struct*/ +void down_heapify(Heap *heap, int index); /*Pushes an element downwards in the + heap to find its correct position*/ +void up_heapify(Heap *heap, int index); /*Pushes an element upwards in the heap + to find its correct position*/ +void push(Heap *heap, int x); /*Inserts an element in the heap*/ +void pop(Heap *heap); /*Removes the top element from the heap*/ +int top(Heap *heap); /*Returns the top element of the heap or returns INT_MIN if + heap is empty*/ +int empty(Heap *heap); /*Checks if heap is empty*/ +int size(Heap *heap); /*Returns the size of heap*/ + +int main() +{ + Heap *head = create_heap(head); + push(head, 10); + printf("Pushing element : 10\n"); + push(head, 3); + printf("Pushing element : 3\n"); + push(head, 2); + printf("Pushing element : 2\n"); + push(head, 8); + printf("Pushing element : 8\n"); + printf("Top element = %d \n", top(head)); + push(head, 1); + printf("Pushing element : 1\n"); + push(head, 7); + printf("Pushing element : 7\n"); + printf("Top element = %d \n", top(head)); + pop(head); + printf("Popping an element.\n"); + printf("Top element = %d \n", top(head)); + pop(head); + printf("Popping an element.\n"); + printf("Top element = %d \n", top(head)); + printf("\n"); + return 0; +} +Heap *create_heap(Heap *heap) +{ + heap = (Heap *)malloc(sizeof(Heap)); + heap->size = 1; + heap->p = (int *)malloc(heap->size * sizeof(int)); + heap->count = 0; + return heap; +} + +void down_heapify(Heap *heap, int index) +{ + if (index >= heap->count) + return; + int left = index * 2 + 1; + int right = index * 2 + 2; + int leftflag = 0, rightflag = 0; + + int maximum = *((heap->p) + index); + if (left < heap->count && maximum < *((heap->p) + left)) + { + maximum = *((heap->p) + left); + leftflag = 1; + } + if (right < heap->count && maximum < *((heap->p) + right)) + { + maximum = *((heap->p) + right); + leftflag = 0; + rightflag = 1; + } + if (leftflag) + { + *((heap->p) + left) = *((heap->p) + index); + *((heap->p) + index) = maximum; + down_heapify(heap, left); + } + if (rightflag) + { + *((heap->p) + right) = *((heap->p) + index); + *((heap->p) + index) = maximum; + down_heapify(heap, right); + } +} +void up_heapify(Heap *heap, int index) +{ + int parent = (index - 1) / 2; + if (parent < 0) + return; + if (*((heap->p) + index) > *((heap->p) + parent)) + { + int temp = *((heap->p) + index); + *((heap->p) + index) = *((heap->p) + parent); + *((heap->p) + parent) = temp; + up_heapify(heap, parent); + } +} + +void push(Heap *heap, int x) +{ + if (heap->count >= heap->size) + return; + *((heap->p) + heap->count) = x; + heap->count++; + if (4 * heap->count >= 3 * heap->size) + { + heap->size *= 2; + (heap->p) = (int *)realloc((heap->p), (heap->size) * sizeof(int)); + } + up_heapify(heap, heap->count - 1); +} +void pop(Heap *heap) +{ + if (heap->count == 0) + return; + heap->count--; + int temp = *((heap->p) + heap->count); + *((heap->p) + heap->count) = *(heap->p); + *(heap->p) = temp; + down_heapify(heap, 0); + if (4 * heap->count <= heap->size) + { + heap->size /= 2; + (heap->p) = (int *)realloc((heap->p), (heap->size) * sizeof(int)); + } +} +int top(Heap *heap) +{ + if (heap->count != 0) + return *(heap->p); + else + return INT_MIN; +} +int empty(Heap *heap) +{ + if (heap->count != 0) + return 0; + else + return 1; +} +int size(Heap *heap) { return heap->count; } diff --git a/data_structures/heap/min_heap.c b/data_structures/heap/min_heap.c new file mode 100644 index 0000000000..88bfee1ce0 --- /dev/null +++ b/data_structures/heap/min_heap.c @@ -0,0 +1,148 @@ +#include +#include + +typedef struct min_heap +{ + int *p; + int size; + int count; +} Heap; + +Heap *create_heap(Heap *heap); /*Creates a min_heap structure and returns a + pointer to the struct*/ +void down_heapify(Heap *heap, int index); /*Pushes an element downwards in the + heap to find its correct position*/ +void up_heapify(Heap *heap, int index); /*Pushes an element upwards in the heap + to find its correct position*/ +void push(Heap *heap, int x); /*Inserts an element in the heap*/ +void pop(Heap *heap); /*Removes the top element from the heap*/ +int top(Heap *heap); /*Returns the top element of the heap or returns INT_MIN if + heap is empty*/ +int empty(Heap *heap); /*Checks if heap is empty*/ +int size(Heap *heap); /*Returns the size of heap*/ + +int main() +{ + Heap *head = create_heap(head); + push(head, 10); + printf("Pushing element : 10\n"); + push(head, 3); + printf("Pushing element : 3\n"); + push(head, 2); + printf("Pushing element : 2\n"); + push(head, 8); + printf("Pushing element : 8\n"); + printf("Top element = %d \n", top(head)); + push(head, 1); + printf("Pushing element : 1\n"); + push(head, 7); + printf("Pushing element : 7\n"); + printf("Top element = %d \n", top(head)); + pop(head); + printf("Popping an element.\n"); + printf("Top element = %d \n", top(head)); + pop(head); + printf("Popping an element.\n"); + printf("Top element = %d \n", top(head)); + printf("\n"); + return 0; +} +Heap *create_heap(Heap *heap) +{ + heap = (Heap *)malloc(sizeof(Heap)); + heap->size = 1; + heap->p = (int *)malloc(heap->size * sizeof(int)); + heap->count = 0; + return heap; +} + +void down_heapify(Heap *heap, int index) +{ + if (index >= heap->count) + return; + int left = index * 2 + 1; + int right = index * 2 + 2; + int leftflag = 0, rightflag = 0; + + int minimum = *((heap->p) + index); + if (left < heap->count && minimum > *((heap->p) + left)) + { + minimum = *((heap->p) + left); + leftflag = 1; + } + if (right < heap->count && minimum > *((heap->p) + right)) + { + minimum = *((heap->p) + right); + leftflag = 0; + rightflag = 1; + } + if (leftflag) + { + *((heap->p) + left) = *((heap->p) + index); + *((heap->p) + index) = minimum; + down_heapify(heap, left); + } + if (rightflag) + { + *((heap->p) + right) = *((heap->p) + index); + *((heap->p) + index) = minimum; + down_heapify(heap, right); + } +} +void up_heapify(Heap *heap, int index) +{ + int parent = (index - 1) / 2; + if (parent < 0) + return; + if (*((heap->p) + index) < *((heap->p) + parent)) + { + int temp = *((heap->p) + index); + *((heap->p) + index) = *((heap->p) + parent); + *((heap->p) + parent) = temp; + up_heapify(heap, parent); + } +} + +void push(Heap *heap, int x) +{ + if (heap->count >= heap->size) + return; + *((heap->p) + heap->count) = x; + heap->count++; + if (4 * heap->count >= 3 * heap->size) + { + heap->size *= 2; + (heap->p) = (int *)realloc((heap->p), (heap->size) * sizeof(int)); + } + up_heapify(heap, heap->count - 1); +} +void pop(Heap *heap) +{ + if (heap->count == 0) + return; + heap->count--; + int temp = *((heap->p) + heap->count); + *((heap->p) + heap->count) = *(heap->p); + *(heap->p) = temp; + down_heapify(heap, 0); + if (4 * heap->count <= heap->size) + { + heap->size /= 2; + (heap->p) = (int *)realloc((heap->p), (heap->size) * sizeof(int)); + } +} +int top(Heap *heap) +{ + if (heap->count != 0) + return *(heap->p); + else + return INT_MIN; +} +int empty(Heap *heap) +{ + if (heap->count != 0) + return 0; + else + return 1; +} +int size(Heap *heap) { return heap->count; } diff --git a/data_structures/linked_list/ascending_priority_queue.c b/data_structures/linked_list/ascending_priority_queue.c new file mode 100644 index 0000000000..e252dc5837 --- /dev/null +++ b/data_structures/linked_list/ascending_priority_queue.c @@ -0,0 +1,283 @@ +/* Ascending priority queue using Linked List - Program to implement Ascending + * priority queue using Linked List */ + +/*A priority queue is a special type of queue in which each element is +associated with a priority and is served according to its priority. If elements +with the same priority occur, they are served according to their order in the +queue. + +Generally, the value of the element itself is considered for assigning the +priority. + +For example: The element with the highest value is considered as the highest +priority element. However, in other cases, we can assume the element with the +lowest value as the highest priority element. In other cases, we can set +priorities according to our needs. + +In a queue, the first-in-first-out rule is implemented whereas, in a priority +queue, the values are removed on the basis of priority. The element with the +highest priority is removed first. + +insert() - Would insert an element in a queue +delete() - Would delete the smallest element in the queue +*/ + +#include +#include +#define NULL ((void *)0) + +struct node +{ + int data; + struct node *next; +}; + +struct node *front, *rear; + +/* This function initializes the queue to empty by making both front and rear as + * NULL */ +void createqueue() { front = rear = NULL; } + +int empty() +{ + if (front == NULL) + return 1; + else + return 0; +} + +void insert(int x) +{ + struct node *pnode; + + pnode = (struct node *)malloc(sizeof(struct node)); + if (pnode == NULL) + { + printf("Memory overflow. Unable to insert.\n"); + exit(1); + } + + pnode->data = x; + pnode->next = NULL; /* New node is always last node */ + + if (empty()) + front = rear = pnode; + else + { + rear->next = pnode; + rear = pnode; + } +} + +int removes() +{ + int min; + struct node *follow, *follow1, *p, *p1; + + if (empty()) + { + printf("\nQueue Underflow. Unable to remove."); + exit(1); + } + + /* finding the node with minimum value in the APQ.*/ + p = p1 = front; + follow = follow1 = NULL; + min = front->data; + while (p != NULL) + { + if (p->data < min) + { + min = p->data; + follow1 = follow; + p1 = p; + } + follow = p; + p = p->next; + } + + /* Deleting the node with min value */ + + if (p1 == front) /* deleting first node.*/ + { + front = front->next; + if (front == NULL) /* Deleting the only one node */ + rear = NULL; + } + else if (p1 == rear) /* Deleting last node */ + { + rear = follow1; + rear->next = NULL; + } + else /* deleting any other node.*/ + follow1->next = p1->next; + + free(p1); + return min; /* DONT FORGET LAST 2 STATEMENTS.*/ +} + +void show() +{ + struct node *p; + + if (empty()) + printf("Queue empty. No data to display \n"); + else + { + printf("Queue from front to rear is as shown: \n"); + + p = front; + while (p != NULL) + { + printf("%d ", p->data); + p = p->next; + } + + printf("\n"); + } +} + +void destroyqueue() { front = rear = NULL; } + +int main() +{ + int x, ch; + + createqueue(); + + do + { + printf("\n\n Menu: \n"); + printf("1:Insert \n"); + printf("2:Remove \n"); + printf("3:exit \n"); + printf("Enter your choice: "); + scanf("%d", &ch); + + switch (ch) + { + case 1: + printf("Enter element to be inserted: "); + scanf("%d", &x); + insert(x); + show(); + break; + + case 2: + x = removes(); + printf("Element removed is: %d\n", x); + show(); + break; + + case 3: + break; + } + } while (ch != 3); + + destroyqueue(); + + return 0; +} + +/* Output of the Program*/ + +/* + Menu: +1:Insert +2:Remove +3:exit +Enter your choice: 1 +Enter element to be inserted: 12 +Queue from front to rear is as shown: +12 + + + Menu: +1:Insert +2:Remove +3:exit +Enter your choice: 1 +Enter element to be inserted: 1 +Queue from front to rear is as shown: +12 1 + + + Menu: +1:Insert +2:Remove +3:exit +Enter your choice: 1 +Enter element to be inserted: 14 +Queue from front to rear is as shown: +12 1 14 + + + Menu: +1:Insert +2:Remove +3:exit +Enter your choice: 1 +Enter element to be inserted: 3 +Queue from front to rear is as shown: +12 1 14 3 + + + Menu: +1:Insert +2:Remove +3:exit +Enter your choice: 1 +Enter element to be inserted: 5 +Queue from front to rear is as shown: +12 1 14 3 5 + + + Menu: +1:Insert +2:Remove +3:exit +Enter your choice: 2 +Element removed is: 1 +Queue from front to rear is as shown: +12 14 3 5 + + + Menu: +1:Insert +2:Remove +3:exit +Enter your choice: 2 +Element removed is: 3 +Queue from front to rear is as shown: +12 14 5 + + + Menu: +1:Insert +2:Remove +3:exit +Enter your choice: 2 +Element removed is: 5 +Queue from front to rear is as shown: +12 14 + + + Menu: +1:Insert +2:Remove +3:exit +Enter your choice: 2 +Element removed is: 12 +Queue from front to rear is as shown: +14 + + + Menu: +1:Insert +2:Remove +3:exit +Enter your choice: 2 +Element removed is: 14 +Queue empty. No data to display + +*/ diff --git a/data_structures/linked_list/circular_doubly_linked_list.c b/data_structures/linked_list/circular_doubly_linked_list.c new file mode 100644 index 0000000000..d2302e06b9 --- /dev/null +++ b/data_structures/linked_list/circular_doubly_linked_list.c @@ -0,0 +1,304 @@ +/** + * @file + * + * @details + * Circular [Doubly Linked + * List](https://en.wikipedia.org/wiki/Doubly_linked_list) combines the + * properties of a doubly linked list and a circular linked list in which two + * consecutive elements are linked or connected by the previous. Next, the + * pointer and the last node point to the first node via the next pointer, and + * the first node points to the last node via the previous pointer. + * + * In this implementation, functions to insert at the head, insert at the last + * index, delete the first node, delete the last node, display list, and get + * list size functions are coded. + * + * @author [Sahil Kandhare](https://github.com/SahilK-027) + * + */ + +#include /// to verify assumptions made by the program and print a diagnostic message if this assumption is false. +#include /// to provide a set of integer types with universally consistent definitions that are operating system-independent +#include /// for IO operations +#include /// for including functions involving memory allocation such as `malloc` + +/** + * @brief Circular Doubly linked list struct + */ +typedef struct node +{ + struct node *prev, *next; ///< List pointers + uint64_t value; ///< Data stored on each node +} ListNode; + +/** + * @brief Create a list node + * @param data the data that the node initialises with + * @return ListNode* pointer to the newly created list node + */ +ListNode *create_node(uint64_t data) +{ + ListNode *new_list = (ListNode *)malloc(sizeof(ListNode)); + new_list->value = data; + new_list->next = new_list; + new_list->prev = new_list; + return new_list; +} + +/** + * @brief Insert a node at start of list + * @param head start pointer of list + * @param data the data that the node initialises with + * @return ListNode* pointer to the newly created list node + * inserted at the head + */ +ListNode *insert_at_head(ListNode *head, uint64_t data) +{ + if (head == NULL) + { + head = create_node(data); + return head; + } + else + { + ListNode *temp; + ListNode *new_node = create_node(data); + temp = head->prev; + new_node->next = head; + head->prev = new_node; + new_node->prev = temp; + temp->next = new_node; + head = new_node; + return head; + } +} + +/** + * @brief Insert a node at end of list + * + * @param head start pointer of list + * @param data the data that the node initialises with + * @return ListNode* pointer to the newly added list node that was + * inserted at the head of list. + */ +ListNode *insert_at_tail(ListNode *head, uint64_t data) +{ + if (head == NULL) + { + head = create_node(data); + return head; + } + else + { + ListNode *temp1, *temp2; + ListNode *new_node = create_node(data); + temp1 = head; + temp2 = head->prev; + new_node->prev = temp2; + new_node->next = temp1; + temp1->prev = new_node; + temp2->next = new_node; + return head; + } +} + +/** + * @brief Function for deletion of the first node in list + * + * @param head start pointer of list + * @return ListNode* pointer to the list node after deleting first node + */ +ListNode *delete_from_head(ListNode *head) +{ + if (head == NULL) + { + printf("The list is empty\n"); + return head; + } + ListNode *temp1, *temp2; + temp1 = head; + temp2 = temp1->prev; + if (temp1 == temp2) + { + free(temp2); + head = NULL; + return head; + } + temp2->next = temp1->next; + (temp1->next)->prev = temp2; + head = temp1->next; + free(temp1); + return head; +} + +/** + * @brief Function for deletion of the last node in list + * + * @param head start pointer of list + * @return ListNode* pointer to the list node after deleting first node + */ +ListNode *delete_from_tail(ListNode *head) +{ + if (head == NULL) + { + printf("The list is empty\n"); + return head; + } + + ListNode *temp1, *temp2; + temp1 = head; + temp2 = temp1->prev; + if (temp1 == temp2) + { + free(temp2); + head = NULL; + return head; + } + (temp2->prev)->next = temp1; + temp1->prev = temp2->prev; + free(temp2); + return head; +} + +/** + * @brief The function that will return current size of list + * + * @param head start pointer of list + * @return int size of list + */ +int getsize(ListNode *head) +{ + if (!head) + { + return 0; + } + int size = 1; + ListNode *temp = head->next; + while (temp != head) + { + temp = temp->next; + size++; + } + return size; +} + +/** + * @brief Display list function + * @param head start pointer of list + * @returns void + */ + +void display_list(ListNode *head) +{ + printf("\nContents of your linked list: "); + ListNode *temp; + temp = head; + if (head != NULL) + { + while (temp->next != head) + { + printf("%" PRIu64 " <-> ", temp->value); + temp = temp->next; + } + if (temp->next == head) + { + printf("%" PRIu64, temp->value); + } + } + else + { + printf("The list is empty"); + } + printf("\n"); +} + +/** + * @brief access the list by index + * @param list pointer to the target list + * @param index access location + * @returns the value at the specified index, + * wrapping around if the index is larger than the size of the target + * list + */ +uint64_t get(ListNode *list, const int index) +{ + if (list == NULL || index < 0) + { + exit(EXIT_FAILURE); + } + ListNode *temp = list; + for (int i = 0; i < index; ++i) + { + temp = temp->next; + } + return temp->value; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() +{ + ListNode *testList = NULL; + unsigned int array[] = {2, 3, 4, 5, 6}; + + assert(getsize(testList) == 0); + + printf("Testing inserting elements:\n"); + for (int i = 0; i < 5; ++i) + { + display_list(testList); + testList = insert_at_head(testList, array[i]); + assert(testList->value == array[i]); + assert(getsize(testList) == i + 1); + } + + printf("\nTesting removing elements:\n"); + for (int i = 4; i > -1; --i) + { + display_list(testList); + assert(testList->value == array[i]); + testList = delete_from_head(testList); + assert(getsize(testList) == i); + } + + printf("\nTesting inserting at tail:\n"); + for (int i = 0; i < 5; ++i) + { + display_list(testList); + testList = insert_at_tail(testList, array[i]); + assert(get(testList, i) == array[i]); + assert(getsize(testList) == i + 1); + } + + printf("\nTesting removing from tail:\n"); + for (int i = 4; i > -1; --i) + { + display_list(testList); + testList = delete_from_tail(testList); + assert(getsize(testList) == i); + // If list is not empty, assert that accessing the just removed element + // will wrap around to the list head + if (testList != NULL) + { + assert(get(testList, i) == testList->value); + } + else + { + // If the list is empty, assert that the elements were removed after + // the correct number of iterations + assert(i == 0); + } + } +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + test(); // run self-test implementations + return 0; +} diff --git a/data_structures/linked_list/circular_linked_list.c b/data_structures/linked_list/circular_linked_list.c new file mode 100644 index 0000000000..6d923ae705 --- /dev/null +++ b/data_structures/linked_list/circular_linked_list.c @@ -0,0 +1,155 @@ +/* Circularly Linked List (Basic Operations) - Program to create a Circularly linked list abstract data type and perform various operations on it (Variable first and last declared globally) */ + +#include +#include +#include +#define NULL 0 + +/* Assume that the data portion of each node consists of ONLY an integer.*/ +struct node +{ + int data ; + struct node *next ; +} ; + +struct node *first=NULL ; +struct node *last=NULL ; +/* first and last are global variables and need not be passed to any function. Any changes made to variables first and last by any of the functions in the program will be reflected in the entire program */ + +/* This function is responsible for creating the Circularly Linked List right from the BEGINNING. */ +void create() +{ + int i , n ; + struct node *pnode , *p ; + + printf("Enter the number of nodes required:\n") ; + scanf("%d",&n) ; + + printf("Enter the data value of each node:\n") ; + for(i=1 ; i<=n ; i++) + { + pnode=(struct node*)malloc(sizeof(struct node)) ; + if(pnode==NULL) + { + printf("Memory overflow. Unable to create.\n") ; + return ; + } + + scanf("%d",&pnode->data) ; + + if(first==NULL) + first=last=pnode ; + else + { + last->next=pnode ; + last=pnode ; /* last keeps track of last node */ + } + + last->next=first ; + } +} + +/* This function will delete a node with value k from the Linked List if such a node exists */ +void deletenode(int k) +{ + struct node *p , *follow ; + + /* searching the required node */ + p=first ; + follow=NULL ; + while(follow!=last) + { + if(p->data==k) + break ; + follow=p ; + p=p->next ; + } + + if(follow==last) + printf("Required node not found.\n") ; + else + { + if(p==first&&p==last) /* deleting the one and the only node */ + first=last=NULL ; + else if(p==first) /* deleting the first node */ + { + first=first->next ; + last->next=first ; + } + else if(p==last) /* deleting the last node */ + { + last=follow ; + last->next=first ; + } + else /* deleting any other node */ + follow->next=p->next ; + + free(p) ; + } +} + +/* This function will go through all the nodes of Linked List exactly once and will display data value of each node */ +void traverse() +{ + struct node *p , *follow ; + if(first==NULL) + printf("Circularly Linked List Empty") ; + else + { + printf("Circularly Linked List is as shown: \n") ; + + p=first ; + follow = NULL ; + while(follow!=last) + { + printf("%d " , p->data) ; + follow=p ; + p=p->next ; + } + + printf("\n") ; + } +} + +void main() +{ + int x , k , ch ; + clrscr() ; + do + { + printf("\n Menu: \n") ; + printf("1:Create Linked List \n") ; + printf("2:Delete Node \n") ; + printf("3:Traverse \n") ; + printf("4:Exit \n") ; + + printf("\nEnter your choice: ") ; + scanf("%d",&ch) ; + + switch(ch) + { + case 1: + create() ; + break ; + + case 2: + printf("Enter the data value of the node to be deleted: ") ; + scanf("%d",&k) ; + deletenode(k) ; + break ; + + case 3: + traverse() ; + break ; + + case 4: + break ; + } + } + while(ch!=4) ; + + getch() ; +} + + + diff --git a/data_structures/linked_list/doubly_linked_list.c b/data_structures/linked_list/doubly_linked_list.c new file mode 100644 index 0000000000..8a3d9c48a6 --- /dev/null +++ b/data_structures/linked_list/doubly_linked_list.c @@ -0,0 +1,293 @@ +/** + * @file + * @brief Implementation of [Doubly linked list](https://en.wikipedia.org/wiki/Doubly_linked_list) + * @details + * A doubly linked list is a data structure with a sequence + * of components called nodes. Within that nodes there are + * three elements: a value recorded, a pointer to the next + * node, and a pointer to the previous node. + * + * In this implementation, the functions of creating the list, + * inserting by position, deleting by position, searching + * for value, printing the list, and an example of how the + * list works were coded. + * + * @author [Gabriel Mota Bromonschenkel Lima](https://github.com/GabrielMotaBLima) + */ +#include +#include + +/** + * @brief Doubly linked list struct + */ +typedef struct list +{ + double value; ///< value saved on each node + struct list *next, *prev; ///< directing to other nodes or NULL +} List; + +/** + * @brief Create list function, a new list containing one node will be created + * @param value a value to be saved into the first list node + * @returns new_list the list created + */ +List *create(double value); + +/** + * @brief Insertion by position into the list function + * @param list a doubly linked List + * @param value a value to be inserted into the list + * @param pos a position into the list for value insertion + * @returns list the input list with a node more or the same list + */ +List *insert(List *list, double value, int pos); + +/** + * @brief Deletion by position into the list function + * @param list a doubly linked List + * @param pos a position into the list for value Deletion + * @returns list the input list with deleted values or the same list + */ +List *delete(List *list, int pos); + +/** + * @brief Search value into the list function + * @param list a doubly linked list + * @param value a value to be looked for into the list + * @returns `1` if the looked up value exists + * @returns `0` if the looked up value doesn't exist + */ +int search(List *list, double value); + +/** + * @brief Print list function + * @param list a doubly linked List + * @returns void + */ +void print(List *list); + +/** + * @brief Example function + * @returns void + */ +void example(); + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + // examples for better understanding + example(); + // code here + return 0; +} + +/** + * @brief Create list function, a new list containing one node will be created + * @param value a value to be saved into the first list node + * @returns new_list the list created + */ +List *create(double value) +{ + List *new_list = (List *)malloc(sizeof(List)); + new_list->value = value; + new_list->next = NULL; + new_list->prev = NULL; + return new_list; +} + +/** + * @brief Insertion by position into the list function + * @param list a doubly linked List + * @param value a value to be inserted into the list + * @param pos a position into the list for value insertion + * @returns list the input list with a node more or the same list + */ +List *insert(List *list, double value, int pos) +{ + // list NULL case + if (list == NULL) + { + list = create(value); + return list; + } + + // position existing case + if (pos > 0) + { + List *cpy = list, *tmp = cpy; + int flag = 1, index = 1, size = 0; + + while (tmp != NULL) + { + size++; + tmp = tmp->next; + } + + // first position case + if (pos == 1) + { + List *new_node = create(value); + new_node->next = cpy; + cpy->prev = new_node; + list = new_node; + return list; + } + + // position existing in list range case + if (size + 2 > pos) + { + while (cpy->next != NULL && index < pos) + { + flag++; + index++; + cpy = cpy->next; + } + + List *new_node = (List *)malloc(sizeof(List)); + new_node->value = value; + + // position into list with no poiting for NULL + if (flag == pos) + { + cpy->prev->next = new_node; + new_node->next = cpy; + new_node->prev = cpy->prev; + cpy->prev = new_node; + } + + // last position case + if (flag < pos) + { + new_node->next = cpy->next; + new_node->prev = cpy; + cpy->next = new_node; + } + } + return list; + } +} + +/** + * @brief Deletion by position into the list function + * @param list a doubly linked List + * @param pos a position into the list for value Deletion + * @returns list the input list with deleted values or the same list + */ +List *delete(List *list, int pos) +{ + // list NULL case + if (list == NULL) + return list; + + // position existing case + if (pos > 0) + { + List *cpy = list, *tmp = cpy; + int flag = 1, index = 1, size = 0; + + while (tmp != NULL) + { + size++; + tmp = tmp->next; + } + + // first position case + if (pos == 1) + { + if (size == 1) + return NULL; + cpy = cpy->next; + cpy->prev = NULL; + return cpy; + } + + // position existing in list range case + if (size + 2 > pos) + { + while (cpy->next != NULL && index < pos) + { + flag++; + index++; + cpy = cpy->next; + } + + if (flag == pos) + { + // position into list with no poiting for NULL + if (cpy->next != NULL) + { + cpy->prev->next = cpy->next; + cpy->next->prev = cpy->prev; + } + + // last position case + else + cpy->prev->next = NULL; + } + } + return list; + } +} + +/** + * @brief Search value into the list function + * @param list a doubly linked list + * @param value a value to be looked for into the list + * @returns `1` if the looked up value exists + * @returns `0` if the looked up value doesn't exist + */ +int search(List *list, double value) +{ + if (list == NULL) + return 0; + if (list->value == value) + return 1; + search(list->next, value); +} + +/** + * @brief Print list function + * @param list a doubly linked List + * @returns void + */ +void print(List *list) +{ + if (list != NULL) + { + printf("%f\t", list->value); + print(list->next); + } +} + +/** + * @brief Example function + * @returns void + */ +void example() +{ + List *my_list = NULL; + double node_value = 0; + int searching; + + my_list = create(node_value); + my_list = insert(my_list, 3, 1); + my_list = insert(my_list, 5, 3); + my_list = insert(my_list, 10, 3); + my_list = insert(my_list, 20, 3); + + print(my_list); + searching = search(my_list, 20); + printf("\n%d\n", searching); + + my_list = delete (my_list, 1); + my_list = delete (my_list, 1); + my_list = delete (my_list, 1); + my_list = delete (my_list, 1); + + print(my_list); + searching = search(my_list, 20); + printf("\n%d\n", searching); +} diff --git a/data_structures/linked_list/mergeLinkedLists.c b/data_structures/linked_list/mergeLinkedLists.c deleted file mode 100644 index 0f95ff4e6e..0000000000 --- a/data_structures/linked_list/mergeLinkedLists.c +++ /dev/null @@ -1,103 +0,0 @@ -#include -#include -struct node{ - int data; - struct node *next; -}; - -struct node *head1 = NULL; -struct node *head2 = NULL; - -///// MAIN ALGORITHMIC FUNCTION to MERGE the two input linked lists /////// - -void merge() -{ - struct node *temp1 = head1; - struct node *temp2 = head2; - - struct node *holder1 = NULL; - struct node *holder2 = NULL; - //Temporary pointer variables to store the address of next node of the two input linked list - - while(temp1!=NULL && temp2!=NULL) - { - holder1 = temp1 -> next; - //Storing the address of next node of first linked list - temp1->next=temp2; - //Making the first node of first linked list point to first node of second linked list - - if(holder1!=NULL) { - //Making the first node of second linked list point to second node of first linked list - holder2 = temp2 -> next; - temp2 -> next = holder1; - } - temp1=holder1; - temp2=holder2; - //Updating the address location of two pointer variables temp1 and temp2 - } -} - -void printlist(struct node *temp){ - printf("%d",temp->data); - temp=temp->next; - while(temp!=NULL){ - printf("->%d",temp->data); - temp=temp->next; - } - printf("\n"); -} - -int main() -{ - // Linked List 1: 1->3->5->7 : Linked List 2: 2->4->6 - // making lists - struct node *one = (struct node*)malloc(sizeof(struct node)); - struct node *two = (struct node*)malloc(sizeof(struct node)); - struct node *three = (struct node*)malloc(sizeof(struct node)); - struct node *four = (struct node*)malloc(sizeof(struct node)); - struct node *five = (struct node*)malloc(sizeof(struct node)); - struct node *six = (struct node*)malloc(sizeof(struct node)); - struct node *seven = (struct node*)malloc(sizeof(struct node)); - //Seven nodes are created - - head1=one; - head2=two; - //head1 points to first node of first linked list - //head2 points to first node of second linked list - - one->data=1; - one->next=three; - - two->data=2; - two->next=four; - - three->data=3; - three->next=five; - - four->data=4; - four->next=six; - - five->data=5; - five->next=seven; - - six->data=6; - six->next=NULL; - //Last node of second input linked list - - seven->data=7; - seven->next=NULL; - //Last node of first input linked list - - printf("Linked List 1: "); - printlist(head1); - printf("\nLinked List 2: "); - printlist(head2); - - //Merging the two linked list into single linked list - merge(); - - printf("\nMerged Linked List: "); - printlist(head1); //list one has been modified - - return 0; -} diff --git a/data_structures/linked_list/merge_linked_lists.c b/data_structures/linked_list/merge_linked_lists.c new file mode 100644 index 0000000000..c3f5299d71 --- /dev/null +++ b/data_structures/linked_list/merge_linked_lists.c @@ -0,0 +1,111 @@ +#include +#include +struct node +{ + int data; + struct node *next; +}; + +struct node *head1 = NULL; +struct node *head2 = NULL; + +///// MAIN ALGORITHMIC FUNCTION to MERGE the two input linked lists /////// + +void merge() +{ + struct node *temp1 = head1; + struct node *temp2 = head2; + + struct node *holder1 = NULL; + struct node *holder2 = NULL; + // Temporary pointer variables to store the address of next node of the two + // input linked list + + while (temp1 != NULL && temp2 != NULL) + { + holder1 = temp1->next; + // Storing the address of next node of first linked list + temp1->next = temp2; + // Making the first node of first linked list point to first node of + // second linked list + + if (holder1 != NULL) + { + // Making the first node of second linked list point to second node + // of first linked list + holder2 = temp2->next; + temp2->next = holder1; + } + temp1 = holder1; + temp2 = holder2; + // Updating the address location of two pointer variables temp1 and + // temp2 + } +} + +void printlist(struct node *temp) +{ + printf("%d", temp->data); + temp = temp->next; + while (temp != NULL) + { + printf("->%d", temp->data); + temp = temp->next; + } + printf("\n"); +} + +int main() +{ + // Linked List 1: 1->3->5->7 : Linked List 2: 2->4->6 + // making lists + struct node *one = (struct node *)malloc(sizeof(struct node)); + struct node *two = (struct node *)malloc(sizeof(struct node)); + struct node *three = (struct node *)malloc(sizeof(struct node)); + struct node *four = (struct node *)malloc(sizeof(struct node)); + struct node *five = (struct node *)malloc(sizeof(struct node)); + struct node *six = (struct node *)malloc(sizeof(struct node)); + struct node *seven = (struct node *)malloc(sizeof(struct node)); + // Seven nodes are created + + head1 = one; + head2 = two; + // head1 points to first node of first linked list + // head2 points to first node of second linked list + + one->data = 1; + one->next = three; + + two->data = 2; + two->next = four; + + three->data = 3; + three->next = five; + + four->data = 4; + four->next = six; + + five->data = 5; + five->next = seven; + + six->data = 6; + six->next = NULL; + // Last node of second input linked list + + seven->data = 7; + seven->next = NULL; + // Last node of first input linked list + + printf("Linked List 1: "); + printlist(head1); + printf("\nLinked List 2: "); + printlist(head2); + + // Merging the two linked list into single linked list + merge(); + + printf("\nMerged Linked List: "); + printlist(head1); // list one has been modified + + return 0; +} diff --git a/data_structures/linked_list/middle_element_in_list.c b/data_structures/linked_list/middle_element_in_list.c new file mode 100644 index 0000000000..3437ce4bed --- /dev/null +++ b/data_structures/linked_list/middle_element_in_list.c @@ -0,0 +1,69 @@ +#include +#include + +/* Link list node */ +struct Node +{ + int data; + struct Node *next; +}; + +/* Function to get the middle of the linked list*/ +void printMiddle(struct Node *head) +{ + struct Node *slow_ptr = head; + struct Node *fast_ptr = head; + + if (head != NULL) + { + while (fast_ptr != NULL && fast_ptr->next != NULL) + { + fast_ptr = fast_ptr->next->next; + slow_ptr = slow_ptr->next; + } + printf("The middle element is [%d]\n\n", slow_ptr->data); + } +} + +void push(struct Node **head_ref, int new_data) +{ + /* allocate node */ + struct Node *new_node = (struct Node *)malloc(sizeof(struct Node)); + + /* put in the data */ + new_node->data = new_data; + + /* link the old list off the new node */ + new_node->next = (*head_ref); + + /* move the head to point to the new node */ + (*head_ref) = new_node; +} + +// A utility function to print a given linked list +void printList(struct Node *ptr) +{ + while (ptr != NULL) + { + printf("%d->", ptr->data); + ptr = ptr->next; + } + printf("NULL\n"); +} + +/* Drier program to test above function*/ +int main() +{ + /* Start with the empty list */ + struct Node *head = NULL; + int i; + + for (i = 5; i > 0; i--) + { + push(&head, i); + printList(head); + printMiddle(head); + } + + return 0; +} diff --git a/data_structures/linked_list/queue_linked_list.c b/data_structures/linked_list/queue_linked_list.c new file mode 100644 index 0000000000..5074edeafa --- /dev/null +++ b/data_structures/linked_list/queue_linked_list.c @@ -0,0 +1,141 @@ +/* Queue using Linked List - Program to create a queue ADT using linked list. +ADT should support the following operations 1) Createqueue 2) Insert into the +queue 3) Delete from the queue 4) destroyqueue +*/ + +/* queue q declared globally */ + +#include +#include +#define NULL 0 + +struct node +{ + int data; + struct node *next; +}; + +struct queue +{ + struct node *front, *rear; +}; + +struct queue q; + +/* This function initializes the queue to empty by making both front and rear as + * NULL */ +void createqueue() { q.front = q.rear = NULL; } + +int empty() +{ + if (q.front == NULL) + return 1; + else + return 0; +} + +void insert(int x) +{ + struct node *pnode; + + pnode = (struct node *)malloc(sizeof(struct node)); + if (pnode == NULL) + { + printf("Memory overflow. Unable to insert.\n"); + exit(1); + } + + pnode->data = x; + pnode->next = NULL; /* New node is always last node */ + + if (empty()) + q.front = q.rear = pnode; + else + { + (q.rear)->next = pnode; + q.rear = pnode; + } +} + +int removes() +{ + int x; + struct node *p; + + if (empty()) + { + printf("Queue Underflow. Unable to remove.\n"); + exit(1); + } + + p = q.front; + x = (q.front)->data; + q.front = (q.front)->next; + if (q.front == NULL) /* Queue contained only one node */ + q.rear = NULL; + free(p); + return x; +} + +void show() +{ + struct node *p; + + if (empty()) + printf("Queue empty. No data to display \n"); + else + { + printf("Queue from front to rear is as shown: \n"); + + p = q.front; + while (p != NULL) + { + printf("%d ", p->data); + p = p->next; + } + + printf("\n"); + } +} + +void destroyqueue() { q.front = q.rear = NULL; } + +int main() +{ + int x, ch; + + createqueue(); + + do + { + printf("\n\n Menu: \n"); + printf("1:Insert \n"); + printf("2:Remove \n"); + printf("3:exit \n"); + printf("Enter your choice: "); + scanf("%d", &ch); + + switch (ch) + { + case 1: + printf("Enter element to be inserted: "); + scanf("%d", &x); + insert(x); + show(); + break; + + case 2: + x = removes(); + printf("Element removed is: %d\n", x); + show(); + break; + + case 3: + break; + } + } while (ch != 3); + + destroyqueue(); + + return 0; +} diff --git a/data_structures/linked_list/singly_link_list_deletion.c b/data_structures/linked_list/singly_link_list_deletion.c index a02b75c030..f94aef54ba 100644 --- a/data_structures/linked_list/singly_link_list_deletion.c +++ b/data_structures/linked_list/singly_link_list_deletion.c @@ -1,98 +1,177 @@ -/*Includes structure for a node which can be use to make new nodes of the Linked List. - It is assumed that the data in nodes will be an integer, though - function can be modified according to the data type, easily. - deleteNode deletes a node when passed with a key of the node. +/*Includes structure for a node which can be use to make new nodes of the Linked + List. It is assumed that the data in nodes will be an integer, though function + can be modified according to the data type, easily. deleteNode deletes a node + when passed with a key of the node. */ -#include +#include +#include +#include struct node -{int info; - struct node *link; +{ + int info; + struct node *link; }; -struct node *start=NULL; -/////////////////////////////////////////////////////////// -struct node * createnode()//function to create node +struct node *start = NULL; +////////////////////////////////////////////////////////////////// +struct node *createnode() // function to create node { - struct node *t; - t=(struct node*)malloc(sizeof(struct node)); - return(t); + struct node *t; + t = (struct node *)malloc(sizeof(struct node)); + return (t); } -//////////////////////////////////////////////////////// -void insert()//function to insert at first location +////////////////////////////////////////////////////////////////// +int insert(int pos, int d) { - struct node *p; - p=createnode(); - printf("\nenter the number to insert"); - scanf("%d",&p->info); - p->link=NULL; - if(start==NULL) - { - start=p; - } - else - { - p->link=start; - start=p; - } -} -/////////////////////////////////////////////////////////// -void deleteion()//function to delete from first position + struct node *new; + new = createnode(); + new->info = d; + if (pos == 1) + { + new->link = NULL; + if (start == NULL) + { + start = new; + } + else + { + new->link = start; + start = new; + } + } + else + { + struct node *pre = start; + for (int i = 2; i < pos; i++) + { + if (pre == NULL) + { + break; + } + pre = pre->link; + } + if(pre==NULL) + { + printf("Position not found!"); + return 0; + } + new->link = pre->link; + pre->link = new; + } + return 0; + } + +/////////////////////////////////////////////////////////////////// +int deletion(int pos) // function to delete from any position { struct node *t; - if(start==NULL) + if (start == NULL) { printf("\nlist is empty"); } else { - struct node *p; - p=start; - start=start->link; - free(p); + if (pos == 1) + { + struct node *p; + p = start; + start = start->link; + free(p); + } + else + { + struct node *prev = start; + for (int i = 2; i < pos; i++) + { + if (prev == NULL) + { + printf("Position not found!"); + return 0; + } + prev = prev->link; + } + struct node *n = prev->link; // n points to required node to be deleted + prev->link = n->link; + free(n); + } } + return 0; } -/////////////////////////////////////////////////////// -void viewlist()//function to display values +/////////////////////////////////////////////////////////////////// +void viewlist() // function to display values { struct node *p; - if(start==NULL) + if (start == NULL) { printf("\nlist is empty"); } else - { p=start; - while(p!=NULL) + { + p = start; + while (p != NULL) { - printf("%d ",p->info); - p=p->link; + printf("%d ", p->info); + p = p->link; } } } -////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////// +static void test() +{ + insert(1, 39); + assert(start->info == 39); + insert(2, 10); + insert(3, 11); + deletion(1); + assert(start->info != 39); + printf("Self-tests successfully passed!\n"); +} +////////////////////////////////////////////////////////////////// int main() { - int n; - while(1) + int n = 0, pos = 0, p = 0, num = 0, c = 0; + printf("\n1.self test mode"); + printf("\n2.interactive mode"); + printf("\nenter your choice:"); + scanf("%d", &c); + if (c == 1) + { + test(); + } + else if (c == 2) { - printf("\n1.add value at first location"); - printf("\n2.delete value from first location"); - printf("\n3.view value"); - printf("\nenter your choice"); - scanf("%d",&n); - switch(n) + while (1) { - case 1: - insert(); - break; - case 2: - deleteion(); - break; - case 3: - viewlist(); - break; - default: - printf("\ninvalid choice"); + printf("\n1.add value at the given location"); + printf("\n2.delete value at the given location"); + printf("\n3.view list"); + printf("\nenter your choice :"); + scanf("%d", &n); + switch (n) + { + case 1: + printf("enter the position where the element is to be added :"); + scanf("%d", &p); + printf("enter the element is to be added :"); + scanf("%d", &num); + insert(p, num); + break; + case 2: + printf("enter the position where the element is to be deleted :"); + scanf("%d", &pos); + deletion(pos); + break; + case 3: + viewlist(); + break; + default: + printf("\ninvalid choice"); + } } } - return(0); + else + { + printf("Invalid choice"); + } + return 0; } diff --git a/data_structures/linked_list/stack_using_linked_lists.c b/data_structures/linked_list/stack_using_linked_lists.c new file mode 100644 index 0000000000..a3c473a72c --- /dev/null +++ b/data_structures/linked_list/stack_using_linked_lists.c @@ -0,0 +1,84 @@ +#include +#include +struct node +{ + int info; + struct node *link; +}; +struct node *top = NULL, *temp; +void push(struct node *); +void pop(struct node *); +void display(struct node *); + +int main() +{ + int x = 0, item; + printf("\t****stack using linked list****\n"); + while (x != 4) + { + printf("\n1. Push\n2. Pop\n3. Display\n4. Exit\n"); + printf("Enter your choice: "); + scanf("%d", &x); + switch (x) + { + case 1: + push(top); + break; + case 2: + pop(top); + break; + case 3: + display(top); + break; + case 4: + return 0; + } + } +} + +void push(struct node *p) +{ + int item; + struct node *temp; + temp = (struct node *)malloc(sizeof(struct node)); + printf("\nEnter element to be inserted: "); + scanf("%d", &item); + temp->info = item; + + temp->link = top; + top = temp; + + printf("Inserted successfully.\n"); +} +void pop(struct node *p) +{ + int item; + struct node *temp; + + if (top == NULL) + printf("\nStack is empty.\n"); + else + { + item = top->info; + temp = top; + top = top->link; + free(temp); + printf("\nElement popped is %d.\n", item); + } +} + +void display(struct node *p) +{ + if (top == NULL) + printf("\nStack is empty.\n"); + else + { + printf("\nElements in the stack are:\n"); + while (p != NULL) + { + printf("\t%d\n", p->info); + p = p->link; + } + // printf("%d\n",p->info); + } +} diff --git a/data_structures/linked_list/stack_using_linkedlists.c b/data_structures/linked_list/stack_using_linkedlists.c deleted file mode 100644 index 7945af702e..0000000000 --- a/data_structures/linked_list/stack_using_linkedlists.c +++ /dev/null @@ -1,92 +0,0 @@ -#include -#include -struct node -{ - int info; - struct node *link; -}; -struct node *top=NULL,*temp; -void push(struct node*); -void pop(struct node*); -void display(struct node*); - -int main() -{ - int x=0,item; - printf("\t****stack using linked list****\n"); - while(x!=4) - { - printf("enter your choice"); - printf("\n1.push\n2.pop\n3.display\n4.exit\n"); - scanf("%d",&x); - switch(x) - { - case 1: - push(top); - break; - case 2: pop(top); - break; - case 3: display(top); - break; - case 4: return 0; - - } - } - -} - -void push(struct node *p) -{ - int item; - struct node *temp; - temp=(struct node *)malloc(sizeof(struct node)); - printf("enter element to be inserted\n"); - scanf("%d",&item); - temp->info=item; - - - - temp->link=top; - top=temp; - - - - printf("inserted succesfully\n"); -} -void pop(struct node *p) -{ - int item; - struct node *temp; - - if(top==NULL) - printf("stack is empty\n"); - else{ - item=top->info; - temp=top; - top=top->link; - free(temp); - printf("Element popped is%d\n",item); - } - -} - - -void display(struct node *p) -{ - - if(top==NULL) - printf("stack is empty\n"); - else - { printf("Elements in the stack are\n"); - while(p!=NULL) - { - printf("%d\n",p->info); - p=p->link; - } - // printf("%d\n",p->info); - - } - -} - - diff --git a/data_structures/list/Makefile b/data_structures/list/Makefile new file mode 100644 index 0000000000..9fda5ca1d6 --- /dev/null +++ b/data_structures/list/Makefile @@ -0,0 +1,12 @@ +CC = gcc +CFLAGS = -g -c -Wall + +all: main +main: main.o list.o + $(CC) -g main.o list.o -o main + +list.o: list.c + $(CC) $(CFLAGS) list.c + +clean: + rm *o main diff --git a/data_structures/list/list.c b/data_structures/list/list.c new file mode 100644 index 0000000000..762ffdfaad --- /dev/null +++ b/data_structures/list/list.c @@ -0,0 +1,80 @@ +#include "list.h" +#include +#include +#include +#include +#include + +#define L List_T + +/* Initial list */ +L List_init(void) +{ + L list; + list = (L)malloc(sizeof(L)); + list->next = NULL; + return list; +} + +/* Push an element into top of the list */ +L List_push(L list, void *val) +{ + L new_elem = (L)malloc(sizeof(L)); + new_elem->val = val; + new_elem->next = list; + return new_elem; +} + +/* Length of list */ +int List_length(L list) +{ + int n; + for (n = 0; list; list = list->next) n++; + return n - 1; +} + +/* Convert list to array */ +void **List_toArray(L list) +{ + int i, n = List_length(list) + 1; + void **array = (void **)malloc((n + 1) * sizeof(*array)); + + for (i = 0; i < n; i++) + { + array[i] = list->val; + list = list->next; + } + array[i] = NULL; + return array; +} + +/* Create and return a list */ +L List_list(L list, void *val, ...) +{ + va_list ap; + L *p = &list; + + va_start(ap, val); + for (; val; val = va_arg(ap, void *)) + { + *p = malloc(sizeof(L)); + (*p)->val = val; + p = &(*p)->next; + } + *p = NULL; + va_end(ap); + return list; +} + +/* Append 2 lists together */ +L List_append(L list, L tail) +{ + L *p = &list; + while ((*p)->next) + { + p = &(*p)->next; + } + + *p = tail; + return list; +} diff --git a/data_structures/list/list.h b/data_structures/list/list.h new file mode 100644 index 0000000000..3d31f42de1 --- /dev/null +++ b/data_structures/list/list.h @@ -0,0 +1,24 @@ +#ifndef __LIST__ +#define __LIST__ + +#define L List_T +typedef struct L *L; + +struct L +{ + void *val; + L next; +}; + +extern L List_init(void); +extern L List_push(L list, void *val); +extern int List_length(L list); +extern void **List_toArray(L list); +extern L List_append(L list, L tail); +extern L List_list(L list, void *val, ...); +/* TODO */ +extern L List_copy(L list); +extern int List_pop(L *list); + +#undef L +#endif diff --git a/data_structures/list/main.c b/data_structures/list/main.c new file mode 100644 index 0000000000..95c11b6601 --- /dev/null +++ b/data_structures/list/main.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include "list.h" + +void print_list(char **array) +{ + int i; + for (i = 0; array[i]; i++) printf("%s", array[i]); + printf("\n"); +} + +int main() +{ + List_T list1, list2, list3; + char **str1 = (char **)malloc(100 * sizeof(char *)); + + list1 = List_init(); + list1 = List_push(list1, "Dang "); + list1 = List_push(list1, "Hoang "); + list1 = List_push(list1, "Hai "); + printf("List 1: "); + str1 = (char **)List_toArray(list1); + print_list(str1); + + list2 = List_init(); + list2 = List_list(list2, "Mentor ", "Graphics ", "Siemens", NULL); + printf("List 2: "); + print_list((char **)List_toArray(list2)); + + list3 = List_append(list1, list2); + printf("Test append list2 into list1: "); + print_list((char **)List_toArray(list3)); + + return 0; +} diff --git a/data_structures/queue.c b/data_structures/queue.c deleted file mode 100644 index bad3d9a04c..0000000000 --- a/data_structures/queue.c +++ /dev/null @@ -1,125 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -//INCLUDES -#include -#include - -//////////////////////////////////////////////////////////////////////////////// -//MACROS: CONSTANTS - -//////////////////////////////////////////////////////////////////////////////// -//DATA STRUCTURES -struct node { - int data; - struct node* next; - struct node* pre; -} *head, *tail, *tmp; - -//////////////////////////////////////////////////////////////////////////////// -//GLOBAL VARIABLES -int count; - -//////////////////////////////////////////////////////////////////////////////// -//FORWARD DECLARATIONS -void create(); -void enque(int x); -int deque(); -int peek(); -int size(); -int isEmpty(); - -//////////////////////////////////////////////////////////////////////////////// -//MAIN ENTRY POINT - -int main(int argc, char const *argv[]) { - - create(); - enque(5); - - - return 0; -} - - -void create() { - head = NULL; - tail = NULL; -} - -/** - * Puts an item into the Queue. - */ -void enque(int x) { - if(head == NULL) { - head = (struct node *)malloc(1 * sizeof(struct node)); - head->data = x; - head->pre = NULL; - tail = head; - } else { - tmp = (struct node *)malloc(1 * sizeof(struct node)); - tmp->data = x; - tmp->next = tail; - tail = tmp; - } -} - -/** - * Takes the next item from the Queue. - */ -int deque() { - int returnData; - if(head == NULL) { - printf("ERROR: Deque from empty queue.\n"); - exit(1); - } else { - returnData = head->data; - if(head->pre == NULL) - head = NULL; - else - head = head->pre; - head->next = NULL; - } -} - -/** - * Returns the size of the Queue. - */ -int size() { - return count; -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/data_structures/queue/include.h b/data_structures/queue/include.h new file mode 100644 index 0000000000..e4820eb517 --- /dev/null +++ b/data_structures/queue/include.h @@ -0,0 +1,28 @@ +////////////////////////////////////////////////////////////////////////////////////// +/// INCLUDES + +#include +#include +//////////////////////////////////////////////////////////////////////////////// +// DATA STRUCTURES +/** + * Defining the structure of the node which contains 'data' (type : integer), + * two pointers 'next' and 'pre' (type : struct node). + */ + +struct node +{ + int data; + struct node *next; + struct node *pre; +} * head, *tail, *tmp; + +//////////////////////////////////////////////////////////////////////////////// +// FORWARD DECLARATIONS + +void create(); +void enque(int x); +int deque(); +int peek(); +int size(); +int isEmpty(); diff --git a/data_structures/queue/queue.c b/data_structures/queue/queue.c new file mode 100644 index 0000000000..2b936be088 --- /dev/null +++ b/data_structures/queue/queue.c @@ -0,0 +1,73 @@ +//////////////////////////////////////////////////////////////////////////////// +// INCLUDES +#include "include.h"; + +//////////////////////////////////////////////////////////////////////////////// +// GLOBAL VARIABLES +int count; + +//////////////////////////////////////////////////////////////////////////////// +// MAIN ENTRY POINT + +int main(int argc, char const *argv[]) +{ + create(); + enque(5); + + return 0; +} + +void create() +{ + head = NULL; + tail = NULL; +} + +/** + * Puts an item into the Queue. + */ +void enque(int x) +{ + if (head == NULL) + { + head = (struct node *)malloc(sizeof(struct node)); + head->data = x; + head->pre = NULL; + tail = head; + } + else + { + tmp = (struct node *)malloc(sizeof(struct node)); + tmp->data = x; + tmp->next = tail; + tail = tmp; + } +} + +/** + * Takes the next item from the Queue. + */ +int deque() +{ + int returnData = 0; + if (head == NULL) + { + printf("ERROR: Deque from empty queue.\n"); + exit(1); + } + else + { + returnData = head->data; + if (head->pre == NULL) + head = NULL; + else + head = head->pre; + head->next = NULL; + } + return returnData; +} + +/** + * Returns the size of the Queue. + */ +int size() { return count; } diff --git a/data_structures/stack.c b/data_structures/stack.c index 54bd29c138..0bae7c52a4 100644 --- a/data_structures/stack.c +++ b/data_structures/stack.c @@ -4,27 +4,31 @@ */ //////////////////////////////////////////////////////////////////////////////// -//INCLUDES +// INCLUDES #include #include //////////////////////////////////////////////////////////////////////////////// -//MACROS: CONSTANTS +// MACROS: CONSTANTS //////////////////////////////////////////////////////////////////////////////// -//DATA STRUCTURES -struct node { +// DATA STRUCTURES +/** + * creating a stucture with 'data'(type:int), two pointers 'next','pre' (type: struct node) . + */ +struct node +{ int data; - struct node* next; - struct node* pre; -} *head, *tmp; + struct node *next; + struct node *pre; +} * head, *tmp; //////////////////////////////////////////////////////////////////////////////// -//GLOBAL VARIABLES +// GLOBAL VARIABLES int count = 0; //////////////////////////////////////////////////////////////////////////////// -//FUNCTION PROTOTYPES +// FUNCTION PROTOTYPES void create(); void push(int x); int pop(); @@ -33,10 +37,10 @@ int size(); int isEmpty(); //////////////////////////////////////////////////////////////////////////////// -//MAIN ENTRY POINT - -int main(int argc, char const *argv[]) { +// MAIN ENTRY POINT +int main(int argc, char const *argv[]) +{ int x, y, z; create(); @@ -64,30 +68,33 @@ int main(int argc, char const *argv[]) { // 1, 6, 7, 8. Count: 2. Empty: 0. printf("%d, %d, %d.\tCount: %d.\tEmpty: %d.\n", x, y, z, size(), isEmpty()); - return 0; + return 0; } /** * Initialize the stack to NULL. */ -void create() { - head = NULL; -} +void create() { head = NULL; } /** * Push data onto the stack. */ -void push(int x) { - if(head == NULL) { +void push(int x) +{ + if (head == NULL) + { head = (struct node *)malloc(1 * sizeof(struct node)); head->next = NULL; head->pre = NULL; head->data = x; - } else { + } + else + { tmp = (struct node *)malloc(1 * sizeof(struct node)); tmp->data = x; tmp->next = NULL; tmp->pre = head; + head->next = tmp; head = tmp; } ++count; @@ -96,17 +103,25 @@ void push(int x) { /** * Pop data from the stack */ -int pop() { +int pop() +{ int returnData; - if(head == NULL) { + if (head == NULL) + { printf("ERROR: Pop from empty stack.\n"); exit(1); - } else { + } + else + { returnData = head->data; - if(head->pre == NULL) + if (head->pre == NULL) + { + free(head); head = NULL; - else { + } + else + { head = head->pre; free(head->next); } @@ -118,10 +133,12 @@ int pop() { /** * Returns the next value to be popped. */ -int peek() { - if(head != NULL) +int peek() +{ + if (head != NULL) return head->data; - else { + else + { printf("ERROR: Peeking from empty stack."); exit(1); } @@ -130,15 +147,14 @@ int peek() { /** * Returns the size of the stack. */ -int size() { - return count; -} +int size() { return count; } /** * Returns 1 if stack is empty, returns 0 if not empty. */ -int isEmpty() { - if(count == 0) +int isEmpty() +{ + if (count == 0) return 1; return 0; } diff --git a/data_structures/stack/README.md b/data_structures/stack/README.md index 174e94549d..c90459ac69 100644 --- a/data_structures/stack/README.md +++ b/data_structures/stack/README.md @@ -1,4 +1,4 @@ -# Simple generic Stack +# Simple generic Stack This is a modular generic stack data-structure. The stack is self growing. @@ -6,31 +6,42 @@ This is a modular generic stack data-structure. The stack is self growing. * stack-Header file for import. * stack.c implementation of the stack -* main.c framework program for testing. +* main.c framework program for testing. +* stack_linkedlist: Another stack implementation by linkedlist You need to only import the **stack.h** ### Public interface -``` void initStack(); ``` +```c +void initStack(); +``` Initializes the stack with a capacity of 10 elements. -``` void push(void * object); ``` +```c +void push(void * object); +``` -pushs the argument onto the stack +pushs the argument onto the stack -``` void * pop(); ``` +```c +void * pop(); +``` pop: pops the top element of the stack from the stack. assumes: stack not empty. -``` int size(); ``` +```c +int size(); +``` gets the number of elements of the stack. -``` int isEmpty(); ``` +```c +int isEmpty(); +``` returns 1 if stack is empty otherwise 0. diff --git a/data_structures/stack/dynamic_stack.c b/data_structures/stack/dynamic_stack.c new file mode 100644 index 0000000000..482896eabd --- /dev/null +++ b/data_structures/stack/dynamic_stack.c @@ -0,0 +1,250 @@ +/** + * @file + * + * @brief + * Dynamic [Stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)), + * just like Dynamic Array, is a stack data structure whose the length or + * capacity (maximum number of elements that can be stored) increases or + * decreases in real time based on the operations (like insertion or deletion) + * performed on it. + * + * In this implementation, functions such as PUSH, POP, PEEK, show_capacity, + * isempty, and stack_size are coded to implement dynamic stack. + * + * @author [SahilK-027](https://github.com/SahilK-027) + * + */ +#include /// to verify assumptions made by the program and print a diagnostic message if this assumption is false. +#include /// to provide a set of integer types with universally consistent definitions that are operating system-independent +#include /// for IO operations +#include /// for including functions involving memory allocation such as `malloc` +/** + * @brief DArrayStack Structure of stack. + */ +typedef struct DArrayStack +{ + int capacity, top; ///< to store capacity and top of the stack + int *arrPtr; ///< array pointer +} DArrayStack; + +/** + * @brief Create a Stack object + * + * @param cap Capacity of stack + * @return DArrayStack* Newly created stack object pointer + */ +DArrayStack *create_stack(int cap) +{ + DArrayStack *ptr; + ptr = (DArrayStack *)malloc(sizeof(DArrayStack)); + ptr->capacity = cap; + ptr->top = -1; + ptr->arrPtr = (int *)malloc(sizeof(int) * cap); + printf("\nStack of capacity %d is successfully created.\n", ptr->capacity); + return (ptr); +} + +/** + * @brief As this is stack implementation using dynamic array this function will + * expand the size of the stack by twice as soon as the stack is full. + * + * @param ptr Stack pointer + * @param cap Capacity of stack + * @return DArrayStack*: Modified stack + */ +DArrayStack *double_array(DArrayStack *ptr, int cap) +{ + int newCap = 2 * cap; + int *temp; + temp = (int *)malloc(sizeof(int) * newCap); + for (int i = 0; i < (ptr->top) + 1; i++) + { + temp[i] = ptr->arrPtr[i]; + } + free(ptr->arrPtr); + ptr->arrPtr = temp; + ptr->capacity = newCap; + return ptr; +} + +/** + * @brief As this is stack implementation using dynamic array this function will + * shrink the size of stack by twice as soon as the stack's capacity and size + * has significant difference. + * + * @param ptr Stack pointer + * @param cap Capacity of stack + * @return DArrayStack*: Modified stack + */ +DArrayStack *shrink_array(DArrayStack *ptr, int cap) +{ + int newCap = cap / 2; + int *temp; + temp = (int *)malloc(sizeof(int) * newCap); + for (int i = 0; i < (ptr->top) + 1; i++) + { + temp[i] = ptr->arrPtr[i]; + } + free(ptr->arrPtr); + ptr->arrPtr = temp; + ptr->capacity = newCap; + return ptr; +} + +/** + * @brief The push function pushes the element onto the stack. + * + * @param ptr Stack pointer + * @param data Value to be pushed onto stack + * @return int Position of top pointer + */ +int push(DArrayStack *ptr, int data) +{ + if (ptr->top == (ptr->capacity) - 1) + { + ptr = double_array(ptr, ptr->capacity); + ptr->top++; + ptr->arrPtr[ptr->top] = data; + } + else + { + ptr->top++; + ptr->arrPtr[ptr->top] = data; + } + printf("Successfully pushed : %d\n", data); + return ptr->top; +} + +/** + * @brief The pop function to pop an element from the stack. + * + * @param ptr Stack pointer + * @return int Popped value + */ +int pop(DArrayStack *ptr) +{ + if (ptr->top == -1) + { + printf("Stack is empty UNDERFLOW \n"); + return -1; + } + int ele = ptr->arrPtr[ptr->top]; + ptr->arrPtr[ptr->top] = 0; + ptr->top = (ptr->top - 1); + if ((ptr->capacity) % 2 == 0) + { + if (ptr->top <= (ptr->capacity / 2) - 1) + { + ptr = shrink_array(ptr, ptr->capacity); + } + } + printf("Successfully popped: %d\n", ele); + return ele; +} + +/** + * @brief To retrieve or fetch the first element of the Stack or the element + * present at the top of the Stack. + * + * @param ptr Stack pointer + * @return int Top of the stack + */ +int peek(DArrayStack *ptr) +{ + if (ptr->top == -1) + { + printf("Stack is empty UNDERFLOW \n"); + return -1; + } + return ptr->arrPtr[ptr->top]; +} + +/** + * @brief To display the current capacity of the stack. + * + * @param ptr Stack pointer + * @return int Current capacity of the stack + */ +int show_capacity(DArrayStack *ptr) { return ptr->capacity; } + +/** + * @brief The function is used to check whether the stack is empty or not and + * return true or false accordingly. + * + * @param ptr Stack pointer + * @return int returns 1 -> true OR returns 0 -> false + */ +int isempty(DArrayStack *ptr) +{ + if (ptr->top == -1) + { + return 1; + } + return 0; +} + +/** + * @brief Used to get the size of the Stack or the number of elements present in + * the Stack. + * + * @param ptr Stack pointer + * @return int size of stack + */ +int stack_size(DArrayStack *ptr) { return ptr->top + 1; } + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() +{ + DArrayStack *NewStack; + int capacity = 1; + NewStack = create_stack(capacity); + uint64_t arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + + printf("\nTesting Empty stack: "); + assert(stack_size(NewStack) == 0); + assert(isempty(NewStack) == 1); + printf("Size of an empty stack is %d\n", stack_size(NewStack)); + + printf("\nTesting PUSH operation:\n"); + for (int i = 0; i < 12; ++i) + { + int topVal = push(NewStack, arr[i]); + printf("Size: %d, Capacity: %d\n\n", stack_size(NewStack), + show_capacity(NewStack)); + assert(topVal == i); + assert(peek(NewStack) == arr[i]); + assert(stack_size(NewStack) == i + 1); + assert(isempty(NewStack) == 0); + } + + printf("\nTesting POP operation:\n"); + for (int i = 11; i > -1; --i) + { + peek(NewStack); + assert(peek(NewStack) == arr[i]); + int ele = pop(NewStack); + assert(ele == arr[i]); + assert(stack_size(NewStack) == i); + } + + printf("\nTesting Empty stack size: "); + assert(stack_size(NewStack) == 0); + assert(isempty(NewStack) == 1); + printf("Size of an empty stack is %d\n", stack_size(NewStack)); + + printf("\nTesting POP operation on empty stack: "); + assert(pop(NewStack) == -1); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + test(); // run self-test implementations + return 0; +} diff --git a/data_structures/stack/main.c b/data_structures/stack/main.c index 6a1502bbfa..d3f20c0a93 100644 --- a/data_structures/stack/main.c +++ b/data_structures/stack/main.c @@ -1,26 +1,26 @@ -//program for stack using array - +// program for stack using array #include void push(); void pop(); void peek(); void update(); +void display(); int a[100], top = -1; int main() { - int x; while (1) { - printf("\n0.exit"); - printf("\n1.push"); - printf("\n2.pop"); - printf("\n3.peek"); - printf("\n4.update"); - printf("\nenter your choice? "); + printf("\n0 or CTRL-C to Exit "); + printf("\n1. Push"); + printf("\n2. Pop"); + printf("\n3. Peek"); + printf("\n4. Update"); + printf("\n5. Display"); + printf("\nEnter your choice? \n"); scanf("%d", &x); switch (x) { @@ -38,62 +38,80 @@ int main() case 4: update(); break; + case 5: + display(); + break; default: - printf("\ninvalid choice"); + printf("\nInvalid choice,\nPlease try again.\n"); } } return (0); } -//function for pushing the element +// function for pushing the element void push() { int n = 0; - printf("\nenter the value to insert? "); + printf("\nEnter the value to be inserted: "); scanf("%d", &n); top += 1; a[top] = n; } -//function for poping the element out +// function for poping the element out void pop() { if (top == -1) { - printf("\nstack is empty"); + printf("\nStack is empty"); } else { int item; item = a[top]; top -= 1; - printf("\npoped item is %d ", item); + printf("\nPoped item is %d ", item); } } -//function for peeping the element from top of the stack +// function for peeping the element from top of the stack void peek() { if (top >= 0) - printf("\n the top element is %d", a[top]); + printf("\nThe top element is %d", a[top]); else - printf("\nstack is empty"); + printf("\nStack is empty"); } -//function to update the element of stack +// function to update the element of stack void update() { int i, n; - printf("\nenter the position to update? "); + printf("\nEnter the position to update? "); scanf("%d", &i); - printf("\nenter the item to insert? "); + printf("\nEnter the item to insert? "); scanf("%d", &n); if (top - i + 1 < 0) { - printf("\nunderflow condition"); + printf("\nUnderflow condition "); } else { a[top - i + 1] = n; } -} \ No newline at end of file +} +// function to view entire stack +void display() +{ + if (top == -1) + { + printf("\nStack is empty"); + } + else + { + for (int i = top; i >= 0; i--) + { + printf("%d\n", a[i]); + } + } +} diff --git a/data_structures/stack/parenthesis.c b/data_structures/stack/parenthesis.c index 993f2edd15..126abbc3e6 100644 --- a/data_structures/stack/parenthesis.c +++ b/data_structures/stack/parenthesis.c @@ -1,7 +1,7 @@ +#include #include #include #include -#include #define SIZE 100 @@ -11,15 +11,16 @@ struct node struct node *link; }; -int c = 0; // c used as counter to check if stack is empty or not -struct node *head; //declaring head pointer globally assigned to NULL +int c = 0; // c used as counter to check if stack is empty or not +struct node *head; // declaring head pointer globally assigned to NULL -void push(char x) //function for pushing +void push(char x) // function for pushing { struct node *p = head, *temp; temp = (struct node *)malloc(sizeof(struct node)); temp->data = x; - if (head == NULL) //will be execute only one time i.e, 1st time push is called + if (head == + NULL) // will be execute only one time i.e, 1st time push is called { head = temp; p = head; @@ -35,7 +36,7 @@ void push(char x) //function for pushing } } -char pop(void) //function for pop +char pop(void) // function for pop { char x; struct node *p = head; @@ -50,14 +51,16 @@ int isBalanced(char *s) { int i = 0; char x; - while (s[i] != '\0') //loop for covering entire string of brackets + while (s[i] != '\0') // loop for covering entire string of brackets { // printf("\t s[i]=%c\n", s[i]); //DEBUG - if (s[i] == '{' || s[i] == '(' || s[i] == '[') //if opening bracket then push + if (s[i] == '{' || s[i] == '(' || + s[i] == '[') // if opening bracket then push push(s[i]); else { - if (c <= 0) //i.e, stack is empty as only opening brackets are added to stack + if (c <= 0) // i.e, stack is empty as only opening brackets are + // added to stack return 0; x = pop(); @@ -71,7 +74,8 @@ int isBalanced(char *s) i++; } - //at end if stack is empy which means whole process has been performed correctly so return 1 + // at end if stack is empy which means whole process has been performed + // correctly so return 1 return (c == 0) ? 1 : 0; } diff --git a/data_structures/stack/stack.c b/data_structures/stack/stack.c index 29c6a1de73..31cd4d2b73 100644 --- a/data_structures/stack/stack.c +++ b/data_structures/stack/stack.c @@ -6,15 +6,15 @@ of data hiding. */ +#include #include #include -#include #include "stack.h" -/* +/* actual stack data structure - This pointer will pointing at the actual field (of void * pointers) + This pointer will pointing at the actual field (of void * pointers) that represents the stack. */ void **array; @@ -25,15 +25,14 @@ int max = 10; /* counter variable for counting the elements of the stack. */ int counter = 0; -/* - offset address +/* + offset address points at the top element of the stack. */ int offset = -1; void initStack() { - array = malloc(sizeof(void *) * max); assert(array); /* tests whether pointer is assigned to memory. */ } @@ -46,7 +45,7 @@ void grow() { max += 10; /* increases the capacity */ - int i; // for the loop + int i; // for the loop void **tmp = malloc(sizeof(void *) * max); /* copies the elements from the origin array in the new one. */ @@ -54,24 +53,23 @@ void grow() { *(tmp + i) = *(array + i); } - - array = tmp; /* setups the new one as basis */ + /*free the memory */ + free(array); + array = tmp; } /* push: pushs the argument onto the stack */ void push(void *object) { - assert(object); /* tests whether pointer isn't null */ if (counter < max) { - offset++; /* increases the element-pointer */ - /* - moves pointer by the offset address - pushs the object onto stack + /* + moves pointer by the offset address + pushs the object onto stack */ *(array + offset) = object; @@ -80,8 +78,7 @@ void push(void *object) } else /* stack is full */ { - - grow(); /* lets grow stack */ + grow(); /* lets grow stack */ push(object); /* recursive call */ } } @@ -91,7 +88,6 @@ void push(void *object) */ void *pop() { - void *top = *(array + offset); /* check pointers */ @@ -113,18 +109,12 @@ void *pop() /* size: gets the number of elements of the stack. */ -int size() -{ - return counter; -} +int size() { return counter; } /* isEmpty(): returns 1 if stack is empty otherwise 0. */ -int isEmpty() -{ - return counter == 0; -} +int isEmpty() { return counter == 0; } /* top: returns the top element from the stack without removing it. @@ -133,4 +123,4 @@ void *top() { /* offset address points to the top element */ return array[offset]; -} \ No newline at end of file +} diff --git a/data_structures/stack/stack.h b/data_structures/stack/stack.h index 5af106a941..03703b9504 100644 --- a/data_structures/stack/stack.h +++ b/data_structures/stack/stack.h @@ -2,10 +2,9 @@ author: Christian Bender This header represents the public stack-interface. - The stack is generic and self growing. + The stack is generic and self growing. */ - #ifndef __STACK__ #define __STACK__ @@ -15,15 +14,15 @@ void initStack(); /* - push: pushs the argument onto the stack + push: pushs the argument onto the stack */ -void push(void * object); +void push(void *object); /* pop: pops the top element of the stack from the stack. assumes: stack not empty. */ -void * pop(); +void *pop(); /* size: gets the number of elements of the stack. @@ -38,6 +37,6 @@ int isEmpty(); /* top: returns the top element from the stack without removing it. */ -void * top(); +void *top(); #endif \ No newline at end of file diff --git a/data_structures/stack/stack_linked_list/Makefile b/data_structures/stack/stack_linked_list/Makefile new file mode 100644 index 0000000000..1fcb6fd8dc --- /dev/null +++ b/data_structures/stack/stack_linked_list/Makefile @@ -0,0 +1,12 @@ +CC = gcc +CFLAGS = -c -Wall + +all: main +main: main.o stack.o + $(CC) main.o stack.o -o main + +stack.o: stack.c + $(CC) $(CFLAGS) stack.c + +clean: + rm *o main diff --git a/data_structures/stack/stack_linked_list/main.c b/data_structures/stack/stack_linked_list/main.c new file mode 100644 index 0000000000..1e1a6c77cd --- /dev/null +++ b/data_structures/stack/stack_linked_list/main.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include "stack.h" + +int main() +{ + Stack_T stk; + stk = Stack_init(); + Stack_push(stk, (int *)1); + Stack_push(stk, (int *)2); + Stack_push(stk, (int *)3); + Stack_push(stk, (int *)4); + printf("Size: %d\n", Stack_size(stk)); + Stack_print(stk); + Stack_pop(stk); + printf("Stack after popping: \n"); + Stack_print(stk); + Stack_pop(stk); + printf("Stack after popping: \n"); + Stack_print(stk); + return 0; +} diff --git a/data_structures/stack/stack_linked_list/stack.c b/data_structures/stack/stack_linked_list/stack.c new file mode 100644 index 0000000000..cd02b6ebce --- /dev/null +++ b/data_structures/stack/stack_linked_list/stack.c @@ -0,0 +1,88 @@ +#include "stack.h" +#include +#include +#include +#include + +#define T Stack_T + +typedef struct elem +{ + void *val; + struct elem *next; +} elem_t; + +struct T +{ + int count; + elem_t *head; +}; + +/* Initial stack */ +T Stack_init(void) +{ + T stack; + stack = (T)malloc(sizeof(T)); + stack->count = 0; + stack->head = NULL; + return stack; +} + +/* Check empty stack*/ +int Stack_empty(T stack) +{ + assert(stack); + return stack->count == 0; +} + +/* Return size of the stack */ +int Stack_size(T stack) +{ + assert(stack); + return stack->count; +} + +/* Push an element into the stack */ +void Stack_push(T stack, void *val) +{ + elem_t *t; + + assert(stack); + t = (elem_t *)malloc(sizeof(elem_t)); + t->val = val; + t->next = stack->head; + stack->head = t; + stack->count++; +} + +/* Pop an element out of the stack */ +void *Stack_pop(T stack) +{ + void *val; + elem_t *t; + + assert(stack); + assert(stack->count > 0); + t = stack->head; + stack->head = t->next; + stack->count--; + val = t->val; + free(t); + return val; +} + +/* Print all elements in the stack */ +void Stack_print(Stack_T stack) +{ + assert(stack); + + int i, size = Stack_size(stack); + elem_t *current_elem = stack->head; + printf("Stack [Top --- Bottom]: "); + for (i = 0; i < size; ++i) + { + printf("%p ", (int *)current_elem->val); + current_elem = current_elem->next; + } + printf("\n"); +} diff --git a/data_structures/stack/stack_linked_list/stack.h b/data_structures/stack/stack_linked_list/stack.h new file mode 100644 index 0000000000..d9b0315eaf --- /dev/null +++ b/data_structures/stack/stack_linked_list/stack.h @@ -0,0 +1,15 @@ +#ifndef __STACK__ +#define __STACK__ + +#define T Stack_T +typedef struct T *T; + +extern T Stack_init(void); +extern int Stack_size(T stack); +extern int Stack_empty(T stack); +extern void Stack_push(T stack, void *val); +extern void *Stack_pop(T stack); +extern void Stack_print(T stack); + +#undef T +#endif diff --git a/data_structures/trie/dictionary.txt b/data_structures/trie/dictionary.txt index 88a1145fb3..5fb37fc306 100644 --- a/data_structures/trie/dictionary.txt +++ b/data_structures/trie/dictionary.txt @@ -11398,7 +11398,6 @@ ancylostome ancylostomiasis ancyroid and -and/or anda andabata andabatarian @@ -23796,8 +23795,6 @@ azymous b bhoy bs -b/l -b/s ba baa baaed @@ -41542,10 +41539,6 @@ byzants bz c cs -c/d -c/f -c/m -c/o ca ca cacanny @@ -126581,7 +126574,6 @@ hailweed haily haimsucken hain -hain"t haint hainberry hainch @@ -128730,7 +128722,6 @@ hdlc hdqrs hdwe he -he"ll hed hell hes @@ -139010,7 +139001,6 @@ ill im is ive -i/c ia iago iamatology @@ -145956,7 +145946,6 @@ inpours inpush input inputs -input/output inputfile inputs inputted @@ -151770,7 +151759,6 @@ isuretine isuroid isz it -it"ll itd itll its @@ -155260,7 +155248,6 @@ kb kbar kbps kc -kc/s kcal kea keach @@ -156978,7 +156965,6 @@ klva klystron klystrons km -km/sec kmel kmet kmole @@ -158105,7 +158091,6 @@ lenvoy loeil ls ltre -l/w la laager laagered @@ -164745,8 +164730,6 @@ ller lloyds llyn lm -lm/ft -lm/m ln lndg lnr @@ -167403,7 +167386,6 @@ lyttas lyxose m ms -m/s ma maam maad @@ -185958,8 +185940,6 @@ n ngana nimporte ns -n/a -n/f na naa naam @@ -198979,8 +198959,6 @@ oclock oer oertop os -o/c -o/s oad oadal oaf @@ -345815,8 +345793,6 @@ vyingly vyrnwy w ws -w/ -w/o wa wa waac @@ -354932,4 +354908,4 @@ zymurgy zythem zythum zyzzyva -zyzzyvas \ No newline at end of file +zyzzyvas diff --git a/data_structures/trie/trie.c b/data_structures/trie/trie.c index d748a11ca6..78ab9d9d82 100644 --- a/data_structures/trie/trie.c +++ b/data_structures/trie/trie.c @@ -3,181 +3,203 @@ /*-----character - 97 used for get the character from the ASCII value-----*/ -#include +// needed for strnlen +#define _POSIX_C_SOURCE 200809L + #include +#include #include #include #define ALPHABET_SIZE 26 /*--Node in the Trie--*/ -typedef struct TrieNode +struct trie { + struct trie *children[ALPHABET_SIZE]; + bool end_of_word; +}; + + +/*--Create new trie node--*/ +int trie_new ( + struct trie ** trie +) { - struct TrieNode *children[ALPHABET_SIZE]; - char character; - bool isEndOfWord; - -} TrieNode; - -/*--Create new node--*/ -TrieNode *createTrieNode() -{ - TrieNode *node; - node = malloc(sizeof(TrieNode)); - node->isEndOfWord = false; - int i = 0; - while(ichildren[i] = NULL; - i++; + *trie = calloc(1, sizeof(struct trie)); + if (NULL == *trie) { + // memory allocation failed + return -1; } - return node; + return 0; } + /*--Insert new word to Trie--*/ -void insert(TrieNode *root,char *word) +int trie_insert ( + struct trie * trie, + char *word, + unsigned word_len +) { - /*----Addition of the word done by recurcively----*/ - - //Check wheather word character pointer is NULL - if((strlen(word)-1) != 0) - { - char character = *word; - if(root->children[character-97] == NULL) - { - TrieNode *node = NULL; - node = createTrieNode(); - node->character = character; - root->children[character-97] = node; - } - word++; - insert(root->children[character-97],word); - } - else - { - root->isEndOfWord = true; - } - return; + int ret = 0; + + // this is the end of this word; add an end-of-word marker here and we're + // done. + if (0 == word_len) { + trie->end_of_word = true; + return 0; + } + + // if you have some more complex mapping, you could introduce one here. In + // this easy example, we just subtract 'a' (97) from it, meaning that 'a' is 0, + // 'b' is 1, and so on. + const unsigned int index = word[0] - 'a'; + + // this index is outside the alphabet size; indexing this would mean an + // out-of-bound memory access (bad!). If you introduce a separate map + // function for indexing, then you could move the out-of-bounds index in + // there. + if (ALPHABET_SIZE <= index) { + return -1; + } + + // The index does not exist yet, allocate it. + if (NULL == trie->children[index]) { + ret = trie_new(&trie->children[index]); + if (-1 == ret) { + // creating new trie node failed + return -1; + } + } + + // recurse into the child node + return trie_insert( + /* trie = */ trie->children[index], + /* word = */ word + 1, + /* word_len = */ word_len - 1 + ); } + /*--Search a word in the Trie--*/ -TrieNode *search( TrieNode *root, char *word) +int trie_search( + struct trie * trie, + char *word, + unsigned word_len, + struct trie ** result +) { - TrieNode *temp; - while(*word != '\0') - { - char character = *word; - if(root->children[character - 97] != NULL) - { - temp = root->children[character-97]; - word++; - root = temp; - } - else - { - printf("No possible words!!\n"); - return NULL; - } - } - return root; -} + // we found a match + if (0 == word_len) { + *result = trie; + return 0; + } -/*---Print a word in the array--*/ -void printArray(char chars[], int len) -{ - int i; - for (i=0; ichildren[index]) { + return -1; + } + + // traverse the trie + return trie_search( + /* trie = */ trie->children[index], + /* word = */ word + 1, + /* word_len = */ word_len - 1, + /* result = */ result + ); } /*---Return all the related words------*/ -void printPathsRecur(TrieNode* node, char prefix[], int filledLen) +void trie_print ( + struct trie * trie, + char prefix[], + unsigned prefix_len +) { - if (node==NULL) return; - prefix[filledLen] = node->character; - filledLen++; + // An end-of-word marker means that this is a complete word, print it. + if (true == trie->end_of_word) { + printf("%.*s\n", prefix_len, prefix); + } + + // However, there can be longer words with the same prefix; traverse into + // those as well. + for (int i = 0; i < ALPHABET_SIZE; i++) { - if (node->isEndOfWord) - { - printArray(prefix, filledLen); - } + // No words on this character + if (NULL == trie->children[i]) { + continue; + } - int i ; - for(i=0;ichildren[i], prefix, filledLen); - } -} + // If you have a separate index mapping, then you'd need the inverse of + // the map here. Since we subtracted 'a' for the index, we can just add + // 'a' to get the inverse map function. + prefix[prefix_len] = i + 'a'; -/*--Travel through the Trie and return words from it--*/ -void traverse(char prefix[], TrieNode *root) -{ - TrieNode *temp = NULL; - temp = search(root,prefix); - int j=0; - while(prefix[j]!='\0') - { - j++; + // traverse the print into the child + trie_print(trie->children[i], prefix, prefix_len + 1); } - printPathsRecur(temp,prefix,j-1); } + /*------Demonstrate purposes uses text file called dictionary -------*/ -#define NUMBER_OF_WORDS (354935) -#define INPUT_WORD_SIZE (100) +int main() { + int ret = 0; + struct trie * root = NULL; + struct trie * trie = NULL; + char word[100] = {0}; -/*----Get input from the user------*/ -char *receiveInput(char *s) -{ - scanf("%99s", s); - return s; -} + // Create a root trie + ret = trie_new(&root); + if (-1 == ret) { + fprintf(stderr, "Could not create trie\n"); + exit(1); + } -int main() -{ - //Read the file dictionary - int word_count = 0; - char* words[NUMBER_OF_WORDS]; + // open the dictionary file FILE *fp = fopen("dictionary.txt", "r"); - - if (fp == 0) - { + if (NULL == fp) { fprintf(stderr, "Error while opening dictionary file"); exit(1); } - - words[word_count] = malloc(INPUT_WORD_SIZE); - - while (fgets(words[word_count], INPUT_WORD_SIZE, fp)) - { - word_count++; - words[word_count] = malloc(INPUT_WORD_SIZE); - } - - //Push the words in to Trie - TrieNode *root = NULL; - root = createTrieNode(); - int i; - for(i=0;i /// for IO operations +#include /// for malloc() and free() +#include /// for testing using assert() + +/** This is the struct that defines the vector. */ +typedef struct { + int len; ///< contains the length of the vector + int current; ///< holds the current item + int* contents; ///< the internal array itself +} Vector; + +/** + * This function initilaizes the vector and gives it a size of 1 + * and initializes the first index to 0. + * @params Vector* (a pointer to the Vector struct) + * @params int (the actual data to be passed to the vector) + * @returns none + */ +void init(Vector* vec, int val) { + vec->contents = (int*)malloc(sizeof(int)); + vec->contents[0] = val; + vec->current = 0; + vec->len = 1; +} + +/** + * This function clears the heap memory allocated by the Vector. + * @params Vector* (a pointer to the Vector struct) + * @returns: none + */ +void delete(Vector* vec) { + free(vec->contents); +} + +/** + * This function clears the contents of the Vector. + * @params Vector* (a pointer to the Vector struct) + * @returns: none + */ +void clear(Vector* vec) { + delete(vec); + init(vec, 0); +} + +/** + * This function returns the length the Vector. + * @params Vector* (a pointer to the Vector struct) + * @returns: int + */ +int len(Vector* vec) { + return vec->len; +} + +/** + * This function pushes a value to the end of the Vector. + * @params Vector* (a pointer to the Vector struct) + * @params int (the value to be pushed) + * @returns: none + */ +void push(Vector* vec, int val) { + vec->contents = realloc(vec->contents, (sizeof(int) * (vec->len + 1))); + vec->contents[vec->len] = val; + vec->len++; +} + +/** + * This function get the item at the specified index of the Vector. + * @params Vector* (a pointer to the Vector struct) + * @params int (the index to get value from) + * @returns: int + */ +int get(Vector* vec, int index) { + if(index < vec->len) { + return vec->contents[index]; + } + return -1; +} + +/** + * This function sets an item at the specified index of the Vector. + * @params Vector* (a pointer to the Vector struct) + * @params int (the index to set value at) + * @returns: none + */ +void set(Vector* vec, int index, int val) { + if(index < vec->len) { + vec->contents[index] = val; + } +} + +/** + * This function gets the next item from the Vector each time it's called. + * @params Vector* (a pointer to the Vector struct) + * @returns: int + */ +int next(Vector* vec) { + if(vec->current == vec->len) { + vec->current = 0; + } + int current_val = vec->contents[vec->current]; + vec->current++; + return current_val; +} + +/** + * This function returns the pointer to the begining of the Vector. + * @params Vector* (a pointer to the Vector struct) + * @returns: void* + */ +void* begin(Vector* vec) { + return (void*)vec->contents; +} + +/** + * This function prints the entire Vector as a list. + * @params Vector* (a pointer to the Vector struct) + * @returns: none + */ +void print(Vector* vec) { + int size = vec->len; + printf("[ "); + for(int count = 0; count < size; count++) { + printf("%d ", vec->contents[count]); + } + printf("]\n"); +} + +/** + * This function tests the functions used to work with Vectors. + * @returns: none + */ +static void test() { + Vector vec; + init(&vec, 10); + assert(get(&vec, 0) == 10); + push(&vec, 20); + assert(get(&vec, 1) == 20); + set(&vec, 0, 11); + assert(get(&vec, 0) == 11); + assert(next(&vec) == 11); + set(&vec, 1, 22); + assert(get(&vec, 1) == 22); + assert(len(&vec) == 2); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); + + Vector vec; + init(&vec, 10); + push(&vec, 20); + print(&vec); + set(&vec, 0, 11); + set(&vec, 1, 22); + print(&vec); + printf("Length: %d\n", len(&vec)); + return 0; +} diff --git a/developer_tools/CMakeLists.txt b/developer_tools/CMakeLists.txt new file mode 100644 index 0000000000..848250b85e --- /dev/null +++ b/developer_tools/CMakeLists.txt @@ -0,0 +1,35 @@ +# 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} *.c ) +# file( GLOB APP_SOURCES ${CMAKE_SOURCE_DIR}/*.c ) +# AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} APP_SOURCES) + +add_library(malloc_dbg malloc_dbg.c) # Create a static library from malloc_dbg.c file + +foreach( testsourcefile ${APP_SOURCES} ) + string( REPLACE ".c" "" testname ${testsourcefile} ) + string( REPLACE ".C" "" testname ${testname} ) + string( REPLACE " " "_" testname ${testname} ) + + if ("${testsourcefile}" STREQUAL "malloc_dbg.c") + continue() + endif() + + add_executable( ${testname} ${testsourcefile} ) + + if ("${testname}" STREQUAL "test_malloc_dbg") + target_link_libraries(${testname} malloc_dbg) + endif() + + if(OpenMP_C_FOUND) + target_link_libraries(${testname} OpenMP::OpenMP_C) + endif() + + if(MATH_LIBRARY) + target_link_libraries(${testname} ${MATH_LIBRARY}) + endif() + # target_link_libraries(${testname} malloc_dbg) # Link the malloc_dbg library + install(TARGETS ${testname} DESTINATION "bin/developer_tools") + +endforeach( testsourcefile ${APP_SOURCES} ) diff --git a/developer_tools/malloc_dbg.c b/developer_tools/malloc_dbg.c new file mode 100644 index 0000000000..83b01cfdeb --- /dev/null +++ b/developer_tools/malloc_dbg.c @@ -0,0 +1,289 @@ +/** + * @file + * @brief This file contains malloc_dbg, calloc_dbg, free_dbg and printLeaks implementations. + * @author [tinouduart33](https://github.com/tinouduart33) + */ + +#include /// For the malloc, calloc and free functions. +#include /// For IO operations (printf). +#include /// For the memcmp function. +#include "malloc_dbg.h" /// Header file which contains the prototypes of malloc_dbg, calloc_dbg and fre_dbg. + +/* We must undef these macros in order to use the real malloc / calloc and free functions */ +#undef malloc +#undef calloc +#undef free + +/** + * @brief Structure used to save an allocated pointer + */ +typedef struct MEMORY_INFORMATION +{ + void* ptr; ///< Pointer returned by malloc / calloc + const char* fileName; ///< File in which malloc or calloc has been called + const char* functionName; ///< Function in which malloc or calloc has been called + size_t bytes; ///< Number of bytes allocated + int line; ///< Line number (in file) corresponding to the malloc / calloc call + struct MEMORY_INFORMATION* next; ///< Next element in the list + struct MEMORY_INFORMATION* previous; ///< Previous element in the list +} mem_info; + +/** We use a global variable for the list so we can use it at any time. + * */ +mem_info* memoryInformation = NULL; + +/** Another global variable. This one is used to know if we already call the atexit function. + * */ +int atexitCalled = 0; + + +/** + * @brief addMemInfo function add a memory allocation in the memoryInfo list. + * @details This function creates a new element and add it on top of the list + * @param memoryInfo Pointer to the doubly linked list used to store all of the allocations + * @param ptrToreturn Pointer returned by malloc or calloc + * @param bytes Size in bytes of the allocation + * @param line Line where the allocation has been called + * @param filename File where the allocation has been called + * @param functionName Name of the function where the allocation has been called + * @returns mem_info pointer if it succeeds, NULL otherwise + */ +mem_info* addMemInfo(mem_info* memoryInfo, void* ptrToReturn, size_t bytes, int line, const char* filename, const char* functionName) +{ + mem_info* newMemInfo = (mem_info*)malloc(sizeof(mem_info)); + if (!newMemInfo) + { + return NULL; + } + + newMemInfo->ptr = ptrToReturn; + newMemInfo->bytes = bytes; + newMemInfo->line = line; + newMemInfo->fileName = filename; + newMemInfo->functionName = functionName; + newMemInfo->next = memoryInfo; + newMemInfo->previous = NULL; + if (memoryInformation) + memoryInformation->previous = newMemInfo; + + return newMemInfo; +} + +/** + * @brief inList function is used to know if an element is already in the memoryInfo list. + * @details This function is used to know if an allocation in a specific file at a specific line already exists in the list. + * @param filename File in which malloc or calloc has been called + * @param line Line number in the file in which malloc or calloc has been called + * @returns Position of the element in the list if the element is found, -1 otherwise. + */ +int inList(const char* filename, int line) +{ + mem_info* tmp = memoryInformation; + int counter = 0; + int len = strlen(filename); + + while (tmp) + { + if (len == strlen(tmp->fileName)) + { + if (!memcmp(filename, tmp->fileName, len) && tmp->line == line) + { + return counter; + } + } + tmp = tmp->next; + counter++; + } + return -1; +} + +/** + * @brief editInfo function is used to edit an element in the memoryInfo list. + * @details This function is used to edit the number of bytes allocated at a specific line. + * @param elemPos Position of an element in the doubly linked list memoryInfo + * @param bytes Size of the allocation in bytes + * @returns Nothing. + */ +void editInfo(int elemPos, size_t bytes) +{ + int counter = 0; + mem_info* tmp = memoryInformation; + + while (counter != elemPos) + { + tmp = tmp->next; + counter++; + } + tmp->bytes += bytes; +} + +/** + * @brief malloc_dbg function is a wrapper around the malloc function. + * @details This function calls malloc and allocates the number of bytes passed in the parameters. + * If the allocation succeeds then it add the pointer returned by malloc in the mem_info list. + * @param bytes Size of the allocation in bytes + * @param filename Caller file + * @param functionName Caller function + * @returns Pointer returned by malloc if it's valid, NULL otherwhise. + */ +void* malloc_dbg(size_t bytes, int line, const char* filename, const char* functionName) +{ + void* ptrToReturn = malloc(bytes); + int pos = 0; + if (!ptrToReturn) + { + return NULL; + } + + // We must check atexitCalled value to know if we already called the function + if (!atexitCalled) + { + atexit(printLeaks); // Used to call printLeaks when the program exit + atexitCalled = 1; + } + + pos = inList(filename, line); + if (pos == -1) + { + // Add a new element in the mem_info list + memoryInformation = addMemInfo(memoryInformation, ptrToReturn, bytes, line, filename, functionName); + if (!memoryInformation) + { + free(ptrToReturn); + return NULL; + } + } + else + { + editInfo(pos, bytes); + } + return ptrToReturn; +} + +/** + * @brief calloc_dbg function is a wrapper around the calloc function. + * @details This function calls calloc and allocates the number of bytes passed in the parameters. + * If the allocation succeeds then it add the pointer returned by malloc in the mem_info list. + * @param elementCount number of element to allocate + * @param elementSize Size of each element + * @param line Line number in the caller file + * @param filename Caller file + * @param functionName Caller function + * @returns Pointer returned by calloc if it's valid, NULL otherwhise. + */ +void* calloc_dbg(size_t elementCount, size_t elementSize, int line, const char* filename, const char* functionName) +{ + void* ptrToReturn = calloc(elementCount, elementSize); + if (!ptrToReturn) + { + return NULL; + } + + // We must check atexitCalled value to know if we already called the function + if (!atexitCalled) + { + atexit(printLeaks); // Used to call printLeaks when the program exit + atexitCalled = 1; + } + + // Add a new element in the mem_info list + memoryInformation = addMemInfo(memoryInformation, ptrToReturn, elementCount * elementSize, line, filename, functionName); + if (!memoryInformation) + { + free(ptrToReturn); + return NULL; + } + + return ptrToReturn; +} + +/** + * @brief free_dbg function is used to free the memory allocated to a pointer. + * @details This function free the memory pointed by the pointer passed in parameter. + * To free this pointer, we loop through the mem_info list and check if we find the pointer. + * Once it's found, the pointer is freed and the element is deleted from the list. + * @param ptrToFree Pointer that must be freed + * @returns Nothing. + */ +void free_dbg(void* ptrToFree) +{ + mem_info* tmp = memoryInformation; + mem_info* toFree = NULL; + mem_info* previous = NULL; + + // Check if the head contains the pointer to free + if (tmp->ptr == ptrToFree) + { + toFree = tmp; + memoryInformation = tmp->next; + free(toFree->ptr); + free(toFree); + if (memoryInformation) + { + memoryInformation->previous = NULL; + } + return; + } + + // We can loop through the list without any problems, the head is not the pointer + while (tmp) + { + if (tmp->ptr == ptrToFree) // If we found the pointer that must be freed + { + toFree = tmp; + tmp = tmp->next; + previous = toFree->previous; + + if (previous) + { + previous->next = tmp; + } + if (tmp) + { + tmp->previous = previous; + } + + free(toFree->ptr); + if (toFree == memoryInformation) + { + memoryInformation = NULL; + } + free(toFree); + return; + } + tmp = tmp->next; + } +} + +/** + * @brief printLeaks function is used to print all the memory leaks. + * @details This function is called when the program exits. It loop through the mem_info list and if it's not empty, + * it prints the memory leaks. + * @returns Nothing. + */ +void printLeaks() +{ + mem_info* tmp = memoryInformation; + mem_info* previous = NULL; + size_t sum = 0; + int nbBlocks = 0; + + if (tmp) + { + printf("Memory Leaks detected.\n"); + } + + while (tmp) + { + previous = tmp; + printf("\n%ld bytes lost\n", tmp->bytes); + printf("address : 0x%p in %s\t%s:%d\n", tmp->ptr, tmp->functionName, tmp->fileName, tmp->line); + printf("\n====================================\n"); + sum += tmp->bytes; + tmp = tmp->next; + free(previous); + nbBlocks++; + } + + printf("SUMMARY :\n%ld bytes lost in %d blocks\n", sum, nbBlocks); +} diff --git a/developer_tools/malloc_dbg.h b/developer_tools/malloc_dbg.h new file mode 100644 index 0000000000..5ff11962b4 --- /dev/null +++ b/developer_tools/malloc_dbg.h @@ -0,0 +1,36 @@ +/** + * @file + * @brief Header file that contains macros used to replace malloc/calloc and free. + * @details + * Macros malloc, calloc and free respectively calls malloc_dbg, calloc_dbg and free_dbg. + * malloc_dbg and calloc_dbg allocates memory using the "real" malloc and calloc and store + * the pointer returned (with additional informations) in a linked list. + * Thanks to this linked list, it is possible to check memory leaks. + * @author [tinouduart33](https://github.com/tinouduart33) + * @see malloc_dbg.c + */ + +#ifndef MALLOC_DBG_H +#define MALLOC_DBG_H + + /** This macro replace the standard malloc function with malloc_dbg. + * */ +#define malloc(bytes) malloc_dbg(bytes, __LINE__, __FILE__, __FUNCTION__) + + /** This macro replace the standard calloc function with calloc_dbg. + * */ +#define calloc(elemCount, elemSize) calloc_dbg(elemCount, elemSize, __LINE__, __FILE__, __FUNCTION__) + + /** This macro replace the standard free function with free_dbg. + * */ +#define free(ptr) free_dbg(ptr) + +void* malloc_dbg(size_t bytes, int line, const char* filename, const char* functionName); + +void* calloc_dbg(size_t elementCount, size_t elementSize, int line, const char* filename, const char* functionName); + +void free_dbg(void* ptrToFree); + +void printLeaks(void); + +#endif /* MALLOC_DBG_H */ diff --git a/developer_tools/min_printf.h b/developer_tools/min_printf.h new file mode 100644 index 0000000000..395331c18f --- /dev/null +++ b/developer_tools/min_printf.h @@ -0,0 +1,356 @@ +/** + * @file + * @brief Implementation of a [function](https://www.geeksforgeeks.org/variable-length-argument-c) similar to `printf` + * @details + * `printf` statement rewritten (as `min_printf`) in C without using the `stdio.h` library + * Syntax of `min_printf` is same as `printf` + * Currently min_printf handles: + * Integers, Doubles, floats, characters and strings + * The format specifiers and escape sequence is the same as for `printf` + * User can also specify the width and precision if required, just like in the case of `printf` + * How to use it: + * - First include min_printf.h in your code + * - Then type `min_printf()`, and pass required parameters to it + * - As already specified, it's syntax is same as printf + * @author [Jaskarn Singh](https://github.com/Jaskarn7) +*/ + +#ifndef MIN_PRINTF_H +#define MIN_PRINTF_H + +#include /// for `malloc` and `free` functions +#ifdef _WIN32 + #include /// for `write` function +#else + #include /// for `write` function +#endif +#include /// for `va_start` and `va_arg` functions + +#define INT_MAX_LENGTH 10 /// used as standard length of string to store integers +#define PRECISION_FOR_FLOAT 8 /// default precision for float or double if not specified + +/** + * @brief struct used to store character in certain times +*/ +typedef struct buffer { + char buffr_char; // Character will be stored in this variable + int buf_size; // Checks if character is present in buffr_char or not, 0 if no and 1 if yes +} Buffer; + +/** + * @details + * This function return ten to the power a(The parameter specified to it) like: + * if the parameter specified is 4 i.e. -> power_of_ten(4) is called then + * this function will return ten to the power four (10000); + * @param a The power of ten which is to be returned + * @return Ten to the power a + */ +int power_of_ten(int a) +{ + int n = 1; ///< This number will be returned as ten to power of a + for (int i = 1; i <= a; ++i) + n *= 10 ; + return n; +} + +/** + * @brief Checks if a character is a number + * @param c character to be checked if it's a number or not + * @return `true`(1) if the character is a number + * @return `false`(0) if the character is NOT a number +*/ +int is_number(char *c) +{ + return (*c >= '0' && *c <= '9') ? 1 : 0; +} + +/** + * @brief Returns specific required next character + * @param p pointer to a format string of `min_printf()` + * @param buffer struct for checking if buffr_char character is present or not + * @return character inside `buffer->buffr_char`, if `buffer->buf_size` is one + * @return character at which p is pointing, if `buffer->buf_size` is zero + */ +char get_ch(char *p, Buffer *buffer) +{ + if (buffer->buf_size) { + buffer->buf_size = 0; ///< Since character is used, this sets `buffer->buf_size` to zero + return buffer->buffr_char; // Returns character inside buffer->buffr_char + } + return *p++; +} + +/** + * @brief Stores character to the `buffer->buffr_char` + * @param c character to be stored in the `buffer->buffr_char` + * @param buffer struct where character will be stored +*/ +void unget_ch(char *c, Buffer *buffer) +{ + buffer->buffr_char = *c; // Character initializes inside buffer->buffr_char + buffer->buf_size = 1; // Sets bufsize to one as new character is stored in buffr_char +} + + +/** + * @brief Calculates the number of digits in a number + * @param n number whose digits are to be counted + * @return number of digits in n +*/ +int get_number_of_digits(int n) +{ + int digits = 0; // Stores encountered number of digits + while (n > 0) { + ++digits; // Since number still contains a digit, so increment digit variable + n /= 10; // Removes last digit from number + } + return digits; +} + +/** + * @brief Prints one character on screen + * @param s character to be printed on the screen +*/ +void put_char(char s) +{ + /* buf used for storing character to be printed in an array (+1 for '\0')*/ + char *buf = (char *) malloc(sizeof(char) + 1); + *buf = s; + *(buf + 1) = '\0'; + write(1, buf, 1); + free(buf); +} + +/** + * @brief Reverses a string using [two pointer algorithm](https://www.geeksforgeeks.org/program-reverse-array-using-pointers/?ref=rp) + * @param p pointer to the string which is to be reversed +*/ +void reverse_str(char *p) +{ + char *l = p; // Points to first character of p + char *h = p; // Will be used to point to last character of p + char temp; // Temporarily stores a character, Used in swapping + + while (*h != '\0') + ++h; + --h; // Now h point to last valid character of string + + /* Swap character which lower and higher are pointing until lower < higher. At that point string will be reversed.*/ + while (l < h) { + temp = *l; + *l = *h; + *h = temp; + ++l; // Increment lower to next character + --h; // Decrement higher to previous character from current character + } +} + +/** + * @details + * The algorithm here is to first convert the number into + * string and then reverse it be passing it to reverse_str function + * and then printing on the screen + * @param n Number to be printed + * @param width Total characters to be printed (Prints ' ' if (size < width) + * @param precision Total character of number to be printed (prints 0 before number if size of number < precision) + * +*/ +void print_int_value(int n, int width, int precision) +{ + char *p = (char *) malloc(INT_MAX_LENGTH * sizeof(char) + 1); /* +1 for '\0' */ + char *s = p; // Temporary pointer + int size = 0; //!< Used to store number of digits in number + + while (n > 0) { + *s++ = n % 10 + '0'; // Converts last digit of number to character and store it in p + ++size; // Increment size variable as one more digit is occurred + n /= 10; // Removes the last digit from the number n as we have successfully stored it in p + } + *s = '\0'; + + s = p; // Again point back s to starting of p + + reverse_str(p); + + /*! + * The next two conditions check weather it is required to + * add blanks before printing the number (ie: width)and is it specified how many + * zeros to be printed before the number is printed (ie: precision) + */ + if (width > 0 && size < width) + for (int i = 0; i < (width - precision); ++i) + put_char(' '); + + if (precision > 0 && precision > size) + for (int i = 0; i < (precision - size); ++i) + put_char('0'); + + /* Prints the number.*/ + while (*s != '\0') + put_char(*s++); + + free(p); +} + +/** +* @brief The algorithm here is also the same as the `print_int_value` function + * + * @details + * First, the digits before decimal is printed by converting the double + * to int. Then after printed a `.`, the double number is subtracted with + * the integer value of the number, leaving us with 0 before the decimal. + * Then, we multiply the number with 10 raised to the power precision ( + * precision means how many digits to be printed after the decimal.) + * By default, the precision is 8 if it is not specified. + * Then, the remaining number is printed on the screen. + * @param dval double number to be printed + * @param width similar to width parameter of print_int_value() + * @param precision tells the number of digits to be printed after the decimal (By default it is 8) + */ +void print_double_value(double dval, int width, int precision) +{ + int ndigits = get_number_of_digits((int) dval); // Store number of digits before decimal in dval + int reqd_blanks = width - (precision + 1) - ndigits; // Blanks to be printed before printing dval, just to cover the width + + print_int_value((int) dval, reqd_blanks, 0); // Prints the part before decimal + + put_char('.'); // Print decimal + + /*Deletes digits before decimal and makes them zero. For example: + if dval = 1923.79022, them this will make dval = 0.79022 + */ + dval = dval - (int) dval; + + dval *= power_of_ten(precision); // Brings precision number of digits after decimal to before decimal + + print_int_value((int) dval, 0, precision); // Prints the remaining number +} + +/** + * @details +* First size of the string is calculated to check whether +* width and precision are to be taken into account or not. +* Then, the string is printed in accordingly. +* @param p pointer to string to be printed +* @param width if (width > sizeof string) then, blanks will be printed before sting to cover up the width +* @param precision total characters of the string to be printed (prints the whole string if 0 or greater than size of string) +*/ +void print_string(char *p, int width, int precision) +{ + int size = 0; // Stores number of character in string + char *s = p; // Temporary pointer + + /* Calculates size of string p*/ + while (*s != '\0') { + ++size; + ++s; + } + + s = p; // Point s to starting of p + + /* Checks how many characters to be printed. + if precision is defined then size variable is changed to precision so that only precision + number of characters were printed. + */ + if (precision != 0 && precision < size) + size = precision; + + /* Prints blanks to cover the width if required*/ + for (int i = 0; i < (width - size); ++i) + put_char(' '); + + /* Print the string.*/ + for (int i = 0; i < size; ++i) + put_char(*s++); + +} + +/** +* @brief Takes width and precision specified from the format of the string +* @param p pointer of the format string +* @param width variable in which width will be stored +* @param precision variable in which precision will be stored +* @return character pointer to the current pointer of string p (used to update value of p) +*/ +char *get_width_and_precision(char *p, Buffer *buffer, int *width, int *precision) +{ + /* Skip % if p is pointing to it.*/ + if (*p == '%') + ++p; + + /* Calculates the width specified. */ + while (*p != '.' && is_number(p)) + *width = *width * 10 + (*p++ - '0'); + + /* Calculates the precision specified.*/ + if (*p == '.' /* Since a precision is always specified after a '.'. */) { + while (is_number(++p)) + *precision = *precision * 10 + (*p - '0'); + unget_ch(p, buffer); // The non number will be stored in `buffer->buffr` + } + return p; +} + +/** + * min_printf is the function same as printf + * @param fmt format of string + * @param ... arguments passed according to the format +*/ +void min_printf(char *fmt, ...) +{ + va_list ap; // Points to each unnamed arg in turn + char *p, *sval; // p will be used to point to fmt and sval will store string value + char cval; // Stores character value + int ival; // For integer values + double dval; // For double or float values + va_start(ap, fmt); // Makes ap points to first unnames argument + + /* Initializing the buffer for storing character. */ + Buffer *buffer = (Buffer *) malloc(sizeof(Buffer)); + buffer->buf_size = 0; // Initially set buffer size to zero as no character is inserted + + for (p = fmt; *p != '\0'; ++p) { + + /* If p != '%' then the character is printed to screen. */ + if (*p != '%') { + put_char(*p); + continue; + } + + int width = 0; // Stores width specified + int precision = 0; // Stores precision specified + + /* Updates values of width, precision and p. */ + p = get_width_and_precision(p, buffer, &width, &precision); + + /* Checks format of next argument.*/ + switch (get_ch(p, buffer)) { + case 'd': // Integer + ival = va_arg(ap, int); + print_int_value(ival, width, precision); + break; + case 'c': // Character + cval = va_arg(ap, int); + put_char(cval); + break; + case 'f': // Float or Double + dval = va_arg(ap, double); + + // If precision is not specified then default value is applied + if (precision == 0) + precision = PRECISION_FOR_FLOAT; + print_double_value(dval, width, precision); + break; + case 's': // String pointer + sval = va_arg(ap, char *); + print_string(sval, width, precision); + break; + default: + put_char(*p); + break; + } + } + va_end(ap); +} + +#endif /* MIN_PRINTF_H */ diff --git a/developer_tools/test_malloc_dbg.c b/developer_tools/test_malloc_dbg.c new file mode 100644 index 0000000000..830ada04a4 --- /dev/null +++ b/developer_tools/test_malloc_dbg.c @@ -0,0 +1,31 @@ +/** + * @file + * @brief File used to test the malloc_dbg, calloc_dbg and free_dbg functions. + * @details + * This file only have a main function that calls malloc, calloc and free. + * When the program exits, memory leaks must be printed. + * @author [tinouduart33](https://github.com/tinouduart33) + * @see malloc_dbg.c, malloc_dbg.h + */ + +#include /// For IO operations if needed. +#include /// For the EXIT_SUCCESS macro and the "real" malloc, calloc and free functions. +#include "malloc_dbg.h" /// For the macros malloc, calloc and free and the malloc_dbg, calloc_dbg and free_dbg functions. + + +/** + * @brief Main function + * @param argc number of arguments (not used) + * @param argv list of arguments (not used) + * @returns 0 on exit + */ +int main(int argc, char* argv[]) +{ + int* iptr = malloc(10 * sizeof(int)); + char* cptr = calloc(256, sizeof(char)); + + free(iptr); + // free(cptr); + + return 0; +} diff --git a/developer_tools/test_min_printf.c b/developer_tools/test_min_printf.c new file mode 100644 index 0000000000..9d0ed215e8 --- /dev/null +++ b/developer_tools/test_min_printf.c @@ -0,0 +1,42 @@ +/** + * @file + * @brief File used to test min_printf function. + * @details + * The test will be executed by comparing the result of both `min_printf` and `printf` functions + * @author [Jaskarn7](https://github.com/Jaskarn7) + * @see min_printf.h +*/ + +#include "min_printf.h" /// for `min_printf` function +#include /// for `printf` function + +/** + * @brief Main function + * @details + * This function is used to test `min_printf` function. + * The numbers and string used for the test is generated randomly (The user can also specify their own value for tests) + * First integers were tested then floats and at last strings + * After running the program the user will see three pair of lines with each pair followed by an empty line + * In each pair of lines, the first line will be printed by `min_printf` function and next line by the actual `printf` function + * In each line user will see number or string covered with two colons, they are used to check from where the printing was started and where it ends + * @returns 0 on exit +*/ +int main() +{ + // print strings using `printf` and `min_printf` + min_printf(":%d: :%1.6d:\n", 12, 56); + printf(":%d: :%1.6d:\n", 12, 56); + + printf("\n"); /// Printing an empty new line + + // print floats or doubles using `printf` and `min_printf` + min_printf(":%f: :%3.6f:\n", 104.5654, 43.766443332); + printf(":%f: :%3.6f:\n", 104.5654, 43.766443332); + + printf("\n"); + + // print integers `printf` and `min_printf` + min_printf(":%s: :%4.3s:\n", "Hello, World!", "Hello, World!"); + printf(":%s: :%4.3s:\n", "Hello, World!", "Hello, World!"); + +} diff --git a/dynamic_programming/CMakeLists.txt b/dynamic_programming/CMakeLists.txt new file mode 100644 index 0000000000..a65bbb7da6 --- /dev/null +++ b/dynamic_programming/CMakeLists.txt @@ -0,0 +1,18 @@ +# 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} *.c ) +foreach( testsourcefile ${APP_SOURCES} ) + string( REPLACE ".c" "" testname ${testsourcefile} ) # File type. Example: `.c` + add_executable( ${testname} ${testsourcefile} ) + + if(OpenMP_C_FOUND) + target_link_libraries(${testname} OpenMP::OpenMP_C) + endif() + if(MATH_LIBRARY) + target_link_libraries(${testname} ${MATH_LIBRARY}) + endif() + install(TARGETS ${testname} DESTINATION "bin/dynamic_programming") # Folder name. Do NOT include `<>` + +endforeach( testsourcefile ${APP_SOURCES} ) diff --git a/dynamic_programming/lcs.c b/dynamic_programming/lcs.c new file mode 100644 index 0000000000..bf360b7321 --- /dev/null +++ b/dynamic_programming/lcs.c @@ -0,0 +1,165 @@ +/** + * @file + * @brief [Longest Common + * Subsequence](https://en.wikipedia.org/wiki/Longest_common_subsequence_problem) + * algorithm + * @details + * From Wikipedia: The longest common subsequence (LCS) problem is the problem + * of finding the longest subsequence common to all sequences in a set of + * sequences (often just two sequences). + * @author [Kurtz](https://github.com/itskurtz) + */ + +#include /* for io operations */ +#include /* for memory management & exit */ +#include /* for string manipulation & ooperations */ +#include /* for asserts */ + +enum {LEFT, UP, DIAG}; + +/** + * @brief Computes LCS between s1 and s2 using a dynamic-programming approach + * @param s1 first null-terminated string + * @param s2 second null-terminated string + * @param l1 length of s1 + * @param l2 length of s2 + * @param L matrix of size l1 x l2 + * @param B matrix of size l1 x l2 + * @returns void + */ +void lcslen(const char *s1, const char *s2, int l1, int l2, int **L, int **B) { + /* B is the directions matrix + L is the LCS matrix */ + int i, j; + + /* loop over the simbols in my sequences + save the directions according to the LCS */ + for (i = 1; i <= l1; ++i) { + for (j = 1; j <= l2; ++j) { + if (s1[i-1] == s2[j-1]) { + L[i][j] = 1 + L[i-1][j-1]; + B[i][j] = DIAG; + } + else if (L[i-1][j] < L[i][j-1]) { + L[i][j] = L[i][j-1]; + B[i][j] = LEFT; + } + else { + L[i][j] = L[i-1][j]; + B[i][j] = UP; + } + } + } +} + +/** + * @brief Builds the LCS according to B using a traceback approach + * @param s1 first null-terminated string + * @param l1 length of s1 + * @param l2 length of s2 + * @param L matrix of size l1 x l2 + * @param B matrix of size l1 x l2 + * @returns lcs longest common subsequence + */ +char *lcsbuild(const char *s1, int l1, int l2, int **L, int **B) { + int i, j, lcsl; + char *lcs; + lcsl = L[l1][l2]; + + /* my lcs is at least the empty symbol */ + lcs = (char *)calloc(lcsl+1, sizeof(char)); /* null-terminated \0 */ + if (!lcs) { + perror("calloc: "); + return NULL; + } + + i = l1, j = l2; + while (i > 0 && j > 0) { + /* walk the matrix backwards */ + if (B[i][j] == DIAG) { + lcs[--lcsl] = s1[i-1]; + i = i - 1; + j = j - 1; + } + else if (B[i][j] == LEFT) + { + j = j - 1; + } + else + { + i = i - 1; + } + } + return lcs; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + /* https://en.wikipedia.org/wiki/Subsequence#Applications */ + int **L, **B, j, l1, l2; + + char *s1 = "ACGGTGTCGTGCTATGCTGATGCTGACTTATATGCTA"; + char *s2 = "CGTTCGGCTATCGTACGTTCTATTCTATGATTTCTAA"; + char *lcs; + + l1 = strlen(s1); + l2 = strlen(s2); + + L = (int **)calloc(l1+1, sizeof(int *)); + B = (int **)calloc(l1+1, sizeof(int *)); + + if (!L) { + perror("calloc: "); + exit(1); + } + if (!B) { + perror("calloc: "); + exit(1); + } + for (j = 0; j <= l1; j++) { + L[j] = (int *)calloc(l2+1, sizeof(int)); + if (!L[j]) { + perror("calloc: "); + exit(1); + } + B[j] = (int *)calloc(l2+1, sizeof(int)); + if (!L[j]) { + perror("calloc: "); + exit(1); + } + } + + lcslen(s1, s2, l1, l2, L, B); + lcs = lcsbuild(s1, l1, l2, L, B); + + assert(L[l1][l2] == 27); + assert(strcmp(lcs, "CGTTCGGCTATGCTTCTACTTATTCTA") == 0); + + printf("S1: %s\tS2: %s\n", s1, s2); + printf("LCS len:%3d\n", L[l1][l2]); + printf("LCS: %s\n", lcs); + + free(lcs); + for (j = 0; j <= l1; j++) + { + free(L[j]), free(B[j]); + } + free(L); + free(B); + + printf("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 + return 0; +} diff --git a/dynamic_programming/matrix_chain_order.c b/dynamic_programming/matrix_chain_order.c new file mode 100644 index 0000000000..7b48f4ca5e --- /dev/null +++ b/dynamic_programming/matrix_chain_order.c @@ -0,0 +1,119 @@ +/** + * @file + * @brief [Matrix Chain + * Order](https://en.wikipedia.org/wiki/Matrix_chain_multiplication) + * @details + * From Wikipedia: Matrix chain multiplication (or the matrix chain ordering + * problem) is an optimization problem concerning the most efficient way to + * multiply a given sequence of matrices. The problem is not actually to perform + * the multiplications, but merely to decide the sequence of the matrix + * multiplications involved. + * @author [CascadingCascade](https://github.com/CascadingCascade) + */ + +#include /// for assert +#include /// for INT_MAX macro +#include /// for IO operations +#include /// for malloc() and free() + +/** + * @brief Finds the optimal sequence using the classic O(n^3) algorithm. + * @param l length of cost array + * @param p costs of each matrix + * @param s location to store results + * @returns number of operations + */ +int matrixChainOrder(int l, const int *p, int *s) +{ + // mat stores the cost for a chain that starts at i and ends on j (inclusive + // on both ends) + int **mat = malloc(l * sizeof(int *)); + for (int i = 0; i < l; ++i) + { + mat[i] = malloc(l * sizeof(int)); + } + + for (int i = 0; i < l; ++i) + { + mat[i][i] = 0; + } + // cl denotes the difference between start / end indices, cl + 1 would be + // chain length. + for (int cl = 1; cl < l; ++cl) + { + for (int i = 0; i < l - cl; ++i) + { + int j = i + cl; + mat[i][j] = INT_MAX; + for (int div = i; div < j; ++div) + { + int q = mat[i][div] + mat[div + 1][j] + p[i] * p[div] * p[j]; + if (q < mat[i][j]) + { + mat[i][j] = q; + s[i * l + j] = div; + } + } + } + } + int result = mat[0][l - 1]; + + // Free dynamically allocated memory + for (int i = 0; i < l; ++i) + { + free(mat[i]); + } + free(mat); + + return result; +} + +/** + * @brief Recursively prints the solution + * @param l dimension of the solutions array + * @param s solutions + * @param i starting index + * @param j ending index + * @returns void + */ +void printSolution(int l, int *s, int i, int j) +{ + if (i == j) + { + printf("A%d", i); + return; + } + putchar('('); + printSolution(l, s, i, s[i * l + j]); + printSolution(l, s, s[i * l + j] + 1, j); + putchar(')'); +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() +{ + int sizes[] = {35, 15, 5, 10, 20, 25}; + int len = 6; + int *sol = malloc(len * len * sizeof(int)); + int r = matrixChainOrder(len, sizes, sol); + assert(r == 18625); + printf("Result : %d\n", r); + printf("Optimal ordering : "); + printSolution(len, sol, 0, 5); + free(sol); + + printf("\n"); +} + +/** + * @brief Main function + * @returns 0 + */ +int main() +{ + test(); // run self-test implementations + return 0; +} diff --git a/exercism/acronym/acronym.c b/exercism/acronym/acronym.c index 828b925c7a..2c1c4e6455 100644 --- a/exercism/acronym/acronym.c +++ b/exercism/acronym/acronym.c @@ -1,6 +1,6 @@ -#include -#include #include +#include +#include char *abbreviate(const char *phrase) { @@ -19,8 +19,8 @@ char *abbreviate(const char *phrase) /* for -loop variable */ int i = 0; - /* - counts the empty-characters. + /* + counts the empty-characters. for determine the number of words */ while (p_str && (i < 80)) @@ -38,12 +38,13 @@ char *abbreviate(const char *phrase) i = 0; counter++; - char words[counter][80]; + char **words = (char **)malloc(counter * sizeof(char *)); /* initalizes words-array with empty strings */ for (i = 0; i < counter; i++) { - strcpy(words[i],""); + words[i] = (char *)malloc(80 * sizeof(char)); + strcpy(words[i], ""); } /* rewind string */ @@ -83,5 +84,8 @@ char *abbreviate(const char *phrase) strcat(acr, words[i]); } + for (i = 0; i < counter; i++) free(words[i]); + free(words); + return acr; -} \ No newline at end of file +} diff --git a/exercism/hello-world/hello_world.c b/exercism/hello_world/hello_world.c similarity index 50% rename from exercism/hello-world/hello_world.c rename to exercism/hello_world/hello_world.c index 4534990006..270911dab0 100644 --- a/exercism/hello-world/hello_world.c +++ b/exercism/hello_world/hello_world.c @@ -4,10 +4,7 @@ const char *hello(void) { - char * ans = malloc(sizeof(char) * strlen("Hello, World!")); - if (!ans) return NULL; - strcpy(ans,"Hello, World!"); - + char *ans = strdup("Hello, World!"); /* string is pointer of the first character */ - return ans; + return ans; } diff --git a/exercism/hello-world/hello_world.h b/exercism/hello_world/hello_world.h similarity index 100% rename from exercism/hello-world/hello_world.h rename to exercism/hello_world/hello_world.h diff --git a/exercism/isogram/isogram.c b/exercism/isogram/isogram.c index a54e3c815b..574b98d9aa 100644 --- a/exercism/isogram/isogram.c +++ b/exercism/isogram/isogram.c @@ -4,9 +4,8 @@ /* is_isogram: returns true if the given string a isogram, otherwise false. */ -bool is_isogram(const char phrase[]) +bool is_isogram(const char phrase[]) { - /* use 'unsigned' because of the function strlen(...) */ unsigned int i = 0; unsigned int j = 0; @@ -20,18 +19,18 @@ bool is_isogram(const char phrase[]) /* contains the length of the given string */ unsigned int len_phrase = strlen(phrase); - for (i = 0; i < len_phrase; i++ ) + for (i = 0; i < len_phrase; i++) { current_char = phrase[i]; /* makes sure the current character has no repetition */ - for (j = i+1; j < len_phrase; j++) + for (j = i + 1; j < len_phrase; j++) { if (current_char == phrase[j]) { status = false; - /* + /* because the given string is none isogram. that means we can exit the nested for-loop. */ @@ -40,7 +39,7 @@ bool is_isogram(const char phrase[]) } } - /* exit label */ - end: - return status; +/* exit label */ +end: + return status; } \ No newline at end of file diff --git a/exercism/rna-transcription/rna_transcription.c b/exercism/rna_transcription/rna_transcription.c similarity index 99% rename from exercism/rna-transcription/rna_transcription.c rename to exercism/rna_transcription/rna_transcription.c index 856af351fe..8d3b18024c 100644 --- a/exercism/rna-transcription/rna_transcription.c +++ b/exercism/rna_transcription/rna_transcription.c @@ -4,7 +4,6 @@ char *to_rna(const char s[]) { - /* determines the length of the given string */ int len = strlen(s); diff --git a/exercism/rna-transcription/rna_transcription.h b/exercism/rna_transcription/rna_transcription.h similarity index 80% rename from exercism/rna-transcription/rna_transcription.h rename to exercism/rna_transcription/rna_transcription.h index 6c3bc0f15e..cab577359c 100644 --- a/exercism/rna-transcription/rna_transcription.h +++ b/exercism/rna_transcription/rna_transcription.h @@ -2,6 +2,6 @@ #define __RNA_TRANSCRIPTION__H /* to_rna: compiles a DNA strand in its RNA complement */ -char * to_rna(const char s[]); +char *to_rna(const char s[]); #endif \ No newline at end of file diff --git a/exercism/word-count/word_count.c b/exercism/word_count/word_count.c similarity index 95% rename from exercism/word-count/word_count.c rename to exercism/word_count/word_count.c index 4bdf27f5b4..ac2ceea479 100644 --- a/exercism/word-count/word_count.c +++ b/exercism/word_count/word_count.c @@ -2,7 +2,7 @@ #include /* - word_count: returns the full number of words in the input_text, + word_count: returns the full number of words in the input_text, otherwise an error code: (see below) error codes: EXCESSIVE_LENGTH_WORD -1 @@ -41,7 +41,6 @@ int word_count(const char *input_text, word_count_word_t *words) input[index] = '\0'; if (strlen(p_str) <= MAX_WORD_LENGTH) { - if (index_list <= MAX_WORDS) { strcpy(word_list[index_list], p_str); @@ -71,7 +70,7 @@ int word_count(const char *input_text, word_count_word_t *words) words->count = 0; - /* make sure none error is occured */ + /* make sure none error is occurred */ if (loop) { /* collects the last word up to the \0-character. and counts it.*/ @@ -80,7 +79,7 @@ int word_count(const char *input_text, word_count_word_t *words) for (i = 0; i <= index_list; i++) { - if (strcmp(word_list[i],words->text) == 0) + if (strcmp(word_list[i], words->text) == 0) { words->count++; } @@ -89,4 +88,4 @@ int word_count(const char *input_text, word_count_word_t *words) /* returns the number of words or an error code */ return count_all; -} \ No newline at end of file +} diff --git a/exercism/word-count/word_count.h b/exercism/word_count/word_count.h similarity index 57% rename from exercism/word-count/word_count.h rename to exercism/word_count/word_count.h index ba81941433..584db7368e 100644 --- a/exercism/word-count/word_count.h +++ b/exercism/word_count/word_count.h @@ -1,20 +1,21 @@ #ifndef WORD_COUNT_H #define WORD_COUNT_H -#define MAX_WORDS 20 // at most MAX_WORDS can be found in the test input string -#define MAX_WORD_LENGTH 50 // no individual word can exceed this length +#define MAX_WORDS 20 // at most MAX_WORDS can be found in the test input string +#define MAX_WORD_LENGTH 50 // no individual word can exceed this length // results structure -typedef struct word_count_word { - char text[MAX_WORD_LENGTH]; - int count; +typedef struct word_count_word +{ + char text[MAX_WORD_LENGTH]; + int count; } word_count_word_t; -#define EXCESSIVE_LENGTH_WORD -1 +#define EXCESSIVE_LENGTH_WORD -1 #define EXCESSIVE_NUMBER_OF_WORDS -2 -// word_count - routine to classify the unique words and their frequency in a test input string -// inputs: +// word_count - routine to classify the unique words and their frequency in a +// test input string inputs: // input_text = a null-terminated string containing that is analyzed // // outputs: @@ -22,6 +23,6 @@ typedef struct word_count_word { // uniqueWords - number of words in the words structure // returns a negative number if an error. // words will contain the results up to that point. -int word_count(const char *input_text, word_count_word_t * words); +int word_count(const char *input_text, word_count_word_t *words); #endif diff --git a/games/CMakeLists.txt b/games/CMakeLists.txt new file mode 100644 index 0000000000..ca45ee499d --- /dev/null +++ b/games/CMakeLists.txt @@ -0,0 +1,24 @@ +# 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} *.c ) +# file( GLOB APP_SOURCES ${CMAKE_SOURCE_DIR}/*.c ) +# AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} APP_SOURCES) + +foreach( testsourcefile ${APP_SOURCES} ) + string( REPLACE ".c" "" testname ${testsourcefile} ) + string( REPLACE ".C" "" testname ${testname} ) + string( REPLACE " " "_" testname ${testname} ) + + add_executable( ${testname} ${testsourcefile} ) + + if(OpenMP_C_FOUND) + target_link_libraries(${testname} OpenMP::OpenMP_C) + endif() + + if(MATH_LIBRARY) + target_link_libraries(${testname} ${MATH_LIBRARY}) + endif() + install(TARGETS ${testname} DESTINATION "bin/games") + +endforeach( testsourcefile ${APP_SOURCES} ) diff --git a/games/hangman.c b/games/hangman.c new file mode 100644 index 0000000000..5d2697df75 --- /dev/null +++ b/games/hangman.c @@ -0,0 +1,291 @@ +/** + * @file + * @brief C implementation of [Hangman Game](https://en.wikipedia.org/wiki/Hangman_(game)) + * @details + * Simple, readable version of hangman. + * Changed graphic to duck instead of traditional stick figure (same number of guesses). + * @author [AtlantaEmrys2002](https://github.com/AtlantaEmrys2002) +*/ + +#include /// for main() - tolower() +#include /// for main(), new_word(), new_guess(), won() - I/O operations +#include /// for all functions - exit(), rand() and file functions +#include /// for main() - for string operations strlen, strchr, strcpy +#include /// for new_game() - used with srand() for declaring new game instance + +/* + * @brief game_instance structure that holds current state of game + */ +struct game_instance{ + + char current_word[30]; ///< word to be guessed by player + char hidden[30]; ///< hidden version of word that is displayed to player + int size; ///< size of word + int incorrect; ///< number of incorrect guesses + char guesses[25]; ///< previous guesses + int guesses_size; ///< size of guesses array + +}; + +// function prototypes +struct game_instance new_game(void); // creates a new game +int new_guess(char, const char guesses[], int size); // checks if player has already played letter +int in_word(char, const char word[], unsigned int size); // checks if letter is in word +void picture(int score); // outputs image of duck (instead of hang man) +void won(const char word[], int score); // checks if player has won or lost + +/** + * @brief Main Function + * @returns 0 on exit + */ +int main() { + + struct game_instance game = new_game(); // new game created + char guess; // current letter guessed by player + + // main loop - asks player for guesses + while ((strchr(game.hidden, '_') != NULL) && game.incorrect <= 12) { + do { + printf("\n****************************\n"); + printf("Your word: "); + + for (int i = 0; i < game.size; i++) { + printf("%c ", game.hidden[i]); + } + + if (game.guesses_size > 0) { + printf("\nSo far, you have guessed: "); + for (int i = 0; i < game.guesses_size; i++) { + printf("%c ", game.guesses[i]); + } + } + + printf("\nYou have %d guesses left.", (12 - game.incorrect)); + printf("\nPlease enter a letter: "); + scanf(" %c", &guess); + guess = tolower(guess); + + } while (new_guess(guess, game.guesses, game.guesses_size) != -1); + + game.guesses[game.guesses_size] = guess; // adds new letter to guesses array + game.guesses_size++; // updates size of guesses array + + if (in_word(guess, game.current_word, game.size) == 1) { + printf("That letter is in the word!"); + for (int i = 0; i < game.size; i++) { + if ((game.current_word[i]) == guess) { + game.hidden[i] = guess; + } + } + } else { + printf("That letter is not in the word.\n"); + (game.incorrect)++; + } + picture(game.incorrect); + } + + won(game.current_word, game.incorrect); + return 0; +} + +/** + * @brief checks if letter has been guessed before + * @param new_guess letter that has been guessed by player + * @param guesses array of player's previous guesses + * @param size size of guesses[] array + * @returns 1 if letter has been guessed before + * @returns -1 if letter has not been guessed before + */ +int new_guess(char new_guess, const char guesses[], int size) { + + for (int j = 0; j < size; j++) { + if (guesses[j] == new_guess) { + printf("\nYou have already guessed that letter."); + return 1; + } + } + + return -1; +} + +/** + * @brief checks if letter is in current word + * @param letter letter guessed by player + * @param word current word + * @param size length of word + * @returns 1 if letter is in word + * @returns -1 if letter is not in word + */ +int in_word(char letter, const char word[], unsigned int size) { + + for (int i = 0; i < size; i++) { + if ((word[i]) == letter) { + return 1; + } + } + + return -1; +} + +/** + * @brief creates a new game - generates a random word and stores in global variable current_word + * @returns current_game - a new game instance containing randomly selected word, its length and hidden version of word + */ +struct game_instance new_game() { + + char word[30]; // used throughout function + + FILE *fptr; + fptr = fopen("games/words.txt", "r"); + + if (fptr == NULL){ + fprintf(stderr, "File not found.\n"); + exit(EXIT_FAILURE); + } + + // counts number of words in file - assumes each word on new line + int line_number = 0; + while (fgets(word, 30, fptr) != NULL) { + line_number++; + } + + rewind(fptr); + + // generates random number + int random_num; + srand(time(NULL)); + random_num = rand() % line_number; + + // selects randomly generated word + int s = 0; + while (s <= random_num){ + fgets(word, 30, fptr); + s++; + } + + // formats string correctly + if (strchr(word, '\n') != NULL){ + word[strlen(word) - 1] = '\0'; + } + + fclose(fptr); + + // creates new game instance + struct game_instance current_game; + strcpy(current_game.current_word, word); + current_game.size = strlen(word); + for (int i = 0; i < (strlen(word)); i++) { + current_game.hidden[i] = '_'; + } + current_game.incorrect = 0; + current_game.guesses_size = 0; + + return current_game; +} + +/** + * @brief checks if player has won or lost + * @param word the word player has attempted to guess + * @param score how many incorrect guesses player has made + * @returns void + */ +void won(const char word[], int score) { + if (score > 12) { + printf("\nYou lost! The word was: %s.\n", word); + } + else { + printf("\nYou won! You had %d guesses left.\n", (12 - score)); + } +} + +/* + * @brief gradually draws duck as player gets letters incorrect + * @param score how many incorrect guesses player has made + * @returns void + */ +void picture(int score) { + + switch(score) { + + case 12: + printf("\n _\n" + " __( ' )> \n" + " \\_ < _ ) "); + break; + + case 11: + printf("\n _\n" + " __( ' )\n" + " \\_ < _ ) "); + break; + + case 10: + printf("\n _\n" + " __( )\n" + " \\_ < _ ) "); + break; + + case 9: + printf("\n \n" + " __( )\n" + " \\_ < _ ) "); + break; + + case 8: + printf("\n \n" + " __( \n" + " \\_ < _ ) "); + break; + + case 7: + printf("\n \n" + " __ \n" + " \\_ < _ ) "); + break; + + case 6: + printf("\n \n" + " _ \n" + " \\_ < _ ) "); + break; + + case 5: + printf("\n \n" + " _ \n" + " _ < _ ) "); + break; + + case 4: + printf("\n \n" + " \n" + " _ < _ ) "); + break; + + case 3: + printf("\n \n" + " \n" + " < _ ) "); + break; + + case 2: + printf("\n \n" + " \n" + " _ ) "); + break; + + case 1: + printf("\n \n" + " \n" + " ) "); + break; + + case 0: + break; + + default: + printf("\n _\n" + " __( ' )> QUACK!\n" + " \\_ < _ ) "); + break; + } +} diff --git a/games/naval_battle.c b/games/naval_battle.c new file mode 100644 index 0000000000..ec7f540c6e --- /dev/null +++ b/games/naval_battle.c @@ -0,0 +1,946 @@ +/** + * @file + * @author [Carlos Rafael](https://github.com/CarlosZoft) + * @author [Herick Lima](https://github.com/hericklima22) + * @brief [naval_battle](https://en.wikipedia.org/wiki/Battleship_(game)) + * implementation in C using only the stdio.h for Standard Input and Output. + * @details Naval battle is a game, to be played by two people. It consists of + * knocking down the enemy ship, through shots , when hit the ship is + * revealed with the respective number of its size. Example: size 3 = 3 3 3 on + * the board. + * To play - boats over size 1, need direction; V -> vertical and H -> + * horizontal. Example Input 1 A H -> line 1, column A, direction H + * (Horizontal). + */ + +#include /// for Standard Input Output + +/** + * @brief Function validEntryLineColumn + * Responsible for validating entries, for positioning boats + * @param line matrix row + * @param column matrix column + * @returns if the row and column are valid + */ +int validEntryLineColumn(int line, char column) +{ + if ((line >= 1 && line <= 10) && (column >= 65 && column <= 74)) + { + return 1; + } + + return 0; +} +/** + * @brief Function validatePosition + * Responsible for checking if the position can receive the boat. + * @param mat board + * @param boat boat + * @param line matrix row + * @param column matrix column + * @returns if the position is valid + */ +int validatePosition(int mat[10][10], int boat, int line, int column, + char guide) +{ + int cont = 0; + int i, j; + + if (line < 0 || line > 9 || column < 0 || column > 9 || + (guide != 'H' && guide != 'V') || boat < 1 || boat > 3) + { + return 0; + } + + if (guide == 'H') + { + if ((10 - column) < boat) + { + return 0; + } + else + { + for (j = column; j < (column + boat); j++) + { + if (mat[line][j] == 0) + { + cont++; + } + } + } + } + + if (guide == 'V') + { + if ((10 - line) < boat) + { + return 0; + } + + else + { + for (i = line; i < (line + boat); i++) + { + if (mat[i][column] == 0) + { + cont++; + } + } + } + } + + if (cont == boat) + { + return 1; + } + return 0; +} +/** + * @brief Function canShoot + * Responsible to verify that it is a valid position to shoot + * @param mat board + * @param line matrix row + * @param column matrix column + * @returns if the position is valid for shooting + */ + +int canShoot(int mat[10][10], int line, int column) +{ + if (mat[line][column] == -2 || mat[line][column] == 10 || + mat[line][column] == 20 || mat[line][column] == 30 || + mat[line][column] == 50) + { + return 0; + } + + return 1; +} +/** + * @brief Function positionBoat + * Responsible for placing the boats on the board, according to the size. + * @param mat board + * @param boat boat + */ +void positionBoat(int mat[10][10], int boat) +{ + int line, j; + char column, guide; + + if (boat == 1) + { + scanf("%d %c", &line, &column); + + while (validEntryLineColumn(line, column) != 1 || + validatePosition(mat, boat, (line - 1), (column - 65), 'H') != 1) + { + printf("Position unavailable!\n"); + scanf("%d %c", &line, &column); + } + } + + else + { + scanf("%d %c %c", &line, &column, &guide); + + while (validEntryLineColumn(line, column) == 0 || + validatePosition(mat, boat, (line - 1), (column - 65), guide) == + 0) + { + printf("Position unavailable!\n"); + scanf("%d %c %c", &line, &column, &guide); + } + } + + int aux = column - 'A'; + line -= 1; + + if (boat == 1) + { + for (j = aux; j < (aux + boat); j++) + { + mat[line][j] = boat; + } + + for (int a = line - 1; a < (line + boat + 1); a++) + { + for (int b = aux - 1; b < (aux + boat + 1); b++) + { + if (a >= 0 && a <= 9 && b >= 0 && b <= 9) + { + if (mat[a][b] != boat) + { + mat[a][b] = -1; + } + } + } + } + } + + if (guide == 'H') + { + for (j = aux; j < (aux + boat); j++) + { + mat[line][j] = boat; + } + if (boat == 3) + { + for (int a = line - 1; a < (line + boat - 1); a++) + { + for (int b = aux - 1; b < (aux + boat + 1); b++) + { + if (a >= 0 && a <= 9 && b >= 0 && b <= 9) + { + if (mat[a][b] != boat) + { + mat[a][b] = -1; + } + } + } + } + } + + else + { + for (int a = line - 1; a < (line + boat); a++) + { + for (int b = aux - 1; b < (aux + boat + 1); b++) + { + if (a >= 0 && a <= 9 && b >= 0 && b <= 9) + { + if (mat[a][b] != boat) + { + mat[a][b] = -1; + } + } + } + } + } + } + + if (guide == 'V') + { + for (j = line; j < (line + boat); j++) + { + mat[j][aux] = boat; + } + if (boat == 3) + { + for (int a = line - 1; a < (line + boat + 1); a++) + { + for (int b = aux - 1; b < (aux + boat - 1); b++) + { + if (a >= 0 && a <= 9 && b >= 0 && b <= 9) + { + if (mat[a][b] != boat) + { + mat[a][b] = -1; + } + } + } + } + } + + else + { + for (int a = line - 1; a < (line + boat + 1); a++) + { + for (int b = aux - 1; b < (aux + boat); b++) + { + if (a >= 0 && a <= 9 && b >= 0 && b <= 9) + { + if (mat[a][b] != boat) + { + mat[a][b] = -1; + } + } + } + } + } + } +} +/** + * @brief Function printMessage + * Responsible for printing the auxiliary message + * @param msg msg with board + */ +void printMessage(char *msg) +{ + printf("************************\n"); + printf("*\n"); + printf("* %s\n", msg); + printf("*\n"); + printf("************************\n"); +} +/** + * @brief Function printMessageScore + * Responsible for printing the score messages + * @param pts1 player 1 score + * @param pts2 player 2 score + */ +void printMessageScore(int pts1, int pts2) +{ + printf("************************\n"); + printf("*\n"); + printf("* Player'S SCORE 1: %02d\n", pts1); + printf("* Player'S SCORE 2: %02d\n", pts2); + printf("*\n"); + printf("************************\n"); +} +/** + * @brief Function printTable + * Responsible for printing the board + * @param logic return of the logical matrix + * @param stage game step + * @returns char for visual matrix + */ +char printTable(int logic, int stage) +{ + if (stage == 0) + { + if (logic == 0) + { + return '.'; + } + + else if (logic == -1) + { + return '*'; + } + + else if (logic == 1) + { + return '1'; + } + + else if (logic == 2) + { + return '2'; + } + + else + { + return '3'; + } + } + + else + { + if (logic == 0 || logic == -1 || logic == 1 || logic == 2 || logic == 3) + { + return '.'; + } + + else if (logic == -2) + { + return 'x'; + } + + else if (logic == 10 || logic == 20 || logic == 30) + { + return 'N'; + } + + else + { + return 'A'; + } + } +} +/** + * @brief Function printsTray + * Responsible for printing the visual board for the user + * @param mat Matrix + * @param stage game step + */ +void printsTray(int mat[10][10], int stage) +{ + int logic; + char imp; + + printf(" "); + for (int i = 65; i < 75; i++) + { + printf("%c", i); + if (i < 74) + { + printf(" "); + } + } + printf("\n"); + + for (int i = 0; i < 12; i++) + { + if (i > 0 && i < 11) + { + printf("%02d ", i); + } + + else + { + printf(" "); + } + + for (int j = 0; j < 12; j++) + { + if ((i > 0 && i < 11) && (j > 0 && j < 11)) + { + logic = mat[i - 1][j - 1]; + imp = printTable(logic, stage); + printf("%c", imp); + } + else + { + printf("#"); + } + + if (j < 11) + { + printf(" "); + } + } + printf("\n"); + } +} +/** + * @brief Function shoot + * Responsible for saying if he hit a boat + * @param mat board + * @param line matrix row + * @param column matrix column + */ +void shoot(int mat[10][10], int line, int column) +{ + if (mat[line][column] == 0 || mat[line][column] == -1) + { + mat[line][column] = -2; + } + + else if (mat[line][column] == 1) + { + mat[line][column] = 10; + } + + else if (mat[line][column] == 2) + { + mat[line][column] = 20; + } + + else if (mat[line][column] == 3) + { + mat[line][column] = 30; + } +} +/** + * @brief Function calculateScore + * Responsible for calculating the score obtained during the game + * @param mat board + * @param line matrix row + * @param column matrix column + * @returns resulting score + */ + +int calculateScore(int mat[10][10], int line, int column) +{ + int c = 0, b = 0, e = 0, d = 0; + + if (mat[line][column] == 10) + { + mat[line][column] = 50; + return 2; + } + + else if (mat[line][column] == 20) + { + if (mat[line + 1][column] == 20) + { + b = 1; + } + + if (mat[line - 1][column] == 20) + { + c = 1; + } + + if (mat[line][column + 1] == 20) + { + d = 1; + } + + if (mat[line][column - 1] == 20) + { + e = 1; + } + + if (b == 1) + { + if (mat[line + 1][column] == 20) + { + mat[line][column] = 50; + mat[line + 1][column] = 50; + return 4; + } + else + { + return 0; + } + } + + if (c == 1) + { + if (mat[line - 1][column] == 20) + { + mat[line][column] = 50; + mat[line - 1][column] = 50; + return 4; + } + else + { + return 0; + } + } + + if (d == 1) + { + if (mat[line][column + 1] == 20) + { + mat[line][column] = 50; + mat[line][column + 1] = 50; + return 4; + } + else + { + return 0; + } + } + + if (e == 1) + { + if (mat[line][column - 1] == 20) + { + mat[line][column] = 50; + mat[line][column - 1] = 50; + return 4; + } + else + { + return 0; + } + } + } + + else if (mat[line][column] == 30) + { + if (mat[line + 1][column] == 30) + { + b = 1; + } + + if (mat[line - 1][column] == 30) + { + c = 1; + } + if (mat[line][column + 1] == 30) + { + d = 1; + } + + if (mat[line][column - 1] == 30) + { + e = 1; + } + + if (b == 1 && c == 1) + { + if (mat[line + 1][column] == 30 && mat[line - 1][column] == 30) + { + mat[line][column] = 50; + mat[line + 1][column] = 50; + mat[line - 1][column] = 50; + return 7; + } + else + { + return 0; + } + } + + else if (d == 1 && e == 1) + { + if (mat[line][column + 1] == 30 && mat[line][column - 1] == 30) + { + mat[line][column] = 50; + mat[line][column - 1] = 50; + mat[line][column + 1] = 50; + return 7; + } + else + { + return 0; + } + } + + else if (d == 1) + { + if (mat[line][column + 1] == 30 && mat[line][column + 2] == 30) + { + mat[line][column] = 50; + mat[line][column + 1] = 50; + mat[line][column + 2] = 50; + return 7; + } + else + { + return 0; + } + } + + else if (e == 1) + { + if (mat[line][column - 1] == 30 && mat[line][column - 2] == 30) + { + mat[line][column] = 50; + mat[line][column - 1] = 50; + mat[line][column - 2] = 50; + return 7; + } + else + { + return 0; + } + } + + else if (c == 1) + { + if (mat[line - 1][column] == 30 && mat[line - 2][column] == 30) + { + mat[line][column] = 50; + mat[line - 1][column] = 50; + mat[line - 2][column] = 50; + return 7; + } + else + { + return 0; + } + } + + else if (b == 1) + { + if (mat[line + 1][column] == 30 && mat[line + 2][column] == 30) + { + mat[line][column] = 50; + mat[line + 1][column] = 50; + mat[line + 2][column] = 50; + return 7; + } + else + { + return 0; + } + } + } + return 0; +} +/** + * @brief Function printPositioning + * Responsible for printing messages for positioning boats on the board; of + * player 1 and 2 + * @param Player number representing the Player + * @param boat number that represents the boat + * @param nm which message to print + */ +void printPositioning(int Player, int boat, int nm) +{ + if (Player == 1) + { + char msg1[60] = "Player 1 - Position the size boat 1 (1/6)"; + char msg2[60] = "Player 1 - Position the size boat 1 (2/6)"; + char msg3[60] = "Player 1 - Position the size boat 1 (3/6)"; + char msg4[60] = "Player 1 - Position the size boat 1 (4/6)"; + char msg5[60] = "Player 1 - Position the size boat 1 (5/6)"; + char msg6[60] = "Player 1 - Position the size boat 1 (6/6)"; + + char msg7[60] = "Player 1 - Position the size boat 2 (1/4)"; + char msg8[60] = "Player 1 - Position the size boat 2 (2/4)"; + char msg9[60] = "Player 1 - Position the size boat 2 (3/4)"; + char msg10[60] = "Player 1 - Position the size boat 2 (4/4)"; + + char msg11[60] = "Player 1 - Position the size boat 3 (1/2)"; + char msg12[60] = "Player 1 - Position the size boat 3 (2/2)"; + + if (boat == 1) + { + if (nm == 1) + { + printMessage(msg1); + } + else if (nm == 2) + { + printMessage(msg2); + } + else if (nm == 3) + { + printMessage(msg3); + } + + else if (nm == 4) + { + printMessage(msg4); + } + + else if (nm == 5) + { + printMessage(msg5); + } + + else if (nm == 6) + { + printMessage(msg6); + } + } + else if (boat == 2) + { + if (nm == 1) + { + printMessage(msg7); + } + else if (nm == 2) + { + printMessage(msg8); + } + else if (nm == 3) + { + printMessage(msg9); + } + else if (nm == 4) + { + printMessage(msg10); + } + } + else if (boat == 3) + { + if (nm == 1) + { + printMessage(msg11); + } + if (nm == 2) + { + printMessage(msg12); + } + } + } + + if (Player == 2) + { + char msg1[60] = "Player 2 - Position the size boat 1 (1/6)"; + char msg2[60] = "Player 2 - Position the size boat 1 (2/6)"; + char msg3[60] = "Player 2 - Position the size boat 1 (3/6)"; + char msg4[60] = "Player 2 - Position the size boat 1 (4/6)"; + char msg5[60] = "Player 2 - Position the size boat 1 (5/6)"; + char msg6[60] = "Player 2 - Position the size boat 1 (6/6)"; + + char msg7[60] = "Player 2 - Position the size boat 2 (1/4)"; + char msg8[60] = "Player 2 - Position the size boat 2 (2/4)"; + char msg9[60] = "Player 2 - Position the size boat 2 (3/4)"; + char msg10[60] = "Player 2 - Position the size boat 2 (4/4)"; + + char msg11[60] = "Player 2 - Position the size boat 3 (1/2)"; + char msg12[60] = "Player 2 - Position the size boat 3 (2/2)"; + + if (boat == 1) + { + if (nm == 1) + { + printMessage(msg1); + } + else if (nm == 2) + { + printMessage(msg2); + } + else if (nm == 3) + { + printMessage(msg3); + } + else if (nm == 4) + { + printMessage(msg4); + } + else if (nm == 5) + { + printMessage(msg5); + } + else if (nm == 6) + { + printMessage(msg6); + } + } + else if (boat == 2) + { + if (nm == 1) + { + printMessage(msg7); + } + else if (nm == 2) + { + printMessage(msg8); + } + else if (nm == 3) + { + printMessage(msg9); + } + else if (nm == 4) + { + printMessage(msg10); + } + } + else if (boat == 3) + { + if (nm == 1) + { + printMessage(msg11); + } + else if (nm == 2) + { + printMessage(msg12); + } + } + } +} +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + int Player1[10][10]; + int Player2[10][10]; + int plays = 1; + int pts1 = 0, pts2 = 0, a1 = 0, a2 = 0; + int line, col = 0, lin = 0; + char column; + + // filling matrix with 0 + for (int i = 0; i < 10; i++) + { + for (int j = 0; j < 10; j++) + { + Player1[i][j] = 0; + Player2[i][j] = 0; + } + } + + // positioning boats + for (int i = 1; i <= 2; i++) + { + for (int j = 1; j <= 6; j++) + { + if (i == 1) + { + printPositioning(i, 1, j); + printsTray(Player1, 0); + positionBoat(Player1, 1); + } + else if (i == 2) + { + printPositioning(i, 1, j); + printsTray(Player2, 0); + positionBoat(Player2, 1); + } + } + for (int j = 1; j <= 4; j++) + { + if (i == 1) + { + printPositioning(i, 2, j); + printsTray(Player1, 0); + positionBoat(Player1, 2); + } + else if (i == 2) + { + printPositioning(i, 2, j); + printsTray(Player2, 0); + positionBoat(Player2, 2); + } + } + for (int j = 1; j <= 2; j++) + { + if (i == 1) + { + printPositioning(i, 3, j); + printsTray(Player1, 0); + positionBoat(Player1, 3); + } + else if (i == 2) + { + printPositioning(i, 3, j); + printsTray(Player2, 0); + positionBoat(Player2, 3); + } + } + } + + // starting the game + while (plays <= 40) + { + if (plays % 2 != 0) + { + printMessageScore(pts1, pts2); + printMessage("Player 1's turn"); + printsTray(Player2, 1); + scanf("%d %c", &line, &column); + + while (validEntryLineColumn(line, column) != 1 || + canShoot(Player2, line - 1, column - 65) != 1) + { + line = 0; + column = 'a'; + printf("Position unavailable!\n"); + scanf("%d %c", &line, &column); + } + lin = line - 1; + col = column - 65; + shoot(Player2, lin, col); + a1 = pts1; + pts1 += calculateScore(Player2, lin, col); + + if (a1 != pts1) + { + printMessage("Player 1 DROPPED A BOAT!"); + } + } + else + { + printMessageScore(pts1, pts2); + printMessage("Player 2's turn"); + printsTray(Player1, 1); + scanf("%d %c", &line, &column); + + while (validEntryLineColumn(line, column) != 1 || + canShoot(Player1, line - 1, column - 65) != 1) + { + printf("Position unavailable!\n"); + scanf("%d %c", &line, &column); + } + lin = line - 1; + col = column - 65; + shoot(Player1, lin, col); + a2 = pts2; + pts2 += calculateScore(Player1, lin, col); + + if (a2 != pts2) + { + printMessage("Player 2 DROPPED A BOAT!"); + } + } + + plays++; + } + /** + * the one with the most points wins, or the one who knocks down all boats + * first. + */ + printMessage("END GAME\n"); + printMessageScore(pts1, pts2); + + return 0; +} diff --git a/games/tic_tac_toe.c b/games/tic_tac_toe.c new file mode 100644 index 0000000000..fbaf0e22be --- /dev/null +++ b/games/tic_tac_toe.c @@ -0,0 +1,449 @@ +/** + * @file tic-tac-toe.c + * @author [vivekboss99](github.com/vivekboss99) + * @author [Krishna Vedala](https://github.com/kvedala) + * @brief [Tic-Tac-Toe game](https://en.wikipedia.org/wiki/Tic-tac-toe) + * implementation in C + * @details Tic-Tac-Toe Game, where the user can decide to play with the + * computer(single player mode) or with other user(double player mode), the + * code as an array named 'game_table' which is the table and user needs to enter the + * position inside the array(from 1-9) where he/she wants to place 'X' or 'O' on the + * table. + */ +#include +#include +#include +#include + +// Functions Declarations +static void singlemode(); +static void doublemode(); +static void placex(int); // used for placing position of X by the 1st player +static void place(); // used by the computer to place O +static void placey(int); // used in Double Player mode by the 2nd player to + // place the position of O +int checkwin(); // checks everytime when a player or computer places 'X' or 'O' + +/** Tic-Tac-Toe table, so basically we are using variable 'game_table' as the table(size:3X3) and + * updating it regularly + */ +static char game_table[9]; + +/** + * Main program function. + * @returns 0 on clean exit. + * @note No checks are included for program execution failures! + */ +int main() +{ + srand( (unsigned int)time(NULL)); + int l = 0; + do + { + int n = 0; + + // filling the table with multiple asterisks + for (int i = 0; i < 9; i++) game_table[i] = '*'; + + // displaying the main menu + printf("***************************************\n"); + printf("*************TIC TAC TOE***************\n"); + printf("***************************************\n"); + printf("***********1. YOU vs COMPUTER ***********\n"); + printf("***********2. YOU vs PLAYER ***********\n"); + printf("***********3.EXIT *********************\n"); + printf("Enter your choice : "); + scanf("%d", &n); + + switch (n) // switch case to select between single player mode or + // double player mode + { + case 1: + singlemode(); + break; + case 2: + doublemode(); + break; + default: + printf("THANK YOU and EXIT!"); + } + + printf("Next game ? : "); + printf("Enter 1 – YES and 0 - NO "); + scanf("%d", &l); + + } while (l == 1); + + return 0; +} + +/** + * @brief Implementation of game vs computer + * + * @returns None + */ +void singlemode() +{ + int m; + int k = 0; + int table_fill_count=0; + + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + printf("%c ", game_table[k]); + k++; + } + + printf("\n"); + } + + for (int x = 1; x < 10; x++) + { + k = 0; + + printf("Where would you like to place 'x' "); + scanf("%d", &m); + + placex(m); + if(table_fill_count<4) + { + place(); + } + + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + printf("%c ", game_table[k]); + k++; + + } + + printf("\n"); + } + table_fill_count++; + int o = checkwin(); + + if (o == -1 || o == -2) + { + if (o == -1) + { + printf("YOU WIN\n"); + } + if (o == -2) + { + printf("YOU LOSE\n"); + } + + break; + } + + if (table_fill_count==4) + { + printf("\nDRAW "); + break; + } + } +} + +/** + * @brief Implementation of game vs another player. + * + * @returns None + */ +void doublemode() +{ + int m; + int e1; + int k = 0; + int doublemode_table_count=0; + + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + printf("%c ", game_table[k]); + k++; + } + + printf("\n"); + } + for (int x = 1; x < 10; x++) + { + k = 0; + + printf("PLAYER1 - where would you like to place 'x' : "); + scanf("%d", &m); + + placex(m); + if(doublemode_table_count<4) + { + printf("PLAYER2 - where would you like to place 'o' : "); + scanf("%d", &e1); + + placey(e1); + } + + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + printf("%c ", game_table[k]); + k++; + } + + printf("\n"); + } + doublemode_table_count++; + int o = checkwin(); + + if (o == -1 || o == -2) + { + if (o == -1) + { + printf("Player 1 WIN\n"); + } + if (o == -2) + { + printf("Player 2 WIN\n"); + } + + break; + } + if (doublemode_table_count==4) + { + printf("\nDRAW "); + break; + } + } +} + +int check_placex(){ + char input[50]; + int n1; + while (1){ + fgets(input,49,stdin); + if ( strlen(input) > 2 || strlen(input) == 0){ + fprintf(stderr,"Invalid move, Enter number 1 - 9: "); + continue; + } + if(sscanf(input,"%d",&n1) != 1){ + fprintf(stderr,"Invalid move, Enter number 1 - 9: "); + continue; + } + if ((game_table[n1-1] == 'x') || (game_table[n1-1]) == 'o' || (n1== 0)){ + fprintf(stderr,"Already allocated, Enter number: "); + continue; + } + return n1; + } +} + + + + + +/** + * @brief Update table by placing an `X` + * + * @param m location to place `X` + * + * @returns None + */ +void placex(int m) +{ + int n1 = 0; + if (m >= 1 && m <= 9) + { + if (game_table[m - 1] != 'x' && game_table[m - 1] != 'o') + { + game_table[m - 1] = 'x'; + } + else + { + int n = check_placex(); + placex(n); + } + } + else + { + int n = check_placex(); + placex(n); + } +} +/** + * @brief Update table by placing an `O` + * + * @returns None + */ +void place() +{ + + int e = rand() % 9; + + if (e >= 0) + { + if (game_table[e] != 'x' && game_table[e] != 'o') + { + game_table[e] = 'o'; + printf("\n Computer placed at %d position\n", e + 1); + } + else + { + place(); + } + } +} +/** + * @brief Update table by placing an `O` + * + * @param e1 location to place `O` + * + * @returns None + */ +void placey(int e1) +{ + int n1 = 0; + if (e1 >= 1 && e1 <= 9) + { + if (game_table[e1 - 1] != 'x' && game_table[e1 - 1] != 'o') + { + game_table[e1 - 1] = 'o'; + } + else + { + int n = check_placex(); + placex(n); + } + } + else + { + int n = check_placex(); + placex(n); + } +} +/** + * @brief Implementation of win conditon checker for 'X' or 'O' whenever the table is updated + * + * @returns -1: if 'X' won + * @returns -2: if 'O' won + * @returns 0: if there is no win condition for 'X' or 'O' + */ +int checkwin() +{ + if (game_table[0] == game_table[1] && game_table[1] == game_table[2]) + { + if (game_table[0] == 'x' && game_table[1] == 'x' && + game_table[2] == 'x') + { + return -1; + } + + if (game_table[0] == 'o' && game_table[1] == 'o' && + game_table[2] == 'o') + { + return -2; + } + } + else if (game_table[0] == game_table[4] && game_table[4] == game_table[8]) + { + if (game_table[0] == 'x' && game_table[4] == 'x' && + game_table[8] == 'x') + { + return -1; + } + + if (game_table[0] == 'o' && game_table[4] == 'o' && + game_table[8] == 'o') + { + return -2; + } + } + else if (game_table[0] == game_table[3] && game_table[3] == game_table[6]) + { + if (game_table[0] == 'x' && game_table[3] == 'x' && + game_table[6] == 'x') + { + return -1; + } + + if (game_table[0] == 'o' && game_table[3] == 'o' && + game_table[6] == 'o') + { + return -2; + } + } + else if (game_table[3] == game_table[4] && game_table[4] == game_table[5]) + { + if (game_table[3] == 'x' && game_table[4] == 'x' && + game_table[5] == 'x') + { + return -1; + } + + if (game_table[3] == 'o' && game_table[4] == 'o' && + game_table[5] == 'o') + { + return -2; + } + } + else if (game_table[6] == game_table[7] && game_table[7] == game_table[8]) + { + if (game_table[6] == 'x' && game_table[7] == 'x' && + game_table[8] == 'x') + { + return -1; + } + + if (game_table[6] == 'o' && game_table[7] == 'o' && + game_table[8] == 'o') + { + return -2; + } + } + else if (game_table[1] == game_table[4] && game_table[4] == game_table[7]) + { + if (game_table[1] == 'x' && game_table[4] == 'x' && + game_table[7] == 'x') + { + return -1; + } + + if (game_table[1] == 'o' && game_table[4] == 'o' && + game_table[7] == 'o') + { + return -2; + } + } + else if (game_table[2] == game_table[5] && game_table[5] == game_table[8]) + { + if (game_table[2] == 'x' && game_table[5] == 'x' && + game_table[8] == 'x') + { + return -1; + } + + if (game_table[2] == 'o' && game_table[5] == 'o' && + game_table[8] == 'o') + { + return -2; + } + } + else if (game_table[2] == game_table[4] && game_table[4] == game_table[6]) + { + if (game_table[2] == 'x' && game_table[4] == 'x' && + game_table[6] == 'x') + { + return -1; + } + + if (game_table[2] == 'o' && game_table[4] == 'o' && + game_table[6] == 'o') + { + return -2; + } + } + return 0; +} diff --git a/games/words.txt b/games/words.txt new file mode 100644 index 0000000000..0db94bf699 --- /dev/null +++ b/games/words.txt @@ -0,0 +1,8 @@ +dog +cat +tree +flower +table +programming +language +testing \ No newline at end of file diff --git a/geometry/CMakeLists.txt b/geometry/CMakeLists.txt new file mode 100644 index 0000000000..85d22445c0 --- /dev/null +++ b/geometry/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} *.c) +# 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 ".c" "" testname ${testsourcefile} ) + add_executable( ${testname} ${testsourcefile} ) + + if(OpenMP_C_FOUND) + target_link_libraries(${testname} OpenMP::OpenMP_C) + endif() + if(MATH_LIBRARY) + target_link_libraries(${testname} ${MATH_LIBRARY}) + endif() + install(TARGETS ${testname} DESTINATION "bin/geometry") + +endforeach( testsourcefile ${APP_SOURCES} ) diff --git a/geometry/geometry_datatypes.h b/geometry/geometry_datatypes.h new file mode 100644 index 0000000000..a92388453b --- /dev/null +++ b/geometry/geometry_datatypes.h @@ -0,0 +1,115 @@ +/** + * @addtogroup quaternions Library for 3D Vectors & Quaternions + * @{ + * @file + * @brief Generic header that provides data types for 3D vectors and quaternions + * @author Krishna Vedala + */ + +#ifndef __LIBQUAT_H_ +#define __LIBQUAT_H_ + +/** Minimum recognizable value. Any value less than this is considered to be + * @f$=0@f$ */ +#define EPSILON 1e-9 + +/** + * @addtogroup vec_3d 3D Vector operations + * @{ + */ +/** 3D vector type */ +typedef struct vec_3d_ +{ + float x; /**< X co-ordinate */ + float y; /**< Y co-ordinate */ + float z; /**< Z co-ordinate */ +} vec_3d; +/** @} */ + +/** + * @addtogroup matrix Matrix operations + * @{ + */ +/** A 3x3 Matrix type definition */ +typedef struct mat_3x3_ +{ + union + { /**< 3 element row 1 */ + float row1[3]; + vec_3d vec1; + }; + union + { /**< 3 element row 2 */ + float row2[3]; + vec_3d vec2; + }; + union + { /**< 3 element row 3 */ + float row3[3]; + vec_3d vec3; + }; +} mat_3x3; +/** @} */ + +/** @addtogroup quats 3D Quaternion operations + * @{ + */ +/** a Quaternion type represented using a scalar \f$w\f$ or \f$q_0\f$ and a + * 3D vector \f$\left(q_1,q_2,q_3\right)\f$ + */ +typedef struct quaternion_ +{ + union + { + float w; /**< real part of quaternion */ + float q0; /**< real part of quaternion */ + }; + /**< dual part of quaternion */ + union + { + vec_3d dual; /**< can be a 3D vector */ + /** or individual values */ + struct + { + float q1, q2, q3; + }; + }; +} quaternion; + +/** 3D Euler or Tait-Bryan angles (in radian) */ +typedef struct euler_ +{ + union + { + float roll; /**< or bank \f$\phi\f$ = rotation about X axis */ + float bank; /**< or roll \f$\phi\f$ = rotation about X axis */ + }; + union + { + float pitch; /**< or elevation \f$\theta\f$ = rotation about Y axis */ + float elevation; /**< or pitch \f$\theta\f$ = rotation about Y axis */ + }; + union + { + float yaw; /**< or heading \f$\psi\f$ = rotation about Z axis */ + float heading; /**< or yaw \f$\psi\f$ = rotation about Z axis */ + }; +} euler; + +/** @} */ + +/** @addtogroup dual_quats 3D Dual-Quaternion operations + * @{ + */ +/** a dual quaternion type */ +typedef struct dual_quat_ +{ + quaternion real; /**< real part of dual quaternion */ + quaternion dual; /**< dual part of dual quaternion */ +} dual_quat; + +/** @} */ + +#endif // __LIBQUAT_H_ + +/** @} */ diff --git a/geometry/quaternions.c b/geometry/quaternions.c new file mode 100644 index 0000000000..2e95923acf --- /dev/null +++ b/geometry/quaternions.c @@ -0,0 +1,173 @@ +/** + * @file + * @brief Functions related to 3D quaternions and Euler angles. + * @author Krishna Vedala + */ + +#include +#ifdef __arm__ // if compiling for ARM-Cortex processors +#define LIBQUAT_ARM +#include +#else +#include +#endif +#include + +#include "geometry_datatypes.h" + +/** + * @addtogroup quats 3D Quaternion operations + * @{ + */ + +/** + * Function to convert given Euler angles to a quaternion. + * \f{eqnarray*}{ + * q_{0} & = + * &\cos\left(\frac{\phi}{2}\right)\cos\left(\frac{\theta}{2}\right)\cos\left(\frac{\psi}{2}\right) + * + + * \sin\left(\frac{\phi}{2}\right)\sin\left(\frac{\theta}{2}\right)\sin\left(\frac{\psi}{2}\right)\\ + * q_{1} & = + * &\sin\left(\frac{\phi}{2}\right)\cos\left(\frac{\theta}{2}\right)\cos\left(\frac{\psi}{2}\right) + * - + * \cos\left(\frac{\phi}{2}\right)\sin\left(\frac{\theta}{2}\right)\sin\left(\frac{\psi}{2}\right)\\ + * q_{2} & = + * &\cos\left(\frac{\phi}{2}\right)\sin\left(\frac{\theta}{2}\right)\cos\left(\frac{\psi}{2}\right) + * + + * \sin\left(\frac{\phi}{2}\right)\cos\left(\frac{\theta}{2}\right)\sin\left(\frac{\psi}{2}\right)\\ + * q_{3} & = + * &\cos\left(\frac{\phi}{2}\right)\cos\left(\frac{\theta}{2}\right)\sin\left(\frac{\psi}{2}\right) + * - + * \sin\left(\frac{\phi}{2}\right)\sin\left(\frac{\theta}{2}\right)\cos\left(\frac{\psi}{2}\right)\\ + * \f} + * + * @param [in] in_euler input Euler angles instance + * @returns converted quaternion + */ +quaternion quat_from_euler(const euler *in_euler) +{ + quaternion out_quat; + + if (!in_euler) // if null + { + fprintf(stderr, "%s: Invalid input.", __func__); + return out_quat; + } + + quaternion temp; + + float cy = cosf(in_euler->yaw * 0.5f); + float sy = sinf(in_euler->yaw * 0.5f); + float cp = cosf(in_euler->pitch * 0.5f); + float sp = sinf(in_euler->pitch * 0.5f); + float cr = cosf(in_euler->roll * 0.5f); + float sr = sinf(in_euler->roll * 0.5f); + + temp.w = cr * cp * cy + sr * sp * sy; + temp.q1 = sr * cp * cy - cr * sp * sy; + temp.q2 = cr * sp * cy + sr * cp * sy; + temp.q3 = cr * cp * sy - sr * sp * cy; + + return temp; +} + +/** + * Function to convert given quaternion to Euler angles. + * \f{eqnarray*}{ + * \phi & = & + * \tan^{-1}\left[\frac{2\left(q_0q_1+q_2q_3\right)}{1-2\left(q_1^2+q_2^2\right)}\right]\\ + * \theta & = + * &-\sin^{-1}\left[2\left(q_0q_2-q_3q_1\right)\right]\\ + * \psi & = & + * \tan^{-1}\left[\frac{2\left(q_0q_3+q_1q_2\right)}{1-2\left(q_2^2+q_3^2\right)}\right]\\ + * \f} + * + * @param [in] in_quat input quaternion instance + * @returns converted euler angles + */ +euler euler_from_quat(const quaternion *in_quat) +{ + euler out_euler; + if (!in_quat) // if null + { + fprintf(stderr, "%s: Invalid input.", __func__); + return out_euler; + } + + out_euler.roll = atan2f( + 2.f * (in_quat->w * in_quat->q1 + in_quat->q2 * in_quat->q3), + 1.f - 2.f * (in_quat->q1 * in_quat->q1 + in_quat->q2 * in_quat->q2)); + out_euler.pitch = + asinf(2.f * (in_quat->w * in_quat->q2 + in_quat->q1 * in_quat->q3)); + out_euler.yaw = atan2f( + 2.f * (in_quat->w * in_quat->q3 + in_quat->q1 * in_quat->q2), + 1.f - 2.f * (in_quat->q2 * in_quat->q2 + in_quat->q3 * in_quat->q3)); + + return out_euler; +} + +/** + * Function to multiply two quaternions. + * \f{eqnarray*}{ + * \mathbf{c} & = & \mathbf{a}\otimes\mathbf{b}\\ + * & = & \begin{bmatrix}a_{0} & a_{1} & a_{2} & + * a_{3}\end{bmatrix}\otimes\begin{bmatrix}b_{0} & b_{1} & b_{2} & + * b_{3}\end{bmatrix}\\ + * & = & + * \begin{bmatrix} + * a_{0}b_{0}-a_{1}b_{1}-a_{2}b_{2}-a_{3}b_{3}\\ + * a_{0}b_{1}+a_{1}b_{0}+a_{2}b_{3}-a_{3}b_{2}\\ + * a_{0}b_{2}-a_{1}b_{3}+a_{2}b_{0}+a_{3}b_{1}\\ + * a_{0}b_{3}+a_{1}b_{2}-a_{2}b_{1}+a_{3}b_{0} + * \end{bmatrix}^{T} + * \f} + * + * @param [in] in_quat1 first input quaternion instance + * @param [in] in_quat2 second input quaternion instance + * @returns resultant quaternion + */ +quaternion quaternion_multiply(const quaternion *in_quat1, + const quaternion *in_quat2) +{ + quaternion out_quat; + if (!in_quat1 || !in_quat2) // if null + { + fprintf(stderr, "%s: Invalid input.", __func__); + return out_quat; + } + + out_quat.w = in_quat1->w * in_quat2->w - in_quat1->q1 * in_quat2->q1 - + in_quat1->q2 * in_quat2->q2 - in_quat1->q3 * in_quat2->q3; + out_quat.q1 = in_quat1->w * in_quat2->q1 + in_quat1->q1 * in_quat2->w + + in_quat1->q2 * in_quat2->q3 - in_quat1->q3 * in_quat2->q2; + out_quat.q2 = in_quat1->w * in_quat2->q2 - in_quat1->q1 * in_quat2->q3 + + in_quat1->q2 * in_quat2->w + in_quat1->q3 * in_quat2->q1; + out_quat.q3 = in_quat1->w * in_quat2->q3 + in_quat1->q1 * in_quat2->q2 - + in_quat1->q2 * in_quat2->q1 + in_quat1->q3 * in_quat2->w; + + return out_quat; +} + +/** @} */ + +static void test() +{ + quaternion quat = {0.7071f, 0.7071f, 0.f, 0.f}; + euler eul = euler_from_quat(&quat); + printf("Euler: %.4g, %.4g, %.4g\n", eul.pitch, eul.roll, eul.yaw); + + quaternion test_quat = quat_from_euler(&eul); + printf("Quaternion: %.4g %+.4g %+.4g %+.4g\n", test_quat.w, + test_quat.dual.x, test_quat.dual.y, test_quat.dual.z); + + assert(fabsf(test_quat.w - quat.w) < .01); + assert(fabsf(test_quat.q1 - quat.q1) < .01); + assert(fabsf(test_quat.q2 - quat.q2) < .01); + assert(fabsf(test_quat.q3 - quat.q3) < .01); +} + +int main() +{ + test(); + return 0; +} diff --git a/geometry/vectors_3d.c b/geometry/vectors_3d.c new file mode 100644 index 0000000000..90ea1f009b --- /dev/null +++ b/geometry/vectors_3d.c @@ -0,0 +1,265 @@ +/** + * @file + * @brief Functions related to 3D vector operations. + * @author Krishna Vedala + */ + +#include +#ifdef __arm__ // if compiling for ARM-Cortex processors +#define LIBQUAT_ARM +#include +#else +#include +#endif +#include + +#include "geometry_datatypes.h" + +/** + * @addtogroup vec_3d 3D Vector operations + * @{ + */ + +/** + * Subtract one vector from another. @f[ + * \vec{c}=\vec{a}-\vec{b}=\left(a_x-b_x\right)\hat{i}+ + * \left(a_y-b_y\right)\hat{j}+\left(a_z-b_z\right)\hat{k}@f] + * @param[in] a vector to subtract from + * @param[in] b vector to subtract + * @returns resultant vector + */ +vec_3d vector_sub(const vec_3d *a, const vec_3d *b) +{ + vec_3d out; +#ifdef LIBQUAT_ARM + arm_sub_f32((float *)a, (float *)b, (float *)&out); +#else + out.x = a->x - b->x; + out.y = a->y - b->y; + out.z = a->z - b->z; +#endif + + return out; +} + +/** + * Add one vector to another. @f[ + * \vec{c}=\vec{a}+\vec{b}=\left(a_x+b_x\right)\hat{i}+ + * \left(a_y+b_y\right)\hat{j}+\left(a_z+b_z\right)\hat{k}@f] + * @param[in] a vector to add to + * @param[in] b vector to add + * @returns resultant vector + */ +vec_3d vector_add(const vec_3d *a, const vec_3d *b) +{ + vec_3d out; +#ifdef LIBQUAT_ARM + arm_add_f32((float *)a, (float *)b, (float *)&out); +#else + out.x = a->x + b->x; + out.y = a->y + b->y; + out.z = a->z + b->z; +#endif + + return out; +} + +/** + * Obtain the dot product of two 3D vectors. + * @f[ + * \vec{a}\cdot\vec{b}=a_xb_x + a_yb_y + a_zb_z + * @f] + * @param[in] a first vector + * @param[in] b second vector + * @returns resulting dot product + */ +float dot_prod(const vec_3d *a, const vec_3d *b) +{ + float dot; +#ifdef LIBQUAT_ARM + arm_dot_prod_f32((float *)a, (float *)b, &dot); +#else + dot = a->x * b->x; + dot += a->y * b->y; + dot += a->z * b->z; +#endif + + return dot; +} + +/** + * Compute the vector product of two 3d vectors. + * @f[\begin{align*} + * \vec{a}\times\vec{b} &= \begin{vmatrix} + * \hat{i} & \hat{j} & \hat{k}\\ + * a_x & a_y & a_z\\ + * b_x & b_y & b_z + * \end{vmatrix}\\ + * &= \left(a_yb_z-b_ya_z\right)\hat{i} - \left(a_xb_z-b_xa_z\right)\hat{j} + * + \left(a_xb_y-b_xa_y\right)\hat{k} \end{align*} + * @f] + * @param[in] a first vector @f$\vec{a}@f$ + * @param[in] b second vector @f$\vec{b}@f$ + * @returns resultant vector @f$\vec{o}=\vec{a}\times\vec{b}@f$ + */ +vec_3d vector_prod(const vec_3d *a, const vec_3d *b) +{ + vec_3d out; // better this way to avoid copying results to input + // vectors themselves + out.x = a->y * b->z - a->z * b->y; + out.y = -a->x * b->z + a->z * b->x; + out.z = a->x * b->y - a->y * b->x; + + return out; +} + +/** + * Print formatted vector on stdout. + * @param[in] a vector to print + * @param[in] name name of the vector + * @returns string representation of vector + */ +const char *print_vector(const vec_3d *a, const char *name) +{ + static char vec_str[100]; // static to ensure the string life extends the + // life of function + + snprintf(vec_str, 99, "vec(%s) = (%.3g)i + (%.3g)j + (%.3g)k\n", name, a->x, + a->y, a->z); + return vec_str; +} + +/** + * Compute the norm a vector. + * @f[\lVert\vec{a}\rVert = \sqrt{\vec{a}\cdot\vec{a}} @f] + * @param[in] a input vector + * @returns norm of the given vector + */ +float vector_norm(const vec_3d *a) +{ + float n = dot_prod(a, a); +#ifdef LIBQUAT_ARM + arm_sqrt_f32(*n, n); +#else + n = sqrtf(n); +#endif + + return n; +} + +/** + * Obtain unit vector in the same direction as given vector. + * @f[\hat{a}=\frac{\vec{a}}{\lVert\vec{a}\rVert}@f] + * @param[in] a input vector + * @returns n unit vector in the direction of @f$\vec{a}@f$ + */ +vec_3d unit_vec(const vec_3d *a) +{ + vec_3d n = {0}; + + float norm = vector_norm(a); + if (fabsf(norm) < EPSILON) + { // detect possible divide by 0 + return n; + } + + if (norm != 1.F) // perform division only if needed + { + n.x = a->x / norm; + n.y = a->y / norm; + n.z = a->z / norm; + } + return n; +} + +/** + * The cross product of vectors can be represented as a matrix + * multiplication operation. This function obtains the `3x3` matrix + * of the cross-product operator from the first vector. + * @f[\begin{align*} + * \left(\vec{a}\times\right)\vec{b} &= \tilde{A}_a\vec{b}\\ + * \tilde{A}_a &= + * \begin{bmatrix}0&-a_z&a_y\\a_z&0&-a_x\\-a_y&a_x&0\end{bmatrix} + * \end{align*}@f] + * @param[in] a input vector + * @returns the `3x3` matrix for the cross product operator + * @f$\left(\vec{a}\times\right)@f$ + */ +mat_3x3 get_cross_matrix(const vec_3d *a) +{ + mat_3x3 A = {0., -a->z, a->y, a->z, 0., -a->x, -a->y, a->x, 0.}; + return A; +} + +/** + * Obtain the angle between two given vectors. + * @f[\alpha=acos\left(\frac{\vec{a} \cdot \vec{b}}{\lVert\vec{a}\rVert \cdot \lVert\vec{b}\rVert}\right)@f] + * @param[in] a first input vector + * @param[in] b second input vector + * @returns angle between @f$\vec{a}@f$ and @f$\vec{b}@f$ in radians + */ + +double get_angle(const vec_3d *a, const vec_3d *b) +{ + double alpha, cos_alpha; + float norm_a = vector_norm(a); ///< The norm of vector a + float norm_b = vector_norm(b); ///< The norm of vector b + if (fabsf(norm_a) < EPSILON || fabsf(norm_b) < EPSILON) /// detect possible division by 0 - the angle is not defined in this case + { + return NAN; + } + + cos_alpha = dot_prod(a, b) / (norm_a * norm_b); + alpha = acos(cos_alpha); // delivers the radian + return alpha; // in range from -1 to 1 +} + +/** @} */ + +/** + * @brief Testing function + * @returns `void` + */ +static void test() +{ + vec_3d a = {1., 2., 3.}; + vec_3d b = {1., 1., 1.}; + float d; + + // printf("%s", print_vector(&a, "a")); + // printf("%s", print_vector(&b, "b")); + + d = vector_norm(&a); + // printf("|a| = %.4g\n", d); + assert(fabsf(d - 3.742f) < 0.01); + d = vector_norm(&b); + // printf("|b| = %.4g\n", d); + assert(fabsf(d - 1.732f) < 0.01); + + d = dot_prod(&a, &b); + // printf("Dot product: %f\n", d); + assert(fabsf(d - 6.f) < 0.01); + + vec_3d c = vector_prod(&a, &b); + // printf("Vector product "); + // printf("%s", print_vector(&c, "c")); + assert(fabsf(c.x - (-1.f)) < 0.01); + assert(fabsf(c.y - (2.f)) < 0.01); + assert(fabsf(c.z - (-1.f)) < 0.01); + + double alpha = get_angle(&a, &b); + // printf("The angle is %f\n", alpha); + assert(fabsf(alpha - 0.387597) < 0.01); +} + +/** + * @brief Main function + * + * @return 0 on exit + */ +int main(void) +{ + test(); + + return 0; +} diff --git a/graphics/CMakeLists.txt b/graphics/CMakeLists.txt new file mode 100644 index 0000000000..89fc65659b --- /dev/null +++ b/graphics/CMakeLists.txt @@ -0,0 +1,88 @@ +find_package(OpenGL) +if(OpenGL_FOUND) + find_package(GLUT) + if(NOT GLUT_FOUND) + message("FreeGLUT library will be downloaded and built.") + include(ExternalProject) + ExternalProject_Add ( + FREEGLUT-PRJ + URL https://github.com/FreeGLUTProject/freeglut/releases/download/v3.2.1/freeglut-3.2.1.tar.gz + URL_MD5 cd5c670c1086358598a6d4a9d166949d + CMAKE_GENERATOR ${CMAKE_GENERATOR} + CMAKE_GENERATOR_TOOLSET ${CMAKE_GENERATOR_TOOLSET} + CMAKE_GENERATOR_PLATFORM ${CMAKE_GENERATOR_PLATFORM} + CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release + -DFREEGLUT_BUILD_SHARED_LIBS=OFF + -DFREEGLUT_BUILD_STATIC_LIBS=ON + -DFREEGLUT_BUILD_DEMOS=OFF + PREFIX ${CMAKE_CURRENT_BINARY_DIR}/freeglut + # BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/freeglut-build + # BUILD_IN_SOURCE ON + # UPDATE_COMMAND "" + INSTALL_COMMAND "" + # CONFIGURE_COMMAND "" + # BUILD_COMMAND "" + ) + ExternalProject_Get_Property(FREEGLUT-PRJ SOURCE_DIR) + ExternalProject_Get_Property(FREEGLUT-PRJ BINARY_DIR) + set(FREEGLUT_BIN_DIR ${BINARY_DIR}) + set(FREEGLUT_SRC_DIR ${SOURCE_DIR}) + # add_library(libfreeglut STATIC IMPORTED) + # set_target_properties(libfreeglut PROPERTIES IMPORTED_LOCATION ${FREEGLUT_BIN_DIR}) + + # set(FREEGLUT_BUILD_DEMOS OFF CACHE BOOL "") + # set(FREEGLUT_BUILD_SHARED_LIBS OFF CACHE BOOL "") + # set(FREEGLUT_BUILD_STATIC_LIBS ON CACHE BOOL "") + # add_subdirectory(${FREEGLUT_SRC_DIR} ${FREEGLUT_BIN_DIR} EXCLUDE_FROM_ALL) + # add_subdirectory(${BINARY_DIR}) + # find_package(FreeGLUT) + endif(NOT GLUT_FOUND) +else(OpenGL_FOUND) + message(WARNING "OPENGL not found. Will not build graphical outputs.") +endif(OpenGL_FOUND) + +# 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} *.c ) +# 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 ".c" "" testname ${testsourcefile} ) + add_executable( ${testname} ${testsourcefile} ) + + # set_target_properties(${testname} PROPERTIES LINKER_LANGUAGE C) + + if(OpenMP_C_FOUND) + target_link_libraries(${testname} PRIVATE OpenMP::OpenMP_C) + endif() + + if(MATH_LIBRARY) + target_link_libraries(${testname} PRIVATE ${MATH_LIBRARY}) + endif() + + if(OpenGL_FOUND) + if(NOT GLUT_FOUND) + add_dependencies(${testname} FREEGLUT-PRJ) + target_compile_definitions(${testname} PRIVATE FREEGLUT_STATIC) + target_include_directories(${testname} PRIVATE ${FREEGLUT_SRC_DIR}/include) + target_link_directories(${testname} PRIVATE ${FREEGLUT_BIN_DIR}/lib) + target_link_libraries(${testname} PRIVATE OpenGL::GL) + target_link_libraries(${testname} INTERFACE FREEGLUT-PRJ) + # target_include_directories(${testname} PRIVATE ${FREEGLUT_INCLUDE_DIRS}) + # target_link_libraries(${testname} INTERFACE freeglut_static) + else() + target_include_directories(${testname} PRIVATE ${GLUT_INCLUDE_DIRS}) + target_link_libraries(${testname} PRIVATE OpenGL::GL ${GLUT_LIBRARIES}) + endif() + target_compile_definitions(${testname} PRIVATE USE_GLUT) + endif(OpenGL_FOUND) + + if(APPLE) + target_compile_options(${testname} PRIVATE -Wno-deprecated) + endif(APPLE) + + install(TARGETS ${testname} DESTINATION "bin/graphics") + +endforeach( testsourcefile ${APP_SOURCES} ) diff --git a/graphics/spirograph.c b/graphics/spirograph.c new file mode 100644 index 0000000000..2615bf7d5b --- /dev/null +++ b/graphics/spirograph.c @@ -0,0 +1,288 @@ +/** + * @file + * @author [Krishna Vedala](https://github.com/kvedala) + * @brief Implementation of + * [Spirograph](https://en.wikipedia.org/wiki/Spirograph) + * + * @details + * Implementation of the program is based on the geometry shown in the figure + * below: + * + * Spirograph geometry from Wikipedia + */ +#define _USE_MATH_DEFINES /**< required for MSVC compiler */ +#include +#include +#include +#include +#include + +/** Generate spirograph curve into arrays `x` and `y` such that the i^th point + * in 2D is represented by `(x[i],y[i])`. The generating function is given by: + * \f{eqnarray*}{ + * x &=& R\left[ (1-k) \cos (t) + l\cdot k\cdot\cos \left(\frac{1-k}{k}t\right) + * \right]\\ + * y &=& R\left[ (1-k) \sin (t) - l\cdot k\cdot\sin \left(\frac{1-k}{k}t\right) + * \right] \f} + * where + * * \f$R\f$ is the scaling parameter that we will consider \f$=1\f$ + * * \f$l=\frac{\rho}{r}\f$ is the relative distance of marker from the centre + * of inner circle and \f$0\le l\le1\f$ + * * \f$\rho\f$ is physical distance of marker from centre of inner circle + * * \f$r\f$ is the radius of inner circle + * * \f$k=\frac{r}{R}\f$ is the ratio of radius of inner circle to outer circle + * and \f$0 // include path on Macs is different +#else +#include +#endif + +static bool paused = 0; /**< flag to set pause/unpause animation */ +static const int animation_speed = 25; /**< animation delate in ms */ + +static const double step = 0.01; /**< animation step size */ +static double l_ratio = 0.1; /**< the l-ratio defined in docs */ +static double k_ratio = 0.1; /**< the k-ratio defined in docs */ +static const double num_rot = 20.; /**< number of rotations to simulate */ + +/** A wrapper that is not available in all GLUT implementations. + */ +static inline void glutBitmapString(void *font, char *string) +{ + for (char *ch = string; *ch != '\0'; ch++) glutBitmapCharacter(font, *ch); +} + +/** + * @brief Function to graph (x,y) points on the OpenGL graphics window. + * + * @param x array containing absicca of points (must be pre-allocated) + * @param y array containing ordinates of points (must be pre-allocated) + * @param N number of points in the arrays + */ +void display_graph(const double *x, const double *y, size_t N, double l, + double k) +{ + glClearColor(1.0f, 1.0f, 1.0f, + 0.0f); // Set background color to white and opaque + glClear(GL_COLOR_BUFFER_BIT); // Clear the color buffer (background) + + if (x && y) + { + glBegin(GL_LINES); // draw line segments + glColor3f(0.f, 0.f, 1.f); // blue + glPointSize(2.f); // point size in pixels + + for (size_t i = 1; i < N; i++) + { + glVertex2f(x[i - 1], y[i - 1]); // line from + glVertex2f(x[i], y[i]); // line to + } + glEnd(); + } + glColor3f(0.f, 0.f, 0.f); + char buffer[20]; + snprintf(buffer, 20, "l = %.3f", l); + glRasterPos2f(-.85, .85); + glutBitmapString(GLUT_BITMAP_HELVETICA_18, buffer); + snprintf(buffer, 20, "k = %.3f", k); + glRasterPos2f(-.85, .75); + glutBitmapString(GLUT_BITMAP_HELVETICA_18, buffer); + + glutSwapBuffers(); +} + +/** + * @brief Test function with animation + * + */ +void test2(void) +{ + const size_t N = 1000; // number of samples + + static bool direction1 = true; // increment if true, otherwise decrement + static bool direction2 = true; // increment if true, otherwise decrement + + double *x = (double *)malloc(N * sizeof(double)); + double *y = (double *)malloc(N * sizeof(double)); + + spirograph(x, y, l_ratio, k_ratio, N, num_rot); + display_graph(x, y, N, l_ratio, k_ratio); + + free(x); // free dynamic memories + free(y); + + if (paused) + // if paused, do not update l_ratio and k_ratio + return; + + if (direction1) // increment k_ratio + { + if (k_ratio >= (1.f - step)) // maximum limit + direction1 = false; // reverse direction of k_ratio + else + k_ratio += step; + } + else // decrement k_ratio + { + if (k_ratio <= step) // minimum limit + { + direction1 = true; // reverse direction of k_ratio + + if (direction2) // increment l_ratio + { + if (l_ratio >= (1.f - step)) // max limit of l_ratio + direction2 = false; // reverse direction of l_ratio + else + l_ratio += step; + } + else // decrement l_ratio + { + if (l_ratio <= step) // minimum limit of l_ratio + direction2 = true; // reverse direction of l_ratio + else + l_ratio -= step; + } + } + else // no min limit of k_ratio + k_ratio -= step; + } +} + +/** + * @brief GLUT timer callback function to add animation delay. + */ +void timer_cb(int id) +{ + glutPostRedisplay(); + glutTimerFunc(animation_speed, timer_cb, 0); +} + +/** + * @brief Keypress event call back function. + * + * @param key ID of the key pressed + * @param x mouse pointer position at event + * @param y mouse pointer position at event + */ +void keyboard_cb(unsigned char key, int x, int y) +{ + switch (key) + { + case ' ': // spacebar toggles pause + paused = !paused; // toggle + break; + case '+': // up arrow key + k_ratio += step; + display_graph(NULL, NULL, 1, l_ratio, k_ratio); + break; + case '_': // down arrow key + k_ratio -= step; + display_graph(NULL, NULL, 1, l_ratio, k_ratio); + break; + case '=': // left arrow key + l_ratio += step; + display_graph(NULL, NULL, 1, l_ratio, k_ratio); + break; + case '-': // right arrow key + l_ratio -= step; + display_graph(NULL, NULL, 1, l_ratio, k_ratio); + break; + case 0x1B: // escape key exits + exit(EXIT_SUCCESS); + } +} +#endif + +/** Main function */ +int main(int argc, char **argv) +{ + test(); + +#ifdef USE_GLUT + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); + glutCreateWindow("Spirograph"); + glutInitWindowSize(400, 400); + // glutIdleFunc(glutPostRedisplay); + glutTimerFunc(animation_speed, timer_cb, 0); + glutKeyboardFunc(keyboard_cb); + glutDisplayFunc(test2); + glutMainLoop(); +#endif + + return 0; +} diff --git a/greedy_approach/dijkstra.c b/greedy_approach/dijkstra.c new file mode 100644 index 0000000000..e9d1c63ca8 --- /dev/null +++ b/greedy_approach/dijkstra.c @@ -0,0 +1,87 @@ +#include +#include + +#define MAX 20 +#define INF 999 + +int mat[MAX][MAX]; +int V; + +int dist[MAX]; + +int q[MAX]; +int qp = 0; + +void enqueue(int v) { q[qp++] = v; } + +int cf(void *a, void *b) +{ + int *x = (int *)a; + int *y = (int *)b; + return *y - *x; +} + +int dequeue() +{ + qsort(q, qp, sizeof(int), cf); + return q[--qp]; +} + +int queue_has_something() { return (qp > 0); } + +int visited[MAX]; +int vp = 0; + +void dijkstra(int s) +{ + dist[s] = 0; + int i; + for (i = 0; i < V; ++i) + { + if (i != s) + { + dist[i] = INF; + } + enqueue(i); + } + while (queue_has_something()) + { + int u = dequeue(); + visited[vp++] = u; + for (i = 0; i < V; ++i) + { + if (mat[u][i]) + { + if (dist[i] > dist[u] + mat[u][i]) + { + dist[i] = dist[u] + mat[u][i]; + } + } + } + } +} + +int main(int argc, char const *argv[]) +{ + printf("Enter the number of vertices: "); + scanf(" %d", &V); + printf("Enter the adj matrix: "); + int i, j; + for (i = 0; i < V; ++i) + { + for (j = 0; j < V; ++j) + { + scanf(" %d", &mat[i][j]); + } + } + + dijkstra(0); + + printf("\nNode\tDist\n"); + for (i = 0; i < V; ++i) + { + printf("%d\t%d\n", i, dist[i]); + } + + return 0; +} diff --git a/greedy_approach/prim.c b/greedy_approach/prim.c new file mode 100644 index 0000000000..e4076a0847 --- /dev/null +++ b/greedy_approach/prim.c @@ -0,0 +1,203 @@ +/** + * @file + * @author [Timothy Maloney](https://github.com/sl1mb0) + * @brief [Prim's algorithm](https://en.wikipedia.org/wiki/Prim%27s_algorithm) + * implementation in C to find the MST of a weighted, connected graph. + * @details Prim's algorithm uses a greedy approach to generate the MST of a weighted connected graph. + * The algorithm begins at an arbitrary vertex v, and selects a next vertex u, + * where v and u are connected by a weighted edge whose weight is the minimum of all edges connected to v. + * @references Page 319 "Introduction to the Design and Analysis of Algorithms" - Anany Levitin + * + * To test - run './prim -test' + * prim() will find the MST of the following adj. matrix: + * + * 0 1 2 3 + * 1 0 4 6 + * 2 4 0 5 + * 3 6 5 0 + * + * The minimum spanning tree for the above weighted connected graph is given by the following adj matrix: + * + * 0 1 2 3 + * 1 0 0 0 + * 2 0 0 0 + * 3 0 0 0 + * + * + * The following [link](https://visualgo.net/en/mst) provides a visual representation of graphs that can be used to test/verify the algorithm for different adj + * matrices and their weighted, connected graphs. + */ + +#include /// for IO operations +#include /// for string comparison +#include /// for assert() +#include /// for uint16_t + +#define MAX 20 +#define INF 999 + +/** + * @brief Finds index of minimum element in edge list for an arbitrary vertex + * @param arr graph row + * @param N number of elements in arr + * @returns index of minimum element in arr + */ +uint16_t minimum(uint16_t arr[], uint16_t N) +{ + uint16_t index = 0; + uint16_t min = INF; + + for (uint16_t i = 0; i < N; i++) + { + if (arr[i] < min) + { + min = arr[i]; + index = i; + } + } + return index; +} + +/** + * @brief Used to find MST of user-generated adj matrix G + * @returns void + */ +void prim(uint16_t G[][MAX], uint16_t MST[][MAX], uint16_t V) +{ + uint16_t u, v; + uint16_t E_t[MAX], path[MAX]; + uint16_t V_t[MAX], no_of_edges; + + E_t[0] = 0; // edges for current vertex + V_t[0] = 1; // list of visited vertices + + for (uint16_t i = 1; i < V; i++) + { + E_t[i] = G[i][0]; + path[i] = 0; + V_t[i] = 0; + } + + no_of_edges = V - 1; + + while (no_of_edges > 0) + { + u = minimum(E_t, V); + while (V_t[u] == 1) + { + E_t[u] = INF; + u = minimum(E_t, V); + } + + v = path[u]; + MST[v][u] = E_t[u]; + MST[u][v] = E_t[u]; + no_of_edges--; + V_t[u] = 1; + + for (uint16_t i = 1; i < V; i++) + { + if (V_t[i] == 0 && G[u][i] < E_t[i]) + { + E_t[i] = G[u][i]; + path[i] = v; + } + } + } +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test(uint16_t G[][MAX], uint16_t MST[][MAX], uint16_t V) +{ + + uint16_t test[4][4] = {{0,1,2,3},{1,0,4,6},{2,4,0,5},{3,6,5,0}}; + uint16_t solution[4][4] = {{0,1,2,3},{1,0,0,0},{2,0,0,0},{3,0,0,0}}; + + V = 4; + + for(uint16_t i = 0; i < V; ++i) + { + for(uint16_t j = 0; j < V; ++j) + { + G[i][j] = test[i][j]; + } + } + + prim(&(*G),&(*MST),V); + + for(uint16_t i = 0; i < V; ++i) + { + for(uint16_t j = 0; j < V; ++j) + { + assert(MST[i][j] == solution[i][j]); + } + } +} + +/** + * @brief Function user_graph(); + * gets user input adj. matrix and finds MST of that graph + * @returns void + */ +void user_graph(uint16_t G[][MAX], uint16_t MST[][MAX], uint16_t V) +{ + printf("Enter the number of vertices: "); + scanf(" %hd", &V); + + assert(V <= MAX); + + printf("Enter the adj matrix\n"); + uint16_t i, j; + for (i = 0; i < V; ++i) + { + for (j = 0; j < V; ++j) + { + printf("G[%d][%d]: ", i, j); + scanf(" %hd", &G[i][j]); + if (G[i][j] == 0) + G[i][j] = INF; + } + } + + prim(&(*G),&(*MST),V); + + printf("minimum spanning tree:\n"); + for (i = 0; i < V; ++i) + { + printf("\n"); + for (j = 0; j < V; ++j) + { + printf("%d\t", MST[i][j]); + } + } +} + + +/** + * @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 const *argv[]) +{ + + uint16_t G[MAX][MAX]; ///< weighted, connected graph G + uint16_t MST[MAX][MAX]; ///< adj matrix to hold minimum spanning tree of G + uint16_t V; ///< number of vertices in V in G + + + if(argc == 2 && strcmp(argv[1],"-test") == 0) + { + test(&(*G),&(*MST),V); + } + else + { + user_graph(&(*G),&(*MST),V); + } + + return 0; +} diff --git a/hash/CMakeLists.txt b/hash/CMakeLists.txt new file mode 100644 index 0000000000..9c65e0966f --- /dev/null +++ b/hash/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} *.c ) +# 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 ".c" "" testname ${testsourcefile} ) + add_executable( ${testname} ${testsourcefile} ) + + if(OpenMP_C_FOUND) + target_link_libraries(${testname} OpenMP::OpenMP_C) + endif() + if(MATH_LIBRARY) + target_link_libraries(${testname} ${MATH_LIBRARY}) + endif() + install(TARGETS ${testname} DESTINATION "bin/hash") + +endforeach( testsourcefile ${APP_SOURCES} ) diff --git a/hash/README.md b/hash/README.md index 1bf23b8f2e..90942636cf 100644 --- a/hash/README.md +++ b/hash/README.md @@ -1,7 +1,8 @@ # Hash algorithms -Overview files **hash.h** and **hash.c** * sdbm * djb2 * xor8 (8 bit) -* adler_32 (32 bit) \ No newline at end of file +* adler_32 (32 bit) +* crc32 (32 bit) +* BLAKE2b diff --git a/hash/hash.c b/hash/hash.c deleted file mode 100644 index 220bb5ca97..0000000000 --- a/hash/hash.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - author: Christian Bender - This is the implementation unit of the hash-functions. - - Overview about hash-functions: - - - sdbm - - djb2 - - xor8 (8 bits) - - adler_32 (32 bits) -*/ - -long long sdbm(char s[]) -{ - long long hash = 0; - int i = 0; - while (s[i] != '\0') - { - hash = s[i] + (hash << 6) + (hash << 16) - hash; - i++; - } - return hash; -} - -long long djb2(char s[]) -{ - long long hash = 5381; /* init value */ - int i = 0; - while (s[i] != '\0') - { - hash = ((hash << 5) + hash) + s[i]; - i++; - } - return hash; -} - -char xor8(char s[]) -{ - int hash = 0; - int i = 0; - while (s[i] != '\0') - { - hash = (hash + s[i]) & 0xff; - i++; - } - return (((hash ^ 0xff) + 1) & 0xff); -} - -int adler_32(char s[]) -{ - int a = 1; - int b = 0; - const int MODADLER = 65521; - - int i = 0; - while (s[i] != '\0') - { - a = (a + s[i]) % MODADLER; - b = (b + a) % MODADLER; - i++; - } - return (b << 16) | a; -} \ No newline at end of file diff --git a/hash/hash.h b/hash/hash.h deleted file mode 100644 index 7497b1b28a..0000000000 --- a/hash/hash.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - author: Christian Bender - This file contains the public interface - - Overview about hash-functions: - - - sdbm - - djb2 - - xor8 (8 bit) - - adler_32 (32 bits) -*/ - -#ifndef __HASH__H -#define __HASH__H - -/* - sdbm: implements the sdbm hash-algorithm - returns a whole number of type long long. -*/ -long long sdbm(char[]); - -/* - djb2: implements the djb2 hash-algorithm - returns a whole number of type long long. -*/ -long long djb2(char[]); - -/* - xor8: implements the xor8 hash-algorithm - returns a whole number of type char. - length: 8 bit -*/ -char xor8(char[]); - -/* - adler_32: implements the adler-32 hash-algorithm - returns a whole number of type int. - length: 32 bit - assumes: int has a length of 32 bits. -*/ -int adler_32(char[]); - -#endif \ No newline at end of file diff --git a/hash/hash_adler32.c b/hash/hash_adler32.c new file mode 100644 index 0000000000..4cd5891e09 --- /dev/null +++ b/hash/hash_adler32.c @@ -0,0 +1,54 @@ +/** + * @addtogroup hash Hash algorithms + * @{ + * @file hash_adler32.c + * @author [Christian Bender](https://github.com/christianbender) + * @brief 32-bit [Adler hash](https://en.wikipedia.org/wiki/Adler-32) algorithm + */ +#include +#include +#include + +/** + * @brief 32-bit Adler algorithm implementation + * + * @param s NULL terminated ASCII string to hash + * @return 32-bit hash result + */ +uint32_t adler32(const char* s) +{ + uint32_t a = 1; + uint32_t b = 0; + const uint32_t MODADLER = 65521; + + size_t i = 0; + while (s[i] != '\0') + { + a = (a + s[i]) % MODADLER; + b = (b + a) % MODADLER; + i++; + } + return (b << 16) | a; +} + +/** + * @brief Test function for ::adler32 + * \returns None + */ +void test_adler32() +{ + assert(adler32("Hello World") == 403375133); + assert(adler32("Hello World!") == 474547262); + assert(adler32("Hello world") == 413860925); + assert(adler32("Hello world!") == 487130206); + printf("Tests passed\n"); +} + +/** @} */ + +/** Main function */ +int main() +{ + test_adler32(); + return 0; +} diff --git a/hash/hash_blake2b.c b/hash/hash_blake2b.c new file mode 100644 index 0000000000..3c7b75781b --- /dev/null +++ b/hash/hash_blake2b.c @@ -0,0 +1,551 @@ +/** + * @addtogroup hash Hash algorithms + * @{ + * @file + * @author [Daniel Murrow](https://github.com/dsmurrow) + * @brief [Blake2b cryptographic hash + * function](https://www.rfc-editor.org/rfc/rfc7693) + * + * The Blake2b cryptographic hash function provides + * hashes for data that are secure enough to be used in + * cryptographic applications. It is designed to perform + * optimally on 64-bit platforms. The algorithm can output + * digests between 1 and 64 bytes long, for messages up to + * 128 bits in length. Keyed hashing is also supported for + * keys up to 64 bytes in length. + */ +#include /// for asserts +#include /// for fixed-width integer types e.g. uint64_t and uint8_t +#include /// for IO +#include /// for malloc, calloc, and free. As well as size_t + +/* Warning suppressed is in blake2b() function, more + * details are over there */ +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wshift-count-overflow" +#elif _MSC_VER +#pragma warning(disable : 4293) +#endif + +/** + * @brief the size of a data block in bytes + */ +#define bb 128 + +/** + * @brief max key length for BLAKE2b + */ +#define KK_MAX 64 + +/** + * @brief max length of BLAKE2b digest in bytes + */ +#define NN_MAX 64 + +/** + * @brief ceiling division macro without floats + * + * @param a dividend + * @param b divisor + */ +#define CEIL(a, b) (((a) / (b)) + ((a) % (b) != 0)) + +/** + * @brief returns minimum value + */ +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +/** + * @brief returns maximum value + */ +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + +/** + * @brief macro to rotate 64-bit ints to the right + * Ripped from RFC 7693 + */ +#define ROTR64(n, offset) (((n) >> (offset)) ^ ((n) << (64 - (offset)))) + +/** + * @brief zero-value initializer for u128 type + */ +#define U128_ZERO \ + { \ + 0, 0 \ + } + +/** 128-bit number represented as two uint64's */ +typedef uint64_t u128[2]; + +/** Padded input block containing bb bytes */ +typedef uint64_t block_t[bb / sizeof(uint64_t)]; + +static const uint8_t R1 = 32; ///< Rotation constant 1 for mixing function G +static const uint8_t R2 = 24; ///< Rotation constant 2 for mixing function G +static const uint8_t R3 = 16; ///< Rotation constant 3 for mixing function G +static const uint8_t R4 = 63; ///< Rotation constant 4 for mixing function G + +static const uint64_t blake2b_iv[8] = { + 0x6A09E667F3BCC908, 0xBB67AE8584CAA73B, 0x3C6EF372FE94F82B, + 0xA54FF53A5F1D36F1, 0x510E527FADE682D1, 0x9B05688C2B3E6C1F, + 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179}; ///< BLAKE2b Initialization vector + ///< blake2b_iv[i] = floor(2**64 * + ///< frac(sqrt(prime(i+1)))), + ///< where prime(i) is the i:th + ///< prime number + +static const uint8_t blake2b_sigma[12][16] = { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, + {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, + {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, + {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, + {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, + {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, + {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, + 3}}; ///< word schedule permutations for each round of the algorithm + +/** + * @brief put value of n into dest + * + * @param dest 128-bit number to get copied from n + * @param n value put into dest + * + * @returns void + */ +static inline void u128_fill(u128 dest, size_t n) +{ + dest[0] = n & UINT64_MAX; + + if (sizeof(n) > 8) + { + /* The C standard does not specify a maximum length for size_t, + * although most machines implement it to be the same length as + * uint64_t. On machines where size_t is 8 bytes long this will issue a + * compiler warning, which is why it is suppressed. But on a machine + * where size_t is greater than 8 bytes, this will work as normal. */ + dest[1] = n >> 64; + } + else + { + dest[1] = 0; + } +} + +/** + * @brief increment an 128-bit number by a given amount + * + * @param dest the value being incremented + * @param n what dest is being increased by + * + * @returns void + */ +static inline void u128_increment(u128 dest, uint64_t n) +{ + /* Check for overflow */ + if (UINT64_MAX - dest[0] <= n) + { + dest[1]++; + } + + dest[0] += n; +} + +/** + * @brief blake2b mixing function G + * + * Shuffles values in block v depending on + * provided indeces a, b, c, and d. x and y + * are also mixed into the block. + * + * @param v array of words to be mixed + * @param a first index + * @param b second index + * @param c third index + * @param d fourth index + * @param x first word being mixed into v + * @param y second word being mixed into y + * + * @returns void + */ +static void G(block_t v, uint8_t a, uint8_t b, uint8_t c, uint8_t d, uint64_t x, + uint64_t y) +{ + v[a] += v[b] + x; + v[d] = ROTR64(v[d] ^ v[a], R1); + v[c] += v[d]; + v[b] = ROTR64(v[b] ^ v[c], R2); + v[a] += v[b] + y; + v[d] = ROTR64(v[d] ^ v[a], R3); + v[c] += v[d]; + v[b] = ROTR64(v[b] ^ v[c], R4); +} + +/** + * @brief compression function F + * + * Securely mixes the values in block m into + * the state vector h. Value at v[14] is also + * inverted if this is the final block to be + * compressed. + * + * @param h the state vector + * @param m message vector to be compressed into h + * @param t 128-bit offset counter + * @param f flag to indicate whether this is the final block + * + * @returns void + */ +static void F(uint64_t h[8], block_t m, u128 t, int f) +{ + int i; + block_t v; + + /* v[0..7] := h[0..7] */ + for (i = 0; i < 8; i++) + { + v[i] = h[i]; + } + /* v[8..15] := IV[0..7] */ + for (; i < 16; i++) + { + v[i] = blake2b_iv[i - 8]; + } + + v[12] ^= t[0]; /* v[12] ^ (t mod 2**w) */ + v[13] ^= t[1]; /* v[13] ^ (t >> w) */ + + if (f) + { + v[14] = ~v[14]; + } + + for (i = 0; i < 12; i++) + { + const uint8_t *s = blake2b_sigma[i]; + + G(v, 0, 4, 8, 12, m[s[0]], m[s[1]]); + G(v, 1, 5, 9, 13, m[s[2]], m[s[3]]); + G(v, 2, 6, 10, 14, m[s[4]], m[s[5]]); + G(v, 3, 7, 11, 15, m[s[6]], m[s[7]]); + + G(v, 0, 5, 10, 15, m[s[8]], m[s[9]]); + G(v, 1, 6, 11, 12, m[s[10]], m[s[11]]); + G(v, 2, 7, 8, 13, m[s[12]], m[s[13]]); + G(v, 3, 4, 9, 14, m[s[14]], m[s[15]]); + } + + for (i = 0; i < 8; i++) + { + h[i] ^= v[i] ^ v[i + 8]; + } +} + +/** + * @brief driver function to perform the hashing as described in specification + * + * pseudocode: (credit to authors of RFC 7693 listed above) + * FUNCTION BLAKE2( d[0..dd-1], ll, kk, nn ) + * | + * | h[0..7] := IV[0..7] // Initialization Vector. + * | + * | // Parameter block p[0] + * | h[0] := h[0] ^ 0x01010000 ^ (kk << 8) ^ nn + * | + * | // Process padded key and data blocks + * | IF dd > 1 THEN + * | | FOR i = 0 TO dd - 2 DO + * | | | h := F( h, d[i], (i + 1) * bb, FALSE ) + * | | END FOR. + * | END IF. + * | + * | // Final block. + * | IF kk = 0 THEN + * | | h := F( h, d[dd - 1], ll, TRUE ) + * | ELSE + * | | h := F( h, d[dd - 1], ll + bb, TRUE ) + * | END IF. + * | + * | RETURN first "nn" bytes from little-endian word array h[]. + * | + * END FUNCTION. + * + * @param dest destination of hashing digest + * @param d message blocks + * @param dd length of d + * @param ll 128-bit length of message + * @param kk length of secret key + * @param nn length of hash digest + * + * @returns 0 upon successful hash + */ +static int BLAKE2B(uint8_t *dest, block_t *d, size_t dd, u128 ll, uint8_t kk, + uint8_t nn) +{ + uint8_t bytes[8]; + uint64_t i, j; + uint64_t h[8]; + u128 t = U128_ZERO; + + /* h[0..7] = IV[0..7] */ + for (i = 0; i < 8; i++) + { + h[i] = blake2b_iv[i]; + } + + h[0] ^= 0x01010000 ^ (kk << 8) ^ nn; + + if (dd > 1) + { + for (i = 0; i < dd - 1; i++) + { + u128_increment(t, bb); + F(h, d[i], t, 0); + } + } + + if (kk != 0) + { + u128_increment(ll, bb); + } + F(h, d[dd - 1], ll, 1); + + /* copy bytes from h to destination buffer */ + for (i = 0; i < nn; i++) + { + if (i % sizeof(uint64_t) == 0) + { + /* copy values from uint64 to 8 u8's */ + for (j = 0; j < sizeof(uint64_t); j++) + { + uint16_t offset = 8 * j; + uint64_t mask = 0xFF; + mask <<= offset; + + bytes[j] = (h[i / 8] & (mask)) >> offset; + } + } + + dest[i] = bytes[i % 8]; + } + + return 0; +} + +/** + * @brief blake2b hash function + * + * This is the front-end function that sets up the argument for BLAKE2B(). + * + * @param message the message to be hashed + * @param len length of message (0 <= len < 2**128) (depends on sizeof(size_t) + * for this implementation) + * @param key optional secret key + * @param kk length of optional secret key (0 <= kk <= 64) + * @param nn length of output digest (1 <= nn < 64) + * + * @returns NULL if heap memory couldn't be allocated. Otherwise heap allocated + * memory nn bytes large + */ +uint8_t *blake2b(const uint8_t *message, size_t len, const uint8_t *key, + uint8_t kk, uint8_t nn) +{ + uint8_t *dest = NULL; + uint64_t long_hold; + size_t dd, has_key, i; + size_t block_index, word_in_block; + u128 ll; + block_t *blocks; + + if (message == NULL) + { + len = 0; + } + if (key == NULL) + { + kk = 0; + } + + kk = MIN(kk, KK_MAX); + nn = MIN(nn, NN_MAX); + + dd = MAX(CEIL(kk, bb) + CEIL(len, bb), 1); + + blocks = calloc(dd, sizeof(block_t)); + if (blocks == NULL) + { + return NULL; + } + + dest = malloc(nn * sizeof(uint8_t)); + if (dest == NULL) + { + free(blocks); + return NULL; + } + + /* If there is a secret key it occupies the first block */ + for (i = 0; i < kk; i++) + { + long_hold = key[i]; + long_hold <<= 8 * (i % 8); + + word_in_block = (i % bb) / 8; + /* block_index will always be 0 because kk <= 64 and bb = 128*/ + blocks[0][word_in_block] |= long_hold; + } + + has_key = kk > 0 ? 1 : 0; + + for (i = 0; i < len; i++) + { + /* long_hold exists because the bit-shifting will overflow if we don't + * store the value */ + long_hold = message[i]; + long_hold <<= 8 * (i % 8); + + block_index = has_key + (i / bb); + word_in_block = (i % bb) / 8; + + blocks[block_index][word_in_block] |= long_hold; + } + + u128_fill(ll, len); + + BLAKE2B(dest, blocks, dd, ll, kk, nn); + + free(blocks); + + return dest; +} + +/** @} */ + +/** + * @brief Self-test implementations + * @returns void + */ +static void assert_bytes(const uint8_t *expected, const uint8_t *actual, + uint8_t len) +{ + uint8_t i; + + assert(expected != NULL); + assert(actual != NULL); + assert(len > 0); + + for (i = 0; i < len; i++) + { + assert(expected[i] == actual[i]); + } +} + +/** + * @brief testing function + * + * @returns void + */ +static void test() +{ + uint8_t *digest = NULL; + + /* "abc" example straight out of RFC-7693 */ + uint8_t abc[3] = {'a', 'b', 'c'}; + uint8_t abc_answer[64] = { + 0xBA, 0x80, 0xA5, 0x3F, 0x98, 0x1C, 0x4D, 0x0D, 0x6A, 0x27, 0x97, + 0xB6, 0x9F, 0x12, 0xF6, 0xE9, 0x4C, 0x21, 0x2F, 0x14, 0x68, 0x5A, + 0xC4, 0xB7, 0x4B, 0x12, 0xBB, 0x6F, 0xDB, 0xFF, 0xA2, 0xD1, 0x7D, + 0x87, 0xC5, 0x39, 0x2A, 0xAB, 0x79, 0x2D, 0xC2, 0x52, 0xD5, 0xDE, + 0x45, 0x33, 0xCC, 0x95, 0x18, 0xD3, 0x8A, 0xA8, 0xDB, 0xF1, 0x92, + 0x5A, 0xB9, 0x23, 0x86, 0xED, 0xD4, 0x00, 0x99, 0x23}; + + digest = blake2b(abc, 3, NULL, 0, 64); + assert_bytes(abc_answer, digest, 64); + + free(digest); + + uint8_t key[64] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f}; + uint8_t key_answer[64] = { + 0x10, 0xeb, 0xb6, 0x77, 0x00, 0xb1, 0x86, 0x8e, 0xfb, 0x44, 0x17, + 0x98, 0x7a, 0xcf, 0x46, 0x90, 0xae, 0x9d, 0x97, 0x2f, 0xb7, 0xa5, + 0x90, 0xc2, 0xf0, 0x28, 0x71, 0x79, 0x9a, 0xaa, 0x47, 0x86, 0xb5, + 0xe9, 0x96, 0xe8, 0xf0, 0xf4, 0xeb, 0x98, 0x1f, 0xc2, 0x14, 0xb0, + 0x05, 0xf4, 0x2d, 0x2f, 0xf4, 0x23, 0x34, 0x99, 0x39, 0x16, 0x53, + 0xdf, 0x7a, 0xef, 0xcb, 0xc1, 0x3f, 0xc5, 0x15, 0x68}; + + digest = blake2b(NULL, 0, key, 64, 64); + assert_bytes(key_answer, digest, 64); + + free(digest); + + uint8_t zero[1] = {0}; + uint8_t zero_key[64] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f}; + uint8_t zero_answer[64] = { + 0x96, 0x1f, 0x6d, 0xd1, 0xe4, 0xdd, 0x30, 0xf6, 0x39, 0x01, 0x69, + 0x0c, 0x51, 0x2e, 0x78, 0xe4, 0xb4, 0x5e, 0x47, 0x42, 0xed, 0x19, + 0x7c, 0x3c, 0x5e, 0x45, 0xc5, 0x49, 0xfd, 0x25, 0xf2, 0xe4, 0x18, + 0x7b, 0x0b, 0xc9, 0xfe, 0x30, 0x49, 0x2b, 0x16, 0xb0, 0xd0, 0xbc, + 0x4e, 0xf9, 0xb0, 0xf3, 0x4c, 0x70, 0x03, 0xfa, 0xc0, 0x9a, 0x5e, + 0xf1, 0x53, 0x2e, 0x69, 0x43, 0x02, 0x34, 0xce, 0xbd}; + + digest = blake2b(zero, 1, zero_key, 64, 64); + assert_bytes(zero_answer, digest, 64); + + free(digest); + + uint8_t filled[64] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f}; + uint8_t filled_key[64] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f}; + uint8_t filled_answer[64] = { + 0x65, 0x67, 0x6d, 0x80, 0x06, 0x17, 0x97, 0x2f, 0xbd, 0x87, 0xe4, + 0xb9, 0x51, 0x4e, 0x1c, 0x67, 0x40, 0x2b, 0x7a, 0x33, 0x10, 0x96, + 0xd3, 0xbf, 0xac, 0x22, 0xf1, 0xab, 0xb9, 0x53, 0x74, 0xab, 0xc9, + 0x42, 0xf1, 0x6e, 0x9a, 0xb0, 0xea, 0xd3, 0x3b, 0x87, 0xc9, 0x19, + 0x68, 0xa6, 0xe5, 0x09, 0xe1, 0x19, 0xff, 0x07, 0x78, 0x7b, 0x3e, + 0xf4, 0x83, 0xe1, 0xdc, 0xdc, 0xcf, 0x6e, 0x30, 0x22}; + + digest = blake2b(filled, 64, filled_key, 64, 64); + assert_bytes(filled_answer, digest, 64); + + free(digest); + + printf("All tests have successfully passed!\n"); +} + +/** + * @brief main function + * + * @returns 0 on successful program exit + */ +int main() +{ + test(); + return 0; +} diff --git a/hash/hash_crc32.c b/hash/hash_crc32.c new file mode 100644 index 0000000000..ec905dc942 --- /dev/null +++ b/hash/hash_crc32.c @@ -0,0 +1,58 @@ +/** + * @addtogroup hash Hash algorithms + * @{ + * @file hash_crc32.c + * @author [Christian Bender](https://github.com/christianbender) + * @brief 32-bit [CRC + * hash](https://en.wikipedia.org/wiki/Cyclic_redundancy_check#CRC-32_algorithm) + * algorithm + */ +#include +#include +#include + +/** + * @brief 32-bit CRC algorithm implementation + * + * @param s NULL terminated ASCII string to hash + * @return 32-bit hash result + */ +uint32_t crc32(const char* s) +{ + uint32_t crc = 0xffffffff; + size_t i = 0; + while (s[i] != '\0') + { + uint8_t byte = s[i]; + crc = crc ^ byte; + for (uint8_t j = 8; j > 0; --j) + { + crc = (crc >> 1) ^ (0xEDB88320 & (-(crc & 1))); + } + + i++; + } + return crc ^ 0xffffffff; +} + +/** + * @brief Test function for ::crc32 + * \returns None + */ +void test_crc32() +{ + assert(crc32("Hello World") == 1243066710); + assert(crc32("Hello World!") == 472456355); + assert(crc32("Hello world") == 2346098258); + assert(crc32("Hello world!") == 461707669); + printf("Tests passed\n"); +} + +/** @} */ + +/** Main function */ +int main() +{ + test_crc32(); + return 0; +} diff --git a/hash/hash_djb2.c b/hash/hash_djb2.c new file mode 100644 index 0000000000..48d0e1f9ab --- /dev/null +++ b/hash/hash_djb2.c @@ -0,0 +1,50 @@ +/** + * @addtogroup hash Hash algorithms + * @{ + * @file hash_djb2.c + * @author [Christian Bender](https://github.com/christianbender) + * @brief [DJB2 hash algorithm](http://www.cse.yorku.ca/~oz/hash.html) + */ +#include +#include +#include + +/** + * @brief DJB2 algorithm implementation + * + * @param s NULL terminated string to hash + * @return 64-bit hash result + */ +uint64_t djb2(const char* s) +{ + uint64_t hash = 5381; /* init value */ + size_t i = 0; + while (s[i] != '\0') + { + hash = ((hash << 5) + hash) + s[i]; + i++; + } + return hash; +} + +/** + * Test function for ::djb2 + * \returns none + */ +void test_djb2(void) +{ + assert(djb2("Hello World") == 13827776004929097857); + assert(djb2("Hello World!") == 13594750393630990530); + assert(djb2("Hello world") == 13827776004967047329); + assert(djb2("Hello world!") == 13594750394883323106); + printf("Tests passed\n"); +} + +/** @} */ + +/** Main function */ +int main() +{ + test_djb2(); + return 0; +} diff --git a/hash/hash_sdbm.c b/hash/hash_sdbm.c new file mode 100644 index 0000000000..4a5d279b5d --- /dev/null +++ b/hash/hash_sdbm.c @@ -0,0 +1,50 @@ +/** + * @addtogroup hash Hash algorithms + * @{ + * @file hash_sdbm.c + * @author [Christian Bender](https://github.com/christianbender) + * @brief [SDBM hash algorithm](http://www.cse.yorku.ca/~oz/hash.html) + */ +#include +#include +#include + +/** + * @brief SDBM algorithm implementation + * + * @param s NULL terminated string to hash + * @return 64-bit hash result + */ +uint64_t sdbm(const char* s) +{ + uint64_t hash = 0; + size_t i = 0; + while (s[i] != '\0') + { + hash = s[i] + (hash << 6) + (hash << 16) - hash; + i++; + } + return hash; +} + +/** + * @brief Test function for ::sdbm + * \returns None + */ +void test_sdbm() +{ + assert(sdbm("Hello World") == 12881824461405877380U); + assert(sdbm("Hello World!") == 7903571203300273309); + assert(sdbm("Hello world") == 15154913742888948900U); + assert(sdbm("Hello world!") == 15254999417003201661U); + printf("Tests passed\n"); +} + +/** @} */ + +/** Main function */ +int main() +{ + test_sdbm(); + return 0; +} diff --git a/hash/hash_xor8.c b/hash/hash_xor8.c new file mode 100644 index 0000000000..f365782954 --- /dev/null +++ b/hash/hash_xor8.c @@ -0,0 +1,51 @@ +/** + * @addtogroup hash Hash algorithms + * @{ + * @file hash_xor8.c + * @author [Christian Bender](https://github.com/christianbender) + * @brief 8-bit [XOR hash](https://en.wikipedia.org/wiki/XOR_cipher) algorithm + * for ASCII characters + */ +#include +#include +#include + +/** + * @brief 8-bit XOR algorithm implementation + * + * @param s NULL terminated ASCII string to hash + * @return 8-bit hash result + */ +uint8_t xor8(const char* s) +{ + uint8_t hash = 0; + size_t i = 0; + while (s[i] != '\0') + { + hash = (hash + s[i]) & 0xff; + i++; + } + return (((hash ^ 0xff) + 1) & 0xff); +} + +/** + * @brief Test function for ::xor8 + * \returns None + */ +void test_xor8() +{ + assert(xor8("Hello World") == 228); + assert(xor8("Hello World!") == 195); + assert(xor8("Hello world") == 196); + assert(xor8("Hello world!") == 163); + printf("Tests passed\n"); +} + +/** @} */ + +/** Main function */ +int main() +{ + test_xor8(); + return 0; +} diff --git a/hash/test_program.c b/hash/test_program.c deleted file mode 100644 index f9dcd29905..0000000000 --- a/hash/test_program.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - author: Christian Bender - This file contains a simple test program for each hash-function. -*/ - -#include -#include "hash.h" - -int main(void) -{ - char s[] = "name"; - - /* actual tests */ - printf("sdbm: %s --> %lld\n", s, sdbm(s)); - printf("djb2: %s --> %lld\n", s, djb2(s)); - printf("xor8: %s --> %i\n", s, xor8(s)); /* 8 bit */ - printf("adler_32: %s --> %i\n", s, adler_32(s)); /* 32 bit */ - - return 0; -} \ No newline at end of file diff --git a/leetcode/DIRECTORY.md b/leetcode/DIRECTORY.md new file mode 100644 index 0000000000..d4436ea420 --- /dev/null +++ b/leetcode/DIRECTORY.md @@ -0,0 +1,157 @@ + +# LeetCode + +### LeetCode Algorithm + +| # | Title | Solution | Difficulty | +| ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------- | ---------- | +| 1 | [Two Sum](https://leetcode.com/problems/two-sum) | [C](./src/1.c) | Easy | +| 2 | [Add Two Numbers](https://leetcode.com/problems/add-two-numbers) | [C](./src/2.c) | Medium | +| 3 | [Longest Substring Without Repeating Characters](https://leetcode.com/problems/longest-substring-without-repeating-characters) | [C](./src/3.c) | Medium | +| 4 | [Median of Two Sorted Arrays](https://leetcode.com/problems/median-of-two-sorted-arrays) | [C](./src/4.c) | Hard | +| 5 | [Longest Palindromic Substring](https://leetcode.com/problems/longest-palindromic-substring) | [C](./src/5.c) | Medium | +| 6 | [Zigzag Conversion](https://leetcode.com/problems/zigzag-conversion) | [C](./src/6.c) | Medium | +| 7 | [Reverse Integer](https://leetcode.com/problems/reverse-integer) | [C](./src/7.c) | Medium | +| 8 | [String to Integer (atoi)](https://leetcode.com/problems/string-to-integer-atoi) | [C](./src/8.c) | Medium | +| 9 | [Palindrome Number](https://leetcode.com/problems/palindrome-number) | [C](./src/9.c) | Easy | +| 10 | [Regular Expression Matching](https://leetcode.com/problems/regular-expression-matching) | [C](./src/10.c) | Hard | +| 11 | [Container With Most Water](https://leetcode.com/problems/container-with-most-water) | [C](./src/11.c) | Medium | +| 12 | [Integer to Roman](https://leetcode.com/problems/integer-to-roman) | [C](./src/12.c) | Medium | +| 13 | [Roman to Integer](https://leetcode.com/problems/roman-to-integer) | [C](./src/13.c) | Easy | +| 14 | [Longest Common Prefix](https://leetcode.com/problems/longest-common-prefix) | [C](./src/14.c) | Easy | +| 16 | [3Sum Closest](https://leetcode.com/problems/3sum-closest) | [C](./src/16.c) | Medium | +| 17 | [Letter Combinations of a Phone Number](https://leetcode.com/problems/letter-combinations-of-a-phone-number) | [C](./src/17.c) | Medium | +| 19 | [Remove Nth Node From End of List](https://leetcode.com/problems/remove-nth-node-from-end-of-list) | [C](./src/19.c) | Medium | +| 20 | [Valid Parentheses](https://leetcode.com/problems/valid-parentheses) | [C](./src/20.c) | Easy | +| 21 | [Merge Two Sorted Lists](https://leetcode.com/problems/merge-two-sorted-lists) | [C](./src/21.c) | Easy | +| 24 | [Swap Nodes in Pairs](https://leetcode.com/problems/swap-nodes-in-pairs) | [C](./src/24.c) | Medium | +| 26 | [Remove Duplicates from Sorted Array](https://leetcode.com/problems/remove-duplicates-from-sorted-array) | [C](./src/26.c) | Easy | +| 27 | [Remove Element](https://leetcode.com/problems/remove-element) | [C](./src/27.c) | Easy | +| 28 | [Find the Index of the First Occurrence in a String](https://leetcode.com/problems/find-the-index-of-the-first-occurrence-in-a-string) | [C](./src/28.c) | Easy | +| 29 | [Divide Two Integers](https://leetcode.com/problems/divide-two-integers) | [C](./src/29.c) | Medium | +| 32 | [Longest Valid Parentheses](https://leetcode.com/problems/longest-valid-parentheses) | [C](./src/32.c) | Hard | +| 35 | [Search Insert Position](https://leetcode.com/problems/search-insert-position) | [C](./src/35.c) | Easy | +| 37 | [Sudoku Solver](https://leetcode.com/problems/sudoku-solver) | [C](./src/37.c) | Hard | +| 38 | [Count and Say](https://leetcode.com/problems/count-and-say) | [C](./src/38.c) | Medium | +| 42 | [Trapping Rain Water](https://leetcode.com/problems/trapping-rain-water) | [C](./src/42.c) | Hard | +| 45 | [Jump Game II](https://leetcode.com/problems/jump-game-ii) | [C](./src/45.c) | Medium | +| 50 | [Pow(x, n)](https://leetcode.com/problems/powx-n) | [C](./src/50.c) | Medium | +| 53 | [Maximum Subarray](https://leetcode.com/problems/maximum-subarray) | [C](./src/53.c) | Medium | +| 62 | [Unique Paths](https://leetcode.com/problems/unique-paths) | [C](./src/62.c) | Medium | +| 63 | [Unique Paths II](https://leetcode.com/problems/unique-paths-ii) | [C](./src/63.c) | Medium | +| 66 | [Plus One](https://leetcode.com/problems/plus-one) | [C](./src/66.c) | Easy | +| 75 | [Sort Colors](https://leetcode.com/problems/sort-colors) | [C](./src/75.c) | Medium | +| 79 | [Word Search](https://leetcode.com/problems/word-search) | [C](./src/79.c) | Medium | +| 82 | [Remove Duplicates from Sorted List II](https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii) | [C](./src/82.c) | Medium | +| 83 | [Remove Duplicates from Sorted List](https://leetcode.com/problems/remove-duplicates-from-sorted-list) | [C](./src/83.c) | Easy | +| 94 | [Binary Tree Inorder Traversal](https://leetcode.com/problems/binary-tree-inorder-traversal) | [C](./src/94.c) | Easy | +| 98 | [Validate Binary Search Tree](https://leetcode.com/problems/validate-binary-search-tree) | [C](./src/98.c) | Medium | +| 101 | [Symmetric Tree](https://leetcode.com/problems/symmetric-tree) | [C](./src/101.c) | Easy | +| 104 | [Maximum Depth of Binary Tree](https://leetcode.com/problems/maximum-depth-of-binary-tree) | [C](./src/104.c) | Easy | +| 108 | [Convert Sorted Array to Binary Search Tree](https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree) | [C](./src/108.c) | Easy | +| 109 | [Convert Sorted List to Binary Search Tree](https://leetcode.com/problems/convert-sorted-list-to-binary-search-tree) | [C](./src/109.c) | Medium | +| 110 | [Balanced Binary Tree](https://leetcode.com/problems/balanced-binary-tree) | [C](./src/110.c) | Easy | +| 112 | [Path Sum](https://leetcode.com/problems/path-sum) | [C](./src/112.c) | Easy | +| 118 | [Pascal's Triangle](https://leetcode.com/problems/pascals-triangle) | [C](./src/118.c) | Easy | +| 119 | [Pascal's Triangle II](https://leetcode.com/problems/pascals-triangle-ii) | [C](./src/119.c) | Easy | +| 121 | [Best Time to Buy and Sell Stock](https://leetcode.com/problems/best-time-to-buy-and-sell-stock) | [C](./src/121.c) | Easy | +| 124 | [Binary Tree Maximum Path Sum](https://leetcode.com/problems/binary-tree-maximum-path-sum) | [C](./src/124.c) | Hard | +| 125 | [Valid Palindrome](https://leetcode.com/problems/valid-palindrome) | [C](./src/125.c) | Easy | +| 136 | [Single Number](https://leetcode.com/problems/single-number) | [C](./src/136.c) | Easy | +| 141 | [Linked List Cycle](https://leetcode.com/problems/linked-list-cycle) | [C](./src/141.c) | Easy | +| 142 | [Linked List Cycle II](https://leetcode.com/problems/linked-list-cycle-ii) | [C](./src/142.c) | Medium | +| 153 | [Find Minimum in Rotated Sorted Array](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array) | [C](./src/153.c) | Medium | +| 160 | [Intersection of Two Linked Lists](https://leetcode.com/problems/intersection-of-two-linked-lists) | [C](./src/160.c) | Easy | +| 169 | [Majority Element](https://leetcode.com/problems/majority-element) | [C](./src/169.c) | Easy | +| 173 | [Binary Search Tree Iterator](https://leetcode.com/problems/binary-search-tree-iterator) | [C](./src/173.c) | Medium | +| 189 | [Rotate Array](https://leetcode.com/problems/rotate-array) | [C](./src/189.c) | Medium | +| 190 | [Reverse Bits](https://leetcode.com/problems/reverse-bits) | [C](./src/190.c) | Easy | +| 191 | [Number of 1 Bits](https://leetcode.com/problems/number-of-1-bits) | [C](./src/191.c) | Easy | +| 201 | [Bitwise AND of Numbers Range](https://leetcode.com/problems/bitwise-and-of-numbers-range) | [C](./src/201.c) | Medium | +| 203 | [Remove Linked List Elements](https://leetcode.com/problems/remove-linked-list-elements) | [C](./src/203.c) | Easy | +| 206 | [Reverse Linked List](https://leetcode.com/problems/reverse-linked-list) | [C](./src/206.c) | Easy | +| 215 | [Kth Largest Element in an Array](https://leetcode.com/problems/kth-largest-element-in-an-array) | [C](./src/215.c) | Medium | +| 217 | [Contains Duplicate](https://leetcode.com/problems/contains-duplicate) | [C](./src/217.c) | Easy | +| 223 | [Rectangle Area](https://leetcode.com/problems/rectangle-area) | [C](./src/223.c) | Medium | +| 226 | [Invert Binary Tree](https://leetcode.com/problems/invert-binary-tree) | [C](./src/226.c) | Easy | +| 230 | [Kth Smallest Element in a BST](https://leetcode.com/problems/kth-smallest-element-in-a-bst) | [C](./src/230.c) | Medium | +| 231 | [Power of Two](https://leetcode.com/problems/power-of-two) | [C](./src/231.c) | Easy | +| 234 | [Palindrome Linked List](https://leetcode.com/problems/palindrome-linked-list) | [C](./src/234.c) | Easy | +| 236 | [Lowest Common Ancestor of a Binary Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree) | [C](./src/236.c) | Medium | +| 242 | [Valid Anagram](https://leetcode.com/problems/valid-anagram) | [C](./src/242.c) | Easy | +| 268 | [Missing Number](https://leetcode.com/problems/missing-number) | [C](./src/268.c) | Easy | +| 274 | [H-Index](https://leetcode.com/problems/h-index) | [C](./src/274.c) | Medium | +| 278 | [First Bad Version](https://leetcode.com/problems/first-bad-version) | [C](./src/278.c) | Easy | +| 283 | [Move Zeroes](https://leetcode.com/problems/move-zeroes) | [C](./src/283.c) | Easy | +| 287 | [Find the Duplicate Number](https://leetcode.com/problems/find-the-duplicate-number) | [C](./src/287.c) | Medium | +| 344 | [Reverse String](https://leetcode.com/problems/reverse-string) | [C](./src/344.c) | Easy | +| 367 | [Valid Perfect Square](https://leetcode.com/problems/valid-perfect-square) | [C](./src/367.c) | Easy | +| 387 | [First Unique Character in a String](https://leetcode.com/problems/first-unique-character-in-a-string) | [C](./src/387.c) | Easy | +| 389 | [Find the Difference](https://leetcode.com/problems/find-the-difference) | [C](./src/389.c) | Easy | +| 404 | [Sum of Left Leaves](https://leetcode.com/problems/sum-of-left-leaves) | [C](./src/404.c) | Easy | +| 434 | [Number of Segments in a String](https://leetcode.com/problems/number-of-segments-in-a-string) | [C](./src/434.c) | Easy | +| 442 | [Find All Duplicates in an Array](https://leetcode.com/problems/find-all-duplicates-in-an-array) | [C](./src/442.c) | Medium | +| 461 | [Hamming Distance](https://leetcode.com/problems/hamming-distance) | [C](./src/461.c) | Easy | +| 476 | [Number Complement](https://leetcode.com/problems/number-complement) | [C](./src/476.c) | Easy | +| 485 | [Max Consecutive Ones](https://leetcode.com/problems/max-consecutive-ones) | [C](./src/485.c) | Easy | +| 509 | [Fibonacci Number](https://leetcode.com/problems/fibonacci-number) | [C](./src/509.c) | Easy | +| 520 | [Detect Capital](https://leetcode.com/problems/detect-capital) | [C](./src/520.c) | Easy | +| 540 | [Single Element in a Sorted Array](https://leetcode.com/problems/single-element-in-a-sorted-array) | [C](./src/540.c) | Medium | +| 561 | [Array Partition](https://leetcode.com/problems/array-partition) | [C](./src/561.c) | Easy | +| 567 | [Permutation in String](https://leetcode.com/problems/permutation-in-string) | [C](./src/567.c) | Medium | +| 617 | [Merge Two Binary Trees](https://leetcode.com/problems/merge-two-binary-trees) | [C](./src/617.c) | Easy | +| 647 | [Palindromic Substrings](https://leetcode.com/problems/palindromic-substrings) | [C](./src/647.c) | Medium | +| 669 | [Trim a Binary Search Tree](https://leetcode.com/problems/trim-a-binary-search-tree) | [C](./src/669.c) | Medium | +| 674 | [Longest Continuous Increasing Subsequence](https://leetcode.com/problems/longest-continuous-increasing-subsequence) | [C](./src/674.c) | Easy | +| 684 | [Redundant Connection](https://leetcode.com/problems/redundant-connection) | [C](./src/684.c) | Medium | +| 700 | [Search in a Binary Search Tree](https://leetcode.com/problems/search-in-a-binary-search-tree) | [C](./src/700.c) | Easy | +| 701 | [Insert into a Binary Search Tree](https://leetcode.com/problems/insert-into-a-binary-search-tree) | [C](./src/701.c) | Medium | +| 704 | [Binary Search](https://leetcode.com/problems/binary-search) | [C](./src/704.c) | Easy | +| 709 | [To Lower Case](https://leetcode.com/problems/to-lower-case) | [C](./src/709.c) | Easy | +| 771 | [Jewels and Stones](https://leetcode.com/problems/jewels-and-stones) | [C](./src/771.c) | Easy | +| 807 | [Max Increase to Keep City Skyline](https://leetcode.com/problems/max-increase-to-keep-city-skyline) | [C](./src/807.c) | Medium | +| 841 | [Keys and Rooms](https://leetcode.com/problems/keys-and-rooms) | [C](./src/841.c) | Medium | +| 852 | [Peak Index in a Mountain Array](https://leetcode.com/problems/peak-index-in-a-mountain-array) | [C](./src/852.c) | Medium | +| 876 | [Middle of the Linked List](https://leetcode.com/problems/middle-of-the-linked-list) | [C](./src/876.c) | Easy | +| 901 | [Online Stock Span](https://leetcode.com/problems/online-stock-span) | [C](./src/901.c) | Medium | +| 905 | [Sort Array By Parity](https://leetcode.com/problems/sort-array-by-parity) | [C](./src/905.c) | Easy | +| 917 | [Reverse Only Letters](https://leetcode.com/problems/reverse-only-letters) | [C](./src/917.c) | Easy | +| 931 | [Minimum Falling Path Sum](https://leetcode.com/problems/minimum-falling-path-sum) | [C](./src/931.c) | Medium | +| 938 | [Range Sum of BST](https://leetcode.com/problems/range-sum-of-bst) | [C](./src/938.c) | Easy | +| 953 | [Verifying an Alien Dictionary](https://leetcode.com/problems/verifying-an-alien-dictionary) | [C](./src/953.c) | Easy | +| 965 | [Univalued Binary Tree](https://leetcode.com/problems/univalued-binary-tree) | [C](./src/965.c) | Easy | +| 977 | [Squares of a Sorted Array](https://leetcode.com/problems/squares-of-a-sorted-array) | [C](./src/977.c) | Easy | +| 979 | [Distribute Coins in Binary Tree](https://leetcode.com/problems/distribute-coins-in-binary-tree) | [C](./src/979.c) | Medium | +| 985 | [Sum of Even Numbers After Queries](https://leetcode.com/problems/sum-of-even-numbers-after-queries) | [C](./src/985.c) | Medium | +| 997 | [Find the Town Judge](https://leetcode.com/problems/find-the-town-judge) | [C](./src/997.c) | Easy | +| 1008 | [Construct Binary Search Tree from Preorder Traversal](https://leetcode.com/problems/construct-binary-search-tree-from-preorder-traversal) | [C](./src/1008.c) | Medium | +| 1009 | [Complement of Base 10 Integer](https://leetcode.com/problems/complement-of-base-10-integer) | [C](./src/1009.c) | Easy | +| 1019 | [Next Greater Node In Linked List](https://leetcode.com/problems/next-greater-node-in-linked-list) | [C](./src/1019.c) | Medium | +| 1026 | [Maximum Difference Between Node and Ancestor](https://leetcode.com/problems/maximum-difference-between-node-and-ancestor) | [C](./src/1026.c) | Medium | +| 1089 | [Duplicate Zeros](https://leetcode.com/problems/duplicate-zeros) | [C](./src/1089.c) | Easy | +| 1137 | [N-th Tribonacci Number](https://leetcode.com/problems/n-th-tribonacci-number) | [C](./src/1137.c) | Easy | +| 1147 | [Longest Chunked Palindrome Decomposition](https://leetcode.com/problems/longest-chunked-palindrome-decomposition) | [C](./src/1147.c) | Hard | +| 1184 | [Distance Between Bus Stops](https://leetcode.com/problems/distance-between-bus-stops) | [C](./src/1184.c) | Easy | +| 1189 | [Maximum Number of Balloons](https://leetcode.com/problems/maximum-number-of-balloons) | [C](./src/1189.c) | Easy | +| 1207 | [Unique Number of Occurrences](https://leetcode.com/problems/unique-number-of-occurrences) | [C](./src/1207.c) | Easy | +| 1283 | [Find the Smallest Divisor Given a Threshold](https://leetcode.com/problems/find-the-smallest-divisor-given-a-threshold) | [C](./src/1283.c) | Medium | +| 1524 | [Number of Sub-arrays With Odd Sum](https://leetcode.com/problems/number-of-sub-arrays-with-odd-sum) | [C](./src/1524.c) | Medium | +| 1653 | [Minimum Deletions to Make String Balanced](https://leetcode.com/problems/minimum-deletions-to-make-string-balanced) | [C](./src/1653.c) | Medium | +| 1657 | [Determine if Two Strings Are Close](https://leetcode.com/problems/determine-if-two-strings-are-close) | [C](./src/1657.c) | Medium | +| 1695 | [Maximum Erasure Value](https://leetcode.com/problems/maximum-erasure-value) | [C](./src/1695.c) | Medium | +| 1704 | [Determine if String Halves Are Alike](https://leetcode.com/problems/determine-if-string-halves-are-alike) | [C](./src/1704.c) | Easy | +| 1752 | [Check if Array Is Sorted and Rotated](https://leetcode.com/problems/check-if-array-is-sorted-and-rotated) | [C](./src/1752.c) | Easy | +| 1769 | [Minimum Number of Operations to Move All Balls to Each Box](https://leetcode.com/problems/minimum-number-of-operations-to-move-all-balls-to-each-box) | [C](./src/1769.c) | Medium | +| 1833 | [Maximum Ice Cream Bars](https://leetcode.com/problems/maximum-ice-cream-bars) | [C](./src/1833.c) | Medium | +| 1838 | [Frequency of the Most Frequent Element](https://leetcode.com/problems/frequency-of-the-most-frequent-element) | [C](./src/1838.c) | Medium | +| 2024 | [Maximize the Confusion of an Exam](https://leetcode.com/problems/maximize-the-confusion-of-an-exam) | [C](./src/2024.c) | Medium | +| 2095 | [Delete the Middle Node of a Linked List](https://leetcode.com/problems/delete-the-middle-node-of-a-linked-list) | [C](./src/2095.c) | Medium | +| 2125 | [Number of Laser Beams in a Bank](https://leetcode.com/problems/number-of-laser-beams-in-a-bank) | [C](./src/2125.c) | Medium | +| 2130 | [Maximum Twin Sum of a Linked List](https://leetcode.com/problems/maximum-twin-sum-of-a-linked-list) | [C](./src/2130.c) | Medium | +| 2222 | [Number of Ways to Select Buildings](https://leetcode.com/problems/number-of-ways-to-select-buildings) | [C](./src/2222.c) | Medium | +| 2256 | [Minimum Average Difference](https://leetcode.com/problems/minimum-average-difference) | [C](./src/2256.c) | Medium | +| 2270 | [Number of Ways to Split Array](https://leetcode.com/problems/number-of-ways-to-split-array) | [C](./src/2270.c) | Medium | +| 2279 | [Maximum Bags With Full Capacity of Rocks](https://leetcode.com/problems/maximum-bags-with-full-capacity-of-rocks) | [C](./src/2279.c) | Medium | +| 2304 | [Minimum Path Cost in a Grid](https://leetcode.com/problems/minimum-path-cost-in-a-grid) | [C](./src/2304.c) | Medium | +| 2482 | [Difference Between Ones and Zeros in Row and Column](https://leetcode.com/problems/difference-between-ones-and-zeros-in-row-and-column) | [C](./src/2482.c) | Medium | +| 2501 | [Longest Square Streak in an Array](https://leetcode.com/problems/longest-square-streak-in-an-array) | [C](./src/2501.c) | Medium | diff --git a/leetcode/README.md b/leetcode/README.md new file mode 100644 index 0000000000..8f938b440a --- /dev/null +++ b/leetcode/README.md @@ -0,0 +1,69 @@ +# 📚 Contributing 📚 + +We're glad you're interested in adding C LeetCode solutions to the repository.\ +Here we'll be explaining how to contribute to LeetCode solutions properly. + +## 💻 Cloning/setting up the project 💻 + +First off, you'll need to fork the repository [**here**](https://github.com/TheAlgorithms/C/fork).\ +Then, you'll need to clone the repository to your local machine. + +```bash +git clone https://github.com/your-username/C.git +``` + +After that, you'll need to create a new branch for your solution. + +```bash +git checkout -b solution/your-solution-name +``` + +## 📝 Adding a new solution 📝 + +All LeetCode problems can be found [**here**](https://leetcode.com/problemset/all/).\ +If you have a solution to any of these problems (which are not being [**repeated**](https://github.com/TheAlgorithms/C/blob/master/leetcode/DIRECTORY.md)), that's great! Here are the steps: + +1. Add a new file in `leetcode/src` with the number of the problem. + - For example: if the problem's number is 98, the filename should be `98.c`. +2. Provide a small description of the solution at the top of the file. A function should go below that. For example: + +```c +/** + * Return an array of arrays of size *returnSize. + * The sizes of the arrays are returned as *returnColumnSizes array. + * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free(). + */ +``` + +3. Do not provide a `main` function. Use the required standalone functions instead. +4. Doxygen documentation isn't used in LeetCode solutions. Simple/small documentation or comments should be fine. +5. Don't include libraries/headers such as `stdio.h`. Your file should be the solution to the problem only. + +> **Note** +> There was a requirement to update the `leetcode/DIRECTORY.md` file with details of the solved problem. It's not required anymore. The information about the problem is fetched automatically throughout the LeetCode API. + +## 📦 Committing your changes 📦 + +Once you're done with adding a new LeetCode solution, it's time we make a pull request. + +1. First, stage your changes. + +```bash +git add leetcode/src/98.c # Use `git add .` to stage all changes. +``` + +2. Then, commit your changes. + +```bash +git commit -m "feat: add LeetCode problem 98" -m "Commit description" # Optional +``` + +3. Finally, push your changes to your forked repository. + +```bash +git push origin solution/your-solution-name:solution/your-solution-name +``` + +4. You're done now! You just have to make a [**pull request**](https://github.com/TheAlgorithms/C/compare). 🎉 + +If you need any help, don't hesitate to ask and join our [**Discord server**](https://the-algorithms.com/discord)! 🙂 diff --git a/leetcode/src/1.c b/leetcode/src/1.c new file mode 100644 index 0000000000..53f260a10b --- /dev/null +++ b/leetcode/src/1.c @@ -0,0 +1,17 @@ +int *twoSum(int *nums, int numsSize, int target, int *returnSize) +{ + int i, j; + int *ret = calloc(2, sizeof(int)); + for (i = 0; i < numsSize; i++) + { + int key = target - nums[i]; + for (j = i + 1; j < numsSize; j++) + if (nums[j] == key) + { + ret[0] = i; + ret[1] = j; + } + } + *returnSize = 2; + return ret; +} diff --git a/leetcode/src/10.c b/leetcode/src/10.c new file mode 100644 index 0000000000..26ed6a3b89 --- /dev/null +++ b/leetcode/src/10.c @@ -0,0 +1,59 @@ +/* +Prompt: + +Given an input string s and a pattern p, implement regular expression matching with support for '.' and '*' where: +- '.' Matches any single character. +- '*' Matches zero or more of the preceding element. +The matching should cover the entire input string (not partial). + +Constraints: + +1 <= s.length <= 20 +1 <= p.length <= 30 +s contains only lowercase English letters. +p contains only lowercase English letters, '.', and '*'. + +It is guaranteed for each appearance of the character '*', there will be a previous valid character to match. +*/ + +bool isMatch(char* s, char* p); +bool matchStar(char ch, char* s, char* p); + +/* +Uses Rob pikes Regexp matcher - https://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html +Implementation: + // match: search for regexp anywhere in text + int match(char *regexp, char *text) + { + if (regexp[0] == '^') + return matchhere(regexp+1, text); + do { + if (matchhere(regexp, text)) + return 1; + } while (*text++ != '\0'); + return 0; + } +*/ + +bool matchStar(char ch, char* s, char* p) { + do { + if (isMatch(s, p)) + return true; + } while (*s != '\0' && (*s++ == ch || ch == '.')); + + return false; +} + +bool isMatch(char* s, char* p) { + if (*p == '\0') + return *s == '\0'; + + if (p[1] == '*') + return matchStar(p[0], s, p + 2); + + if (*s != '\0' && (p[0] == '.' || *p == *s)) { + return isMatch(s + 1, p + 1); + } + + return false; +} diff --git a/leetcode/src/1008.c b/leetcode/src/1008.c new file mode 100644 index 0000000000..ce4871ecd4 --- /dev/null +++ b/leetcode/src/1008.c @@ -0,0 +1,39 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * struct TreeNode *left; + * struct TreeNode *right; + * }; + */ + +struct TreeNode* bstFromPreorder(int* preorder, int preorderSize) +{ + struct TreeNode* new; + int left_ptr; + + new = malloc(sizeof(struct TreeNode)); + new->val = preorder[0]; + + if (preorderSize == 1) + { + new->right = NULL; + new->left = NULL; + return new; + } + + left_ptr = 1; + while ((left_ptr < preorderSize) && (preorder[left_ptr] < preorder[0])) + left_ptr++; + if (left_ptr == 1) + new->left = NULL; + else + new->left = bstFromPreorder(preorder + 1, left_ptr - 1); + if (left_ptr < preorderSize) + new->right = + bstFromPreorder(preorder + left_ptr, preorderSize - left_ptr); + else + new->right = NULL; + + return new; +} diff --git a/leetcode/src/1009.c b/leetcode/src/1009.c new file mode 100644 index 0000000000..77480d71a7 --- /dev/null +++ b/leetcode/src/1009.c @@ -0,0 +1,15 @@ +// Bit manipulation. +// - Find the bit length of n using log2 +// - Create bit mask of bit length of n +// - Retun ~n and bit of ones mask +// Runtime: O(log2(n)) +// Space: O(1) + +int bitwiseComplement(int n){ + if (n == 0){ + return 1; + } + + int binary_number_length = ceil(log2(n)); + return (~n) & ((1 << binary_number_length) - 1); +} diff --git a/leetcode/src/101.c b/leetcode/src/101.c new file mode 100644 index 0000000000..68a8dc5ed2 --- /dev/null +++ b/leetcode/src/101.c @@ -0,0 +1,23 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * struct TreeNode *left; + * struct TreeNode *right; + * }; + */ + +bool checkSymmetric(struct TreeNode *left, struct TreeNode *right) +{ + if (!left || !right) + return left == right; + if (left->val != right->val) + return 0; + return checkSymmetric(left->left, right->right) && + checkSymmetric(left->right, right->left); +} + +bool isSymmetric(struct TreeNode *root) +{ + return root == NULL || checkSymmetric(root->left, root->right); +} diff --git a/leetcode/src/1019.c b/leetcode/src/1019.c new file mode 100644 index 0000000000..31eca53d72 --- /dev/null +++ b/leetcode/src/1019.c @@ -0,0 +1,29 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * struct ListNode *next; + * }; + */ + +int* nextLargerNodes(struct ListNode* head, int* returnSize) +{ + int *output, count = 0; + struct ListNode *tmp = head, *tmp2; + for (; tmp != NULL; tmp = tmp->next, count++) + ; + output = (int*)calloc(count, sizeof(int)); + *returnSize = count; + for (tmp = head, count = 0; tmp->next != NULL; tmp = tmp->next, count++) + { + for (tmp2 = tmp->next; tmp2 != NULL; tmp2 = tmp2->next) + { + if (tmp2->val > tmp->val) + { + output[count] = tmp2->val; + break; + } + } + } + return output; +} diff --git a/leetcode/src/1026.c b/leetcode/src/1026.c new file mode 100644 index 0000000000..0dda623023 --- /dev/null +++ b/leetcode/src/1026.c @@ -0,0 +1,38 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * struct TreeNode *left; + * struct TreeNode *right; + * }; + */ + +#define max(a,b) (((a)>(b))?(a):(b)) +#define min(a,b) (((a)<(b))?(a):(b)) + +void recursiveSolve(struct TreeNode* node, int* result, int minVal, int maxVal){ + if (node == NULL){ + return; + } + + *result = max(*result, abs(minVal - node->val)); + *result = max(*result, abs(maxVal - node->val)); + + minVal = min(minVal, node->val); + maxVal = max(maxVal, node->val); + + recursiveSolve(node->left, result, minVal, maxVal); + recursiveSolve(node->right, result, minVal, maxVal); +} + +// Depth First Search +// If The maximum diff is exists it should be the difference of the MAX or MIN value in the tree path to the LEAF +// Runtime: O(n) +// Space: O(1) +int maxAncestorDiff(struct TreeNode* root){ + int result = 0; + int maxVal = root->val; + int minVal = root->val; + recursiveSolve(root, &result, minVal, maxVal); + return result; +} diff --git a/leetcode/src/104.c b/leetcode/src/104.c new file mode 100644 index 0000000000..91d8019aad --- /dev/null +++ b/leetcode/src/104.c @@ -0,0 +1,23 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * struct TreeNode *left; + * struct TreeNode *right; + * }; + */ + +int maxval(int a, int b) +{ + if (a > b) + return a; + else + return b; +} +int maxDepth(struct TreeNode *root) +{ + if (root == NULL) + return 0; + else + return 1 + maxval(maxDepth(root->left), maxDepth(root->right)); +} diff --git a/leetcode/src/108.c b/leetcode/src/108.c new file mode 100644 index 0000000000..24ab54983b --- /dev/null +++ b/leetcode/src/108.c @@ -0,0 +1,31 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * struct TreeNode *left; + * struct TreeNode *right; + * }; + */ + +struct TreeNode *convertBST(int *nums, int left, int right) +{ + if (left > right) + return NULL; + else + { + int mid = (right + left) / 2; + struct TreeNode *new_val = malloc(sizeof(struct TreeNode)); + new_val->val = nums[mid]; + new_val->left = convertBST(nums, left, mid - 1); + new_val->right = convertBST(nums, mid + 1, right); + return new_val; + } +} + +struct TreeNode *sortedArrayToBST(int *nums, int numsSize) +{ + if (numsSize == 0) + return NULL; + else + return convertBST(nums, 0, numsSize - 1); +} diff --git a/leetcode/src/1089.c b/leetcode/src/1089.c new file mode 100644 index 0000000000..81c89b8c97 --- /dev/null +++ b/leetcode/src/1089.c @@ -0,0 +1,22 @@ +void duplicateZeros(int *arr, int arrSize) +{ + int i, start = 0; + int *tmp = malloc(arrSize * sizeof(int)); + /* Copy arr into tmp arr */ + for (i = 0; i < arrSize; i++) + { + tmp[i] = arr[i]; + } + i = 0; + for (start = 0; start < arrSize; start++) + { + arr[start] = tmp[i]; + if (tmp[i] == 0) + { + start++; + if (start < arrSize) + arr[start] = 0; + } + i++; + } +} diff --git a/leetcode/src/109.c b/leetcode/src/109.c new file mode 100644 index 0000000000..5daf5ac317 --- /dev/null +++ b/leetcode/src/109.c @@ -0,0 +1,23 @@ +struct TreeNode *buildBST(struct ListNode *head, struct ListNode *tail) +{ + if (head == tail) + return NULL; + struct ListNode *slow = head, *fast = head; + while (fast != tail && fast->next != tail) + { + fast = fast->next->next; + slow = slow->next; + } + struct TreeNode *node = malloc(sizeof(struct TreeNode)); + node->val = slow->val; + node->left = buildBST(head, slow); + node->right = buildBST(slow->next, tail); + return node; +} +struct TreeNode *sortedListToBST(struct ListNode *head) +{ + if (!head) + return NULL; + else + return buildBST(head, NULL); +} diff --git a/leetcode/src/11.c b/leetcode/src/11.c new file mode 100644 index 0000000000..5a38ebc547 --- /dev/null +++ b/leetcode/src/11.c @@ -0,0 +1,27 @@ +// Fucntion to calculate min of values a and b +int min(int a, int b) { return ((a < b) ? a : b); } + +// Two pointer approach to find maximum container area +int maxArea(int *height, int heightSize) +{ + // Start with maximum container width + int start = 0; + int end = heightSize - 1; + int res = 0; + + while (start < end) + { + // Calculate current area by taking minimum of two heights + int currArea = (end - start) * min(height[start], height[end]); + + if (currArea > res) + res = currArea; + + if (height[start] < height[end]) + start = start + 1; + else + end = end - 1; + } + + return res; +} diff --git a/leetcode/src/110.c b/leetcode/src/110.c new file mode 100644 index 0000000000..639feab6e3 --- /dev/null +++ b/leetcode/src/110.c @@ -0,0 +1,19 @@ +int max(int a, int b) { return a >= b ? a : b; } + +int height(struct TreeNode *root) +{ + if (root == NULL) + return 0; + else + return 1 + max(height(root->left), height(root->right)); +} + +bool isBalanced(struct TreeNode *root) +{ + if (root == NULL) + return 1; + int left = height(root->left); + int right = height(root->right); + return abs(left - right) <= 1 && isBalanced(root->left) && + isBalanced(root->right); +} diff --git a/leetcode/src/112.c b/leetcode/src/112.c new file mode 100644 index 0000000000..dc3256d96e --- /dev/null +++ b/leetcode/src/112.c @@ -0,0 +1,9 @@ +bool hasPathSum(struct TreeNode *root, int sum) +{ + if (root == NULL) + return 0; + if (!root->left && !root->right && sum - root->val == 0) + return 1; + return hasPathSum(root->left, sum - root->val) || + hasPathSum(root->right, sum - root->val); +} diff --git a/leetcode/src/1137.c b/leetcode/src/1137.c new file mode 100644 index 0000000000..0bb7fdc38a --- /dev/null +++ b/leetcode/src/1137.c @@ -0,0 +1,29 @@ +// Dynamic Programming +// Runtime: O(n) +// Space: O(1) +int tribonacci(int n){ + int t0 = 0; + int t1 = 1; + int t2 = 1; + + if (n == 0) { + return t0; + } + + if (n == 1){ + return t1; + } + + if (n == 2){ + return t2; + } + + for (int i = 0; i < n - 2; i++){ + int nextT = t0 + t1 + t2; + t0 = t1; + t1 = t2; + t2 = nextT; + } + + return t2; +} diff --git a/leetcode/src/1147.c b/leetcode/src/1147.c new file mode 100644 index 0000000000..501060d098 --- /dev/null +++ b/leetcode/src/1147.c @@ -0,0 +1,49 @@ +#define max(a,b) (((a)>(b))?(a):(b)) + +bool equalSubstrings(char* text, int firstIndex, int secondIndex, int length){ + for (int i = 0; i < length; i++){ + if (text[firstIndex + i] != text[secondIndex + i]){ + return false; + } + } + + return true; +} + +int longestDecompositionDpCached(char* text, int textLen, int index, int* dp){ + if (2 * index >= textLen){ + return 0; + } + + if (dp[index] == 0){ + dp[index] = longestDecompositionDp(text, textLen, index, dp); + } + + return dp[index]; +} + +int longestDecompositionDp(char* text, int textLen, int index, int* dp){ + char ch = text[index]; + int result = 1; + + for (int i = 0; i < (textLen - 2 * index) / 2; i++){ + if (ch == text[textLen - 1 - index - i] + && equalSubstrings(text, index, textLen - 1 - index - i, i + 1)){ + return max(result, 2 + longestDecompositionDpCached(text, textLen, index + i + 1, dp)); + } + } + + return result; +} + +// Dynamic programming. Up -> down approach. +// Runtime: O(n*n) +// Space: O(n) +int longestDecomposition(char * text){ + int textLen = strlen(text); + int* dp = calloc(textLen, sizeof(int)); + int result = longestDecompositionDpCached(text, textLen, 0, dp); + + free(dp); + return result; +} diff --git a/leetcode/src/118.c b/leetcode/src/118.c new file mode 100644 index 0000000000..a926efdcb1 --- /dev/null +++ b/leetcode/src/118.c @@ -0,0 +1,26 @@ +/** + * Return an array of arrays of size *returnSize. + * The sizes of the arrays are returned as *returnColumnSizes array. + * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free(). + */ +int** generate(int numRows, int* returnSize, int** returnColumnSizes){ + *returnSize = numRows; + int **ans = (int**)malloc(numRows*sizeof(int*)); + *returnColumnSizes = (int*)malloc(numRows*sizeof(int)); + + for (int i=0; i destination) + { + int tmp = start; + start = destination; + destination = tmp; + } + for (auto i = 0; i < distanceSize; ++i) + { + if (i >= start && i < destination) + sum1 += distance[i]; + else + sum2 += distance[i]; + } + return sum1 < sum2 ? sum1 : sum2; +} diff --git a/leetcode/src/1189.c b/leetcode/src/1189.c new file mode 100644 index 0000000000..c1af4453b0 --- /dev/null +++ b/leetcode/src/1189.c @@ -0,0 +1,51 @@ +int maxNumberOfBalloons(char *text) +{ + /* + 0 -> b, + 1 -> a, + 2 -> l, + 3 -> o, + 4 -> n + */ + int count_letters[5] = {0}; + int i, min_counter_ballons; + + for (char *ptr = text; *ptr; ptr++) + { + if (*ptr == 'b') + { + count_letters[0]++; + } + else if (*ptr == 'a') + { + count_letters[1]++; + } + else if (*ptr == 'l') + { + count_letters[2]++; + } + else if (*ptr == 'o') + { + count_letters[3]++; + } + else if (*ptr == 'n') + { + count_letters[4]++; + } + } + + /* Divide by 2 the repeted letters */ + count_letters[2] /= 2; + count_letters[3] /= 2; + + /* Max number of times which we can write ballon is equal to min value of + * letters on count_letter */ + min_counter_ballons = count_letters[0]; + for (i = 1; i < 5; i++) + { + if (count_letters[i] < min_counter_ballons) + min_counter_ballons = count_letters[i]; + } + + return min_counter_ballons; +} diff --git a/leetcode/src/119.c b/leetcode/src/119.c new file mode 100644 index 0000000000..a4b6f7a921 --- /dev/null +++ b/leetcode/src/119.c @@ -0,0 +1,22 @@ +/** + * Note: The returned array must be malloced, assume caller calls free(). + */ +int* getRow(int rowIndex, int* returnSize){ + int colIndex = rowIndex + 1; + int* ans = (int*) malloc(sizeof(int) * colIndex); + for (int i = 0; i < colIndex; i++) + { + ans[i] = 1; + } + *returnSize = colIndex; + + for (int r = 2; r <= rowIndex; r++) + { + for (int c = r - 1; c > 0; c--) + { + ans[c] = ans[c] + ans[c-1]; + } + } + + return ans; +} diff --git a/leetcode/src/12.c b/leetcode/src/12.c new file mode 100644 index 0000000000..b8d8f7c04f --- /dev/null +++ b/leetcode/src/12.c @@ -0,0 +1,172 @@ +char *getOne(char c) +{ + switch (c) + { + case '9': + return "IX"; + + case '8': + return "VIII"; + + case '7': + return "VII"; + + case '6': + return "VI"; + + case '5': + return "V"; + + case '4': + return "IV"; + + case '3': + return "III"; + + case '2': + return "II"; + + case '1': + return "I"; + + case '0': + return ""; + + default: + return NULL; + } +} + +char *getTen(char c) +{ + switch (c) + { + case '9': + return "XC"; + + case '8': + return "LXXX"; + + case '7': + return "LXX"; + + case '6': + return "LX"; + + case '5': + return "L"; + + case '4': + return "XL"; + + case '3': + return "XXX"; + + case '2': + return "XX"; + + case '1': + return "X"; + + case '0': + return ""; + + default: + return NULL; + } +} + +char *getHundred(char c) +{ + switch (c) + { + case '9': + return "CM"; + + case '8': + return "DCCC"; + + case '7': + return "DCC"; + + case '6': + return "DC"; + + case '5': + return "D"; + + case '4': + return "CD"; + + case '3': + return "CCC"; + + case '2': + return "CC"; + + case '1': + return "C"; + + case '0': + return ""; + + default: + return NULL; + } +} + +char *getThousand(char c) +{ + switch (c) + { + case '3': + return "MMM"; + + case '2': + return "MM"; + + case '1': + return "M"; + + default: + return NULL; + } +} + +char *intToRoman(int num) +{ + int length; + char number[5]; + char *s = malloc(16 * sizeof(char)); + + sprintf(number, "%i", num); + + length = strlen(number); + + switch (length) + { + case 4: + sprintf(s, "%s%s%s%s", getThousand(number[0]), getHundred(number[1]), + getTen(number[2]), getOne(number[3])); + break; + + case 3: + sprintf(s, "%s%s%s", getHundred(number[0]), getTen(number[1]), + getOne(number[2])); + + break; + + case 2: + sprintf(s, "%s%s", getTen(number[0]), getOne(number[1])); + + break; + + case 1: + s = getOne(number[0]); + break; + + default: + break; + } + return s; +} diff --git a/leetcode/src/1207.c b/leetcode/src/1207.c new file mode 100644 index 0000000000..8c8eb8dc02 --- /dev/null +++ b/leetcode/src/1207.c @@ -0,0 +1,26 @@ +#define MAP_SIZE 2048 + +int cmpvalue(const void *a, const void *b) { return *(int *)b - *(int *)a; } +bool uniqueOccurrences(int *arr, int arrSize) +{ + int *map = calloc(MAP_SIZE, sizeof(int)); + int i; + for (i = 0; i < arrSize; i++) + { + if (arr[i] < 0) + map[arr[i] + MAP_SIZE / 2] += 1; + else + map[arr[i]] += 1; + } + /* number of occurrences is sorted by decreasing order + Ex: 3 2 1 0 0 0 0 */ + qsort(map, MAP_SIZE, sizeof(int), cmpvalue); + i = 0; + while (map[i]) + { + if (map[i] == map[i + 1]) + return 0; + i++; + } + return 1; +} diff --git a/leetcode/src/121.c b/leetcode/src/121.c new file mode 100644 index 0000000000..43d3b6a7c8 --- /dev/null +++ b/leetcode/src/121.c @@ -0,0 +1,17 @@ +int maxcmp(int a, int b) { return (a >= b) ? a : b; } + +/* max subarray problem by using Kadane's Algorithm + */ +int maxProfit(int *prices, int pricesSize) +{ + /* maxCur: current maximum + * maxSoFar: found maximum for subarray so far + */ + int maxCur = 0, maxSoFar = 0; + for (int i = 1; i < pricesSize; i++) + { + maxCur = maxcmp(0, maxCur + prices[i] - prices[i - 1]); + maxSoFar = maxcmp(maxSoFar, maxCur); + } + return maxSoFar; +} diff --git a/leetcode/src/124.c b/leetcode/src/124.c new file mode 100644 index 0000000000..a846dfcb44 --- /dev/null +++ b/leetcode/src/124.c @@ -0,0 +1,36 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * struct TreeNode *left; + * struct TreeNode *right; + * }; + */ + +#define max(a,b) (((a)>(b))?(a):(b)) + +int recursiveSolve(struct TreeNode* node, int* result){ + if (node == NULL){ + return 0; + } + + int leftSum = max(recursiveSolve(node->left, result), 0); + int rightSum = max(recursiveSolve(node->right, result), 0); + + // Check if it's possible to make a maximum path from left right and current node + int maxValueNode = node->val + leftSum + rightSum; + *result = max(maxValueNode, *result); + + // Choose the max sum val path + return node->val + max(leftSum, rightSum); +} + +// Depth First Search +// Runtime: O(n), n - the number of nodes in tree. +// Space: O(1) +int maxPathSum(struct TreeNode* root){ + const int LOWER_BOUND = -2147483648 + int result = LOWER_BOUND; + recursiveSolve(root, &result); + return result; +} diff --git a/leetcode/src/125.c b/leetcode/src/125.c new file mode 100644 index 0000000000..07a210b0a5 --- /dev/null +++ b/leetcode/src/125.c @@ -0,0 +1,25 @@ +bool isPalindrome(char *s) +{ + int start = 0, end = strlen(s) - 1; + while (start < end) + { + if (!isalpha(s[start]) && !isalnum(s[start])) + { + start++; + } + else if (!isalpha(s[end]) && !isalnum(s[end])) + { + end--; + } + else + { + char c1 = tolower(s[start]); + char c2 = tolower(s[end]); + if (c1 != c2) + return 0; + start++; + end--; + } + } + return 1; +} diff --git a/leetcode/src/1283.c b/leetcode/src/1283.c new file mode 100644 index 0000000000..ccdf9e2980 --- /dev/null +++ b/leetcode/src/1283.c @@ -0,0 +1,44 @@ +#define max(a,b) (((a)>(b))?(a):(b)) + +long getSum(int* nums, int numsSize, int divizor){ + long result = 0; + for (int i = 0; i < numsSize; i++){ + int value = nums[i] / divizor; + if (value * divizor != nums[i]){ + value++; + } + + result += value; + } + + return result; +} + +// Divide and conquer +// Runtime: O(n*log(n)) +// Space: O(1) +int smallestDivisor(int* nums, int numsSize, int threshold){ + int maxNum = 0; + for (int i = 0; i < numsSize; i++){ + maxNum = max(maxNum, nums[i]); + } + + int left = 1; + int right = maxNum; + while (left <= right){ + int middle = (left + right) / 2; + long middleSum = getSum(nums, numsSize, middle); + if (middleSum <= threshold && (middle == 1 || getSum(nums, numsSize, middle - 1) > threshold)){ + return middle; + } + + if (middleSum > threshold){ + left = middle + 1; + } + else{ + right = middle - 1; + } + } + + return -1; +} diff --git a/leetcode/src/13.c b/leetcode/src/13.c new file mode 100644 index 0000000000..1450813bec --- /dev/null +++ b/leetcode/src/13.c @@ -0,0 +1,58 @@ +int romanToInt(char *s) +{ + int romanToInt = 0; + for (int i = 0; i < strlen(s); i++) + { + switch (s[i]) + { + case 'I': + if (i + 1 < strlen(s)) + { + if (s[i + 1] == 'V' || s[i + 1] == 'X') + { + romanToInt -= 1; + break; + } + } + romanToInt += 1; + break; + case 'V': + romanToInt += 5; + break; + case 'X': + if (i + 1 < strlen(s)) + { + if (s[i + 1] == 'L' || s[i + 1] == 'C') + { + romanToInt -= 10; + break; + } + } + romanToInt += 10; + break; + case 'L': + romanToInt += 50; + break; + case 'C': + if (i + 1 < strlen(s)) + { + if (s[i + 1] == 'D' || s[i + 1] == 'M') + { + romanToInt -= 100; + break; + } + } + romanToInt += 100; + break; + case 'D': + romanToInt += 500; + break; + case 'M': + romanToInt += 1000; + break; + default: + break; + } + } + return romanToInt; +} \ No newline at end of file diff --git a/leetcode/src/136.c b/leetcode/src/136.c new file mode 100644 index 0000000000..c18fe933d6 --- /dev/null +++ b/leetcode/src/136.c @@ -0,0 +1,6 @@ +int singleNumber(int *nums, int numsSize) +{ + int i, result = 0; + for (i = 0; i < numsSize; i++) result = result ^ nums[i]; + return result; +} diff --git a/leetcode/src/14.c b/leetcode/src/14.c new file mode 100644 index 0000000000..8f5a22d840 --- /dev/null +++ b/leetcode/src/14.c @@ -0,0 +1,25 @@ +int findMaxConsecutiveOnes(int* nums, int numsSize){ + int i=0; + int maxCount=0; + int count = 0; + + while(inext) + { + fast = fast->next->next; + slow = slow->next; + if (fast == slow) + return true; + } + return false; +} diff --git a/leetcode/src/142.c b/leetcode/src/142.c new file mode 100644 index 0000000000..c45fe586fb --- /dev/null +++ b/leetcode/src/142.c @@ -0,0 +1,23 @@ +struct ListNode *detectCycle(struct ListNode *head) +{ + if (head == NULL || head->next == NULL) + return NULL; + struct ListNode *slow, *fast; + slow = fast = head; + while (fast && fast->next) + { + slow = slow->next; + fast = fast->next->next; + if (slow == fast) + { + struct ListNode *entry = head; + while (slow != entry) + { + slow = slow->next; + entry = entry->next; + } + return entry; + } + } + return NULL; +} diff --git a/leetcode/src/1524.c b/leetcode/src/1524.c new file mode 100644 index 0000000000..46ad3e46d1 --- /dev/null +++ b/leetcode/src/1524.c @@ -0,0 +1,24 @@ +// Counting whole summ. evens sums number and odd summs number. +// Runtime: O(n), +// Space: O(1) +int numOfSubarrays(int* arr, int arrSize){ + int result = 0; + int curSumm = 0; + int currOddSumms = 0; + int currEvenSumm = 0; + int modulo = 1000000000 + 7; + + for(int i = 0; i < arrSize; i++){ + curSumm += arr[i]; + if (curSumm % 2 == 0){ + currEvenSumm++; + result = (result + currOddSumms) % modulo; + } + else { + currOddSumms++; + result = (result + 1 + currEvenSumm) % modulo; + } + } + + return result % modulo; +} diff --git a/leetcode/src/153.c b/leetcode/src/153.c new file mode 100644 index 0000000000..84b8a12a57 --- /dev/null +++ b/leetcode/src/153.c @@ -0,0 +1,15 @@ +int findMin(int *nums, int numsSize) +{ + int low = 0, high = numsSize - 1; + while (low < high) + { + int mid = low + (high - low) / 2; + /* minimum is on left side */ + if (nums[mid] < nums[high]) + high = mid; + /* minimum is on right side */ + else + low = mid + 1; + } + return nums[low]; +} diff --git a/leetcode/src/16.c b/leetcode/src/16.c new file mode 100644 index 0000000000..a3d1cd7ea6 --- /dev/null +++ b/leetcode/src/16.c @@ -0,0 +1,30 @@ +#include // for qsort() + +int cmp(const void* a, const void* b) { + const int *A = a, *B = b; + return (*A > *B) - (*A < *B); +} + +int threeSumClosest(int* nums, int nums_size, int target) { + int i, j, k, result, sum3; + qsort(nums, nums_size, sizeof(int), cmp); + result = nums[0] + nums[1] + nums[2]; + for (i = 0; i < nums_size - 2; i++) { + j = i + 1; + k = nums_size - 1; + while (j < k) { + sum3 = nums[i] + nums[j] + nums[k]; + if (abs(target - sum3) < abs(target - result)) { + result = sum3; + } + if (sum3 < target) { + j++; + } else if (sum3 > target) { + k--; + } else { + return sum3; + } + } + } + return result; +} diff --git a/leetcode/src/160.c b/leetcode/src/160.c new file mode 100644 index 0000000000..bfca759bc3 --- /dev/null +++ b/leetcode/src/160.c @@ -0,0 +1,19 @@ +struct ListNode *getIntersectionNode(struct ListNode *headA, + struct ListNode *headB) +{ + struct ListNode *cur1 = headA, *cur2 = headB; + if (cur1 == NULL || cur2 == NULL) + return NULL; + while (cur1 && cur2 && cur1 != cur2) + { + cur1 = cur1->next; + cur2 = cur2->next; + if (cur1 == cur2) + return cur1; + if (!cur1) + cur1 = headB; + if (!cur2) + cur2 = headA; + } + return cur1; +} diff --git a/leetcode/src/1653.c b/leetcode/src/1653.c new file mode 100644 index 0000000000..04ac0c16b6 --- /dev/null +++ b/leetcode/src/1653.c @@ -0,0 +1,29 @@ +#define min(X, Y) ((X) < (Y) ? (X) : (Y)) + +// Dynamic programming approach. Down -> Up. +// Runtime: O(n) +// Space: O(1) +int minimumDeletions(char * s){ + int len = strlen(s); + + int aStateValue = s[0] == 'b'; + + int bStateValue = 0; + + int newAStateValue; + int newBStateValue; + + for(int i = 1; i < len; i++){ + newAStateValue = aStateValue + (s[i] == 'b'); + + newBStateValue = min( + aStateValue, + bStateValue + (s[i] == 'a') + ); + + aStateValue = newAStateValue; + bStateValue = newBStateValue; + } + + return min(aStateValue, bStateValue); +} diff --git a/leetcode/src/1657.c b/leetcode/src/1657.c new file mode 100644 index 0000000000..10aa60d258 --- /dev/null +++ b/leetcode/src/1657.c @@ -0,0 +1,51 @@ +const charLength = 26; + +int* charsCount(char* word){ + int* result = calloc(charLength, sizeof(int)); + int wordLen = strlen(word); + for (int i = 0; i < wordLen; i++){ + result[word[i] - 'a']++; + } + + return result; +} + +int diff(const int *i, const int *j) +{ + return *i - *j; +} + +// Counting +// Runtime: O(n) +// Space: O(1) +bool closeStrings(char * word1, char * word2){ + int* word1CharsCounter = charsCount(word1); + int* word2CharsCounter = charsCount(word2); + + // The lengths of both string should be equal + if (strlen(word1) != strlen(word2)){ + return false; + } + + // The char should appear in both strings + for (int i = 0; i < charLength; i++){ + if ((word1CharsCounter[i] != 0 && word2CharsCounter[i] == 0) || + (word1CharsCounter[i] == 0 && word2CharsCounter[i] != 0)){ + return false; + } + } + + qsort(word1CharsCounter, charLength, sizeof (int), (int(*) (const void *, const void *)) diff); + qsort(word2CharsCounter, charLength, sizeof (int), (int(*) (const void *, const void *)) diff); + + // appearing of chars should be the same in both strings. + for (int i = 0; i < charLength; i++){ + if (word1CharsCounter[i] != word2CharsCounter[i]){ + return false; + } + } + + free(word1CharsCounter); + free(word2CharsCounter); + return true; +} diff --git a/leetcode/src/169.c b/leetcode/src/169.c new file mode 100644 index 0000000000..6a2215be95 --- /dev/null +++ b/leetcode/src/169.c @@ -0,0 +1,20 @@ +/* Boyer-Moore Majority Vote Algorithm + * http://www.cs.utexas.edu/~moore/best-ideas/mjrty/ */ +int majorityElement(int *nums, int numsSize) +{ + int count = 1; + int majorNum = nums[0]; + for (int i = 1; i < numsSize; i++) + { + if (count == 0) + { + majorNum = nums[i]; + count++; + } + else if (majorNum == nums[i]) + count++; + else + count--; + } + return majorNum; +} diff --git a/leetcode/src/1695.c b/leetcode/src/1695.c new file mode 100644 index 0000000000..c0a57247a0 --- /dev/null +++ b/leetcode/src/1695.c @@ -0,0 +1,29 @@ +// Window sliding. Runtime: O(n), Space: O(n) +int maximumUniqueSubarray(int* nums, int numsSize){ + short* numsSet = (short*)calloc(10001, sizeof(short)); + numsSet[nums[0]] = 1; + + int maxSum = nums[0]; + + int windowSumm = maxSum; + int leftIndex = 0; + + int num = 0; + for(int i = 1; i < numsSize; i++){ + num = nums[i]; + while (numsSet[num] != 0){ + numsSet[nums[leftIndex]] = 0; + windowSumm -= nums[leftIndex]; + leftIndex++; + } + + numsSet[num] = 1; + windowSumm += num; + + if (maxSum < windowSumm){ + maxSum = windowSumm; + } + } + + return maxSum; +} diff --git a/leetcode/src/17.c b/leetcode/src/17.c new file mode 100644 index 0000000000..ff6e77d048 --- /dev/null +++ b/leetcode/src/17.c @@ -0,0 +1,78 @@ +/** + * Letter Combinations of a Phone Number problem + * The algorithm determines the final size of the return array (combs) and allocates + * corresponding letter for each element, assuming that the return array is alphabetically sorted. + * It does so by running two loops for each letter: + * - the first loop determines the starting positions of the sequence of subsequent letter positions + * - the second loop determines the length of each subsequent sequence for each letter + * The size and space complexity are both O("size of final array"), as even though there are 4 loops, + * each element in the final array is accessed only once. + */ + +#include // for the malloc() function +#include // for the strlen() function + +char *get_letters(char digit) { + switch (digit) { + case '2': + return "abc"; + case '3': + return "def"; + case '4': + return "ghi"; + case '5': + return "jkl"; + case '6': + return "mno"; + case '7': + return "pqrs"; + case '8': + return "tuv"; + case '9': + return "wxyz"; + default: + return ""; + } +} + +char **letterCombinations(char *digits, int *return_size) { + char *cp; + int i, j, k, l, ind, k_tot, l_tot, digits_size = 0; + + if (*digits == '\0') { + *return_size = 0; + return NULL; + } + + *return_size = 1; + cp = digits; + while (*cp != '\0') { + *return_size *= strlen(get_letters(*cp)); + digits_size++; + cp++; + } + + char **combs = malloc(sizeof(char*) * (*return_size)); + for (i = 0; i < *return_size; i++) { + combs[i] = malloc(sizeof(char) * (digits_size + 1)); + combs[i][digits_size] = '\0'; + } + + k_tot = 1; + l_tot = (*return_size); + for (i = 0; i < digits_size; i++) { // loop accross digits + cp = get_letters(digits[i]); + l_tot /= strlen(cp); + for (j = 0; j < strlen(cp); j++) { // loop accross letters of the digit + for (k = 0; k < k_tot; k++) { // loop across the subset starting positions for each letter + for (l = 0; l < l_tot; l++) { // loop accross each subset positions for each letter + ind = k * l_tot * strlen(cp) + l + l_tot * j; + combs[ind][i] = cp[j]; + } + } + } + k_tot *= strlen(cp); + } + + return combs; +} diff --git a/leetcode/src/1704.c b/leetcode/src/1704.c new file mode 100644 index 0000000000..25251983bc --- /dev/null +++ b/leetcode/src/1704.c @@ -0,0 +1,38 @@ +bool isVowel(char chr){ + switch(chr){ + case 'a': + case 'e': + case 'i': + case 'o': + case 'u': + case 'A': + case 'E': + case 'I': + case 'O': + case 'U': + return true; + } + + return false; +} + +// Counting +// Runtime: O(n) +// Space: O(1) +bool halvesAreAlike(char * s){ + int lenS = strlen(s); + int halfVowels = 0; + int currVowels = 0; + + for (int i = 0; i < lenS; i++){ + if (isVowel(s[i])){ + currVowels++; + } + + if (2 * (i + 1) == lenS){ + halfVowels = currVowels; + } + } + + return 2 * halfVowels == currVowels; +} diff --git a/leetcode/src/173.c b/leetcode/src/173.c new file mode 100644 index 0000000000..0dcc59964e --- /dev/null +++ b/leetcode/src/173.c @@ -0,0 +1,78 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * struct TreeNode *left; + * struct TreeNode *right; + * }; + */ + +#include + +typedef struct +{ + int *values; + int CurrentIndex; + int NumberOfNodes; +} BSTIterator; + +void TraverseAndAssign(struct TreeNode *root, BSTIterator *obj) +{ + if (!root) + return; + if (root->left) + TraverseAndAssign(root->left, obj); + obj->values[obj->CurrentIndex] = root->val; + obj->CurrentIndex++; + if (root->right) + TraverseAndAssign(root->right, obj); +} + +int TotalNodes(struct TreeNode *root) +{ + if (!root) + return 0; + int nodes_left = TotalNodes(root->left); + int nodes_right = TotalNodes(root->right); + return nodes_left + nodes_right + 1; +} + +BSTIterator *bSTIteratorCreate(struct TreeNode *root) +{ + int n = TotalNodes(root); + int size = n + 1; + printf("%d", size); + BSTIterator *obj = (BSTIterator *)malloc(sizeof(BSTIterator)); + obj->values = (int *)calloc(size, sizeof(int)); + obj->CurrentIndex = 0; + obj->NumberOfNodes = n; + obj->values[size - 1] = INT_MAX; + TraverseAndAssign(root, obj); + obj->CurrentIndex = 0; + return obj; +} + +/** @return the next smallest number */ +int bSTIteratorNext(BSTIterator *obj) +{ + int NextValue = obj->values[obj->CurrentIndex]; + obj->CurrentIndex++; + return NextValue; +} + +/** @return whether we have a next smallest number */ +bool bSTIteratorHasNext(BSTIterator *obj) +{ + if (!obj->NumberOfNodes) + { + return false; + } + printf(" Here "); + return (obj->values[obj->CurrentIndex] == INT_MAX) ? false : true; +} + +void bSTIteratorFree(BSTIterator *obj) +{ + free(obj->values); + free(obj); +} diff --git a/leetcode/src/1752.c b/leetcode/src/1752.c new file mode 100644 index 0000000000..492a82b484 --- /dev/null +++ b/leetcode/src/1752.c @@ -0,0 +1,18 @@ +bool check(int* nums, int numsSize){ + if (numsSize == 1) { + return true; + } + + bool wasShift = false; + for(int i = 1; i < numsSize; i++) { + if (nums[i - 1] > nums[i]) { + if (wasShift) { + return false; + } + + wasShift = true; + } + } + + return !wasShift || nums[0] >= nums[numsSize-1]; +} diff --git a/leetcode/src/1769.c b/leetcode/src/1769.c new file mode 100644 index 0000000000..e1a81d0492 --- /dev/null +++ b/leetcode/src/1769.c @@ -0,0 +1,41 @@ +/** + * Note: The returned array must be malloced, assume caller calls free(). + */ + +// Count one's from right. Each step from right side decrease for one for each 1's and increase from left: +// 1001*0101 -> left: 4 + 1, right: 2 + 4 +// 10010*101 -> left: (4+1) + (1+1), right: (2-1) + (4-1) +// Runtime: O(n) +// Space: O(1) +int* minOperations(char* boxes, int* returnSize){ + int leftOnes = 0; + int leftCommonDistance = 0; + + int rightOnes = 0; + int rightCommonDistance = 0; + + int boxesLength = strlen(boxes); + + *returnSize = boxesLength; + int* result = malloc(boxesLength * sizeof(int)); + + for (int i = 0; i < boxesLength; i++){ + if (boxes[i] == '1'){ + rightOnes += 1; + rightCommonDistance += i; + } + } + + for (int i = 0; i < boxesLength; i++){ + if (boxes[i] == '1'){ + rightOnes -= 1; + leftOnes += 1; + } + + result[i] = rightCommonDistance + leftCommonDistance; + rightCommonDistance -= rightOnes; + leftCommonDistance += leftOnes; + } + + return result; +} diff --git a/leetcode/src/1833.c b/leetcode/src/1833.c new file mode 100644 index 0000000000..e77d8a2921 --- /dev/null +++ b/leetcode/src/1833.c @@ -0,0 +1,24 @@ +int compare(const void* i, const void* j) +{ + return *((int*)i) - *((int*)j); +} + +// Greedy + sorting +// Runtime: O(n*log(n)) +// Space: O(1) +int maxIceCream(int* costs, int costsSize, int coins){ + qsort(costs, costsSize, sizeof(int), compare); + + int result = 0; + int leftCoins = coins; + for (int i = 0; i < costsSize; i++){ + if (costs[i] > leftCoins){ + break; + } + + leftCoins -= costs[i]; + result++; + } + + return result; +} diff --git a/leetcode/src/1838.c b/leetcode/src/1838.c new file mode 100644 index 0000000000..fe4469bf3b --- /dev/null +++ b/leetcode/src/1838.c @@ -0,0 +1,36 @@ +#define max(a,b) (((a)>(b))?(a):(b)) + +int compare(const int* i, const int* j) +{ + return *i - *j; +} + +// Sort + prefix sum + windows sliding +// Runtime: O(n*log(n)) +// Space: O(n) +int maxFrequency(int* nums, int numsSize, int k){ + qsort(nums, numsSize, sizeof (int), (int(*) (const void*, const void*)) compare); + long* prefixSum = malloc(numsSize * sizeof(long)); + + prefixSum[0] = nums[0]; + for(int i = 0; i < numsSize - 1; i++){ + prefixSum[i + 1] = prefixSum[i] + nums[i]; + } + + int leftWindowPosition = 0; + int result = 0; + + for(int rightWindowPosition = 0; rightWindowPosition < numsSize; rightWindowPosition++){ + long rightSum = prefixSum[rightWindowPosition]; + long leftSum = prefixSum[leftWindowPosition]; + + while ((long)nums[rightWindowPosition] * (rightWindowPosition - leftWindowPosition) - (rightSum - leftSum) > k){ + leftWindowPosition += 1; + } + + result = max(result, rightWindowPosition - leftWindowPosition + 1); + } + + free(prefixSum); + return result; +} diff --git a/leetcode/src/189.c b/leetcode/src/189.c new file mode 100644 index 0000000000..efdb88b59c --- /dev/null +++ b/leetcode/src/189.c @@ -0,0 +1,14 @@ +void rotate(int *nums, int numsSize, int k) +{ + for (int i = 1; i <= k; i++) + { + int j; + int lastElement; + lastElement = nums[numsSize - 1]; + for (j = numsSize - 1; j > 0; j--) + { + nums[j] = nums[j - 1]; + } + nums[0] = lastElement; + } +} \ No newline at end of file diff --git a/leetcode/src/19.c b/leetcode/src/19.c new file mode 100644 index 0000000000..c189f8f288 --- /dev/null +++ b/leetcode/src/19.c @@ -0,0 +1,27 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * struct ListNode *next; + * }; + */ + +struct ListNode *removeNthFromEnd(struct ListNode *head, int n) { + struct ListNode entry, *p_free, *p = head; + int i, sz = 0; + entry.next = head; + while (p != NULL) { + p = p->next; + sz++; + } + for (i = 0, p = &entry; i < sz - n; i++, p = p -> next) + ; + p_free = p->next; + if (n != 1) { + p->next = p->next->next; + } else { + p->next = NULL; + } + free(p_free); + return entry.next; +} diff --git a/leetcode/src/190.c b/leetcode/src/190.c new file mode 100644 index 0000000000..7ab3bbe23b --- /dev/null +++ b/leetcode/src/190.c @@ -0,0 +1,26 @@ +uint32_t reverseBits(uint32_t n) +{ + uint TotalBits = 32; + uint32_t reverse_int = 0; // stored in memory as 32 bits, each bit valued 0 + uint i; + for (i = 0; i < TotalBits; i++) + { + if ((n & (UINT32_C(1) + << i))) // if the bit on the ith position of 32 bit input is + // 1, then proceed Further note the use of UINT32_C + // to convert 1 to unsigned 32 bit int, since just 1 + // is treated as int which cannot be shifted left + // more than 30 times + reverse_int = + reverse_int | + (UINT32_C(1) + << (TotalBits - 1 - + i)); // Convert the ith bit from the end in reverse_int + // from 0 to 1, if ith bit from beginning in n is 1 + // This is achieved by using bitwise OR on + // reverse_int (where ith bit from end is currently + // 0) and 1 shifted left 31 - i bits (to ith bit from + // the end) + } + return reverse_int; +} \ No newline at end of file diff --git a/leetcode/src/191.c b/leetcode/src/191.c new file mode 100644 index 0000000000..d28854cf6c --- /dev/null +++ b/leetcode/src/191.c @@ -0,0 +1,16 @@ +int hammingWeight(uint32_t n) +{ + int TotalBits = 32; + int i, weight = 0; + for (i = 0; i < TotalBits; i++) + { + if (n & + (UINT32_C(1) + << i)) // if the bit on the ith position of 32 bit input is 1, + // then proceed Further note the use of UINT32_C to + // convert 1 to unsigned 32 bit int, as just 1 is treated + // as int which cannot be shifted left more than 30 times + weight += 1; + } + return weight; +} \ No newline at end of file diff --git a/leetcode/src/2.c b/leetcode/src/2.c new file mode 100644 index 0000000000..d2bec03099 --- /dev/null +++ b/leetcode/src/2.c @@ -0,0 +1,57 @@ +/* + * Definition for singly-linked list. + * struct ListNode { + * int val; + * struct ListNode *next; + * }; + */ + +struct ListNode *addTwoNumbers(struct ListNode *l1, struct ListNode *l2) +{ + struct ListNode *head = NULL; + struct ListNode *walk = NULL; + struct ListNode *tmp = NULL; + + int carry = 0; + int val1 = 0; + int val2 = 0; + int val = 0; + + while (l1 != NULL || l2 != NULL || carry) + { + val1 = 0; + val2 = 0; + val = 0; + + if (l1) + { + val1 = l1->val; + l1 = l1->next; + } + + if (l2) + { + val2 = l2->val; + l2 = l2->next; + } + + val = carry + val1 + val2; + carry = val / 10; + + tmp = malloc(sizeof(struct ListNode)); + tmp->val = val % 10; + tmp->next = NULL; + + if (!head) + { + head = walk = tmp; + } + else + { + walk->next = tmp; + walk = walk->next; + } + } + + return head; +} diff --git a/leetcode/src/20.c b/leetcode/src/20.c new file mode 100644 index 0000000000..7d3ad5c0a4 --- /dev/null +++ b/leetcode/src/20.c @@ -0,0 +1,32 @@ +bool isValid(char *s) +{ + int i, k = 0, len = strlen(s); + char *store = calloc(len, sizeof(char)); + + for (i = 0; s[i] != '\0'; i++) + { + switch (s[i]) + { + case '(': + case '{': + case '[': + store[k++] = s[i]; + break; + case ')': + if (k < 1 || store[--k] != '(') + goto out; + break; + case '}': + if (k < 1 || store[--k] != '{') + goto out; + break; + case ']': + if (k < 1 || store[--k] != '[') + goto out; + break; + } + } +out: + free(store); + return s[i] == '\0' && k == 0; +} diff --git a/leetcode/src/201.c b/leetcode/src/201.c new file mode 100644 index 0000000000..47507f4f9b --- /dev/null +++ b/leetcode/src/201.c @@ -0,0 +1,8 @@ +int rangeBitwiseAnd(int m, int n) +{ + while (m < n) + { + n &= n - 1; + } + return n; +} \ No newline at end of file diff --git a/leetcode/src/2024.c b/leetcode/src/2024.c new file mode 100644 index 0000000000..5796f0b03f --- /dev/null +++ b/leetcode/src/2024.c @@ -0,0 +1,33 @@ +#define max(X, Y) ((X) > (Y) ? (X) : (Y)) + +int maximizeTarget(char * answerKey, char targetChar, int k){ + int leftIndex = -1; + int result = 0; + int currTargetChars = 0; + int lenAnswerKey = strlen(answerKey); + + for (int rightIndex = 0; rightIndex < lenAnswerKey; rightIndex++){ + char ch = answerKey[rightIndex]; + if (ch == targetChar){ + currTargetChars++; + } + + while (rightIndex - leftIndex > currTargetChars + k) { + leftIndex++; + if (answerKey[leftIndex] == targetChar){ + currTargetChars--; + } + } + + result = max(result, rightIndex - leftIndex); + } + + return result; +} + +// Use sliding window approach + two pointers. +// Runtime: O(n) +// Space: O(1) +int maxConsecutiveAnswers(char * answerKey, int k){ + return max(maximizeTarget(answerKey, 'T', k), maximizeTarget(answerKey, 'F', k)); +} diff --git a/leetcode/src/203.c b/leetcode/src/203.c new file mode 100644 index 0000000000..f652aaeb45 --- /dev/null +++ b/leetcode/src/203.c @@ -0,0 +1,14 @@ +struct ListNode *removeElements(struct ListNode *head, int val) +{ + if (head == NULL) + return NULL; + if (head->val == val) + { + return removeElements(head->next, val); + } + else + { + head->next = removeElements(head->next, val); + } + return head; +} diff --git a/leetcode/src/206.c b/leetcode/src/206.c new file mode 100644 index 0000000000..adc4657b9d --- /dev/null +++ b/leetcode/src/206.c @@ -0,0 +1,20 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * struct ListNode *next; + * }; + */ + +struct ListNode *reverseList(struct ListNode *head) +{ + struct ListNode *res = NULL; + while (head) + { + struct ListNode *pre_node = head; + head = head->next; + pre_node->next = res; + res = pre_node; + } + return res; +} diff --git a/leetcode/src/2095.c b/leetcode/src/2095.c new file mode 100644 index 0000000000..196b0892a7 --- /dev/null +++ b/leetcode/src/2095.c @@ -0,0 +1,38 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * struct ListNode *next; + * }; + */ + +struct ListNode* deleteMiddle(struct ListNode* head) +{ + if (head == NULL || head->next == NULL) + return NULL; + struct ListNode *fast, *slow, *prev; + int n = 0; + fast = head; + slow = head; + while (fast != NULL) + { + n = n + 1; + fast = fast->next; + } + fast = head; + while (fast->next != NULL && fast->next->next != NULL) // finds mid node + { + prev = slow; + slow = slow->next; + fast = fast->next->next; + } + if (n % 2 == 0) + { + prev = slow; + slow = slow->next; + prev->next = slow->next; + } + else + prev->next = slow->next; + return head; +} diff --git a/leetcode/src/21.c b/leetcode/src/21.c new file mode 100644 index 0000000000..54d31e1b3e --- /dev/null +++ b/leetcode/src/21.c @@ -0,0 +1,72 @@ +/* + * Iterative approach + */ +struct ListNode *mergeTwoLists(struct ListNode *l1, struct ListNode *l2) +{ + struct ListNode *list = NULL; + struct ListNode *tmp = NULL; + + if (!l1) + return l2; + if (!l2) + return l1; + + if (l1 && l2) + { + if (l1->val < l2->val) + { + list = tmp = l1; + l1 = l1->next; + } + else + { + list = tmp = l2; + l2 = l2->next; + } + + while (l1 && l2) + { + if (l1->val < l2->val) + { + tmp->next = l1; + l1 = l1->next; + } + else + { + tmp->next = l2; + l2 = l2->next; + } + tmp = tmp->next; + } + + if (l1) + tmp->next = l1; + if (l2) + tmp->next = l2; + + return list; + } + + return NULL; +} + +/* + * Recursive approach + */ +struct ListNode *mergeTwoLists(struct ListNode *l1, struct ListNode *l2) +{ + if (!l1) + return l2; + if (!l2) + return l1; + if (l1->val < l2->val) + { + l1->next = mergeTwoLists(l1->next, l2); + return l1; + } + else + { + l2->next = mergeTwoLists(l1, l2->next); + return l2; + } +} diff --git a/leetcode/src/2125.c b/leetcode/src/2125.c new file mode 100644 index 0000000000..0f65b24dff --- /dev/null +++ b/leetcode/src/2125.c @@ -0,0 +1,30 @@ +int coundDevices(char* bankRow){ + int result = 0; + int bankRowSize = strlen(bankRow); + for(int i = 0; i < bankRowSize; i++){ + if (bankRow[i] == '1'){ + result++; + } + } + + return result; +} + +// Counting devices in each row +// Runtime: O(n*m), n-number of bank rows, m - max size of row. +// Space: O(1) +int numberOfBeams(char ** bank, int bankSize){ + int prevRowDevices = 0; + int result = 0; + for(int i = 0; i < bankSize; i++){ + int devices = coundDevices(bank[i]); + if (devices == 0){ + continue; + } + + result += devices * prevRowDevices; + prevRowDevices = devices; + } + + return result; +} diff --git a/leetcode/src/2130.c b/leetcode/src/2130.c new file mode 100644 index 0000000000..6dbacc1d20 --- /dev/null +++ b/leetcode/src/2130.c @@ -0,0 +1,30 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * struct ListNode *next; + * }; + */ + +int pairSum(struct ListNode* head) +{ + struct ListNode* dup = head; + int count = 0, i = 0, max = 0; + while (head != NULL) + { + count++; + head = head->next; + } + int* arr = malloc(count * sizeof(int)); + while (dup != NULL) + { + arr[i++] = dup->val; + dup = dup->next; + } + for (i = 0; i < count / 2; ++i) + { + if (arr[i] + arr[count - i - 1] > max) + max = arr[i] + arr[count - i - 1]; + } + return max; +} diff --git a/leetcode/src/215.c b/leetcode/src/215.c new file mode 100644 index 0000000000..7a301f5b92 --- /dev/null +++ b/leetcode/src/215.c @@ -0,0 +1,7 @@ +int *cmpval(const void *a, const void *b) { return *(int *)b - *(int *)a; } + +int findKthLargest(int *nums, int numsSize, int k) +{ + qsort(nums, numsSize, sizeof(int), cmpval); + return nums[k - 1]; +} diff --git a/leetcode/src/217.c b/leetcode/src/217.c new file mode 100644 index 0000000000..a349ef9e2c --- /dev/null +++ b/leetcode/src/217.c @@ -0,0 +1,13 @@ +int numcmp(const void *a, const void *b) { return *(int *)a - *(int *)b; } + +bool containsDuplicate(int *nums, int numsSize) +{ + int i; + qsort(nums, numsSize, sizeof(int), numcmp); + for (i = 0; i < numsSize - 1; i++) + { + if (nums[i] == nums[i + 1]) + return 1; + } + return 0; +} diff --git a/leetcode/src/2222.c b/leetcode/src/2222.c new file mode 100644 index 0000000000..795ff077d3 --- /dev/null +++ b/leetcode/src/2222.c @@ -0,0 +1,30 @@ +long numberOfWaysForChar(char * s, char c){ + long firstBuildingAppearNumber = 0; + long secondBuildingAppearNumber = 0; + long result = 0; + + int sLength = strlen(s); + for (int i = 0; i < sLength; i++){ + if (s[i] == c){ + result += secondBuildingAppearNumber; + + firstBuildingAppearNumber += 1; + continue; + } + + secondBuildingAppearNumber += firstBuildingAppearNumber; + } + + return result; + +} + +// numberOfWays returns the sum of number ways of selecting first building +// and the number of ways of selecting second building which gives us the +// number of ways of selecting three building such that no +// consecutive buildings are in the same category. +// Runtime: O(n) +// Space: O(n) +long long numberOfWays(char * s){ + return numberOfWaysForChar(s, '0') + numberOfWaysForChar(s, '1'); +} diff --git a/leetcode/src/223.c b/leetcode/src/223.c new file mode 100644 index 0000000000..6f424dc9e4 --- /dev/null +++ b/leetcode/src/223.c @@ -0,0 +1,24 @@ +#define min(X, Y) ((X) < (Y) ? (X) : (Y)) + +int intersectionSize(int p11, int p12, int p21, int p22){ + if (p11 >= p22 || p12 <= p21){ + return 0; + } + + if (p11 < p21){ + return min(p12 - p21, p22 - p21); + } + + return min(p22 - p11, p12 - p11); +} + +// Calculation area of the A, then area of the B then minus intersection of A and B +// Runtime: O(1) +// Space: O(1) +int computeArea(int ax1, int ay1, int ax2, int ay2, int bx1, int by1, int bx2, int by2){ + int areaA = (ay2 - ay1) * (ax2 - ax1); + int areaB = (by2 - by1) * (bx2 - bx1); + int areaInteresection = intersectionSize(ax1, ax2, bx1, bx2) * intersectionSize(ay1, ay2, by1, by2); + + return areaA + areaB - areaInteresection; +} diff --git a/leetcode/src/2256.c b/leetcode/src/2256.c new file mode 100644 index 0000000000..06e4d123a5 --- /dev/null +++ b/leetcode/src/2256.c @@ -0,0 +1,37 @@ +// Prefix sum. +// - Calculate whole nums sum. +// - Calculate currIndex sum. +// - Compare averages +// Runtime: O(n) +// Space: O(1) + +int minimumAverageDifference(int* nums, int numsSize){ + long numsSum = 0; + for (int i = 0; i < numsSize; i++){ + numsSum += nums[i]; + } + + long currSum = 0; + long minAverage = 9223372036854775807; // Long max + int minIndex = 0; + + for (int i = 0; i < numsSize; i++){ + currSum += nums[i]; + + int leftItemsNumber = (numsSize - i - 1); + long leftItemsNumberAverage = 0; + if (leftItemsNumber != 0){ + leftItemsNumberAverage = (numsSum - currSum) / leftItemsNumber; + } + + long currItemsNumberAverage = currSum / (i + 1); + long averageDiff = abs(currItemsNumberAverage - leftItemsNumberAverage); + + if (averageDiff < minAverage){ + minAverage = averageDiff; + minIndex = i; + } + } + + return minIndex; +} diff --git a/leetcode/src/226.c b/leetcode/src/226.c new file mode 100644 index 0000000000..ac2bf1613a --- /dev/null +++ b/leetcode/src/226.c @@ -0,0 +1,13 @@ +struct TreeNode *invertTree(struct TreeNode *root) +{ + struct TreeNode *tmp; + if (root == NULL) + return NULL; + tmp = root->left; + root->left = root->right; + root->right = tmp; + + invertTree(root->left); + invertTree(root->right); + return root; +} diff --git a/leetcode/src/2270.c b/leetcode/src/2270.c new file mode 100644 index 0000000000..b797f56770 --- /dev/null +++ b/leetcode/src/2270.c @@ -0,0 +1,21 @@ +// Prefix sum. +// Collect sum fromleft part and compare it with left sum. +// Runtime: O(n) +// Space: O(1) +int waysToSplitArray(int* nums, int numsSize){ + long sumNums = 0; + for (int i = 0; i < numsSize; i++){ + sumNums += nums[i]; + } + + long prefixSum = 0; + int result = 0; + for (int i = 0; i < numsSize - 1; i++){ + prefixSum += nums[i]; + if (prefixSum >= sumNums - prefixSum){ + result += 1; + } + } + + return result; +} diff --git a/leetcode/src/2279.c b/leetcode/src/2279.c new file mode 100644 index 0000000000..8dc05d981e --- /dev/null +++ b/leetcode/src/2279.c @@ -0,0 +1,29 @@ +int compare(const int* i, const int* j) +{ + return *i - *j; +} + +// Sorting. +// Runtime: O(n*log(n)) +// Space: O(n) +int maximumBags(int* capacity, int capacitySize, int* rocks, int rocksSize, int additionalRocks) { + int* capacityLeft = malloc(capacitySize * sizeof(int)); + for (int i = 0; i < capacitySize; i++) { + capacityLeft[i] = capacity[i] - rocks[i]; + } + + qsort(capacityLeft, capacitySize, sizeof (int), (int(*) (const void*, const void*)) compare); + + int bags = 0; + for (int i = 0; i < capacitySize; i++) { + if (additionalRocks < capacityLeft[i]){ + break; + } + + additionalRocks -= capacityLeft[i]; + bags++; + } + + free(capacityLeft); + return bags; +} diff --git a/leetcode/src/230.c b/leetcode/src/230.c new file mode 100644 index 0000000000..61fa0e77f8 --- /dev/null +++ b/leetcode/src/230.c @@ -0,0 +1,35 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * struct TreeNode *left; + * struct TreeNode *right; + * }; + */ + +struct TreeNode* findKthSmallest(struct TreeNode* node, int* k){ + if (node == NULL){ + return NULL; + } + + struct TreeNode* resultNode = findKthSmallest(node->left, k); + + if (resultNode != NULL){ + return resultNode; + } + + *k -= 1; + + if (*k == 0){ + return node; + } + + return findKthSmallest(node->right, k); +} + +// Depth-First Search +// Runtime: O(n) +// Space: O(1) +int kthSmallest(struct TreeNode* root, int k){ + return findKthSmallest(root, &k)->val; +} diff --git a/leetcode/src/2304.c b/leetcode/src/2304.c new file mode 100644 index 0000000000..d8cfcb2521 --- /dev/null +++ b/leetcode/src/2304.c @@ -0,0 +1,42 @@ +#define min(x,y)(((x)<(y))?(x):(y)) + +// DP up -> down. We are going down from gridline to gridline +// and collect the minumum cost path. +// Runtime : O(gridSize*gridColSize*gridColSize) +// Space: O(gridColSize) +int minPathCost(int** grid, int gridSize, int* gridColSize, int** moveCost, int moveCostSize, int* moveCostColSize){ + int* dp = (int*)calloc(gridColSize[0], sizeof(int)); + int* newDp = (int*)calloc(gridColSize[0], sizeof(int)); + + for(int i = 0; i < gridSize - 1; i++){ + int currGridColSize = gridColSize[i]; + for(int j = 0; j < currGridColSize; j++){ + newDp[j] = -1; + } + + for(int j = 0; j < currGridColSize; j++){ + int currGridItem = grid[i][j]; + for(int z = 0; z < currGridColSize; z++){ + int currMoveCost = dp[j] + moveCost[currGridItem][z] + currGridItem; + + newDp[z] = (newDp[z] == -1) ? currMoveCost : min(newDp[z], currMoveCost); + } + } + + for(int j = 0; j < currGridColSize; j++){ + dp[j] = newDp[j]; + } + } + + // Find minimum value. + int minValue = dp[0] + grid[gridSize - 1][0]; + for(int j = 1; j < gridColSize[0]; j++){ + minValue = min(minValue, dp[j] + grid[gridSize - 1][j]); + } + + // free resources + free(dp); + free(newDp); + + return minValue; +} diff --git a/leetcode/src/231.c b/leetcode/src/231.c new file mode 100644 index 0000000000..81ea2b0454 --- /dev/null +++ b/leetcode/src/231.c @@ -0,0 +1,6 @@ +// Without loops/recursion. +// Runtime: O(1) +// Space: O(1) +bool isPowerOfTwo(int n){ + return (n > 0) && ((n & (n - 1)) == 0); +} diff --git a/leetcode/src/234.c b/leetcode/src/234.c new file mode 100644 index 0000000000..b541bf6172 --- /dev/null +++ b/leetcode/src/234.c @@ -0,0 +1,42 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * struct ListNode *next; + * }; + */ + +struct ListNode *reverse(struct ListNode *head) +{ + struct ListNode *res = NULL; + while (head) + { + struct ListNode *pre_node = head; + head = head->next; + pre_node->next = res; + res = pre_node; + } + return res; +} +bool isPalindrome(struct ListNode *head) +{ + struct ListNode *slow = head; + struct ListNode *fast = head; + struct ListNode *last; + while (fast && fast->next) + { + slow = slow->next; + fast = fast->next->next; + } + if (fast != NULL) + slow = slow->next; + last = reverse(slow); + while (last) + { + if (head->val != last->val) + return 0; + head = head->next; + last = last->next; + } + return 1; +} diff --git a/leetcode/src/236.c b/leetcode/src/236.c new file mode 100644 index 0000000000..71235c4e64 --- /dev/null +++ b/leetcode/src/236.c @@ -0,0 +1,82 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * struct TreeNode *left; + * struct TreeNode *right; + * }; + */ + +// The list for TreeNodes. +struct ListItem { + struct TreeNode* node; // TreeNode pointer + struct ListItem* next; // Pointer to the next ListItem +}; + +bool findTargetPath(struct TreeNode* node, struct TreeNode* target, struct ListItem* path){ + if (node == NULL){ + return false; + } + + struct ListItem* pathItem = malloc(sizeof(struct ListItem)); + pathItem->node = node; + pathItem->next = NULL; + path->next = pathItem; + + if (node->val == target->val){ + return true; + } + + if (findTargetPath(node->left, target, pathItem)){ + return true; + } + + if (findTargetPath(node->right, target, pathItem)){ + return true; + } + + path->next = NULL; + free(pathItem); + return false; +} + +void freeList(struct ListItem* target){ + if (target->next != NULL){ + freeList(target->next); + } + + free(target); +} + + +// Find full path for p and q. +// Find the longest common path in paths. + +// Runtime: O(n) +// Space: O(n) +struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) { + struct ListItem* pPath = malloc(sizeof(struct ListItem)); + struct ListItem* qPath = malloc(sizeof(struct ListItem)); + + findTargetPath(root, p, pPath); + findTargetPath(root, q, qPath); + + struct TreeNode* lowestTreeNode = NULL; + struct ListItem* pPathCursor = pPath->next; + struct ListItem* qPathCursor = qPath->next; + while(pPathCursor != NULL && qPathCursor != NULL) { + if (pPathCursor->node->val == qPathCursor->node->val){ + lowestTreeNode = pPathCursor->node; + pPathCursor = pPathCursor->next; + qPathCursor = qPathCursor->next; + continue; + } + + break; + } + + freeList(pPath); + freeList(qPath); + + return lowestTreeNode; +} diff --git a/leetcode/src/24.c b/leetcode/src/24.c new file mode 100644 index 0000000000..e4ce505b1d --- /dev/null +++ b/leetcode/src/24.c @@ -0,0 +1,9 @@ +struct ListNode *swapPairs(struct ListNode *head) +{ + if (!head || !head->next) + return head; + struct ListNode *tmp = head->next; + head->next = swapPairs(head->next->next); + tmp->next = head; + return tmp; +} diff --git a/leetcode/src/242.c b/leetcode/src/242.c new file mode 100644 index 0000000000..9b4abbf6a0 --- /dev/null +++ b/leetcode/src/242.c @@ -0,0 +1,18 @@ +bool isAnagram(char *s, char *t) +{ + int n = strlen(s); + int m = strlen(t); + + int cnt_s[1000], cnt_t[1000]; + for (int c = 97; c < 97 + 26; c++) cnt_s[c] = cnt_t[c] = 0; + + for (int i = 0; i < n; i++) cnt_s[s[i]]++; + + for (int i = 0; i < m; i++) cnt_t[t[i]]++; + + for (int c = 97; c < 97 + 26; c++) + if (cnt_s[c] != cnt_t[c]) + return false; + + return true; +} diff --git a/leetcode/src/2482.c b/leetcode/src/2482.c new file mode 100644 index 0000000000..df9f702dec --- /dev/null +++ b/leetcode/src/2482.c @@ -0,0 +1,42 @@ +/** + * Return an array of arrays of size *returnSize. + * The sizes of the arrays are returned as *returnColumnSizes array. + * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free(). + */ + +// Calculating ones on each row and column. +// Runtime: O(n * m) +// Space: O(n + m) +int** onesMinusZeros(int** grid, int gridSize, int* gridColSize, int* returnSize, int** returnColumnSizes){ + int n = gridSize; + int m = gridColSize[0]; + + int** result = malloc(gridSize * sizeof(int*)); + for (int i = 0; i < n; i++){ + result[i] = malloc(m * sizeof(int)); + } + + int* onesRows = calloc(n, sizeof(int)); + int* onesCols = calloc(m, sizeof(int)); + for (int i = 0; i < n; i++){ + for (int j = 0; j < m; j++){ + if (grid[i][j] == 1){ + onesRows[i] += 1; + onesCols[j] += 1; + } + } + } + + for (int i = 0; i < gridSize; i++){ + for (int j = 0; j < gridColSize[i]; j++){ + result[i][j] = onesRows[i] + onesCols[j] - (m - onesRows[i]) - (n - onesCols[j]); + } + } + + free(onesRows); + free(onesCols); + + *returnSize = gridSize; + *returnColumnSizes = gridColSize; + return result; +} diff --git a/leetcode/src/2501.c b/leetcode/src/2501.c new file mode 100644 index 0000000000..87cfa2702b --- /dev/null +++ b/leetcode/src/2501.c @@ -0,0 +1,52 @@ +#define max(a,b) (((a)>(b))?(a):(b)) + +int longestSquareStreakDp(int* numsSet, int numsSetSize, int* dp, long num){ + if (dp[num] != 0){ + return dp[num]; + } + + long numSquare = num * num; + + dp[num] = 1; + if (numSquare <= numsSetSize && numsSet[numSquare] == 1){ + dp[num] += longestSquareStreakDp(numsSet, numsSetSize, dp, numSquare); + } + + return dp[num]; +} + +// Dynamic approach. Up -> down. +// Runtime: O(numsSize) +// Space: O(max(nums)) +int longestSquareStreak(int* nums, int numsSize){ + // Find nums maximum + int numMax = 0; + for(int i = 0; i < numsSize; i++){ + numMax = max(numMax, nums[i]); + } + + int* numsSet = calloc(numMax + 1, sizeof(int)); + int* dp = calloc(numMax + 1, sizeof(int)); + + // Init set of nums + for(int i = 0; i < numsSize; i++){ + numsSet[nums[i]] = 1; + } + + // Find result + int result = -1; + for(int i = 0; i < numsSize; i++){ + long num = nums[i]; + long numSquare = num * num; + + if (numSquare > numMax || numsSet[numSquare] == 0){ + continue; + } + + result = max(result, 1 + longestSquareStreakDp(numsSet, numMax, dp, numSquare)); + } + + free(dp); + free(numsSet); + return result; +} diff --git a/leetcode/src/26.c b/leetcode/src/26.c new file mode 100644 index 0000000000..c9f085f79b --- /dev/null +++ b/leetcode/src/26.c @@ -0,0 +1,12 @@ +int removeDuplicates(int *nums, int numsSize) +{ + int count = 0, i; + for (i = 1; i < numsSize; i++) + { + if (nums[i] == nums[i - 1]) + count++; + else + nums[i - count] = nums[i]; + } + return numsSize - count; +} diff --git a/leetcode/src/268.c b/leetcode/src/268.c new file mode 100644 index 0000000000..600556bdcb --- /dev/null +++ b/leetcode/src/268.c @@ -0,0 +1,10 @@ +int missingNumber(int *nums, int numsSize) +{ + int i, actual_sum = 0, sum = 0; + for (i = 0; i < numsSize; i++) + { + sum = sum + nums[i]; + actual_sum = actual_sum + i; + } + return actual_sum + numsSize - sum; +} diff --git a/leetcode/src/27.c b/leetcode/src/27.c new file mode 100644 index 0000000000..7ba0dee90a --- /dev/null +++ b/leetcode/src/27.c @@ -0,0 +1,10 @@ +int removeElement(int *nums, int numsSize, int val) +{ + int i, start = 0; + for (i = 0; i < numsSize; i++) + { + if (nums[i] != val) + nums[start++] = nums[i]; + } + return start; +} diff --git a/leetcode/src/274.c b/leetcode/src/274.c new file mode 100644 index 0000000000..e233fd04f0 --- /dev/null +++ b/leetcode/src/274.c @@ -0,0 +1,21 @@ +int diff(const int* i, const int* j) + +{ + return *i - *j; +} + + +// Sorting. +// Runtime: O(n*log(n)) +// Space: O(1) +int hIndex(int* citations, int citationsSize){ + qsort(citations, citationsSize, sizeof(int), (int(*) (const void*, const void*)) diff); + + for(int i = 0; i < citationsSize; i++){ + if (citations[citationsSize - 1 - i] <= i){ + return i; + } + } + + return citationsSize; +} diff --git a/leetcode/src/278.c b/leetcode/src/278.c new file mode 100644 index 0000000000..ec292d73b9 --- /dev/null +++ b/leetcode/src/278.c @@ -0,0 +1,20 @@ +// Forward declaration of isBadVersion API. +bool isBadVersion(int version); + +int firstBadVersion(int n) +{ + int low = 1, high = n; + while (low <= high) + { + int mid = low + (high - low) / 2; + if (isBadVersion(mid)) + { + high = mid - 1; + } + else + { + low = mid + 1; + } + } + return low; +} diff --git a/leetcode/src/28.c b/leetcode/src/28.c new file mode 100644 index 0000000000..ad11969e82 --- /dev/null +++ b/leetcode/src/28.c @@ -0,0 +1,120 @@ +/* + * brute force approach + * time complexity: O(mn) + */ +int strStr(char *haystack, char *needle) +{ + int i = 0; + int j = 0; + int k = 0; + int hlen = 0; + int nlen = 0; + + if (needle == NULL || *needle == 0) + return 0; + + if (haystack == NULL || *haystack == 0) + return -1; + + hlen = strlen(haystack); + nlen = strlen(needle); + + if (hlen < nlen) + return -1; + + for (i = 0; i <= hlen - nlen; i++) + { + j = 0; + if (haystack[i] != needle[j++]) + continue; + + k = i + 1; + for (; j < nlen; j++) + { + if (haystack[k] != needle[j]) + { + break; + } + else + k++; + } + if (j == nlen) + return i; + } + return -1; +} + +/* ---------------------------------------------------------------------------------------- + */ + +/* + * KMP algorithm + * time complexity: O(m + n) + */ + +/* fills overlap with longest proper prefix which is also suffix for each index + * in needle */ +void fill_overlap(char *needle, int len_needle, int *overlap) +{ + int len = 0; + int i = 0; + + overlap[0] = 0; + + for (i = 1; i < len_needle;) + { + if (needle[i] == needle[len]) + { + len++; + overlap[i++] = len; + } + else + { + if (len) + len = overlap[len - 1]; + else + overlap[i++] = 0; + } + } +} + +int strStr(char *haystack, char *needle) +{ + int i = 0; /* index for haystack */ + int j = 0; /* index for needle */ + + int len_needle = strlen(needle); + int len_haystack = strlen(haystack); + + if (!len_needle) + return 0; + + int overlap[len_needle]; + + fill_overlap(needle, len_needle, overlap); + + while (i < len_haystack) + { + if (needle[j] == haystack[i]) + { + i++; + j++; + } + + if (j == len_needle) + { + return (i - j); + } + else if (i < len_haystack && needle[j] != haystack[i]) + { + if (j != 0) + j = overlap[j - 1]; + else + i = i + 1; + } + } + return -1; +} + +/* ---------------------------------------------------------------------------------------- + */ diff --git a/leetcode/src/283.c b/leetcode/src/283.c new file mode 100644 index 0000000000..647bdfd642 --- /dev/null +++ b/leetcode/src/283.c @@ -0,0 +1,15 @@ +void moveZeroes(int *nums, int numsSize) +{ + int i = 0, start = 0; + + for (i = 0; i < numsSize; i++) + { + if (nums[i]) + nums[start++] = nums[i]; + } + + for (start; start < numsSize; start++) + { + nums[start] = 0; + } +} diff --git a/leetcode/src/287.c b/leetcode/src/287.c new file mode 100644 index 0000000000..1c273b9b1a --- /dev/null +++ b/leetcode/src/287.c @@ -0,0 +1,12 @@ +int cmpval(const void *a, const void *b) { return *(int *)a - *(int *)b; } +int findDuplicate(int *nums, int numsSize) +{ + int i; + qsort(nums, numsSize, sizeof(int), cmpval); + for (i = 0; i < numsSize - 1; i++) + { + if (nums[i] == nums[i + 1]) + return nums[i]; + } + return nums[i]; +} diff --git a/leetcode/src/29.c b/leetcode/src/29.c new file mode 100644 index 0000000000..43de4c531a --- /dev/null +++ b/leetcode/src/29.c @@ -0,0 +1,46 @@ +int divide(int dividend, int divisor) +{ + int sign = 1; + long int output = 0; + if (dividend < 0) + { + sign *= -1; + } + else + { + dividend *= -1; + } + if (divisor < 0) + { + sign *= -1; + } + else + { + divisor *= -1; + } + while (dividend <= divisor) + { + long int tmp = 0; + long int div = divisor; + while (dividend <= div) + { + tmp += (tmp + 1); + dividend -= div; + div += div; + } + if (output >= INT_MAX) + { + if (sign == -1) + { + return INT_MIN; + } + else + { + return INT_MAX; + } + } + output += tmp; + } + + return output * sign; +} diff --git a/leetcode/src/3.c b/leetcode/src/3.c new file mode 100644 index 0000000000..f47cf518f3 --- /dev/null +++ b/leetcode/src/3.c @@ -0,0 +1,65 @@ +int lengthOfLongestSubstring(char *str) +{ + int n = strlen(str); + + if (!n) + return 0; + + int L_len = 1; // length of longest substring + int C_len = 1; // length of current substring + + int P_ind, i; // P_ind for previous index + int visited[256]; // visited will keep track of visiting char for the last + // instance. since there are 256 ASCII char, its size is + // limited to that value. + memset(visited, -1, sizeof(int) * 256); + visited[str[0]] = + 0; // the index of that char will tell us that when it was visited. + for (i = 1; i < n; i++) + { + P_ind = visited[str[i]]; + if (P_ind == -1 || i - C_len > P_ind) + C_len++; // if the current char was not visited earlier, or it is + // not the part of current substring + else + { // otherwise, we need to change the current/longest substring length + if (C_len > L_len) + L_len = C_len; + C_len = i - P_ind; + } + visited[str[i]] = i; + } + if (C_len > L_len) + L_len = C_len; + return L_len; +} +/* Brute force */ +int lengthOfLongestSubstring(char *s) +{ + int cur_max = 0, max = 0; + int counter[255]; + int end = 0; + + memset(counter, 0, sizeof(int) * 255); + while (end < strlen(s)) + { + if (counter[s[end]] == 0) + { + counter[s[end]]++; + end++; + cur_max++; + } + else + { + char c = s[end]; + memset(counter, 0, 255 * sizeof(int)); + if (cur_max >= max) + max = cur_max; + cur_max = 0; + while (s[end - 1] != c) end--; + } + } + if (cur_max >= max) + max = cur_max; + return max; +} diff --git a/leetcode/src/32.c b/leetcode/src/32.c new file mode 100644 index 0000000000..ce05249af9 --- /dev/null +++ b/leetcode/src/32.c @@ -0,0 +1,60 @@ +#define max(x,y)(((x)>(y))?(x):(y)) + +const int notCalculated = -2; +const int notValid = -1; + +int getEndValidIndexFromDp(int* dp, char* s, int index, int lenS){ + if (index >= lenS){ + return notValid; + } + + if (dp[index] == notCalculated){ + dp[index] = getEndValidIndex(dp, s, index, lenS); + } + + return dp[index]; +} + +int getEndValidIndex(int* dp, char* s, int index, int lenS){ + if (s[index] == '('){ + if (index + 1 >= lenS){ + return notValid; + } + + if (s[index + 1] == ')'){ + return max(index + 1, getEndValidIndexFromDp(dp, s, index + 2, lenS)); + } + + int nextEndValidIndex = getEndValidIndexFromDp(dp, s, index + 1, lenS); + if (nextEndValidIndex == notValid || nextEndValidIndex + 1 >= lenS || s[nextEndValidIndex + 1] != ')') { + return notValid; + } + + return max(nextEndValidIndex + 1, getEndValidIndexFromDp(dp, s, nextEndValidIndex + 2, lenS)); + } + + return notValid; +} + +// Dynamic Programming. UP -> down approach. +// Runtime: O(n) +// Space: O(n) +int longestValidParentheses(char * s){ + int lenS = strlen(s); + if (lenS == 0){ + return 0; + } + + int* dp = malloc(lenS * sizeof(int)); + for(int i = 0; i < lenS; i++){ + dp[i] = notCalculated; + } + + int result = 0; + for(int i = 0; i < lenS; i++){ + result = max(result, getEndValidIndexFromDp(dp, s, i, lenS) - i + 1); + } + + free(dp); + return result; +} diff --git a/leetcode/src/344.c b/leetcode/src/344.c new file mode 100644 index 0000000000..44510f2011 --- /dev/null +++ b/leetcode/src/344.c @@ -0,0 +1,11 @@ +void reverseString(char *s, int sSize) +{ + int last = sSize - 1, i; + for (i = 0; i < last; i++) + { + char tmp = s[i]; + s[i] = s[last]; + s[last] = tmp; + last--; + } +} diff --git a/leetcode/src/35.c b/leetcode/src/35.c new file mode 100644 index 0000000000..95ca7b2381 --- /dev/null +++ b/leetcode/src/35.c @@ -0,0 +1,30 @@ +int searchInsert(int *nums, int numsSize, int target) +{ + int low = 0, high = numsSize - 1, mid; + while (low <= high) + { + mid = low + (high - low) / 2; + if (target > nums[mid]) + low = mid + 1; + else if (target < nums[mid]) + high = mid - 1; + else + return mid; + } + return low; +} + +/* Recursive version */ +int searchInsert(int *nums, int numsSize, int target) +{ + int idx = numsSize - 1; + if (numsSize > 0) + { + if (target > nums[idx]) + { + return numsSize; + } + return searchInsert(nums, numsSize - 1, target); + } + return 0; +} diff --git a/leetcode/src/367.c b/leetcode/src/367.c new file mode 100644 index 0000000000..e05eb646a0 --- /dev/null +++ b/leetcode/src/367.c @@ -0,0 +1,7 @@ +bool isPerfectSquare(int num) +{ + for (long i = 1; i * i <= num; i++) + if (i * i == num) + return true; + return false; +} diff --git a/leetcode/src/37.c b/leetcode/src/37.c new file mode 100644 index 0000000000..7d8cae115e --- /dev/null +++ b/leetcode/src/37.c @@ -0,0 +1,88 @@ +int** initSet(int size){ + int** result = (int**) malloc(size * sizeof(int*)); + for (int i = 0; i < size; i++) { + result[i] = (int*)calloc(size, sizeof(int)); + } + + return result; +} + +// Returns the id of triplet which the point (i, j) belongs to +int getTripletId(int i, int j){ + return (i / 3) * 3 + (j / 3); +} + +// Recursive function which populates sudoku board. +bool sudokuSolver(int startI, int startJ, char** board, int boardSize, int* boardColSize, int** horizontalsSets, int** verticalsSets, int** tripletsSets){ + for (int i = startI; i < boardSize; i++) { + for (int j = startJ; j < boardColSize[i]; j++) { + if (board[i][j] != '.'){ + continue; + } + + // Find the sets of the current point (i, j) + int* horizontalSet = horizontalsSets[i]; + int* verticalSet = verticalsSets[j]; + int* tripletsSet = tripletsSets[getTripletId(i, j)]; + + for (int z = 1; z < 10; z++) { + if (horizontalSet[z] || verticalSet[z] || tripletsSet[z]){ + continue; + } + + // If the z doesn't belong to occupations sets, we check this value to be in place + horizontalSet[z] = 1; + verticalSet[z] = 1; + tripletsSet[z] = 1; + + if (sudokuSolver(i, j + 1, board, boardSize, boardColSize, horizontalsSets, verticalsSets, tripletsSets)){ + board[i][j] = z + '0'; + return true; + } + + horizontalSet[z] = 0; + verticalSet[z] = 0; + tripletsSet[z] = 0; + } + + // We tried all possible values in range 1-10. No variants - returns false; + return false; + } + + // startJ to begin of the row. + startJ = 0; + } + + // Reach it when the end of the board - then all previous values are setup correctly. + return true; +} + +// Use backtracking +void solveSudoku(char** board, int boardSize, int* boardColSize){ + // Declare sets for cheking occupation of numbers by horizontals, verticals lines and triplets. + int** horizontalsSets = initSet(boardSize + 1); + int** verticalsSets = initSet(boardSize + 1); + int** tripletsSets = initSet(getTripletId(boardSize + 1, boardSize + 1)); + + // Populate sets with values from the board. + for (int i = 0; i < boardSize; i++) { + for (int j = 0; j < boardColSize[i]; j++) { + if (board[i][j] == '.'){ + continue; + } + + int value = board[i][j] - '0'; + horizontalsSets[i][value] = 1; + verticalsSets[j][value] = 1; + tripletsSets[getTripletId(i, j)][value] = 1; + } + } + + // Solving + sudokuSolver(0, 0, board, boardSize, boardColSize, horizontalsSets, verticalsSets, tripletsSets); + + // Free resources + free(horizontalsSets); + free(verticalsSets); + free(tripletsSets); +} diff --git a/leetcode/src/38.c b/leetcode/src/38.c new file mode 100644 index 0000000000..599655468d --- /dev/null +++ b/leetcode/src/38.c @@ -0,0 +1,47 @@ +char *countAndSay(int n) +{ + // Calculating the length of array + double result = 1.0; + for (int i = 0; i < n - 1; i++) + { + result *= 1.4; + } + + int k, j, count, convert = (int)result; + + // Creating array with the length calculated above + char *arr = malloc(convert + 4); + arr[0] = '1'; + arr[1] = '\0'; + + for (int i = 2, length; i <= n; i++) + { + length = strlen(arr); + char newArr[length * 2]; + strcpy(newArr, arr); + + k = 0; + j = 0; + count = 1; + + while (newArr[j] != '\0') + { + if (newArr[j] == newArr[j + 1]) + { + count++; + j++; + } + else + { + arr[k] = (48 + count); + arr[k + 1] = newArr[j]; + arr[k + 2] = '\0'; + j++; + k += 2; + count = 1; + } + } + } + + return arr; +} diff --git a/leetcode/src/387.c b/leetcode/src/387.c new file mode 100644 index 0000000000..cbc78b7e53 --- /dev/null +++ b/leetcode/src/387.c @@ -0,0 +1,12 @@ +int firstUniqChar(char *s) +{ + int *arr = calloc(256, sizeof(int)); + int i; + for (i = 0; i < strlen(s); i++) arr[s[i]] = arr[s[i]] + 1; + for (i = 0; i < strlen(s); i++) + { + if (arr[s[i]] == 1) + return i; + } + return -1; +} diff --git a/leetcode/src/389.c b/leetcode/src/389.c new file mode 100644 index 0000000000..3775a55a26 --- /dev/null +++ b/leetcode/src/389.c @@ -0,0 +1,8 @@ +char findTheDifference(char *s, char *t) +{ + int sum1 = 0, sum2 = 0; + int i; + for (i = 0; i < strlen(s); i++) sum1 += s[i]; + for (i = 0; i < strlen(t); i++) sum2 += t[i]; + return (char)(sum2 - sum1); +} diff --git a/leetcode/src/4.c b/leetcode/src/4.c new file mode 100644 index 0000000000..de676f44f5 --- /dev/null +++ b/leetcode/src/4.c @@ -0,0 +1,50 @@ + + +double findMedianSortedArrays(int *nums1, int nums1Size, int *nums2, + int nums2Size) +{ + int index1 = 0; + int index2 = 0; + int v[nums1Size + nums2Size]; + int v_index = 0; + + while (index1 < nums1Size && index2 < nums2Size) + { + if (nums1[index1] <= nums2[index2]) + { + v[v_index++] = nums1[index1++]; + } + else + { + v[v_index++] = nums2[index2++]; + } + } + if (index1 < nums1Size) + { + while (index1 < nums1Size) + { + v[v_index++] = nums1[index1++]; + } + } + if (index2 < nums2Size) + { + while (index2 < nums2Size) + { + v[v_index++] = nums2[index2++]; + } + } + if (v_index == 1) + { + return v[0]; + } + if (v_index % 2 == 0) + { + double n1, n2; + n1 = v[v_index / 2]; + n2 = v[(v_index / 2) - 1]; + return (n1 + n2) / 2; + } + int new_index = (int)v_index / 2; + int i = 0; + return v[new_index]; +} diff --git a/leetcode/src/404.c b/leetcode/src/404.c new file mode 100644 index 0000000000..260c7c0b05 --- /dev/null +++ b/leetcode/src/404.c @@ -0,0 +1,16 @@ +bool isleaf(struct TreeNode *root) +{ + return root->left == NULL && root->right == NULL; +} + +int sumOfLeftLeaves(struct TreeNode *root) +{ + if (root == NULL) + return 0; + if (root->left) + { + if (isleaf(root->left)) + return root->left->val + sumOfLeftLeaves(root->right); + } + return sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right); +} diff --git a/leetcode/src/42.c b/leetcode/src/42.c new file mode 100644 index 0000000000..7c49239740 --- /dev/null +++ b/leetcode/src/42.c @@ -0,0 +1,27 @@ +#define max(x,y)(((x)>(y))?(x):(y)) +#define min(x,y)(((x)<(y))?(x):(y)) + +// Max stack. Runtime: O(n), Space: O(n) +// Algorithm description: +// - Calculate the stack of maximums from right board. +// - For each index find left maximum and right maximum of height +// - The each index if heights could place nor greater than minimum of left and right max minus curr height +// - Sum all index in result +int trap(int* height, int heightSize){ + int* rightMaxStack = malloc(heightSize * sizeof(int)); + rightMaxStack[heightSize - 1] = height[heightSize - 1]; + + for (int i = heightSize - 2; i >= 0; i--){ + rightMaxStack[i] = max(rightMaxStack[i + 1], height[i]); + } + + int leftMax = 0; + int result = 0; + for (int i = 0; i < heightSize; i++){ + leftMax = max(leftMax, height[i]); + result += max(0, min(leftMax, rightMaxStack[i]) - height[i]); + } + + free(rightMaxStack); + return result; +} diff --git a/leetcode/src/434.c b/leetcode/src/434.c new file mode 100644 index 0000000000..a2d05d5cad --- /dev/null +++ b/leetcode/src/434.c @@ -0,0 +1,20 @@ +// Given a string s, returns the number of segments in the string. +int countSegments(char * s){ + int sLen = strlen(s); + int prevSpace = 1; + int result = 0; + char currChar; + + for (int i = 0; i < sLen; i++){ + currChar = s[i]; + + //A string of whitespaces will only be counted once as the condition below is only true when we transition from whitespace to non-whitespace. + //Since we start with assumed whitespace (prevSpace = 1), initial whitespaces are handled as well, if any + if (s[i] != ' ' && prevSpace) { + result++; + } + prevSpace = (currChar == ' '); + } + + return result; +} diff --git a/leetcode/src/442.c b/leetcode/src/442.c new file mode 100644 index 0000000000..7bfdfb4534 --- /dev/null +++ b/leetcode/src/442.c @@ -0,0 +1,23 @@ +int cmpval(const void *a, const void *b) { return *(int *)a - *(int *)b; } + +int *findDuplicates(int *nums, int numsSize, int *returnSize) +{ + int i; + qsort(nums, numsSize, sizeof(int), cmpval); + int *retArr = malloc(numsSize * sizeof(int)); + *returnSize = 0; + for (i = 0; i < numsSize - 1;) + { + if (nums[i] == nums[i + 1]) + { + retArr[*returnSize] = nums[i]; + *returnSize = *returnSize + 1; + i = i + 2; + } + else + { + i = i + 1; + } + } + return retArr; +} diff --git a/leetcode/src/45.c b/leetcode/src/45.c new file mode 100644 index 0000000000..4deaab4594 --- /dev/null +++ b/leetcode/src/45.c @@ -0,0 +1,50 @@ +// Breadth-first search, imitation. +// Runtime: O(n) +// Space: O(n) +int jump(int* nums, int numsSize) { + if (numsSize == 1) { + return 0; + } + + int step = 1; + int* visitedCells = calloc(numsSize, sizeof(int)); + + int* queue = malloc(numsSize * sizeof(int)); + queue[0] = 0; + int queueLength = 1; + + while (queueLength > 0){ + int* nextQueue = malloc(numsSize * sizeof(int)); + int nextQueueLength = 0; + + for (int i = 0; i < queueLength; i++) { + int cell = queue[i]; + int jump = nums[cell]; + + if (cell + jump >= numsSize - 1) { + free(visitedCells); + free(queue); + free(nextQueue); + return step; + } + + // populate next queue wave for searching + for (int nextCell = cell; nextCell <= cell + jump; nextCell++) { + if (visitedCells[nextCell] == 0){ + nextQueue[nextQueueLength++] = nextCell; + visitedCells[nextCell] = 1; + } + } + } + + step++; + free(queue); + + queue = nextQueue; + queueLength = nextQueueLength; + } + + free(visitedCells); + free(queue); + return -1; +} diff --git a/leetcode/src/461.c b/leetcode/src/461.c new file mode 100644 index 0000000000..6453f769c0 --- /dev/null +++ b/leetcode/src/461.c @@ -0,0 +1,20 @@ +int hammingDistance(int x, int y) +{ + int difference = + x ^ y; // The XOR operator generates the bitwise difference in the + // binary representation of two numbers If bit in ith position + // of both numbers is same, bit in difference is 0, otherwise 1 + int TotalBits = sizeof(difference) * 8; // total number of bits + int i, distance = 0; + for (i = 0; i < TotalBits; i++) + { + if (difference & + (UINT32_C(1) + << i)) // if the bit on the ith position of 32 bit input is 1, + // then proceed Further note the use of UINT32_C to convert + // 1 to unsigned 32 bit int, as just 1 is treated as int + // which cannot be shifted left more than 30 times + distance += 1; + } + return distance; +} \ No newline at end of file diff --git a/leetcode/src/476.c b/leetcode/src/476.c new file mode 100644 index 0000000000..27e52e1fd7 --- /dev/null +++ b/leetcode/src/476.c @@ -0,0 +1,24 @@ +int findComplement(int num) +{ + int TotalBits = 0; + int temp = num; + while (temp) + { // To find position of MSB in given num. Since num is represented as a + // standard size in memory, we cannot rely on size for that information. + TotalBits++; // increment TotalBits till temp becomes 0 + temp >>= 1; // shift temp right by 1 bit every iteration; temp loses 1 + // bit to underflow every iteration till it becomes 0 + } + int i, + flipNumber = 1; // Eg: 1's complement of 101(binary) can be found as + // 101^111 (XOR with 111 flips all bits that are 1 to 0 + // and flips 0 to 1) + for (i = 1; i < TotalBits; i++) + { + flipNumber += UINT32_C(1) + << i; // Note the use of unsigned int to facilitate left + // shift more than 31 times, if needed + } + num = num ^ flipNumber; + return num; +} \ No newline at end of file diff --git a/leetcode/src/485.c b/leetcode/src/485.c new file mode 100644 index 0000000000..a288761590 --- /dev/null +++ b/leetcode/src/485.c @@ -0,0 +1,23 @@ +int max(a,b){ + if(a>b) + return a; + else + return b; +} + +int findMaxConsecutiveOnes(int* nums, int numsSize){ + int count = 0; + int result = 0; + + for (int i = 0; i < numsSize; i++) + { + if (nums[i] == 0) + count = 0; + else + { + count++; + result = max(result, count); + } + } + return result; +} diff --git a/leetcode/src/5.c b/leetcode/src/5.c new file mode 100644 index 0000000000..e54bf598da --- /dev/null +++ b/leetcode/src/5.c @@ -0,0 +1,52 @@ +/** + * Find longest palindrome by traversing the string and checking how + * long palindrome can be constructed from each element by going left and right. + * Checking palindromes of types '..aa..' and '..bab..' + */ + +#include /// for allocating new string via malloc() +#include /// for copying the contents of the string via strncpy() + +char * longestPalindrome(char * s) { + int si_max = 0, ei_max = 0, sz_max = 0, sz, i, delta_i; + char ch, *s_longest; + if (s[1] == '\0') return s; + + for (ch = s[1], i = 1; ch != '\0'; ch = s[++i]) { + if (s[i - 1] == ch) { + sz = 2; + delta_i = 1; + while (i - 1 - delta_i >= 0 && s[i + delta_i] != '\0' && s[i - 1 - delta_i] == s[i + delta_i]) { + sz += 2; + delta_i += 1; + } + if (sz > sz_max) { + sz_max = sz; + si_max = i - 1 - delta_i + 1; + ei_max = i + delta_i - 1; + } + } + } + + for (ch = s[0], i = 1; ch != '\0'; ch = s[++i]) { + sz = 1; + delta_i = 1; + while (i - delta_i >= 0 && s[i + delta_i] != '\0' && s[i - delta_i] == s[i + delta_i]) { + sz += 2; + delta_i += 1; + } + if (sz > sz_max) { + sz_max = sz; + si_max = i - delta_i + 1; + ei_max = i + delta_i - 1; + } + } + + if ((s_longest = (char *) malloc(sizeof(s))) == NULL) { + return NULL; + } + strncpy(s_longest, s + si_max, sz_max); + s_longest[sz_max] = '\0'; + + return s_longest; +} diff --git a/leetcode/src/50.c b/leetcode/src/50.c new file mode 100644 index 0000000000..1e539e0421 --- /dev/null +++ b/leetcode/src/50.c @@ -0,0 +1,39 @@ +double powPositive(double x, int n){ + if (n == 1){ + return x; + } + + double val = powPositive(x, n / 2); + double result = val * val; + + // if n is odd + if (n & 1 > 0){ + result *= x; + } + + return result; +} + +// Divide and conquer. +// Runtime: O(log(n)) +// Space: O(1) +double myPow(double x, int n){ + if (n == 0){ + return 1; + } + + const int LOWER_BOUND = -2147483648; + + // n is the minimum int, couldn't be converted in -n because maximum is 2147483647. + // this case we use (1 / pow(x, -(n + 1))) * n + if (n == LOWER_BOUND){ + return 1 / (powPositive(x, -(n + 1)) * x); + } + + // 1 / pow(x, -(n + 1)) + if (n < 0){ + return 1 / powPositive(x, -n); + } + + return powPositive(x, n); +} diff --git a/leetcode/src/509.c b/leetcode/src/509.c new file mode 100644 index 0000000000..8129354bc5 --- /dev/null +++ b/leetcode/src/509.c @@ -0,0 +1,8 @@ +int fib(int N) +{ + if (N == 0) + return 0; + if (N == 1) + return 1; + return fib(N - 1) + fib(N - 2); +} diff --git a/leetcode/src/520.c b/leetcode/src/520.c new file mode 100644 index 0000000000..399c1c8956 --- /dev/null +++ b/leetcode/src/520.c @@ -0,0 +1,43 @@ +bool detectCapitalUse(char *word) +{ + int len = strlen(word); + if (len == 1) + return 1; + int countUpper = 0, i; + for (i = 0; i < len; i++) + { + if (isupper(word[i])) + countUpper++; + } + /* All lower case */ + if (countUpper == 0) + return 1; + /* 1st character is upper, and the rest is lower case */ + if (countUpper == 1 && isupper(word[0])) + return 1; + /* Check all character is upper case? */ + else + return countUpper == len; +} + +/* Another way */ +bool isAllUpper(char *word) +{ + int len = strlen(word); + for (int i = 0; i < len; i++) + { + if (islower(word[i])) + return 0; + } + return 1; +} +bool detectCapitalUse(char *word) +{ + int len = strlen(word); + for (int i = 1; i < len; i++) + { + if (isupper(word[i]) && !isAllUpper(word)) + return 0; + } + return 1; +} diff --git a/leetcode/src/53.c b/leetcode/src/53.c new file mode 100644 index 0000000000..78351c251f --- /dev/null +++ b/leetcode/src/53.c @@ -0,0 +1,13 @@ + +int maxcmp(int a, int b) { return a >= b ? a : b; } + +int maxSubArray(int *nums, int numsSize) +{ + int maxSoFar = nums[0], maxEndingHere = nums[0]; + for (int i = 1; i < numsSize; i++) + { + maxEndingHere = maxcmp(maxEndingHere + nums[i], nums[i]); + maxSoFar = maxcmp(maxSoFar, maxEndingHere); + } + return maxSoFar; +} diff --git a/leetcode/src/540.c b/leetcode/src/540.c new file mode 100644 index 0000000000..094bb132b0 --- /dev/null +++ b/leetcode/src/540.c @@ -0,0 +1,32 @@ +/** + * Time complexity: O(log n). + * Space complexity: O(1). + * @details The array has a pattern that consists in of the existing sub-array to + * the left of the non-repeating number will satisfy the condition that + * each pair of repeated elements have their first occurrence at the even index + * and their second occurrence at the odd index, and that the sub-array to + * the right of the non-repeating number will satisfy the condition that + * each pair of repeated elements have their first occurrence at the odd index + * and their second occurrence at the even index. With this pattern in mind, + * we can solve the problem using binary search. + */ + +int singleNonDuplicate(int* nums, int numsSize) { + int left = 0, right = numsSize - 1; + while (left < right) { + int mid = (right + left) / 2; + if (mid % 2 == 0) { + if (nums[mid] == nums[mid + 1]) + left = mid + 2; + else + right = mid; + } + else { + if (nums[mid] == nums[mid - 1]) + left = mid + 1; + else + right = mid - 1; + } + } + return nums[left]; +} diff --git a/leetcode/src/561.c b/leetcode/src/561.c new file mode 100644 index 0000000000..fde1ad6fcc --- /dev/null +++ b/leetcode/src/561.c @@ -0,0 +1,8 @@ +int cmpval(const void *a, const void *b) { return *(int *)a - *(int *)b; } +int arrayPairSum(int *nums, int numsSize) +{ + int sum = 0, i; + qsort(nums, numsSize, sizeof(int), cmpval); + for (i = 0; i < numsSize; i = i + 2) sum = sum + nums[i]; + return sum; +} diff --git a/leetcode/src/567.c b/leetcode/src/567.c new file mode 100644 index 0000000000..268579a03d --- /dev/null +++ b/leetcode/src/567.c @@ -0,0 +1,67 @@ +const int EnglishLettersNumber = 26; + +void countCharsForStringSlice(int* charsCounter, char* s, int length, int sign) { + for (int i = 0; i < length; i++) { + + charsCounter[s[i] - 'a'] += sign; + } +} + +// Sliding window +// Calculate number of chars in the current slide. +// Runtime: O(n) +// Space: O(1) - only number of english lowercase letters. +bool checkInclusion(char* s1, char* s2) { + int lengthS1 = strlen(s1); + int lengthS2 = strlen(s2); + + if (lengthS1 > lengthS2) { + + return false; + } + + int* charsCounter = calloc(EnglishLettersNumber, sizeof(int)); + + // We keep counters of s1 with '-' sign. It has to be offset by s2 chars + countCharsForStringSlice(charsCounter, s1, lengthS1, -1); + countCharsForStringSlice(charsCounter, s2, lengthS1, 1); + + int diffChars = 0; + for (int i = 0; i < EnglishLettersNumber; i++) { + if (charsCounter[i] != 0) { + diffChars++; + } + } + + if (diffChars == 0) { + return true; + } + + for (int i = 0; i < lengthS2 - lengthS1; i++) { + int charNumberLeft = s2[i] - 'a'; + int charNumberRight = s2[i + lengthS1] - 'a'; + + charsCounter[charNumberLeft] -= 1; + if (charsCounter[charNumberLeft] == 0) { + diffChars -= 1; + } + else if (charsCounter[charNumberLeft] == -1) { + diffChars += 1; + } + + charsCounter[charNumberRight] += 1; + if (charsCounter[charNumberRight] == 0) { + diffChars -= 1; + } + else if (charsCounter[charNumberRight] == 1) { + diffChars += 1; + } + + if (diffChars == 0) { + return true; + } + } + + free(charsCounter); + return false; +} diff --git a/leetcode/src/6.c b/leetcode/src/6.c new file mode 100644 index 0000000000..0c67b4f8db --- /dev/null +++ b/leetcode/src/6.c @@ -0,0 +1,151 @@ +/** + * @file + * @brief Implementation of the [ZigZag + * Conversion](https://leetcode.com/problems/zigzag-conversion/) Leetcode + * problem + * @details + * A decent solution to the ZigZag conversion problem. + * Take advantage of the fact that the maximum gap between the chars is 2 times + * the depth(the number of rows). + * The actual gap between the two first chars of a rows depends on the depth of + * the row. The gaps between successives chars on the same row is the complement + * of the first gap to the maximum gap. + * @author [straight_into_the_wall](https://github.com/straight-into-the-wall) + */ + +#include /// for assert +#include /// for unsigned int with fixed size +#include /// for IO operations +#include /// for malloc +#include /// for string tools + +/** + * @brief Convert a string to the it's zigzag equivalent on a given number of + * rows. + * @param in the string in input. + * @param numRows the desired number of rows. + * @returns the converted new (malloced) string. + */ +char* convert(char* in, uint16_t numRows) +{ + uint16_t len = strlen(in); + + if (len < numRows) + { + numRows = len; + } + char* out = calloc(len + 1, sizeof(char)); + + if (numRows < 2) + { + memcpy(out, in, len + 1); + return out; + } + + uint16_t max = numRows - 1; + uint16_t rr = 2 * max; + uint16_t i = 0; + uint16_t o = 0; + uint16_t delta = 0; + + // first row + while (i < len) + { + out[o++] = in[i]; + i += rr; + } + + // middle rows + for (uint16_t l = 1; l < max; l++) + { + i = l; + delta = 2 * l; + while (i < len) + { + out[o++] = in[i]; + delta = rr - delta; + i += delta; + } + } + + // last row + i = max; + while (i < len) + { + out[o++] = in[i]; + i += rr; + } + + return out; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void testZigZag(char* s, int numRows, char* expected) +{ + char* ret = convert(s, numRows); + int len = strlen(s); + int cmp = strncmp(ret, expected, len); + assert(!cmp); + + free(ret); +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() +{ + char* s01 = "PAYPALISHIRING"; + + char* r01 = "PINALSIGYAHRPI"; + testZigZag(s01, 4, r01); + + char* r02 = "PAHNAPLSIIGYIR"; + testZigZag(s01, 3, r02); + + char* s03 = "A"; + testZigZag(s03, 1, s03); + testZigZag(s03, 3, s03); + + char* s04 = + "cbxdwjccgtdoqiscyspqzvuqivzptlpvooynyapgvswoaosaghrffnxnjyeeltzaiznicc" + "ozwknwyhzgpqlwfkjqipuu" + "jvwtxlbznryjdohbvghmyuiggtyqjtmuqinntqmihntkddnalwnmsxsatqqeldacnnpjfe" + "rmrnyuqnwbjjpdjhdeavkn" + "ykpoxhxclqqedqavdwzoiorrwwxyrhlsrdgqkduvtmzzczufvtvfioygkvedervvudnegh" + "bctcbxdxezrzgbpfhzanff" + "eccbgqfmzjqtlrsppxqiywjobspefujlxnmddurddiyobqfspvcoulcvdrzkmkwlyiqdch" + "ghrgytzdnobqcvdeqjystm" + "epxcaniewqmoxkjwpymqorluxedvywhcoghotpusfgiestckrpaigocfufbubiyrrffmwa" + "eeimidfnnzcphkflpbqsvt" + "dwludsgaungfzoihbxifoprwcjzsdxngtacw"; + + char* r04 = + "cbxdwjccgtdoqiscyspqzvuqivzptlpvooynyapgvswoaosaghrffnxnjyeeltzaiznicc" + "ozwknwyhzgpqlwfkjqipuu" + "jvwtxlbznryjdohbvghmyuiggtyqjtmuqinntqmihntkddnalwnmsxsatqqeldacnnpjfe" + "rmrnyuqnwbjjpdjhdeavkn" + "ykpoxhxclqqedqavdwzoiorrwwxyrhlsrdgqkduvtmzzczufvtvfioygkvedervvudnegh" + "bctcbxdxezrzgbpfhzanff" + "eccbgqfmzjqtlrsppxqiywjobspefujlxnmddurddiyobqfspvcoulcvdrzkmkwlyiqdch" + "ghrgytzdnobqcvdeqjystm" + "epxcaniewqmoxkjwpymqorluxedvywhcoghotpusfgiestckrpaigocfufbubiyrrffmwa" + "eeimidfnnzwccpahtkgfnl" + "xpdbsqzsjvctwdrwploufdisxgbahuinogzf"; + + testZigZag(s04, 472, r04); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main(void) +{ + test(); // run self-test implementations + return 0; +} diff --git a/leetcode/src/617.c b/leetcode/src/617.c new file mode 100644 index 0000000000..95fca003a1 --- /dev/null +++ b/leetcode/src/617.c @@ -0,0 +1,20 @@ +struct TreeNode *newNode(int item) +{ + struct TreeNode *node = (struct TreeNode *)malloc(sizeof(struct TreeNode)); + node->val = item; + node->left = node->right = NULL; + return node; +} + +struct TreeNode *mergeTrees(struct TreeNode *t1, struct TreeNode *t2) +{ + if (t1 == NULL && t2 == NULL) + return NULL; + int item = (t1 == NULL ? 0 : t1->val) + (t2 == NULL ? 0 : t2->val); + struct TreeNode *node = newNode(item); + node->left = + mergeTrees(t1 == NULL ? NULL : t1->left, t2 == NULL ? NULL : t2->left); + node->right = mergeTrees(t1 == NULL ? NULL : t1->right, + t2 == NULL ? NULL : t2->right); + return node; +} diff --git a/leetcode/src/62.c b/leetcode/src/62.c new file mode 100644 index 0000000000..b2ac88d687 --- /dev/null +++ b/leetcode/src/62.c @@ -0,0 +1,39 @@ +// Dynamic programming can be applied here, because every solved sub-problem has +// an optimal sub-solution +// Searching backwards from end to start, we can incrementally calculate number +// of paths to destination. i.e. start from bottom-right, and calculate +// leftwards (lowest row should all be 1). then go to second-last-row, rightmost +// column, and calculate leftwards the last cell to be calculated is the start +// location (0, 0). The iteration ordering is intentional: the inner loop +// iterates the contents of each vector, the outer loop iterates each vector. +// This is more cache-friendly. + +// Example below, calculated from right-to-left, bottom-to-top. +// 7 by 3 grid +// 28 21 15 10 6 3 1 +// 7 6 5 4 3 2 1 +// 1 1 1 1 1 1 1 + +int uniquePaths(int m, int n) +{ + int dp[m][n]; + + for (int column = 0; column < n; column++) + { + dp[0][column] = 1; + } + + for (int row = 1; row < m; row++) + { + dp[row][0] = 1; + } + + for (int row = 1; row < m; row++) + { + for (int column = 1; column < n; column++) + { + dp[row][column] = dp[row - 1][column] + dp[row][column - 1]; + } + } + return dp[m - 1][n - 1]; +} diff --git a/leetcode/src/63.c b/leetcode/src/63.c new file mode 100644 index 0000000000..d26106fd90 --- /dev/null +++ b/leetcode/src/63.c @@ -0,0 +1,39 @@ +/* +I walk through the grids and record the path numbers at the +same time. +By using a 2D array called paths, it will add up possible so +urce path and save the number. +Noted that: +if the destination has obstacle, we can't reach it +the first grid (paths[0][0]) always set as 1 our previous +path source is either from top or left border of grid has +different condition +*/ + +int uniquePathsWithObstacles(int** obstacleGrid, int obstacleGridSize, + int* obstacleGridColSize) +{ + if (obstacleGrid[obstacleGridSize - 1][*obstacleGridColSize - 1] == 1) + { + return 0; + } + int paths[obstacleGridSize][*obstacleGridColSize]; + for (int i = 0; i < obstacleGridSize; i++) + { + for (int j = 0; j < *obstacleGridColSize; j++) + { + if (obstacleGrid[i][j]) + { + paths[i][j] = 0; + } + else + { + paths[i][j] = (i == 0 && j == 0) + ? 1 + : ((i == 0 ? 0 : paths[i - 1][j]) + + (j == 0 ? 0 : paths[i][j - 1])); + } + } + } + return paths[obstacleGridSize - 1][*obstacleGridColSize - 1]; +} diff --git a/leetcode/src/647.c b/leetcode/src/647.c new file mode 100644 index 0000000000..fa3a0bdc0c --- /dev/null +++ b/leetcode/src/647.c @@ -0,0 +1,25 @@ + +/* Author : Saurav Dubey */ + +int countSubstrings(char *s) +{ + int len = strlen(s); + int i; + int count = 0; + for (i = 0; i < len; i++) + { + // cases handled for both odd and even lenghted Palindrome + + count += countPalin(s, i, i, len); + if (i != len - 1) + count += countPalin(s, i, i + 1, len); + } + return count; +} +int countPalin(char *s, int head, int tail, int len) +{ + int ret = (s[head] == s[tail]) ? 1 : 0; + if (ret && head - 1 >= 0 && tail + 1 < len) + ret += countPalin(s, head - 1, tail + 1, len); + return ret; +} diff --git a/leetcode/src/66.c b/leetcode/src/66.c new file mode 100644 index 0000000000..e312940a88 --- /dev/null +++ b/leetcode/src/66.c @@ -0,0 +1,28 @@ +/** + * Note: The returned array must be malloced, assume caller calls free(). + */ +int *plusOne(int *digits, int digitsSize, int *returnSize) +{ + for (int i = digitsSize - 1; i >= 0; i--) + { + if (digits[i] < 9) + { + digits[i]++; + *returnSize = digitsSize; + return digits; + } + else + { + digits[i] = 0; + } + } + + int *newdigit = (int *)malloc((digitsSize + 1) * sizeof(int)); + newdigit[0] = 1; + for (int i = 1; i < (digitsSize + 1); i++) + { + newdigit[i] = digits[i - 1]; + } + *returnSize = digitsSize + 1; + return newdigit; +} \ No newline at end of file diff --git a/leetcode/src/669.c b/leetcode/src/669.c new file mode 100644 index 0000000000..f8842a3463 --- /dev/null +++ b/leetcode/src/669.c @@ -0,0 +1,30 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * struct TreeNode *left; + * struct TreeNode *right; + * }; + */ + + +// Depth-First Search +// Runtime: O(n) +// Space: O(1) +struct TreeNode* trimBST(struct TreeNode* root, int low, int high){ + if (root == NULL){ + return NULL; + } + + if (root->val > high){ + return trimBST(root->left, low, high); + } + + if (root->val < low){ + return trimBST(root->right, low, high); + } + + root->left = trimBST(root->left, low, high); + root->right = trimBST(root->right, low, high); + return root; +} diff --git a/leetcode/src/674.c b/leetcode/src/674.c new file mode 100644 index 0000000000..1bf6898033 --- /dev/null +++ b/leetcode/src/674.c @@ -0,0 +1,20 @@ +int findLengthOfLCIS(int *nums, int numsSize) +{ + int maxval = 1, i, count = 1; + if (numsSize == 0) + return 0; + for (i = 1; i < numsSize; i++) + { + if (nums[i] > nums[i - 1]) + { + count++; + if (count >= maxval) + maxval = count; + } + else + { + count = 1; + } + } + return maxval; +} diff --git a/leetcode/src/684.c b/leetcode/src/684.c new file mode 100644 index 0000000000..e5de7faa1e --- /dev/null +++ b/leetcode/src/684.c @@ -0,0 +1,49 @@ +/** + * Note: The returned array must be malloced, assume caller calls free(). + */ +int find(int* sets, int index){ + while (sets[index] != index){ + index = sets[index]; + } + + return index; +} + +void unionSet(int* sets, int i1, int i2){ + int i1Parent = find(sets, i1); + int i2Parent = find(sets, i2); + + sets[i1Parent] = i2Parent; +} + +// Union find +// Runtime: O(n) +// Space: O(n) +int* findRedundantConnection(int** edges, int edgesSize, int* edgesColSize, int* returnSize){ + int setsSize = edgesSize + 1; + int* sets = malloc(setsSize * sizeof(int)); + for (int i = 0; i < setsSize; i++){ + sets[i] = i; + } + + int* result = malloc(2 * sizeof(int)); + *returnSize = 2; + + for (int i = 0; i < edgesSize; i++){ + int* edge = edges[i]; + + int i0Parent = find(sets, edge[0]); + int i1Parent = find(sets, edge[1]); + + if (i0Parent == i1Parent){ + result[0] = edge[0]; + result[1] = edge[1]; + continue; + } + + unionSet(sets, i0Parent, i1Parent); + } + + free(sets); + return result; +} diff --git a/leetcode/src/69.c b/leetcode/src/69.c new file mode 100644 index 0000000000..63c0d02519 --- /dev/null +++ b/leetcode/src/69.c @@ -0,0 +1,23 @@ +//using the binary search method is one of the efficient ones for this problem statement. +int mySqrt(int x){ +int start=0; + int end=x; + long long int ans=0; + while(start <= end){ + long long int mid=(start+end)/2; + long long int val=mid*mid; + if( val == x){ + return mid; + } +//if mid is less than the square root of the number(x) store the value of mid in ans. + if( val < x){ + ans = mid; + start = mid+1; + } +//if mid is greater than the square root of the number(x) then ssign the value mid-1 to end. + if( val > x){ + end = mid-1; + } + } + return ans; +} diff --git a/leetcode/src/7.c b/leetcode/src/7.c new file mode 100644 index 0000000000..5b4f76770d --- /dev/null +++ b/leetcode/src/7.c @@ -0,0 +1,17 @@ +#include + +int reverse(int x) +{ + int rev = 0; + while (x != 0) + { + int pop = x % 10; + x /= 10; + if (rev > INT_MAX / 10 || (rev == INT_MAX / 10 && pop > 7)) + return 0; + if (rev < INT_MIN / 10 || (rev == INT_MIN / 10 && pop < -8)) + return 0; + rev = rev * 10 + pop; + } + return rev; +} diff --git a/leetcode/src/700.c b/leetcode/src/700.c new file mode 100644 index 0000000000..73cc1a5a2d --- /dev/null +++ b/leetcode/src/700.c @@ -0,0 +1,27 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * struct TreeNode *left; + * struct TreeNode *right; + * }; + */ + +struct TreeNode *searchBST(struct TreeNode *root, int val) +{ + if (!root) + return NULL; + + if (root->val == val) + { + return root; + } + else if (root->val > val) + { + return searchBST(root->left, val); + } + else + { + return searchBST(root->right, val); + } +} diff --git a/leetcode/src/701.c b/leetcode/src/701.c new file mode 100644 index 0000000000..3f7b7c97f9 --- /dev/null +++ b/leetcode/src/701.c @@ -0,0 +1,18 @@ +struct TreeNode *insertIntoBST(struct TreeNode *root, int val) +{ + if (root == NULL) + { + struct TreeNode *new_val = malloc(sizeof(struct TreeNode)); + new_val->val = val; + new_val->left = new_val->right = NULL; + return new_val; + } + else + { + if (root->val >= val) + root->left = insertIntoBST(root->left, val); + else + root->right = insertIntoBST(root->right, val); + } + return root; +} diff --git a/leetcode/src/704.c b/leetcode/src/704.c new file mode 100644 index 0000000000..8dd2891ccf --- /dev/null +++ b/leetcode/src/704.c @@ -0,0 +1,33 @@ +int search(int *nums, int numsSize, int target) +{ + int low = 0, high = numsSize - 1; + while (low <= high) + { + int mid = low + (high - low) / 2; + if (target > nums[mid]) + { + low = mid + 1; + } + else if (target < nums[mid]) + { + high = mid - 1; + } + else + { + return mid; + } + } + return -1; +} + +/* Another solution: Using bsearch() */ +int cmpint(const void *a, const void *b) { return *(int *)a - *(int *)b; } + +int search(int *nums, int numsSize, int target) +{ + int *ret = bsearch(&target, nums, numsSize, sizeof(int), cmpint); + if (ret) + return (ret - nums); + else + return -1; +} diff --git a/leetcode/src/709.c b/leetcode/src/709.c new file mode 100644 index 0000000000..db2fdee5e6 --- /dev/null +++ b/leetcode/src/709.c @@ -0,0 +1,5 @@ +char *toLowerCase(char *str) +{ + for (int i = 0; i < strlen(str); i++) str[i] = tolower(str[i]); + return str; +} diff --git a/leetcode/src/75.c b/leetcode/src/75.c new file mode 100644 index 0000000000..2cf402f2c8 --- /dev/null +++ b/leetcode/src/75.c @@ -0,0 +1,24 @@ +void swap(int *x, int *y){ + if (x==y) + return; + *x = *x + *y; + *y= *x - *y; + *x= *x - *y; +} + +void sortColors(int* arr, int n){ + int start=0, mid=0, end=n-1; + while(mid<=end){ + if(arr[mid]==1) + mid++; + else if(arr[mid]==0){ + swap(&arr[mid],&arr[start]); + mid++; + start++; + } + else{ + swap(&arr[mid],&arr[end]); + end--; + } + } +} diff --git a/leetcode/src/771.c b/leetcode/src/771.c new file mode 100644 index 0000000000..a635f10635 --- /dev/null +++ b/leetcode/src/771.c @@ -0,0 +1,17 @@ +// for strlen() +#include + +int numJewelsInStones(char *j, char *s) +{ + // as strlen is O(n), store it once rather than using it in for loop + int cnt[500], lens = strlen(s), lenj = strlen(j), sol = 0; + memset(cnt, 0, sizeof(cnt)); + + // lookup to know which character occurs in j + for (int i = 0; i < lenj; i++) cnt[j[i]]++; + + // count the characters in s + for (int i = 0; i < lens; i++) sol += cnt[s[i]]; + + return sol; +} diff --git a/leetcode/src/79.c b/leetcode/src/79.c new file mode 100644 index 0000000000..3ac9d11fbc --- /dev/null +++ b/leetcode/src/79.c @@ -0,0 +1,60 @@ +int getPointKey(int i, int j, int boardSize, int boardColSize){ + return boardSize * boardColSize * i + j; +} + +const int directionsSize = 4; +const int directions[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; + +bool exitsWord(int i, int j, char** board, int boardSize, int* boardColSize, int wordIndex, char* word, int* vistedPointSet){ + if (board[i][j] != word[wordIndex]){ + return false; + } + + if (wordIndex == strlen(word) - 1){ + return true; + } + + for (int k = 0; k < directionsSize; k++){ + int nextI = i + directions[k][0]; + int nextJ = j + directions[k][1]; + + if (nextI < 0 || nextI >= boardSize || nextJ < 0 || nextJ >= boardColSize[i]){ + continue; + } + + int key = getPointKey(nextI, nextJ, boardSize, boardColSize[i]); + if (vistedPointSet[key] == 1){ + continue; + } + + vistedPointSet[key] = 1; + if (exitsWord(nextI, nextJ, board, boardSize, boardColSize, wordIndex + 1, word, vistedPointSet)){ + return true; + } + + vistedPointSet[key] = 0; + } + + return false; +} + + +// Use backtracking. +// Runtime: Runtime: O(n*m*4^len(word)) +bool exist(char** board, int boardSize, int* boardColSize, char* word){ + int* vistedPointSet = (int*) calloc(getPointKey(boardSize, boardColSize[0], boardSize, boardColSize[0]), sizeof(int)); + + for (int i = 0; i < boardSize; i++){ + for (int j = 0; j < boardColSize[i]; j++){ + int key = getPointKey(i, j, boardSize, boardColSize[i]); + vistedPointSet[key] = 1; + if (exitsWord(i, j, board, boardSize, boardColSize, 0, word, vistedPointSet)){ + return true; + }; + + vistedPointSet[key] = 0; + } + } + + return false; +} diff --git a/leetcode/src/8.c b/leetcode/src/8.c new file mode 100644 index 0000000000..bf3f905d72 --- /dev/null +++ b/leetcode/src/8.c @@ -0,0 +1,78 @@ +int myAtoi(char *str) +{ + int minusFlag = 0; + int length = strlen(str); + long int result = 0; + char numberBuffer[11]; + int counter = 0; + while (str[counter] == ' ') + { + counter++; + } + str = &str[counter]; + counter = 0; + + for (int i = 0; i < length; i++) + { + if (i == 0) + { + if (str[0] == '-') + { + minusFlag = 1; + i++; + } + else if (str[0] == '+') + { + i++; + } + } + if (counter > 10) + { + if (minusFlag) + { + return __INT_MAX__ * -1 - 1; + } + else + { + return __INT_MAX__; + } + } + + if (str[i] < '0' || str[i] > '9') + { + break; + } + if (counter == 0 && str[i] == '0') + { + continue; + } + + numberBuffer[counter] = str[i]; + counter++; + } + + int i = 0; + while (counter > 0) + { + if (minusFlag) + { + result -= (numberBuffer[i] - '0') * pow(10.0, counter - 1); + } + else + { + result += (numberBuffer[i] - '0') * pow(10.0, counter - 1); + } + i++; + counter--; + } + + if (result > __INT_MAX__) + { + return __INT_MAX__; + } + else if (result < __INT_MAX__ * -1 - 1) + { + return __INT_MAX__ * -1 - 1; + } + return result; +} diff --git a/leetcode/src/807.c b/leetcode/src/807.c new file mode 100644 index 0000000000..1f51bdd753 --- /dev/null +++ b/leetcode/src/807.c @@ -0,0 +1,32 @@ +#define min(a,b) (((a)<(b))?(a):(b)) +#define max(a,b) (((a)>(b))?(a):(b)) + +// Collect maxes on each row and each column. +// Runtime: O(n * n) +// Space: O(n) +int maxIncreaseKeepingSkyline(int** grid, int gridSize, int* gridColSize){ + int* rowsMaxs = calloc(gridSize, sizeof(int)); + int* colsMaxs = calloc(gridSize, sizeof(int)); + + // Find max of each row and column + for(int i = 0; i < gridSize; i++){ + for (int j = 0; j < gridSize; j++){ + rowsMaxs[i] = max(rowsMaxs[i], grid[i][j]); + colsMaxs[j] = max(colsMaxs[j], grid[i][j]); + } + } + + int result = 0; + for(int i = 0; i < gridSize; i++){ + for (int j = 0; j < gridSize; j++){ + int rowMax = rowsMaxs[i]; + int colMax = colsMaxs[j]; + result += min(rowMax - grid[i][j], colMax - grid[i][j]); + } + } + + free(rowsMaxs); + free(colsMaxs); + + return result; +} diff --git a/leetcode/src/82.c b/leetcode/src/82.c new file mode 100644 index 0000000000..6f784c5993 --- /dev/null +++ b/leetcode/src/82.c @@ -0,0 +1,20 @@ +struct ListNode *deleteDuplicates(struct ListNode *head) +{ + if (head == NULL) + return NULL; + + if (head->next && head->val == head->next->val) + { + /* Remove all duplicate numbers */ + while (head->next && head->val == head->next->val) + { + head = head->next; + } + return deleteDuplicates(head->next); + } + else + { + head->next = deleteDuplicates(head->next); + } + return head; +} diff --git a/leetcode/src/83.c b/leetcode/src/83.c new file mode 100644 index 0000000000..c1848a08bf --- /dev/null +++ b/leetcode/src/83.c @@ -0,0 +1,13 @@ + +struct ListNode *deleteDuplicates(struct ListNode *head) +{ + struct ListNode *cur = head; + while (cur && cur->next) + { + if (cur->val == cur->next->val) + cur->next = cur->next->next; + else + cur = cur->next; + } + return head; +} diff --git a/leetcode/src/841.c b/leetcode/src/841.c new file mode 100644 index 0000000000..cae224887e --- /dev/null +++ b/leetcode/src/841.c @@ -0,0 +1,27 @@ +void visitRooms(int key, int** rooms, int roomsSize, int* roomsColSize, int* visitedRooms){ + if (visitedRooms[key] == 1){ + return; + } + + visitedRooms[key] = 1; + for (int i = 0; i < roomsColSize[key]; i++){ + visitRooms(rooms[key][i], rooms, roomsSize, roomsColSize, visitedRooms); + } +} + +// Depth-first search +// Runtime: O(n) +// Space: O(n) +bool canVisitAllRooms(int** rooms, int roomsSize, int* roomsColSize){ + int* visitedRooms = calloc(roomsSize, sizeof(int)); + visitRooms(0, rooms, roomsSize, roomsColSize, visitedRooms); + + int visitedRoomsNumber = 0; + for (int i = 0; i < roomsSize; i++){ + if (visitedRooms[i] == 1){ + visitedRoomsNumber++; + } + } + + return visitedRoomsNumber == roomsSize; +} diff --git a/leetcode/src/852.c b/leetcode/src/852.c new file mode 100644 index 0000000000..2b485d5567 --- /dev/null +++ b/leetcode/src/852.c @@ -0,0 +1,15 @@ +int peakIndexInMountainArray(int *A, int ASize) +{ + int low = 1, high = ASize; + while (low <= high) + { + int mid = low + (high - low) / 2; + if (A[mid - 1] < A[mid] && A[mid] > A[mid + 1]) + return mid; + else if (A[mid - 1] < A[mid] && A[mid] < A[mid + 1]) + low = mid + 1; + else + high = mid - 1; + } + return -1; +} diff --git a/leetcode/src/876.c b/leetcode/src/876.c new file mode 100644 index 0000000000..b3b3a0a285 --- /dev/null +++ b/leetcode/src/876.c @@ -0,0 +1,19 @@ +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * struct ListNode *next; + * }; + */ + +struct ListNode *middleNode(struct ListNode *head) +{ + struct ListNode *fast, *slow; + fast = slow = head; + while (fast && fast->next) + { + slow = slow->next; + fast = fast->next->next; + } + return slow; +} diff --git a/leetcode/src/9.c b/leetcode/src/9.c new file mode 100644 index 0000000000..29c99c160c --- /dev/null +++ b/leetcode/src/9.c @@ -0,0 +1,16 @@ +bool isPalindrome(int x) +{ + if (x < 0 || (x % 10 == 0 && x != 0)) + { + return false; + } + + int revertedNumber = 0; + while (x > revertedNumber) + { + revertedNumber = revertedNumber * 10 + x % 10; + x /= 10; + } + + return x == revertedNumber || x == revertedNumber / 10; +} diff --git a/leetcode/src/901.c b/leetcode/src/901.c new file mode 100644 index 0000000000..efa712b69c --- /dev/null +++ b/leetcode/src/901.c @@ -0,0 +1,68 @@ +// Use monotonic stack. +// Keep the stack of monotonically increasing price and index. + +// Runtime: O(n) +// Space: O(n) +typedef struct stack{ + int price; + int index; + struct stack* previous; +} Stack; + + +typedef struct { + int index; + Stack* stackPointer; + Stack* sentry; +} StockSpanner; + + +StockSpanner* stockSpannerCreate() { + Stack* sentry = (Stack *)malloc(sizeof(Stack)); + StockSpanner* result = (StockSpanner *)malloc(sizeof(StockSpanner)); + result->index = 0; + result->sentry = sentry; + result->stackPointer = sentry; + return result; +} + +int stockSpannerNext(StockSpanner* obj, int price) { + while(obj->stackPointer != obj->sentry && obj->stackPointer->price <= price){ + Stack* currStackPointer = obj->stackPointer; + obj->stackPointer = obj->stackPointer->previous; + free(currStackPointer); + } + + obj->index += 1; + int result = obj->index; + if (obj->stackPointer != obj->sentry){ + result -= obj->stackPointer->index; + } + + Stack* newStackItem = (Stack *)malloc(sizeof(Stack)); + newStackItem->index = obj->index; + newStackItem->price = price; + newStackItem->previous = obj->stackPointer; + obj->stackPointer = newStackItem; + + return result; +} + +void stockSpannerFree(StockSpanner* obj) { + while(obj->stackPointer != obj->sentry){ + Stack* currStackPointer = obj->stackPointer; + obj->stackPointer = obj->stackPointer->previous; + free(currStackPointer); + } + + free(obj->sentry); + free(obj); +} + +/** + * Your StockSpanner struct will be instantiated and called as such: + * StockSpanner* obj = stockSpannerCreate(); + * int param_1 = stockSpannerNext(obj, price); + + * stockSpannerFree(obj); + */ diff --git a/leetcode/src/905.c b/leetcode/src/905.c new file mode 100644 index 0000000000..802b97f081 --- /dev/null +++ b/leetcode/src/905.c @@ -0,0 +1,34 @@ +/** + * 905. Sort Array By Parity + * Given an array A of non-negative integers, return an array consisting of + * all the even elements of A, followed by all the odd elements of A. + * You may return any answer array that satisfies this condition. + * Example 1: + * Input: [3,1,2,4] + * Output: [2,4,3,1] + * The outputs [4,2,3,1], [2,4,1,3], and [4,2,1,3] would also be accepted. + * + * Note: The returned array must be malloced, assume caller calls free(). + */ +int *sortArrayByParity(int *A, int ASize, int *returnSize) +{ + int *retArr = malloc(ASize * sizeof(int)); + int oddIndex = ASize - 1; + int evenIndex = 0; + *returnSize = ASize; + for (int i = 0; i < ASize; i++) + { + if (A[i] % 2 == 0) + { + retArr[evenIndex] = A[i]; + evenIndex++; + } + else + { + retArr[oddIndex] = A[i]; + oddIndex--; + } + } + + return retArr; +} diff --git a/leetcode/src/917.c b/leetcode/src/917.c new file mode 100644 index 0000000000..fae38a901e --- /dev/null +++ b/leetcode/src/917.c @@ -0,0 +1,23 @@ +char *reverseOnlyLetters(char *S) +{ + int last = strlen(S) - 1, i; + for (i = 0; i < last;) + { + if (!isalpha(S[i])) + { + i++; + continue; + } + if (!isalpha(S[last])) + { + last--; + continue; + } + char tmp = S[i]; + S[i] = S[last]; + S[last] = tmp; + i++; + last--; + } + return S; +} diff --git a/leetcode/src/931.c b/leetcode/src/931.c new file mode 100644 index 0000000000..b257c8c33e --- /dev/null +++ b/leetcode/src/931.c @@ -0,0 +1,37 @@ +#define min(a,b) (((a)<(b))?(a):(b)) + +// Dynamic programming. +// Runtime O(n*n) +// Space O(n) +int minFallingPathSum(int** matrix, int matrixSize, int* matrixColSize){ + int* dp = calloc(matrixSize, sizeof(int)); + + for (int i = 0; i < matrixSize; i++){ + int* nextDp = calloc(matrixSize, sizeof(int)); + + for (int j = 0; j < matrixSize; j++){ + nextDp[j] = dp[j] + matrix[i][j]; + + // If not the first column - try to find minimum in prev column + if(j > 0){ + nextDp[j] = min(nextDp[j], dp[j - 1] + matrix[i][j]); + } + + // If not the last column - try to find minimum in next column + if (j < matrixSize - 1){ + nextDp[j] = min(nextDp[j], dp[j + 1] + matrix[i][j]); + } + } + + free(dp); + dp = nextDp; + } + + int result = dp[0]; + for (int j = 1; j < matrixSize; j++){ + result = min(result, dp[j]); + } + + free(dp); + return result; +} diff --git a/leetcode/src/938.c b/leetcode/src/938.c new file mode 100644 index 0000000000..7c6636a830 --- /dev/null +++ b/leetcode/src/938.c @@ -0,0 +1,16 @@ +int rangeSumBST(struct TreeNode *root, int L, int R) +{ + if (root == NULL) + { + return 0; + } + else if (root->val >= L && root->val <= R) + { + return root->val + rangeSumBST(root->left, L, R) + + rangeSumBST(root->right, L, R); + } + else + { + return rangeSumBST(root->left, L, R) + rangeSumBST(root->right, L, R); + } +} diff --git a/leetcode/src/94.c b/leetcode/src/94.c new file mode 100644 index 0000000000..d9abcc4508 --- /dev/null +++ b/leetcode/src/94.c @@ -0,0 +1,17 @@ +void processTraversal(struct TreeNode *root, int *res, int *size) +{ + if (!root) + return; + processTraversal(root->left, res, size); + res[*size] = root->val; + *size = *size + 1; + processTraversal(root->right, res, size); +} + +int *inorderTraversal(struct TreeNode *root, int *returnSize) +{ + int *res = malloc(256 * sizeof(int)); + *returnSize = 0; + processTraversal(root, res, returnSize); + return res; +} diff --git a/leetcode/src/953.c b/leetcode/src/953.c new file mode 100644 index 0000000000..cb13d85d1e --- /dev/null +++ b/leetcode/src/953.c @@ -0,0 +1,40 @@ +#define min(x, y) (((x) < (y)) ? (x) : (y)) + +bool isWordLess(char* word1, char* word2, int* charOrder){ + int word1Length = strlen(word1); + int word2Length = strlen(word2); + + for(int i = 0; i < min(word1Length, word2Length); i++) { + int charWordsDiff = (charOrder[word1[i] - 'a'] - charOrder[word2[i] - 'a']); + + if (charWordsDiff < 0){ + return true; + } + + if (charWordsDiff > 0){ + return false; + } + } + + return word1Length <= word2Length; +} + +// Keep array-hashtable of order letters. +// Runtime: O(n) +// Space: O(1) +bool isAlienSorted(char ** words, int wordsSize, char * order){ + const int lowerCaseLettersNumber = 26; + int charorder[lowerCaseLettersNumber]; + + for(int i = 0; i < lowerCaseLettersNumber; i++) { + charorder[order[i] - 'a'] = i; + } + + for(int i = 0; i < wordsSize - 1; i++) { + if (!isWordLess(words[i], words[i + 1], charorder)){ + return false; + } + } + + return true; +} diff --git a/leetcode/src/965.c b/leetcode/src/965.c new file mode 100644 index 0000000000..0892be6cbc --- /dev/null +++ b/leetcode/src/965.c @@ -0,0 +1,16 @@ +bool isUnivalTree(struct TreeNode *root) +{ + if (root == NULL) + return 1; + if (root->left) + { + if (root->left->val != root->val) + return 0; + } + if (root->right) + { + if (root->right->val != root->val) + return 0; + } + return isUnivalTree(root->left) && isUnivalTree(root->right); +} diff --git a/leetcode/src/977.c b/leetcode/src/977.c new file mode 100644 index 0000000000..66b23607af --- /dev/null +++ b/leetcode/src/977.c @@ -0,0 +1,33 @@ +/* 1st way: Using 2 pointers */ +int *sortedSquares(int *A, int ASize, int *returnSize) +{ + int i, start = 0, end = ASize - 1; + int *res = malloc(ASize * sizeof(int)); + *returnSize = ASize; + for (i = ASize - 1; i >= 0; i--) + { + if (abs(A[start]) > A[end]) + { + res[i] = A[start] * A[start]; + start++; + } + else + { + res[i] = A[end] * A[end]; + end--; + } + } + return res; +} + +/* 2nd way: Using qsort */ +int cmpval(const void *a, const void *b) { return *(int *)a - *(int *)b; } + +int *sortedSquares(int *A, int ASize, int *returnSize) +{ + int *res = malloc(ASize * sizeof(int)); + for (int i = 0; i < ASize; i++) res[i] = A[i] * A[i]; + *returnSize = ASize; + qsort(res, ASize, sizeof(int), cmpval); + return res; +} diff --git a/leetcode/src/979.c b/leetcode/src/979.c new file mode 100644 index 0000000000..b6ad8b1b95 --- /dev/null +++ b/leetcode/src/979.c @@ -0,0 +1,47 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * struct TreeNode *left; + * struct TreeNode *right; + * }; + */ + +struct NodeDistributeInfo { + int distributeMoves; + int distributeExcess; +}; + +struct NodeDistributeInfo* getDisturb(struct TreeNode* node) { + struct NodeDistributeInfo* result = malloc(sizeof(struct NodeDistributeInfo)); + + if (node == NULL) { + result->distributeMoves = 0; + result->distributeExcess = 1; + return result; + } + + struct NodeDistributeInfo* leftDistribute = getDisturb(node->left); + struct NodeDistributeInfo* rightDistribute = getDisturb(node->right); + + int coinsToLeft = 1 - leftDistribute->distributeExcess; + int coinsToRight = 1 - rightDistribute->distributeExcess; + + // Calculate moves as excess and depth between left and right subtrees. + result->distributeMoves = leftDistribute->distributeMoves + rightDistribute->distributeMoves + abs(coinsToLeft) + abs(coinsToRight); + result->distributeExcess = node->val - coinsToLeft - coinsToRight; + + free(leftDistribute); + free(rightDistribute); + + return result; +} + +// Depth-first search . +// On each node-step we try to recombinate coins between left and right subtree. +// We know that coins are the same number that nodes, and we can get coins by depth +// Runtime: O(n) +// Space: O(1) +int distributeCoins(struct TreeNode* root) { + return getDisturb(root)->distributeMoves; +} diff --git a/leetcode/src/98.c b/leetcode/src/98.c new file mode 100644 index 0000000000..775fe9e1b7 --- /dev/null +++ b/leetcode/src/98.c @@ -0,0 +1,24 @@ +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * struct TreeNode *left; + * struct TreeNode *right; + * }; + */ + +// Depth first search approach. +// Runtime: O(n) +// Space: O(1) +bool checkIsBst(struct TreeNode* node, bool leftBoundInf, int leftBound, bool rightBoundInf, int rightBound){ + return + (node == NULL) + || (leftBoundInf || node->val > leftBound) + && (rightBoundInf || node->val < rightBound) + && checkIsBst(node->left, leftBoundInf, leftBound, false, node->val) + && checkIsBst(node->right, false, node->val, rightBoundInf, rightBound); +} + +bool isValidBST(struct TreeNode* root){ + return checkIsBst(root, true, INT_MIN, true, INT_MAX); +} diff --git a/leetcode/src/985.c b/leetcode/src/985.c new file mode 100644 index 0000000000..7a2343ab22 --- /dev/null +++ b/leetcode/src/985.c @@ -0,0 +1,39 @@ +/** + * Note: The returned array must be malloced, assume caller calls free(). + */ + +// collecting sum Runtime: O(len(queries)), Space: O(1) +int* sumEvenAfterQueries(int* nums, int numsSize, int** queries, int queriesSize, int* queriesColSize, int* returnSize){ + int summ = 0; + int* result = malloc(queriesSize * sizeof(int)); + *returnSize = queriesSize; + + for(int i = 0; i < numsSize; i++){ + if (nums[i] % 2 == 0) { + summ += nums[i]; + } + } + + for(int i = 0; i < queriesSize; i++){ + int* query = queries[i]; + int val = query[0]; + int index = query[1]; + + // sub index value from summ if it's even + if (nums[index] % 2 == 0) { + summ -= nums[index]; + } + + // modify the nums[index] value + nums[index] += val; + + // add index value from summ if it's even + if (nums[index] % 2 == 0) { + summ += nums[index]; + } + + result[i] = summ; + } + + return result; +} diff --git a/leetcode/src/997.c b/leetcode/src/997.c new file mode 100644 index 0000000000..a599555fc3 --- /dev/null +++ b/leetcode/src/997.c @@ -0,0 +1,29 @@ +// Using hashtable. +// Runtime: O(n + len(trust)) +// Space: O(n) +int findJudge(int n, int** trust, int trustSize, int* trustColSize){ + int* personsToTrust = calloc(n + 1, sizeof(int)); + int* personsFromTrust = calloc(n + 1, sizeof(int)); + + for(int i = 0; i < trustSize; i++){ + int* currentTrust = trust[i]; + personsToTrust[currentTrust[1]] += 1; + personsFromTrust[currentTrust[0]] += 1; + } + + int potentialJudjeNumber = -1; + for(int i = 1; i < n + 1; i++){ + if (personsToTrust[i] == n - 1 && personsFromTrust[i] == 0){ + if (potentialJudjeNumber > -1){ + return -1; + } + + potentialJudjeNumber = i; + } + } + + free(personsToTrust); + free(personsFromTrust); + + return potentialJudjeNumber; +} diff --git a/machine_learning/CMakeLists.txt b/machine_learning/CMakeLists.txt new file mode 100644 index 0000000000..598ed72f43 --- /dev/null +++ b/machine_learning/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} *.c ) +# 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 ".c" "" testname ${testsourcefile} ) + add_executable( ${testname} ${testsourcefile} ) + + if(OpenMP_C_FOUND) + target_link_libraries(${testname} OpenMP::OpenMP_C) + endif() + if(MATH_LIBRARY) + target_link_libraries(${testname} ${MATH_LIBRARY}) + endif() + install(TARGETS ${testname} DESTINATION "bin/machine_learning") + +endforeach( testsourcefile ${APP_SOURCES} ) diff --git a/machine_learning/adaline_learning.c b/machine_learning/adaline_learning.c new file mode 100644 index 0000000000..b81cccd945 --- /dev/null +++ b/machine_learning/adaline_learning.c @@ -0,0 +1,419 @@ +/** + * \file + * \brief [Adaptive Linear Neuron + * (ADALINE)](https://en.wikipedia.org/wiki/ADALINE) implementation + * \details + * + * [source](https://commons.wikimedia.org/wiki/File:Adaline_flow_chart.gif) + * ADALINE is one of the first and simplest single layer artificial neural + * network. The algorithm essentially implements a linear function + * \f[ f\left(x_0,x_1,x_2,\ldots\right) = + * \sum_j x_jw_j+\theta + * \f] + * where \f$x_j\f$ are the input features of a sample, \f$w_j\f$ are the + * coefficients of the linear function and \f$\theta\f$ is a constant. If we + * know the \f$w_j\f$, then for any given set of features, \f$y\f$ can be + * computed. Computing the \f$w_j\f$ is a supervised learning algorithm wherein + * a set of features and their corresponding outputs are given and weights are + * computed using stochastic gradient descent method. + * \author [Krishna Vedala](https://github.com/kvedala) + */ + +#include +#include +#include +#include +#include +#include +#include + +/** + * @addtogroup machine_learning Machine learning algorithms + * @{ + * @addtogroup adaline Adaline learning algorithm + * @{ + */ + +/** Maximum number of iterations to learn */ +#define MAX_ADALINE_ITER 500 // INT_MAX + +/** structure to hold adaline model parameters */ +struct adaline +{ + double eta; /**< learning rate of the algorithm */ + double *weights; /**< weights of the neural network */ + int num_weights; /**< number of weights of the neural network */ +}; + +/** convergence accuracy \f$=1\times10^{-5}\f$ */ +#define ADALINE_ACCURACY 1e-5 + +/** + * Default constructor + * \param[in] num_features number of features present + * \param[in] eta learning rate (optional, default=0.1) + * \returns new adaline model + */ +struct adaline new_adaline(const int num_features, const double eta) +{ + if (eta <= 0.f || eta >= 1.f) + { + fprintf(stderr, "learning rate should be > 0 and < 1\n"); + exit(EXIT_FAILURE); + } + + // additional weight is for the constant bias term + int num_weights = num_features + 1; + struct adaline ada; + ada.eta = eta; + ada.num_weights = num_weights; + ada.weights = (double *)malloc(num_weights * sizeof(double)); + if (!ada.weights) + { + perror("Unable to allocate error for weights!"); + return ada; + } + + // initialize with random weights in the range [-50, 49] + for (int i = 0; i < num_weights; i++) ada.weights[i] = 1.f; + // ada.weights[i] = (double)(rand() % 100) - 50); + + return ada; +} + +/** delete dynamically allocated memory + * \param[in] ada model from which the memory is to be freed. + */ +void delete_adaline(struct adaline *ada) +{ + if (ada == NULL) + return; + + free(ada->weights); +}; + +/** [Heaviside activation + * function](https://en.wikipedia.org/wiki/Heaviside_step_function) + * @param x activation function input + * @returns \f$f(x)= \begin{cases}1 & \forall\; x > 0\\ -1 & \forall\; x \le0 + * \end{cases}\f$ + */ +int adaline_activation(double x) { return x > 0 ? 1 : -1; } + +/** + * Operator to print the weights of the model + * @param ada model for which the values to print + * @returns pointer to a NULL terminated string of formatted weights + */ +char *adaline_get_weights_str(const struct adaline *ada) +{ + static char out[100]; // static so the value is persistent + + sprintf(out, "<"); + for (int i = 0; i < ada->num_weights; i++) + { + sprintf(out, "%s%.4g", out, ada->weights[i]); + if (i < ada->num_weights - 1) + sprintf(out, "%s, ", out); + } + sprintf(out, "%s>", out); + return out; +} + +/** + * predict the output of the model for given set of features + * + * \param[in] ada adaline model to predict + * \param[in] x input vector + * \param[out] out optional argument to return neuron output before applying + * activation function (`NULL` to ignore) + * \returns model prediction output + */ +int adaline_predict(struct adaline *ada, const double *x, double *out) +{ + double y = ada->weights[ada->num_weights - 1]; // assign bias value + + for (int i = 0; i < ada->num_weights - 1; i++) y += x[i] * ada->weights[i]; + + if (out) // if out variable is not NULL + *out = y; + + // quantizer: apply ADALINE threshold function + return adaline_activation(y); +} + +/** + * Update the weights of the model using supervised learning for one feature + * vector + * + * \param[in] ada adaline model to fit + * \param[in] x feature vector + * \param[in] y known output value + * \returns correction factor + */ +double adaline_fit_sample(struct adaline *ada, const double *x, const int y) +{ + /* output of the model with current weights */ + int p = adaline_predict(ada, x, NULL); + int prediction_error = y - p; // error in estimation + double correction_factor = ada->eta * prediction_error; + + /* update each weight, the last weight is the bias term */ + for (int i = 0; i < ada->num_weights - 1; i++) + { + ada->weights[i] += correction_factor * x[i]; + } + ada->weights[ada->num_weights - 1] += correction_factor; // update bias + + return correction_factor; +} + +/** + * Update the weights of the model using supervised learning for an array of + * vectors. + * + * \param[in] ada adaline model to train + * \param[in] X array of feature vector + * \param[in] y known output value for each feature vector + * \param[in] N number of training samples + */ +void adaline_fit(struct adaline *ada, double **X, const int *y, const int N) +{ + double avg_pred_error = 1.f; + + int iter; + for (iter = 0; + (iter < MAX_ADALINE_ITER) && (avg_pred_error > ADALINE_ACCURACY); + iter++) + { + avg_pred_error = 0.f; + + // perform fit for each sample + for (int i = 0; i < N; i++) + { + double err = adaline_fit_sample(ada, X[i], y[i]); + avg_pred_error += fabs(err); + } + avg_pred_error /= N; + + // Print updates every 200th iteration + // if (iter % 100 == 0) + printf("\tIter %3d: Training weights: %s\tAvg error: %.4f\n", iter, + adaline_get_weights_str(ada), avg_pred_error); + } + + if (iter < MAX_ADALINE_ITER) + printf("Converged after %d iterations.\n", iter); + else + printf("Did not converged after %d iterations.\n", iter); +} + +/** @} + * @} + */ + +/** + * test function to predict points in a 2D coordinate system above the line + * \f$x=y\f$ as +1 and others as -1. + * Note that each point is defined by 2 values or 2 features. + * \param[in] eta learning rate (optional, default=0.01) + */ +void test1(double eta) +{ + struct adaline ada = new_adaline(2, eta); // 2 features + + const int N = 10; // number of sample points + const double saved_X[10][2] = {{0, 1}, {1, -2}, {2, 3}, {3, -1}, + {4, 1}, {6, -5}, {-7, -3}, {-8, 5}, + {-9, 2}, {-10, -15}}; + + double **X = (double **)malloc(N * sizeof(double *)); + const int Y[10] = {1, -1, 1, -1, -1, + -1, 1, 1, 1, -1}; // corresponding y-values + for (int i = 0; i < N; i++) + { + X[i] = (double *)saved_X[i]; + } + + printf("------- Test 1 -------\n"); + printf("Model before fit: %s\n", adaline_get_weights_str(&ada)); + + adaline_fit(&ada, X, Y, N); + printf("Model after fit: %s\n", adaline_get_weights_str(&ada)); + + double test_x[] = {5, -3}; + int pred = adaline_predict(&ada, test_x, NULL); + printf("Predict for x=(5,-3): % d\n", pred); + assert(pred == -1); + printf(" ...passed\n"); + + double test_x2[] = {5, 8}; + pred = adaline_predict(&ada, test_x2, NULL); + printf("Predict for x=(5, 8): % d\n", pred); + assert(pred == 1); + printf(" ...passed\n"); + + // for (int i = 0; i < N; i++) + // free(X[i]); + free(X); + delete_adaline(&ada); +} + +/** + * test function to predict points in a 2D coordinate system above the line + * \f$x+3y=-1\f$ as +1 and others as -1. + * Note that each point is defined by 2 values or 2 features. + * The function will create random sample points for training and test purposes. + * \param[in] eta learning rate (optional, default=0.01) + */ +void test2(double eta) +{ + struct adaline ada = new_adaline(2, eta); // 2 features + + const int N = 50; // number of sample points + + double **X = (double **)malloc(N * sizeof(double *)); + int *Y = (int *)malloc(N * sizeof(int)); // corresponding y-values + for (int i = 0; i < N; i++) X[i] = (double *)malloc(2 * sizeof(double)); + + // generate sample points in the interval + // [-range2/100 , (range2-1)/100] + int range = 500; // sample points full-range + int range2 = range >> 1; // sample points half-range + for (int i = 0; i < N; i++) + { + double x0 = ((rand() % range) - range2) / 100.f; + double x1 = ((rand() % range) - range2) / 100.f; + X[i][0] = x0; + X[i][1] = x1; + Y[i] = (x0 + 3. * x1) > -1 ? 1 : -1; + } + + printf("------- Test 2 -------\n"); + printf("Model before fit: %s\n", adaline_get_weights_str(&ada)); + + adaline_fit(&ada, X, Y, N); + printf("Model after fit: %s\n", adaline_get_weights_str(&ada)); + + int N_test_cases = 5; + double test_x[2]; + for (int i = 0; i < N_test_cases; i++) + { + double x0 = ((rand() % range) - range2) / 100.f; + double x1 = ((rand() % range) - range2) / 100.f; + + test_x[0] = x0; + test_x[1] = x1; + int pred = adaline_predict(&ada, test_x, NULL); + printf("Predict for x=(% 3.2f,% 3.2f): % d\n", x0, x1, pred); + + int expected_val = (x0 + 3. * x1) > -1 ? 1 : -1; + assert(pred == expected_val); + printf(" ...passed\n"); + } + + for (int i = 0; i < N; i++) free(X[i]); + free(X); + free(Y); + delete_adaline(&ada); +} + +/** + * test function to predict points in a 3D coordinate system lying within the + * sphere of radius 1 and centre at origin as +1 and others as -1. Note that + * each point is defined by 3 values but we use 6 features. The function will + * create random sample points for training and test purposes. + * The sphere centred at origin and radius 1 is defined as: + * \f$x^2+y^2+z^2=r^2=1\f$ and if the \f$r^2<1\f$, point lies within the sphere + * else, outside. + * + * \param[in] eta learning rate (optional, default=0.01) + */ +void test3(double eta) +{ + struct adaline ada = new_adaline(6, eta); // 2 features + + const int N = 50; // number of sample points + + double **X = (double **)malloc(N * sizeof(double *)); + int *Y = (int *)malloc(N * sizeof(int)); // corresponding y-values + for (int i = 0; i < N; i++) X[i] = (double *)malloc(6 * sizeof(double)); + + // generate sample points in the interval + // [-range2/100 , (range2-1)/100] + int range = 200; // sample points full-range + int range2 = range >> 1; // sample points half-range + for (int i = 0; i < N; i++) + { + double x0 = ((rand() % range) - range2) / 100.f; + double x1 = ((rand() % range) - range2) / 100.f; + double x2 = ((rand() % range) - range2) / 100.f; + X[i][0] = x0; + X[i][1] = x1; + X[i][2] = x2; + X[i][3] = x0 * x0; + X[i][4] = x1 * x1; + X[i][5] = x2 * x2; + Y[i] = (x0 * x0 + x1 * x1 + x2 * x2) <= 1 ? 1 : -1; + } + + printf("------- Test 3 -------\n"); + printf("Model before fit: %s\n", adaline_get_weights_str(&ada)); + + adaline_fit(&ada, X, Y, N); + printf("Model after fit: %s\n", adaline_get_weights_str(&ada)); + + int N_test_cases = 5; + double test_x[6]; + for (int i = 0; i < N_test_cases; i++) + { + double x0 = ((rand() % range) - range2) / 100.f; + double x1 = ((rand() % range) - range2) / 100.f; + double x2 = ((rand() % range) - range2) / 100.f; + test_x[0] = x0; + test_x[1] = x1; + test_x[2] = x2; + test_x[3] = x0 * x0; + test_x[4] = x1 * x1; + test_x[5] = x2 * x2; + int pred = adaline_predict(&ada, test_x, NULL); + printf("Predict for x=(% 3.2f,% 3.2f): % d\n", x0, x1, pred); + + int expected_val = (x0 * x0 + x1 * x1 + x2 * x2) <= 1 ? 1 : -1; + assert(pred == expected_val); + printf(" ...passed\n"); + } + + for (int i = 0; i < N; i++) free(X[i]); + free(X); + free(Y); + delete_adaline(&ada); +} + +/** Main function */ +int main(int argc, char **argv) +{ + srand(time(NULL)); // initialize random number generator + + double eta = 0.1; // default value of eta + if (argc == 2) // read eta value from commandline argument if present + eta = strtof(argv[1], NULL); + + test1(eta); + + printf("Press ENTER to continue...\n"); + getchar(); + + test2(eta); + + printf("Press ENTER to continue...\n"); + getchar(); + + test3(eta); + + return 0; +} diff --git a/machine_learning/k_means_clustering.c b/machine_learning/k_means_clustering.c new file mode 100644 index 0000000000..d762a7b4e0 --- /dev/null +++ b/machine_learning/k_means_clustering.c @@ -0,0 +1,390 @@ +/** + * @file k_means_clustering.c + * @brief K Means Clustering Algorithm implemented + * @details + * This file has K Means algorithm implemmented + * It prints test output in eps format + * + * Note: + * Though the code for clustering works for all the + * 2D data points and can be extended for any size vector + * by making the required changes, but note that + * the output method i.e. printEPS is only good for + * polar data points i.e. in a circle and both test + * use the same. + * @author [Lakhan Nad](https://github.com/Lakhan-Nad) + */ + +#define _USE_MATH_DEFINES /* required for MS Visual C */ +#include /* DBL_MAX, DBL_MIN */ +#include /* PI, sin, cos */ +#include /* printf */ +#include /* rand */ +#include /* memset */ +#include /* time */ + +/*! + * @addtogroup machine_learning Machine Learning Algorithms + * @{ + * @addtogroup k_means K-Means Clustering Algorithm + * @{ + */ + +/*! @struct observation + * a class to store points in 2d plane + * the name observation is used to denote + * a random point in plane + */ +typedef struct observation +{ + double x; /**< abscissa of 2D data point */ + double y; /**< ordinate of 2D data point */ + int group; /**< the group no in which this observation would go */ +} observation; + +/*! @struct cluster + * this class stores the coordinates + * of centroid of all the points + * in that cluster it also + * stores the count of observations + * belonging to this cluster + */ +typedef struct cluster +{ + double x; /**< abscissa centroid of this cluster */ + double y; /**< ordinate of centroid of this cluster */ + size_t count; /**< count of observations present in this cluster */ +} cluster; + +/*! + * Returns the index of centroid nearest to + * given observation + * + * @param o observation + * @param clusters array of cluster having centroids coordinates + * @param k size of clusters array + * + * @returns the index of nearest centroid for given observation + */ +int calculateNearst(observation* o, cluster clusters[], int k) +{ + double minD = DBL_MAX; + double dist = 0; + int index = -1; + int i = 0; + for (; i < k; i++) + { + /* Calculate Squared Distance*/ + dist = (clusters[i].x - o->x) * (clusters[i].x - o->x) + + (clusters[i].y - o->y) * (clusters[i].y - o->y); + if (dist < minD) + { + minD = dist; + index = i; + } + } + return index; +} + +/*! + * Calculate centoid and assign it to the cluster variable + * + * @param observations an array of observations whose centroid is calculated + * @param size size of the observations array + * @param centroid a reference to cluster object to store information of + * centroid + */ +void calculateCentroid(observation observations[], size_t size, + cluster* centroid) +{ + size_t i = 0; + centroid->x = 0; + centroid->y = 0; + centroid->count = size; + for (; i < size; i++) + { + centroid->x += observations[i].x; + centroid->y += observations[i].y; + observations[i].group = 0; + } + centroid->x /= centroid->count; + centroid->y /= centroid->count; +} + +/*! + * --K Means Algorithm-- + * 1. Assign each observation to one of k groups + * creating a random initial clustering + * 2. Find the centroid of observations for each + * cluster to form new centroids + * 3. Find the centroid which is nearest for each + * observation among the calculated centroids + * 4. Assign the observation to its nearest centroid + * to create a new clustering. + * 5. Repeat step 2,3,4 until there is no change + * the current clustering and is same as last + * clustering. + * + * @param observations an array of observations to cluster + * @param size size of observations array + * @param k no of clusters to be made + * + * @returns pointer to cluster object + */ +cluster* kMeans(observation observations[], size_t size, int k) +{ + cluster* clusters = NULL; + if (k <= 1) + { + /* + If we have to cluster them only in one group + then calculate centroid of observations and + that will be a ingle cluster + */ + clusters = (cluster*)malloc(sizeof(cluster)); + memset(clusters, 0, sizeof(cluster)); + calculateCentroid(observations, size, clusters); + } + else if (k < size) + { + clusters = malloc(sizeof(cluster) * k); + memset(clusters, 0, k * sizeof(cluster)); + /* STEP 1 */ + for (size_t j = 0; j < size; j++) + { + observations[j].group = rand() % k; + } + size_t changed = 0; + size_t minAcceptedError = + size / + 10000; // Do until 99.99 percent points are in correct cluster + int t = 0; + do + { + /* Initialize clusters */ + for (int i = 0; i < k; i++) + { + clusters[i].x = 0; + clusters[i].y = 0; + clusters[i].count = 0; + } + /* STEP 2*/ + for (size_t j = 0; j < size; j++) + { + t = observations[j].group; + clusters[t].x += observations[j].x; + clusters[t].y += observations[j].y; + clusters[t].count++; + } + for (int i = 0; i < k; i++) + { + clusters[i].x /= clusters[i].count; + clusters[i].y /= clusters[i].count; + } + /* STEP 3 and 4 */ + changed = 0; // this variable stores change in clustering + for (size_t j = 0; j < size; j++) + { + t = calculateNearst(observations + j, clusters, k); + if (t != observations[j].group) + { + changed++; + observations[j].group = t; + } + } + } while (changed > minAcceptedError); // Keep on grouping until we have + // got almost best clustering + } + else + { + /* If no of clusters is more than observations + each observation can be its own cluster + */ + clusters = (cluster*)malloc(sizeof(cluster) * k); + memset(clusters, 0, k * sizeof(cluster)); + for (int j = 0; j < size; j++) + { + clusters[j].x = observations[j].x; + clusters[j].y = observations[j].y; + clusters[j].count = 1; + observations[j].group = j; + } + } + return clusters; +} + +/** + * @} + * @} + */ + +/*! + * A function to print observations and clusters + * The code is taken from + * http://rosettacode.org/wiki/K-means%2B%2B_clustering. + * Even the K Means code is also inspired from it + * + * @note To print in a file use pipeline operator + * ```sh + * ./k_means_clustering > image.eps + * ``` + * + * @param observations observations array + * @param len size of observation array + * @param cent clusters centroid's array + * @param k size of cent array + */ +void printEPS(observation pts[], size_t len, cluster cent[], int k) +{ + int W = 400, H = 400; + double min_x = DBL_MAX, max_x = DBL_MIN, min_y = DBL_MAX, max_y = DBL_MIN; + double scale = 0, cx = 0, cy = 0; + double* colors = (double*)malloc(sizeof(double) * (k * 3)); + int i; + size_t j; + double kd = k * 1.0; + for (i = 0; i < k; i++) + { + *(colors + 3 * i) = (3 * (i + 1) % k) / kd; + *(colors + 3 * i + 1) = (7 * i % k) / kd; + *(colors + 3 * i + 2) = (9 * i % k) / kd; + } + + for (j = 0; j < len; j++) + { + if (max_x < pts[j].x) + { + max_x = pts[j].x; + } + if (min_x > pts[j].x) + { + min_x = pts[j].x; + } + if (max_y < pts[j].y) + { + max_y = pts[j].y; + } + if (min_y > pts[j].y) + { + min_y = pts[j].y; + } + } + scale = W / (max_x - min_x); + if (scale > (H / (max_y - min_y))) + { + scale = H / (max_y - min_y); + }; + cx = (max_x + min_x) / 2; + cy = (max_y + min_y) / 2; + + printf("%%!PS-Adobe-3.0 EPSF-3.0\n%%%%BoundingBox: -5 -5 %d %d\n", W + 10, + H + 10); + printf( + "/l {rlineto} def /m {rmoveto} def\n" + "/c { .25 sub exch .25 sub exch .5 0 360 arc fill } def\n" + "/s { moveto -2 0 m 2 2 l 2 -2 l -2 -2 l closepath " + " gsave 1 setgray fill grestore gsave 3 setlinewidth" + " 1 setgray stroke grestore 0 setgray stroke }def\n"); + for (int i = 0; i < k; i++) + { + printf("%g %g %g setrgbcolor\n", *(colors + 3 * i), + *(colors + 3 * i + 1), *(colors + 3 * i + 2)); + for (j = 0; j < len; j++) + { + if (pts[j].group != i) + { + continue; + } + printf("%.3f %.3f c\n", (pts[j].x - cx) * scale + W / 2, + (pts[j].y - cy) * scale + H / 2); + } + printf("\n0 setgray %g %g s\n", (cent[i].x - cx) * scale + W / 2, + (cent[i].y - cy) * scale + H / 2); + } + printf("\n%%%%EOF"); + + // free accquired memory + free(colors); +} + +/*! + * A function to test the kMeans function + * Generates 100000 points in a circle of + * radius 20.0 with center at (0,0) + * and cluster them into 5 clusters + * + * Output for 100000 points divided in 5 clusters + * @returns None + */ +static void test() +{ + size_t size = 100000L; + observation* observations = + (observation*)malloc(sizeof(observation) * size); + double maxRadius = 20.00; + double radius = 0; + double ang = 0; + size_t i = 0; + for (; i < size; i++) + { + radius = maxRadius * ((double)rand() / RAND_MAX); + ang = 2 * M_PI * ((double)rand() / RAND_MAX); + observations[i].x = radius * cos(ang); + observations[i].y = radius * sin(ang); + } + int k = 5; // No of clusters + cluster* clusters = kMeans(observations, size, k); + printEPS(observations, size, clusters, k); + // Free the accquired memory + free(observations); + free(clusters); +} + +/*! + * A function to test the kMeans function + * Generates 1000000 points in a circle of + * radius 20.0 with center at (0,0) + * and cluster them into 11 clusters + * + * Output for 1000000 points divided in 11 clusters + * @returns None + */ +void test2() +{ + size_t size = 1000000L; + observation* observations = + (observation*)malloc(sizeof(observation) * size); + double maxRadius = 20.00; + double radius = 0; + double ang = 0; + size_t i = 0; + for (; i < size; i++) + { + radius = maxRadius * ((double)rand() / RAND_MAX); + ang = 2 * M_PI * ((double)rand() / RAND_MAX); + observations[i].x = radius * cos(ang); + observations[i].y = radius * sin(ang); + } + int k = 11; // No of clusters + cluster* clusters = kMeans(observations, size, k); + printEPS(observations, size, clusters, k); + // Free the accquired memory + free(observations); + free(clusters); +} + +/*! + * This function calls the test + * function + */ +int main() +{ + srand(time(NULL)); + test(); + /* test2(); */ + return 0; +} diff --git a/machine_learning/kohonen_som_topology.c b/machine_learning/kohonen_som_topology.c new file mode 100644 index 0000000000..2dcc10ac70 --- /dev/null +++ b/machine_learning/kohonen_som_topology.c @@ -0,0 +1,698 @@ +/** + * \file + * \brief [Kohonen self organizing + * map](https://en.wikipedia.org/wiki/Self-organizing_map) (topological map) + * + * This example implements a powerful unsupervised learning algorithm called as + * a self organizing map. The algorithm creates a connected network of weights + * that closely follows the given data points. This thus creates a topological + * map of the given data i.e., it maintains the relationship between various + * data points in a much higher dimensional space by creating an equivalent in a + * 2-dimensional space. + * Trained topological maps for the test cases in the program + * \author [Krishna Vedala](https://github.com/kvedala) + * \warning MSVC 2019 compiler generates code that does not execute as expected. + * However, MinGW, Clang for GCC and Clang for MSVC compilers on windows perform + * as expected. Any insights and suggestions should be directed to the author. + * \see kohonen_som_trace.c + */ +#define _USE_MATH_DEFINES /**< required for MS Visual C */ +#include +#include +#include +#include +#ifdef _OPENMP // check if OpenMP based parallellization is available +#include +#endif + +/** + * @addtogroup machine_learning Machine learning algorithms + * @{ + * @addtogroup kohonen_2d Kohonen SOM topology algorithm + * @{ + */ + +#ifndef max +/** shorthand for maximum value */ +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef min +/** shorthand for minimum value */ +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +/** to store info regarding 3D arrays */ +struct kohonen_array_3d +{ + int dim1; /**< lengths of first dimension */ + int dim2; /**< lengths of second dimension */ + int dim3; /**< lengths of thirddimension */ + double *data; /**< pointer to data */ +}; + +/** Function that returns the pointer to (x, y, z) ^th location in the + * linear 3D array given by: + * \f[ + * X_{i,j,k} = i\times M\times N + j\times N + k + * \f] + * where \f$L\f$, \f$M\f$ and \f$N\f$ are the 3D matrix dimensions. + * \param[in] arr pointer to ::kohonen_array_3d structure + * \param[in] x first index + * \param[in] y second index + * \param[in] z third index + * \returns pointer to (x,y,z)^th location of data + */ +double *kohonen_data_3d(const struct kohonen_array_3d *arr, int x, int y, int z) +{ + int offset = (x * arr->dim2 * arr->dim3) + (y * arr->dim3) + z; + return arr->data + offset; +} + +/** + * Helper function to generate a random number in a given interval. + * \n Steps: + * 1. `r1 = rand() % 100` gets a random number between 0 and 99 + * 2. `r2 = r1 / 100` converts random number to be between 0 and 0.99 + * 3. scale and offset the random number to given range of \f$[a,b)\f$ + * \f[ + * y = (b - a) \times \frac{\text{(random number between 0 and RAND_MAX)} \; + * \text{mod}\; 100}{100} + a \f] + * + * \param[in] a lower limit + * \param[in] b upper limit + * \returns random number in the range \f$[a,b)\f$ + */ +double _random(double a, double b) +{ + return ((b - a) * (rand() % 100) / 100.f) + a; +} + +/** + * Save a given n-dimensional data martix to file. + * + * \param[in] fname filename to save in (gets overwritten without confirmation) + * \param[in] X matrix to save + * \param[in] num_points rows in the matrix = number of points + * \param[in] num_features columns in the matrix = dimensions of points + * \returns 0 if all ok + * \returns -1 if file creation failed + */ +int save_2d_data(const char *fname, double **X, int num_points, + int num_features) +{ + FILE *fp = fopen(fname, "wt"); + if (!fp) // error with fopen + { + char msg[120]; + sprintf(msg, "File error (%s): ", fname); + perror(msg); + return -1; + } + + for (int i = 0; i < num_points; i++) // for each point in the array + { + for (int j = 0; j < num_features; j++) // for each feature in the array + { + fprintf(fp, "%.4g", X[i][j]); // print the feature value + if (j < num_features - 1) // if not the last feature + fputc(',', fp); // suffix comma + } + if (i < num_points - 1) // if not the last row + fputc('\n', fp); // start a new line + } + fclose(fp); + return 0; +} + +/** + * Create the distance matrix or + * [U-matrix](https://en.wikipedia.org/wiki/U-matrix) from the trained weights + * and save to disk. + * + * \param [in] fname filename to save in (gets overwriten without confirmation) + * \param [in] W model matrix to save + * \returns 0 if all ok + * \returns -1 if file creation failed + */ +int save_u_matrix(const char *fname, struct kohonen_array_3d *W) +{ + FILE *fp = fopen(fname, "wt"); + if (!fp) // error with fopen + { + char msg[120]; + sprintf(msg, "File error (%s): ", fname); + perror(msg); + return -1; + } + + int R = max(W->dim1 >> 3, 2); /* neighborhood range */ + + for (int i = 0; i < W->dim1; i++) // for each x + { + for (int j = 0; j < W->dim2; j++) // for each y + { + double distance = 0.f; + int k; + + int from_x = max(0, i - R); + int to_x = min(W->dim1, i + R + 1); + int from_y = max(0, j - R); + int to_y = min(W->dim2, j + R + 1); + int l; +#ifdef _OPENMP +#pragma omp parallel for reduction(+ : distance) +#endif + for (l = from_x; l < to_x; l++) // scan neighborhoor in x + { + for (int m = from_y; m < to_y; m++) // scan neighborhood in y + { + double d = 0.f; + for (k = 0; k < W->dim3; k++) // for each feature + { + double *w1 = kohonen_data_3d(W, i, j, k); + double *w2 = kohonen_data_3d(W, l, m, k); + d += (w1[0] - w2[0]) * (w1[0] - w2[0]); + // distance += w1[0] * w1[0]; + } + distance += sqrt(d); + // distance += d; + } + } + + distance /= R * R; // mean distance from neighbors + fprintf(fp, "%.4g", distance); // print the mean separation + if (j < W->dim2 - 1) // if not the last column + fputc(',', fp); // suffix comma + } + if (i < W->dim1 - 1) // if not the last row + fputc('\n', fp); // start a new line + } + fclose(fp); + return 0; +} + +/** + * Get minimum value and index of the value in a matrix + * \param[in] X matrix to search + * \param[in] N number of points in the vector + * \param[out] val minimum value found + * \param[out] x_idx x-index where minimum value was found + * \param[out] y_idx y-index where minimum value was found + */ +void get_min_2d(double **X, int N, double *val, int *x_idx, int *y_idx) +{ + val[0] = INFINITY; // initial min value + + for (int i = 0; i < N; i++) // traverse each x-index + { + for (int j = 0; j < N; j++) // traverse each y-index + { + if (X[i][j] < val[0]) // if a lower value is found + { // save the value and its index + x_idx[0] = i; + y_idx[0] = j; + val[0] = X[i][j]; + } + } + } +} + +/** + * Update weights of the SOM using Kohonen algorithm + * + * \param[in] X data point + * \param[in,out] W weights matrix + * \param[in,out] D temporary vector to store distances + * \param[in] num_out number of output points + * \param[in] num_features number of features per input sample + * \param[in] alpha learning rate \f$0<\alpha\le1\f$ + * \param[in] R neighborhood range + * \returns minimum distance of sample and trained weights + */ +double kohonen_update_weights(const double *X, struct kohonen_array_3d *W, + double **D, int num_out, int num_features, + double alpha, int R) +{ + int x, y, k; + double d_min = 0.f; + +#ifdef _OPENMP +#pragma omp for +#endif + // step 1: for each 2D output point + for (x = 0; x < num_out; x++) + { + for (y = 0; y < num_out; y++) + { + D[x][y] = 0.f; + // compute Euclidian distance of each output + // point from the current sample + for (k = 0; k < num_features; k++) + { + double *w = kohonen_data_3d(W, x, y, k); + D[x][y] += (w[0] - X[k]) * (w[0] - X[k]); + } + D[x][y] = sqrt(D[x][y]); + } + } + + // step 2: get closest node i.e., node with smallest Euclidian distance to + // the current pattern + int d_min_x, d_min_y; + get_min_2d(D, num_out, &d_min, &d_min_x, &d_min_y); + + // step 3a: get the neighborhood range + int from_x = max(0, d_min_x - R); + int to_x = min(num_out, d_min_x + R + 1); + int from_y = max(0, d_min_y - R); + int to_y = min(num_out, d_min_y + R + 1); + + // step 3b: update the weights of nodes in the + // neighborhood +#ifdef _OPENMP +#pragma omp for +#endif + for (x = from_x; x < to_x; x++) + { + for (y = from_y; y < to_y; y++) + { + /* you can enable the following normalization if needed. + personally, I found it detrimental to convergence */ + // const double s2pi = sqrt(2.f * M_PI); + // double normalize = 1.f / (alpha * s2pi); + + /* apply scaling inversely proportional to distance from the + current node */ + double d2 = + (d_min_x - x) * (d_min_x - x) + (d_min_y - y) * (d_min_y - y); + double scale_factor = exp(-d2 / (2.f * alpha * alpha)); + + for (k = 0; k < num_features; k++) + { + double *w = kohonen_data_3d(W, x, y, k); + // update weights of nodes in the neighborhood + w[0] += alpha * scale_factor * (X[k] - w[0]); + } + } + } + return d_min; +} + +/** + * Apply incremental algorithm with updating neighborhood and learning rates + * on all samples in the given datset. + * + * \param[in] X data set + * \param[in,out] W weights matrix + * \param[in] num_samples number of output points + * \param[in] num_features number of features per input sample + * \param[in] num_out number of output points + * \param[in] alpha_min terminal value of alpha + */ +void kohonen_som(double **X, struct kohonen_array_3d *W, int num_samples, + int num_features, int num_out, double alpha_min) +{ + int R = num_out >> 2, iter = 0; + double **D = (double **)malloc(num_out * sizeof(double *)); + for (int i = 0; i < num_out; i++) + D[i] = (double *)malloc(num_out * sizeof(double)); + + double dmin = 1.f; // average minimum distance of all samples + + // Loop alpha from 1 to slpha_min + for (double alpha = 1.f; alpha > alpha_min && dmin > 1e-3; + alpha -= 0.001, iter++) + { + dmin = 0.f; + // Loop for each sample pattern in the data set + for (int sample = 0; sample < num_samples; sample++) + { + // update weights for the current input pattern sample + dmin += kohonen_update_weights(X[sample], W, D, num_out, + num_features, alpha, R); + } + + // every 20th iteration, reduce the neighborhood range + if (iter % 100 == 0 && R > 1) + R--; + + dmin /= num_samples; + printf("iter: %5d\t alpha: %.4g\t R: %d\td_min: %.4g\r", iter, alpha, R, + dmin); + } + putchar('\n'); + + for (int i = 0; i < num_out; i++) free(D[i]); + free(D); +} + +/** + * @} + * @} + */ + +/** Creates a random set of points distributed in four clusters in + * 3D space with centroids at the points + * * \f$(0,5, 0.5, 0.5)\f$ + * * \f$(0,5,-0.5, -0.5)\f$ + * * \f$(-0,5, 0.5, 0.5)\f$ + * * \f$(-0,5,-0.5, -0.5)\f$ + * + * \param[out] data matrix to store data in + * \param[in] N number of points required + */ +void test_2d_classes(double *const *data, int N) +{ + const double R = 0.3; // radius of cluster + int i; + const int num_classes = 4; + const double centres[][2] = { + // centres of each class cluster + {.5, .5}, // centre of class 1 + {.5, -.5}, // centre of class 2 + {-.5, .5}, // centre of class 3 + {-.5, -.5} // centre of class 4 + }; + +#ifdef _OPENMP +#pragma omp for +#endif + for (i = 0; i < N; i++) + { + int class = + rand() % num_classes; // select a random class for the point + + // create random coordinates (x,y,z) around the centre of the class + data[i][0] = _random(centres[class][0] - R, centres[class][0] + R); + data[i][1] = _random(centres[class][1] - R, centres[class][1] + R); + + /* The follosing can also be used + for (int j = 0; j < 2; j++) + data[i][j] = _random(centres[class][j] - R, centres[class][j] + R); + */ + } +} + +/** Test that creates a random set of points distributed in four clusters in + * 2D space and trains an SOM that finds the topological pattern. + * The following [CSV](https://en.wikipedia.org/wiki/Comma-separated_values) + * files are created to validate the execution: + * * `test1.csv`: random test samples points with a circular pattern + * * `w11.csv`: initial random U-matrix + * * `w12.csv`: trained SOM U-matrix + */ +void test1() +{ + int j, N = 300; + int features = 2; + int num_out = 30; // image size - N x N + + // 2D space, hence size = number of rows * 2 + double **X = (double **)malloc(N * sizeof(double *)); + + // cluster nodex in 'x' * cluster nodes in 'y' * 2 + struct kohonen_array_3d W; + W.dim1 = num_out; + W.dim2 = num_out; + W.dim3 = features; + W.data = (double *)malloc(num_out * num_out * features * + sizeof(double)); // assign rows + + for (int i = 0; i < max(num_out, N); i++) // loop till max(N, num_out) + { + if (i < N) // only add new arrays if i < N + X[i] = (double *)malloc(features * sizeof(double)); + if (i < num_out) // only add new arrays if i < num_out + { + for (int k = 0; k < num_out; k++) + { +#ifdef _OPENMP +#pragma omp for +#endif + // preallocate with random initial weights + for (j = 0; j < features; j++) + { + double *w = kohonen_data_3d(&W, i, k, j); + w[0] = _random(-5, 5); + } + } + } + } + + test_2d_classes(X, N); // create test data around circumference of a circle + save_2d_data("test1.csv", X, N, features); // save test data points + save_u_matrix("w11.csv", &W); // save initial random weights + kohonen_som(X, &W, N, features, num_out, 1e-4); // train the SOM + save_u_matrix("w12.csv", &W); // save the resultant weights + + for (int i = 0; i < N; i++) free(X[i]); + free(X); + free(W.data); +} + +/** Creates a random set of points distributed in four clusters in + * 3D space with centroids at the points + * * \f$(0,5, 0.5, 0.5)\f$ + * * \f$(0,5,-0.5, -0.5)\f$ + * * \f$(-0,5, 0.5, 0.5)\f$ + * * \f$(-0,5,-0.5, -0.5)\f$ + * + * \param[out] data matrix to store data in + * \param[in] N number of points required + */ +void test_3d_classes1(double *const *data, int N) +{ + const double R = 0.2; // radius of cluster + int i; + const int num_classes = 4; + const double centres[][3] = { + // centres of each class cluster + {.5, .5, .5}, // centre of class 1 + {.5, -.5, -.5}, // centre of class 2 + {-.5, .5, .5}, // centre of class 3 + {-.5, -.5 - .5} // centre of class 4 + }; + +#ifdef _OPENMP +#pragma omp for +#endif + for (i = 0; i < N; i++) + { + int class = + rand() % num_classes; // select a random class for the point + + // create random coordinates (x,y,z) around the centre of the class + data[i][0] = _random(centres[class][0] - R, centres[class][0] + R); + data[i][1] = _random(centres[class][1] - R, centres[class][1] + R); + data[i][2] = _random(centres[class][2] - R, centres[class][2] + R); + + /* The follosing can also be used + for (int j = 0; j < 3; j++) + data[i][j] = _random(centres[class][j] - R, centres[class][j] + R); + */ + } +} + +/** Test that creates a random set of points distributed in 4 clusters in + * 3D space and trains an SOM that finds the topological pattern. The following + * [CSV](https://en.wikipedia.org/wiki/Comma-separated_values) files are created + * to validate the execution: + * * `test2.csv`: random test samples points + * * `w21.csv`: initial random U-matrix + * * `w22.csv`: trained SOM U-matrix + */ +void test2() +{ + int j, N = 500; + int features = 3; + int num_out = 30; // image size - N x N + + // 3D space, hence size = number of rows * 3 + double **X = (double **)malloc(N * sizeof(double *)); + + // cluster nodex in 'x' * cluster nodes in 'y' * 2 + struct kohonen_array_3d W; + W.dim1 = num_out; + W.dim2 = num_out; + W.dim3 = features; + W.data = (double *)malloc(num_out * num_out * features * + sizeof(double)); // assign rows + + for (int i = 0; i < max(num_out, N); i++) // loop till max(N, num_out) + { + if (i < N) // only add new arrays if i < N + X[i] = (double *)malloc(features * sizeof(double)); + if (i < num_out) // only add new arrays if i < num_out + { + for (int k = 0; k < num_out; k++) + { +#ifdef _OPENMP +#pragma omp for +#endif + for (j = 0; j < features; j++) + { // preallocate with random initial weights + double *w = kohonen_data_3d(&W, i, k, j); + w[0] = _random(-5, 5); + } + } + } + } + + test_3d_classes1(X, N); // create test data + save_2d_data("test2.csv", X, N, features); // save test data points + save_u_matrix("w21.csv", &W); // save initial random weights + kohonen_som(X, &W, N, features, num_out, 1e-4); // train the SOM + save_u_matrix("w22.csv", &W); // save the resultant weights + + for (int i = 0; i < N; i++) free(X[i]); + free(X); + free(W.data); +} + +/** Creates a random set of points distributed in four clusters in + * 3D space with centroids at the points + * * \f$(0,5, 0.5, 0.5)\f$ + * * \f$(0,5,-0.5, -0.5)\f$ + * * \f$(-0,5, 0.5, 0.5)\f$ + * * \f$(-0,5,-0.5, -0.5)\f$ + * + * \param[out] data matrix to store data in + * \param[in] N number of points required + */ +void test_3d_classes2(double *const *data, int N) +{ + const double R = 0.2; // radius of cluster + int i; + const int num_classes = 8; + const double centres[][3] = { + // centres of each class cluster + {.5, .5, .5}, // centre of class 1 + {.5, .5, -.5}, // centre of class 2 + {.5, -.5, .5}, // centre of class 3 + {.5, -.5, -.5}, // centre of class 4 + {-.5, .5, .5}, // centre of class 5 + {-.5, .5, -.5}, // centre of class 6 + {-.5, -.5, .5}, // centre of class 7 + {-.5, -.5, -.5} // centre of class 8 + }; + +#ifdef _OPENMP +#pragma omp for +#endif + for (i = 0; i < N; i++) + { + int class = + rand() % num_classes; // select a random class for the point + + // create random coordinates (x,y,z) around the centre of the class + data[i][0] = _random(centres[class][0] - R, centres[class][0] + R); + data[i][1] = _random(centres[class][1] - R, centres[class][1] + R); + data[i][2] = _random(centres[class][2] - R, centres[class][2] + R); + + /* The follosing can also be used + for (int j = 0; j < 3; j++) + data[i][j] = _random(centres[class][j] - R, centres[class][j] + R); + */ + } +} + +/** Test that creates a random set of points distributed in eight clusters in + * 3D space and trains an SOM that finds the topological pattern. The following + * [CSV](https://en.wikipedia.org/wiki/Comma-separated_values) files are created + * to validate the execution: + * * `test3.csv`: random test samples points + * * `w31.csv`: initial random U-matrix + * * `w32.csv`: trained SOM U-matrix + */ +void test3() +{ + int j, N = 500; + int features = 3; + int num_out = 30; + double **X = (double **)malloc(N * sizeof(double *)); + + // cluster nodex in 'x' * cluster nodes in 'y' * 2 + struct kohonen_array_3d W; + W.dim1 = num_out; + W.dim2 = num_out; + W.dim3 = features; + W.data = (double *)malloc(num_out * num_out * features * + sizeof(double)); // assign rows + + for (int i = 0; i < max(num_out, N); i++) // loop till max(N, num_out) + { + if (i < N) // only add new arrays if i < N + X[i] = (double *)malloc(features * sizeof(double)); + if (i < num_out) // only add new arrays if i < num_out + { + for (int k = 0; k < num_out; k++) + { +#ifdef _OPENMP +#pragma omp for +#endif + // preallocate with random initial weights + for (j = 0; j < features; j++) + { + double *w = kohonen_data_3d(&W, i, k, j); + w[0] = _random(-5, 5); + } + } + } + } + + test_3d_classes2(X, N); // create test data around the lamniscate + save_2d_data("test3.csv", X, N, features); // save test data points + save_u_matrix("w31.csv", &W); // save initial random weights + kohonen_som(X, &W, N, features, num_out, 0.01); // train the SOM + save_u_matrix("w32.csv", &W); // save the resultant weights + + for (int i = 0; i < N; i++) free(X[i]); + free(X); + free(W.data); +} + +/** + * Convert clock cycle difference to time in seconds + * + * \param[in] start_t start clock + * \param[in] end_t end clock + * \returns time difference in seconds + */ +double get_clock_diff(clock_t start_t, clock_t end_t) +{ + return (double)(end_t - start_t) / (double)CLOCKS_PER_SEC; +} + +/** Main function */ +int main(int argc, char **argv) +{ +#ifdef _OPENMP + printf("Using OpenMP based parallelization\n"); +#else + printf("NOT using OpenMP based parallelization\n"); +#endif + clock_t start_clk, end_clk; + + start_clk = clock(); + test1(); + end_clk = clock(); + printf("Test 1 completed in %.4g sec\n", + get_clock_diff(start_clk, end_clk)); + + start_clk = clock(); + test2(); + end_clk = clock(); + printf("Test 2 completed in %.4g sec\n", + get_clock_diff(start_clk, end_clk)); + + start_clk = clock(); + test3(); + end_clk = clock(); + printf("Test 3 completed in %.4g sec\n", + get_clock_diff(start_clk, end_clk)); + + printf("(Note: Calculated times include: writing files to disk.)\n\n"); + return 0; +} diff --git a/machine_learning/kohonen_som_trace.c b/machine_learning/kohonen_som_trace.c new file mode 100644 index 0000000000..8ca54218ba --- /dev/null +++ b/machine_learning/kohonen_som_trace.c @@ -0,0 +1,543 @@ +/** + * \file + * \brief [Kohonen self organizing + * map](https://en.wikipedia.org/wiki/Self-organizing_map) (data tracing) + * + * \details + * This example implements a powerful self organizing map algorithm. + * The algorithm creates a connected network of weights that closely + * follows the given data points. This creates a chain of nodes that + * resembles the given input shape. + * \author [Krishna Vedala](https://github.com/kvedala) + * \see kohonen_som_topology.c + */ +#define _USE_MATH_DEFINES /**< required for MS Visual C */ +#include +#include +#include +#include +#ifdef _OPENMP // check if OpenMP based parallelization is available +#include +#endif + +/** + * @addtogroup machine_learning Machine learning algorithms + * @{ + * @addtogroup kohonen_1d Kohonen SOM trace/chain algorithm + * @{ + */ + +#ifndef max +/** shorthand for maximum value */ +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#endif +#ifndef min +/** shorthand for minimum value */ +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +/** + * \brief Helper function to generate a random number in a given interval. + * \details + * \n Steps: + * 1. `r1 = rand() % 100` gets a random number between 0 and 99 + * 2. `r2 = r1 / 100` converts random number to be between 0 and 0.99 + * 3. scale and offset the random number to given range of \f$[a,b)\f$ + * \f[ + * y = (b - a) \times \frac{\text{(random number between 0 and RAND_MAX)} \; + * \text{mod}\; 100}{100} + a \f] + * + * \param a lower limit + * \param b upper limit + * \returns random number in the range \f$[a,b)\f$ + */ +double _random(double a, double b) +{ + int r = rand() % 100; + return ((b - a) * r / 100.f) + a; +} + +/** + * Save a given n-dimensional data martix to file. + * + * \param [in] fname filename to save in (gets overwriten without confirmation) + * \param [in] X matrix to save + * \param [in] num_points rows in the matrix = number of points + * \param [in] num_features columns in the matrix = dimensions of points + * \returns 0 if all ok + * \returns -1 if file creation failed + */ +int save_nd_data(const char *fname, double **X, int num_points, + int num_features) +{ + FILE *fp = fopen(fname, "wt"); + if (!fp) // error with fopen + { + char msg[120]; + sprintf(msg, "File error (%s): ", fname); + perror(msg); + return -1; + } + + for (int i = 0; i < num_points; i++) // for each point in the array + { + for (int j = 0; j < num_features; j++) // for each feature in the array + { + fprintf(fp, "%.4g", X[i][j]); // print the feature value + if (j < num_features - 1) // if not the last feature + fprintf(fp, ","); // suffix comma + } + if (i < num_points - 1) // if not the last row + fprintf(fp, "\n"); // start a new line + } + fclose(fp); + return 0; +} + +/** + * Get minimum value and index of the value in a vector + * \param[in] X vector to search + * \param[in] N number of points in the vector + * \param[out] val minimum value found + * \param[out] idx index where minimum value was found + */ +void kohonen_get_min_1d(double const *X, int N, double *val, int *idx) +{ + val[0] = INFINITY; // initial min value + + for (int i = 0; i < N; i++) // check each value + { + if (X[i] < val[0]) // if a lower value is found + { // save the value and its index + idx[0] = i; + val[0] = X[i]; + } + } +} + +/** + * Update weights of the SOM using Kohonen algorithm + * + * \param[in] x data point + * \param[in,out] W weights matrix + * \param[in,out] D temporary vector to store distances + * \param[in] num_out number of output points + * \param[in] num_features number of features per input sample + * \param[in] alpha learning rate \f$0<\alpha\le1\f$ + * \param[in] R neighborhood range + */ +void kohonen_update_weights(double const *x, double *const *W, double *D, + int num_out, int num_features, double alpha, int R) +{ + int j, k; + +#ifdef _OPENMP +#pragma omp for +#endif + // step 1: for each output point + for (j = 0; j < num_out; j++) + { + D[j] = 0.f; + // compute Euclidian distance of each output + // point from the current sample + for (k = 0; k < num_features; k++) + D[j] += (W[j][k] - x[k]) * (W[j][k] - x[k]); + } + + // step 2: get closest node i.e., node with smallest Euclidian distance to + // the current pattern + int d_min_idx; + double d_min; + kohonen_get_min_1d(D, num_out, &d_min, &d_min_idx); + + // step 3a: get the neighborhood range + int from_node = max(0, d_min_idx - R); + int to_node = min(num_out, d_min_idx + R + 1); + + // step 3b: update the weights of nodes in the + // neighborhood +#ifdef _OPENMP +#pragma omp for +#endif + for (j = from_node; j < to_node; j++) + for (k = 0; k < num_features; k++) + // update weights of nodes in the neighborhood + W[j][k] += alpha * (x[k] - W[j][k]); +} + +/** + * Apply incremental algorithm with updating neighborhood and learning rates + * on all samples in the given datset. + * + * \param[in] X data set + * \param[in,out] W weights matrix + * \param[in] num_samples number of output points + * \param[in] num_features number of features per input sample + * \param[in] num_out number of output points + * \param[in] alpha_min terminal value of alpha + */ +void kohonen_som_tracer(double **X, double *const *W, int num_samples, + int num_features, int num_out, double alpha_min) +{ + int R = num_out >> 2, iter = 0; + double alpha = 1.f; + double *D = (double *)malloc(num_out * sizeof(double)); + + // Loop alpha from 1 to alpha_min + for (; alpha > alpha_min; alpha -= 0.01, iter++) + { + // Loop for each sample pattern in the data set + for (int sample = 0; sample < num_samples; sample++) + { + const double *x = X[sample]; + // update weights for the current input pattern sample + kohonen_update_weights(x, W, D, num_out, num_features, alpha, R); + } + + // every 10th iteration, reduce the neighborhood range + if (iter % 10 == 0 && R > 1) + R--; + } + + free(D); +} + +/** + * @} + * @} + */ + +/** Creates a random set of points distributed *near* the circumference + * of a circle and trains an SOM that finds that circular pattern. The + * generating function is + * \f{eqnarray*}{ + * r &\in& [1-\delta r, 1+\delta r)\\ + * \theta &\in& [0, 2\pi)\\ + * x &=& r\cos\theta\\ + * y &=& r\sin\theta + * \f} + * + * \param[out] data matrix to store data in + * \param[in] N number of points required + */ +void test_circle(double *const *data, int N) +{ + const double R = 0.75, dr = 0.3; + double a_t = 0., b_t = 2.f * M_PI; // theta random between 0 and 2*pi + double a_r = R - dr, b_r = R + dr; // radius random between R-dr and R+dr + int i; + +#ifdef _OPENMP +#pragma omp for +#endif + for (i = 0; i < N; i++) + { + double r = _random(a_r, b_r); // random radius + double theta = _random(a_t, b_t); // random theta + data[i][0] = r * cos(theta); // convert from polar to cartesian + data[i][1] = r * sin(theta); + } +} + +/** Test that creates a random set of points distributed *near* the + * circumference of a circle and trains an SOM that finds that circular pattern. + * The following [CSV](https://en.wikipedia.org/wiki/Comma-separated_values) + * files are created to validate the execution: + * * `test1.csv`: random test samples points with a circular pattern + * * `w11.csv`: initial random map + * * `w12.csv`: trained SOM map + * + * The outputs can be readily plotted in [gnuplot](https:://gnuplot.info) using + * the following snippet + * ```gnuplot + * set datafile separator ',' + * plot "test1.csv" title "original", \ + * "w11.csv" title "w1", \ + * "w12.csv" title "w2" + * ``` + * ![Sample execution + * output](https://raw.githubusercontent.com/TheAlgorithms/C/docs/images/machine_learning/kohonen/test1.svg) + */ +void test1() +{ + int j, N = 500; + int features = 2; + int num_out = 50; + + // 2D space, hence size = number of rows * 2 + double **X = (double **)malloc(N * sizeof(double *)); + + // number of clusters nodes * 2 + double **W = (double **)malloc(num_out * sizeof(double *)); + + for (int i = 0; i < max(num_out, N); i++) // loop till max(N, num_out) + { + if (i < N) // only add new arrays if i < N + X[i] = (double *)malloc(features * sizeof(double)); + if (i < num_out) // only add new arrays if i < num_out + { + W[i] = (double *)malloc(features * sizeof(double)); +#ifdef _OPENMP +#pragma omp for +#endif + // preallocate with random initial weights + for (j = 0; j < features; j++) W[i][j] = _random(-1, 1); + } + } + + test_circle(X, N); // create test data around circumference of a circle + save_nd_data("test1.csv", X, N, features); // save test data points + save_nd_data("w11.csv", W, num_out, + features); // save initial random weights + kohonen_som_tracer(X, W, N, features, num_out, 0.1); // train the SOM + save_nd_data("w12.csv", W, num_out, + features); // save the resultant weights + + for (int i = 0; i < max(num_out, N); i++) + { + if (i < N) + free(X[i]); + if (i < num_out) + free(W[i]); + } +} + +/** Creates a random set of points distributed *near* the locus + * of the [Lamniscate of + * Gerono](https://en.wikipedia.org/wiki/Lemniscate_of_Gerono). + * \f{eqnarray*}{ + * \delta r &=& 0.2\\ + * \delta x &\in& [-\delta r, \delta r)\\ + * \delta y &\in& [-\delta r, \delta r)\\ + * \theta &\in& [0, \pi)\\ + * x &=& \delta x + \cos\theta\\ + * y &=& \delta y + \frac{\sin(2\theta)}{2} + * \f} + * \param[out] data matrix to store data in + * \param[in] N number of points required + */ +void test_lamniscate(double *const *data, int N) +{ + const double dr = 0.2; + int i; + +#ifdef _OPENMP +#pragma omp for +#endif + for (i = 0; i < N; i++) + { + double dx = _random(-dr, dr); // random change in x + double dy = _random(-dr, dr); // random change in y + double theta = _random(0, M_PI); // random theta + data[i][0] = dx + cos(theta); // convert from polar to cartesian + data[i][1] = dy + sin(2. * theta) / 2.f; + } +} + +/** Test that creates a random set of points distributed *near* the locus + * of the [Lamniscate of + * Gerono](https://en.wikipedia.org/wiki/Lemniscate_of_Gerono) and trains an SOM + * that finds that circular pattern. The following + * [CSV](https://en.wikipedia.org/wiki/Comma-separated_values) files are created + * to validate the execution: + * * `test2.csv`: random test samples points with a lamniscate pattern + * * `w21.csv`: initial random map + * * `w22.csv`: trained SOM map + * + * The outputs can be readily plotted in [gnuplot](https:://gnuplot.info) using + * the following snippet + * ```gnuplot + * set datafile separator ',' + * plot "test2.csv" title "original", \ + * "w21.csv" title "w1", \ + * "w22.csv" title "w2" + * ``` + * ![Sample execution + * output](https://raw.githubusercontent.com/TheAlgorithms/C/docs/images/machine_learning/kohonen/test2.svg) + */ +void test2() +{ + int j, N = 500; + int features = 2; + int num_out = 20; + double **X = (double **)malloc(N * sizeof(double *)); + double **W = (double **)malloc(num_out * sizeof(double *)); + for (int i = 0; i < max(num_out, N); i++) + { + if (i < N) // only add new arrays if i < N + X[i] = (double *)malloc(features * sizeof(double)); + if (i < num_out) // only add new arrays if i < num_out + { + W[i] = (double *)malloc(features * sizeof(double)); + +#ifdef _OPENMP +#pragma omp for +#endif + // preallocate with random initial weights + for (j = 0; j < features; j++) W[i][j] = _random(-1, 1); + } + } + + test_lamniscate(X, N); // create test data around the lamniscate + save_nd_data("test2.csv", X, N, features); // save test data points + save_nd_data("w21.csv", W, num_out, + features); // save initial random weights + kohonen_som_tracer(X, W, N, features, num_out, 0.01); // train the SOM + save_nd_data("w22.csv", W, num_out, + features); // save the resultant weights + + for (int i = 0; i < max(num_out, N); i++) + { + if (i < N) + free(X[i]); + if (i < num_out) + free(W[i]); + } + free(X); + free(W); +} + +/** Creates a random set of points distributed in four clusters in + * 3D space with centroids at the points + * * \f$(0,5, 0.5, 0.5)\f$ + * * \f$(0,5,-0.5, -0.5)\f$ + * * \f$(-0,5, 0.5, 0.5)\f$ + * * \f$(-0,5,-0.5, -0.5)\f$ + * + * \param[out] data matrix to store data in + * \param[in] N number of points required + */ +void test_3d_classes(double *const *data, int N) +{ + const double R = 0.1; // radius of cluster + int i; + const int num_classes = 4; + const double centres[][3] = { + // centres of each class cluster + {.5, .5, .5}, // centre of class 1 + {.5, -.5, -.5}, // centre of class 2 + {-.5, .5, .5}, // centre of class 3 + {-.5, -.5 - .5} // centre of class 4 + }; + +#ifdef _OPENMP +#pragma omp for +#endif + for (i = 0; i < N; i++) + { + int class = + rand() % num_classes; // select a random class for the point + + // create random coordinates (x,y,z) around the centre of the class + data[i][0] = _random(centres[class][0] - R, centres[class][0] + R); + data[i][1] = _random(centres[class][1] - R, centres[class][1] + R); + data[i][2] = _random(centres[class][2] - R, centres[class][2] + R); + + /* The follosing can also be used + for (int j = 0; j < 3; j++) + data[i][j] = _random(centres[class][j] - R, centres[class][j] + R); + */ + } +} + +/** Test that creates a random set of points distributed in six clusters in + * 3D space. The following + * [CSV](https://en.wikipedia.org/wiki/Comma-separated_values) files are created + * to validate the execution: + * * `test3.csv`: random test samples points with a circular pattern + * * `w31.csv`: initial random map + * * `w32.csv`: trained SOM map + * + * The outputs can be readily plotted in [gnuplot](https:://gnuplot.info) using + * the following snippet + * ```gnuplot + * set datafile separator ',' + * plot "test3.csv" title "original", \ + * "w31.csv" title "w1", \ + * "w32.csv" title "w2" + * ``` + * ![Sample execution + * output](https://raw.githubusercontent.com/TheAlgorithms/C/docs/images/machine_learning/kohonen/test3.svg) + */ +void test3() +{ + int j, N = 200; + int features = 3; + int num_out = 20; + double **X = (double **)malloc(N * sizeof(double *)); + double **W = (double **)malloc(num_out * sizeof(double *)); + for (int i = 0; i < max(num_out, N); i++) + { + if (i < N) // only add new arrays if i < N + X[i] = (double *)malloc(features * sizeof(double)); + if (i < num_out) // only add new arrays if i < num_out + { + W[i] = (double *)malloc(features * sizeof(double)); + +#ifdef _OPENMP +#pragma omp for +#endif + // preallocate with random initial weights + for (j = 0; j < features; j++) W[i][j] = _random(-1, 1); + } + } + + test_3d_classes(X, N); // create test data around the lamniscate + save_nd_data("test3.csv", X, N, features); // save test data points + save_nd_data("w31.csv", W, num_out, + features); // save initial random weights + kohonen_som_tracer(X, W, N, features, num_out, 0.01); // train the SOM + save_nd_data("w32.csv", W, num_out, + features); // save the resultant weights + + for (int i = 0; i < max(num_out, N); i++) + { + if (i < N) + free(X[i]); + if (i < num_out) + free(W[i]); + } + free(X); + free(W); +} + +/** + * Convert clock cycle difference to time in seconds + * + * \param[in] start_t start clock + * \param[in] end_t end clock + * \returns time difference in seconds + */ +double get_clock_diff(clock_t start_t, clock_t end_t) +{ + return (double)(end_t - start_t) / (double)CLOCKS_PER_SEC; +} + +/** Main function */ +int main(int argc, char **argv) +{ +#ifdef _OPENMP + printf("Using OpenMP based parallelization\n"); +#else + printf("NOT using OpenMP based parallelization\n"); +#endif + clock_t start_clk = clock(); + test1(); + clock_t end_clk = clock(); + printf("Test 1 completed in %.4g sec\n", + get_clock_diff(start_clk, end_clk)); + start_clk = clock(); + test2(); + end_clk = clock(); + printf("Test 2 completed in %.4g sec\n", + get_clock_diff(start_clk, end_clk)); + start_clk = clock(); + test3(); + end_clk = clock(); + printf("Test 3 completed in %.4g sec\n", + get_clock_diff(start_clk, end_clk)); + printf( + "(Note: Calculated times include: creating test sets, training " + "model and writing files to disk.)\n\n"); + return 0; +} diff --git a/math/CMakeLists.txt b/math/CMakeLists.txt new file mode 100644 index 0000000000..517ec8ccbd --- /dev/null +++ b/math/CMakeLists.txt @@ -0,0 +1,18 @@ +# 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} *.c ) +foreach( testsourcefile ${APP_SOURCES} ) + string( REPLACE ".c" "" testname ${testsourcefile} ) # File type. Example: `.c` + add_executable( ${testname} ${testsourcefile} ) + + if(OpenMP_C_FOUND) + target_link_libraries(${testname} OpenMP::OpenMP_C) + endif() + if(MATH_LIBRARY) + target_link_libraries(${testname} ${MATH_LIBRARY}) + endif() + install(TARGETS ${testname} DESTINATION "bin/math") # Folder name. Do NOT include `<>` + +endforeach( testsourcefile ${APP_SOURCES} ) diff --git a/math/armstrong_number.c b/math/armstrong_number.c new file mode 100644 index 0000000000..66812f6004 --- /dev/null +++ b/math/armstrong_number.c @@ -0,0 +1,65 @@ +// A number is called as Armstrong number if sum of cubes of digits of number is +// equal to the number itself. +// For Example 153 is an Armstrong number because 153 = 1³+5³+3³. +#include + +// Function to calculate x raised to the power y +int power(int x, unsigned int y) +{ + if (y == 0) + return 1; + if (y % 2 == 0) + return power(x, y / 2) * power(x, y / 2); + return x * power(x, y / 2) * power(x, y / 2); +} + +// Function to calculate order of the number +int order(int x) +{ + int n = 0; + while (x) + { + n++; + x = x / 10; + } + return n; +} + +// Function to check whether the given number is +// Armstrong number or not +int isArmstrong(int x) +{ + // Calling order function + int n = order(x); + int temp = x, sum = 0; + while (temp) + { + int r = temp % 10; + sum += power(r, n); + temp = temp / 10; + } + + // If satisfies Armstrong condition + if (sum == x) + return 1; + else + return 0; +} + +// +int main() +{ + int x = 153; + if (isArmstrong(x) == 1) + printf("True\n"); + else + printf("False\n"); + + x = 1253; + if (isArmstrong(x) == 1) + printf("True\n"); + else + printf("False\n"); + + return 0; +} diff --git a/math/cantor_set.c b/math/cantor_set.c new file mode 100644 index 0000000000..300d620316 --- /dev/null +++ b/math/cantor_set.c @@ -0,0 +1,123 @@ +/** + * @file + * @brief Program to generate [Cantor ternary + * set](https://en.wikipedia.org/wiki/Cantor_set) + */ +#include +#include +#include + +/** structure to define Cantor set */ +typedef struct _cantor_set +{ + double start; /**< start of interval */ + double end; /**< end of interval */ + struct _cantor_set *next; /**< pointer to next set */ +} CantorSet; + +/** Iterative constructor of all sets in the current level. This function + * dynamically allocates memory when creating new sets. These are freed by the + * function ::free_memory. + * @param head pointer to interval set instance to update + */ +void propagate(CantorSet *head) +{ + // if input is NULL, ignore the process + if (head == NULL) + return; + + CantorSet *temp = head; // local pointer to track propagation + + // create new node for the new set + CantorSet *newNode = (CantorSet *)malloc(sizeof(CantorSet)); + + // get 1/3rd of interval + double diff = (((temp->end) - (temp->start)) / 3); + + // update interval ranges + newNode->end = temp->end; + temp->end = ((temp->start) + diff); + newNode->start = (newNode->end) - diff; + + // update pointer to next set in this level + newNode->next = temp->next; + + // point to next set + temp->next = newNode; + + // create next set + propagate(temp->next->next); +} + +/** Print sets in the current range to `stdout` + * @param head pointer to first set in the current level + */ +void print(CantorSet *head) +{ + CantorSet *temp = head; + while (temp != NULL) // print while a valid set is found + { + printf("\t"); + printf("[%lf] -- ", temp->start); + printf("[%lf]", temp->end); + temp = temp->next; + } + + printf("\n"); +} + +/** Clear memory allocated by ::propagate function. + * @param head pointer to first allocated instance. + */ +void free_memory(CantorSet *head) +{ + if (!head) + return; + + if (head->next) + free_memory(head->next); + + free(head); +} + +/** Main function */ +int main(int argc, char const *argv[]) +{ + int start_num, end_num, levels; + + if (argc < 2) + { + printf("Enter 3 arguments: start_num \t end_num \t levels\n"); + scanf("%d %d %d", &start_num, &end_num, &levels); + } + else + { + start_num = atoi(argv[1]); + end_num = atoi(argv[2]); + levels = atoi(argv[3]); + } + + if (start_num < 0 || end_num < 0 || levels < 0) + { + fprintf(stderr, "All numbers must be positive\n"); + return -1; + } + + CantorSet head = {.start = start_num, .end = end_num, .next = NULL}; + + // loop to propagate each level from top to bottom + for (int i = 0; i < levels; i++) + { + printf("Level %d\t", i); + print(&head); + propagate(&head); + printf("\n"); + } + printf("Level %d\t", levels); + print(&head); + + // delete all memory allocated + free_memory(head.next); + + return 0; +} diff --git a/math/cartesian_to_polar.c b/math/cartesian_to_polar.c new file mode 100644 index 0000000000..bac24632af --- /dev/null +++ b/math/cartesian_to_polar.c @@ -0,0 +1,123 @@ +/** + * @file + * @brief Function to convert a Cartesian co-ordinate to polar form. + */ +#define _USE_MATH_DEFINES /**< required for MS Visual C */ +#include +#include +#include +#include + +/** + * @brief Function to convert cartesian coordinates to polar. + *\f{eqnarray*}{ + r &=& \sqrt{x^2+y^2}\\ + \theta &=& \atan\frac{y}{x} + \f} + * @param [in] x absicca value + * @param [in] y ordinate value + * @param [out] r pointer to store polar radius + * @param [out] theta pointer to store polar angle (in radian) + */ +void to_polar(double x, double y, double *r, double *theta) +{ + double thetaFinal = 0.f; + + *r = sqrt(x * x + y * y); + + if (x != 0) + { + if (y != 0) + { + *theta = atan(y / x); + if ((x > 0 && y > 0) || (x == -y)) + { // Q1 + thetaFinal = *theta; + } + else if (x < 0 && y > 0) + { // Q2 + thetaFinal = *theta + M_PI; + } + else if (x < 0 && y < 0) + { // Q3 + thetaFinal = *theta - M_PI; + } + else if (x > 0 && y < 0) + { // Q4 + thetaFinal = 2 * M_PI - *theta; + } + else + { + fprintf(stderr, "Should not reach here!\n"); + } + } + } + else + { // exceptions when no actual angle is present + if (y > 0) + { + thetaFinal = M_PI / 2; + } + else + { + thetaFinal = -(M_PI / 2); + } + } + if (y == 0) + { + if (x > 0) + { + thetaFinal = 0; + } + else + { + thetaFinal = -M_PI; + } + } + + *theta = thetaFinal; +} + +/** + * @brief Generate a random number in the given limits + * + * @param lim1 lower limit + * @param lim2 upper limit + * @return random number in the given range + */ +double get_rand(double lim1, double lim2) +{ + double r = (double)rand() / RAND_MAX; // value in [0,1) + return (lim2 - lim1) * r + lim1; // scale to range +} + +/** + * @brief Test implementation + * + */ +void test() +{ + srand(10); + int NUM_TESTS = 5; + + for (int i = 0; i < NUM_TESTS; i++) + { + double r, theta; + printf("Test %d.... ", i); + double x = get_rand(-5, 5); + double y = get_rand(-5, 5); + printf("(%.2g, %.2g).... ", x, y); + to_polar(x, y, &r, &theta); + assert(fabs(r - hypot(x, y)) < 0.01); + assert(fabs(theta - atan2(y, x)) < 0.01); + printf("passed\n"); + } +} + +/** Main function */ +int main() +{ + test(); + + return 0; +} diff --git a/math/catalan.c b/math/catalan.c new file mode 100644 index 0000000000..2116f5cb68 --- /dev/null +++ b/math/catalan.c @@ -0,0 +1,28 @@ +/* +code for computing nth catalan number +*/ +#include +long int factorial(int x) // long int for more than 10 factorial +{ + int i; + long int fac; // fac stores x factorial + fac = x; + for (i = 1; i < x; i++) // loop to calculate x factorial + { + fac = fac * (x - i); + } + return fac; // returning x factorial +} +int main() +{ + long int f1, f2, f3; // long int for more than 10 factorial + int n; + float C; // C is catalan number for n; + scanf("%d", &n); + f1 = factorial(2 * n); + f2 = factorial(n + 1); + f3 = factorial(n); + C = f1 / (f2 * f3); // formula for catalan number for n + printf("%0.2f", C); + return 0; +} diff --git a/math/collatz.c b/math/collatz.c new file mode 100644 index 0000000000..3725929b39 --- /dev/null +++ b/math/collatz.c @@ -0,0 +1,39 @@ +/** + * \file + * + * \brief Implementation of [Collatz' + * conjecture](https://en.wikipedia.org/wiki/Collatz_conjecture) + * + * Collatz conjecture: a series for a number \f$n\f$ in which if \f$n\f$ even + * then the next number is \f$\frac{n}{2}\f$ ,but if n is odd then the next + * number is \f$3n+1\f$. This series continues till \f$n\f$ reaches 1 + */ + +#include +#include + +/** Main function */ +int main(int argc, char *argv[]) +{ + unsigned long long n, curr_no, num_steps = 0; + if (argc == 2) + n = strtoull(argv[1], NULL, 10); + else + { + printf("Enter starting number: "); + scanf("%lu", &n); // input number + } + + curr_no = n; // curr_no stores input number n + while (curr_no != 1) // loop till series reaches 1 + { + num_steps++; + printf("%llu->", curr_no); + if (curr_no % 2 == 0) // condition for even number + curr_no = curr_no / 2; + else + curr_no = (curr_no * 3) + 1; // condition for odd number + } + printf("1\nNumber of steps: %llu\n", num_steps); + return 0; +} diff --git a/math/euclidean_algorithm_extended.c b/math/euclidean_algorithm_extended.c new file mode 100644 index 0000000000..914eb98ba0 --- /dev/null +++ b/math/euclidean_algorithm_extended.c @@ -0,0 +1,154 @@ +/** + * @{ + * @file + * @brief Program to perform the [extended Euclidean + * algorithm](https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm) + * + * @details The extended Euclidean algorithm, on top of finding the GCD (greatest common + * divisor) of two integers a and b, also finds the values x and y such that + * ax+by = gcd(a, b) + */ + +#include /// for tests +#include /// for IO +#include /// for div function and corresponding div_t struct + +/** + * @brief a structure holding the values resulting from the extended Euclidean + * algorithm + */ +typedef struct euclidean_result +{ + int gcd; ///< the greatest common divisor calculated with the Euclidean + ///< algorithm + int x, y; ///< the values x and y such that ax + by = gcd(a, b) +} euclidean_result_t; + +/** + * @brief gives queue-like behavior to an array of two ints, pushing an element + * onto the end and pushing one off the front + * + * @param arr an array of ints acting as a queue + * @param newval the value being pushed into arr + * + * @returns void + */ +static inline void xy_push(int arr[2], int newval) +{ + arr[1] = arr[0]; + arr[0] = newval; +} + +/** + * @brief calculates the value of x or y and push those into the small 'queues' + * + * @details Both x and y are found by taking their value from 2 iterations ago minus the + * product of their value from 1 iteration ago and the most recent quotient. + * + * @param quotient the quotient from the latest iteration of the Euclidean + * algorithm + * @param prev the 'queue' holding the values of the two previous iterations + * + * @returns void + */ +static inline void calculate_next_xy(int quotient, int prev[2]) +{ + int next = prev[1] - (prev[0] * quotient); + xy_push(prev, next); +} + +/** + * @brief performs the extended Euclidean algorithm on integer inputs a and b + * + * @param a first integer input + * @param b second integer input + * + * @returns euclidean_result_t containing the gcd, and values x and y such that + * ax + by = gcd + */ +euclidean_result_t extended_euclidean_algorithm(int a, int b) +{ + int previous_remainder = 1; + int previous_x_values[2] = {0, 1}; + int previous_y_values[2] = {1, 0}; + div_t div_result; + euclidean_result_t result; + + /* swap values of a and b */ + if (abs(a) < abs(b)) + { + a ^= b; + b ^= a; + a ^= b; + } + + div_result.rem = b; + + while (div_result.rem > 0) + { + div_result = div(a, b); + + previous_remainder = b; + + a = b; + b = div_result.rem; + + calculate_next_xy(div_result.quot, previous_x_values); + calculate_next_xy(div_result.quot, previous_y_values); + } + + result.gcd = previous_remainder; + result.x = previous_x_values[1]; + result.y = previous_y_values[1]; + + return result; +} + +/** @} */ + +/** + * @brief perform one single check on the result of the algorithm with provided + * parameters and expected output + * + * @param a first paramater for Euclidean algorithm + * @param b second parameter for Euclidean algorithm + * @param gcd expected value of result.gcd + * @param x expected value of result.x + * @param y expected value of result.y + * + * @returns void + */ +static inline void single_test(int a, int b, int gcd, int x, int y) +{ + euclidean_result_t result; + + result = extended_euclidean_algorithm(a, b); + assert(result.gcd == gcd); + assert(result.x == x); + assert(result.y == y); +} + +/** + * @brief Perform tests on known results + * @returns void + */ +static void test() +{ + single_test(40, 27, 1, -2, 3); + single_test(71, 41, 1, -15, 26); + single_test(48, 18, 6, -1, 3); + single_test(99, 303, 3, -16, 49); + single_test(14005, 3507, 1, -305, 1218); + + printf("All tests have successfully passed!\n"); +} + +/** + * @brief Main Function + * @returns 0 upon successful program exit + */ +int main() +{ + test(); // run self-test implementations + return 0; +} diff --git a/math/factorial.c b/math/factorial.c new file mode 100644 index 0000000000..3435b2f963 --- /dev/null +++ b/math/factorial.c @@ -0,0 +1,31 @@ +#include +int main() +{ + int a[200], n, counter, temp, i; + a[0] = 1; + counter = 0; + printf("Enter a whole number to Find its Factorial: "); + scanf("%d", &n); + if (n < 0) + printf("Cannot Calculate factorials for negative numbers."); + else + { + for (; n >= 2; n--) + { + temp = 0; + for (i = 0; i <= counter; i++) + { + temp = (a[i] * n) + temp; + a[i] = temp % 10; + temp = temp / 10; + } + while (temp > 0) + { + a[++counter] = temp % 10; + temp = temp / 10; + } + } + for (i = counter; i >= 0; i--) printf("%d", a[i]); + } + return 0; +} diff --git a/math/factorial_large_number.c b/math/factorial_large_number.c new file mode 100644 index 0000000000..c3939b38c9 --- /dev/null +++ b/math/factorial_large_number.c @@ -0,0 +1,122 @@ +/** + * @file + * \brief Compute factorial of arbitrarily large numbers by + * storing individual digits in a byte. + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include +#include +#include + +/** + * dynamically large number + */ +typedef struct _large_num +{ + char *digits; /**< array to store individual digits */ + unsigned int num_digits; /**< number of digits in the number */ +} large_num; + +/** + * create a new large number + * \returns pointer to a large number + */ +large_num *new_number(void) +{ + large_num *new_num = (large_num *)malloc(sizeof(large_num)); + new_num->num_digits = 1; + new_num->digits = (char *)malloc(1 * sizeof(char)); + new_num->digits[0] = 1; + return new_num; +} + +/** + * delete all memory allocated for large number + * \param[in] num pointer to large_num to delete + */ +void delete_number(large_num *num) +{ + free(num->digits); + free(num); +} + +/** + * add a digit to the large number + * \param[in,out] num + * \param[in] value value of the digit to insert + */ +void add_digit(large_num *num, unsigned int value) +{ + if (value > 9) + { + fprintf(stderr, "digit > 9!!\n"); + delete_number(num); + exit(EXIT_FAILURE); + } + + num->num_digits++; + num->digits = (char *)realloc(num->digits, num->num_digits * sizeof(char)); + num->digits[num->num_digits - 1] = value; +} + +/** + * multiply large number with another integer and + * store the result in the same large number + */ +void multiply(large_num *num, unsigned long n) +{ + int i; + unsigned long carry = 0, temp; + for (i = 0; i < num->num_digits; i++) + { + temp = num->digits[i] * n; + temp += carry; + if (temp < 10) + carry = 0; + else + { + carry = temp / 10; + temp = temp % 10; + } + num->digits[i] = temp; + } + + while (carry != 0) + { + add_digit(num, carry % 10); + carry /= 10; + } +} + +/** + * main function + */ +int main(int argc, char *argv[]) +{ + int number, i; + + // Asks for the number/position of term in Fibonnacci sequence + if (argc == 2) + number = atoi(argv[1]); + else + { + printf("Enter the value of n(n starts from 0 ): "); + scanf("%d", &number); + } + + large_num *result = new_number(); + + clock_t start_time = clock(); + for (i = 2; i <= number; i++) /* Multiply every number from 2 thru N */ + multiply(result, i); + double time_taken = (clock() - start_time) * (double)1e3 / CLOCKS_PER_SEC; + // time_taken = (clock() - start_time) / (double) CLOCKS_PER_SEC; + + printf("%d! = ", number); + for (i = result->num_digits; i > 0; i--) + putchar(result->digits[i - 1] + '0'); + printf("\nTime taken: %.4g ms\n", time_taken); + + delete_number(result); + return 0; +} diff --git a/math/factorial_trailing_zeroes.c b/math/factorial_trailing_zeroes.c new file mode 100644 index 0000000000..b578c1e65b --- /dev/null +++ b/math/factorial_trailing_zeroes.c @@ -0,0 +1,30 @@ +/* +programme for computing number of zeroes at the end of factorial of a given +number n +*/ +#include //including math.h header file to use pow function +#include +int main() +{ + int i, n, test = 0, count = 0; + // taking input number n + scanf("%d", &n); + + // looping from 1 till loop break + for (i = 1;; i++) + { + test = + n / + pow(5, + i); // division of n by ith power of 5(storing in integer form) + if (test != + 0) // condition for zeroes at end corresponding individual ith case + { + count = count + test; + } + else + break; // break the loop for if test=0 + } + printf("%d\n", count); + return 0; +} diff --git a/math/fibonacci.c b/math/fibonacci.c new file mode 100644 index 0000000000..60752e7ae5 --- /dev/null +++ b/math/fibonacci.c @@ -0,0 +1,124 @@ +/** + * @file + * @brief Program to print the nth term of the Fibonacci series. + * @details + * Fibonacci series generally starts from 0 and 1. Every next term in + * the series is equal to the sum of the two preceding terms. + * For further info: https://en.wikipedia.org/wiki/Fibonacci_sequence + * + * @author [Luiz Carlos Aguiar C](https://github.com/IKuuhakuI) + * @author [Niranjan](https://github.com/niranjank2022) + */ + +#include /// for assert() +#include /// for errno - to determine whether there is an error while using strtol() +#include /// for input, output +#include /// for exit() - to exit the program +#include /// to calculate time taken by fib() +/** + * @brief Determines the nth Fibonacci term + * @param number - n in "nth term" and it can't be negative as well as zero + * @return nth term in unsigned type + * @warning + * Only till 47th and 48th fibonacci element can be stored in `int` and + * `unsigned int` respectively (takes more than 20 seconds to print) + */ +unsigned int fib(int number) +{ + // Check for negative integers + if (number <= 0) + { + fprintf(stderr, "Illegal Argument Is Passed!\n"); + exit(EXIT_FAILURE); + } + + // Base conditions + if (number == 1) + return 0; + + if (number == 2) + return 1; + + // Recursive call to the function + return fib(number - 1) + fib(number - 2); +} + +/** + * @brief Get the input from the user + * @return valid argument to the fibonacci function + */ +int getInput(void) +{ + int num, excess_len; + char buffer[3], *endPtr; + + while (1) + { // Repeat until a valid number is entered + printf("Please enter a valid number:"); + fgets(buffer, 3, stdin); // Inputs the value from user + + excess_len = 0; + if (!(buffer[0] == '\n' || + buffer[1] == '\n' || + buffer[2] == '\n')) { + while (getchar() != '\n') excess_len++; + } + + num = strtol(buffer, &endPtr, + 10); // Attempts to convert the string to integer + + // Checking the input + if ( // The number is too large + (excess_len > 0 || num > 48) || + // Characters other than digits are included in the input + (*endPtr != '\0' && *endPtr != '\n') || + // No characters are entered + endPtr == buffer) + { + continue; + } + + break; + } + + printf("\nEntered digit: %d (it might take sometime)\n", num); + return num; +} + +/** + * @brief self-test implementation + * @return void + */ +static void test() +{ + assert(fib(5) == 3); + assert(fib(2) == 1); + assert(fib(9) == 21); +} + +/** + * @brief Main function + * @return 0 on exit + */ +int main() +{ + // Performing the test + test(); + printf("Tests passed...\n"); + + // Getting n + printf( + "Enter n to find nth fibonacci element...\n" + "Note: You would be asked to enter input until valid number ( less " + "than or equal to 48 ) is entered.\n"); + + int number = getInput(); + clock_t start, end; + + start = clock(); + printf("Fibonacci element %d is %u ", number, fib(number)); + end = clock(); + + printf("in %.3f seconds.\n", ((double)(end - start)) / CLOCKS_PER_SEC ); + return 0; +} diff --git a/math/fibonacci_dp.c b/math/fibonacci_dp.c new file mode 100644 index 0000000000..fff4532ac2 --- /dev/null +++ b/math/fibonacci_dp.c @@ -0,0 +1,54 @@ +// Fibonacci Series using Dynamic Programming + +/* Author: Moinak Banerjee(moinak878) + Date : 1 October ,2019 +*/ + +#include +#include + +int fib(int n) +{ + // Out of Range checking + if (n < 0) + { + printf("\nNo Such term !\n"); + exit(0); + } + // declaring array to store fibonacci numbers -- memoization + int *f = (int *)malloc( + (n + 2) * sizeof(int)); // one extra to handle edge case, n = 0 + int i; + + /* let 0th and 1st number of the series be 0 and 1*/ + f[0] = 0; + f[1] = 1; + + for (i = 2; i <= n; i++) + { + // Adding the previous 2 terms to make the 3rd term + f[i] = f[i - 1] + f[i - 2]; + } + + int out = f[n]; + free(f); + return out; +} + +int main(int argc, char *argv[]) +{ + int number; + + // Asks for the number/position of term in Fibonnacci sequence + if (argc == 2) + number = atoi(argv[1]); + else + { + printf("Enter the value of n(n starts from 0 ): "); + scanf("%d", &number); + } + + printf("The nth term is : %d \n", fib(number)); + + return 0; +} \ No newline at end of file diff --git a/math/fibonacci_fast.c b/math/fibonacci_fast.c new file mode 100644 index 0000000000..0a57820a09 --- /dev/null +++ b/math/fibonacci_fast.c @@ -0,0 +1,85 @@ +/** + @file + @author [Krishna Vedala](https://github.com/kvedala) + @date 2 October, 2019 + @brief Compute \f$m^{mth}\f$ Fibonacci number using the formulae: + \f{eqnarray*}{ + F_{2n-1} &=& F_n^2 + F_{n-1}^2 \\ + F_{2n} &=& F_n\left(2F_{n-1} + F_n\right) + \f} +*/ + +#include +#include +#include + +/** + * Get the \f$n^{th}\f$ and \f$n+1^{th}\f$ Fibonacci number using recursive + * half-interval decimation. + * \param [in] n index of Fibonacci number to get + * \param [out] C left half interval value - end result here. Cannot be NULL + * \param [out] D right half interval can be discarded at end and can be NULL + */ +void fib(unsigned long n, unsigned long *C, unsigned long *D) +{ + // Out of Range checking + // commented out since `n` is unsigned integer + // if (n < 0) + // { + // printf("\nNo Such term !\n"); + // exit(0); + // } + + unsigned long a, b, c, d; + + if (n == 0) + { + C[0] = 0; + if (D) /* if D is not NULL */ + D[0] = 1; + return; + } + + fib(n >> 1, &c, &d); /* Compute F(n/2) */ + + a = c * ((d << 1) - c); + b = c * c + d * d; + if (n % 2 == 0) /* If n is even */ + { + C[0] = a; + if (D) + D[0] = b; + return; + } + + /**< If n is odd */ + C[0] = b; + if (D) /* if D is not NULL */ + D[0] = a + b; + return; +} + +/** + * main function + */ +int main(int argc, char *argv[]) +{ + unsigned long number, result; + + setlocale(LC_NUMERIC, ""); // format the printf output + + // Asks for the number/position of term in Fibonnacci sequence + if (argc == 2) + number = atoi(argv[1]); + else + { + printf("Enter the value of n(n starts from 0 ): "); + scanf("%lu", &number); + } + + fib(number, &result, NULL); + + printf("The nth term is : %'lu \n", result); + + return 0; +} diff --git a/math/fibonacci_formula.c b/math/fibonacci_formula.c new file mode 100644 index 0000000000..cf86d0ed55 --- /dev/null +++ b/math/fibonacci_formula.c @@ -0,0 +1,59 @@ +/** + * @file + * @brief Finding Fibonacci number of any `n` number using [Binet's closed form formula](https://en.wikipedia.org/wiki/Fibonacci_number#Binet's_formula) + * compute \f$f_{nth}\f$ Fibonacci number using the binet's formula: + * Fn = 1√5 * (1+√5 / 2)^n+1 − 1√5 * (1−√5 / 2)^n+1 + * @author [GrandSir](https://github.com/GrandSir/) + */ + +#include /// for pow and sqrt +#include /// for printf +#include /// for assert + +/** + * @param n index of number in Fibonacci sequence + * @returns nth value of fibonacci sequence for all n >= 0 + */ +int fib(unsigned int n) { + float seq = (1 / sqrt(5) * pow(((1 + sqrt(5)) / 2), n + 1)) - (1 / sqrt(5) * pow(((1 - sqrt(5)) / 2), n + 1)); + + // removing unnecessary fractional part by implicitly converting float to int + return seq; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test () { + /* this ensures that the first 10 number of fibonacci sequence + * (1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89) + * matches with algorithm + */ + assert(fib(0) == 1); + assert(fib(1) == 1); + assert(fib(2) == 2); + assert(fib(3) == 3); + assert(fib(4) == 5); + assert(fib(5) == 8); + assert(fib(6) == 13); + assert(fib(7) == 21); + assert(fib(8) == 34); + assert(fib(9) == 55); + assert(fib(10) == 89); + + printf("All tests have successfully passed!\n"); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + + for(int i = 0; i <= 10; i++){ + printf("%d. fibonacci number is: %d\n", i, fib(i)); + } + return 0; +} diff --git a/misc/GCD.c b/math/gcd.c similarity index 77% rename from misc/GCD.c rename to math/gcd.c index 771d25cf2d..5b25b5002a 100644 --- a/misc/GCD.c +++ b/math/gcd.c @@ -1,13 +1,15 @@ #include // Euclid's algorithm -int GCD(int x, int y) { +int GCD(int x, int y) +{ if (y == 0) return x; - return GCD(y, x%y); + return GCD(y, x % y); } -int main() { +int main() +{ int a, b; printf("Input two numbers:\n"); scanf("%d %d", &a, &b); diff --git a/math/is_armstrong.c b/math/is_armstrong.c new file mode 100644 index 0000000000..7b7f9d2f3b --- /dev/null +++ b/math/is_armstrong.c @@ -0,0 +1,24 @@ +#include + +int main() +{ + int n, sum = 0, i, num; + printf("Enter number: "); + scanf("%d", &n); + num = n; + while (n != 0) + { + i = n % 10; + sum = sum + (i * i * i); + n = n / 10; + } + if (sum == num) + { + printf("%d is an armstrong number!\n", num); + } + else + { + printf("%d is not an armstrong number!\n", num); + } + return 0; +} diff --git a/math/large_factorials.c b/math/large_factorials.c new file mode 100644 index 0000000000..9670b7ca49 --- /dev/null +++ b/math/large_factorials.c @@ -0,0 +1,50 @@ +#include + +int main() +{ + int a[16500], T; + long long int i, j; + + printf("Enter number of test cases : "); + scanf("%d", &T); + + while (T--) + { + for (i = 0; i < 16500; i++) + { + a[i] = 0; + } + + a[1] = 1; + int N, carry = 0, count = 0; + printf("Enter a number : "); + scanf("%d", &N); + + for (i = 1; i <= N; i++) + { + carry = 0; + for (j = 0; j < 16500; j++) + { + a[j] = a[j] * i + carry; + carry = a[j] / 10; + a[j] = a[j] % 10; + } + } + + for (i = 0; i < 16500; i++) + { + if (a[i] != 0) + { + count = i; + } + } + + for (i = count; i > 0; i--) + { + printf("%d", a[i]); + } + printf("\n"); + } + + return 0; +} diff --git a/math/lcm.c b/math/lcm.c new file mode 100644 index 0000000000..c1f7487f02 --- /dev/null +++ b/math/lcm.c @@ -0,0 +1,37 @@ +// C program to find LCM of two numbers +/* + suppose we have two numbers a and b. + Property: Since product of LCM and GCD of two numbers are equal to product + of that number itself. i.e, LCM(a,b)*GCD(a,b)=a*b. So,here we first find the + GCD of two numbers and using above property we find LCM of that two numbers. +*/ +#include + +// Recursive function to return gcd of a and b +int gcd(int a, int b) +{ + if (a == 0) + return b; + return gcd(b % a, a); +} + +// Function to return LCM of two numbers +int lcm(int a, int b) { return (a * b) / gcd(a, b); } + +// Driver program +int main() +{ + int a, b; + printf("Enter two numbers to find their LCM \n"); + scanf("%d%d", &a, &b); + printf("LCM of %d and %d is %d ", a, b, lcm(a, b)); + return 0; +} +/* +Test Case1: +a=15,b=20 +LCM(a,b)=60 +Test Case2: +a=12,b=18 +LCM(a,b)=36 +*/ diff --git a/math/lerp.c b/math/lerp.c new file mode 100644 index 0000000000..7acc302487 --- /dev/null +++ b/math/lerp.c @@ -0,0 +1,28 @@ +#include +#include + +float lerp(float k0, float k1, float t) { return k0 + t * (k1 - k0); } + +float lerp_precise(int k0, int k1, float t) { return (1 - t) * k0 + t * k1; } + +int main() +{ + float start = 0; + float finish = 5; + float steps = 0; + + printf("Input a number, this is the bigger bound of the lerp:\n"); + scanf("%f", &finish); + + printf( + "Input a number, this is in how many steps you want to divide the " + "lerp:\n"); + scanf("%f", &steps); + + for (int i = 0; i < steps + 1; i++) + { + printf("%f\n", lerp(start, finish, i / steps)); + } + + return 0; +} diff --git a/math/palindrome.c b/math/palindrome.c new file mode 100644 index 0000000000..c8592473a0 --- /dev/null +++ b/math/palindrome.c @@ -0,0 +1,40 @@ +/** + * @file + * @brief Program to identify if a number is [palindrome + * number](https://en.wikipedia.org/wiki/Palindrome) or not. + * @see project_euler/problem_4/sol1.c + */ +#include +#include +#include + +bool isPalindrome(int number); + +/** Driver Code */ +int main() +{ + assert(isPalindrome(0)); + assert(isPalindrome(1)); + assert(isPalindrome(12321)); + assert(!isPalindrome(1234)); + return 0; +} + +/** + * Check given number whether is palindrome number or not + * @param number number to check + * @return `true` if given number is palindrome number + * @return `false` if number is not a palindrome number + */ +bool isPalindrome(int number) +{ + int reversedNumber = 0; + int originalNumber = number; + while (number != 0) + { + int remainder = number % 10; + reversedNumber = reversedNumber * 10 + remainder; + number /= 10; + } + return originalNumber == reversedNumber; +} diff --git a/math/prime.c b/math/prime.c new file mode 100644 index 0000000000..165da574d8 --- /dev/null +++ b/math/prime.c @@ -0,0 +1,71 @@ +/** + * @file + * @brief Program to identify if a number is [prime + * number](https://en.wikipedia.org/wiki/Prime_number) or not + */ +#include +#include +#include +#include + +/** + * Check if a given number is prime number or not + * @param x number to check + * @return `true` if given number is prime number, otherwise `false` + */ +bool isPrime(int x) +{ + if (x == 2) + { + return true; + } + if (x < 2 || x % 2 == 0) + { + return false; + } + + double squareRoot = sqrt(x); + + for (int i = 3; i <= squareRoot; i += 2) + { + if (x % i == 0) + { + return false; + } + } + return true; +} + +/** + * Test function + * @return void + */ +void test() +{ + /* all the prime numbers less than 100 */ + int primers[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, + 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}; + for (size_t i = 0, size = sizeof(primers) / sizeof(primers[0]); i < size; + ++i) + { + assert(isPrime(primers[i])); + } + + /* Example Non-prime numbers */ + int NonPrimers[] = {-1, 0, 1, 4, 6, 8, 9, 10}; + for (size_t i = 0, size = sizeof(NonPrimers) / sizeof(NonPrimers[0]); + i < size; ++i) + { + assert(!isPrime(NonPrimers[i])); + } +} + +/** + * Driver Code + * @return None + */ +int main() +{ + test(); + return 0; +} diff --git a/misc/PrimeFactoriziation.c b/math/prime_factoriziation.c similarity index 89% rename from misc/PrimeFactoriziation.c rename to math/prime_factoriziation.c index 15d8f192bd..7e466923be 100644 --- a/misc/PrimeFactoriziation.c +++ b/math/prime_factoriziation.c @@ -1,13 +1,14 @@ /* AUTHOR: Christian Bender DATE: 12.02.2019 - DESCRIPTION: This program calculates the prime factoriziation of a positive integer > 1 + DESCRIPTION: This program calculates the prime factoriziation of a positive + integer > 1 */ +#include #include #include #include -#include /* initial length of the dynamic array */ #define LEN 10 @@ -22,10 +23,10 @@ */ typedef struct data { - int * range; + int *range; int length; } range; -typedef range* Range; +typedef range *Range; /* int_fac : calculates the prime factoriziation of positive integers */ Range int_fact(int); @@ -34,7 +35,7 @@ Range int_fact(int); void print_arr(Range); /* increase : increases the dynamic integer array */ -int * increase(int *, int); +int *increase(int *, int); /* destroy: destroys the range-structure */ void destroy(Range); @@ -44,7 +45,6 @@ void destroy(Range); */ int main() { - int n = 0; /* for user input */ printf("\t\tPrim factoriziation\n\n"); @@ -57,7 +57,6 @@ int main() return 0; } - Range int_fact(int n) { assert(n > 1); /* precondition : n must be greater then 1*/ @@ -65,9 +64,9 @@ Range int_fact(int n) int len = LEN; int count = 0; int i = 0; - int * range = (int *) malloc(sizeof(int) * len); + int *range = (int *)malloc(sizeof(int) * len); assert(range); - Range pstr = (Range) malloc(sizeof(range)); + Range pstr = (Range)malloc(sizeof(range)); assert(pstr); while (n % 2 == 0) @@ -86,11 +85,10 @@ Range int_fact(int n) i++; } count++; - } int j = 3; - while (j*j <= n) + while (j * j <= n) { while (n % j == 0) { @@ -113,7 +111,6 @@ Range int_fact(int n) j += 2; } - if (n > 1) { if (i < len) @@ -134,11 +131,8 @@ Range int_fact(int n) pstr->range = range; pstr->length = count; return pstr; - - } - void print_arr(Range pStr) { assert(pStr); /* checks whether pStr is a null-pointer */ @@ -154,17 +148,15 @@ void print_arr(Range pStr) printf("\n"); } - -int * increase(int * arr, int len) +int *increase(int *arr, int len) { assert(arr); /* checks whether arr is a null-pointer */ - int * tmp = (int*) realloc(arr, sizeof(int) * (len + STEP)); + int *tmp = (int *)realloc(arr, sizeof(int) * (len + STEP)); assert(tmp); return tmp; -// assert(arr); + // assert(arr); } - void destroy(Range r) { free(r->range); diff --git a/math/prime_sieve.c b/math/prime_sieve.c new file mode 100644 index 0000000000..c7a32c6502 --- /dev/null +++ b/math/prime_sieve.c @@ -0,0 +1,77 @@ +/** + * @file + * @brief [Prime Sieve](https://leetcode.com/problems/count-primes/) + * algorithm implementation. + * @author [Divyansh Kushwaha](https://github.com/webdesignbydivyansh) + */ +#include /// for assert +#include /// for standard input output +#include /// for general purpose standard library + +const unsigned long long MAX_SIZE = 1000000; /// variable upto which prime numbers are to be found out +/** + * @addtogroup misc + * @{ + */ +/** + * @brief Prime Sieve works in O(nlogn) time + * @param p array to be updated + * @returns void + */ +void prime(int *p) +{ + for(long long int i=3;i<=MAX_SIZE;i+=2) { p[i]=1; } + for(long long int i=3;i<=MAX_SIZE;i+=2) + { + if(p[i]==1) { + for(long long int j=i*i;j<=MAX_SIZE;j+=i) { + p[j]=0; + } + } + } + p[2]=1; + p[0]=p[1]=0; +} +/** + * @brief Count func counts the number of + * prime numbers. + * @param arr contains the prime numbers + * @param size denotes upto which prime numbers are to be found out + * @returns count of prime numbers + */ +int count(int *arr, const int size){ + int k=0; + for(int i=0;i<=size;i++){ + if(arr[i]==1){ + k++; + } + } + return k; +} + +/** + * @brief Test implementations + * @returns void + */ +static void test() +{ + // Test Case 1 + const int size = 10; /* array size */ + printf("Test Case 1..."); + int arr[1000005]={0}; /* array to store prime numbers */ + prime(arr); + assert(count(arr,size)==4); + printf("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, const char *argv[]) +{ + test(); // execute the tests + return 0; +} diff --git a/math/strong_number.c b/math/strong_number.c new file mode 100644 index 0000000000..ee6dae58da --- /dev/null +++ b/math/strong_number.c @@ -0,0 +1,57 @@ +/** + * @file + * @brief Strong number is a number whose sum of all digits’ factorial is equal + * to the number n For example: 145 = 1!(1) + 4!(24) + 5!(120) + */ +#include +#include +#include + +/** + * Check if given number is strong number or not + * @param number + * @return `true` if given number is strong number, otherwise `false` + */ +bool isStrong(int number) +{ + if (number < 0) + { + return false; + } + int sum = 0; + int originalNumber = number; + while (originalNumber != 0) + { + int remainder = originalNumber % 10; + int factorial = remainder == 0 ? 0 : 1; /* 0! == 1 */ + + /* calculate factorial of n */ + for (int i = 1; i <= remainder; factorial *= i, i++) + { + ; + } + sum += factorial; + originalNumber /= 10; + } + return number == sum; +} + +/** + * Test function + * @return void + */ +void test() +{ + assert(isStrong(145)); /* 145 = 1! + 4! + 5! */ + assert(!isStrong(543)); /* 543 != 5!+ 4! + 3! */ +} + +/** + * Driver Code + * @return None + */ +int main() +{ + test(); + return 0; +} diff --git a/misc/CMakeLists.txt b/misc/CMakeLists.txt new file mode 100644 index 0000000000..8245d92bf6 --- /dev/null +++ b/misc/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} *.c ) +# 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 ".c" "" testname ${testsourcefile} ) + add_executable( ${testname} ${testsourcefile} ) + + if(OpenMP_C_FOUND) + target_link_libraries(${testname} OpenMP::OpenMP_C) + endif() + if(MATH_LIBRARY) + target_link_libraries(${testname} ${MATH_LIBRARY}) + endif() + install(TARGETS ${testname} DESTINATION "bin/misc") + +endforeach( testsourcefile ${APP_SOURCES} ) diff --git a/misc/Collatz.c b/misc/Collatz.c deleted file mode 100644 index bccc0b5140..0000000000 --- a/misc/Collatz.c +++ /dev/null @@ -1,26 +0,0 @@ -/* -collatz conjecture: a series for a number n in which if n even then the next number is n/2 ,but if n is odd then the next number is 3n+1. -this series continues till it reaches 1*/ - -#include -int main() -{ - int n,curr_no; - scanf("%d",&n); //input number - curr_no=n; //curr_no stores input number n - while(curr_no!=1) //loop till series reaches 1 - { - if(curr_no%2==0) //condition for even number - { - curr_no=curr_no/2; - printf("%d->",curr_no); - } - else - { - curr_no=(curr_no*3)+1; //condition for odd number - printf("%d->",curr_no); - } - } - printf("1"); - return 0; -} diff --git a/misc/Factorial.c b/misc/Factorial.c deleted file mode 100644 index e88852842a..0000000000 --- a/misc/Factorial.c +++ /dev/null @@ -1,20 +0,0 @@ -#include - -int fat(int number){ - if (number == 1 || number == 0) - return 1; - else - return number*fat(number-1); -} - -int main(){ - int number; - - //Asks the factorial of the number n - printf("Number: "); - scanf("%d", &number); - - printf("%d\n", fat(number)); - - return 0; -} diff --git a/misc/Fibonacci.c b/misc/Fibonacci.c deleted file mode 100644 index bc2a60001d..0000000000 --- a/misc/Fibonacci.c +++ /dev/null @@ -1,19 +0,0 @@ -#include - -//Fibonnacci function -int fib(int number){ - if(number==1||number==2) return 1; - else return fib(number-1)+fib(number-2); -} - -int main(){ - int number; - - //Asks for the number that is in n position in Fibonnacci sequence - printf("Number: "); - scanf("%d", &number); - - printf("%d \n", fib(number)); - - return 0; -} \ No newline at end of file diff --git a/misc/LongestSubSequence.c b/misc/LongestSubSequence.c deleted file mode 100644 index b1d74a4194..0000000000 --- a/misc/LongestSubSequence.c +++ /dev/null @@ -1,88 +0,0 @@ -#include -#include - - -void longestSub(int* ARRAY,int ARRAY_LENGTH, int** RESULT,int* RESULT_LENGTH){ //RESULT and RESULT_LENGTH will be modified by their pointers - - if(ARRAY_LENGTH <= 1){ - *RESULT=ARRAY; - *RESULT_LENGTH = ARRAY_LENGTH; - } - else{ - int PIVOT = ARRAY[0]; - int *LONGEST_SUB = NULL; - int i, j, LONGEST_SUB_LENGTH = 0; - int TEMPORARY_ARRAY_LENGTH = 0, *TEMPORARY_ARRAY = NULL; - - for(i = 1; i < ARRAY_LENGTH; i++){ - if (ARRAY[i] < PIVOT){ - - TEMPORARY_ARRAY_LENGTH = 0; - TEMPORARY_ARRAY = NULL; - - for(j = i+1;j < ARRAY_LENGTH; j++){ - if(ARRAY[j] >= ARRAY[i]){ - - TEMPORARY_ARRAY_LENGTH++; - TEMPORARY_ARRAY = (int *)realloc(TEMPORARY_ARRAY, TEMPORARY_ARRAY_LENGTH*sizeof(int)); - TEMPORARY_ARRAY[TEMPORARY_ARRAY_LENGTH-1] = ARRAY[j]; - } - } - - longestSub(TEMPORARY_ARRAY, TEMPORARY_ARRAY_LENGTH, &TEMPORARY_ARRAY, &TEMPORARY_ARRAY_LENGTH); - if(LONGEST_SUB_LENGTH < TEMPORARY_ARRAY_LENGTH + 1){ - - LONGEST_SUB_LENGTH = TEMPORARY_ARRAY_LENGTH + 1; - LONGEST_SUB = (int *)realloc(LONGEST_SUB, LONGEST_SUB_LENGTH*sizeof(int)); - LONGEST_SUB[0] = ARRAY[i]; - - for(i = 1;i < LONGEST_SUB_LENGTH; i++) - LONGEST_SUB[i] = TEMPORARY_ARRAY[i-1]; - } - } - } - - TEMPORARY_ARRAY = NULL; - TEMPORARY_ARRAY_LENGTH = 0; - for(i = 1;i < ARRAY_LENGTH; i++){ - - if(ARRAY[i] >= PIVOT){ - TEMPORARY_ARRAY_LENGTH++; - TEMPORARY_ARRAY = (int *)realloc(TEMPORARY_ARRAY, TEMPORARY_ARRAY_LENGTH*sizeof(int)); - TEMPORARY_ARRAY[TEMPORARY_ARRAY_LENGTH-1] = ARRAY[i]; - } - } - - longestSub(TEMPORARY_ARRAY, TEMPORARY_ARRAY_LENGTH, &TEMPORARY_ARRAY, &TEMPORARY_ARRAY_LENGTH); - if(TEMPORARY_ARRAY_LENGTH + 1 > LONGEST_SUB_LENGTH){ - - LONGEST_SUB_LENGTH = TEMPORARY_ARRAY_LENGTH + 1; - LONGEST_SUB = (int *)realloc(LONGEST_SUB, LONGEST_SUB_LENGTH*sizeof(int)); - LONGEST_SUB[0] = PIVOT; - for(i = 1;i < LONGEST_SUB_LENGTH; i++) - LONGEST_SUB[i] = TEMPORARY_ARRAY[i-1]; - } - *RESULT = LONGEST_SUB; - *RESULT_LENGTH = LONGEST_SUB_LENGTH; - } - - -} - -int main(){ - - int EXAMPLE_LENGTH = 8; - int EXAMPLE[] = {18, 2, 15, 4, 30, 0, 11, 12}; - - int *RESULT = NULL; - int RESULT_LENGTH, i; - - longestSub(EXAMPLE, EXAMPLE_LENGTH, &RESULT, &RESULT_LENGTH); - - printf("Longest Sub Sequence length: %d and it's:\n", RESULT_LENGTH); - for(i = 0;i < RESULT_LENGTH; i++) - printf("%d ",RESULT[i]); - printf("\n"); - - return 0; -} \ No newline at end of file diff --git a/misc/Prime.c b/misc/Prime.c deleted file mode 100644 index c98284bc48..0000000000 --- a/misc/Prime.c +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include - -int isPrime(int x) { - for (int i = 2; i < sqrt(x); i++) { - if (x%i == 0) - return 0; - } - return 1; - -} - -int main() { - int a; - printf("Input a number to see if it is a prime number:\n"); - scanf("%d", &a); - if (isPrime(a)) - printf("%d is a prime number.\n", a); - else - printf("%d is not a prime number.\n", a); - return 0; -} diff --git a/misc/QUARTILE.c b/misc/QUARTILE.c deleted file mode 100644 index a8498e6497..0000000000 --- a/misc/QUARTILE.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include -#include -void main() -{ - int a[10],n,i,j,temp; - float q1,q3,iqr; - clrscr(); - printf("Enter no. for Random Numbers :"); - scanf("%d",&n); - for(i=0;i -#include - -// Function for Tower of Hanoi algorithm -void hanoi(int noOfDisks,char where,char to,char extra){ - if(noOfDisks == 0 ) - { - return; - } - else - { - hanoi(noOfDisks-1, where, extra , to); - printf("Move disk : %d from %c to %c\n",noOfDisks,where,to); - hanoi(noOfDisks-1,extra,to,where); - } -} -int main(void){ - int noOfDisks; - - //Asks the number of disks in the tower - printf("Number of disks: \n"); - scanf("%d", &noOfDisks); - - hanoi(noOfDisks,'A','B','C'); - - return 0; - -} diff --git a/misc/catalan.c b/misc/catalan.c deleted file mode 100644 index 6e8dde34a4..0000000000 --- a/misc/catalan.c +++ /dev/null @@ -1,28 +0,0 @@ -/* -code for computing nth catalan number -*/ -#include -long int factorial(int x) //long int for more than 10 factorial -{ - int i; - long int fac; //fac stores x factorial - fac=x; - for(i=1;i +#include -int ways(int n, int a[], int k) +int ways(int n, int *a, int k) { - if(n<0 || k<0) return 0; - if(n == 0) return 1; - if(k == 0) return 0; - return ways(n, a, k-1) + ways(n-a[k-1], a, k); + if (n < 0 || k < 0) + return 0; + if (n == 0) + return 1; + if (k == 0) + return 0; + return ways(n, a, k - 1) + ways(n - a[k - 1], a, k); } int main() @@ -20,15 +24,15 @@ int main() printf("Number of coins? "); scanf("%d", &m); - int coin[m], i; - for(i=0; i -#include //including math.h header file to use pow function -int main() -{ - int i,n,test=0,count=0; - //taking input number n - scanf("%d",&n); - - //looping from 1 till loop break - for(i=1;;i++) - { - test=n/pow(5,i);//division of n by ith power of 5(storing in integer form) - if(test!=0) //condition for zeroes at end corresponding individual ith case - { - count=count+test; - } - else - break; //break the loop for if test=0 - } - printf("%d\n",count); - return 0; -} diff --git a/misc/hamming_distance.c b/misc/hamming_distance.c new file mode 100644 index 0000000000..e479bf144e --- /dev/null +++ b/misc/hamming_distance.c @@ -0,0 +1,62 @@ +/** + * @file + * @brief [Hamming distance](https://en.wikipedia.org/wiki/Hamming_distance) + * algorithm implementation. + * @details + * In information theory, the Hamming distance between two strings of + * equal length is the number of positions at which the corresponding symbols + * are different. + * @author [Aybars Nazlica](https://github.com/aybarsnazlica) + */ + +#include /// for assert +#include /// for IO operations + +/** + * @brief Function to calculate the Hamming distance between two strings + * @param param1 string 1 + * @param param2 string 2 + * @returns Hamming distance + */ +int hamming_distance(char* str1, char* str2) +{ + int i = 0, distance = 0; + + while (str1[i] != '\0') + { + if (str1[i] != str2[i]) + { + distance++; + } + i++; + } + + return distance; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() +{ + char str1[] = "karolin"; + char str2[] = "kathrin"; + + assert(hamming_distance(str1, str2) == 3); + + char str3[] = "00000"; + char str4[] = "11111"; + + assert(hamming_distance(str3, str4) == 5); + printf("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/misc/isArmstrong.c b/misc/isArmstrong.c deleted file mode 100644 index b7955ae771..0000000000 --- a/misc/isArmstrong.c +++ /dev/null @@ -1,24 +0,0 @@ -#include - -int main() -{ - int n, sum=0, i, num; - printf("Enter number: "); - scanf("%d",&n); - num=n; - while (n!=0) - { - i=n%10; - sum=sum+(i*i*i); - n=n/10; - } - if (sum==num) - { - printf("%d is an armstrong number!\n", num); - } - else - { - printf("%d is not an armstrong number!\n", num); - } - return 0; -} diff --git a/misc/lexicographicPermutations.c b/misc/lexicographicPermutations.c deleted file mode 100644 index cfffdbdf75..0000000000 --- a/misc/lexicographicPermutations.c +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include -#include - -void swap(char* left, char* right){ - char temp = *left; - *left = *right; - *right = temp; -} - -int compare (const void * a, const void * b){ - return ( *(char*)a - *(char*)b ); -} - -void PrintSortedPermutations(char str[]) -{ - int strSize = strlen(str); - qsort(str, strSize, sizeof(char), compare); - - int largerPermFound = 1; - do{ - // 1. Print permutation - printf("%s\n", str); - // 2. Find rightmost char that is smaller than char to its right - int i; - for (i = strSize - 2; i >= 0 && str[i] >= str[i+1]; --i){} - - // if we couldn't find one, we're finished, else we can swap - if (i >= 0){ - // 3. find character at index j such that str[j] = min(str[k]) && str[k] > str[i] for all k > i - int j = i+1, k; - for(k=j; k str[i] && str[k] < str[j]) - j = k; - } - // 3. Swap chars at i and j - swap(&str[i], &str[j]); - // 4. Sort string to the right of i - qsort(str+i+1, strSize-i-1, sizeof(char), compare); - } - else largerPermFound = 0; - } - while(largerPermFound); -} - -int main() { - int n; //size of string - scanf("%d\n",&n); - char str[n]; - scanf("%s",str); - PrintSortedPermutations(str); - return 0; -} diff --git a/misc/lexicographic_permutations.c b/misc/lexicographic_permutations.c new file mode 100644 index 0000000000..10f8cedff7 --- /dev/null +++ b/misc/lexicographic_permutations.c @@ -0,0 +1,65 @@ +#include +#include +#include + +void swap(char *left, char *right) +{ + char temp = *left; + *left = *right; + *right = temp; +} + +int compare(const void *a, const void *b) { return (*(char *)a - *(char *)b); } + +void PrintSortedPermutations(char *str) +{ + int strSize = strlen(str); + qsort(str, strSize, sizeof(char), compare); + + int largerPermFound = 1; + do + { + // 1. Print permutation + printf("%s\n", str); + // 2. Find rightmost char that is smaller than char to its right + int i; + for (i = strSize - 2; i >= 0 && str[i] >= str[i + 1]; --i) + { + } + + // if we couldn't find one, we're finished, else we can swap + if (i >= 0) + { + // 3. find character at index j such that str[j] = min(str[k]) && + // str[k] > str[i] for all k > i + int j = i + 1, k; + for (k = j; k < strSize && str[k]; k++) + { + if (str[k] > str[i] && str[k] < str[j]) + j = k; + } + // 3. Swap chars at i and j + swap(&str[i], &str[j]); + // 4. Sort string to the right of i + qsort(str + i + 1, strSize - i - 1, sizeof(char), compare); + } + else + largerPermFound = 0; + } while (largerPermFound); +} + +int main() +{ + int n; // size of string + scanf("%d\n", &n); + if (n <= 0 || n >= 1000) + { + perror("Input number out of range: >0 and <1000\n"); + return -1; + } + char *str = (char *)malloc(n * sizeof(char)); + scanf("%s", str); + PrintSortedPermutations(str); + free(str); + return 0; +} diff --git a/misc/longest_subsequence.c b/misc/longest_subsequence.c new file mode 100644 index 0000000000..0beeda9de2 --- /dev/null +++ b/misc/longest_subsequence.c @@ -0,0 +1,97 @@ +#include +#include + +void longestSub(int *ARRAY, int ARRAY_LENGTH, int **RESULT, int *RESULT_LENGTH) +{ // RESULT and RESULT_LENGTH will be modified by their pointers + + if (ARRAY_LENGTH <= 1) + { + *RESULT = ARRAY; + *RESULT_LENGTH = ARRAY_LENGTH; + } + else + { + int PIVOT = ARRAY[0]; + int *LONGEST_SUB = NULL; + int i, j, LONGEST_SUB_LENGTH = 0; + int TEMPORARY_ARRAY_LENGTH = 0, *TEMPORARY_ARRAY = NULL; + + for (i = 1; i < ARRAY_LENGTH; i++) + { + if (ARRAY[i] < PIVOT) + { + TEMPORARY_ARRAY_LENGTH = 0; + TEMPORARY_ARRAY = NULL; + + for (j = i + 1; j < ARRAY_LENGTH; j++) + { + if (ARRAY[j] >= ARRAY[i]) + { + TEMPORARY_ARRAY_LENGTH++; + TEMPORARY_ARRAY = (int *)realloc( + TEMPORARY_ARRAY, + TEMPORARY_ARRAY_LENGTH * sizeof(int)); + TEMPORARY_ARRAY[TEMPORARY_ARRAY_LENGTH - 1] = ARRAY[j]; + } + } + + longestSub(TEMPORARY_ARRAY, TEMPORARY_ARRAY_LENGTH, + &TEMPORARY_ARRAY, &TEMPORARY_ARRAY_LENGTH); + if (LONGEST_SUB_LENGTH < TEMPORARY_ARRAY_LENGTH + 1) + { + LONGEST_SUB_LENGTH = TEMPORARY_ARRAY_LENGTH + 1; + LONGEST_SUB = (int *)realloc( + LONGEST_SUB, LONGEST_SUB_LENGTH * sizeof(int)); + LONGEST_SUB[0] = ARRAY[i]; + + for (i = 1; i < LONGEST_SUB_LENGTH; i++) + LONGEST_SUB[i] = TEMPORARY_ARRAY[i - 1]; + } + } + } + + TEMPORARY_ARRAY = NULL; + TEMPORARY_ARRAY_LENGTH = 0; + for (i = 1; i < ARRAY_LENGTH; i++) + { + if (ARRAY[i] >= PIVOT) + { + TEMPORARY_ARRAY_LENGTH++; + TEMPORARY_ARRAY = (int *)realloc( + TEMPORARY_ARRAY, TEMPORARY_ARRAY_LENGTH * sizeof(int)); + TEMPORARY_ARRAY[TEMPORARY_ARRAY_LENGTH - 1] = ARRAY[i]; + } + } + + longestSub(TEMPORARY_ARRAY, TEMPORARY_ARRAY_LENGTH, &TEMPORARY_ARRAY, + &TEMPORARY_ARRAY_LENGTH); + if (TEMPORARY_ARRAY_LENGTH + 1 > LONGEST_SUB_LENGTH) + { + LONGEST_SUB_LENGTH = TEMPORARY_ARRAY_LENGTH + 1; + LONGEST_SUB = + (int *)realloc(LONGEST_SUB, LONGEST_SUB_LENGTH * sizeof(int)); + LONGEST_SUB[0] = PIVOT; + for (i = 1; i < LONGEST_SUB_LENGTH; i++) + LONGEST_SUB[i] = TEMPORARY_ARRAY[i - 1]; + } + *RESULT = LONGEST_SUB; + *RESULT_LENGTH = LONGEST_SUB_LENGTH; + } +} + +int main() +{ + int EXAMPLE_LENGTH = 8; + int EXAMPLE[] = {18, 2, 15, 4, 30, 0, 11, 12}; + + int *RESULT = NULL; + int RESULT_LENGTH, i; + + longestSub(EXAMPLE, EXAMPLE_LENGTH, &RESULT, &RESULT_LENGTH); + + printf("Longest Sub Sequence length: %d and it's:\n", RESULT_LENGTH); + for (i = 0; i < RESULT_LENGTH; i++) printf("%d ", RESULT[i]); + printf("\n"); + + return 0; +} \ No newline at end of file diff --git a/misc/mcnaughton_yamada_thompson.c b/misc/mcnaughton_yamada_thompson.c new file mode 100644 index 0000000000..9f13ae03e4 --- /dev/null +++ b/misc/mcnaughton_yamada_thompson.c @@ -0,0 +1,721 @@ +/** + * @file + * @brief [McNaughton–Yamada–Thompson algorithm](https://en.wikipedia.org/wiki/Thompson%27s_construction) + * @details + * From Wikipedia: + * In computer science, Thompson's construction algorithm, + * also called the McNaughton–Yamada–Thompson algorithm, + * is a method of transforming a regular expression into + * an equivalent nondeterministic finite automaton (NFA). + * This implementation implements the all three operations + * (implicit concatenation, '|' for union, '*' for Kleene star) + * required by the formal definition of regular expressions. + * @author [Sharon Cassidy](https://github.com/CascadingCascade) + */ + +#include /// for assert() +#include /// for IO operations +#include /// for string operations +#include /// for memory management + +/* Begin declarations, I opted to place various helper / utility functions + * close to their usages and didn't split their declaration / definition */ + +/** + * @brief Definition for a binary abstract syntax tree (AST) node + */ +struct ASTNode { + char content; ///< the content of this node + struct ASTNode* left; ///< left child + struct ASTNode* right; ///< right child +}; + +struct ASTNode* createNode(char content); +void destroyNode(struct ASTNode* node); +char* preProcessing(const char* input); +struct ASTNode* buildAST(const char* input); + +/** + * @brief Definition for a NFA state transition rule + */ +struct transRule { + struct NFAState* target; ///< pointer to the state to transit to + char cond; ///< the input required to activate this transition +}; + +struct transRule* createRule(struct NFAState* state, char c); +void destroyRule(struct transRule* rule); + +/** + * @brief Definition for a NFA state. Each NFAState object is initialized + * to have a capacity of three rules, since there will only be at most two + * outgoing rules and one empty character circular rule in this algorithm + */ +struct NFAState { + int ruleCount; ///< number of transition rules this state have + struct transRule** rules; ///< the transition rules +}; + +struct NFAState* createState(void); +void destroyState(struct NFAState* state); + +/** + * @brief Definition for the NFA itself. + * statePool[0] is defined to be its starting state, + * and statePool[1] is defined to be its accepting state. + * for simplicity's sake all NFAs are initialized to have + * a small fixed capacity, although due to the recursive nature + * of this algorithm this capacity is believed to be sufficient + */ +struct NFA { + int stateCount; ///< the total number of states this NFA have + struct NFAState** statePool; ///< the pool of all available states + int ruleCount; ///< the total number of transition rules in this NFA + struct transRule** rulePool; ///< the pool of all transition rules + int CSCount; ///< the number of currently active states + struct NFAState** currentStates; ///< the pool of all active states + int subCount; ///< the number of sub NFAs + struct NFA** subs; ///< the pool of all sub NFAs + int wrapperFlag; ///< whether this NFA is a concatenation wrapper +}; + +struct NFA* createNFA(void); +void destroyNFA(struct NFA* nfa); +void addState(struct NFA* nfa, struct NFAState* state); +void addRule(struct NFA* nfa, struct transRule* rule, int loc); +void postProcessing(struct NFA* nfa); +void transit(struct NFA* nfa, char input); +int isAccepting(const struct NFA* nfa); + +/* End definitions, begin abstract syntax tree construction */ + +/** + * @brief helper function to determine whether a character should be + * considered a character literal + * @param ch the character to be tested + * @returns `1` if it is a character literal + * @returns `0` otherwise + */ +int isLiteral(const char ch) { + return !(ch == '(' || ch == ')' || ch == '*' || ch == '\n' || ch == '|'); +} + +/** + * @brief performs preprocessing on a regex string, + * making all implicit concatenations explicit + * @param input target regex string + * @returns pointer to the processing result + */ +char* preProcessing(const char* input) { + const size_t len = strlen(input); + if(len == 0) { + char* str = malloc(1); + str[0] = '\0'; + return str; + } + + char* str = malloc(len * 2); + size_t op = 0; + + for (size_t i = 0; i < len - 1; ++i) { + char c = input[i]; + str[op++] = c; + // one character lookahead + char c1 = input[i + 1]; + + if( (isLiteral(c) && isLiteral(c1)) || + (isLiteral(c) && c1 == '(') || + (c == ')' && c1 == '(') || + (c == ')' && isLiteral(c1)) || + (c == '*' && isLiteral(c1)) || + (c == '*' && c1 == '(') + ) { + // '\n' is used to represent concatenation + // in this implementation + str[op++] = '\n'; + } + } + + str[op++] = input[len - 1]; + str[op] = '\0'; + return str; +} + +/** + * @brief utility function to locate the first occurrence + * of a character in a string while respecting parentheses + * @param str target string + * @param key the character to be located + * @returns the index of its first occurrence, `0` if it could not be found + */ +size_t indexOf(const char* str, char key) { + int depth = 0; + + for (size_t i = 0; i < strlen(str); ++i) { + const char c = str[i]; + + if(depth == 0 && c == key) { + return i; + } + if(c == '(') depth++; + if(c == ')') depth--; + } + // Due to the way this function is intended to be used, + // it's safe to assume the character will not appear as + // the string's first character + // thus `0` is used as the `not found` value + return 0; +} + +/** + * @brief utility function to create a subString + * @param str target string + * @param begin starting index, inclusive + * @param end ending index, inclusive + * @returns pointer to the newly created subString + */ +char* subString(const char* str, size_t begin, size_t end) { + char* res = malloc(end - begin + 2); + strncpy(res, str + begin, end - begin + 1); + res[end - begin + 1] = '\0'; + return res; +} + +/** + * @brief recursively constructs a AST from a preprocessed regex string + * @param input regex + * @returns pointer to the resulting tree + */ +struct ASTNode* buildAST(const char* input) { + + struct ASTNode* node = createNode('\0'); + node->left = NULL; + node->right = NULL; + const size_t len = strlen(input); + size_t index; + + // Empty input + if(len == 0) return node; + + // Character literals + if(len == 1) { + node->content = input[0]; + return node; + } + + // Discard parentheses + if(input[0] == '(' && input[len - 1] == ')') { + char* temp = subString(input, 1, len - 2); + destroyNode(node); + node = buildAST(temp); + + free(temp); + return node; + } + + // Union + index = indexOf(input, '|'); + if(index) { + node->content = '|'; + + char* temp1 = subString(input, 0, index - 1); + char* temp2 = subString(input, index + 1, len - 1); + node->left = buildAST(temp1); + node->right = buildAST(temp2); + + free(temp2); + free(temp1); + return node; + } + + // Concatenation + index = indexOf(input, '\n'); + if(index) { + node->content = '\n'; + + char* temp1 = subString(input, 0, index - 1); + char* temp2 = subString(input, index + 1, len - 1); + node->left = buildAST(temp1); + node->right = buildAST(temp2); + + free(temp2); + free(temp1); + return node; + } + + // Kleene star + // Testing with indexOf() is unnecessary here, + // Since all other possibilities have been exhausted + node->content = '*'; + char* temp = subString(input, 0, len - 2); + node->left = buildAST(temp); + node->right = NULL; + + free(temp); + return node; +} + +/* End AST construction, begins the actual algorithm itself */ + +/** + * @brief helper function to recursively redirect transition rule targets + * @param nfa target NFA + * @param src the state to redirect away from + * @param dest the state to redirect to + * @returns void + */ +void redirect(struct NFA* nfa, struct NFAState* src, struct NFAState* dest) { + for (int i = 0; i < nfa->subCount; ++i) { + redirect(nfa->subs[i], src, dest); + } + for (int i = 0; i < nfa->ruleCount; ++i) { + struct transRule* rule = nfa->rulePool[i]; + if (rule->target == src) { + rule->target = dest; + } + } +} + +struct NFA* compileFromAST(struct ASTNode* root) { + + struct NFA* nfa = createNFA(); + + // Empty input + if (root->content == '\0') { + addRule(nfa, createRule(nfa->statePool[1], '\0'), 0); + return nfa; + } + + // Character literals + if (isLiteral(root->content)) { + addRule(nfa, createRule(nfa->statePool[1], root->content), 0); + return nfa; + } + + switch (root->content) { + + case '\n': { + struct NFA* ln = compileFromAST(root->left); + struct NFA* rn = compileFromAST(root->right); + + // Redirects all rules targeting ln's accepting state to + // target rn's starting state + redirect(ln, ln->statePool[1], rn->statePool[0]); + + // Manually creates and initializes a special + // "wrapper" NFA + destroyNFA(nfa); + struct NFA* wrapper = malloc(sizeof(struct NFA)); + wrapper->stateCount = 2; + wrapper->statePool = malloc(sizeof(struct NFAState*) * 2); + wrapper->subCount = 0; + wrapper->subs = malloc(sizeof(struct NFA*) * 2); + wrapper->ruleCount = 0; + wrapper->rulePool = malloc(sizeof(struct transRule*) * 3); + wrapper->CSCount = 0; + wrapper->currentStates = malloc(sizeof(struct NFAState*) * 2); + wrapper->wrapperFlag = 1; + wrapper->subs[wrapper->subCount++] = ln; + wrapper->subs[wrapper->subCount++] = rn; + + // Maps the wrapper NFA's starting and ending states + // to its sub NFAs + wrapper->statePool[0] = ln->statePool[0]; + wrapper->statePool[1] = rn->statePool[1]; + + return wrapper; + } + case '|': { + + struct NFA* ln = compileFromAST(root->left); + struct NFA* rn = compileFromAST(root->right); + nfa->subs[nfa->subCount++] = ln; + nfa->subs[nfa->subCount++] = rn; + + // Adds empty character transition rules + addRule(nfa, createRule(ln->statePool[0], '\0'), 0); + addRule(ln, createRule(nfa->statePool[1], '\0'), 1); + addRule(nfa, createRule(rn->statePool[0], '\0'), 0); + addRule(rn, createRule(nfa->statePool[1], '\0'), 1); + + return nfa; + } + case '*': { + struct NFA* ln = compileFromAST(root->left); + nfa->subs[nfa->subCount++] = ln; + + addRule(ln, createRule(ln->statePool[0], '\0'), 1); + addRule(nfa, createRule(ln->statePool[0], '\0'), 0); + addRule(ln, createRule(nfa->statePool[1], '\0'), 1); + addRule(nfa, createRule(nfa->statePool[1], '\0'), 0); + + return nfa; + } + } + + // Fallback, shouldn't happen in normal operation + destroyNFA(nfa); + return NULL; +} + +/* Ends the algorithm, begins NFA utility functions*/ + +/** + * @brief adds a state to a NFA + * @param nfa target NFA + * @param state the NFA state to be added + * @returns void + */ +void addState(struct NFA* nfa, struct NFAState* state) { + nfa->statePool[nfa->stateCount++] = state; +} + +/** + * @brief adds a transition rule to a NFA + * @param nfa target NFA + * @param rule the rule to be added + * @param loc which state this rule should be added to + * @returns void + */ +void addRule(struct NFA* nfa, struct transRule* rule, int loc) { + nfa->rulePool[nfa->ruleCount++] = rule; + struct NFAState* state = nfa->statePool[loc]; + state->rules[state->ruleCount++] = rule; +} + +/** + * @brief performs postprocessing on a compiled NFA, + * add circular empty character transition rules where + * it's needed for the NFA to function correctly + * @param nfa target NFA + * @returns void + */ +void postProcessing(struct NFA* nfa) { + // Since the sub NFA's states and rules are managed + // through their own pools, recursion is necessary + for (int i = 0; i < nfa->subCount; ++i) { + postProcessing(nfa->subs[i]); + } + + // If a state does not have any empty character accepting rule, + // we add a rule that circles back to itself + // So this state will be preserved when + // empty characters are inputted + for (int i = 0; i < nfa->stateCount; ++i) { + + struct NFAState* pState = nfa->statePool[i]; + int f = 0; + for (int j = 0; j < pState->ruleCount; ++j) { + if(pState->rules[j]->cond == '\0') { + f = 1; + break; + } + } + + if (!f) { + addRule(nfa, createRule(pState, '\0'), i); + } + } +} + +/** + * @brief helper function to determine an element's presence in an array + * @param states target array + * @param len length of the target array + * @param state the element to search for + * @returns `1` if the element is present, `0` otherwise + */ +int contains(struct NFAState** states, int len, struct NFAState* state) { + int f = 0; + for (int i = 0; i < len; ++i) { + if(states[i] == state) { + f = 1; + break; + } + } + return f; +} + +/** + * @brief helper function to manage empty character transitions + * @param target target NFA + * @param states pointer to results storage location + * @param sc pointer to results count storage location + * @returns void + */ +void findEmpty(struct NFAState* target, struct NFAState** states, int *sc) { + for (int i = 0; i < target->ruleCount; ++i) { + const struct transRule *pRule = target->rules[i]; + + if (pRule->cond == '\0' && !contains(states, *sc, pRule->target)) { + states[(*sc)++] = pRule->target; + // the use of `states` and `sc` is necessary + // to sync data across recursion levels + findEmpty(pRule->target, states, sc); + } + } +} + +/** + * @brief moves a NFA forward + * @param nfa target NFA + * @param input the character to be fed into the NFA + * @returns void + */ +void transit(struct NFA* nfa, char input) { + struct NFAState** newStates = malloc(sizeof(struct NFAState*) * 10); + int NSCount = 0; + + if (input == '\0') { + // In case of empty character input, it's possible for + // a state to transit to another state that's more than + // one rule away, we need to take that into account + for (int i = nfa->CSCount - 1; i > -1; --i) { + struct NFAState *pState = nfa->currentStates[i]; + nfa->CSCount--; + + struct NFAState** states = malloc(sizeof(struct NFAState*) * 10); + int sc = 0; + findEmpty(pState, states, &sc); + + for (int j = 0; j < sc; ++j) { + if(!contains(newStates,NSCount, states[j])) { + newStates[NSCount++] = states[j]; + } + } + free(states); + } + } else { + // Iterates through all current states + for (int i = nfa->CSCount - 1; i > -1; --i) { + struct NFAState *pState = nfa->currentStates[i]; + // Gradually empties the current states pool, so + // it can be refilled + nfa->CSCount--; + + // Iterates through rules of this state + for (int j = 0; j < pState->ruleCount; ++j) { + const struct transRule *pRule = pState->rules[j]; + + if(pRule->cond == input) { + if(!contains(newStates, NSCount, pRule->target)) { + newStates[NSCount++] = pRule->target; + } + } + } + } + } + + nfa->CSCount = NSCount; + for (int i = 0; i < NSCount; ++i) { + nfa->currentStates[i] = newStates[i]; + } + free(newStates); +} + +/** + * @brief determines whether the NFA is currently in its accepting state + * @param nfa target NFA + * @returns `1` if the NFA is in its accepting state + * @returns `0` otherwise + */ +int isAccepting(const struct NFA* nfa) { + for (int i = 0; i < nfa->CSCount; ++i) { + if(nfa->currentStates[i] == nfa->statePool[1]) { + return 1; + } + } + return 0; +} + +/* Ends NFA utilities, begins testing function*/ + +/** + * @brief Testing helper function + * @param regex the regular expression to be used + * @param string the string to match against + * @param expected expected results + * @returns void + */ +void testHelper(const char* regex, const char* string, const int expected) { + char* temp = preProcessing(regex); + struct ASTNode* node = buildAST(temp); + + struct NFA* nfa = compileFromAST(node); + postProcessing(nfa); + + // reallocates the outermost NFA's current states pool + // because it will actually be used to store all the states + nfa->currentStates = realloc(nfa->currentStates, sizeof(struct NFAState*) * 100); + // Starts the NFA by adding its starting state to the pool + nfa->currentStates[nfa->CSCount++] = nfa->statePool[0]; + + // feeds empty characters into the NFA before and after + // every normal character + for (size_t i = 0; i < strlen(string); ++i) { + transit(nfa, '\0'); + transit(nfa, string[i]); + } + transit(nfa, '\0'); + + assert(isAccepting(nfa) == expected); + + destroyNFA(nfa); + destroyNode(node); + free(temp); +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test(void) { + testHelper("(c|a*b)", "c", 1); + testHelper("(c|a*b)", "aab", 1); + testHelper("(c|a*b)", "ca", 0); + testHelper("(c|a*b)*", "caaab", 1); + testHelper("(c|a*b)*", "caba", 0); + testHelper("", "", 1); + testHelper("", "1", 0); + testHelper("(0|(1(01*(00)*0)*1)*)*","11",1); + testHelper("(0|(1(01*(00)*0)*1)*)*","110",1); + testHelper("(0|(1(01*(00)*0)*1)*)*","1100",1); + testHelper("(0|(1(01*(00)*0)*1)*)*","10000",0); + testHelper("(0|(1(01*(00)*0)*1)*)*","00000",1); + + printf("All tests have successfully passed!\n"); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main(void) { + test(); // run self-test implementations + return 0; +} + +/* I opted to place these more-or-less boilerplate code and their docs + * at the end of file for better readability */ + +/** + * @brief creates and initializes a AST node + * @param content data to initializes the node with + * @returns pointer to the newly created node + */ +struct ASTNode* createNode(const char content) { + struct ASTNode* node = malloc(sizeof(struct ASTNode)); + node->content = content; + node->left = NULL; + node->right = NULL; + return node; +} + +/** + * @brief recursively destroys a AST + * @param node the root node of the tree to be deleted + * @returns void + */ +void destroyNode(struct ASTNode* node) { + if(node->left != NULL) { + destroyNode(node->left); + } + + if(node->right != NULL) { + destroyNode(node->right); + } + + free(node); +} + +/** + * @brief creates and initializes a transition rule + * @param state transition target + * @param c transition condition + * @returns pointer to the newly created rule + */ +struct transRule* createRule(struct NFAState* state, char c) { + struct transRule* rule = malloc(sizeof(struct transRule)); + rule->target = state; + rule->cond = c; + return rule; +} + +/** + * @brief destroys a transition rule object + * @param rule pointer to the object to be deleted + * @returns void + */ +void destroyRule(struct transRule* rule) { + free(rule); +} + +/** + * @brief creates and initializes a NFA state + * @returns pointer to the newly created NFA state + */ +struct NFAState* createState(void) { + struct NFAState* state = malloc(sizeof(struct NFAState)); + state->ruleCount = 0; + state->rules = malloc(sizeof(struct transRule*) * 3); + return state; +} + +/** + * @brief destroys a NFA state + * @param state pointer to the object to be deleted + * @returns void + */ +void destroyState(struct NFAState* state) { + free(state->rules); + free(state); +} + +/** + * @brief creates and initializes a NFA + * @returns pointer to the newly created NFA + */ +struct NFA* createNFA(void) { + struct NFA* nfa = malloc(sizeof(struct NFA)); + + nfa->stateCount = 0; + nfa->statePool = malloc(sizeof(struct NFAState*) * 5); + nfa->ruleCount = 0; + nfa->rulePool = malloc(sizeof(struct transRule*) * 10); + nfa->CSCount = 0; + nfa->currentStates = malloc(sizeof(struct NFAState*) * 5); + nfa->subCount = 0; + nfa->subs = malloc(sizeof(struct NFA*) * 5); + nfa->wrapperFlag = 0; + + addState(nfa, createState()); + addState(nfa, createState()); + return nfa; +} + +/** + * @brief recursively destroys a NFA + * @param nfa pointer to the object to be deleted + * @returns void + */ +void destroyNFA(struct NFA* nfa) { + for (int i = 0; i < nfa->subCount; ++i) { + destroyNFA(nfa->subs[i]); + } + + // In case of a wrapper NFA, do not free its states + // because it doesn't really have any states of its own + if (!nfa->wrapperFlag) { + for (int i = 0; i < nfa->stateCount; ++i) { + destroyState(nfa->statePool[i]); + } + } + for (int i = 0; i < nfa->ruleCount; ++i) { + destroyRule(nfa->rulePool[i]); + } + free(nfa->statePool); + free(nfa->currentStates); + free(nfa->rulePool); + free(nfa->subs); + free(nfa); +} diff --git a/misc/mirror b/misc/mirror deleted file mode 100644 index 6db82a80fe..0000000000 --- a/misc/mirror +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include // we include the library string.h to the use of string - -void saisie (char *cpointeur); // Prototypes of the three functions used in the program -int compte (char *s); -char* miroir (char * s); - -int main (int argc , char *argv[]) -{ -char chaine[20]; -saisie(chaine); -printf("miroir est %s",miroir(chaine)); - -} -// this function is used to put a string -void saisie (char *cpointeur) -{ - printf("saisir une chaine\n"); - scanf("%s",cpointeur); -} -/* the function miroir (in french ) it means "mirror" , the major idea is to permute the first caractere with the last using an auxilary -variable (aux) the the 2nd character with the penultimate one and so on . -we made a call to the function (compte) which counts the length of the string . As you can see clearly , I substruct 1 from the equation -k = compte(s)-1 ; to get rid of the EOF caractere which is '\0' because it is not a caractere from the string typed */ -char* miroir (char *s) -{ -int i ; -char aux ; -int k ; -k = compte(s)-1 ; -i = 0 ; -while(i<=k) -{ -aux = s[i]; -s[i]=s[k]; -s[k]=aux ; -k-- ; -i++ ; -} - -return s ; -} - -// compte plays the role of strlen so we can change it by an strlen function if you want that -int compte (char *s) -{ - char *p ; - int k ; - p=s ; - k=0 ; - while(*p!='\0') - { - p++ ; - k++ ; - } - return k ; -} diff --git a/misc/mirror.c b/misc/mirror.c new file mode 100644 index 0000000000..56ffc88a6f --- /dev/null +++ b/misc/mirror.c @@ -0,0 +1,60 @@ +#include +#include // we include the library string.h to the use of string + +void saisie( + char *cpointeur); // Prototypes of the three functions used in the program +int compte(char *s); +char *miroir(char *s); + +int main(int argc, char *argv[]) +{ + char chaine[20]; + saisie(chaine); + printf("miroir est %s", miroir(chaine)); +} +// this function is used to put a string +void saisie(char *cpointeur) +{ + printf("saisir une chaine\n"); + scanf("%s", cpointeur); +} +/* the function miroir (in french ) it means "mirror" , the major idea is to +permute the first caractere with the last using an auxilary variable (aux) the +the 2nd character with the penultimate one and so on . we made a call to the +function (compte) which counts the length of the string . As you can see clearly +, I substruct 1 from the equation k = compte(s)-1 ; to get rid of the EOF +caractere which is '\0' because it is not a caractere from the string typed */ +char *miroir(char *s) +{ + int i; + char aux; + int k; + k = compte(s) - 1; + i = 0; + while (i <= k) + { + aux = s[i]; + s[i] = s[k]; + s[k] = aux; + k--; + i++; + } + + return s; +} + +// compte plays the role of strlen so we can change it by an strlen function if +// you want that +int compte(char *s) +{ + char *p; + int k; + p = s; + k = 0; + while (*p != '\0') + { + p++; + k++; + } + return k; +} diff --git a/misc/palindrome.c b/misc/palindrome.c deleted file mode 100644 index ec82e8932d..0000000000 --- a/misc/palindrome.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -int main() -{ - int n, reversedInteger = 0, remainder, originalInteger; - - printf("Enter an integer: "); - scanf("%d", &n); - - originalInteger = n; - - // reversed integer is stored in variable - while( n!=0 ) - { - remainder = n%10; - reversedInteger = reversedInteger*10 + remainder; - n /= 10; - } - - // palindrome if orignalInteger and reversedInteger are equal - if (originalInteger == reversedInteger) - printf("%d is a palindrome.", originalInteger); - else - printf("%d is not a palindrome.", originalInteger); - - return 0; -} diff --git a/misc/pid.c b/misc/pid.c new file mode 100644 index 0000000000..95c743ca96 --- /dev/null +++ b/misc/pid.c @@ -0,0 +1,88 @@ +/** + * PID Controller + * + * The PID controller is a linear control algorithm that has three terms: + * - Proportional: A simple scaling of the error value by a gain kP + * - Integral: Integration of the error value over time, then multipled by gain + * kI + * - Derivative: Rate of change of the error value over time, multiplied by + * gain kD + * + * Terms of the controller can be removed by setting their gain to 0, creating a + * PI (kD = 0) or PD (kI = 0) controller. Depending on the control problem at + * hand, some terms may not increase the performance of the system, or may have + * a negative effect. + * + * For a more mathematical expanation of the PID Controller, see + * https://en.wikipedia.org/wiki/PID_controller + * + * Limitations of this implementation: + * - Since this implementation is just for demonstration, the pid_step function + * takes the dt as a parameter, and it can be provided by the user in main(). + * This allows deterministic experimentation with the algorithm, rather than + * using time(NULL) which would make the function non-deterministic. + * + * Inputs: e(t) - Current error at time t. For example, how far a servo is off + * the desired angle Output: u(t) - Controller output at time t. + */ +#include + +struct pid +{ + // Controller gains + float kP; + float kI; + float kD; + + // State variables + float lastError; + float integral; +}; + +float pid_step(struct pid *controller, float dt, float error) +{ + // Calculate p term + float p = error * controller->kP; + + // Calculate i term + controller->integral += error * dt * controller->kI; + + // Calculate d term, taking care to not divide by zero + float d = + dt == 0 ? 0 : ((error - controller->lastError) / dt) * controller->kD; + controller->lastError = error; + + return p + controller->integral + d; +} + +int main() +{ + printf("PID Controller Example\n"); + + struct pid controller = {.lastError = 0, .integral = 0}; + + // Take the controller gains from the user + printf( + "Please enter controller gains in format kP, kI, KD. For example, " + "\"1.2 2.1 3.2\"\n> "); + scanf("%f %f %f", &controller.kP, &controller.kI, &controller.kD); + printf("Using kP: %f, kI: %f, kD: %f\n", controller.kP, controller.kI, + controller.kD); + + // How often the pid_step algorithm expects to be called. In a real life + // scenario this would be provided by calling time(NULL) - last_time, or by + // calling the function reliably at X Hz (using a timer or RTOS etc) For + // demonstration of this algorithm though, it is defined below as 1 second, + // allowing easy testing of integral and derivative terms. + float time_step = 1; + + float error_value; + while (1) + { + printf("Enter error value\n>"); + scanf("%f", &error_value); + + float output = pid_step(&controller, time_step, error_value); + printf("Output: %f\n", output); + } +} diff --git a/misc/poly_add.c b/misc/poly_add.c new file mode 100644 index 0000000000..8280315e09 --- /dev/null +++ b/misc/poly_add.c @@ -0,0 +1,301 @@ +/** + * @file + * @brief Implementation of [Addition of two polynomials] + * (https://en.wikipedia.org/wiki/Polynomial#Addition) + * @author [Ankita Roy Chowdhury](https://github.com/Ankita19ms0010) + * @details + * This code takes two polynomials as input + * and prints their sum using linked list. + * The polynomials must be in increasing or decreasing order of degree. + * Degree must be positive. + */ +#include // for io operations +#include + +/** + * @brief identifier for single-variable polynomial coefficients as a linked + * list + */ +struct term +{ + int coef; /**< coefficient value */ + int pow; /**< power of the polynomial term */ + struct term *next; /**< pointer to the successive term */ +}; + +/** + * @brief Frees memory space + * @param poly first term of polynomial + * @returns void + */ +void free_poly(struct term *poly) +{ + while (poly) + { + struct term *next = poly->next; + free(poly); + poly = next; + } +} + +/** + * The function will create a polynomial + * @param poly stores the address of the polynomial being created + * @param coef contains the coefficient of the node + * @param pow contains the degree + * @returns none + */ +void create_polynomial(struct term **poly, int coef, int pow) +{ + // Creating the polynomial using temporary linked lists + struct term **temp1 = poly; + + while (*temp1) + { + temp1 = &(*temp1)->next; + } + + // Now temp1 reaches to the end of the list + *temp1 = (struct term *)malloc( + sizeof(struct term)); // Create the term and linked as the tail + (*temp1)->coef = coef; + (*temp1)->pow = pow; + (*temp1)->next = NULL; +} + +/** + * The function will add 2 polynomials + * @param poly1 first polynomial of the addition + * @param poly2 second polynomial of the addition + * @param pol the resultant polynomial + */ + +void poly_add(struct term **pol, struct term *poly1, struct term *poly2) +{ + // Creating a temporary linked list to store the resultant polynomial + struct term *temp = (struct term *)malloc(sizeof(struct term)); + temp->next = NULL; + *pol = + temp; //*pol always points to the 1st node of the resultant polynomial + + // Comparing the powers of the nodes of both the polynomials + // until one gets exhausted + while (poly1 && poly2) + { + /* If the power of the first polynomial is greater than the power of the + second one place the power and coefficient of that node of the first + polynomial in temp and increase the pointer poly1 + */ + if (poly1->pow > poly2->pow) + { + temp->coef = poly1->coef; + temp->pow = poly1->pow; + poly1 = poly1->next; + } + /* If the power of the second polynomial is greater than the power of + the first one place the power and coefficient of that node of the + second polynomial in temp and increase the pointer poly2 + */ + else if (poly1->pow < poly2->pow) + { + temp->coef = poly2->coef; + temp->pow = poly2->pow; + poly2 = poly2->next; + } + /* If both of them have same power then sum the coefficients + place both the summed coefficient and the power in temp + increase both the pointers poly1 and poly2 + */ + else + { + temp->coef = poly1->coef + poly2->coef; + temp->pow = poly1->pow; + poly1 = poly1->next; + poly2 = poly2->next; + } + /* If none of the polynomials are exhausted + dynamically create a node in temp + */ + if (poly1 && poly2) + { + temp->next = (struct term *)malloc( + sizeof(struct term)); // Dynamic node creation + temp = temp->next; // Increase the pointer temp + temp->next = NULL; + } + } + /* If one of the polynomials is exhausted + place the rest of the other polynomial as it is in temp + by creating nodes dynamically + */ + while (poly1 || poly2) + { + temp->next = (struct term *)malloc( + sizeof(struct term)); // Dynamic node creation + temp = temp->next; // Increasing the pointer + temp->next = NULL; + + /* If poly1 is not exhausted + place rest of that polynomial in temp + */ + if (poly1) + { + temp->coef = poly1->coef; + temp->pow = poly1->pow; + poly1 = poly1->next; + } + /* If poly2 is not exhausted + place rest of that polynomial in temp + */ + else if (poly2) + { + temp->coef = poly2->coef; + temp->pow = poly2->pow; + poly2 = poly2->next; + } + } +} + +/** + * The function will display the polynomial + * @param poly first term of the polynomial to be displayed + * @returns none + */ +void display_polynomial(struct term *poly) +{ + while (poly != NULL) + { + printf("%d x^%d", poly->coef, poly->pow); + poly = poly->next; + if (poly != NULL) + { + printf(" + "); + } + } +} + +/** + * @brief Test function 1 + * + * @details + * Polynomial 1 is 5 x^2 + 3 x^1 + 2 x^0 + * Polynomial 2 is 7 x^3 + 9 x^1 + 10 x^0 + * Resultant polynomial is 7 x^3 + 5 x^2 + 12 x^1 + 12 x^0 + * @returns void + */ +static void test1(struct term *poly1, struct term *poly2, struct term *poly3) +{ + printf("\n----Test 1----\n"); + printf("\nFirst Polynomial:\n"); // Defining the 1st polynomial + create_polynomial(&poly1, 5, 2); + create_polynomial(&poly1, 3, 1); + create_polynomial(&poly1, 2, 0); + display_polynomial(poly1); + + printf("\nSecond Polynomial:\n"); // Defining the 2nd polynomial + create_polynomial(&poly2, 7, 3); + create_polynomial(&poly2, 9, 1); + create_polynomial(&poly2, 10, 0); + display_polynomial(poly2); + + poly_add(&poly3, poly1, poly2); // Adding the two polynomials + printf("\nResultant polynomial:\n"); + display_polynomial(poly3); + printf("\n"); + + // Frees memory space + free_poly(poly1); + free_poly(poly2); + free_poly(poly3); +} + +/** + * @brief Test function 2 + * + * @details + * Polynomial 1 is 3 x^5 + 1 x^4 + 2 x^3 + -2 x^1 + 5 x^0 + * Polynomial 2 is 2 x^5 + 3 x^3 + 7 x^1 + 2 x^0 + * Resultant polynomial is 5 x^5 + 1 x^4 + 5 x^3 + 5 x^1 + 7 x^0 + * @returns void + */ +static void test2(struct term *poly1, struct term *poly2, struct term *poly3) +{ + printf("\n----Test 2----\n"); + printf("\nFirst Polynomial:\n"); // Defining the 1st polynomial + create_polynomial(&poly1, 3, 5); + create_polynomial(&poly1, 1, 4); + create_polynomial(&poly1, 2, 3); + create_polynomial(&poly1, -2, 1); + create_polynomial(&poly1, 5, 0); + + display_polynomial(poly1); + + printf("\nSecond Polynomial:\n"); // Defining the 2nd polynomial + create_polynomial(&poly2, 2, 5); + create_polynomial(&poly2, 3, 3); + create_polynomial(&poly2, 7, 1); + create_polynomial(&poly2, 2, 0); + + display_polynomial(poly2); + + poly_add(&poly3, poly1, poly2); // Adding the two polynomials + printf("\nResultant polynomial:\n"); + display_polynomial(poly3); + printf("\n"); + + // Frees memory space + free_poly(poly1); + free_poly(poly2); + free_poly(poly3); +} + +/** + * @brief Test function 3 + * + * @details + * Polynomial 1 is -12 x^0 + 8 x^1 + 4 x^3 + * Polynomial 2 is 5 x^0 + -13 x^1 + 3 x^3 + * Resultant polynomial is -7 x^0 + -5 x^1 + 7 x^3 + * @returns void + */ +static void test3(struct term *poly1, struct term *poly2, struct term *poly3) +{ + printf("\n----Test 3----\n"); + printf("\nFirst Polynomial:\n"); // Defining the 1st polynomial + create_polynomial(&poly1, -12, 0); + create_polynomial(&poly1, 8, 1); + create_polynomial(&poly1, 4, 3); + + display_polynomial(poly1); + + printf("\nSecond Polynomial:\n"); // Defining the 2nd polynomial + create_polynomial(&poly2, 5, 0); + create_polynomial(&poly2, -13, 1); + create_polynomial(&poly2, 3, 3); + + display_polynomial(poly2); + + poly_add(&poly3, poly1, poly2); // Adding the two polynomials + printf("\nResultant polynomial:\n"); + display_polynomial(poly3); + printf("\n"); + + // Frees memory space + free_poly(poly1); + free_poly(poly2); + free_poly(poly3); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main(void) +{ + struct term *poly1 = NULL, *poly2 = NULL, *poly3 = NULL; + test1(poly1, poly2, poly3); + test2(poly1, poly2, poly3); + test3(poly1, poly2, poly3); + + return 0; +} diff --git a/misc/postfix_evaluation.c b/misc/postfix_evaluation.c new file mode 100644 index 0000000000..ca8e97c37f --- /dev/null +++ b/misc/postfix_evaluation.c @@ -0,0 +1,128 @@ +/** + * @file + * @brief [Postfix evaluation algorithm](https://www.includehelp.com/c/evaluation-of-postfix-expressions-using-stack-with-c-program.aspx) implementation + * @details + * The input postfix expression is of type string upto 49 characters (including space delimiters). + * Supported operations- '+', '-', '/', '*', '%' + * @author [Kumar Yash](https://github.com/kumaryash18) + */ + +#include /// for IO operations +#include /// for strlen() +#include /// for isdigit() +#include /// for exit() +#include /// for int8_t +#include /// for assert + +/** + * @brief array implementation of stack using structure + */ +struct Stack { + int8_t stack[20]; ///< array stack + int top; ///< stores index of the top element +}; +struct Stack st; ///< global declaration of stack st + +/** + * @brief Function to push on the stack + * @param opd number to be pushed in the stack + * @returns void + */ +void push(int8_t opd) { + if(st.top == 19) { // overflow condition + printf("Stack overflow..."); + exit(1); + } + st.top++; + st.stack[st.top] = opd; +} + +/** + * @brief Function to pop from the stack + * @returns popped number + */ +int8_t pop() { + int8_t item; ///< to store the popped value to be returned + if(st.top == -1) { // underflow condition + printf("Stack underflow..."); + exit(1); + } + item = st.stack[st.top]; + st.top--; + return item; +} + +/** + * @brief Function to evaluate postfix expression + * @param post the input postfix expression + * @returns evaluated answer + */ +int8_t evaluate(char post[]) { + int8_t it1; + int8_t it2; + int8_t temp; + int8_t number; + int i; + for(i = 0; i < strlen(post); i++) { + if(post[i] == ' ') { + continue; // ignore delimiter + } + else if(isdigit(post[i])) { + number = 0; + do { + number = number * 10 + (post[i]-'0'); + i++; + } while(i < strlen(post) && isdigit(post[i])); + push(number); + } + else { + it2 = pop(); + it1 = pop(); + switch(post[i]) { + case '+': + temp = it1 + it2; break; + case '-': + temp = it1 - it2; break; + case '*': + temp = it1 * it2; break; + case '/': + temp = it1 / it2; break; + case '%': + temp = it1 % it2; break; + default: + printf("Invalid operator"); exit(1); + } + push(temp); + } + } + return pop(); +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + /* check sample test case + input: "2 10 + 9 6 - /" + expected output: 4 + */ + char temp1[50] = "2 10 + 9 6 - /"; + assert(evaluate(temp1) == 4); /// this ensures that the algorithm works as expected + /* input: "4 2 + 3 5 1 - * +" + expected output: 18 + */ + char temp2[50] = "4 2 + 3 5 1 - * +"; + assert(evaluate(temp2) == 18); /// this ensures that the algorithm works as expected + printf("All tests have successfully passed!\n"); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + st.top = -1; /// initialize + test(); /// run self-test implementations + return 0; +} diff --git a/misc/quartile.c b/misc/quartile.c new file mode 100644 index 0000000000..d3b2d47721 --- /dev/null +++ b/misc/quartile.c @@ -0,0 +1,47 @@ +#include +#include +#include + +int main() +{ + int a[10], n, i, j, temp; + float q1, q3, iqr; + + printf("Enter no. for Random Numbers :"); + scanf("%d", &n); + for (i = 0; i < n; i++) + { + a[i] = rand() % 100; + } + printf("Random Numbers Generated are :\n"); + for (i = 0; i < n; i++) + { + printf("\n%d", a[i]); + } + printf("\n"); + printf("\nSorted Data:"); + for (i = 0; i < n; i++) + { + for (j = 0; j < n; j++) + { + if (a[i] < a[j]) + { + temp = a[i]; + a[i] = a[j]; + a[j] = temp; + } + } + } + for (i = 0; i < n; i++) + { + printf("\n%d", a[i]); + } + q1 = a[n / 4]; + printf("\nFirst Quartile : %f", q1); + q3 = a[(3 * n) / 4]; + printf("\nThird Quartile : %f", q3); + iqr = q3 - q1; + printf("\nInterQuartile Range is : %f", iqr); + + return 0; +} \ No newline at end of file diff --git a/misc/rselect.c b/misc/rselect.c index 9679bf00af..af9be9421d 100644 --- a/misc/rselect.c +++ b/misc/rselect.c @@ -1,54 +1,77 @@ #include -#include -#include -void swap(int *a ,int *b) -{int t;t =*a;*a=*b;*b=t;} -int part(int a[],int l,int r,int n,int pivot,int pindex) -{int p1=l,p2=r; - while(p2>p1) +#include +#include +void swap(int *a, int *b) +{ + int t; + t = *a; + *a = *b; + *b = t; +} +int part(int a[], int l, int r, int n, int pivot, int pindex) +{ + int p1 = l, p2 = r; + while (p2 > p1) { - if (a[p1] > pivot && a[p2] pivot && a[p2] < pivot) + { + swap(&a[p1], &a[p2]); + } else { - if (a[p1] <=pivot) - {p1++;} - if (a[p2]>=pivot) - {p2--;} + if (a[p1] <= pivot) + { + p1++; + } + if (a[p2] >= pivot) + { + p2--; + } } } - swap(&a[pindex],&a[p2]); + swap(&a[pindex], &a[p2]); return p2; } -int rselect(int a[],int l,int r,int n,int o) +int rselect(int a[], int l, int r, int n, int o) { - int pivot,pindex,pactual; - if (r>l) + int pivot, pindex, pactual; + if (r > l) + { + pindex = rand() % (r - l + 1); + pivot = a[pindex]; + pactual = part(a, l, r, n, pivot, pindex); + + if (pactual == o) + { + return a[pactual]; + } + + if (o < pactual) + { + rselect(a, l, pactual - 1, n, o); + } + + if (o > pactual) + { + rselect(a, pactual + 1, r, n, o - pactual); + } + } + if (r == l) { - pindex = rand()%(r-l+1); - pivot = a[pindex]; - pactual = part(a,l,r,n,pivot,pindex); - - if (pactual == o) - {return a[pactual];} - - if (o < pactual) - {rselect(a,l,pactual-1,n,o);} - - if (o>pactual) - {rselect(a,pactual+1,r,n,o-pactual);} + return a[l]; } - if (r==l) - {return a[l];} + return -1; } int main() -{srand(time(NULL)); - int n,o,i,*a; - scanf("%d %d",&n,&o); - a = (int*)malloc(n*sizeof(int)); - for (i=0;i /// for IO operations +#include /// for string functions +#include /// for malloc/free +#include /// for assert + +/** + * @brief Encodes a null-terminated string using run-length encoding + * @param str String to encode + * @return char* Encoded string + */ + +char* run_length_encode(char* str) { + int str_length = strlen(str); + int encoded_index = 0; + + //allocate space for worst-case scenario + char* encoded = malloc(2 * strlen(str)); + + //temp space for int to str conversion + char int_str[20]; + + for(int i = 0; i < str_length; ++i) { + int count = 0; + char current = str[i]; + + //count occurences + while(current == str[i + count]) count++; + + i += count - 1; + + //convert occurrence amount to string and write to encoded string + sprintf(int_str, "%d", count); + int int_str_length = strlen(int_str); + strncpy(&encoded[encoded_index], int_str, strlen(int_str)); + + //write current char to encoded string + encoded_index += strlen(int_str); + encoded[encoded_index] = current; + ++encoded_index; + } + + //null terminate string and move encoded string to compacted memory space + encoded[encoded_index] = '\0'; + char* compacted_string = malloc(strlen(encoded) + 1); + strcpy(compacted_string, encoded); + + free(encoded); + + return compacted_string; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + char* test; + test = run_length_encode("aaaaaaabbbaaccccdefaadr"); + assert(!strcmp(test, "7a3b2a4c1d1e1f2a1d1r")); + free(test); + test = run_length_encode("lidjhvipdurevbeirbgipeahapoeuhwaipefupwieofb"); + assert(!strcmp(test, "1l1i1d1j1h1v1i1p1d1u1r1e1v1b1e1i1r1b1g1i1p1e1a1h1a1p1o1e1u1h1w1a1i1p1e1f1u1p1w1i1e1o1f1bq")); + free(test); + test = run_length_encode("htuuuurwuquququuuaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaahghghrw"); + assert(!strcmp(test, "1h1t4u1r1w1u1q1u1q1u1q3u76a1h1g1h1g1h1r1w")); + free(test); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + printf("All tests have passed!\n"); + return 0; +} diff --git a/misc/shunting_yard.c b/misc/shunting_yard.c new file mode 100644 index 0000000000..7cf7bc44b2 --- /dev/null +++ b/misc/shunting_yard.c @@ -0,0 +1,238 @@ +/** + * @file + * @brief [Shunting Yard Algorithm](https://en.wikipedia.org/wiki/Shunting_yard_algorithm) + * @details From Wikipedia: In computer science, + * the shunting yard algorithm is a method for parsing arithmetical or logical expressions, or a combination of both, specified in infix notation. + * It can produce either a postfix notation string, also known as Reverse Polish notation (RPN), or an abstract syntax tree (AST). + * The algorithm was invented by Edsger Dijkstra and named the "shunting yard" algorithm because its operation resembles that of a railroad shunting yard. + * @author [CascadingCascade](https://github.com/CascadingCascade) + */ + +#include /// for assertion +#include /// for IO operations +#include /// for memory management +#include /// for string operations +#include /// for isdigit() + +/** + * @brief Helper function that returns each operator's precedence + * @param operator the operator to be queried + * @returns the operator's precedence + */ +int getPrecedence(char operator) { + switch (operator) { + case '+': + case '-': { + return 1; + } + case '*': + case '/': { + return 2; + } + case '^': { + return 3; + } + default:{ + fprintf(stderr,"Error: Invalid operator\n"); + return -1; + } + } +} + +/** + * @brief Helper function that returns each operator's associativity + * @param operator the operator to be queried + * @returns '1' if the operator is left associative + * @returns '0' if the operator is right associative + */ +int getAssociativity(char operator) { + switch (operator) { + case '^': { + return 0; + } + case '+': + case '-': + case '*': + case '/': { + return 1; + } + default: { + fprintf(stderr,"Error: Invalid operator\n"); + return -1; + } + } +} + +/** + * @brief An implementation of the shunting yard that converts infix notation to reversed polish notation + * @param input pointer to input string + * @param output pointer to output location + * @returns `1` if a parentheses mismatch is detected + * @returns `0` if no mismatches are detected + */ +int shuntingYard(const char *input, char *output) { + const unsigned int inputLength = strlen(input); + char* operatorStack = (char*) malloc(sizeof(char) * inputLength); + + // This pointer points at where we should insert the next element, + // Hence stackPointer - 1 is used when accessing elements + unsigned int stackPointer = 0; + + // We will parse the input with strtok(), + // Since strtok() is destructive, we make a copy of the input to preserve the original string + char* str = malloc(sizeof(char) * inputLength + 1); + strcpy(str,input); + char* token = strtok(str," "); + + // We will push to output with strcat() and strncat(), + // This initializes output to be a string with a length of zero + output[0] = '\0'; + + while (token != NULL) { + // If it's a number, push it to the output directly + if (isdigit(token[0])) { + strcat(output,token); + strcat(output," "); + + token = strtok(NULL," "); + continue; + } + + switch (token[0]) { + // If it's a left parenthesis, push it to the operator stack for later matching + case '(': { + operatorStack[stackPointer++] = token[0]; + break; + } + + // If it's a right parenthesis, search for a left parenthesis to match it + case ')': { + // Guard statement against accessing an empty stack + if(stackPointer < 1) { + fprintf(stderr,"Error: Mismatched parentheses\n"); + free(operatorStack); + free(str); + return 1; + } + + while (operatorStack[stackPointer - 1] != '(') { + // strncat() with a count of 1 is used to append characters to output + const unsigned int i = (stackPointer--) - 1; + strncat(output, &operatorStack[i], 1); + strcat(output," "); + + // If the operator stack is exhausted before a match can be found, + // There must be a mismatch + if(stackPointer == 0) { + fprintf(stderr,"Error: Mismatched parentheses\n"); + free(operatorStack); + free(str); + return 1; + } + } + + // Discards the parentheses now the matching is complete, + // Simply remove the left parenthesis from the stack is enough, + // Since the right parenthesis didn't enter the stack in the first place + stackPointer--; + break; + } + + // If it's an operator(o1), we compare it to whatever is at the top of the operator stack(o2) + default: { + // Places the operator into the stack directly if it's empty + if(stackPointer < 1) { + operatorStack[stackPointer++] = token[0]; + break; + } + + // We need to check if there's actually a valid operator at the top of the stack + if((stackPointer - 1 > 0) && operatorStack[stackPointer - 1] != '(') { + const int precedence1 = getPrecedence(token[0]); + const int precedence2 = getPrecedence(operatorStack[stackPointer - 1]); + const int associativity = getAssociativity(token[0]); + + // We pop operators from the stack, if... + while ( // ... their precedences are equal, and o1 is left associative, ... + ((associativity && precedence1 == precedence2) || + // ... or o2 simply have a higher precedence, ... + precedence2 > precedence1) && + // ... and there are still operators available to be popped. + ((stackPointer - 1 > 0) && operatorStack[stackPointer - 1] != '(')) { + + strncat(output,&operatorStack[(stackPointer--) - 1],1); + strcat(output," "); + } + } + + // We'll save o1 for later + operatorStack[stackPointer++] = token[0]; + break; + } + } + + token = strtok(NULL," "); + } + + free(str); + + // Now all input has been exhausted, + // Pop everything from the operator stack, then push them to the output + while (stackPointer > 0) { + // If there are still leftover left parentheses in the stack, + // There must be a mismatch + if(operatorStack[stackPointer - 1] == '(') { + fprintf(stderr,"Error: Mismatched parentheses\n"); + free(operatorStack); + return 1; + } + + const unsigned int i = (stackPointer--) - 1; + strncat(output, &operatorStack[i], 1); + if (i != 0) { + strcat(output," "); + } + } + + free(operatorStack); + return 0; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + char* in = malloc(sizeof(char) * 50); + char* out = malloc(sizeof(char) * 50); + int i; + + strcpy(in,"3 + 4 * ( 2 - 1 )"); + printf("Infix: %s\n",in); + i = shuntingYard(in, out); + printf("RPN: %s\n",out); + printf("Return code: %d\n\n",i); + assert(strcmp(out,"3 4 2 1 - * +") == 0); + assert(i == 0); + + strcpy(in,"3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3"); + printf("Infix: %s\n",in); + i = shuntingYard(in, out); + printf("RPN: %s\n",out); + printf("Return code: %d\n\n",i); + assert(strcmp(out,"3 4 2 * 1 5 - 2 3 ^ ^ / +") == 0); + assert(i == 0); + + printf("Testing successfully completed!\n"); + free(in); + free(out); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // Run self-test implementations + return 0; +} diff --git a/misc/strongNumber.c b/misc/strongNumber.c deleted file mode 100644 index 9b5d352776..0000000000 --- a/misc/strongNumber.c +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Modified on 07/12/2017, Kyler Smith - * - * A number is called strong number if sum of the - * factorial of its digit is equal to number itself. - */ - -#include - - -void strng(int a) -{ - int j=a; - int sum=0; - int b,i,fact=1; - while(a>0) - { - fact=1; - b=a%10; - for(i=1;i<=b;i++) - { - fact=fact*i; - } - a=a/10; - sum=sum+fact; - } - if(sum==j) - printf("%d is a strong number",j); - else - printf("%d is not a strong number",j); -} -void main() -{ - int a; - printf("Enter the number to check"); - scanf("%d",&a); - strng(a); -} diff --git a/misc/sudoku_solver.c b/misc/sudoku_solver.c new file mode 100644 index 0000000000..ddde4a5ff8 --- /dev/null +++ b/misc/sudoku_solver.c @@ -0,0 +1,270 @@ +/** + * @file + * @brief Sudoku Solver using recursive implementation of brute-force algorithm + * + * @details + * Given an incomplete N*N Sudoku and asked to solve it using the + * following recursive algorithm: + * 1. Scan the Sudoku from left to right row-wise to search for an empty cell. + * 2. If there are no empty cells, print the Sudoku. Go to step 5. + * 3. In the empty cell, try putting numbers 1 to N + * while ensuring that no two numbers in a single row, column, or box are same. + * Go back to step 1. + * 4. Declare that the Sudoku is Invalid. + * 5. Exit. + * + * @authors [Anuj Shah](https://github.com/anujms1999) + * @authors [Krishna Vedala](https://github.com/kvedala) + */ +#include +#include +#include +#include +#include +#include +#include + +/** @addtogroup sudoku Sudoku solver + * @{ + */ +/** Structure to hold the matrix and dimensions + */ +struct sudoku +{ + uint8_t *a; /**< matrix as a flattened 1D row-major array */ + uint8_t N; /**< number of elements */ + uint8_t N2; /**< block of elements */ +}; + +/** + * Check if `x`^th row is valid + * @param a ::sudoku to check + * @param x row to check + * @param y ignored column + * @param v value to check if it repeats + * @returns `true` if valid + * @returns `false` if in-valid + */ +bool OKrow(const struct sudoku *a, int x, int y, int v) +{ + int offset = x * a->N; + for (int j = 0; j < a->N; j++) + if (a->a[offset + j] == v) + // if the value is found in the row + return false; + return true; +} + +/** + * Check if `y`^th column is valid + * @param a ::sudoku to check + * @param x ignored row + * @param y column to check + * @param v value to check if it repeats + * @returns `true` if valid + * @returns `false` if in-valid + */ +bool OKcol(const struct sudoku *a, int x, int y, int v) +{ + for (int i = 0; i < a->N; i++) + if (a->a[i * a->N + y] == v) + // if the value is found in the column + return false; + return true; +} + +/** + * Check if a 3x3 box is valid + * @param a matrix to check + * @param x row index of the element to check + * @param y column index of the element to check + * @param v value to check if it repeats + * @returns `true` if valid + * @returns `false` if in-valid + */ +bool OKbox(const struct sudoku *a, int x, int y, int v) +{ + /* get start indices of the box that the current (x,y) lies in + remember that in C/C++, division operation always rounds towards + -infinity for signed integers and towards 0 for unsigned integers + */ + int bi = x - x % a->N2, bj = y - y % a->N2; + // printf("Checking box: (%d,%d)\n", bi, bj); + + for (int i = bi; i < (bi + a->N2); i++) + for (int j = bj; j < (bj + a->N2); j++) + if (a->a[i * a->N + j] == v) + // if the value is found in the box + return false; + return true; +} + +/** + * Check if element `v` is valid to place at (x,y) location. + * @param a ::sudoku to check + * @param x row to place value + * @param y column to place value + * @param v value to check if it is valid + * @returns `true` if valid + * @returns `false` if in-valid + */ +bool OK(const struct sudoku *a, int x, int y, int v) +{ + bool result = OKrow(a, x, y, v); + if (result) + result = OKcol(a, x, y, v); + if (result) + result = OKbox(a, x, y, v); + + return result; +} + +/** + * Print the matrix to stdout + * @param [in] a array to print + */ +void print(const struct sudoku *a) +{ + int i, j; + for (i = 0; i < a->N; i++) + for (j = 0; j < a->N; j++) + printf("%" SCNu8 "%c", a->a[i * a->N + j], + (j == a->N - 1 ? '\n' : ' ')); +} + +/** + * @brief Find and get the location for next empty cell. + * + * @param [in] a pointer to sudoku instance + * @param [out] x pointer to row index of next unknown + * @param [out] y pointer to column index of next unknown + * @returns `true` if an empty location was found + * @returns `false` if no more empty locations found + */ +bool get_next_unknown(const struct sudoku *a, int *x, int *y) +{ + for (int i = 0; i < a->N; i++) + { + for (int j = 0; j < a->N; j++) + { + if (a->a[i * a->N + j] == 0) + { + *x = i; + *y = j; + return true; + } + } + } + + /* no unknown locations found */ + return false; +} + +/** + * @brief Function to solve a partially filled sudoku matrix. For each unknown + * value (0), the function fills a possible value and calls the function again + * to check forvalid solution. + * + * @param [in,out] a sudoku matrix to solve + * @return `true` if solution found + * @return `false` if no solution found + */ +bool solve(struct sudoku *a) +{ + static uint32_t counter = 0; + int i, j; + static char prefix[100] = ""; // enough memory + + if (!get_next_unknown(a, &i, &j)) + { + /* no more empty location found + implies all good in the matrix + */ + return true; + } + + /* try all possible values for the unknown */ + for (uint8_t v = 1; v <= a->N; v++) + { /* try all possible values 1 thru N */ + printf("%sTry (%d,%d) = %" SCNu8 "... ", prefix, i, j, v); + counter++; + if (OK(a, i, j, v)) + { + /* if assignment checks satisfy, set the value and + continue with remaining elements */ + printf("passed (counter=%" SCNu32 ")\n", counter); + a->a[i * a->N + j] = v; + strcat(prefix, " "); + if (solve(a)) + { + /* solution found */ + return true; + } + + printf("%sBacktrack (%d,%d) <- %" SCNu8 " (counter=%" SCNu32 ")\n", + prefix, i, j, a->a[i * a->N + j], counter); + + prefix[strlen(prefix) - 2] = '\0'; // truncate the prefix + a->a[i * a->N + j] = 0; + } + else + { + printf("\r"); + } + } + + return false; +} + +/** @} */ + +void test() +{ + printf("Test begin...\n"); + + uint8_t test_array[] = {3, 0, 6, 5, 0, 8, 4, 0, 0, 5, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 8, 7, 0, 0, 0, 0, 3, 1, 0, 0, 3, 0, 1, 0, 0, + 8, 0, 9, 0, 0, 8, 6, 3, 0, 0, 5, 0, 5, 0, 0, 9, 0, + 6, 0, 0, 1, 3, 0, 0, 0, 0, 2, 5, 0, 0, 0, 0, 0, 0, + 0, 0, 7, 4, 0, 0, 5, 2, 0, 6, 3, 0, 0}; + struct sudoku a = {.N = 9, .N2 = 3, .a = test_array}; + assert(solve(&a)); // ensure that solution is obtained + + uint8_t expected[] = {3, 1, 6, 5, 7, 8, 4, 9, 2, 5, 2, 9, 1, 3, 4, 7, 6, + 8, 4, 8, 7, 6, 2, 9, 5, 3, 1, 2, 6, 3, 4, 1, 5, 9, + 8, 7, 9, 7, 4, 8, 6, 3, 1, 2, 5, 8, 5, 1, 7, 9, 2, + 6, 4, 3, 1, 3, 8, 9, 4, 7, 2, 5, 6, 6, 9, 2, 3, 5, + 1, 8, 7, 4, 7, 4, 5, 2, 8, 6, 3, 1, 9}; + for (int i = 0; i < a.N; i++) + for (int j = 0; j < a.N; j++) + assert(a.a[i * a.N + j] == expected[i * a.N + j]); + + printf("Test passed\n"); +} + +/** \brief Main function */ +int main() +{ + test(); + + struct sudoku a; // store the matrix as a 1D array + scanf("%" SCNu8, &(a.N)); + a.a = (uint8_t *)malloc(a.N * a.N * sizeof(uint8_t)); + a.N2 = (uint8_t)sqrt(a.N); + + for (int i = 0; i < a.N; i++) + for (int j = 0; j < a.N; j++) scanf("%" SCNu8, &(a.a[i * a.N + j])); + + printf("Entered a %udx%ud matrix with block size: %" SCNu8 "\n", a.N, a.N, + a.N2); + // print(&a); + printf("\n\n"); + if (solve(&a)) + printf("Valid solution found!\n"); + else + printf("Invalid\n"); + print(&a); + + free(a.a); + return 0; +} diff --git a/misc/sudokusolver.c b/misc/sudokusolver.c deleted file mode 100644 index 30dc4ad961..0000000000 --- a/misc/sudokusolver.c +++ /dev/null @@ -1,77 +0,0 @@ -//recursion problem : Sudoku Solver -/*You are given an incomplete N*N Sudoku and asked to solve it using the following recursive algorithm: -(1) Scan the Sudoku from left to right row-wise to search for an empty cell. -(2) If there are no empty cells, print the Sudoku. Go to step 5. -(3) In the empty cell, try putting numbers 1 to N while ensuring that no two numbers in a single row, column, or box are same. Go back to step 1. -(4) Declare that the Sudoku is Invalid. -(5) Exit.*/ - -#include - -const int M=144; -int N, R, C; - -int OKrow(int a[M], int x, int y, int v) { - int j; - for(j=0; j +#include + +// Function for Tower of Hanoi algorithm +void hanoi(int noOfDisks, char where, char to, char extra) +{ + if (noOfDisks != 0) + { + hanoi(noOfDisks - 1, where, extra, to); + printf("Move disk : %d from %c to %c\n", noOfDisks, where, to); + hanoi(noOfDisks - 1, extra, to, where); + } +} +int main(void) +{ + int noOfDisks; + + // Asks the number of disks in the tower + printf("Number of disks: \n"); + scanf("%d", &noOfDisks); + + hanoi(noOfDisks, 'A', 'B', 'C'); + + return 0; +} diff --git a/misc/union_find.c b/misc/union_find.c new file mode 100644 index 0000000000..a2bf3f2751 --- /dev/null +++ b/misc/union_find.c @@ -0,0 +1,89 @@ +/** + * @file union_find.c + * @brief [Union + * find](https://en.wikipedia.org/wiki/Disjoint-set_data_structure) algorithm. + */ +#include +#include +#define MAX_SIZE 1000 /**< maximum number of elements in the set */ + +/** + * @brief Find index of or value in an array + * + * @param [in,out] p array to search and update + * @param x value to search + * @return value at the index `x` + */ +int find(int *p, int x) +{ + if (x >= MAX_SIZE) + { + fprintf(stderr, "Out-of bounds value\n"); + exit(EXIT_FAILURE); + } + + if (p[x] == x) + { + return x; + } + else + { + p[x] = find(p, p[x]); + return p[x]; + } +} + +/** + * @brief Function to join + * @param [in,out] p array to join in + * @param x value or index to join to + * @param y value or index to join from + */ +void join(int *p, int x, int y) { p[find(p, x)] = find(p, y); } + +/** Main function */ +int main() +{ + int union_set[MAX_SIZE]; + + // Have all array indexes that you need to use reference themselves + for (int i = 0; i < 10; i++) + { + union_set[i] = i; + } + // p = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} + + join(union_set, 3, 5); + printf("The array is now: "); + for (int i = 0; i < 10; i++) + { + printf("%d ", union_set[i]); + } + printf("\n"); + // Now 3 and 5 are groupped together, that is find(3) = find(5) + // p = {0, 1, 2, 5, 4, 5, 6, 7, 8, 9} + + join(union_set, 3, 8); + printf("The array is now: "); + for (int i = 0; i < 10; i++) + { + printf("%d ", union_set[i]); + } + printf("\n"); + + // Now 3, 5 and are groupped together, find(3) = find(5) = find(8) + // p = {0, 1, 2, 5, 4, 8, 6, 7, 8, 9} + join(union_set, 0, 5); + if (find(union_set, 0) == find(union_set, 3)) + { + printf("0 and 3 are groupped together\n"); + } + printf("The array is now: "); + for (int i = 0; i < 10; i++) + { + printf("%d ", union_set[i]); + } + printf("\n"); + + return 0; +} diff --git a/numerical_methods/CMakeLists.txt b/numerical_methods/CMakeLists.txt new file mode 100644 index 0000000000..5bfaafd116 --- /dev/null +++ b/numerical_methods/CMakeLists.txt @@ -0,0 +1,34 @@ +# 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} *.c ) +# file( GLOB APP_SOURCES ${CMAKE_SOURCE_DIR}/*.c ) +# AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} APP_SOURCES) + +# List of files that use complex.h and complex data type +set (NEED_COMPLEX + "newton_raphson_root.c" + "durand_kerner_roots.c" +) + +foreach( testsourcefile ${APP_SOURCES} ) + # compile files that use complex.h only if available + if ( ${testsourcefile} IN_LIST NEED_COMPLEX AND NOT HAS_COMPLEX_TYPE) + continue() + endif() + string( REPLACE ".c" "" testname ${testsourcefile} ) + string( REPLACE ".C" "" testname ${testname} ) + string( REPLACE " " "_" testname ${testname} ) + + add_executable( ${testname} ${testsourcefile} ) + + if(OpenMP_C_FOUND) + target_link_libraries(${testname} OpenMP::OpenMP_C) + endif() + + if(MATH_LIBRARY) + target_link_libraries(${testname} ${MATH_LIBRARY}) + endif() + install(TARGETS ${testname} DESTINATION "bin/numerical_methods") + +endforeach( testsourcefile ${APP_SOURCES} ) diff --git a/numerical_methods/bisection_method.c b/numerical_methods/bisection_method.c new file mode 100644 index 0000000000..ce790f441f --- /dev/null +++ b/numerical_methods/bisection_method.c @@ -0,0 +1,111 @@ +/** + * @file + * @brief In mathematics, the [Bisection + * Method](https://en.wikipedia.org/wiki/Bisection_method) is a root-finding + * method that applies to any continuous function for which one knows two values + * with opposite signs. + * @details + * The method consists of repeatedly bisecting the interval + * defined by the two values and then selecting the subinterval in which the + * function changes sign, and therefore must contain a root. It is a very + * simple and robust method, but it is also relatively slow. Because of this, + * it is often used to obtain a rough approximation to a solution which is + * then used as a starting point for more rapidly converging methods. + * @author [Aybars Nazlica](https://github.com/aybarsnazlica) + */ + +#include /// for assert +#include /// for fabs +#include /// for IO operations + +#define EPSILON 0.0001 // a small positive infinitesimal quantity +#define NMAX 50 // maximum number of iterations + +/** + * @brief Function to check if two input values have the same sign (the property + * of being positive or negative) + * @param a Input value + * @param b Input value + * @returns 1.0 if the input values have the same sign, + * @returns -1.0 if the input values have different signs + */ +double sign(double a, double b) +{ + return (a > 0 && b > 0) + (a < 0 && b < 0) - (a > 0 && b < 0) - + (a < 0 && b > 0); +} + +/** + * @brief Continuous function for which we want to find the root + * @param x Real input variable + * @returns The evaluation result of the function using the input value + */ +double func(double x) +{ + return x * x * x + 2.0 * x - 10.0; // f(x) = x**3 + 2x - 10 +} + +/** + * @brief Root-finding method for a continuous function given two values with + * opposite signs + * @param x_left Lower endpoint value of the interval + * @param x_right Upper endpoint value of the interval + * @param tolerance Error threshold + * @returns `root of the function` if bisection method succeed within the + * maximum number of iterations + * @returns `-1` if bisection method fails + */ +double bisection(double x_left, double x_right, double tolerance) +{ + int n = 1; // step counter + double middle; // midpoint + + while (n <= NMAX) + { + middle = (x_left + x_right) / 2; // bisect the interval + double error = middle - x_left; + + if (fabs(func(middle)) < EPSILON || error < tolerance) + { + return middle; + } + + if (sign(func(middle), func(x_left)) > 0.0) + { + x_left = middle; // new lower endpoint + } + else + { + x_right = middle; // new upper endpoint + } + + n++; // increase step counter + } + return -1; // method failed (maximum number of steps exceeded) +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() +{ + /* Compares root value that is found by the bisection method within a given + * floating point error*/ + assert(fabs(bisection(1.0, 2.0, 0.0001) - 1.847473) < + EPSILON); // the algorithm works as expected + assert(fabs(bisection(100.0, 250.0, 0.0001) - 249.999928) < + EPSILON); // the algorithm works as expected + + printf("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/numerical_methods/durand_kerner_roots.c b/numerical_methods/durand_kerner_roots.c new file mode 100644 index 0000000000..0042e21df0 --- /dev/null +++ b/numerical_methods/durand_kerner_roots.c @@ -0,0 +1,252 @@ +/** + * @file + * \brief Compute all possible approximate roots of any given polynomial using + * [Durand Kerner + * algorithm](https://en.wikipedia.org/wiki/Durand%E2%80%93Kerner_method) + * + * \author [Krishna Vedala](https://github.com/kvedala) + * + * Test the algorithm online: + * https://gist.github.com/kvedala/27f1b0b6502af935f6917673ec43bcd7 + * + * Try the highly unstable Wilkinson's polynomial: + * ``` + * ./numerical_methods/durand_kerner_roots.c 1 -210 20615 -1256850 53327946 + * -1672280820 40171771630 -756111184500 11310276995381 -135585182899530 + * 1307535010540395 -10142299865511450 63030812099294896 -311333643161390640 + * 1206647803780373360 -3599979517947607200 8037811822645051776 + * -12870931245150988800 13803759753640704000 -8752948036761600000 + * 2432902008176640000 + * ``` + * Sample implementation results to compute approximate roots of the equation + * \f$x^4-1=0\f$:\n + * Error evolution during root approximations computed every
+ * iteration. Roots evolution - shows the initial approximation of the
+ * roots and their convergence to a final approximation along with the iterative
+ * approximations + */ + +#include +#include +#include +#include +#include +#include +#include + +#define ACCURACY 1e-10 /**< maximum accuracy limit */ + +/** + * Evaluate the value of a polynomial with given coefficients + * \param[in] coeffs coefficients of the polynomial + * \param[in] degree degree of polynomial + * \param[in] x point at which to evaluate the polynomial + * \returns \f$f(x)\f$ + */ +long double complex poly_function(long double *coeffs, unsigned int degree, + long double complex x) +{ + long double complex out = 0.; + unsigned int n; + + for (n = 0; n < degree; n++) out += coeffs[n] * cpow(x, degree - n - 1); + + return out; +} + +/** + * create a textual form of complex number + * \param[in] x point at which to evaluate the polynomial + * \returns pointer to converted string + */ +const char *complex_str(long double complex x) +{ + static char msg[50]; + double r = creal(x); + double c = cimag(x); + + sprintf(msg, "% 7.04g%+7.04gj", r, c); + + return msg; +} + +/** + * check for termination condition + * \param[in] delta point at which to evaluate the polynomial + * \returns 0 if termination not reached + * \returns 1 if termination reached + */ +char check_termination(long double delta) +{ + static long double past_delta = INFINITY; + if (fabsl(past_delta - delta) <= ACCURACY || delta < ACCURACY) + return 1; + past_delta = delta; + return 0; +} + +/*** + * the comandline inputs are taken as coeffiecients of a polynomial + */ +int main(int argc, char **argv) +{ + long double *coeffs = NULL; + long double complex *s0 = NULL; + unsigned int degree = 0; + unsigned int n, i; + + if (argc < 2) + { + printf( + "Please pass the coefficients of the polynomial as commandline " + "arguments.\n"); + return 0; + } + + degree = argc - 1; /* detected polynomial degree */ + coeffs = (long double *)malloc( + degree * sizeof(long double)); /* store all input coefficients */ + s0 = (long double complex *)malloc( + (degree - 1) * + sizeof(long double complex)); /* number of roots = degree-1 */ + + /* initialize random seed: */ + srand(time(NULL)); + + if (!coeffs || !s0) + { + perror("Unable to allocate memory!"); + if (coeffs) + free(coeffs); + if (s0) + free(s0); + return EXIT_FAILURE; + } + +#if defined(DEBUG) || !defined(NDEBUG) + /** + * store intermediate values to a CSV file + */ + FILE *log_file = fopen("durand_kerner.log.csv", "wt"); + if (!log_file) + { + perror("Unable to create a storage log file!"); + free(coeffs); + free(s0); + return EXIT_FAILURE; + } + fprintf(log_file, "iter#,"); +#endif + + printf("Computing the roots for:\n\t"); + for (n = 0; n < degree; n++) + { + coeffs[n] = strtod(argv[n + 1], NULL); + if (n < degree - 1 && coeffs[n] != 0) + printf("(%Lg) x^%d + ", coeffs[n], degree - n - 1); + else if (coeffs[n] != 0) + printf("(%Lg) x^%d = 0\n", coeffs[n], degree - n - 1); + + double tmp; + if (n > 0) + coeffs[n] /= tmp; /* numerical errors less when the first + coefficient is "1" */ + else + { + tmp = coeffs[0]; + coeffs[0] = 1; + } + + /* initialize root approximations with random values */ + if (n < degree - 1) + { + s0[n] = (long double)rand() + (long double)rand() * I; +#if defined(DEBUG) || !defined(NDEBUG) + fprintf(log_file, "root_%d,", n); +#endif + } + } + +#if defined(DEBUG) || !defined(NDEBUG) + fprintf(log_file, "avg. correction"); + fprintf(log_file, "\n0,"); + for (n = 0; n < degree - 1; n++) + fprintf(log_file, "%s,", complex_str(s0[n])); +#endif + + double tol_condition = 1; + unsigned long iter = 0; + + clock_t end_time, start_time = clock(); + while (!check_termination(tol_condition) && iter < INT_MAX) + { + long double complex delta = 0; + tol_condition = 0; + iter++; + +#if defined(DEBUG) || !defined(NDEBUG) + fprintf(log_file, "\n%ld,", iter); +#endif + + for (n = 0; n < degree - 1; n++) + { + long double complex numerator = + poly_function(coeffs, degree, s0[n]); + long double complex denominator = 1.0; + for (i = 0; i < degree - 1; i++) + if (i != n) + denominator *= s0[n] - s0[i]; + + delta = numerator / denominator; + + if (isnan(cabsl(delta)) || isinf(cabsl(delta))) + { + printf("\n\nOverflow/underrun error - got value = %Lg", + cabsl(delta)); + goto end; + } + + s0[n] -= delta; + + tol_condition = fmaxl(tol_condition, fabsl(cabsl(delta))); + +#if defined(DEBUG) || !defined(NDEBUG) + fprintf(log_file, "%s,", complex_str(s0[n])); +#endif + } + // tol_condition /= (degree - 1); + +#if defined(DEBUG) || !defined(NDEBUG) + if (iter % 500 == 0) + { + printf("Iter: %lu\t", iter); + for (n = 0; n < degree - 1; n++) printf("\t%s", complex_str(s0[n])); + printf("\t\tabsolute average change: %.4g\n", tol_condition); + } + + fprintf(log_file, "%.4g", tol_condition); +#endif + } +end: + + end_time = clock(); + +#if defined(DEBUG) || !defined(NDEBUG) + fclose(log_file); +#endif + + printf("\nIterations: %lu\n", iter); + for (n = 0; n < degree - 1; n++) printf("\t%s\n", complex_str(s0[n])); + printf("absolute average change: %.4g\n", tol_condition); + printf("Time taken: %.4g sec\n", + (end_time - start_time) / (double)CLOCKS_PER_SEC); + + free(coeffs); + free(s0); + + return 0; +} diff --git a/numerical_methods/gauss_elimination.c b/numerical_methods/gauss_elimination.c new file mode 100644 index 0000000000..18405ce69e --- /dev/null +++ b/numerical_methods/gauss_elimination.c @@ -0,0 +1,104 @@ +#include +#include + +#define ARRAY_SIZE 20 + +void display(float a[ARRAY_SIZE][ARRAY_SIZE], int n) +{ + int i, j; + for (i = 0; i < n; i++) + { + for (j = 0; j <= n; j++) + { + printf("%.2f \t", a[i][j]); + } + printf("\n"); + } +} + +float interchange(float m[ARRAY_SIZE][ARRAY_SIZE], int i, int n) +{ + float tmp[ARRAY_SIZE][ARRAY_SIZE]; + float max = fabs(m[i][i]); + int j, k = i; + + for (j = i; j < n; j++) + { + if (max < fabs(m[j][i])) + { + max = fabs(m[j][i]); + k = j; + } + } + for (j = 0; j <= n; j++) + { + tmp[i][j] = m[i][j]; + m[i][j] = m[k][j]; + m[k][j] = tmp[i][j]; + } + return m[ARRAY_SIZE - 1][ARRAY_SIZE - 1]; +} +float eliminate(float m[ARRAY_SIZE][ARRAY_SIZE], int i, int n) +{ + float tmp; + int k = 1, l, j; + for (j = i; j < n - 1; j++) + { + tmp = -((m[i + k][i]) / (m[i][i])); + for (l = 0; l <= n; l++) + { + m[i + k][l] = (m[i + k][l]) + (m[i][l] * tmp); + } + k++; + } + return m[ARRAY_SIZE - 1][ARRAY_SIZE - 1]; +} +int main(void) +{ + int i, j, n, k = 0, l; + float m[ARRAY_SIZE][ARRAY_SIZE], mul, tmp[ARRAY_SIZE][ARRAY_SIZE], val, + ans[ARRAY_SIZE]; + + printf("Total No.of Equations : "); + scanf("%d", &n); + + printf("\n"); + for (i = 0; i < n; i++) + { + printf("Enter Co-efficient Of Equations %d & Total --->>>\n", i + 1); + for (j = 0; j <= n; j++) + { + printf("r%d%d : ", i, j); + scanf("%f", &m[i][j]); + } + printf("\n"); + } + printf(":::::::::::: Current Matrix ::::::::::::\n\n"); + display(m, n); + + for (i = 0; i < n - 1; i++) + { + printf("\n------->>>>>>>>>>>>>>>>>>>>>>>>-------- %d\n", i + 1); + m[ARRAY_SIZE - 1][ARRAY_SIZE - 1] = interchange(m, i, n); + display(m, n); + printf("\n_______________________________________\n"); + m[ARRAY_SIZE - 1][ARRAY_SIZE - 1] = eliminate(m, i, n); + display(m, n); + } + printf("\n\n Values are : \n"); + for (i = n - 1; i >= 0; i--) + { + l = n - 1; + mul = 0; + for (j = 0; j < k; j++) + { + mul = mul + m[i][l] * ans[l]; + l--; + } + k++; + ans[i] = (m[i][n] - mul) / m[i][i]; + printf("X%d = %.2f\n", i + 1, ans[i]); + } + + return 0; +} diff --git a/numerical_methods/gauss_seidel_method.c b/numerical_methods/gauss_seidel_method.c new file mode 100644 index 0000000000..a33d512b41 --- /dev/null +++ b/numerical_methods/gauss_seidel_method.c @@ -0,0 +1,28 @@ +#include +#include + +int main() +{ + float a, b, c, a1, a2, a3, b1, b2, b3, c1, c2, c3, d1, d2, d3, x1, x2, x3; + + printf("Enter values of eq1:"); + scanf("%f%f%f%f", &a1, &a2, &a3, &d1); + printf("Enter values of eq2:"); + scanf("%f%f%f%f", &b1, &b2, &b3, &d2); + printf("Enter values of eq3:"); + scanf("%f%f%f%f", &c1, &c2, &c3, &d3); + x1 = x2 = x3 = 0.0; + do + { + a = x1; + b = x2; + c = x3; + x1 = (1 / a1) * (d1 - (a2 * x2) - (a3 * x3)); + x2 = (1 / b2) * (d2 - (b1 * x1) - (b3 * x3)); + x3 = (1 / c3) * (d3 - (c1 * x1) - (c2 * x2)); + } while (fabs(x1 - a) > 0.0001 && fabs(x2 - b) > 0.0001 && + fabs(x3 - c) > 0.0001); + printf("x1=%f\nx2=%f\nx3=%f", x1, x2, x3); + + return 0; +} \ No newline at end of file diff --git a/numerical_methods/lagrange_theorem.c b/numerical_methods/lagrange_theorem.c new file mode 100644 index 0000000000..6ad4530d44 --- /dev/null +++ b/numerical_methods/lagrange_theorem.c @@ -0,0 +1,45 @@ +#include +#include +#include + +int main() +{ + float x[20], y[20], a, sum, p; + int n, i, j; + + printf("Enter the no of entry to insert->"); + scanf("%d", &n); + + for (i = 0; i < n; i++) + { + printf("enter the value of x%d->", i); + scanf("%f", &x[i]); + printf("enter the value of y%d->", i); + scanf("%f", &y[i]); + } + printf("\n X \t\t Y \n"); + printf("----------------------------\n"); + for (i = 0; i < n; i++) + { + printf("%f\t", x[i]); + printf("%f\n", y[i]); + } + printf("\nenter the value of x for interpolation:"); + scanf("%f", &a); + sum = 0; + for (i = 0; i < n; i++) + { + p = 1.0; + for (j = 0; j < n; j++) + { + if (i != j) + { + p = p * (a - x[j]) / (x[i] - x[j]); + } + sum = sum + y[i] * p; + } + printf("ans is->%f", sum); + + return 0; + } +} \ No newline at end of file diff --git a/numerical_methods/lu_decompose.c b/numerical_methods/lu_decompose.c new file mode 100644 index 0000000000..22dd8f472d --- /dev/null +++ b/numerical_methods/lu_decompose.c @@ -0,0 +1,126 @@ +/** + * \file + * \brief [LU decomposition](https://en.wikipedia.org/wiki/LU_decompositon) of a + * square matrix + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include +#include +#include +#ifdef _OPENMP +#include +#endif + +/** Perform LU decomposition on matrix + * \param[in] A matrix to decompose + * \param[out] L output L matrix + * \param[out] U output U matrix + * \param[in] mat_size input square matrix size + */ +int lu_decomposition(double **A, double **L, double **U, int mat_size) +{ + int row, col, j; + + // regularize each row + for (row = 0; row < mat_size; row++) + { + // Upper triangular matrix +#ifdef _OPENMP +#pragma omp for +#endif + for (col = row; col < mat_size; col++) + { + // Summation of L[i,j] * U[j,k] + double lu_sum = 0.; + for (j = 0; j < row; j++) lu_sum += L[row][j] * U[j][col]; + + // Evaluate U[i,k] + U[row][col] = A[row][col] - lu_sum; + } + + // Lower triangular matrix +#ifdef _OPENMP +#pragma omp for +#endif + for (col = row; col < mat_size; col++) + { + if (row == col) + { + L[row][col] = 1.; + continue; + } + + // Summation of L[i,j] * U[j,k] + double lu_sum = 0.; + for (j = 0; j < row; j++) lu_sum += L[col][j] * U[j][row]; + + // Evaluate U[i,k] + L[col][row] = (A[col][row] - lu_sum) / U[row][row]; + } + } + + return 0; +} + +/** Function to display square matrix */ +void display(double **A, int N) +{ + for (int i = 0; i < N; i++) + { + for (int j = 0; j < N; j++) + { + printf("% 3.3g \t", A[i][j]); + } + putchar('\n'); + } +} + +/** Main function */ +int main(int argc, char **argv) +{ + int mat_size = 3; // default matrix size + const int range = 10; + const int range2 = range >> 1; + + if (argc == 2) + mat_size = atoi(argv[1]); + + srand(time(NULL)); // random number initializer + + /* Create a square matrix with random values */ + double **A = (double **)malloc(mat_size * sizeof(double *)); + double **L = (double **)malloc(mat_size * sizeof(double *)); // output + double **U = (double **)malloc(mat_size * sizeof(double *)); // output + for (int i = 0; i < mat_size; i++) + { + // calloc so that all valeus are '0' by default + A[i] = (double *)calloc(mat_size, sizeof(double)); + L[i] = (double *)calloc(mat_size, sizeof(double)); + U[i] = (double *)calloc(mat_size, sizeof(double)); + for (int j = 0; j < mat_size; j++) + /* create random values in the limits [-range2, range-1] */ + A[i][j] = (double)(rand() % range - range2); + } + + lu_decomposition(A, L, U, mat_size); + + printf("A = \n"); + display(A, mat_size); + printf("\nL = \n"); + display(L, mat_size); + printf("\nU = \n"); + display(U, mat_size); + + /* Free dynamically allocated memory */ + for (int i = 0; i < mat_size; i++) + { + free(A[i]); + free(L[i]); + free(U[i]); + } + free(A); + free(L); + free(U); + + return 0; +} \ No newline at end of file diff --git a/numerical_methods/mean.c b/numerical_methods/mean.c new file mode 100644 index 0000000000..6b18637de1 --- /dev/null +++ b/numerical_methods/mean.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include + +#define MAX_LEN INT_MAX + +int main(int argc, char **argv) +{ + int *a, n = 10, i, j, temp, sum = 0; + float mean; + + if (argc == 2) + { + n = atoi(argv[1]); + if (n >= MAX_LEN) + { + fprintf(stderr, "Maximum %d!\n", MAX_LEN); + return 1; + } + } + + a = (int *)malloc(n * sizeof(int)); + + printf("Random Numbers Generated are: "); + for (i = 0; i < n; i++) + { + a[i] = rand() % 100; + printf("%2d, ", a[i]); + } + putchar('\n'); + + for (i = 0; i < n; i++) sum = sum + a[i]; + + mean = sum / (float)n; + printf("\nMean: "); + printf("%f\n", mean); + + free(a); + return 0; +} diff --git a/numerical_methods/median.c b/numerical_methods/median.c new file mode 100644 index 0000000000..8bf63c24ca --- /dev/null +++ b/numerical_methods/median.c @@ -0,0 +1,51 @@ +#include +#include +#include + +int main() +{ + int a[10], n, i, j, temp; + float mean, median; + + printf("Enter no. for Random Numbers :"); + scanf("%d", &n); + for (i = 0; i < n; i++) + { + a[i] = rand() % 100; + } + printf("Random Numbers Generated are :\n"); + for (i = 0; i < n; i++) + { + printf("\n%d", a[i]); + } + printf("\n"); + printf("\nSorted Data:"); + for (i = 0; i < n; i++) + { + for (j = 0; j < n; j++) + { + if (a[i] < a[j]) + { + temp = a[i]; + a[i] = a[j]; + a[j] = temp; + } + } + } + for (i = 0; i < n; i++) + { + printf("\n%d", a[i]); + } + + if (n % 2 == 0) + { + median = (a[n / 2] + a[(n / 2) - 1]) / 2; + } + else + { + median = a[n / 2]; + } + printf("\nMedian is : %f", median); + + return 0; +} diff --git a/numerical_methods/newton_raphson_root.c b/numerical_methods/newton_raphson_root.c new file mode 100644 index 0000000000..952b2b4966 --- /dev/null +++ b/numerical_methods/newton_raphson_root.c @@ -0,0 +1,76 @@ +/** + * @file + * \brief Find approximate solution for \f$f(x) = 0\f$ using + * Newton-Raphson interpolation algorithm. + * + * \author [Krishna Vedala](https://github.com/kvedala) + */ + +#include /* requires minimum of C99 */ +#include +#include +#include +#include +#include + +#define ACCURACY 1e-10 /**< solution accuracy */ + +/** + * Return value of the function to find the root for. + * \f$f(x)\f$ + */ +double complex func(double complex x) +{ + return x * x - 3.; /* x^2 = 3 - solution is sqrt(3) */ + // return x * x - 2.; /* x^2 = 2 - solution is sqrt(2) */ +} + +/** + * Return first order derivative of the function. + * \f$f'(x)\f$ + */ +double complex d_func(double complex x) { return 2. * x; } + +/** + * main function + */ +int main(int argc, char **argv) +{ + double delta = 1; + double complex cdelta = 1; + + /* initialize random seed: */ + srand(time(NULL)); + + /* random initial approximation */ + double complex root = (rand() % 100 - 50) + (rand() % 100 - 50) * I; + + unsigned long counter = 0; + /* iterate till a convergence is reached */ + while (delta > ACCURACY && counter < ULONG_MAX) + { + cdelta = func(root) / d_func(root); + root += -cdelta; + counter++; + delta = fabs(cabs(cdelta)); + +#if defined(DEBUG) || !defined(NDEBUG) + if (counter % 50 == 0) + { + double r = creal(root); + double c = cimag(root); + + printf("Iter %5lu: Root: %4.4g%c%4.4gi\t\tdelta: %.4g\n", counter, + r, c >= 0 ? '+' : '-', c >= 0 ? c : -c, delta); + } +#endif + } + + double r = creal(root); + double c = fabs(cimag(root)) < ACCURACY ? 0 : cimag(root); + + printf("Iter %5lu: Root: %4.4g%c%4.4gi\t\tdelta: %.4g\n", counter, r, + c >= 0 ? '+' : '-', c >= 0 ? c : -c, delta); + + return 0; +} diff --git a/numerical_methods/ode_forward_euler.c b/numerical_methods/ode_forward_euler.c new file mode 100644 index 0000000000..ee4451b8d4 --- /dev/null +++ b/numerical_methods/ode_forward_euler.c @@ -0,0 +1,182 @@ +/** + * \file + * \authors [Krishna Vedala](https://github.com/kvedala) + * \brief Solve a multivariable first order [ordinary differential equation + * (ODEs)](https://en.wikipedia.org/wiki/Ordinary_differential_equation) using + * [forward Euler + * method](https://en.wikipedia.org/wiki/Numerical_methods_for_ordinary_differential_equations#Euler_method) + * + * \details + * The ODE being solved is: + * \f{eqnarray*}{ + * \dot{u} &=& v\\ + * \dot{v} &=& -\omega^2 u\\ + * \omega &=& 1\\ + * [x_0, u_0, v_0] &=& [0,1,0]\qquad\ldots\text{(initial values)} + * \f} + * The exact solution for the above problem is: + * \f{eqnarray*}{ + * u(x) &=& \cos(x)\\ + * v(x) &=& -\sin(x)\\ + * \f} + * The computation results are stored to a text file `forward_euler.csv` and the + * exact soltuion results in `exact.csv` for comparison. + * Implementation solution + * + * To implement [Van der Pol + * oscillator](https://en.wikipedia.org/wiki/Van_der_Pol_oscillator), change the + * ::problem function to: + * ```cpp + * const double mu = 2.0; + * dy[0] = y[1]; + * dy[1] = mu * (1.f - y[0] * y[0]) * y[1] - y[0]; + * ``` + * \see ode_midpoint_euler.c, ode_semi_implicit_euler.c + */ + +#include +#include +#include +#include + +#define order 2 /**< number of dependent variables in ::problem */ + +/** + * @brief Problem statement for a system with first-order differential + * equations. Updates the system differential variables. + * \note This function can be updated to and ode of any order. + * + * @param[in] x independent variable(s) + * @param[in,out] y dependent variable(s) + * @param[in,out] dy first-derivative of dependent variable(s) + */ +void problem(const double *x, double *y, double *dy) +{ + const double omega = 1.F; // some const for the problem + dy[0] = y[1]; // x dot + dy[1] = -omega * omega * y[0]; // y dot +} + +/** + * @brief Exact solution of the problem. Used for solution comparison. + * + * @param[in] x independent variable + * @param[in,out] y dependent variable + */ +void exact_solution(const double *x, double *y) +{ + y[0] = cos(x[0]); + y[1] = -sin(x[0]); +} + +/** + * @brief Compute next step approximation using the forward-Euler + * method. @f[y_{n+1}=y_n + dx\cdot f\left(x_n,y_n\right)@f] + * @param[in] dx step size + * @param[in,out] x take \f$x_n\f$ and compute \f$x_{n+1}\f$ + * @param[in,out] y take \f$y_n\f$ and compute \f$y_{n+1}\f$ + * @param[in,out] dy compute \f$f\left(x_n,y_n\right)\f$ + */ +void forward_euler_step(const double dx, const double *x, double *y, double *dy) +{ + int o; + problem(x, y, dy); + for (o = 0; o < order; o++) y[o] += dx * dy[o]; +} + +/** + * @brief Compute approximation using the forward-Euler + * method in the given limits. + * @param[in] dx step size + * @param[in] x0 initial value of independent variable + * @param[in] x_max final value of independent variable + * @param[in,out] y take \f$y_n\f$ and compute \f$y_{n+1}\f$ + * @param[in] save_to_file flag to save results to a CSV file (1) or not (0) + * @returns time taken for computation in seconds + */ +double forward_euler(double dx, double x0, double x_max, double *y, + char save_to_file) +{ + double dy[order]; + + FILE *fp = NULL; + if (save_to_file) + { + fp = fopen("forward_euler.csv", "w+"); + if (fp == NULL) + { + perror("Error! "); + return -1; + } + } + + /* start integration */ + clock_t t1 = clock(); + double x = x0; + do // iterate for each step of independent variable + { + if (save_to_file && fp) + fprintf(fp, "%.4g,%.4g,%.4g\n", x, y[0], y[1]); // write to file + forward_euler_step(dx, &x, y, dy); // perform integration + x += dx; // update step + } while (x <= x_max); // till upper limit of independent variable + /* end of integration */ + clock_t t2 = clock(); + + if (save_to_file && fp) + fclose(fp); + + return (double)(t2 - t1) / CLOCKS_PER_SEC; +} + +/** + Main Function +*/ +int main(int argc, char *argv[]) +{ + double X0 = 0.f; /* initial value of x0 */ + double X_MAX = 10.F; /* upper limit of integration */ + double Y0[] = {1.f, 0.f}; /* initial value Y = y(x = x_0) */ + double step_size; + + if (argc == 1) + { + printf("\nEnter the step size: "); + scanf("%lg", &step_size); + } + else + // use commandline argument as independent variable step size + step_size = atof(argv[1]); + + // get approximate solution + double total_time = forward_euler(step_size, X0, X_MAX, Y0, 1); + printf("\tTime = %.6g ms\n", total_time); + + /* compute exact solution for comparion */ + FILE *fp = fopen("exact.csv", "w+"); + if (fp == NULL) + { + perror("Error! "); + return -1; + } + double x = X0; + double *y = &(Y0[0]); + printf("Finding exact solution\n"); + clock_t t1 = clock(); + + do + { + fprintf(fp, "%.4g,%.4g,%.4g\n", x, y[0], y[1]); // write to file + exact_solution(&x, y); + x += step_size; + } while (x <= X_MAX); + + clock_t t2 = clock(); + total_time = (t2 - t1) / CLOCKS_PER_SEC; + printf("\tTime = %.6g ms\n", total_time); + fclose(fp); + + return 0; +} diff --git a/numerical_methods/ode_midpoint_euler.c b/numerical_methods/ode_midpoint_euler.c new file mode 100644 index 0000000000..eaf723075a --- /dev/null +++ b/numerical_methods/ode_midpoint_euler.c @@ -0,0 +1,189 @@ +/** + * \file + * \authors [Krishna Vedala](https://github.com/kvedala) + * \brief Solve a multivariable first order [ordinary differential equation + * (ODEs)](https://en.wikipedia.org/wiki/Ordinary_differential_equation) using + * [midpoint Euler + * method](https://en.wikipedia.org/wiki/Midpoint_method) + * + * \details + * The ODE being solved is: + * \f{eqnarray*}{ + * \dot{u} &=& v\\ + * \dot{v} &=& -\omega^2 u\\ + * \omega &=& 1\\ + * [x_0, u_0, v_0] &=& [0,1,0]\qquad\ldots\text{(initial values)} + * \f} + * The exact solution for the above problem is: + * \f{eqnarray*}{ + * u(x) &=& \cos(x)\\ + * v(x) &=& -\sin(x)\\ + * \f} + * The computation results are stored to a text file `midpoint_euler.csv` and + * the exact soltuion results in `exact.csv` for comparison. Implementation solution + * + * To implement [Van der Pol + * oscillator](https://en.wikipedia.org/wiki/Van_der_Pol_oscillator), change the + * ::problem function to: + * ```cpp + * const double mu = 2.0; + * dy[0] = y[1]; + * dy[1] = mu * (1.f - y[0] * y[0]) * y[1] - y[0]; + * ``` + * \see ode_forward_euler.c, ode_semi_implicit_euler.c + */ + +#include +#include +#include +#include + +#define order 2 /**< number of dependent variables in ::problem */ + +/** + * @brief Problem statement for a system with first-order differential + * equations. Updates the system differential variables. + * \note This function can be updated to and ode of any order. + * + * @param[in] x independent variable(s) + * @param[in,out] y dependent variable(s) + * @param[in,out] dy first-derivative of dependent variable(s) + */ +void problem(const double *x, double *y, double *dy) +{ + const double omega = 1.F; // some const for the problem + dy[0] = y[1]; // x dot + dy[1] = -omega * omega * y[0]; // y dot +} + +/** + * @brief Exact solution of the problem. Used for solution comparison. + * + * @param[in] x independent variable + * @param[in,out] y dependent variable + */ +void exact_solution(const double *x, double *y) +{ + y[0] = cos(x[0]); + y[1] = -sin(x[0]); +} + +/** + * @brief Compute next step approximation using the midpoint-Euler + * method. + * @f[y_{n+1} = y_n + dx\, f\left(x_n+\frac{1}{2}dx, + * y_n + \frac{1}{2}dx\,f\left(x_n,y_n\right)\right)@f] + * @param[in] dx step size + * @param[in,out] x take @f$x_n@f$ and compute @f$x_{n+1}@f$ + * @param[in,out] y take @f$y_n@f$ and compute @f$y_{n+1}@f$ + * @param[in,out] dy compute @f$y_n+\frac{1}{2}dx\,f\left(x_n,y_n\right)@f$ + */ +void midpoint_euler_step(double dx, double *x, double *y, double *dy) +{ + problem(x, y, dy); + double tmp_x = (*x) + 0.5 * dx; + double tmp_y[order]; + int o; + for (o = 0; o < order; o++) tmp_y[o] = y[o] + 0.5 * dx * dy[o]; + + problem(&tmp_x, tmp_y, dy); + + for (o = 0; o < order; o++) y[o] += dx * dy[o]; +} + +/** + * @brief Compute approximation using the midpoint-Euler + * method in the given limits. + * @param[in] dx step size + * @param[in] x0 initial value of independent variable + * @param[in] x_max final value of independent variable + * @param[in,out] y take \f$y_n\f$ and compute \f$y_{n+1}\f$ + * @param[in] save_to_file flag to save results to a CSV file (1) or not (0) + * @returns time taken for computation in seconds + */ +double midpoint_euler(double dx, double x0, double x_max, double *y, + char save_to_file) +{ + double dy[order]; + + FILE *fp = NULL; + if (save_to_file) + { + fp = fopen("midpoint_euler.csv", "w+"); + if (fp == NULL) + { + perror("Error! "); + return -1; + } + } + + /* start integration */ + clock_t t1 = clock(); + double x = x0; + do // iterate for each step of independent variable + { + if (save_to_file && fp) + fprintf(fp, "%.4g,%.4g,%.4g\n", x, y[0], y[1]); // write to file + midpoint_euler_step(dx, &x, y, dy); // perform integration + x += dx; // update step + } while (x <= x_max); // till upper limit of independent variable + /* end of integration */ + clock_t t2 = clock(); + + if (save_to_file && fp) + fclose(fp); + + return (double)(t2 - t1) / CLOCKS_PER_SEC; +} + +/** + Main Function +*/ +int main(int argc, char *argv[]) +{ + double X0 = 0.f; /* initial value of x0 */ + double X_MAX = 10.F; /* upper limit of integration */ + double Y0[] = {1.f, 0.f}; /* initial value Y = y(x = x_0) */ + double step_size; + + if (argc == 1) + { + printf("\nEnter the step size: "); + scanf("%lg", &step_size); + } + else + // use commandline argument as independent variable step size + step_size = atof(argv[1]); + + // get approximate solution + double total_time = midpoint_euler(step_size, X0, X_MAX, Y0, 1); + printf("\tTime = %.6g ms\n", total_time); + + /* compute exact solution for comparion */ + FILE *fp = fopen("exact.csv", "w+"); + if (fp == NULL) + { + perror("Error! "); + return -1; + } + double x = X0; + double *y = &(Y0[0]); + printf("Finding exact solution\n"); + clock_t t1 = clock(); + + do + { + fprintf(fp, "%.4g,%.4g,%.4g\n", x, y[0], y[1]); // write to file + exact_solution(&x, y); + x += step_size; + } while (x <= X_MAX); + + clock_t t2 = clock(); + total_time = (t2 - t1) / CLOCKS_PER_SEC; + printf("\tTime = %.6g ms\n", total_time); + fclose(fp); + + return 0; +} diff --git a/numerical_methods/ode_semi_implicit_euler.c b/numerical_methods/ode_semi_implicit_euler.c new file mode 100644 index 0000000000..e87d2a9117 --- /dev/null +++ b/numerical_methods/ode_semi_implicit_euler.c @@ -0,0 +1,192 @@ +/** + * \file + * \authors [Krishna Vedala](https://github.com/kvedala) + * \brief Solve a multivariable first order [ordinary differential equation + * (ODEs)](https://en.wikipedia.org/wiki/Ordinary_differential_equation) using + * [semi implicit Euler + * method](https://en.wikipedia.org/wiki/Semi-implicit_Euler_method) + * + * \details + * The ODE being solved is: + * \f{eqnarray*}{ + * \dot{u} &=& v\\ + * \dot{v} &=& -\omega^2 u\\ + * \omega &=& 1\\ + * [x_0, u_0, v_0] &=& [0,1,0]\qquad\ldots\text{(initial values)} + * \f} + * The exact solution for the above problem is: + * \f{eqnarray*}{ + * u(x) &=& \cos(x)\\ + * v(x) &=& -\sin(x)\\ + * \f} + * The computation results are stored to a text file `semi_implicit_euler.csv` + * and the exact soltuion results in `exact.csv` for comparison. Implementation solution + * + * To implement [Van der Pol + * oscillator](https://en.wikipedia.org/wiki/Van_der_Pol_oscillator), change the + * ::problem function to: + * ```cpp + * const double mu = 2.0; + * dy[0] = y[1]; + * dy[1] = mu * (1.f - y[0] * y[0]) * y[1] - y[0]; + * ``` + * Van der Pol Oscillator solution + * + * \see ode_forward_euler.c, ode_midpoint_euler.c + */ + +#include +#include +#include +#include + +#define order 2 /**< number of dependent variables in ::problem */ + +/** + * @brief Problem statement for a system with first-order differential + * equations. Updates the system differential variables. + * \note This function can be updated to and ode of any order. + * + * @param[in] x independent variable(s) + * @param[in,out] y dependent variable(s) + * @param[in,out] dy first-derivative of dependent variable(s) + */ +void problem(const double *x, double *y, double *dy) +{ + const double omega = 1.F; // some const for the problem + dy[0] = y[1]; // x dot + dy[1] = -omega * omega * y[0]; // y dot +} + +/** + * @brief Exact solution of the problem. Used for solution comparison. + * + * @param[in] x independent variable + * @param[in,out] y dependent variable + */ +void exact_solution(const double *x, double *y) +{ + y[0] = cos(x[0]); + y[1] = -sin(x[0]); +} + +/** + * @brief Compute next step approximation using the semi-implicit-Euler + * method. + * @param[in] dx step size + * @param[in,out] x take @f$x_n@f$ and compute @f$x_{n+1}@f$ + * @param[in,out] y take @f$y_n@f$ and compute @f$y_{n+1}@f$ + * @param[in,out] dy compute @f$y_n+\frac{1}{2}dx\,f\left(x_n,y_n\right)@f$ + */ +void semi_implicit_euler_step(double dx, double *x, double *y, double *dy) +{ + int o; + + problem(x, y, dy); // update dy once + y[0] += dx * dy[0]; // update y0 + + problem(x, y, dy); // update dy once more + + for (o = 1; o < order; o++) + y[o] += dx * dy[o]; // update remaining using new dy + *x += dx; +} + +/** + * @brief Compute approximation using the semi-implicit-Euler + * method in the given limits. + * @param[in] dx step size + * @param[in] x0 initial value of independent variable + * @param[in] x_max final value of independent variable + * @param[in,out] y take \f$y_n\f$ and compute \f$y_{n+1}\f$ + * @param[in] save_to_file flag to save results to a CSV file (1) or not (0) + * @returns time taken for computation in seconds + */ +double semi_implicit_euler(double dx, double x0, double x_max, double *y, + char save_to_file) +{ + double dy[order]; + + FILE *fp = NULL; + if (save_to_file) + { + fp = fopen("semi_implicit_euler.csv", "w+"); + if (fp == NULL) + { + perror("Error! "); + return -1; + } + } + + /* start integration */ + clock_t t1 = clock(); + double x = x0; + do // iterate for each step of independent variable + { + if (save_to_file && fp) + fprintf(fp, "%.4g,%.4g,%.4g\n", x, y[0], y[1]); // write to file + semi_implicit_euler_step(dx, &x, y, dy); // perform integration + x += dx; // update step + } while (x <= x_max); // till upper limit of independent variable + /* end of integration */ + clock_t t2 = clock(); + + if (save_to_file && fp) + fclose(fp); + + return (double)(t2 - t1) / CLOCKS_PER_SEC; +} + +/** + Main Function +*/ +int main(int argc, char *argv[]) +{ + double X0 = 0.f; /* initial value of x0 */ + double X_MAX = 10.F; /* upper limit of integration */ + double Y0[] = {1.f, 0.f}; /* initial value Y = y(x = x_0) */ + double step_size; + + if (argc == 1) + { + printf("\nEnter the step size: "); + scanf("%lg", &step_size); + } + else + // use commandline argument as independent variable step size + step_size = atof(argv[1]); + + // get approximate solution + double total_time = semi_implicit_euler(step_size, X0, X_MAX, Y0, 1); + printf("\tTime = %.6g ms\n", total_time); + + /* compute exact solution for comparion */ + FILE *fp = fopen("exact.csv", "w+"); + if (fp == NULL) + { + perror("Error! "); + return -1; + } + double x = X0; + double *y = &(Y0[0]); + printf("Finding exact solution\n"); + clock_t t1 = clock(); + + do + { + fprintf(fp, "%.4g,%.4g,%.4g\n", x, y[0], y[1]); // write to file + exact_solution(&x, y); + x += step_size; + } while (x <= X_MAX); + + clock_t t2 = clock(); + total_time = (t2 - t1) / CLOCKS_PER_SEC; + printf("\tTime = %.6g ms\n", total_time); + fclose(fp); + + return 0; +} diff --git a/numerical_methods/qr_decompose.h b/numerical_methods/qr_decompose.h new file mode 100644 index 0000000000..55349f44e3 --- /dev/null +++ b/numerical_methods/qr_decompose.h @@ -0,0 +1,201 @@ +/** + * @file + * \brief Library functions to compute [QR + * decomposition](https://en.wikipedia.org/wiki/QR_decomposition) of a given + * matrix. + * \author [Krishna Vedala](https://github.com/kvedala) + */ + +#ifndef QR_DECOMPOSE_H +#define QR_DECOMPOSE_H + +#include +#include +#include +#ifdef _OPENMP +#include +#endif + +/** + * function to display matrix on stdout + */ +void print_matrix(double **A, /**< matrix to print */ + int M, /**< number of rows of matrix */ + int N) /**< number of columns of matrix */ +{ + for (int row = 0; row < M; row++) + { + for (int col = 0; col < N; col++) printf("% 9.3g\t", A[row][col]); + putchar('\n'); + } + putchar('\n'); +} + +/** + * Compute dot product of two vectors of equal lengths + * + * If \f$\vec{a}=\left[a_0,a_1,a_2,...,a_L\right]\f$ and + * \f$\vec{b}=\left[b_0,b_1,b_1,...,b_L\right]\f$ then + * \f$\vec{a}\cdot\vec{b}=\displaystyle\sum_{i=0}^L a_i\times b_i\f$ + * + * \returns \f$\vec{a}\cdot\vec{b}\f$ + */ +double vector_dot(double *a, double *b, int L) +{ + double mag = 0.f; + int i; +#ifdef _OPENMP +// parallelize on threads +#pragma omp parallel for reduction(+ : mag) +#endif + for (i = 0; i < L; i++) mag += a[i] * b[i]; + + return mag; +} + +/** + * Compute magnitude of vector. + * + * If \f$\vec{a}=\left[a_0,a_1,a_2,...,a_L\right]\f$ then + * \f$\left|\vec{a}\right|=\sqrt{\displaystyle\sum_{i=0}^L a_i^2}\f$ + * + * \returns \f$\left|\vec{a}\right|\f$ + */ +double vector_mag(double *vector, int L) +{ + double dot = vector_dot(vector, vector, L); + return sqrt(dot); +} + +/** + * Compute projection of vector \f$\vec{a}\f$ on \f$\vec{b}\f$ defined as + * \f[\text{proj}_\vec{b}\vec{a}=\frac{\vec{a}\cdot\vec{b}}{\left|\vec{b}\right|^2}\vec{b}\f] + * + * \returns NULL if error, otherwise pointer to output + */ +double *vector_proj(double *a, double *b, double *out, int L) +{ + const double num = vector_dot(a, b, L); + const double deno = vector_dot(b, b, L); + if (deno == 0) /*! check for division by zero */ + return NULL; + + const double scalar = num / deno; + int i; +#ifdef _OPENMP +// parallelize on threads +#pragma omp for +#endif + for (i = 0; i < L; i++) out[i] = scalar * b[i]; + + return out; +} + +/** + * Compute vector subtraction + * + * \f$\vec{c}=\vec{a}-\vec{b}\f$ + * + * \returns pointer to output vector + */ +double *vector_sub(double *a, /**< minuend */ + double *b, /**< subtrahend */ + double *out, /**< resultant vector */ + int L /**< length of vectors */ +) +{ + int i; +#ifdef _OPENMP +// parallelize on threads +#pragma omp for +#endif + for (i = 0; i < L; i++) out[i] = a[i] - b[i]; + + return out; +} + +/** + * Decompose matrix \f$A\f$ using [Gram-Schmidt + *process](https://en.wikipedia.org/wiki/QR_decomposition). + * + * \f{eqnarray*}{ + * \text{given that}\quad A &=& + *\left[\mathbf{a}_1,\mathbf{a}_2,\ldots,\mathbf{a}_{N-1},\right]\\ + * \text{where}\quad\mathbf{a}_i &=& + *\left[a_{0i},a_{1i},a_{2i},\ldots,a_{(M-1)i}\right]^T\quad\ldots\mbox{(column + *vectors)}\\ + * \text{then}\quad\mathbf{u}_i &=& \mathbf{a}_i + *-\sum_{j=0}^{i-1}\text{proj}_{\mathbf{u}_j}\mathbf{a}_i\\ + * \mathbf{e}_i &=&\frac{\mathbf{u}_i}{\left|\mathbf{u}_i\right|}\\ + * Q &=& \begin{bmatrix}\mathbf{e}_0 & \mathbf{e}_1 & \mathbf{e}_2 & \dots & + *\mathbf{e}_{N-1}\end{bmatrix}\\ + * R &=& \begin{bmatrix}\langle\mathbf{e}_0\,,\mathbf{a}_0\rangle & + *\langle\mathbf{e}_1\,,\mathbf{a}_1\rangle & + *\langle\mathbf{e}_2\,,\mathbf{a}_2\rangle & \dots \\ + * 0 & \langle\mathbf{e}_1\,,\mathbf{a}_1\rangle & + *\langle\mathbf{e}_2\,,\mathbf{a}_2\rangle & \dots\\ + * 0 & 0 & \langle\mathbf{e}_2\,,\mathbf{a}_2\rangle & \dots\\ + * \vdots & \vdots & \vdots & \ddots + * \end{bmatrix}\\ + * \f} + */ +void qr_decompose(double **A, /**< input matrix to decompose */ + double **Q, /**< output decomposed matrix */ + double **R, /**< output decomposed matrix */ + int M, /**< number of rows of matrix A */ + int N /**< number of columns of matrix A */ +) +{ + double *col_vector = (double *)malloc(M * sizeof(double)); + double *col_vector2 = (double *)malloc(M * sizeof(double)); + double *tmp_vector = (double *)malloc(M * sizeof(double)); + for (int i = 0; i < N; + i++) /* for each column => R is a square matrix of NxN */ + { + int j; +#ifdef _OPENMP +// parallelize on threads +#pragma omp for +#endif + for (j = 0; j < i; j++) /* second dimension of column */ + R[i][j] = 0.; /* make R upper triangular */ + + /* get corresponding Q vector */ +#ifdef _OPENMP +// parallelize on threads +#pragma omp for +#endif + for (j = 0; j < M; j++) + { + tmp_vector[j] = A[j][i]; /* accumulator for uk */ + col_vector[j] = A[j][i]; + } + for (j = 0; j < i; j++) + { + for (int k = 0; k < M; k++) col_vector2[k] = Q[k][j]; + vector_proj(col_vector, col_vector2, col_vector2, M); + vector_sub(tmp_vector, col_vector2, tmp_vector, M); + } + double mag = vector_mag(tmp_vector, M); + +#ifdef _OPENMP +// parallelize on threads +#pragma omp for +#endif + for (j = 0; j < M; j++) Q[j][i] = tmp_vector[j] / mag; + + /* compute upper triangular values of R */ + for (int kk = 0; kk < M; kk++) col_vector[kk] = Q[kk][i]; + for (int k = i; k < N; k++) + { + for (int kk = 0; kk < M; kk++) col_vector2[kk] = A[kk][k]; + R[i][k] = vector_dot(col_vector, col_vector2, M); + } + } + + free(col_vector); + free(col_vector2); + free(tmp_vector); +} + +#endif // QR_DECOMPOSE_H diff --git a/numerical_methods/qr_decomposition.c b/numerical_methods/qr_decomposition.c new file mode 100644 index 0000000000..3efeddc931 --- /dev/null +++ b/numerical_methods/qr_decomposition.c @@ -0,0 +1,80 @@ +/** + * @file + * \brief Program to compute the [QR + * decomposition](https://en.wikipedia.org/wiki/QR_decomposition) of a given + * matrix. + * \author [Krishna Vedala](https://github.com/kvedala) + */ + +#include +#include +#include +#include +#include "qr_decompose.h" + +/** + * main function + */ +int main(void) +{ + double **A; + unsigned int ROWS, COLUMNS; + + printf("Enter the number of rows and columns: "); + scanf("%u %u", &ROWS, &COLUMNS); + if (ROWS < COLUMNS) + { + fprintf(stderr, + "Number of rows must be greater than or equal to " + "number of columns.\n"); + return -1; + } + + printf("Enter matrix elements row-wise:\n"); + + A = (double **)malloc(ROWS * sizeof(double *)); + for (int i = 0; i < ROWS; i++) + A[i] = (double *)malloc(COLUMNS * sizeof(double)); + + for (int i = 0; i < ROWS; i++) + for (int j = 0; j < COLUMNS; j++) scanf("%lf", &A[i][j]); + + print_matrix(A, ROWS, COLUMNS); + + double **R = (double **)malloc(sizeof(double *) * ROWS); + double **Q = (double **)malloc(sizeof(double *) * ROWS); + if (!Q || !R) + { + perror("Unable to allocate memory for Q & R!"); + return -1; + } + for (int i = 0; i < ROWS; i++) + { + R[i] = (double *)malloc(sizeof(double) * COLUMNS); + Q[i] = (double *)malloc(sizeof(double) * ROWS); + if (!Q[i] || !R[i]) + { + perror("Unable to allocate memory for Q & R."); + return -1; + } + } + + clock_t t1 = clock(); + qr_decompose(A, Q, R, ROWS, COLUMNS); + double dtime = (double)(clock() - t1) / CLOCKS_PER_SEC; + + print_matrix(R, ROWS, COLUMNS); + print_matrix(Q, ROWS, COLUMNS); + printf("Time taken to compute: %.4g sec\n", dtime); + + for (int i = 0; i < ROWS; i++) + { + free(A[i]); + free(R[i]); + free(Q[i]); + } + free(A); + free(R); + free(Q); + return 0; +} diff --git a/numerical_methods/qr_eigen_values.c b/numerical_methods/qr_eigen_values.c new file mode 100644 index 0000000000..716094fcb3 --- /dev/null +++ b/numerical_methods/qr_eigen_values.c @@ -0,0 +1,369 @@ +/** + * @file + * \brief Compute real eigen values and eigen vectors of a symmetric matrix + * using [QR decomposition](https://en.wikipedia.org/wiki/QR_decomposition) + * method. + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include +#include +#include +#include +#include + +#include "qr_decompose.h" +#ifdef _OPENMP +#include +#endif + +#define LIMS 9 /**< limit of range of matrix values */ +#define EPSILON 1e-10 /**< accuracy tolerance limit */ + +/** + * create a square matrix of given size with random elements + * \param[out] A matrix to create (must be pre-allocated in memory) + * \param[in] N matrix size + */ +void create_matrix(double **A, int N) +{ + int i, j, tmp, lim2 = LIMS >> 1; + +#ifdef _OPENMP +#pragma omp for +#endif + for (i = 0; i < N; i++) + { + A[i][i] = (rand() % LIMS) - lim2; + for (j = i + 1; j < N; j++) + { + tmp = (rand() % LIMS) - lim2; + A[i][j] = tmp; + A[j][i] = tmp; + } + } +} + +/** + * Perform multiplication of two matrices. + * * R2 must be equal to C1 + * * Resultant matrix size should be R1xC2 + * \param[in] A first matrix to multiply + * \param[in] B second matrix to multiply + * \param[out] OUT output matrix (must be pre-allocated) + * \param[in] R1 number of rows of first matrix + * \param[in] C1 number of columns of first matrix + * \param[in] R2 number of rows of second matrix + * \param[in] C2 number of columns of second matrix + * \returns pointer to resultant matrix + */ +double **mat_mul(double **A, double **B, double **OUT, int R1, int C1, int R2, + int C2) +{ + if (C1 != R2) + { + perror("Matrix dimensions mismatch!"); + return OUT; + } + + int i; +#ifdef _OPENMP +#pragma omp for +#endif + for (i = 0; i < R1; i++) + { + for (int j = 0; j < C2; j++) + { + OUT[i][j] = 0.f; + for (int k = 0; k < C1; k++) OUT[i][j] += A[i][k] * B[k][j]; + } + } + return OUT; +} + +/** Compute eigen values using iterative shifted QR decomposition algorithm as + * follows: + * 1. Use last diagonal element of A as eigen value approximation \f$c\f$ + * 2. Shift diagonals of matrix \f$A' = A - cI\f$ + * 3. Decompose matrix \f$A'=QR\f$ + * 4. Compute next approximation \f$A'_1 = RQ \f$ + * 5. Shift diagonals back \f$A_1 = A'_1 + cI\f$ + * 6. Termination condition check: last element below diagonal is almost 0 + * 1. If not 0, go back to step 1 with the new approximation \f$A_1\f$ + * 2. If 0, continue to step 7 + * 7. Save last known \f$c\f$ as the eigen value. + * 8. Are all eigen values found? + * 1. If not, remove last row and column of \f$A_1\f$ and go back to step 1. + * 2. If yes, stop. + * + * \note The matrix \f$A\f$ gets modified + * + * \param[in,out] A matrix to compute eigen values for + * \param[out] eigen_vals resultant vector containing computed eigen values + * \param[in] mat_size matrix size + * \param[in] debug_print 1 to print intermediate Q & R matrices, 0 for not to + * \returns time for computation in seconds + */ +double eigen_values(double **A, double *eigen_vals, int mat_size, + char debug_print) +{ + if (!eigen_vals) + { + perror("Output eigen value vector cannot be NULL!"); + return -1; + } + double **R = (double **)malloc(sizeof(double *) * mat_size); + double **Q = (double **)malloc(sizeof(double *) * mat_size); + if (!Q || !R) + { + perror("Unable to allocate memory for Q & R!"); + if (Q) + { + free(Q); + } + if (R) + { + free(R); + } + return -1; + } + + /* allocate dynamic memory for matrices */ + for (int i = 0; i < mat_size; i++) + { + R[i] = (double *)malloc(sizeof(double) * mat_size); + Q[i] = (double *)malloc(sizeof(double) * mat_size); + if (!Q[i] || !R[i]) + { + perror("Unable to allocate memory for Q & R."); + for (; i >= 0; i--) + { + free(R[i]); + free(Q[i]); + } + free(Q); + free(R); + return -1; + } + } + + if (debug_print) + { + print_matrix(A, mat_size, mat_size); + } + + int rows = mat_size, columns = mat_size; + int counter = 0, num_eigs = rows - 1; + double last_eig = 0; + + clock_t t1 = clock(); + while (num_eigs > 0) /* continue till all eigen values are found */ + { + /* iterate with QR decomposition */ + while (fabs(A[num_eigs][num_eigs - 1]) > EPSILON) + { + last_eig = A[num_eigs][num_eigs]; + for (int i = 0; i < rows; i++) A[i][i] -= last_eig; /* A - cI */ + qr_decompose(A, Q, R, rows, columns); + + if (debug_print) + { + print_matrix(A, rows, columns); + print_matrix(Q, rows, columns); + print_matrix(R, columns, columns); + printf("-------------------- %d ---------------------\n", + ++counter); + } + + mat_mul(R, Q, A, columns, columns, rows, columns); + for (int i = 0; i < rows; i++) A[i][i] += last_eig; /* A + cI */ + } + + /* store the converged eigen value */ + eigen_vals[num_eigs] = last_eig; + + if (debug_print) + { + printf("========================\n"); + printf("Eigen value: % g,\n", last_eig); + printf("========================\n"); + } + + num_eigs--; + rows--; + columns--; + } + eigen_vals[0] = A[0][0]; + double dtime = (double)(clock() - t1) / CLOCKS_PER_SEC; + + if (debug_print) + { + print_matrix(R, mat_size, mat_size); + print_matrix(Q, mat_size, mat_size); + } + + /* cleanup dynamic memory */ + for (int i = 0; i < mat_size; i++) + { + free(R[i]); + free(Q[i]); + } + free(R); + free(Q); + + return dtime; +} + +/** + * test function to compute eigen values of a 2x2 matrix + * \f[\begin{bmatrix} + * 5 & 7\\ + * 7 & 11 + * \end{bmatrix}\f] + * which are approximately, {15.56158, 0.384227} + */ +void test1() +{ + int mat_size = 2; + double X[][2] = {{5, 7}, {7, 11}}; + double y[] = {15.56158, 0.384227}; // corresponding y-values + double eig_vals[2] = {0, 0}; + + // The following steps are to convert a "double[][]" to "double **" + double **A = (double **)malloc(mat_size * sizeof(double *)); + for (int i = 0; i < mat_size; i++) A[i] = X[i]; + + printf("------- Test 1 -------\n"); + + double dtime = eigen_values(A, eig_vals, mat_size, 0); + + for (int i = 0; i < mat_size; i++) + { + printf("%d/5 Checking for %.3g --> ", i + 1, y[i]); + char result = 0; + for (int j = 0; j < mat_size && !result; j++) + { + if (fabs(y[i] - eig_vals[j]) < 0.1) + { + result = 1; + printf("(%.3g) ", eig_vals[j]); + } + } + + // ensure that i^th expected eigen value was computed + assert(result != 0); + printf("found\n"); + } + printf("Test 1 Passed in %.3g sec\n\n", dtime); + free(A); +} + +/** + * test function to compute eigen values of a 2x2 matrix + * \f[\begin{bmatrix} + * -4& 4& 2& 0& -3\\ + * 4& -4& 4& -3& -1\\ + * 2& 4& 4& 3& -3\\ + * 0& -3& 3& -1&-1\\ + * -3& -1& -3& -3& 0 + * \end{bmatrix}\f] + * which are approximately, {9.27648, -9.26948, 2.0181, -1.03516, -5.98994} + */ +void test2() +{ + int mat_size = 5; + double X[][5] = {{-4, 4, 2, 0, -3}, + {4, -4, 4, -3, -1}, + {2, 4, 4, 3, -3}, + {0, -3, 3, -1, -3}, + {-3, -1, -3, -3, 0}}; + double y[] = {9.27648, -9.26948, 2.0181, -1.03516, + -5.98994}; // corresponding y-values + double eig_vals[5]; + + // The following steps are to convert a "double[][]" to "double **" + double **A = (double **)malloc(mat_size * sizeof(double *)); + for (int i = 0; i < mat_size; i++) A[i] = X[i]; + + printf("------- Test 2 -------\n"); + + double dtime = eigen_values(A, eig_vals, mat_size, 0); + + for (int i = 0; i < mat_size; i++) + { + printf("%d/5 Checking for %.3g --> ", i + 1, y[i]); + char result = 0; + for (int j = 0; j < mat_size && !result; j++) + { + if (fabs(y[i] - eig_vals[j]) < 0.1) + { + result = 1; + printf("(%.3g) ", eig_vals[j]); + } + } + + // ensure that i^th expected eigen value was computed + assert(result != 0); + printf("found\n"); + } + printf("Test 2 Passed in %.3g sec\n\n", dtime); + free(A); +} + +/** + * main function + */ +int main(int argc, char **argv) +{ + srand(time(NULL)); + + int mat_size = 5; + if (argc == 2) + { + mat_size = atoi(argv[1]); + } + else + { // if invalid input argument is given run tests + test1(); + test2(); + printf("Usage: ./qr_eigen_values [mat_size]\n"); + return 0; + } + + if (mat_size < 2) + { + fprintf(stderr, "Matrix size should be > 2\n"); + return -1; + } + + int i; + + double **A = (double **)malloc(sizeof(double *) * mat_size); + /* number of eigen values = matrix size */ + double *eigen_vals = (double *)malloc(sizeof(double) * mat_size); + if (!eigen_vals) + { + perror("Unable to allocate memory for eigen values!"); + free(A); + return -1; + } + for (i = 0; i < mat_size; i++) + { + A[i] = (double *)malloc(sizeof(double) * mat_size); + eigen_vals[i] = 0.f; + } + + /* create a random matrix */ + create_matrix(A, mat_size); + + print_matrix(A, mat_size, mat_size); + + double dtime = eigen_values(A, eigen_vals, mat_size, 0); + printf("Eigen vals: "); + for (i = 0; i < mat_size; i++) printf("% 9.4g\t", eigen_vals[i]); + printf("\nTime taken to compute: % .4g sec\n", dtime); + + for (int i = 0; i < mat_size; i++) free(A[i]); + free(A); + free(eigen_vals); + return 0; +} diff --git a/numerical_methods/realtime_stats.c b/numerical_methods/realtime_stats.c new file mode 100644 index 0000000000..8306482126 --- /dev/null +++ b/numerical_methods/realtime_stats.c @@ -0,0 +1,158 @@ +/** + * \file + * \brief Compute statistics for data entered in rreal-time + * \author [Krishna Vedala](https://github.com/kvedala) + * + * This algorithm is really beneficial to compute statistics on data read in + * realtime. For example, devices reading biometrics data. The algorithm is + * simple enough to be easily implemented in an embedded system. + */ +#include +#include +#include + +/** + * continuous mean and variance computance using + * first value as an approximation for the mean. + * If the first number is much far form the mean, the algorithm becomes very + * inaccurate to compute variance and standard deviation. + * \param[in] x new value added to data set + * \param[out] mean if not NULL, mean returns mean of data set + * \param[out] variance if not NULL, mean returns variance of data set + * \param[out] std if not NULL, mean returns standard deviation of data set + */ +void stats_computer1(float x, float *mean, float *variance, float *std) +{ + /* following variables declared static becuase they need to be remembered + * when updating for next sample, when received. + */ + static unsigned int n = 0; + static float Ex = 0.f, Ex2 = 0.f; + static float K = 0.f; + + if (n == 0) + K = x; + n++; + float tmp = x - K; + Ex += tmp; + Ex2 += tmp * tmp; + + /* return sample mean computed till last sample */ + if (mean != NULL) + *mean = K + Ex / n; + + /* return data variance computed till last sample */ + if (variance != NULL) + *variance = (Ex2 - (Ex * Ex) / n) / (n - 1); + + /* return sample standard deviation computed till last sample */ + if (std != NULL) + *std = sqrtf(*variance); +} + +/** + * continuous mean and variance computance using + * Welford's algorithm (very accurate) + * \param[in] x new value added to data set + * \param[out] mean if not NULL, mean returns mean of data set + * \param[out] variance if not NULL, mean returns variance of data set + * \param[out] std if not NULL, mean returns standard deviation of data set + */ +void stats_computer2(float x, float *mean, float *variance, float *std) +{ + /* following variables declared static becuase they need to be remembered + * when updating for next sample, when received. + */ + static unsigned int n = 0; + static float mu = 0, M = 0; + + n++; + float delta = x - mu; + mu += delta / n; + float delta2 = x - mu; + M += delta * delta2; + + /* return sample mean computed till last sample */ + if (mean != NULL) + *mean = mu; + + /* return data variance computed till last sample */ + if (variance != NULL) + *variance = M / n; + + /* return sample standard deviation computed till last sample */ + if (std != NULL) + *std = sqrtf(*variance); +} + +/** Test the algorithm implementation + * \param[in] test_data array of data to test the algorithms + * \param[in] number_of_samples number of samples of data + */ +void test_function(const float *test_data, const int number_of_samples) +{ + float ref_mean = 0.f, ref_variance = 0.f; + float s1_mean = 0.f, s1_variance = 0.f, s1_std = 0.f; + float s2_mean = 0.f, s2_variance = 0.f, s2_std = 0.f; + + for (int i = 0; i < number_of_samples; i++) + { + stats_computer1(test_data[i], &s1_mean, &s1_variance, &s1_std); + stats_computer2(test_data[i], &s2_mean, &s2_variance, &s2_std); + ref_mean += test_data[i]; + } + ref_mean /= number_of_samples; + + for (int i = 0; i < number_of_samples; i++) + { + float temp = test_data[i] - ref_mean; + ref_variance += temp * temp; + } + ref_variance /= number_of_samples; + + printf("<<<<<<<< Test Function >>>>>>>>\n"); + printf("Expected: Mean: %.4f\t Variance: %.4f\n", ref_mean, ref_variance); + printf("\tMethod 1:\tMean: %.4f\t Variance: %.4f\t Std: %.4f\n", s1_mean, + s1_variance, s1_std); + printf("\tMethod 2:\tMean: %.4f\t Variance: %.4f\t Std: %.4f\n", s2_mean, + s2_variance, s2_std); + + assert(fabs(s1_mean - ref_mean) < 0.01); + assert(fabs(s2_mean - ref_mean) < 0.01); + assert(fabs(s2_variance - ref_variance) < 0.01); + + printf("(Tests passed)\n\n"); +} + +/** Main function */ +int main(int argc, char **argv) +{ + const float test_data1[] = {3, 4, 5, -1.4, -3.6, 1.9, 1.}; + test_function(test_data1, sizeof(test_data1) / sizeof(test_data1[0])); + + float s1_mean = 0.f, s1_variance = 0.f, s1_std = 0.f; + float s2_mean = 0.f, s2_variance = 0.f, s2_std = 0.f; + + printf("Enter data. Any non-numeric data will terminate the data input.\n"); + + while (1) + { + float val; + printf("Enter number: "); + + // check for failure to read input. Happens for + // non-numeric data + if (!scanf("%f", &val)) + break; + + stats_computer1(val, &s1_mean, &s1_variance, &s1_std); + stats_computer2(val, &s2_mean, &s2_variance, &s2_std); + + printf("\tMethod 1:\tMean: %.4f\t Variance: %.4f\t Std: %.4f\n", + s1_mean, s1_variance, s1_std); + printf("\tMethod 2:\tMean: %.4f\t Variance: %.4f\t Std: %.4f\n", + s2_mean, s2_variance, s2_std); + } + + return 0; +} diff --git a/numerical_methods/secant_method.c b/numerical_methods/secant_method.c new file mode 100644 index 0000000000..946285388c --- /dev/null +++ b/numerical_methods/secant_method.c @@ -0,0 +1,80 @@ +/** + * @file + * @brief [Secant Method](https://en.wikipedia.org/wiki/Secant_method) implementation. Find a + * continuous function's root by using a succession of roots of secant lines to + * approximate it, starting from the given points' secant line. + * @author [Samuel Pires](https://github.com/disnoca) + */ + +#include /// for assert +#include /// for fabs +#include /// for io operations + +#define TOLERANCE 0.0001 // root approximation result tolerance +#define NMAX 100 // maximum number of iterations + +/** + * @brief Continuous function for which we want to find the root + * @param x Real input variable + * @returns The evaluation result of the function using the input value + */ +double func(double x) +{ + return x * x - 3.; // x^2 = 3 - solution is sqrt(3) +} + +/** + * @brief Root-finding method for a continuous function given two points + * @param x0 One of the starting secant points + * @param x1 One of the starting secant points + * @param tolerance Determines how accurate the returned value is. The returned + * value will be within `tolerance` of the actual root + * @returns `root of the function` if secant method succeed within the + * maximum number of iterations + * @returns `-1` if secant method fails + */ +double secant_method(double x0, double x1, double tolerance) +{ + int n = 1; // step counter + + while (n++ < NMAX) + { + // calculate secant line root + double x2 = x1 - func(x1) * (x1 - x0) / (func(x1) - func(x0)); + + // update values + x0 = x1; + x1 = x2; + + // return value if it meets tolerance + if (fabs(x1 - x0) < tolerance) + return x2; + } + + return -1; // method failed (maximum number of steps exceeded) +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() +{ + // compares root values found by the secant method within the tolerance + assert(secant_method(0.2, 0.5, TOLERANCE) - sqrt(3) < TOLERANCE); + assert(fabs(secant_method(-2, -5, TOLERANCE)) - sqrt(3) < TOLERANCE); + assert(secant_method(-3, 2, TOLERANCE) - sqrt(3) < TOLERANCE); + assert(fabs(secant_method(1, -1.5, TOLERANCE)) - sqrt(3) < TOLERANCE); + + printf("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/numerical_methods/simpsons_1_3rd_rule.c b/numerical_methods/simpsons_1_3rd_rule.c new file mode 100644 index 0000000000..b73b4684eb --- /dev/null +++ b/numerical_methods/simpsons_1_3rd_rule.c @@ -0,0 +1,42 @@ +#include +#include + +float f(float x) +{ + return 1.0 + + x * x * x; // This is the expresion of the function to integrate? +} + +int main() +{ + int i, n; + float a, b, h, x, s2, s3, sum, integral; + + printf("enter the lower limit of the integration:"); + scanf("%f", &a); + printf("enter the upper limit of the integration:"); + scanf("%f", &b); + printf("enter the number of intervals:"); + scanf("%d", &n); + + h = (b - a) / n; + sum = f(a) + f(b); + s2 = s3 = 0.0; + + for (i = 1; i < n; i += 3) + { + x = a + i * h; + s3 = s3 + f(x) + f(x + h); + } + + for (i = 3; i < n; i += 3) + { + x = a + i * h; + s2 = s2 + f(x); + } + + integral = (h / 3.0) * (sum + 2 * s2 + 4 * s3); + printf("\nValue of the integral = %9.4f\n", integral); + + return 0; +} \ No newline at end of file diff --git a/numerical_methods/variance.c b/numerical_methods/variance.c new file mode 100644 index 0000000000..6db3bfbf0d --- /dev/null +++ b/numerical_methods/variance.c @@ -0,0 +1,54 @@ +#include +#include +#include + +int main() +{ + int *ARRAY = NULL, ARRAY_LENGTH, i, TEMPORARY_ELEMENT, isSorted = 0; + float MEAN = 0, VARIANCE = 0, STAND; + + printf("Enter no. for Random Numbers :"); + scanf("%d", &ARRAY_LENGTH); + ARRAY = (int *)realloc( + ARRAY, + ARRAY_LENGTH * (sizeof(int))); // We allocate the dedicated memory + for (i = 0; i < ARRAY_LENGTH; i++) // We generate the random numbers + ARRAY[i] = rand() % 100; + + printf("Random Numbers Generated are :\n"); // We display them + for (i = 0; i < ARRAY_LENGTH; i++) printf("%d ", ARRAY[i]); + + printf("\nSorted Data: "); // Then we sort it using Bubble Sort.. + + while (!isSorted) + { // While our array's not sorted + isSorted = 1; // we suppose that it's sorted + for (i = 0; i < ARRAY_LENGTH - 1; i++) + { // then for each element of the array + if (ARRAY[i] > ARRAY[i + 1]) + { // if the two elements aren't sorted + isSorted = 0; // it means that the array is not sorted + TEMPORARY_ELEMENT = ARRAY[i]; // and we switch these elements + // using TEMPORARY_ELEMENT + ARRAY[i] = ARRAY[i + 1]; + ARRAY[i + 1] = TEMPORARY_ELEMENT; + } + } + } + for (i = 0; i < ARRAY_LENGTH; i++) + { + printf("%d ", ARRAY[i]); + MEAN = MEAN + ARRAY[i]; + } + MEAN = MEAN / (float)ARRAY_LENGTH; + + for (i = 0; i < ARRAY_LENGTH; i++) + VARIANCE = VARIANCE + (pow((ARRAY[i] - MEAN), 2)); + + VARIANCE = VARIANCE / (float)ARRAY_LENGTH; + STAND = sqrt(VARIANCE); + + printf("\n\n- Mean is: %f\n", MEAN); + printf("- Variance is: %f\n", VARIANCE); + printf("- Standard Deviation is: %f\n", STAND); +} diff --git a/process_scheduling_algorithms/CMakeLists.txt b/process_scheduling_algorithms/CMakeLists.txt new file mode 100644 index 0000000000..1d2a56e057 --- /dev/null +++ b/process_scheduling_algorithms/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} *.c ) +# 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 ".c" "" testname ${testsourcefile} ) + add_executable( ${testname} ${testsourcefile} ) + + if(OpenMP_C_FOUND) + target_link_libraries(${testname} OpenMP::OpenMP_C) + endif() + if(MATH_LIBRARY) + target_link_libraries(${testname} ${MATH_LIBRARY}) + endif() + install(TARGETS ${testname} DESTINATION "bin/process_scheduling_algorithms") + +endforeach( testsourcefile ${APP_SOURCES} ) diff --git a/process_scheduling_algorithms/non_preemptive_priority_scheduling.c b/process_scheduling_algorithms/non_preemptive_priority_scheduling.c new file mode 100644 index 0000000000..2dd8ee8fc0 --- /dev/null +++ b/process_scheduling_algorithms/non_preemptive_priority_scheduling.c @@ -0,0 +1,369 @@ +/** + * @file + * @brief + * [Non-Preemptive Priority + * Scheduling](https://en.wikipedia.org/wiki/Scheduling_(computing)) + * is a scheduling algorithm that selects the tasks to execute based on + * priority. + * + * @details + * In this algorithm, processes are executed according to their + * priority. The process with the highest priority is to be executed first and + * so on. In this algorithm, a variable is maintained known as the time quantum. + * The length of the time quantum is decided by the user. The process which is + * being executed is interrupted after the expiration of the time quantum and + * the next process with the highest priority is executed. This cycle of + * interrupting the process after every time quantum and resuming the next + * process with the highest priority continues until all the processes have + * been executed. + * @author [Aryan Raj](https://github.com/aryaraj132) + */ +#include /// for assert +#include /// for boolean data type +#include /// for IO operations (`printf`) +#include /// for memory allocation eg: `malloc`, `realloc`, `free`, `exit` +/** + * @brief Structure to represent a process + */ + typedef struct node { + int ID; ///< ID of the process node + int AT; ///< Arrival Time of the process node + int BT; ///< Burst Time of the process node + int priority; ///< Priority of the process node + int CT; ///< Completion Time of the process node + int WT; ///< Waiting Time of the process node + int TAT; ///< Turn Around Time of the process node + struct node *next; ///< pointer to the node + } node; + +/** + * @brief To insert a new process in the queue + * @param root pointer to the head of the queue + * @param id process ID + * @param at arrival time + * @param bt burst time + * @param prior priority of the process + * @returns void + */ +void insert(node **root, int id, int at, int bt, int prior) +{ + // create a new node and initialize it + node *new = (node *)malloc(sizeof(node)); + node *ptr = *root; + new->ID = id; + new->AT = at; + new->BT = bt; + new->priority = prior; + new->next = NULL; + new->CT = 0; + new->WT = 0; + new->TAT = 0; + // if the root is null, make the new node the root + if (*root == NULL) + { + *root = new; + return; + } + // else traverse to the end of the queue and insert the new node there + while (ptr->next != NULL) + { + ptr = ptr->next; + } + ptr->next = new; + return; +} +/* + * @brief To delete a process from the queue + * @param root pointer to the head of the queue + * @param id process ID + * @returns void + */ +void delete(node **root, int id) +{ + node *ptr = *root, *prev; + // if the root is null, return + if (ptr == NULL) + { + return; + } + // if the root is the process to be deleted, make the next node the root + if (ptr->ID == id) + { + *root = ptr->next; + free(ptr); + return; + } + // else traverse the queue and delete the process + while (ptr != NULL && ptr->ID != id) + { + prev = ptr; + ptr = ptr->next; + } + if (ptr == NULL) + { + return; + } + prev->next = ptr->next; + free(ptr); +} +/** + * @brief To show the process queue + * @param head pointer to the head of the queue + * @returns void + */ +void show_list(node *head) +{ + printf("Process Priority AT BT CT TAT WT \n"); + while (head != NULL) + { + printf("P%d. %d %d %d %d %d %d \n", head->ID, head->priority, head->AT, + head->BT, head->CT, head->TAT, head->WT); + head = head->next; + } +} +/** + * @brief To length process queue + * @param root pointer to the head of the queue + * @returns int total length of the queue + */ +int l_length(node **root) +{ + int count = 0; + node *ptr = *root; + while (ptr != NULL) + { + count++; + ptr = ptr->next; + } + return count; +} +/** + * @brief To update the completion time, turn around time and waiting time of + * the processes + * @param root pointer to the head of the queue + * @param id process ID + * @param ct current time + * @param wt waiting time + * @param tat turn around time + * @returns void + */ +void update(node **root, int id, int ct, int wt, int tat) +{ + node *ptr = *root; + // If process to be updated is head node + if (ptr != NULL && ptr->ID == id) + { + if (ct != 0) + { + ptr->CT = ct; + } + if (wt != 0) + { + ptr->WT = wt; + } + if (tat != 0) + { + ptr->TAT = tat; + } + return; + } + // else traverse the queue and update the values + while (ptr != NULL && ptr->ID != id) + { + ptr = ptr->next; + } + if (ct != 0) + { + ptr->CT = ct; + } + if (wt != 0) + { + ptr->WT = wt; + } + if (tat != 0) + { + ptr->TAT = tat; + } + return; +} +/** + * @brief To compare the priority of two processes based on their arrival time + * and priority + * @param a pointer to the first process + * @param b pointer to the second process + * @returns true if the priority of the first process is greater than the + * the second process + * @returns false if the priority of the first process is NOT greater than the + * second process + */ +bool compare(node *a, node *b) +{ + if (a->AT == b->AT) + { + return a->priority < b->priority; + } + else + { + return a->AT < b->AT; + } +} +/** + * @brief To calculate the average completion time of all the processes + * @param root pointer to the head of the queue + * @returns float average completion time + */ +float calculate_ct(node **root) +{ + // calculate the total completion time of all the processes + node *ptr = *root, *prior, *rpt; + int ct = 0, i, time = 0; + int n = l_length(root); + float avg, sum = 0; + node *duproot = NULL; + // create a duplicate queue + while (ptr != NULL) + { + insert(&duproot, ptr->ID, ptr->AT, ptr->BT, ptr->priority); + ptr = ptr->next; + } + ptr = duproot; + rpt = ptr->next; + // sort the queue based on the arrival time and priority + while (rpt != NULL) + { + if (!compare(ptr, rpt)) + { + ptr = rpt; + } + rpt = rpt->next; + } + // ptr is the process to be executed first. + ct = ptr->AT + ptr->BT; + time = ct; + sum += ct; + // update the completion time, turn around time and waiting time of the + // process + update(root, ptr->ID, ct, 0, 0); + delete (&duproot, ptr->ID); + // repeat the process until all the processes are executed + for (i = 0; i < n - 1; i++) + { + ptr = duproot; + while (ptr != NULL && ptr->AT > time) + { + ptr = ptr->next; + } + rpt = ptr->next; + while (rpt != NULL) + { + if (rpt->AT <= time) + { + if (rpt->priority < ptr->priority) + { + ptr = rpt; + } + } + rpt = rpt->next; + } + ct += ptr->BT; + time += ptr->BT; + sum += ct; + update(root, ptr->ID, ct, 0, 0); + delete (&duproot, ptr->ID); + } + avg = sum / n; + return avg; +} +/** + * @brief To calculate the average turn around time of all the processes + * @param root pointer to the head of the queue + * @returns float average turn around time + */ +float calculate_tat(node **root) +{ + float avg, sum = 0; + int n = l_length(root); + node *ptr = *root; + // calculate the completion time if not already calculated + if (ptr->CT == 0) + { + calculate_ct(root); + } + // calculate the total turn around time of all the processes + while (ptr != NULL) + { + ptr->TAT = ptr->CT - ptr->AT; + sum += ptr->TAT; + ptr = ptr->next; + } + avg = sum / n; + return avg; +} +/** + * @brief To calculate the average waiting time of all the processes + * @param root pointer to the head of the queue + * @returns float average waiting time + */ +float calculate_wt(node **root) +{ + float avg, sum = 0; + int n = l_length(root); + node *ptr = *root; + // calculate the completion if not already calculated + if (ptr->CT == 0) + { + calculate_ct(root); + } + // calculate the total waiting time of all the processes + while (ptr != NULL) + { + ptr->WT = (ptr->TAT - ptr->BT); + sum += ptr->WT; + ptr = ptr->next; + } + avg = sum / n; + return avg; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() +{ + // Entered processes + // printf("ID Priority Arrival Time Burst Time \n"); + // printf("1 0 5 1 \n"); + // printf("2 1 4 2 \n"); + // printf("3 2 3 3 \n"); + // printf("4 3 2 4 \n"); + // printf("5 4 1 5 \n"); + + node *root = NULL; + insert(&root, 1, 0, 5, 1); + insert(&root, 2, 1, 4, 2); + insert(&root, 3, 2, 3, 3); + insert(&root, 4, 3, 2, 4); + insert(&root, 5, 4, 1, 5); + float avgCT = calculate_ct(&root); + float avgTAT = calculate_tat(&root); + float avgWT = calculate_wt(&root); + assert(avgCT == 11); + assert(avgTAT == 9); + assert(avgWT == 6); + printf("[+] All tests have successfully passed!\n"); + // printf("Average Completion Time is : %f \n", calculate_ct(&root)); + // printf("Average Turn Around Time is : %f \n", calculate_tat(&root)); + // printf("Average Waiting Time is : %f \n", calculate_wt(&root)); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + test(); // run self-test implementations + + return 0; +} diff --git a/project_euler/CMakeLists.txt b/project_euler/CMakeLists.txt new file mode 100644 index 0000000000..938b67e1d5 --- /dev/null +++ b/project_euler/CMakeLists.txt @@ -0,0 +1,24 @@ +# 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_RECURSE APP_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.c ) +# 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 ".c" "" testname ${testsourcefile} ) + string( REPLACE "/" "-" testname ${testname} ) + string( REPLACE "\\" "-" testname ${testname} ) + string( REPLACE " " "_" testname ${testname} ) + add_executable( ${testname} ${testsourcefile} ) + + if(OpenMP_C_FOUND) + target_link_libraries(${testname} OpenMP::OpenMP_C) + endif() + + if(MATH_LIBRARY) + target_link_libraries(${testname} ${MATH_LIBRARY}) + endif() + install(TARGETS ${testname} DESTINATION "bin/project_euler") + +endforeach( testsourcefile ${APP_SOURCES} ) diff --git a/project_euler/Problem 01/sol1.c b/project_euler/Problem 01/sol1.c deleted file mode 100644 index 813f4cbe43..0000000000 --- a/project_euler/Problem 01/sol1.c +++ /dev/null @@ -1,24 +0,0 @@ -/*An Efficient code to print all the sum of all numbers that are multiples of 3 & 5 below N.*/ - -#include - -int main(){ - int t; - scanf("%d",&t); - while(t--) - { - unsigned long long N,p=0,sum=0; - - scanf("%lld",&N); //Take input of N from user - p = (N-1)/3; - sum = ((3*p*(p+1))/2); - - p = (N-1)/5; - sum = sum + ((5*p*(p+1))/2); - - p = (N-1)/15; - sum = sum - ((15*p*(p+1))/2); - printf("%lld\n", sum); //print the sum of all numbers that are multiples of 3 & 5 below N - } - return 0; -} diff --git a/project_euler/Problem 01/sol2.c b/project_euler/Problem 01/sol2.c deleted file mode 100644 index af1fb71e4e..0000000000 --- a/project_euler/Problem 01/sol2.c +++ /dev/null @@ -1,24 +0,0 @@ -/* -If we list all the natural numbers below 10 that are multiples of 3 or 5, -we get 3,5,6 and 9. The sum of these multiples is 23. -Find the sum of all the multiples of 3 or 5 below N. -''' -''' -This solution is based on the pattern that the successive numbers in the series follow: 0+3,+2,+1,+3,+1,+2,+3. -*/ -#include - -int main() { - int n = 0; - int sum = 0; - scanf("%d", &n); - - int terms = (n - 1) / 3; - sum += ((terms)*(6 + (terms - 1) * 3)) / 2; //sum of an A.P. - terms = (n - 1) / 5; - sum += ((terms)*(10 + (terms - 1) * 5)) / 2; - terms = (n - 1) / 15; - sum -= ((terms)*(30 + (terms - 1) * 15)) / 2; - - printf("%d\n", sum); -} \ No newline at end of file diff --git a/project_euler/Problem 01/sol3.c b/project_euler/Problem 01/sol3.c deleted file mode 100644 index 04c12bf45a..0000000000 --- a/project_euler/Problem 01/sol3.c +++ /dev/null @@ -1,49 +0,0 @@ -/* -If we list all the natural numbers below 10 that are multiples of 3 or 5, -we get 3,5,6 and 9. The sum of these multiples is 23. -Find the sum of all the multiples of 3 or 5 below N. -''' -''' -This solution is based on the pattern that the successive numbers in the series follow: 0+3,+2,+1,+3,+1,+2,+3. -*/ -#include - -int main() { - int n = 0; - int sum = 0; - int num = 0; - scanf("%d", &n); - - while (1) { - num += 3; - if (num >= n) - break; - sum += num; - num += 2; - if (num >= n) - break; - sum += num; - num += 1; - if (num >= n) - break; - sum += num; - num += 3; - if (num >= n) - break; - sum += num; - num += 1; - if (num >= n) - break; - sum += num; - num += 2; - if (num >= n) - break; - sum += num; - num += 3; - if (num >= n) - break; - sum += num; - } - - printf("%d\n", sum); -} \ No newline at end of file diff --git a/project_euler/Problem 02/so1.c b/project_euler/Problem 02/so1.c deleted file mode 100644 index 5a9029352b..0000000000 --- a/project_euler/Problem 02/so1.c +++ /dev/null @@ -1,28 +0,0 @@ -/* -Problem: -Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, -the first 10 terms will be: -1,2,3,5,8,13,21,34,55,89,.. -By considering the terms in the Fibonacci sequence whose values do not exceed n, find the sum of the even-valued terms. -e.g. for n=10, we have {2,8}, sum is 10. -*/ -#include - -int main() { - int n = 0; - int sum = 0; - int i = 1; - int j = 2; - int temp; - scanf("%d", &n); - - while (j <= n) { - if ((j & 1) == 0) //can also use(j%2 == 0) - sum += j; - temp = i; - i = j; - j = temp + i; - } - - printf("%d\n", sum); -} \ No newline at end of file diff --git a/project_euler/Problem 03/sol1.c b/project_euler/Problem 03/sol1.c deleted file mode 100644 index 369ec72d6a..0000000000 --- a/project_euler/Problem 03/sol1.c +++ /dev/null @@ -1,57 +0,0 @@ -/* -Problem: -The prime factors of 13195 are 5,7,13 and 29. What is the largest prime factor of a given number N? -e.g. for 10, largest prime factor = 5. For 17, largest prime factor = 17. -*/ -#include -#include - -int isprime(int no) { - int sq; - - if (no == 2) { - return 1; - } - else if (no%2 == 0) { - return 0; - } - sq = ((int)(sqrt(no))) + 1; - for (int i = 3; i < sq; i + 2) { - if (no%i == 0) { - return 0; - } - } - return 1; -} - -int main() { - int maxNumber = 0; - int n = 0; - int n1; - scanf("%d", &n); - if (isprime(n) == 1) - printf("%d", n); - else { - while (n % 2 == 0) { - n = n / 2; - } - if (isprime(n) == 1) { - printf("%d\n", n); - } - else { - n1 = ((int)(sqrt(n))) + 1; - for (int i = 3; i < n1; i + 2) { - if (n%i == 0) { - if (isprime((int)(n / i)) == 1) { - maxNumber = n / i; - break; - } - else if (isprime(i) == 1) { - maxNumber = i; - } - } - } - printf("%d\n", maxNumber); - } - } -} \ No newline at end of file diff --git a/project_euler/Problem 03/sol2.c b/project_euler/Problem 03/sol2.c deleted file mode 100644 index d8ccd4ce0d..0000000000 --- a/project_euler/Problem 03/sol2.c +++ /dev/null @@ -1,23 +0,0 @@ -/* -Problem: -The prime factors of 13195 are 5,7,13 and 29. What is the largest prime factor of a given number N? -e.g. for 10, largest prime factor = 5. For 17, largest prime factor = 17. -*/ -#include - -int main() { - int n = 0; - scanf("%d", &n); - int prime = 1; - int i = 2; - while (i*i <= n) { - while (n%i == 0) { - prime = i; - n /= i; - } - i += 1; - } - if (n > 1) - prime = n; - printf("%d\n", prime); -} \ No newline at end of file diff --git a/project_euler/problem_1/sol1.c b/project_euler/problem_1/sol1.c new file mode 100644 index 0000000000..b24891fe87 --- /dev/null +++ b/project_euler/problem_1/sol1.c @@ -0,0 +1,35 @@ +/** + * \file + * \brief [Problem 1](https://projecteuler.net/problem=1) solution + * \details + * An Efficient code to print all the sum of all numbers that are multiples of 3 + * & 5 below N. + */ + +#include + +/** Main function */ +int main() +{ + int t; + printf("Enter number of times you want to try"); + scanf("%d", &t); + while (t--) // while t > 0, decrement 't' before every iteration + { + unsigned long long N, p = 0, sum = 0; + printf("Enter the value of N "); + + scanf("%lld", &N); // Take input of N from user + p = (N - 1) / 3; + sum = ((3 * p * (p + 1)) / 2); + + p = (N - 1) / 5; + sum = sum + ((5 * p * (p + 1)) / 2); + + p = (N - 1) / 15; + sum = sum - ((15 * p * (p + 1)) / 2); + printf("%lld\n", sum); // print the sum of all numbers that are + // multiples of 3 & 5 below N + } + return 0; +} diff --git a/project_euler/problem_1/sol2.c b/project_euler/problem_1/sol2.c new file mode 100644 index 0000000000..72ca678b1c --- /dev/null +++ b/project_euler/problem_1/sol2.c @@ -0,0 +1,29 @@ +/** + * \file + * \brief [Problem 1](https://projecteuler.net/problem=1) solution + * + * If we list all the natural numbers below 10 that are multiples of 3 or 5, + * we get 3,5,6 and 9. The sum of these multiples is 23. + * Find the sum of all the multiples of 3 or 5 below N. + * + * This solution is based on the pattern that the successive numbers in the + * series follow: 0+3,+2,+1,+3,+1,+2,+3. + */ +#include + +/** Main function */ +int main() +{ + int n = 0; + int sum = 0; + scanf("%d", &n); + + int terms = (n - 1) / 3; + sum += ((terms) * (6 + (terms - 1) * 3)) / 2; // sum of an A.P. + terms = (n - 1) / 5; + sum += ((terms) * (10 + (terms - 1) * 5)) / 2; + terms = (n - 1) / 15; + sum -= ((terms) * (30 + (terms - 1) * 15)) / 2; + + printf("%d\n", sum); +} \ No newline at end of file diff --git a/project_euler/problem_1/sol3.c b/project_euler/problem_1/sol3.c new file mode 100644 index 0000000000..c4c4dc74a4 --- /dev/null +++ b/project_euler/problem_1/sol3.c @@ -0,0 +1,55 @@ +/** + * \file + * \brief [Problem 1](https://projecteuler.net/problem=1) solution. + * This solution is based on the pattern that the successive numbers in the + * series follow: 0+3,+2,+1,+3,+1,+2,+3. + * + * If we list all the natural numbers below 10 that are multiples of 3 or 5, + * we get 3,5,6 and 9. The sum of these multiples is 23. + * Find the sum of all the multiples of 3 or 5 below N. + */ +#include + +/** Main function */ +int main() +{ + int n = 0; + int sum = 0; + int num = 0; + scanf("%d", &n); + + while (1) + { + num += 3; + if (num >= n) + break; + sum += num; + num += 2; + if (num >= n) + break; + sum += num; + num += 1; + if (num >= n) + break; + sum += num; + num += 3; + if (num >= n) + break; + sum += num; + num += 1; + if (num >= n) + break; + sum += num; + num += 2; + if (num >= n) + break; + sum += num; + num += 3; + if (num >= n) + break; + sum += num; + } + + printf("%d\n", sum); + return 0; +} \ No newline at end of file diff --git a/project_euler/problem_1/sol4.c b/project_euler/problem_1/sol4.c new file mode 100644 index 0000000000..2775801642 --- /dev/null +++ b/project_euler/problem_1/sol4.c @@ -0,0 +1,34 @@ +/** + * \file + * \brief [Problem 1](https://projecteuler.net/problem=1) solution + * + * An Efficient code to print all the sum of all numbers that are multiples of 3 + * & 5 below N. + */ + +#include + +/** Main function */ +int main() +{ + int t; + printf("Enter number of times you want to try"); + scanf("%d", &t); + while (t--) + { + unsigned long long N, p = 0, sum = 0; + printf("Enter the value of N "); + + scanf("%lld", &N); // Take input of N from user + for (int i = 0; i < N; i++) + { + if (i % 3 == 0 || i % 5 == 0) + { + sum = sum + i; + } + } + printf("%lld\n", sum); // print the sum of all numbers that are + // multiples of 3 & 5 below N + } + return 0; +} diff --git a/project_euler/problem_10/sol1.c b/project_euler/problem_10/sol1.c new file mode 100644 index 0000000000..560582bc8d --- /dev/null +++ b/project_euler/problem_10/sol1.c @@ -0,0 +1,43 @@ +/** + * \file + * \brief [Problem 10](https://projecteuler.net/problem=10) solution + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include +#include +#include + +/** Function to check if a number is prime */ +char is_prime(unsigned long n) +{ + for (unsigned long i = 2; i < sqrtl(n) + 1; i++) + if (n % i == 0) + return 0; + + return 1; +} + +/** Computes sum of prime numbers less than N */ +unsigned long long sum_of_primes(unsigned long N) +{ + unsigned long long sum = 2; + + for (long i = 3; i < N; i += 2) /* skip even numbers */ + if (is_prime(i)) + sum += i; + + return sum; +} + +/** Main function */ +int main(int argc, char *argv[]) +{ + unsigned long n = 100; + + if (argc == 2) /* if command line argument is provided */ + n = atol(argv[1]); /* use that as the upper limit */ + + printf("%ld: %llu\n", n, sum_of_primes(n)); + + return 0; +} \ No newline at end of file diff --git a/project_euler/problem_10/sol2.c b/project_euler/problem_10/sol2.c new file mode 100644 index 0000000000..6c0cda64ea --- /dev/null +++ b/project_euler/problem_10/sol2.c @@ -0,0 +1,56 @@ +/** + * \file + * \brief [Problem 10](https://projecteuler.net/problem=10) solution + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include +#include +#include + +/** Main function */ +int main(int argc, char *argv[]) +{ + long n = 100; + long long sum = 0; + char *sieve = NULL; + + if (argc == 2) /* if command line argument is provided */ + n = atol(argv[1]); /* use that as the upper limit */ + + /* allocate memory for the sieve */ + sieve = calloc(n, sizeof(*sieve)); + if (!sieve) + { + perror("Unable to allocate memory!"); + return -1; + } + + /* build sieve of Eratosthenes + In the array, + * if i^th cell is '1', then 'i' is composite + * if i^th cell is '0', then 'i' is prime + */ + for (long i = 2; i < sqrtl(n); i++) + { + /* if i^th element is prime, mark all its multiples + as composites */ + if (!sieve[i]) + { + for (long j = i * i; j < n + 1; j += i) + { + sieve[j] = 1; + } + sum += i; + } + } + + for (long i = sqrtl(n) + 1; i < n; i++) + if (!sieve[i]) + sum += i; + + free(sieve); + + printf("%ld: %lld\n", n, sum); + + return 0; +} diff --git a/project_euler/problem_12/sol1.c b/project_euler/problem_12/sol1.c new file mode 100644 index 0000000000..d00814acfc --- /dev/null +++ b/project_euler/problem_12/sol1.c @@ -0,0 +1,55 @@ +/** + * \file + * \brief [Problem 12](https://projecteuler.net/problem=12) solution + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include +#include +#include + +/** + * Get number of divisors of a given number + * + * If \f$x = a \times b\f$, then both \f$a\f$ and \f$b\f$ are divisors of + * \f$x\f$. Since multiplication is commutative, we only need to search till a + * maximum of \f$a=b = a^2\f$ i.e., till \f$\sqrt{x}\f$. At every integer till + * then, there are eaxctly 2 divisors and at \f$a=b\f$, there is only one + * divisor. + */ +long count_divisors(long long n) +{ + long num_divisors = 0; + + for (long long i = 1; i < sqrtl(n) + 1; i++) + if (n % i == 0) + num_divisors += 2; + else if (i * i == n) + num_divisors += 1; + + return num_divisors; +} + +/** Main function */ +int main(int argc, char **argv) +{ + int MAX_DIVISORS = 500; + long i = 1, num_divisors; + long long triangle_number = 1; + + if (argc == 2) + MAX_DIVISORS = atoi(argv[1]); + + while (1) + { + i++; + triangle_number += i; + num_divisors = count_divisors(triangle_number); + if (num_divisors > MAX_DIVISORS) + break; + } + + printf("First Triangle number with more than %d divisors: %lld\n", + MAX_DIVISORS, triangle_number); + + return 0; +} diff --git a/project_euler/problem_13/num.txt b/project_euler/problem_13/num.txt new file mode 100644 index 0000000000..bb9d196a41 --- /dev/null +++ b/project_euler/problem_13/num.txt @@ -0,0 +1,100 @@ +37107287533902102798797998220837590246510135740250 +46376937677490009712648124896970078050417018260538 +74324986199524741059474233309513058123726617309629 +91942213363574161572522430563301811072406154908250 +23067588207539346171171980310421047513778063246676 +89261670696623633820136378418383684178734361726757 +28112879812849979408065481931592621691275889832738 +44274228917432520321923589422876796487670272189318 +47451445736001306439091167216856844588711603153276 +70386486105843025439939619828917593665686757934951 +62176457141856560629502157223196586755079324193331 +64906352462741904929101432445813822663347944758178 +92575867718337217661963751590579239728245598838407 +58203565325359399008402633568948830189458628227828 +80181199384826282014278194139940567587151170094390 +35398664372827112653829987240784473053190104293586 +86515506006295864861532075273371959191420517255829 +71693888707715466499115593487603532921714970056938 +54370070576826684624621495650076471787294438377604 +53282654108756828443191190634694037855217779295145 +36123272525000296071075082563815656710885258350721 +45876576172410976447339110607218265236877223636045 +17423706905851860660448207621209813287860733969412 +81142660418086830619328460811191061556940512689692 +51934325451728388641918047049293215058642563049483 +62467221648435076201727918039944693004732956340691 +15732444386908125794514089057706229429197107928209 +55037687525678773091862540744969844508330393682126 +18336384825330154686196124348767681297534375946515 +80386287592878490201521685554828717201219257766954 +78182833757993103614740356856449095527097864797581 +16726320100436897842553539920931837441497806860984 +48403098129077791799088218795327364475675590848030 +87086987551392711854517078544161852424320693150332 +59959406895756536782107074926966537676326235447210 +69793950679652694742597709739166693763042633987085 +41052684708299085211399427365734116182760315001271 +65378607361501080857009149939512557028198746004375 +35829035317434717326932123578154982629742552737307 +94953759765105305946966067683156574377167401875275 +88902802571733229619176668713819931811048770190271 +25267680276078003013678680992525463401061632866526 +36270218540497705585629946580636237993140746255962 +24074486908231174977792365466257246923322810917141 +91430288197103288597806669760892938638285025333403 +34413065578016127815921815005561868836468420090470 +23053081172816430487623791969842487255036638784583 +11487696932154902810424020138335124462181441773470 +63783299490636259666498587618221225225512486764533 +67720186971698544312419572409913959008952310058822 +95548255300263520781532296796249481641953868218774 +76085327132285723110424803456124867697064507995236 +37774242535411291684276865538926205024910326572967 +23701913275725675285653248258265463092207058596522 +29798860272258331913126375147341994889534765745501 +18495701454879288984856827726077713721403798879715 +38298203783031473527721580348144513491373226651381 +34829543829199918180278916522431027392251122869539 +40957953066405232632538044100059654939159879593635 +29746152185502371307642255121183693803580388584903 +41698116222072977186158236678424689157993532961922 +62467957194401269043877107275048102390895523597457 +23189706772547915061505504953922979530901129967519 +86188088225875314529584099251203829009407770775672 +11306739708304724483816533873502340845647058077308 +82959174767140363198008187129011875491310547126581 +97623331044818386269515456334926366572897563400500 +42846280183517070527831839425882145521227251250327 +55121603546981200581762165212827652751691296897789 +32238195734329339946437501907836945765883352399886 +75506164965184775180738168837861091527357929701337 +62177842752192623401942399639168044983993173312731 +32924185707147349566916674687634660915035914677504 +99518671430235219628894890102423325116913619626622 +73267460800591547471830798392868535206946944540724 +76841822524674417161514036427982273348055556214818 +97142617910342598647204516893989422179826088076852 +87783646182799346313767754307809363333018982642090 +10848802521674670883215120185883543223812876952786 +71329612474782464538636993009049310363619763878039 +62184073572399794223406235393808339651327408011116 +66627891981488087797941876876144230030984490851411 +60661826293682836764744779239180335110989069790714 +85786944089552990653640447425576083659976645795096 +66024396409905389607120198219976047599490197230297 +64913982680032973156037120041377903785566085089252 +16730939319872750275468906903707539413042652315011 +94809377245048795150954100921645863754710598436791 +78639167021187492431995700641917969777599028300699 +15368713711936614952811305876380278410754449733078 +40789923115535562561142322423255033685442488917353 +44889911501440648020369068063960672322193204149535 +41503128880339536053299340368006977710650566631954 +81234880673210146739058568557934581403627822703280 +82616570773948327592232845941706525094512325230608 +22918802058777319719839450180888072429661980811197 +77158542502016545090413245809786882778948721859617 +72107838435069186155435662884062257473692284509516 +20849603980134001723930671666823555245252804609722 +53503534226472524250874054075591789781264330331690 \ No newline at end of file diff --git a/project_euler/problem_13/sol1.c b/project_euler/problem_13/sol1.c new file mode 100644 index 0000000000..b342067263 --- /dev/null +++ b/project_euler/problem_13/sol1.c @@ -0,0 +1,172 @@ +/** + * \file + * \brief [Problem 13](https://projecteuler.net/problem=13) solution + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include +#include +#include +#include + +/** Function to read the number from a file and store it in array. + \n index 0 of output buffer => units place + \n index 1 of output buffer => tens place and so on + i.e., index i => 10^i th place + */ +int get_number(FILE *fp, char *buffer, uint8_t *out_int) +{ + long l = fscanf(fp, "%s\n", buffer); + if (!l) + { + perror("Error reading line."); + return -1; + } + // printf("Number: %s\t length: %ld, %ld\n", buffer, strlen(buffer), l); + + long L = strlen(buffer); + + for (int i = 0; i < L; i++) + { + if (buffer[i] < 0x30 || buffer[i] > 0x39) + { + perror("found inavlid character in the number!"); + return -1; + } + else + { + out_int[L - i - 1] = buffer[i] - 0x30; + } + } + + return 0; +} + +/** + * Function to add arbitrary length decimal integers stored in an array. + * a + b = c = new b + */ +int add_numbers(uint8_t *a, uint8_t *b, uint8_t N) +{ + int carry = 0; + uint8_t *c = b; /* accumulate the result in the array 'b' */ + + for (int i = 0; i < N; i++) + { + // printf("\t%d + %d + %d ", a[i], b[i], carry); + c[i] = carry + a[i] + b[i]; // NOLINT // This is a known false-positive + if (c[i] > 9) /* check for carry */ + { + carry = 1; + c[i] -= 10; + } + else + { + carry = 0; + } + // printf("= %d, %d\n", carry, c[i]); + } + + for (int i = N; i < N + 10; i++) + { + if (carry == 0) + { + break; + } + // printf("\t0 + %d + %d ", b[i], carry); + c[i] = carry + c[i]; + if (c[i] > 9) + { + carry = 1; + c[i] -= 10; + } + else + { + carry = 0; + } + // printf("= %d, %d\n", carry, c[i]); + } + return 0; +} + +/** Function to print a long number */ +int print_number(uint8_t *number, uint8_t N, int8_t num_digits_to_print) +{ + uint8_t start_pos = N - 1; + uint8_t end_pos; + + /* skip all initial zeros */ + while (number[start_pos] == 0) start_pos--; + + /* if end_pos < 0, print all digits */ + if (num_digits_to_print < 0) + { + end_pos = 0; + } + else if (num_digits_to_print <= start_pos) + { + end_pos = start_pos - num_digits_to_print + 1; + } + else + { + fprintf(stderr, "invalid number of digits argumet!\n"); + return -1; + } + + for (int i = start_pos; i >= end_pos; i--) putchar(number[i] + 0x30); + + putchar('\n'); + + return 0; +} + +/** Main function */ +int main(void) +{ + /* number of digits of the large number */ + const int N = 10; + /* number of digits in output number */ + const int N2 = N + 10; + + // const char N = 50, N2 = N+10; /* length of numbers */ + char *txt_buffer = + (char *)calloc(N + 5, sizeof(char)); /* temporary buffer */ + uint8_t *number = (uint8_t *)calloc( + N, sizeof(uint8_t)); /* array to store digits of a large number */ + uint8_t *sum = (uint8_t *)calloc( + N2, sizeof(uint8_t)); /* array to store the sum of the large +numbers. For safety, we make it twice the length of a number. */ + + FILE *fp = fopen("num.txt", "rt"); /* open text file to read */ + if (!fp) + { + perror("Unable to open file 'num.txt'."); + free(txt_buffer); + free(sum); + free(number); + return -1; + } + + int count = 0; + get_number(fp, txt_buffer, sum); /* 0 + = first_number = first_number */ + do + { + count++; + if (get_number(fp, txt_buffer, number) != 0) + { + break; + } + add_numbers(number, sum, N); + } while (!feof(fp)); + + printf("\nSum : "); + print_number(sum, N2, -1); + + printf("first 10 digits: \t"); + print_number(sum, N2, 10); + + fclose(fp); /* close file */ + free(txt_buffer); + free(sum); + free(number); + return 0; +} diff --git a/project_euler/problem_14/sol1.c b/project_euler/problem_14/sol1.c new file mode 100644 index 0000000000..f999dcbfca --- /dev/null +++ b/project_euler/problem_14/sol1.c @@ -0,0 +1,79 @@ +/** + * \file + * \brief [Problem 14](https://projecteuler.net/problem=14) solution + * \author [Krishna Vedala](https://github.com/kvedala) + * + * Since the computational values for each iteration step are independent, + * we can compute them in parallel. However, the maximum values should be + * updated in synchrony so that we do not get into a "race condition". + * + * To compile with supporintg gcc or clang, the flag "-fopenmp" should be + * passes while with Microsoft C compiler, the flag "/fopenmp" should be + * used. If you are using the provided CMAKE compilation, it will automatically + * detect OPENMP and compile with it for you. + * + * Automatically detects for OPENMP using the _OPENMP macro. + */ +#include +#include +#ifdef _OPENMP +#include +#endif + +/** + * Computes the length of collatz sequence for a given + * starting number + */ +long long collatz(long long start_num) +{ + long long length = 1; + + while (start_num != 1) /* loop till we reach 1 */ + { + if (start_num & 0x01) /* check for odd */ + start_num = 3 * start_num + 1; + else + start_num >>= 1; /* simpler divide by 2 */ + length++; + } + + return length; +} + +/** Main function */ +int main(int argc, char **argv) +{ + long long max_len = 0, max_len_num = 0; + long long MAX_NUM = 1000000; + + if (argc == + 2) /* set commandline argumnet as the maximum iteration number */ + { + MAX_NUM = atoll(argv[1]); + printf("Maximum number: %lld\n", MAX_NUM); + } + + long long i; +#ifdef _OPENMP +#pragma omp parallel for shared(max_len, max_len_num) schedule(guided) +#endif + for (i = 1; i < MAX_NUM; i++) + { + long long L = collatz(i); + if (L > max_len) + { + max_len = L; /* length of sequence */ + max_len_num = i; /* starting number */ + } + +#if defined(_OPENMP) && defined(DEBUG) + printf("Thread: %2d\t %3lld: \t%5lld\n", omp_get_thread_num(), i, L); +#elif defined(DEBUG) + printf("%3lld: \t%5lld\n", i, L); +#endif + } + + printf("Start: %3lld: \tLength: %5lld\n", max_len_num, max_len); + + return 0; +} diff --git a/project_euler/problem_15/sol1.c b/project_euler/problem_15/sol1.c new file mode 100644 index 0000000000..5cf3184e48 --- /dev/null +++ b/project_euler/problem_15/sol1.c @@ -0,0 +1,41 @@ +/** + * \file + * \brief [Problem 15](https://projecteuler.net/problem=15) solution + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include +#include +#include + +/** + * At every node, there are 2 possible ways to move -> down or right. + * Since it is a square grid, there are in all, 2N steps with N down + * and N right options, without preference for order. + * Hence, the path can be be traced in N out of 2N number of ways. + * This is the same as binomial coeeficient. + */ +unsigned long long number_of_paths(int N) +{ + unsigned long long path = 1; + for (int i = 0; i < N; i++) + { + path *= (N << 1) - i; + path /= i + 1; + } + + return path; +} + +/** Main function */ +int main(int argc, char **argv) +{ + int N = 20; + + if (argc == 2) + N = atoi(argv[1]); + + printf("Number of ways to traverse diagonal of %dx%d grid = %llu\n", N, N, + number_of_paths(N)); + + return 0; +} diff --git a/project_euler/problem_16/sol1.c b/project_euler/problem_16/sol1.c new file mode 100644 index 0000000000..1a93a54624 --- /dev/null +++ b/project_euler/problem_16/sol1.c @@ -0,0 +1,62 @@ +/** + * \file + * \brief [Problem 16](https://projecteuler.net/problem=16) solution + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include +#include +#include +#include + +/** Main function */ +int main(int argc, char **argv) +{ + const double tmp = log(10) / log(2); /* required to get number of digits */ + unsigned long MAX_NUM_DIGITS; + uint8_t *digits = + NULL; /* array to store individual digits. index 0 = units place */ + int N = 1000, sum = 0; + + if (argc == 2) + N = atoi(argv[1]); + + MAX_NUM_DIGITS = (N + tmp) / tmp; + + digits = calloc(MAX_NUM_DIGITS, sizeof(uint8_t)); + digits[0] = 1; + + if (!digits) + { + perror("Unable to allocate memory!"); + return -1; + } + + for (int i = 0; i < N; i++) + { + int carry = 0; + for (int j = 0; j < MAX_NUM_DIGITS; j++) + { + digits[j] = (digits[j] << 1) + carry; /* digit * 2 + carry */ + // printf("\t value: %d\t", digits[j]); + if (digits[j] > 9) + { + carry = 1; + digits[j] -= 10; + } + else + carry = 0; + // printf("carry: %d\t value: %d\n", carry, digits[j]); + + /* accumulate sum for last multiplication */ + if (i == N - 1) + sum += digits[j]; + } + } + + printf("2^%d = ", N); + for (int i = MAX_NUM_DIGITS - 1; i >= 0; i--) putchar(digits[i] + 0x30); + printf("\n\t Sum: %d\t Num. digits: %lu\n", sum, MAX_NUM_DIGITS); + + free(digits); + return 0; +} diff --git a/project_euler/problem_19/sol1.c b/project_euler/problem_19/sol1.c new file mode 100644 index 0000000000..fd8b1d1f3d --- /dev/null +++ b/project_euler/problem_19/sol1.c @@ -0,0 +1,135 @@ +/** + * \file + * \brief [Problem 19](https://projecteuler.net/problem=19) solution + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include + +/** + * Function to get the number of days in a month. + * \param month month identified by an integer -\n + * > 0 = Jan and 11 = December + * \returns number of days in given month + * \note For February, adjust for leap year outside the function. + */ +char get_month_days(short month) +{ + if (month == 1) /* February has 28 days. Adjust leap year in the loop */ + return 28; + else if (month <= 6) /* odd months till July have 30 days - Jan = 0 (even)*/ + { + if (month & 0x01) + return 30; + else + return 31; + } + + // else if (month >= 7) /* odd months after July have 31 days*/ + + if (month & 0x01) + return 31; + + return 30; +} + +/** + * @brief Check if input year is a leap year. + * \param year year to check + * \return 1 if input year is a leap year + * \return 0 if input year is not a leap year + */ +char is_leap_year(short year) +{ + if ((year % 400 == 0) || ((year % 4 == 0) && (year % 100 != 0))) + return 1; + + return 0; +} + +#ifdef DEBUG +/** Function to convert integer month to string + * \param day integer identifier of day (0 = Sunday and 7 = Saturday + * \return pointer to string representation) + */ +const char *day_string(int day) +{ + switch (day) + { + case 0: + return "Sunday"; + case 1: + return "Monday"; + case 2: + return "Tuesday"; + case 3: + return "Wednesday"; + case 4: + return "Thursday"; + case 5: + return "Friday"; + case 6: + return "Saturday"; + default: + return "Shouldn't see this!"; + } +} +#endif + +/** Main function */ +int main(int argc, char **argv) +{ + int count_sundays = 0; + const short start_year = 1901; + const short end_year = 2000; + + /* + * Let us identify days i.e., Sunday thru Saturday with integers - 0 thru 6 + * respectively Jan 1 1901 was a Tuesday + */ + char start_day = 2; + + for (int year = start_year; year <= end_year; year++) + { + char is_leap = is_leap_year(year); + for (char month = 0; month < 12; month++) + { + /* + * These two for-loops count the start of day for the next month. + * Hence, we have to skip the last December count + */ + if (year == end_year && month == 11) + continue; + + int days = get_month_days(month); + + if (is_leap && month == 1) /* for a leap year february, add a day */ + days++; + +#ifdef DEBUG + if (year == end_year) + { + printf("Year: %d\t Month: %d\t Days: %d\t First of day: %s\n", + year, month, days, day_string(start_day)); + } +#endif + + /* Main Algorithm: + * every week has 7 days hence, the start of next day would be + * modulo 7 add to this, the current start date and ensure the + * result is still modulo 7! + */ + start_day = ((days % 7) + start_day) % 7; + + /* If start-day is a Sunday, increment counter */ + if (start_day == 0) + count_sundays++; + } + } + + printf( + "Total number of Sundays that happened on the 1st of a month in the " + "last century: %d\n", + count_sundays); + + return 0; +} diff --git a/project_euler/problem_2/so1.c b/project_euler/problem_2/so1.c new file mode 100644 index 0000000000..de238ebbd8 --- /dev/null +++ b/project_euler/problem_2/so1.c @@ -0,0 +1,37 @@ +/** + * \file + * \brief [Problem 2](https://projecteuler.net/problem=2) solution + * + * Problem: + * + * Each new term in the Fibonacci sequence is generated by adding the previous + * two terms. By starting with 1 and 2, the first 10 terms will be: + * `1,2,3,5,8,13,21,34,55,89,..` + * By considering the terms in the Fibonacci sequence whose values do not exceed + * n, find the sum of the even-valued terms. e.g. for n=10, we have {2,8}, sum + * is 10. + */ +#include + +/** Main function */ +int main() +{ + int n = 0; + int sum = 0; + int i = 1; + int j = 2; + int temp; + scanf("%d", &n); + + while (j <= n) + { + if ((j & 1) == 0) // can also use(j%2 == 0) + sum += j; + temp = i; + i = j; + j = temp + i; + } + + printf("%d\n", sum); + return 0; +} \ No newline at end of file diff --git a/project_euler/problem_20/sol1.c b/project_euler/problem_20/sol1.c new file mode 100644 index 0000000000..a78e014d2e --- /dev/null +++ b/project_euler/problem_20/sol1.c @@ -0,0 +1,183 @@ +/** + * \file + * \brief [Problem 20](https://projecteuler.net/problem=20) solution + * \author [Krishna Vedala](https://github.com/kvedala) + * + * Implementation uses a custom `big_int` structure that can store arbitrarily + * large integer numbers. + */ +#include +#include +#include + +/** + * store arbitratily large integer values + * as a linked list of digits. + */ +typedef struct _big_int +{ + char value; /**< tens place (single digit) */ + struct _big_int *next_digit; /**< hundreds place */ + struct _big_int *prev_digit; /**< units place */ +} big_int; + +#ifdef DEBUG +/** print a digit from large integer */ +void print_digit(const big_int *my_int) +{ + printf("\tValue : %d\n\tNext : %p\n\tPrev : %p\n", my_int->value, + my_int->next_digit, my_int->prev_digit); +} +#endif + +/** + * Function that allocates memory to add another + * digit at the MSB + */ +big_int *add_digit(big_int *digit, char value) +{ + if (digit == NULL) + { + digit = (big_int *)malloc(sizeof(big_int)); + if (!digit) + { + perror("Unable to allocate memory!"); + return NULL; + } + digit->value = value; + digit->next_digit = NULL; + digit->prev_digit = NULL; + + return digit; + } + + if (digit->next_digit) + { + digit->next_digit->value = value; + return digit->next_digit; + } + + digit->next_digit = (big_int *)malloc(sizeof(big_int)); + if (digit->next_digit == NULL) + { + perror("Unable to allocate memory!"); + return NULL; + } + digit->next_digit->value = value; + digit->next_digit->next_digit = NULL; + digit->next_digit->prev_digit = digit; + return digit->next_digit; +} + +/** + * Function to remove digits preceeding the + * current digit. + */ +char remove_digits(big_int *digit, int N) +{ + if (digit == NULL) + return 0; + + if (digit->next_digit == NULL) + { + free(digit); + digit = NULL; + return 0; + } + + if (N > 0) + return remove_digits(digit->next_digit, N - 1); + + return remove_digits(digit->next_digit, 0); +} + +/** Main function */ +int main(int argc, char **argv) +{ + unsigned int N = 5; + big_int *ptr = add_digit(NULL, 1); /* start with 1 */ + const big_int *ptr0 = ptr; /* save the first location */ + unsigned long sum_digits = 0; + unsigned long num_digits = 0; + + if (argc == 2) + N = atoi(argv[1]); + + clock_t start_time = clock(); + + for (unsigned int i = 1; i <= N; i++) + { + int carry = 0; +#ifdef DEBUG + printf("%3d: ", i); +#endif + ptr = (big_int *)ptr0; /* multiply every digit with i */ + while (ptr) + { +#ifdef DEBUG + printf("%p\t", ptr); +#endif + unsigned int tmp = ptr->value * i + carry; + if (tmp >= 10) + { + div_t tmp2 = div(tmp, 10); + carry = tmp2.quot; + tmp = tmp2.rem; + } + else + carry = 0; + + if (carry > 0 && ptr->next_digit == NULL) + add_digit(ptr, 0); + + ptr->value = tmp; + + if (i == N) + /* + * sum digits on the last iteration + * this avoid having another loop over all digits + */ + sum_digits += tmp; + + if (ptr->next_digit) + /* more digits available */ + ptr = ptr->next_digit; + else + /* no more digits left - reached MSB */ + break; + } +#ifdef DEBUG + printf("\n"); +#endif + } + + clock_t end_time = clock(); + +#ifdef DEBUG + printf("ptr = %p\n", ptr); + printf("%d! = ", N); +#endif + + /* Notice that in the loop above, we make sure that at the end of the loop, + * ptr is pointing to the last digit. Thus we can avoid using another loop. + */ + // ptr = &my_int; + // /* move ptr to the MSB digit */ + // while (ptr->next_digit) + // ptr = ptr->next_digit; + do + { + putchar(ptr->value + 0x30); /* convert digit to ASCII char */ + ptr = ptr->prev_digit; + num_digits++; + } while (ptr); /* after coming to units place, there will be no valid ptr */ + + printf("\nTime taken: %.4g millisecond\n", + 1e3 * (end_time - start_time) / CLOCKS_PER_SEC); + printf( + "Digit Sum = %lu\tNumber of digits = %lu\tStorage space = %.3gkb\t \n", + sum_digits, num_digits, num_digits * sizeof(big_int) / 1024.0); + + remove_digits((big_int *)ptr0, -1); + return 0; +} diff --git a/project_euler/problem_21/sol1.c b/project_euler/problem_21/sol1.c new file mode 100644 index 0000000000..aac5b453a5 --- /dev/null +++ b/project_euler/problem_21/sol1.c @@ -0,0 +1,93 @@ +/** + * \file + * \brief [Problem 21](https://projecteuler.net/problem=21) solution + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include +#include +#include + +/** + * function to return the sum of proper divisors of N + */ +unsigned long sum_of_divisors(unsigned int N) +{ + unsigned long sum = 1 + N; /* 1 and itself are always a divisor */ + /* divisors are symmertically distributed about the square-root */ + for (unsigned int i = 2; i * i < N; i++) + { + if ((N % i) != 0) + /* i is not a divisor of N */ + continue; + + // #ifdef DEBUG + // printf("%4d, %4d,", i, N / i); + // #endif + + sum += i + (N / i); + } + // #ifdef DEBUG + // printf("\nSum of divisors of %4d: %4d\n", N, sum); + // #endif + return sum; +} + +/** Main function */ +int main(int argc, char **argv) +{ + unsigned long sum = 0; + unsigned int MAX_N = 500; + if (argc == 2) + MAX_N = atoi(argv[1]); + + /* + * We use an array of flags to check if a number at the index was: + * not-processed = 0 + * is amicable = 1 + * not amicable = -1 + */ + char *flags = (char *)calloc(MAX_N, sizeof(char)); + + clock_t start_time = clock(); + int i; + /* there are no such numbers till 10. Lets search from there on */ + for (i = 10; i < MAX_N; i++) + { + if (flags[i] != 0) + /* already processed, skip */ + continue; + + unsigned int b = sum_of_divisors(i); + if (b >= MAX_N) + flags[i] = -1; + else if (flags[b] == -1) + continue; + + unsigned int c = sum_of_divisors(b); + if (c == i && b != i) + { + /* found amicable */ + flags[b] = 1; + flags[i] = 1; + sum += b + i; +#ifdef DEBUG + printf("Amicable: %4d : %4d\n", i, b); +#endif + } + else + { + flags[i] = -1; + if (b < MAX_N) + flags[b] = -1; + } + } + + clock_t end_time = clock(); + + printf("\nTime taken: %.4g millisecond\n", + 1e3 * (end_time - start_time) / CLOCKS_PER_SEC); + printf("Sum of all numbers = %lu\n", sum); + + free(flags); + return 0; +} diff --git a/project_euler/problem_22/names.txt b/project_euler/problem_22/names.txt new file mode 100644 index 0000000000..7b8986bf6c --- /dev/null +++ b/project_euler/problem_22/names.txt @@ -0,0 +1 @@ +"MARY","PATRICIA","LINDA","BARBARA","ELIZABETH","JENNIFER","MARIA","SUSAN","MARGARET","DOROTHY","LISA","NANCY","KAREN","BETTY","HELEN","SANDRA","DONNA","CAROL","RUTH","SHARON","MICHELLE","LAURA","SARAH","KIMBERLY","DEBORAH","JESSICA","SHIRLEY","CYNTHIA","ANGELA","MELISSA","BRENDA","AMY","ANNA","REBECCA","VIRGINIA","KATHLEEN","PAMELA","MARTHA","DEBRA","AMANDA","STEPHANIE","CAROLYN","CHRISTINE","MARIE","JANET","CATHERINE","FRANCES","ANN","JOYCE","DIANE","ALICE","JULIE","HEATHER","TERESA","DORIS","GLORIA","EVELYN","JEAN","CHERYL","MILDRED","KATHERINE","JOAN","ASHLEY","JUDITH","ROSE","JANICE","KELLY","NICOLE","JUDY","CHRISTINA","KATHY","THERESA","BEVERLY","DENISE","TAMMY","IRENE","JANE","LORI","RACHEL","MARILYN","ANDREA","KATHRYN","LOUISE","SARA","ANNE","JACQUELINE","WANDA","BONNIE","JULIA","RUBY","LOIS","TINA","PHYLLIS","NORMA","PAULA","DIANA","ANNIE","LILLIAN","EMILY","ROBIN","PEGGY","CRYSTAL","GLADYS","RITA","DAWN","CONNIE","FLORENCE","TRACY","EDNA","TIFFANY","CARMEN","ROSA","CINDY","GRACE","WENDY","VICTORIA","EDITH","KIM","SHERRY","SYLVIA","JOSEPHINE","THELMA","SHANNON","SHEILA","ETHEL","ELLEN","ELAINE","MARJORIE","CARRIE","CHARLOTTE","MONICA","ESTHER","PAULINE","EMMA","JUANITA","ANITA","RHONDA","HAZEL","AMBER","EVA","DEBBIE","APRIL","LESLIE","CLARA","LUCILLE","JAMIE","JOANNE","ELEANOR","VALERIE","DANIELLE","MEGAN","ALICIA","SUZANNE","MICHELE","GAIL","BERTHA","DARLENE","VERONICA","JILL","ERIN","GERALDINE","LAUREN","CATHY","JOANN","LORRAINE","LYNN","SALLY","REGINA","ERICA","BEATRICE","DOLORES","BERNICE","AUDREY","YVONNE","ANNETTE","JUNE","SAMANTHA","MARION","DANA","STACY","ANA","RENEE","IDA","VIVIAN","ROBERTA","HOLLY","BRITTANY","MELANIE","LORETTA","YOLANDA","JEANETTE","LAURIE","KATIE","KRISTEN","VANESSA","ALMA","SUE","ELSIE","BETH","JEANNE","VICKI","CARLA","TARA","ROSEMARY","EILEEN","TERRI","GERTRUDE","LUCY","TONYA","ELLA","STACEY","WILMA","GINA","KRISTIN","JESSIE","NATALIE","AGNES","VERA","WILLIE","CHARLENE","BESSIE","DELORES","MELINDA","PEARL","ARLENE","MAUREEN","COLLEEN","ALLISON","TAMARA","JOY","GEORGIA","CONSTANCE","LILLIE","CLAUDIA","JACKIE","MARCIA","TANYA","NELLIE","MINNIE","MARLENE","HEIDI","GLENDA","LYDIA","VIOLA","COURTNEY","MARIAN","STELLA","CAROLINE","DORA","JO","VICKIE","MATTIE","TERRY","MAXINE","IRMA","MABEL","MARSHA","MYRTLE","LENA","CHRISTY","DEANNA","PATSY","HILDA","GWENDOLYN","JENNIE","NORA","MARGIE","NINA","CASSANDRA","LEAH","PENNY","KAY","PRISCILLA","NAOMI","CAROLE","BRANDY","OLGA","BILLIE","DIANNE","TRACEY","LEONA","JENNY","FELICIA","SONIA","MIRIAM","VELMA","BECKY","BOBBIE","VIOLET","KRISTINA","TONI","MISTY","MAE","SHELLY","DAISY","RAMONA","SHERRI","ERIKA","KATRINA","CLAIRE","LINDSEY","LINDSAY","GENEVA","GUADALUPE","BELINDA","MARGARITA","SHERYL","CORA","FAYE","ADA","NATASHA","SABRINA","ISABEL","MARGUERITE","HATTIE","HARRIET","MOLLY","CECILIA","KRISTI","BRANDI","BLANCHE","SANDY","ROSIE","JOANNA","IRIS","EUNICE","ANGIE","INEZ","LYNDA","MADELINE","AMELIA","ALBERTA","GENEVIEVE","MONIQUE","JODI","JANIE","MAGGIE","KAYLA","SONYA","JAN","LEE","KRISTINE","CANDACE","FANNIE","MARYANN","OPAL","ALISON","YVETTE","MELODY","LUZ","SUSIE","OLIVIA","FLORA","SHELLEY","KRISTY","MAMIE","LULA","LOLA","VERNA","BEULAH","ANTOINETTE","CANDICE","JUANA","JEANNETTE","PAM","KELLI","HANNAH","WHITNEY","BRIDGET","KARLA","CELIA","LATOYA","PATTY","SHELIA","GAYLE","DELLA","VICKY","LYNNE","SHERI","MARIANNE","KARA","JACQUELYN","ERMA","BLANCA","MYRA","LETICIA","PAT","KRISTA","ROXANNE","ANGELICA","JOHNNIE","ROBYN","FRANCIS","ADRIENNE","ROSALIE","ALEXANDRA","BROOKE","BETHANY","SADIE","BERNADETTE","TRACI","JODY","KENDRA","JASMINE","NICHOLE","RACHAEL","CHELSEA","MABLE","ERNESTINE","MURIEL","MARCELLA","ELENA","KRYSTAL","ANGELINA","NADINE","KARI","ESTELLE","DIANNA","PAULETTE","LORA","MONA","DOREEN","ROSEMARIE","ANGEL","DESIREE","ANTONIA","HOPE","GINGER","JANIS","BETSY","CHRISTIE","FREDA","MERCEDES","MEREDITH","LYNETTE","TERI","CRISTINA","EULA","LEIGH","MEGHAN","SOPHIA","ELOISE","ROCHELLE","GRETCHEN","CECELIA","RAQUEL","HENRIETTA","ALYSSA","JANA","KELLEY","GWEN","KERRY","JENNA","TRICIA","LAVERNE","OLIVE","ALEXIS","TASHA","SILVIA","ELVIRA","CASEY","DELIA","SOPHIE","KATE","PATTI","LORENA","KELLIE","SONJA","LILA","LANA","DARLA","MAY","MINDY","ESSIE","MANDY","LORENE","ELSA","JOSEFINA","JEANNIE","MIRANDA","DIXIE","LUCIA","MARTA","FAITH","LELA","JOHANNA","SHARI","CAMILLE","TAMI","SHAWNA","ELISA","EBONY","MELBA","ORA","NETTIE","TABITHA","OLLIE","JAIME","WINIFRED","KRISTIE","MARINA","ALISHA","AIMEE","RENA","MYRNA","MARLA","TAMMIE","LATASHA","BONITA","PATRICE","RONDA","SHERRIE","ADDIE","FRANCINE","DELORIS","STACIE","ADRIANA","CHERI","SHELBY","ABIGAIL","CELESTE","JEWEL","CARA","ADELE","REBEKAH","LUCINDA","DORTHY","CHRIS","EFFIE","TRINA","REBA","SHAWN","SALLIE","AURORA","LENORA","ETTA","LOTTIE","KERRI","TRISHA","NIKKI","ESTELLA","FRANCISCA","JOSIE","TRACIE","MARISSA","KARIN","BRITTNEY","JANELLE","LOURDES","LAUREL","HELENE","FERN","ELVA","CORINNE","KELSEY","INA","BETTIE","ELISABETH","AIDA","CAITLIN","INGRID","IVA","EUGENIA","CHRISTA","GOLDIE","CASSIE","MAUDE","JENIFER","THERESE","FRANKIE","DENA","LORNA","JANETTE","LATONYA","CANDY","MORGAN","CONSUELO","TAMIKA","ROSETTA","DEBORA","CHERIE","POLLY","DINA","JEWELL","FAY","JILLIAN","DOROTHEA","NELL","TRUDY","ESPERANZA","PATRICA","KIMBERLEY","SHANNA","HELENA","CAROLINA","CLEO","STEFANIE","ROSARIO","OLA","JANINE","MOLLIE","LUPE","ALISA","LOU","MARIBEL","SUSANNE","BETTE","SUSANA","ELISE","CECILE","ISABELLE","LESLEY","JOCELYN","PAIGE","JONI","RACHELLE","LEOLA","DAPHNE","ALTA","ESTER","PETRA","GRACIELA","IMOGENE","JOLENE","KEISHA","LACEY","GLENNA","GABRIELA","KERI","URSULA","LIZZIE","KIRSTEN","SHANA","ADELINE","MAYRA","JAYNE","JACLYN","GRACIE","SONDRA","CARMELA","MARISA","ROSALIND","CHARITY","TONIA","BEATRIZ","MARISOL","CLARICE","JEANINE","SHEENA","ANGELINE","FRIEDA","LILY","ROBBIE","SHAUNA","MILLIE","CLAUDETTE","CATHLEEN","ANGELIA","GABRIELLE","AUTUMN","KATHARINE","SUMMER","JODIE","STACI","LEA","CHRISTI","JIMMIE","JUSTINE","ELMA","LUELLA","MARGRET","DOMINIQUE","SOCORRO","RENE","MARTINA","MARGO","MAVIS","CALLIE","BOBBI","MARITZA","LUCILE","LEANNE","JEANNINE","DEANA","AILEEN","LORIE","LADONNA","WILLA","MANUELA","GALE","SELMA","DOLLY","SYBIL","ABBY","LARA","DALE","IVY","DEE","WINNIE","MARCY","LUISA","JERI","MAGDALENA","OFELIA","MEAGAN","AUDRA","MATILDA","LEILA","CORNELIA","BIANCA","SIMONE","BETTYE","RANDI","VIRGIE","LATISHA","BARBRA","GEORGINA","ELIZA","LEANN","BRIDGETTE","RHODA","HALEY","ADELA","NOLA","BERNADINE","FLOSSIE","ILA","GRETA","RUTHIE","NELDA","MINERVA","LILLY","TERRIE","LETHA","HILARY","ESTELA","VALARIE","BRIANNA","ROSALYN","EARLINE","CATALINA","AVA","MIA","CLARISSA","LIDIA","CORRINE","ALEXANDRIA","CONCEPCION","TIA","SHARRON","RAE","DONA","ERICKA","JAMI","ELNORA","CHANDRA","LENORE","NEVA","MARYLOU","MELISA","TABATHA","SERENA","AVIS","ALLIE","SOFIA","JEANIE","ODESSA","NANNIE","HARRIETT","LORAINE","PENELOPE","MILAGROS","EMILIA","BENITA","ALLYSON","ASHLEE","TANIA","TOMMIE","ESMERALDA","KARINA","EVE","PEARLIE","ZELMA","MALINDA","NOREEN","TAMEKA","SAUNDRA","HILLARY","AMIE","ALTHEA","ROSALINDA","JORDAN","LILIA","ALANA","GAY","CLARE","ALEJANDRA","ELINOR","MICHAEL","LORRIE","JERRI","DARCY","EARNESTINE","CARMELLA","TAYLOR","NOEMI","MARCIE","LIZA","ANNABELLE","LOUISA","EARLENE","MALLORY","CARLENE","NITA","SELENA","TANISHA","KATY","JULIANNE","JOHN","LAKISHA","EDWINA","MARICELA","MARGERY","KENYA","DOLLIE","ROXIE","ROSLYN","KATHRINE","NANETTE","CHARMAINE","LAVONNE","ILENE","KRIS","TAMMI","SUZETTE","CORINE","KAYE","JERRY","MERLE","CHRYSTAL","LINA","DEANNE","LILIAN","JULIANA","ALINE","LUANN","KASEY","MARYANNE","EVANGELINE","COLETTE","MELVA","LAWANDA","YESENIA","NADIA","MADGE","KATHIE","EDDIE","OPHELIA","VALERIA","NONA","MITZI","MARI","GEORGETTE","CLAUDINE","FRAN","ALISSA","ROSEANN","LAKEISHA","SUSANNA","REVA","DEIDRE","CHASITY","SHEREE","CARLY","JAMES","ELVIA","ALYCE","DEIRDRE","GENA","BRIANA","ARACELI","KATELYN","ROSANNE","WENDI","TESSA","BERTA","MARVA","IMELDA","MARIETTA","MARCI","LEONOR","ARLINE","SASHA","MADELYN","JANNA","JULIETTE","DEENA","AURELIA","JOSEFA","AUGUSTA","LILIANA","YOUNG","CHRISTIAN","LESSIE","AMALIA","SAVANNAH","ANASTASIA","VILMA","NATALIA","ROSELLA","LYNNETTE","CORINA","ALFREDA","LEANNA","CAREY","AMPARO","COLEEN","TAMRA","AISHA","WILDA","KARYN","CHERRY","QUEEN","MAURA","MAI","EVANGELINA","ROSANNA","HALLIE","ERNA","ENID","MARIANA","LACY","JULIET","JACKLYN","FREIDA","MADELEINE","MARA","HESTER","CATHRYN","LELIA","CASANDRA","BRIDGETT","ANGELITA","JANNIE","DIONNE","ANNMARIE","KATINA","BERYL","PHOEBE","MILLICENT","KATHERYN","DIANN","CARISSA","MARYELLEN","LIZ","LAURI","HELGA","GILDA","ADRIAN","RHEA","MARQUITA","HOLLIE","TISHA","TAMERA","ANGELIQUE","FRANCESCA","BRITNEY","KAITLIN","LOLITA","FLORINE","ROWENA","REYNA","TWILA","FANNY","JANELL","INES","CONCETTA","BERTIE","ALBA","BRIGITTE","ALYSON","VONDA","PANSY","ELBA","NOELLE","LETITIA","KITTY","DEANN","BRANDIE","LOUELLA","LETA","FELECIA","SHARLENE","LESA","BEVERLEY","ROBERT","ISABELLA","HERMINIA","TERRA","CELINA","TORI","OCTAVIA","JADE","DENICE","GERMAINE","SIERRA","MICHELL","CORTNEY","NELLY","DORETHA","SYDNEY","DEIDRA","MONIKA","LASHONDA","JUDI","CHELSEY","ANTIONETTE","MARGOT","BOBBY","ADELAIDE","NAN","LEEANN","ELISHA","DESSIE","LIBBY","KATHI","GAYLA","LATANYA","MINA","MELLISA","KIMBERLEE","JASMIN","RENAE","ZELDA","ELDA","MA","JUSTINA","GUSSIE","EMILIE","CAMILLA","ABBIE","ROCIO","KAITLYN","JESSE","EDYTHE","ASHLEIGH","SELINA","LAKESHA","GERI","ALLENE","PAMALA","MICHAELA","DAYNA","CARYN","ROSALIA","SUN","JACQULINE","REBECA","MARYBETH","KRYSTLE","IOLA","DOTTIE","BENNIE","BELLE","AUBREY","GRISELDA","ERNESTINA","ELIDA","ADRIANNE","DEMETRIA","DELMA","CHONG","JAQUELINE","DESTINY","ARLEEN","VIRGINA","RETHA","FATIMA","TILLIE","ELEANORE","CARI","TREVA","BIRDIE","WILHELMINA","ROSALEE","MAURINE","LATRICE","YONG","JENA","TARYN","ELIA","DEBBY","MAUDIE","JEANNA","DELILAH","CATRINA","SHONDA","HORTENCIA","THEODORA","TERESITA","ROBBIN","DANETTE","MARYJANE","FREDDIE","DELPHINE","BRIANNE","NILDA","DANNA","CINDI","BESS","IONA","HANNA","ARIEL","WINONA","VIDA","ROSITA","MARIANNA","WILLIAM","RACHEAL","GUILLERMINA","ELOISA","CELESTINE","CAREN","MALISSA","LONA","CHANTEL","SHELLIE","MARISELA","LEORA","AGATHA","SOLEDAD","MIGDALIA","IVETTE","CHRISTEN","ATHENA","JANEL","CHLOE","VEDA","PATTIE","TESSIE","TERA","MARILYNN","LUCRETIA","KARRIE","DINAH","DANIELA","ALECIA","ADELINA","VERNICE","SHIELA","PORTIA","MERRY","LASHAWN","DEVON","DARA","TAWANA","OMA","VERDA","CHRISTIN","ALENE","ZELLA","SANDI","RAFAELA","MAYA","KIRA","CANDIDA","ALVINA","SUZAN","SHAYLA","LYN","LETTIE","ALVA","SAMATHA","ORALIA","MATILDE","MADONNA","LARISSA","VESTA","RENITA","INDIA","DELOIS","SHANDA","PHILLIS","LORRI","ERLINDA","CRUZ","CATHRINE","BARB","ZOE","ISABELL","IONE","GISELA","CHARLIE","VALENCIA","ROXANNA","MAYME","KISHA","ELLIE","MELLISSA","DORRIS","DALIA","BELLA","ANNETTA","ZOILA","RETA","REINA","LAURETTA","KYLIE","CHRISTAL","PILAR","CHARLA","ELISSA","TIFFANI","TANA","PAULINA","LEOTA","BREANNA","JAYME","CARMEL","VERNELL","TOMASA","MANDI","DOMINGA","SANTA","MELODIE","LURA","ALEXA","TAMELA","RYAN","MIRNA","KERRIE","VENUS","NOEL","FELICITA","CRISTY","CARMELITA","BERNIECE","ANNEMARIE","TIARA","ROSEANNE","MISSY","CORI","ROXANA","PRICILLA","KRISTAL","JUNG","ELYSE","HAYDEE","ALETHA","BETTINA","MARGE","GILLIAN","FILOMENA","CHARLES","ZENAIDA","HARRIETTE","CARIDAD","VADA","UNA","ARETHA","PEARLINE","MARJORY","MARCELA","FLOR","EVETTE","ELOUISE","ALINA","TRINIDAD","DAVID","DAMARIS","CATHARINE","CARROLL","BELVA","NAKIA","MARLENA","LUANNE","LORINE","KARON","DORENE","DANITA","BRENNA","TATIANA","SAMMIE","LOUANN","LOREN","JULIANNA","ANDRIA","PHILOMENA","LUCILA","LEONORA","DOVIE","ROMONA","MIMI","JACQUELIN","GAYE","TONJA","MISTI","JOE","GENE","CHASTITY","STACIA","ROXANN","MICAELA","NIKITA","MEI","VELDA","MARLYS","JOHNNA","AURA","LAVERN","IVONNE","HAYLEY","NICKI","MAJORIE","HERLINDA","GEORGE","ALPHA","YADIRA","PERLA","GREGORIA","DANIEL","ANTONETTE","SHELLI","MOZELLE","MARIAH","JOELLE","CORDELIA","JOSETTE","CHIQUITA","TRISTA","LOUIS","LAQUITA","GEORGIANA","CANDI","SHANON","LONNIE","HILDEGARD","CECIL","VALENTINA","STEPHANY","MAGDA","KAROL","GERRY","GABRIELLA","TIANA","ROMA","RICHELLE","RAY","PRINCESS","OLETA","JACQUE","IDELLA","ALAINA","SUZANNA","JOVITA","BLAIR","TOSHA","RAVEN","NEREIDA","MARLYN","KYLA","JOSEPH","DELFINA","TENA","STEPHENIE","SABINA","NATHALIE","MARCELLE","GERTIE","DARLEEN","THEA","SHARONDA","SHANTEL","BELEN","VENESSA","ROSALINA","ONA","GENOVEVA","COREY","CLEMENTINE","ROSALBA","RENATE","RENATA","MI","IVORY","GEORGIANNA","FLOY","DORCAS","ARIANA","TYRA","THEDA","MARIAM","JULI","JESICA","DONNIE","VIKKI","VERLA","ROSELYN","MELVINA","JANNETTE","GINNY","DEBRAH","CORRIE","ASIA","VIOLETA","MYRTIS","LATRICIA","COLLETTE","CHARLEEN","ANISSA","VIVIANA","TWYLA","PRECIOUS","NEDRA","LATONIA","LAN","HELLEN","FABIOLA","ANNAMARIE","ADELL","SHARYN","CHANTAL","NIKI","MAUD","LIZETTE","LINDY","KIA","KESHA","JEANA","DANELLE","CHARLINE","CHANEL","CARROL","VALORIE","LIA","DORTHA","CRISTAL","SUNNY","LEONE","LEILANI","GERRI","DEBI","ANDRA","KESHIA","IMA","EULALIA","EASTER","DULCE","NATIVIDAD","LINNIE","KAMI","GEORGIE","CATINA","BROOK","ALDA","WINNIFRED","SHARLA","RUTHANN","MEAGHAN","MAGDALENE","LISSETTE","ADELAIDA","VENITA","TRENA","SHIRLENE","SHAMEKA","ELIZEBETH","DIAN","SHANTA","MICKEY","LATOSHA","CARLOTTA","WINDY","SOON","ROSINA","MARIANN","LEISA","JONNIE","DAWNA","CATHIE","BILLY","ASTRID","SIDNEY","LAUREEN","JANEEN","HOLLI","FAWN","VICKEY","TERESSA","SHANTE","RUBYE","MARCELINA","CHANDA","CARY","TERESE","SCARLETT","MARTY","MARNIE","LULU","LISETTE","JENIFFER","ELENOR","DORINDA","DONITA","CARMAN","BERNITA","ALTAGRACIA","ALETA","ADRIANNA","ZORAIDA","RONNIE","NICOLA","LYNDSEY","KENDALL","JANINA","CHRISSY","AMI","STARLA","PHYLIS","PHUONG","KYRA","CHARISSE","BLANCH","SANJUANITA","RONA","NANCI","MARILEE","MARANDA","CORY","BRIGETTE","SANJUANA","MARITA","KASSANDRA","JOYCELYN","IRA","FELIPA","CHELSIE","BONNY","MIREYA","LORENZA","KYONG","ILEANA","CANDELARIA","TONY","TOBY","SHERIE","OK","MARK","LUCIE","LEATRICE","LAKESHIA","GERDA","EDIE","BAMBI","MARYLIN","LAVON","HORTENSE","GARNET","EVIE","TRESSA","SHAYNA","LAVINA","KYUNG","JEANETTA","SHERRILL","SHARA","PHYLISS","MITTIE","ANABEL","ALESIA","THUY","TAWANDA","RICHARD","JOANIE","TIFFANIE","LASHANDA","KARISSA","ENRIQUETA","DARIA","DANIELLA","CORINNA","ALANNA","ABBEY","ROXANE","ROSEANNA","MAGNOLIA","LIDA","KYLE","JOELLEN","ERA","CORAL","CARLEEN","TRESA","PEGGIE","NOVELLA","NILA","MAYBELLE","JENELLE","CARINA","NOVA","MELINA","MARQUERITE","MARGARETTE","JOSEPHINA","EVONNE","DEVIN","CINTHIA","ALBINA","TOYA","TAWNYA","SHERITA","SANTOS","MYRIAM","LIZABETH","LISE","KEELY","JENNI","GISELLE","CHERYLE","ARDITH","ARDIS","ALESHA","ADRIANE","SHAINA","LINNEA","KAROLYN","HONG","FLORIDA","FELISHA","DORI","DARCI","ARTIE","ARMIDA","ZOLA","XIOMARA","VERGIE","SHAMIKA","NENA","NANNETTE","MAXIE","LOVIE","JEANE","JAIMIE","INGE","FARRAH","ELAINA","CAITLYN","STARR","FELICITAS","CHERLY","CARYL","YOLONDA","YASMIN","TEENA","PRUDENCE","PENNIE","NYDIA","MACKENZIE","ORPHA","MARVEL","LIZBETH","LAURETTE","JERRIE","HERMELINDA","CAROLEE","TIERRA","MIRIAN","META","MELONY","KORI","JENNETTE","JAMILA","ENA","ANH","YOSHIKO","SUSANNAH","SALINA","RHIANNON","JOLEEN","CRISTINE","ASHTON","ARACELY","TOMEKA","SHALONDA","MARTI","LACIE","KALA","JADA","ILSE","HAILEY","BRITTANI","ZONA","SYBLE","SHERRYL","RANDY","NIDIA","MARLO","KANDICE","KANDI","DEB","DEAN","AMERICA","ALYCIA","TOMMY","RONNA","NORENE","MERCY","JOSE","INGEBORG","GIOVANNA","GEMMA","CHRISTEL","AUDRY","ZORA","VITA","VAN","TRISH","STEPHAINE","SHIRLEE","SHANIKA","MELONIE","MAZIE","JAZMIN","INGA","HOA","HETTIE","GERALYN","FONDA","ESTRELLA","ADELLA","SU","SARITA","RINA","MILISSA","MARIBETH","GOLDA","EVON","ETHELYN","ENEDINA","CHERISE","CHANA","VELVA","TAWANNA","SADE","MIRTA","LI","KARIE","JACINTA","ELNA","DAVINA","CIERRA","ASHLIE","ALBERTHA","TANESHA","STEPHANI","NELLE","MINDI","LU","LORINDA","LARUE","FLORENE","DEMETRA","DEDRA","CIARA","CHANTELLE","ASHLY","SUZY","ROSALVA","NOELIA","LYDA","LEATHA","KRYSTYNA","KRISTAN","KARRI","DARLINE","DARCIE","CINDA","CHEYENNE","CHERRIE","AWILDA","ALMEDA","ROLANDA","LANETTE","JERILYN","GISELE","EVALYN","CYNDI","CLETA","CARIN","ZINA","ZENA","VELIA","TANIKA","PAUL","CHARISSA","THOMAS","TALIA","MARGARETE","LAVONDA","KAYLEE","KATHLENE","JONNA","IRENA","ILONA","IDALIA","CANDIS","CANDANCE","BRANDEE","ANITRA","ALIDA","SIGRID","NICOLETTE","MARYJO","LINETTE","HEDWIG","CHRISTIANA","CASSIDY","ALEXIA","TRESSIE","MODESTA","LUPITA","LITA","GLADIS","EVELIA","DAVIDA","CHERRI","CECILY","ASHELY","ANNABEL","AGUSTINA","WANITA","SHIRLY","ROSAURA","HULDA","EUN","BAILEY","YETTA","VERONA","THOMASINA","SIBYL","SHANNAN","MECHELLE","LUE","LEANDRA","LANI","KYLEE","KANDY","JOLYNN","FERNE","EBONI","CORENE","ALYSIA","ZULA","NADA","MOIRA","LYNDSAY","LORRETTA","JUAN","JAMMIE","HORTENSIA","GAYNELL","CAMERON","ADRIA","VINA","VICENTA","TANGELA","STEPHINE","NORINE","NELLA","LIANA","LESLEE","KIMBERELY","ILIANA","GLORY","FELICA","EMOGENE","ELFRIEDE","EDEN","EARTHA","CARMA","BEA","OCIE","MARRY","LENNIE","KIARA","JACALYN","CARLOTA","ARIELLE","YU","STAR","OTILIA","KIRSTIN","KACEY","JOHNETTA","JOEY","JOETTA","JERALDINE","JAUNITA","ELANA","DORTHEA","CAMI","AMADA","ADELIA","VERNITA","TAMAR","SIOBHAN","RENEA","RASHIDA","OUIDA","ODELL","NILSA","MERYL","KRISTYN","JULIETA","DANICA","BREANNE","AUREA","ANGLEA","SHERRON","ODETTE","MALIA","LORELEI","LIN","LEESA","KENNA","KATHLYN","FIONA","CHARLETTE","SUZIE","SHANTELL","SABRA","RACQUEL","MYONG","MIRA","MARTINE","LUCIENNE","LAVADA","JULIANN","JOHNIE","ELVERA","DELPHIA","CLAIR","CHRISTIANE","CHAROLETTE","CARRI","AUGUSTINE","ASHA","ANGELLA","PAOLA","NINFA","LEDA","LAI","EDA","SUNSHINE","STEFANI","SHANELL","PALMA","MACHELLE","LISSA","KECIA","KATHRYNE","KARLENE","JULISSA","JETTIE","JENNIFFER","HUI","CORRINA","CHRISTOPHER","CAROLANN","ALENA","TESS","ROSARIA","MYRTICE","MARYLEE","LIANE","KENYATTA","JUDIE","JANEY","IN","ELMIRA","ELDORA","DENNA","CRISTI","CATHI","ZAIDA","VONNIE","VIVA","VERNIE","ROSALINE","MARIELA","LUCIANA","LESLI","KARAN","FELICE","DENEEN","ADINA","WYNONA","TARSHA","SHERON","SHASTA","SHANITA","SHANI","SHANDRA","RANDA","PINKIE","PARIS","NELIDA","MARILOU","LYLA","LAURENE","LACI","JOI","JANENE","DOROTHA","DANIELE","DANI","CAROLYNN","CARLYN","BERENICE","AYESHA","ANNELIESE","ALETHEA","THERSA","TAMIKO","RUFINA","OLIVA","MOZELL","MARYLYN","MADISON","KRISTIAN","KATHYRN","KASANDRA","KANDACE","JANAE","GABRIEL","DOMENICA","DEBBRA","DANNIELLE","CHUN","BUFFY","BARBIE","ARCELIA","AJA","ZENOBIA","SHAREN","SHAREE","PATRICK","PAGE","MY","LAVINIA","KUM","KACIE","JACKELINE","HUONG","FELISA","EMELIA","ELEANORA","CYTHIA","CRISTIN","CLYDE","CLARIBEL","CARON","ANASTACIA","ZULMA","ZANDRA","YOKO","TENISHA","SUSANN","SHERILYN","SHAY","SHAWANDA","SABINE","ROMANA","MATHILDA","LINSEY","KEIKO","JOANA","ISELA","GRETTA","GEORGETTA","EUGENIE","DUSTY","DESIRAE","DELORA","CORAZON","ANTONINA","ANIKA","WILLENE","TRACEE","TAMATHA","REGAN","NICHELLE","MICKIE","MAEGAN","LUANA","LANITA","KELSIE","EDELMIRA","BREE","AFTON","TEODORA","TAMIE","SHENA","MEG","LINH","KELI","KACI","DANYELLE","BRITT","ARLETTE","ALBERTINE","ADELLE","TIFFINY","STORMY","SIMONA","NUMBERS","NICOLASA","NICHOL","NIA","NAKISHA","MEE","MAIRA","LOREEN","KIZZY","JOHNNY","JAY","FALLON","CHRISTENE","BOBBYE","ANTHONY","YING","VINCENZA","TANJA","RUBIE","RONI","QUEENIE","MARGARETT","KIMBERLI","IRMGARD","IDELL","HILMA","EVELINA","ESTA","EMILEE","DENNISE","DANIA","CARL","CARIE","ANTONIO","WAI","SANG","RISA","RIKKI","PARTICIA","MUI","MASAKO","MARIO","LUVENIA","LOREE","LONI","LIEN","KEVIN","GIGI","FLORENCIA","DORIAN","DENITA","DALLAS","CHI","BILLYE","ALEXANDER","TOMIKA","SHARITA","RANA","NIKOLE","NEOMA","MARGARITE","MADALYN","LUCINA","LAILA","KALI","JENETTE","GABRIELE","EVELYNE","ELENORA","CLEMENTINA","ALEJANDRINA","ZULEMA","VIOLETTE","VANNESSA","THRESA","RETTA","PIA","PATIENCE","NOELLA","NICKIE","JONELL","DELTA","CHUNG","CHAYA","CAMELIA","BETHEL","ANYA","ANDREW","THANH","SUZANN","SPRING","SHU","MILA","LILLA","LAVERNA","KEESHA","KATTIE","GIA","GEORGENE","EVELINE","ESTELL","ELIZBETH","VIVIENNE","VALLIE","TRUDIE","STEPHANE","MICHEL","MAGALY","MADIE","KENYETTA","KARREN","JANETTA","HERMINE","HARMONY","DRUCILLA","DEBBI","CELESTINA","CANDIE","BRITNI","BECKIE","AMINA","ZITA","YUN","YOLANDE","VIVIEN","VERNETTA","TRUDI","SOMMER","PEARLE","PATRINA","OSSIE","NICOLLE","LOYCE","LETTY","LARISA","KATHARINA","JOSELYN","JONELLE","JENELL","IESHA","HEIDE","FLORINDA","FLORENTINA","FLO","ELODIA","DORINE","BRUNILDA","BRIGID","ASHLI","ARDELLA","TWANA","THU","TARAH","SUNG","SHEA","SHAVON","SHANE","SERINA","RAYNA","RAMONITA","NGA","MARGURITE","LUCRECIA","KOURTNEY","KATI","JESUS","JESENIA","DIAMOND","CRISTA","AYANA","ALICA","ALIA","VINNIE","SUELLEN","ROMELIA","RACHELL","PIPER","OLYMPIA","MICHIKO","KATHALEEN","JOLIE","JESSI","JANESSA","HANA","HA","ELEASE","CARLETTA","BRITANY","SHONA","SALOME","ROSAMOND","REGENA","RAINA","NGOC","NELIA","LOUVENIA","LESIA","LATRINA","LATICIA","LARHONDA","JINA","JACKI","HOLLIS","HOLLEY","EMMY","DEEANN","CORETTA","ARNETTA","VELVET","THALIA","SHANICE","NETA","MIKKI","MICKI","LONNA","LEANA","LASHUNDA","KILEY","JOYE","JACQULYN","IGNACIA","HYUN","HIROKO","HENRY","HENRIETTE","ELAYNE","DELINDA","DARNELL","DAHLIA","COREEN","CONSUELA","CONCHITA","CELINE","BABETTE","AYANNA","ANETTE","ALBERTINA","SKYE","SHAWNEE","SHANEKA","QUIANA","PAMELIA","MIN","MERRI","MERLENE","MARGIT","KIESHA","KIERA","KAYLENE","JODEE","JENISE","ERLENE","EMMIE","ELSE","DARYL","DALILA","DAISEY","CODY","CASIE","BELIA","BABARA","VERSIE","VANESA","SHELBA","SHAWNDA","SAM","NORMAN","NIKIA","NAOMA","MARNA","MARGERET","MADALINE","LAWANA","KINDRA","JUTTA","JAZMINE","JANETT","HANNELORE","GLENDORA","GERTRUD","GARNETT","FREEDA","FREDERICA","FLORANCE","FLAVIA","DENNIS","CARLINE","BEVERLEE","ANJANETTE","VALDA","TRINITY","TAMALA","STEVIE","SHONNA","SHA","SARINA","ONEIDA","MICAH","MERILYN","MARLEEN","LURLINE","LENNA","KATHERIN","JIN","JENI","HAE","GRACIA","GLADY","FARAH","ERIC","ENOLA","EMA","DOMINQUE","DEVONA","DELANA","CECILA","CAPRICE","ALYSHA","ALI","ALETHIA","VENA","THERESIA","TAWNY","SONG","SHAKIRA","SAMARA","SACHIKO","RACHELE","PAMELLA","NICKY","MARNI","MARIEL","MAREN","MALISA","LIGIA","LERA","LATORIA","LARAE","KIMBER","KATHERN","KAREY","JENNEFER","JANETH","HALINA","FREDIA","DELISA","DEBROAH","CIERA","CHIN","ANGELIKA","ANDREE","ALTHA","YEN","VIVAN","TERRESA","TANNA","SUK","SUDIE","SOO","SIGNE","SALENA","RONNI","REBBECCA","MYRTIE","MCKENZIE","MALIKA","MAIDA","LOAN","LEONARDA","KAYLEIGH","FRANCE","ETHYL","ELLYN","DAYLE","CAMMIE","BRITTNI","BIRGIT","AVELINA","ASUNCION","ARIANNA","AKIKO","VENICE","TYESHA","TONIE","TIESHA","TAKISHA","STEFFANIE","SINDY","SANTANA","MEGHANN","MANDA","MACIE","LADY","KELLYE","KELLEE","JOSLYN","JASON","INGER","INDIRA","GLINDA","GLENNIS","FERNANDA","FAUSTINA","ENEIDA","ELICIA","DOT","DIGNA","DELL","ARLETTA","ANDRE","WILLIA","TAMMARA","TABETHA","SHERRELL","SARI","REFUGIO","REBBECA","PAULETTA","NIEVES","NATOSHA","NAKITA","MAMMIE","KENISHA","KAZUKO","KASSIE","GARY","EARLEAN","DAPHINE","CORLISS","CLOTILDE","CAROLYNE","BERNETTA","AUGUSTINA","AUDREA","ANNIS","ANNABELL","YAN","TENNILLE","TAMICA","SELENE","SEAN","ROSANA","REGENIA","QIANA","MARKITA","MACY","LEEANNE","LAURINE","KYM","JESSENIA","JANITA","GEORGINE","GENIE","EMIKO","ELVIE","DEANDRA","DAGMAR","CORIE","COLLEN","CHERISH","ROMAINE","PORSHA","PEARLENE","MICHELINE","MERNA","MARGORIE","MARGARETTA","LORE","KENNETH","JENINE","HERMINA","FREDERICKA","ELKE","DRUSILLA","DORATHY","DIONE","DESIRE","CELENA","BRIGIDA","ANGELES","ALLEGRA","THEO","TAMEKIA","SYNTHIA","STEPHEN","SOOK","SLYVIA","ROSANN","REATHA","RAYE","MARQUETTA","MARGART","LING","LAYLA","KYMBERLY","KIANA","KAYLEEN","KATLYN","KARMEN","JOELLA","IRINA","EMELDA","ELENI","DETRA","CLEMMIE","CHERYLL","CHANTELL","CATHEY","ARNITA","ARLA","ANGLE","ANGELIC","ALYSE","ZOFIA","THOMASINE","TENNIE","SON","SHERLY","SHERLEY","SHARYL","REMEDIOS","PETRINA","NICKOLE","MYUNG","MYRLE","MOZELLA","LOUANNE","LISHA","LATIA","LANE","KRYSTA","JULIENNE","JOEL","JEANENE","JACQUALINE","ISAURA","GWENDA","EARLEEN","DONALD","CLEOPATRA","CARLIE","AUDIE","ANTONIETTA","ALISE","ALEX","VERDELL","VAL","TYLER","TOMOKO","THAO","TALISHA","STEVEN","SO","SHEMIKA","SHAUN","SCARLET","SAVANNA","SANTINA","ROSIA","RAEANN","ODILIA","NANA","MINNA","MAGAN","LYNELLE","LE","KARMA","JOEANN","IVANA","INELL","ILANA","HYE","HONEY","HEE","GUDRUN","FRANK","DREAMA","CRISSY","CHANTE","CARMELINA","ARVILLA","ARTHUR","ANNAMAE","ALVERA","ALEIDA","AARON","YEE","YANIRA","VANDA","TIANNA","TAM","STEFANIA","SHIRA","PERRY","NICOL","NANCIE","MONSERRATE","MINH","MELYNDA","MELANY","MATTHEW","LOVELLA","LAURE","KIRBY","KACY","JACQUELYNN","HYON","GERTHA","FRANCISCO","ELIANA","CHRISTENA","CHRISTEEN","CHARISE","CATERINA","CARLEY","CANDYCE","ARLENA","AMMIE","YANG","WILLETTE","VANITA","TUYET","TINY","SYREETA","SILVA","SCOTT","RONALD","PENNEY","NYLA","MICHAL","MAURICE","MARYAM","MARYA","MAGEN","LUDIE","LOMA","LIVIA","LANELL","KIMBERLIE","JULEE","DONETTA","DIEDRA","DENISHA","DEANE","DAWNE","CLARINE","CHERRYL","BRONWYN","BRANDON","ALLA","VALERY","TONDA","SUEANN","SORAYA","SHOSHANA","SHELA","SHARLEEN","SHANELLE","NERISSA","MICHEAL","MERIDITH","MELLIE","MAYE","MAPLE","MAGARET","LUIS","LILI","LEONILA","LEONIE","LEEANNA","LAVONIA","LAVERA","KRISTEL","KATHEY","KATHE","JUSTIN","JULIAN","JIMMY","JANN","ILDA","HILDRED","HILDEGARDE","GENIA","FUMIKO","EVELIN","ERMELINDA","ELLY","DUNG","DOLORIS","DIONNA","DANAE","BERNEICE","ANNICE","ALIX","VERENA","VERDIE","TRISTAN","SHAWNNA","SHAWANA","SHAUNNA","ROZELLA","RANDEE","RANAE","MILAGRO","LYNELL","LUISE","LOUIE","LOIDA","LISBETH","KARLEEN","JUNITA","JONA","ISIS","HYACINTH","HEDY","GWENN","ETHELENE","ERLINE","EDWARD","DONYA","DOMONIQUE","DELICIA","DANNETTE","CICELY","BRANDA","BLYTHE","BETHANN","ASHLYN","ANNALEE","ALLINE","YUKO","VELLA","TRANG","TOWANDA","TESHA","SHERLYN","NARCISA","MIGUELINA","MERI","MAYBELL","MARLANA","MARGUERITA","MADLYN","LUNA","LORY","LORIANN","LIBERTY","LEONORE","LEIGHANN","LAURICE","LATESHA","LARONDA","KATRICE","KASIE","KARL","KALEY","JADWIGA","GLENNIE","GEARLDINE","FRANCINA","EPIFANIA","DYAN","DORIE","DIEDRE","DENESE","DEMETRICE","DELENA","DARBY","CRISTIE","CLEORA","CATARINA","CARISA","BERNIE","BARBERA","ALMETA","TRULA","TEREASA","SOLANGE","SHEILAH","SHAVONNE","SANORA","ROCHELL","MATHILDE","MARGARETA","MAIA","LYNSEY","LAWANNA","LAUNA","KENA","KEENA","KATIA","JAMEY","GLYNDA","GAYLENE","ELVINA","ELANOR","DANUTA","DANIKA","CRISTEN","CORDIE","COLETTA","CLARITA","CARMON","BRYNN","AZUCENA","AUNDREA","ANGELE","YI","WALTER","VERLIE","VERLENE","TAMESHA","SILVANA","SEBRINA","SAMIRA","REDA","RAYLENE","PENNI","PANDORA","NORAH","NOMA","MIREILLE","MELISSIA","MARYALICE","LARAINE","KIMBERY","KARYL","KARINE","KAM","JOLANDA","JOHANA","JESUSA","JALEESA","JAE","JACQUELYNE","IRISH","ILUMINADA","HILARIA","HANH","GENNIE","FRANCIE","FLORETTA","EXIE","EDDA","DREMA","DELPHA","BEV","BARBAR","ASSUNTA","ARDELL","ANNALISA","ALISIA","YUKIKO","YOLANDO","WONDA","WEI","WALTRAUD","VETA","TEQUILA","TEMEKA","TAMEIKA","SHIRLEEN","SHENITA","PIEDAD","OZELLA","MIRTHA","MARILU","KIMIKO","JULIANE","JENICE","JEN","JANAY","JACQUILINE","HILDE","FE","FAE","EVAN","EUGENE","ELOIS","ECHO","DEVORAH","CHAU","BRINDA","BETSEY","ARMINDA","ARACELIS","APRYL","ANNETT","ALISHIA","VEOLA","USHA","TOSHIKO","THEOLA","TASHIA","TALITHA","SHERY","RUDY","RENETTA","REIKO","RASHEEDA","OMEGA","OBDULIA","MIKA","MELAINE","MEGGAN","MARTIN","MARLEN","MARGET","MARCELINE","MANA","MAGDALEN","LIBRADA","LEZLIE","LEXIE","LATASHIA","LASANDRA","KELLE","ISIDRA","ISA","INOCENCIA","GWYN","FRANCOISE","ERMINIA","ERINN","DIMPLE","DEVORA","CRISELDA","ARMANDA","ARIE","ARIANE","ANGELO","ANGELENA","ALLEN","ALIZA","ADRIENE","ADALINE","XOCHITL","TWANNA","TRAN","TOMIKO","TAMISHA","TAISHA","SUSY","SIU","RUTHA","ROXY","RHONA","RAYMOND","OTHA","NORIKO","NATASHIA","MERRIE","MELVIN","MARINDA","MARIKO","MARGERT","LORIS","LIZZETTE","LEISHA","KAILA","KA","JOANNIE","JERRICA","JENE","JANNET","JANEE","JACINDA","HERTA","ELENORE","DORETTA","DELAINE","DANIELL","CLAUDIE","CHINA","BRITTA","APOLONIA","AMBERLY","ALEASE","YURI","YUK","WEN","WANETA","UTE","TOMI","SHARRI","SANDIE","ROSELLE","REYNALDA","RAGUEL","PHYLICIA","PATRIA","OLIMPIA","ODELIA","MITZIE","MITCHELL","MISS","MINDA","MIGNON","MICA","MENDY","MARIVEL","MAILE","LYNETTA","LAVETTE","LAURYN","LATRISHA","LAKIESHA","KIERSTEN","KARY","JOSPHINE","JOLYN","JETTA","JANISE","JACQUIE","IVELISSE","GLYNIS","GIANNA","GAYNELLE","EMERALD","DEMETRIUS","DANYELL","DANILLE","DACIA","CORALEE","CHER","CEOLA","BRETT","BELL","ARIANNE","ALESHIA","YUNG","WILLIEMAE","TROY","TRINH","THORA","TAI","SVETLANA","SHERIKA","SHEMEKA","SHAUNDA","ROSELINE","RICKI","MELDA","MALLIE","LAVONNA","LATINA","LARRY","LAQUANDA","LALA","LACHELLE","KLARA","KANDIS","JOHNA","JEANMARIE","JAYE","HANG","GRAYCE","GERTUDE","EMERITA","EBONIE","CLORINDA","CHING","CHERY","CAROLA","BREANN","BLOSSOM","BERNARDINE","BECKI","ARLETHA","ARGELIA","ARA","ALITA","YULANDA","YON","YESSENIA","TOBI","TASIA","SYLVIE","SHIRL","SHIRELY","SHERIDAN","SHELLA","SHANTELLE","SACHA","ROYCE","REBECKA","REAGAN","PROVIDENCIA","PAULENE","MISHA","MIKI","MARLINE","MARICA","LORITA","LATOYIA","LASONYA","KERSTIN","KENDA","KEITHA","KATHRIN","JAYMIE","JACK","GRICELDA","GINETTE","ERYN","ELINA","ELFRIEDA","DANYEL","CHEREE","CHANELLE","BARRIE","AVERY","AURORE","ANNAMARIA","ALLEEN","AILENE","AIDE","YASMINE","VASHTI","VALENTINE","TREASA","TORY","TIFFANEY","SHERYLL","SHARIE","SHANAE","SAU","RAISA","PA","NEDA","MITSUKO","MIRELLA","MILDA","MARYANNA","MARAGRET","MABELLE","LUETTA","LORINA","LETISHA","LATARSHA","LANELLE","LAJUANA","KRISSY","KARLY","KARENA","JON","JESSIKA","JERICA","JEANELLE","JANUARY","JALISA","JACELYN","IZOLA","IVEY","GREGORY","EUNA","ETHA","DREW","DOMITILA","DOMINICA","DAINA","CREOLA","CARLI","CAMIE","BUNNY","BRITTNY","ASHANTI","ANISHA","ALEEN","ADAH","YASUKO","WINTER","VIKI","VALRIE","TONA","TINISHA","THI","TERISA","TATUM","TANEKA","SIMONNE","SHALANDA","SERITA","RESSIE","REFUGIA","PAZ","OLENE","NA","MERRILL","MARGHERITA","MANDIE","MAN","MAIRE","LYNDIA","LUCI","LORRIANE","LORETA","LEONIA","LAVONA","LASHAWNDA","LAKIA","KYOKO","KRYSTINA","KRYSTEN","KENIA","KELSI","JUDE","JEANICE","ISOBEL","GEORGIANN","GENNY","FELICIDAD","EILENE","DEON","DELOISE","DEEDEE","DANNIE","CONCEPTION","CLORA","CHERILYN","CHANG","CALANDRA","BERRY","ARMANDINA","ANISA","ULA","TIMOTHY","TIERA","THERESSA","STEPHANIA","SIMA","SHYLA","SHONTA","SHERA","SHAQUITA","SHALA","SAMMY","ROSSANA","NOHEMI","NERY","MORIAH","MELITA","MELIDA","MELANI","MARYLYNN","MARISHA","MARIETTE","MALORIE","MADELENE","LUDIVINA","LORIA","LORETTE","LORALEE","LIANNE","LEON","LAVENIA","LAURINDA","LASHON","KIT","KIMI","KEILA","KATELYNN","KAI","JONE","JOANE","JI","JAYNA","JANELLA","JA","HUE","HERTHA","FRANCENE","ELINORE","DESPINA","DELSIE","DEEDRA","CLEMENCIA","CARRY","CAROLIN","CARLOS","BULAH","BRITTANIE","BOK","BLONDELL","BIBI","BEAULAH","BEATA","ANNITA","AGRIPINA","VIRGEN","VALENE","UN","TWANDA","TOMMYE","TOI","TARRA","TARI","TAMMERA","SHAKIA","SADYE","RUTHANNE","ROCHEL","RIVKA","PURA","NENITA","NATISHA","MING","MERRILEE","MELODEE","MARVIS","LUCILLA","LEENA","LAVETA","LARITA","LANIE","KEREN","ILEEN","GEORGEANN","GENNA","GENESIS","FRIDA","EWA","EUFEMIA","EMELY","ELA","EDYTH","DEONNA","DEADRA","DARLENA","CHANELL","CHAN","CATHERN","CASSONDRA","CASSAUNDRA","BERNARDA","BERNA","ARLINDA","ANAMARIA","ALBERT","WESLEY","VERTIE","VALERI","TORRI","TATYANA","STASIA","SHERISE","SHERILL","SEASON","SCOTTIE","SANDA","RUTHE","ROSY","ROBERTO","ROBBI","RANEE","QUYEN","PEARLY","PALMIRA","ONITA","NISHA","NIESHA","NIDA","NEVADA","NAM","MERLYN","MAYOLA","MARYLOUISE","MARYLAND","MARX","MARTH","MARGENE","MADELAINE","LONDA","LEONTINE","LEOMA","LEIA","LAWRENCE","LAURALEE","LANORA","LAKITA","KIYOKO","KETURAH","KATELIN","KAREEN","JONIE","JOHNETTE","JENEE","JEANETT","IZETTA","HIEDI","HEIKE","HASSIE","HAROLD","GIUSEPPINA","GEORGANN","FIDELA","FERNANDE","ELWANDA","ELLAMAE","ELIZ","DUSTI","DOTTY","CYNDY","CORALIE","CELESTA","ARGENTINA","ALVERTA","XENIA","WAVA","VANETTA","TORRIE","TASHINA","TANDY","TAMBRA","TAMA","STEPANIE","SHILA","SHAUNTA","SHARAN","SHANIQUA","SHAE","SETSUKO","SERAFINA","SANDEE","ROSAMARIA","PRISCILA","OLINDA","NADENE","MUOI","MICHELINA","MERCEDEZ","MARYROSE","MARIN","MARCENE","MAO","MAGALI","MAFALDA","LOGAN","LINN","LANNIE","KAYCE","KAROLINE","KAMILAH","KAMALA","JUSTA","JOLINE","JENNINE","JACQUETTA","IRAIDA","GERALD","GEORGEANNA","FRANCHESCA","FAIRY","EMELINE","ELANE","EHTEL","EARLIE","DULCIE","DALENE","CRIS","CLASSIE","CHERE","CHARIS","CAROYLN","CARMINA","CARITA","BRIAN","BETHANIE","AYAKO","ARICA","AN","ALYSA","ALESSANDRA","AKILAH","ADRIEN","ZETTA","YOULANDA","YELENA","YAHAIRA","XUAN","WENDOLYN","VICTOR","TIJUANA","TERRELL","TERINA","TERESIA","SUZI","SUNDAY","SHERELL","SHAVONDA","SHAUNTE","SHARDA","SHAKITA","SENA","RYANN","RUBI","RIVA","REGINIA","REA","RACHAL","PARTHENIA","PAMULA","MONNIE","MONET","MICHAELE","MELIA","MARINE","MALKA","MAISHA","LISANDRA","LEO","LEKISHA","LEAN","LAURENCE","LAKENDRA","KRYSTIN","KORTNEY","KIZZIE","KITTIE","KERA","KENDAL","KEMBERLY","KANISHA","JULENE","JULE","JOSHUA","JOHANNE","JEFFREY","JAMEE","HAN","HALLEY","GIDGET","GALINA","FREDRICKA","FLETA","FATIMAH","EUSEBIA","ELZA","ELEONORE","DORTHEY","DORIA","DONELLA","DINORAH","DELORSE","CLARETHA","CHRISTINIA","CHARLYN","BONG","BELKIS","AZZIE","ANDERA","AIKO","ADENA","YER","YAJAIRA","WAN","VANIA","ULRIKE","TOSHIA","TIFANY","STEFANY","SHIZUE","SHENIKA","SHAWANNA","SHAROLYN","SHARILYN","SHAQUANA","SHANTAY","SEE","ROZANNE","ROSELEE","RICKIE","REMONA","REANNA","RAELENE","QUINN","PHUNG","PETRONILA","NATACHA","NANCEY","MYRL","MIYOKO","MIESHA","MERIDETH","MARVELLA","MARQUITTA","MARHTA","MARCHELLE","LIZETH","LIBBIE","LAHOMA","LADAWN","KINA","KATHELEEN","KATHARYN","KARISA","KALEIGH","JUNIE","JULIEANN","JOHNSIE","JANEAN","JAIMEE","JACKQUELINE","HISAKO","HERMA","HELAINE","GWYNETH","GLENN","GITA","EUSTOLIA","EMELINA","ELIN","EDRIS","DONNETTE","DONNETTA","DIERDRE","DENAE","DARCEL","CLAUDE","CLARISA","CINDERELLA","CHIA","CHARLESETTA","CHARITA","CELSA","CASSY","CASSI","CARLEE","BRUNA","BRITTANEY","BRANDE","BILLI","BAO","ANTONETTA","ANGLA","ANGELYN","ANALISA","ALANE","WENONA","WENDIE","VERONIQUE","VANNESA","TOBIE","TEMPIE","SUMIKO","SULEMA","SPARKLE","SOMER","SHEBA","SHAYNE","SHARICE","SHANEL","SHALON","SAGE","ROY","ROSIO","ROSELIA","RENAY","REMA","REENA","PORSCHE","PING","PEG","OZIE","ORETHA","ORALEE","ODA","NU","NGAN","NAKESHA","MILLY","MARYBELLE","MARLIN","MARIS","MARGRETT","MARAGARET","MANIE","LURLENE","LILLIA","LIESELOTTE","LAVELLE","LASHAUNDA","LAKEESHA","KEITH","KAYCEE","KALYN","JOYA","JOETTE","JENAE","JANIECE","ILLA","GRISEL","GLAYDS","GENEVIE","GALA","FREDDA","FRED","ELMER","ELEONOR","DEBERA","DEANDREA","DAN","CORRINNE","CORDIA","CONTESSA","COLENE","CLEOTILDE","CHARLOTT","CHANTAY","CECILLE","BEATRIS","AZALEE","ARLEAN","ARDATH","ANJELICA","ANJA","ALFREDIA","ALEISHA","ADAM","ZADA","YUONNE","XIAO","WILLODEAN","WHITLEY","VENNIE","VANNA","TYISHA","TOVA","TORIE","TONISHA","TILDA","TIEN","TEMPLE","SIRENA","SHERRIL","SHANTI","SHAN","SENAIDA","SAMELLA","ROBBYN","RENDA","REITA","PHEBE","PAULITA","NOBUKO","NGUYET","NEOMI","MOON","MIKAELA","MELANIA","MAXIMINA","MARG","MAISIE","LYNNA","LILLI","LAYNE","LASHAUN","LAKENYA","LAEL","KIRSTIE","KATHLINE","KASHA","KARLYN","KARIMA","JOVAN","JOSEFINE","JENNELL","JACQUI","JACKELYN","HYO","HIEN","GRAZYNA","FLORRIE","FLORIA","ELEONORA","DWANA","DORLA","DONG","DELMY","DEJA","DEDE","DANN","CRYSTA","CLELIA","CLARIS","CLARENCE","CHIEKO","CHERLYN","CHERELLE","CHARMAIN","CHARA","CAMMY","BEE","ARNETTE","ARDELLE","ANNIKA","AMIEE","AMEE","ALLENA","YVONE","YUKI","YOSHIE","YEVETTE","YAEL","WILLETTA","VONCILE","VENETTA","TULA","TONETTE","TIMIKA","TEMIKA","TELMA","TEISHA","TAREN","TA","STACEE","SHIN","SHAWNTA","SATURNINA","RICARDA","POK","PASTY","ONIE","NUBIA","MORA","MIKE","MARIELLE","MARIELLA","MARIANELA","MARDELL","MANY","LUANNA","LOISE","LISABETH","LINDSY","LILLIANA","LILLIAM","LELAH","LEIGHA","LEANORA","LANG","KRISTEEN","KHALILAH","KEELEY","KANDRA","JUNKO","JOAQUINA","JERLENE","JANI","JAMIKA","JAME","HSIU","HERMILA","GOLDEN","GENEVIVE","EVIA","EUGENA","EMMALINE","ELFREDA","ELENE","DONETTE","DELCIE","DEEANNA","DARCEY","CUC","CLARINDA","CIRA","CHAE","CELINDA","CATHERYN","CATHERIN","CASIMIRA","CARMELIA","CAMELLIA","BREANA","BOBETTE","BERNARDINA","BEBE","BASILIA","ARLYNE","AMAL","ALAYNA","ZONIA","ZENIA","YURIKO","YAEKO","WYNELL","WILLOW","WILLENA","VERNIA","TU","TRAVIS","TORA","TERRILYN","TERICA","TENESHA","TAWNA","TAJUANA","TAINA","STEPHNIE","SONA","SOL","SINA","SHONDRA","SHIZUKO","SHERLENE","SHERICE","SHARIKA","ROSSIE","ROSENA","RORY","RIMA","RIA","RHEBA","RENNA","PETER","NATALYA","NANCEE","MELODI","MEDA","MAXIMA","MATHA","MARKETTA","MARICRUZ","MARCELENE","MALVINA","LUBA","LOUETTA","LEIDA","LECIA","LAURAN","LASHAWNA","LAINE","KHADIJAH","KATERINE","KASI","KALLIE","JULIETTA","JESUSITA","JESTINE","JESSIA","JEREMY","JEFFIE","JANYCE","ISADORA","GEORGIANNE","FIDELIA","EVITA","EURA","EULAH","ESTEFANA","ELSY","ELIZABET","ELADIA","DODIE","DION","DIA","DENISSE","DELORAS","DELILA","DAYSI","DAKOTA","CURTIS","CRYSTLE","CONCHA","COLBY","CLARETTA","CHU","CHRISTIA","CHARLSIE","CHARLENA","CARYLON","BETTYANN","ASLEY","ASHLEA","AMIRA","AI","AGUEDA","AGNUS","YUETTE","VINITA","VICTORINA","TYNISHA","TREENA","TOCCARA","TISH","THOMASENA","TEGAN","SOILA","SHILOH","SHENNA","SHARMAINE","SHANTAE","SHANDI","SEPTEMBER","SARAN","SARAI","SANA","SAMUEL","SALLEY","ROSETTE","ROLANDE","REGINE","OTELIA","OSCAR","OLEVIA","NICHOLLE","NECOLE","NAIDA","MYRTA","MYESHA","MITSUE","MINTA","MERTIE","MARGY","MAHALIA","MADALENE","LOVE","LOURA","LOREAN","LEWIS","LESHA","LEONIDA","LENITA","LAVONE","LASHELL","LASHANDRA","LAMONICA","KIMBRA","KATHERINA","KARRY","KANESHA","JULIO","JONG","JENEVA","JAQUELYN","HWA","GILMA","GHISLAINE","GERTRUDIS","FRANSISCA","FERMINA","ETTIE","ETSUKO","ELLIS","ELLAN","ELIDIA","EDRA","DORETHEA","DOREATHA","DENYSE","DENNY","DEETTA","DAINE","CYRSTAL","CORRIN","CAYLA","CARLITA","CAMILA","BURMA","BULA","BUENA","BLAKE","BARABARA","AVRIL","AUSTIN","ALAINE","ZANA","WILHEMINA","WANETTA","VIRGIL","VI","VERONIKA","VERNON","VERLINE","VASILIKI","TONITA","TISA","TEOFILA","TAYNA","TAUNYA","TANDRA","TAKAKO","SUNNI","SUANNE","SIXTA","SHARELL","SEEMA","RUSSELL","ROSENDA","ROBENA","RAYMONDE","PEI","PAMILA","OZELL","NEIDA","NEELY","MISTIE","MICHA","MERISSA","MAURITA","MARYLN","MARYETTA","MARSHALL","MARCELL","MALENA","MAKEDA","MADDIE","LOVETTA","LOURIE","LORRINE","LORILEE","LESTER","LAURENA","LASHAY","LARRAINE","LAREE","LACRESHA","KRISTLE","KRISHNA","KEVA","KEIRA","KAROLE","JOIE","JINNY","JEANNETTA","JAMA","HEIDY","GILBERTE","GEMA","FAVIOLA","EVELYNN","ENDA","ELLI","ELLENA","DIVINA","DAGNY","COLLENE","CODI","CINDIE","CHASSIDY","CHASIDY","CATRICE","CATHERINA","CASSEY","CAROLL","CARLENA","CANDRA","CALISTA","BRYANNA","BRITTENY","BEULA","BARI","AUDRIE","AUDRIA","ARDELIA","ANNELLE","ANGILA","ALONA","ALLYN","DOUGLAS","ROGER","JONATHAN","RALPH","NICHOLAS","BENJAMIN","BRUCE","HARRY","WAYNE","STEVE","HOWARD","ERNEST","PHILLIP","TODD","CRAIG","ALAN","PHILIP","EARL","DANNY","BRYAN","STANLEY","LEONARD","NATHAN","MANUEL","RODNEY","MARVIN","VINCENT","JEFFERY","JEFF","CHAD","JACOB","ALFRED","BRADLEY","HERBERT","FREDERICK","EDWIN","DON","RICKY","RANDALL","BARRY","BERNARD","LEROY","MARCUS","THEODORE","CLIFFORD","MIGUEL","JIM","TOM","CALVIN","BILL","LLOYD","DEREK","WARREN","DARRELL","JEROME","FLOYD","ALVIN","TIM","GORDON","GREG","JORGE","DUSTIN","PEDRO","DERRICK","ZACHARY","HERMAN","GLEN","HECTOR","RICARDO","RICK","BRENT","RAMON","GILBERT","MARC","REGINALD","RUBEN","NATHANIEL","RAFAEL","EDGAR","MILTON","RAUL","BEN","CHESTER","DUANE","FRANKLIN","BRAD","RON","ROLAND","ARNOLD","HARVEY","JARED","ERIK","DARRYL","NEIL","JAVIER","FERNANDO","CLINTON","TED","MATHEW","TYRONE","DARREN","LANCE","KURT","ALLAN","NELSON","GUY","CLAYTON","HUGH","MAX","DWAYNE","DWIGHT","ARMANDO","FELIX","EVERETT","IAN","WALLACE","KEN","BOB","ALFREDO","ALBERTO","DAVE","IVAN","BYRON","ISAAC","MORRIS","CLIFTON","WILLARD","ROSS","ANDY","SALVADOR","KIRK","SERGIO","SETH","KENT","TERRANCE","EDUARDO","TERRENCE","ENRIQUE","WADE","STUART","FREDRICK","ARTURO","ALEJANDRO","NICK","LUTHER","WENDELL","JEREMIAH","JULIUS","OTIS","TREVOR","OLIVER","LUKE","HOMER","GERARD","DOUG","KENNY","HUBERT","LYLE","MATT","ALFONSO","ORLANDO","REX","CARLTON","ERNESTO","NEAL","PABLO","LORENZO","OMAR","WILBUR","GRANT","HORACE","RODERICK","ABRAHAM","WILLIS","RICKEY","ANDRES","CESAR","JOHNATHAN","MALCOLM","RUDOLPH","DAMON","KELVIN","PRESTON","ALTON","ARCHIE","MARCO","WM","PETE","RANDOLPH","GARRY","GEOFFREY","JONATHON","FELIPE","GERARDO","ED","DOMINIC","DELBERT","COLIN","GUILLERMO","EARNEST","LUCAS","BENNY","SPENCER","RODOLFO","MYRON","EDMUND","GARRETT","SALVATORE","CEDRIC","LOWELL","GREGG","SHERMAN","WILSON","SYLVESTER","ROOSEVELT","ISRAEL","JERMAINE","FORREST","WILBERT","LELAND","SIMON","CLARK","IRVING","BRYANT","OWEN","RUFUS","WOODROW","KRISTOPHER","MACK","LEVI","MARCOS","GUSTAVO","JAKE","LIONEL","GILBERTO","CLINT","NICOLAS","ISMAEL","ORVILLE","ERVIN","DEWEY","AL","WILFRED","JOSH","HUGO","IGNACIO","CALEB","TOMAS","SHELDON","ERICK","STEWART","DOYLE","DARREL","ROGELIO","TERENCE","SANTIAGO","ALONZO","ELIAS","BERT","ELBERT","RAMIRO","CONRAD","NOAH","GRADY","PHIL","CORNELIUS","LAMAR","ROLANDO","CLAY","PERCY","DEXTER","BRADFORD","DARIN","AMOS","MOSES","IRVIN","SAUL","ROMAN","RANDAL","TIMMY","DARRIN","WINSTON","BRENDAN","ABEL","DOMINICK","BOYD","EMILIO","ELIJAH","DOMINGO","EMMETT","MARLON","EMANUEL","JERALD","EDMOND","EMIL","DEWAYNE","WILL","OTTO","TEDDY","REYNALDO","BRET","JESS","TRENT","HUMBERTO","EMMANUEL","STEPHAN","VICENTE","LAMONT","GARLAND","MILES","EFRAIN","HEATH","RODGER","HARLEY","ETHAN","ELDON","ROCKY","PIERRE","JUNIOR","FREDDY","ELI","BRYCE","ANTOINE","STERLING","CHASE","GROVER","ELTON","CLEVELAND","DYLAN","CHUCK","DAMIAN","REUBEN","STAN","AUGUST","LEONARDO","JASPER","RUSSEL","ERWIN","BENITO","HANS","MONTE","BLAINE","ERNIE","CURT","QUENTIN","AGUSTIN","MURRAY","JAMAL","ADOLFO","HARRISON","TYSON","BURTON","BRADY","ELLIOTT","WILFREDO","BART","JARROD","VANCE","DENIS","DAMIEN","JOAQUIN","HARLAN","DESMOND","ELLIOT","DARWIN","GREGORIO","BUDDY","XAVIER","KERMIT","ROSCOE","ESTEBAN","ANTON","SOLOMON","SCOTTY","NORBERT","ELVIN","WILLIAMS","NOLAN","ROD","QUINTON","HAL","BRAIN","ROB","ELWOOD","KENDRICK","DARIUS","MOISES","FIDEL","THADDEUS","CLIFF","MARCEL","JACKSON","RAPHAEL","BRYON","ARMAND","ALVARO","JEFFRY","DANE","JOESPH","THURMAN","NED","RUSTY","MONTY","FABIAN","REGGIE","MASON","GRAHAM","ISAIAH","VAUGHN","GUS","LOYD","DIEGO","ADOLPH","NORRIS","MILLARD","ROCCO","GONZALO","DERICK","RODRIGO","WILEY","RIGOBERTO","ALPHONSO","TY","NOE","VERN","REED","JEFFERSON","ELVIS","BERNARDO","MAURICIO","HIRAM","DONOVAN","BASIL","RILEY","NICKOLAS","MAYNARD","SCOT","VINCE","QUINCY","EDDY","SEBASTIAN","FEDERICO","ULYSSES","HERIBERTO","DONNELL","COLE","DAVIS","GAVIN","EMERY","WARD","ROMEO","JAYSON","DANTE","CLEMENT","COY","MAXWELL","JARVIS","BRUNO","ISSAC","DUDLEY","BROCK","SANFORD","CARMELO","BARNEY","NESTOR","STEFAN","DONNY","ART","LINWOOD","BEAU","WELDON","GALEN","ISIDRO","TRUMAN","DELMAR","JOHNATHON","SILAS","FREDERIC","DICK","IRWIN","MERLIN","CHARLEY","MARCELINO","HARRIS","CARLO","TRENTON","KURTIS","HUNTER","AURELIO","WINFRED","VITO","COLLIN","DENVER","CARTER","LEONEL","EMORY","PASQUALE","MOHAMMAD","MARIANO","DANIAL","LANDON","DIRK","BRANDEN","ADAN","BUFORD","GERMAN","WILMER","EMERSON","ZACHERY","FLETCHER","JACQUES","ERROL","DALTON","MONROE","JOSUE","EDWARDO","BOOKER","WILFORD","SONNY","SHELTON","CARSON","THERON","RAYMUNDO","DAREN","HOUSTON","ROBBY","LINCOLN","GENARO","BENNETT","OCTAVIO","CORNELL","HUNG","ARRON","ANTONY","HERSCHEL","GIOVANNI","GARTH","CYRUS","CYRIL","RONNY","LON","FREEMAN","DUNCAN","KENNITH","CARMINE","ERICH","CHADWICK","WILBURN","RUSS","REID","MYLES","ANDERSON","MORTON","JONAS","FOREST","MITCHEL","MERVIN","ZANE","RICH","JAMEL","LAZARO","ALPHONSE","RANDELL","MAJOR","JARRETT","BROOKS","ABDUL","LUCIANO","SEYMOUR","EUGENIO","MOHAMMED","VALENTIN","CHANCE","ARNULFO","LUCIEN","FERDINAND","THAD","EZRA","ALDO","RUBIN","ROYAL","MITCH","EARLE","ABE","WYATT","MARQUIS","LANNY","KAREEM","JAMAR","BORIS","ISIAH","EMILE","ELMO","ARON","LEOPOLDO","EVERETTE","JOSEF","ELOY","RODRICK","REINALDO","LUCIO","JERROD","WESTON","HERSHEL","BARTON","PARKER","LEMUEL","BURT","JULES","GIL","ELISEO","AHMAD","NIGEL","EFREN","ANTWAN","ALDEN","MARGARITO","COLEMAN","DINO","OSVALDO","LES","DEANDRE","NORMAND","KIETH","TREY","NORBERTO","NAPOLEON","JEROLD","FRITZ","ROSENDO","MILFORD","CHRISTOPER","ALFONZO","LYMAN","JOSIAH","BRANT","WILTON","RICO","JAMAAL","DEWITT","BRENTON","OLIN","FOSTER","FAUSTINO","CLAUDIO","JUDSON","GINO","EDGARDO","ALEC","TANNER","JARRED","DONN","TAD","PRINCE","PORFIRIO","ODIS","LENARD","CHAUNCEY","TOD","MEL","MARCELO","KORY","AUGUSTUS","KEVEN","HILARIO","BUD","SAL","ORVAL","MAURO","ZACHARIAH","OLEN","ANIBAL","MILO","JED","DILLON","AMADO","NEWTON","LENNY","RICHIE","HORACIO","BRICE","MOHAMED","DELMER","DARIO","REYES","MAC","JONAH","JERROLD","ROBT","HANK","RUPERT","ROLLAND","KENTON","DAMION","ANTONE","WALDO","FREDRIC","BRADLY","KIP","BURL","WALKER","TYREE","JEFFEREY","AHMED","WILLY","STANFORD","OREN","NOBLE","MOSHE","MIKEL","ENOCH","BRENDON","QUINTIN","JAMISON","FLORENCIO","DARRICK","TOBIAS","HASSAN","GIUSEPPE","DEMARCUS","CLETUS","TYRELL","LYNDON","KEENAN","WERNER","GERALDO","COLUMBUS","CHET","BERTRAM","MARKUS","HUEY","HILTON","DWAIN","DONTE","TYRON","OMER","ISAIAS","HIPOLITO","FERMIN","ADALBERTO","BO","BARRETT","TEODORO","MCKINLEY","MAXIMO","GARFIELD","RALEIGH","LAWERENCE","ABRAM","RASHAD","KING","EMMITT","DARON","SAMUAL","MIQUEL","EUSEBIO","DOMENIC","DARRON","BUSTER","WILBER","RENATO","JC","HOYT","HAYWOOD","EZEKIEL","CHAS","FLORENTINO","ELROY","CLEMENTE","ARDEN","NEVILLE","EDISON","DESHAWN","NATHANIAL","JORDON","DANILO","CLAUD","SHERWOOD","RAYMON","RAYFORD","CRISTOBAL","AMBROSE","TITUS","HYMAN","FELTON","EZEQUIEL","ERASMO","STANTON","LONNY","LEN","IKE","MILAN","LINO","JAROD","HERB","ANDREAS","WALTON","RHETT","PALMER","DOUGLASS","CORDELL","OSWALDO","ELLSWORTH","VIRGILIO","TONEY","NATHANAEL","DEL","BENEDICT","MOSE","JOHNSON","ISREAL","GARRET","FAUSTO","ASA","ARLEN","ZACK","WARNER","MODESTO","FRANCESCO","MANUAL","GAYLORD","GASTON","FILIBERTO","DEANGELO","MICHALE","GRANVILLE","WES","MALIK","ZACKARY","TUAN","ELDRIDGE","CRISTOPHER","CORTEZ","ANTIONE","MALCOM","LONG","KOREY","JOSPEH","COLTON","WAYLON","VON","HOSEA","SHAD","SANTO","RUDOLF","ROLF","REY","RENALDO","MARCELLUS","LUCIUS","KRISTOFER","BOYCE","BENTON","HAYDEN","HARLAND","ARNOLDO","RUEBEN","LEANDRO","KRAIG","JERRELL","JEROMY","HOBERT","CEDRICK","ARLIE","WINFORD","WALLY","LUIGI","KENETH","JACINTO","GRAIG","FRANKLYN","EDMUNDO","SID","PORTER","LEIF","JERAMY","BUCK","WILLIAN","VINCENZO","SHON","LYNWOOD","JERE","HAI","ELDEN","DORSEY","DARELL","BRODERICK","ALONSO" \ No newline at end of file diff --git a/project_euler/problem_22/sol1.c b/project_euler/problem_22/sol1.c new file mode 100644 index 0000000000..0ae681b1ba --- /dev/null +++ b/project_euler/problem_22/sol1.c @@ -0,0 +1,149 @@ +/** + * \file + * \brief [Problem 22](https://projecteuler.net/problem=22) solution + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include +#include +#include +#include +#ifdef _OPENMP +#include +#endif + +#define MAX_NAMES 6000 /**< Maximum number of names to store */ +#define MAX_NAME_LEN 20 /**< Maximum length of each name */ + +/** + * Alphabetical sorting using 'shell sort' algorithm + */ +void shell_sort(char data[][MAX_NAME_LEN], int LEN) +{ + const int gaps[] = {701, 301, 132, 57, 23, 10, 4, 1}; + const int gap_len = 8; + int i, j, g; + + for (g = 0; g < gap_len; g++) + { + int gap = gaps[g]; + for (i = gap; i < LEN; i++) + { + char tmp_buffer[MAX_NAME_LEN]; + strcpy(tmp_buffer, data[i]); + + for (j = i; j >= gap && strcmp(data[j - gap], tmp_buffer) > 0; + j -= gap) + strcpy(data[j], data[j - gap]); + strcpy(data[j], tmp_buffer); + } + } +#ifdef DEBUG + for (i = 0; i < LEN; i++) printf("%s\t", data[i]); +#endif +} + +/** + * Alphabetical sorting using 'lazy sort' algorithm + */ +void lazy_sort(char data[][MAX_NAME_LEN], int LEN) +{ + int i, j; + for (i = 0; i < LEN; i++) + { + for (j = i + 1; j < LEN; j++) + { + if (strcmp(data[i], data[j]) > 0) + { + char tmp_buffer[MAX_NAME_LEN]; + strcpy(tmp_buffer, data[i]); + strcpy(data[i], data[j]); + strcpy(data[j], tmp_buffer); + } + } + } +#ifdef DEBUG + for (i = 0; i < LEN; i++) printf("%s\t", data[i]); +#endif +} + +/** Main function */ +int main(int argc, char **argv) +{ + unsigned long COUNT = 0; + char *fname = "names.txt"; + char names[MAX_NAMES][MAX_NAME_LEN]; + short method = 0; /* sorting algorithm to use. 0 = lazy, 1 = shell-sort */ + + if (argc == 2) + method = atoi(argv[1]); + + FILE *fp = fopen(fname, "rt"); + if (!fp) + { + perror("Unable to open file"); + return -1; + } + + /* + * Loops to get total number of rows and columns in the file + */ + do + { + int ret = fscanf(fp, "\"%[^\",]\",", names[COUNT++]); + if (ret <= 0) + continue; + // printf("%s\t", names[COUNT - 1]); + } while (!feof(fp)); + fclose(fp); + + printf("\nTotal number of names: %lu\n", COUNT); + + if (method == 0) + { + clock_t start_time = clock(); + shell_sort(names, COUNT); + clock_t end_time = clock(); + printf("\nShell sort: %.4g millisecond\n", + 1e3 * (end_time - start_time) / CLOCKS_PER_SEC); + } + else if (method == 1) + { + clock_t start_time = clock(); + lazy_sort(names, COUNT); + clock_t end_time = clock(); + printf("\nLazy sort: %.4g millisecond\n", + 1e3 * (end_time - start_time) / CLOCKS_PER_SEC); + } + + long sum_score = 0; + clock_t start_time = clock(); + int i; + +#ifdef _OPENMP +#pragma omp parallel for schedule(runtime) reduction(+ : sum_score) +#endif +#ifdef DEBUG + for (i = 935; i < 940; i++) +#else + for (i = 0; i < COUNT; i++) +#endif + { + long score = 0; + /* score the alphabets in i^th name */ + for (int j = 0; names[i][j] != '\0'; j++) + score += names[i][j] - 'A' + + 1; /* convert ASCII character to integer score */ + sum_score += score * (i + 1); +#ifdef DEBUG + printf("Name: %s\tScore: %u x %u = %lu\n", names[i], score, i + 1, + (unsigned long)score * (i + 1)); +#endif + } + clock_t end_time = clock(); + printf("Scoring time: %.4g millisecond\n", + 1e3 * (end_time - start_time) / CLOCKS_PER_SEC); + + printf("Total Score = %lu\n", sum_score); + + return 0; +} diff --git a/project_euler/problem_23/sol1.c b/project_euler/problem_23/sol1.c new file mode 100644 index 0000000000..035d9081b1 --- /dev/null +++ b/project_euler/problem_23/sol1.c @@ -0,0 +1,138 @@ +/** + * \file + * \brief [Problem 23](https://projecteuler.net/problem=23) solution + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include +#include +#include +#ifdef _OPENMP +#include +#endif + +/** + * Returns: + * -1 if N is deficient + * 1 if N is abundant + * 0 if N is perfect + */ +char get_perfect_number(unsigned long N) +{ + unsigned long sum = 1; + char ret = 0; + + for (unsigned long i = 2; i * i <= N; i++) + { + if (N % i == 0) + { + sum += i; + unsigned long tmp = N / i; + if (tmp != i) + { + sum += tmp; + } + } + } + + ret = sum == N ? 0 : (sum > N ? 1 : -1); + // #ifdef DEBUG + // printf("%5lu: %5lu : %d\n", N, sum, ret); + // #endif + return ret; +} + +/** + * Is the given number an abundant number (1) or not (0) + */ +unsigned long is_abundant(unsigned long N) +{ + return get_perfect_number(N) == 1 ? 1 : 0; +} + +/** + * Find the next abundant number after N and not including N + */ +unsigned long get_next_abundant(unsigned long N) +{ + unsigned long i; + for (i = N + 1; !is_abundant(i); i++) + { + ; + } + return i; +} + +/** + * check if a given number can be represented as a sum + * of two abundant numbers. + * \returns 1 - if yes + * \returns 0 - if not + */ +char is_sum_of_abundant(unsigned long N) +{ + /* optimized logic: + * i + j = N where both i and j should be abundant + * hence we can simply check for j = N - i as we loop through i + */ + for (unsigned long i = get_next_abundant(1); i <= (N >> 1); + i = get_next_abundant(i)) + { + if (is_abundant(N - i)) + { +#ifdef DEBUG + printf("\t%4lu + %4lu = %4lu\n", i, N - i, N); +#endif + return 1; + } + } + return 0; +} + +/** Main function */ +int main(int argc, char **argv) +{ + unsigned long MAX_N = 28123; /* upper limit of numbers to check */ + + unsigned long sum = 0; + if (argc == 2) + { + MAX_N = strtoul(argv[1], NULL, 10); + } + +#ifdef _OPENMP + printf("Using OpenMP parallleization with %d threads\n", + omp_get_max_threads()); +#else + printf("Not using parallleization!\n"); +#endif + + double total_duration = 0.f; + long i; +#ifdef _OPENMP +#pragma omp parallel for reduction(+ : sum) schedule(runtime) +#endif + for (i = 1; i <= MAX_N; i++) + { + clock_t start_time = clock(); + if (!is_sum_of_abundant(i)) + { + sum += i; + } + clock_t end_time = clock(); + total_duration += (double)(end_time - start_time) / CLOCKS_PER_SEC; + + printf("... %5lu: %8lu\r", i, sum); + if (i % 100 == 0) + { + fflush(stdout); + } + } + + printf("Time taken: %.4g s\n", total_duration); + printf( + "Sum of numbers that cannot be represented as sum of two abundant " + "numbers : %lu\n", + sum); + + return 0; +} diff --git a/project_euler/problem_23/sol2.c b/project_euler/problem_23/sol2.c new file mode 100644 index 0000000000..4bb54fc52f --- /dev/null +++ b/project_euler/problem_23/sol2.c @@ -0,0 +1,205 @@ +/** + * \file + * \brief [Problem 23](https://projecteuler.net/problem=23) solution - + * optimization using look-up array + * \author [Krishna Vedala](https://github.com/kvedala) + * + * Optimization applied - compute & store abundant numbers once + * into a look-up array. + */ +#include +#include +#include +#ifdef _OPENMP +#include +#endif + +/** + * This is the global array to be used to store a flag to identify + * if a particular number is abundant (1) or not (0). + * Using a whole byte to store a binary info would be redundant. + * We will use each byte to represent 8 numbers by relying on bits. + * This saves memory required by 1/8 + */ +char *abundant_flags = NULL; + +/** + * \returns -1 if N is deficient + * \returns 1 if N is abundant + * \returns 0 if N is perfect + */ +char get_perfect_number(unsigned long N) +{ + unsigned long sum = 1; + char ret = 0; + + for (unsigned long i = 2; i * i <= N; i++) + { + if (N % i == 0) + { + sum += i; + unsigned long tmp = N / i; + if (tmp != i) + { + sum += tmp; + } + } + } + + ret = sum == N ? 0 : (sum > N ? 1 : -1); +#ifdef DEBUG + printf("%5lu: %5lu : %d\n", N, sum, ret); +#endif + return ret; +} + +/** + * Is the given number an abundant number (1) or not (0) + */ +char is_abundant(unsigned long N) +{ + // return abundant_flags[N >> 3] & (1 << N % 8) ? 1 : 0; + return abundant_flags[N >> 3] & (1 << (N & 7)) + ? 1 + : 0; /* optimized modulo operation */ +} + +/** + * Find the next abundant number after N and not including N + */ +unsigned long get_next_abundant(unsigned long N) +{ + unsigned long i; + /* keep checking successive numbers till an abundant number is found */ + for (i = N + 1; !is_abundant(i); ++i) + { + ; + } + return i; +} + +/** + * check if a given number can be represented as a sum + * of two abundant numbers. + * \returns 1 - if yes + * \returns 0 - if not + */ +char is_sum_of_abundant(unsigned long N) +{ + /* optimized logic: + * i + j = N where both i and j should be abundant + * hence we can simply check for j = N - i as we loop through i + */ + for (unsigned long i = get_next_abundant(1); i <= (N >> 1); + i = get_next_abundant(i)) + { + if (is_abundant(N - i)) + { +#ifdef DEBUG + printf("\t%4lu + %4lu = %4lu\n", i, N - i, N); +#endif + return 1; + } + } + return 0; +} + +/** Main function */ +int main(int argc, char **argv) +{ + long MAX_N = 28123; /* Limit of numbers to check */ + + unsigned long sum = 0; + if (argc == 2) + { + MAX_N = strtoul(argv[1], NULL, 10); + } + + /* byte array to store flags to identify abundant numbers + * the flags are identified by bits + */ + abundant_flags = (char *)calloc(MAX_N >> 3, 1); + if (!abundant_flags) + { + perror("Unable to allocate memoey!"); + return -1; + } + +#ifdef _OPENMP + printf("Using OpenMP parallleization with %d threads\n", + omp_get_max_threads()); +#else + printf("Not using parallleization!\n"); +#endif + + clock_t start_time = clock(); + + /* Loop to set abundant flags */ + long N; +#ifdef _OPENMP +#pragma omp for schedule(runtime) +#endif + for (N = 1; N <= MAX_N; N++) + { + char ret = get_perfect_number(N); + if (ret == 1) + { + // int byte_offset = N % 8, index = N >> 3; + int byte_offset = N & 7, index = N >> 3; +#ifdef _OPENMP +#pragma omp critical +#endif + abundant_flags[index] |= ret << byte_offset; + } + // if (i % 100 == 0) + // printf("... %5lu: %8lu\r", i, sum); + } + + clock_t end_time = clock(); + double t1 = 1e3 * (end_time - start_time) / CLOCKS_PER_SEC; + printf("Time taken to get abundant numbers: %.4g ms\n", t1); + + clock_t t2 = 0; + long i; +#ifdef _OPENMP +#pragma omp parallel for schedule(runtime) reduction(+ : sum) +#endif + for (i = 1; i < MAX_N; i++) + { + clock_t start_time1 = clock(); + if (!is_sum_of_abundant(i)) + { + // #ifdef _OPENMP + // #pragma omp critical + // #endif + sum += i; + } + clock_t end_time1 = clock(); +#ifdef _OPENMP +#pragma omp critical +#endif + t2 += end_time1 - start_time1; + + printf("... %5lu: %8lu\r", i, sum); + if (i % 100 == 0) + { + fflush(stdout); + } + } + +#ifdef DEBUG + putchar('\n'); +#endif + double t22 = 1e3 * t2 / CLOCKS_PER_SEC; + printf("Time taken for final sum: %.4g ms\nTotal Time taken: %.4g ms\n", + t22, t1 + t22); + printf("Memory used: %lu bytes\n", MAX_N >> 3); + printf( + "Sum of numbers that cannot be represented as sum of two abundant " + "numbers : %lu\n", + sum); + + free(abundant_flags); + + return 0; +} diff --git a/project_euler/problem_24/sol1 b/project_euler/problem_24/sol1 new file mode 100755 index 0000000000..b67b122c01 Binary files /dev/null and b/project_euler/problem_24/sol1 differ diff --git a/project_euler/problem_25/sol1.c b/project_euler/problem_25/sol1.c new file mode 100644 index 0000000000..e72e35149a --- /dev/null +++ b/project_euler/problem_25/sol1.c @@ -0,0 +1,125 @@ +/** + * \file + * \brief [Problem 25](https://projecteuler.net/problem=25) solution implemented + * using arbitrarily large numbers represented as arrays + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include +#include +#include +#include +#include + +#define MAX_DIGITS 1000 /**< maximum number of digits */ + +/** + * Function to add arbitraty length decimal integers stored in an array.\n + * a + b = c = new b + */ +unsigned int add_numbers(unsigned char *a, unsigned char *b, unsigned char *c, + int N) +{ + unsigned char carry = 0; + unsigned int i; + + for (i = 0; i < N; i++) + { + // printf("\t%d + %d + %d ", a[i], b[i], carry); + c[i] = carry + a[i] + b[i]; + if (c[i] > 9) /* check for carry */ + { + carry = 1; + c[i] -= 10; + } + else + { + carry = 0; + } + // printf("= %d, %d\n", carry, c[i]); + } + + while (carry != 0) + { + // printf("\t\t...adding new digit\n"); + // printf("\t0 + %d + %d ", b[i], carry); + c[i] = carry + c[i]; + if (c[i] > 9) + { + carry = 1; + c[i] -= 10; + } + else + { + carry = 0; + } + // printf("= %d, %d\n", carry, c[i]); + i++; + } + return i; +} + +/** Print a large number */ +int print_number(unsigned char *number, int N) +{ + int start_pos = N - 1; + + /* skip all initial zeros */ + while (number[start_pos] == 0) start_pos--; + + for (int i = start_pos; i >= 0; i--) putchar(number[i] + 0x30); + + return 0; +} + +/** Get number of digits in a large number */ +unsigned int get_digits(unsigned char *number) +{ + unsigned int digits = MAX_DIGITS; + while (number[digits] == 0) digits--; + return digits; +} + +/** Main function */ +int main(int argc, char *argv[]) +{ + unsigned char + fn[MAX_DIGITS + 1]; /* array to store digits of a large number */ + unsigned char fn1[MAX_DIGITS + 1]; + unsigned char sum[MAX_DIGITS + 1]; + + memset(fn, 0, MAX_DIGITS); + memset(fn1, 0, MAX_DIGITS); + memset(sum, 0, MAX_DIGITS); + + fn[0] = 1; + fn1[1] = 1; + + unsigned int index = 1, digit_count = 1; + + clock_t start_time = clock(); + do + { + digit_count = add_numbers(fn, fn1, sum, digit_count); + // digit_count = get_digits(sum); + + // printf("%5u (%u) (%u) ", index, digit_count, get_digits(sum)); + // print_number(sum, digit_count); + // putchar('\n'); + + if (digit_count == MAX_DIGITS) + { + break; + } + memcpy(fn, fn1, MAX_DIGITS); + memcpy(fn1, sum, MAX_DIGITS); + index++; + } while (digit_count < MAX_DIGITS); + clock_t end_time = clock(); + + printf("Time taken: %.4g ms\n", + 1e3 * (end_time - start_time) / CLOCKS_PER_SEC); + printf("The nth term for %d digits: %u \n", MAX_DIGITS, index--); + print_number(sum, digit_count); + + return 0; +} diff --git a/project_euler/problem_26/sol1.c b/project_euler/problem_26/sol1.c new file mode 100644 index 0000000000..66decd3211 --- /dev/null +++ b/project_euler/problem_26/sol1.c @@ -0,0 +1,88 @@ +/** + * \file + * \brief [Problem 26](https://projecteuler.net/problem=26) solution + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include +#include +#include +#include +#ifdef _OPENMP +#include +#endif + +#define MAX_DENO 2000 /**< limit of unit fractions */ +#define MAX_LEN \ + (MAX_DENO + 10) /**< length of resulting recurring fraction number */ + +/** comparison function for use with internal `qsort` algorithm */ +int compare(const void *a, const void *b) +{ + return (*(unsigned short *)a - *(unsigned short *)b); +} + +/** Main function */ +int main(int argc, char *argv[]) +{ + unsigned short max_digits = 0, max_idx_number = 0; + + clock_t start_time = clock(); + short deno; +#ifdef _OPENMP +#pragma omp for +#endif + for (deno = 2; deno < MAX_DENO; deno++) + { + unsigned short remainders[MAX_LEN]; + unsigned short rem = 1, *rem_ptr = remainders; + memset(remainders, (unsigned short)-1, + MAX_LEN * sizeof(unsigned short)); + // remainders[0] = 1; + // printf("1/%-4u\t ", deno); + unsigned short index = 0, num_digits; + + while (rem != 0) + { + rem = (rem * 10) % deno; + if (rem == 0) + { + index = 0; + break; + } + rem_ptr = (unsigned short *)bsearch( + &rem, remainders, MAX_LEN, sizeof(unsigned short), compare); + // printf("%2d, ", rem); + // printf("(%14p), ", rem_ptr); + if (rem_ptr != NULL) + break; + remainders[index] = rem; + rem_ptr = remainders; + index++; + } + + num_digits = index - (rem_ptr - remainders); + // printf("\n\t(%14p, %14p, %4u, %4u)\n", rem_ptr, remainders, index, + // num_digits); +#ifdef _OPENMP +#pragma omp critical + { +#endif + if (num_digits > max_digits) + { + max_digits = num_digits; + max_idx_number = deno; + // printf("\t (%u, %u)\n ", max_digits, max_idx_number); + } +#ifdef _OPENMP + } +#endif + } + clock_t end_time = clock(); + + printf("Time taken: %.4g ms\n", + 1e3 * (double)(end_time - start_time) / CLOCKS_PER_SEC); + printf("Maximum digits: %hu\t Denominator: %hu\n", max_digits, + max_idx_number); + + return 0; +} diff --git a/project_euler/problem_3/sol1.c b/project_euler/problem_3/sol1.c new file mode 100644 index 0000000000..24872476b1 --- /dev/null +++ b/project_euler/problem_3/sol1.c @@ -0,0 +1,79 @@ +/** + * \file + * \brief [Problem 3](https://projecteuler.net/problem=3) solution + * + * Problem: + * + * The prime factors of 13195 are 5,7,13 and 29. What is the largest prime + * factor of a given number N? e.g. for 10, largest prime factor = 5. For 17, + * largest prime factor = 17. + */ +#include +#include + +/** Check if the given number is prime */ +char isprime(int no) +{ + int sq; + + if (no == 2) + { + return 1; + } + else if (no % 2 == 0) + { + return 0; + } + sq = ((int)(sqrt(no))) + 1; + for (int i = 3; i < sq; i += 2) + { + if (no % i == 0) + { + return 0; + } + } + return 1; +} + +/** Main function */ +int main() +{ + int maxNumber = 0; + int n = 0; + int n1; + scanf("%d", &n); + if (isprime(n) == 1) + printf("%d", n); + else + { + while (n % 2 == 0) + { + n = n / 2; + } + if (isprime(n) == 1) + { + printf("%d\n", n); + } + else + { + n1 = ((int)(sqrt(n))) + 1; + for (int i = 3; i < n1; i += 2) + { + if (n % i == 0) + { + if (isprime((int)(n / i)) == 1) + { + maxNumber = n / i; + break; + } + else if (isprime(i) == 1) + { + maxNumber = i; + } + } + } + printf("%d\n", maxNumber); + } + } + return 0; +} \ No newline at end of file diff --git a/project_euler/problem_3/sol2.c b/project_euler/problem_3/sol2.c new file mode 100644 index 0000000000..39eefb8c5b --- /dev/null +++ b/project_euler/problem_3/sol2.c @@ -0,0 +1,33 @@ +/** + * \file + * \brief [Problem 3](https://projecteuler.net/problem=3) solution + * + * Problem: + * + * The prime factors of 13195 are 5,7,13 and 29. What is the largest prime + * factor of a given number N? e.g. for 10, largest prime factor = 5. For 17, + * largest prime factor = 17. + */ +#include + +/** Main function */ +int main() +{ + int n = 0; + scanf("%d", &n); + int prime = 1; + int i = 2; + while (i * i <= n) + { + while (n % i == 0) + { + prime = i; + n /= i; + } + i += 1; + } + if (n > 1) + prime = n; + printf("%d\n", prime); + return 0; +} \ No newline at end of file diff --git a/project_euler/problem_4/sol.c b/project_euler/problem_4/sol.c new file mode 100644 index 0000000000..a445d936e7 --- /dev/null +++ b/project_euler/problem_4/sol.c @@ -0,0 +1,41 @@ +/** + * \file + * \brief [Problem 4](https://projecteuler.net/problem=4) solution + */ +#include + +/** Check if number is palindromic + * \param[in] n number to check + * \returns 1 if palindromic + * \returns 0 if not palindromic + */ +int is_palindromic(unsigned int n) +{ + unsigned int reversed = 0, t = n; + + while (t > 0) + { + reversed = 10 * reversed + (t % 10); + t /= 10; + } + return reversed == n; +} + +/** Main function */ +int main(void) +{ + unsigned int i, j, max = 0; + for (i = 100; i <= 999; i++) + { + for (j = 100; j <= 999; j++) + { + unsigned int p = i * j; + if (is_palindromic(p) && p > max) + { + max = p; + } + } + } + printf("%u\n", max); + return 0; +} diff --git a/project_euler/problem_401/sol1.c b/project_euler/problem_401/sol1.c new file mode 100644 index 0000000000..707364fff8 --- /dev/null +++ b/project_euler/problem_401/sol1.c @@ -0,0 +1,155 @@ +/** + * \file + * \brief [Problem 401](https://projecteuler.net/problem=401) solution - + * Sum of squares of divisors + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include +#include +#include +#include +#define __STDC_FORMAT_MACROS +#include +#ifdef _OPENMP +#include +#endif + +#define MOD_LIMIT (uint64_t)1e9 /**< modulo limit */ +#define MAX_LENGTH 5000 /**< chunk size of array allocation */ + +/** + * Check if a number is present in given array + * \param[in] N number to check + * \param[in] D array to check + * \param[in] L length of array + * \returns 1 if present + * \returns 0 if absent + */ +char is_in(uint64_t N, uint64_t *D, uint64_t L) +{ + uint64_t i; + for (i = 0; i < L; i++) + { + if (D[i] == N) + { + return 1; + } + } + return 0; +} + +/** + * Get all integer divisors of a number + * \param[in] N number to find divisors for + * \param[out] D array to store divisors in + * \returns number of divisors found + */ +uint64_t get_divisors(uint64_t N, uint64_t *D) +{ + uint64_t q, r; + int64_t i, num = 0; + + if (N == 1) + { + D[0] = 1; + return 1; + } + + // search till sqrt(N) + // because after this, the pair of divisors will repeat themselves + for (i = 1; i * i <= N + 1; i++) + { + r = N % i; // get reminder + + // reminder = 0 if 'i' is a divisor of 'N' + if (r == 0) + { + q = N / i; + if (!is_in(i, D, num)) // if divisor was already stored + { + D[num] = i; + num++; + } + if (!is_in(q, D, num)) // if divisor was already stored + { + D[num] = q; + num++; + } + } + + if (num == MAX_LENGTH) + { // limit of array reached, allocate more space + D = (uint64_t *)realloc(D, MAX_LENGTH * sizeof(uint64_t) << 1); + } + } + return num; +} + +/** + * compute sum of squares of all integer factors of a number + * \param[in] N + * \returns sum of squares + */ +uint64_t sigma2(uint64_t N) +{ + uint64_t sum = 0, L; + int64_t i; + uint64_t *D = (uint64_t *)malloc(MAX_LENGTH * sizeof(uint64_t)); + + L = get_divisors(N, D); + for (i = 1; i < L; i++) + { + uint64_t DD = (D[i] * D[i]) % MOD_LIMIT; + sum += DD; + } + + free(D); + return sum % MOD_LIMIT; +} + +/** + * sum of squares of factors of numbers + * from 1 thru N + */ +uint64_t sigma(uint64_t N) +{ + uint64_t s, sum = 0; + int64_t i; + +#ifdef _OPENMP +// parallelize on threads +#pragma omp parallel for reduction(+ : sum) +#endif + for (i = 0; i <= N; i++) + { + s = sigma2(i); + sum += s; + } + return sum % MOD_LIMIT; +} + +/** Main function */ +int main(int argc, char **argv) +{ + uint64_t N = 1000; + + if (argc == 2) + { + N = strtoll(argv[1], NULL, 10); + } + else if (argc > 2) + { + fprintf(stderr, "Wrong number of input arguments!\n"); + printf("Usage:\t ./sol1.c [N=1000]"); + return -1; + } + + clock_t start_time = clock(); + uint64_t result = sigma(N); + double dtime = clock() - start_time; + + printf("N = %" PRIu64 "\nSum: %" PRIu64 "\n", N, result); + printf("Time taken: %.4gms\n", dtime * 1e3 / CLOCKS_PER_SEC); + + return 0; +} diff --git a/project_euler/problem_5/sol1.c b/project_euler/problem_5/sol1.c new file mode 100644 index 0000000000..374237fa35 --- /dev/null +++ b/project_euler/problem_5/sol1.c @@ -0,0 +1,48 @@ +/** + * \file + * \brief [Problem 5](https://projecteuler.net/problem=5) solution - Naive + * algorithm (slowest) + * + * \see Faster: problem_5/sol2.c + * \see Fastest: problem_5/sol3.c + */ +#include +#include + +/** Pretty naive implementation. Just checks every number if it's devisable by 1 + * through 20 + * @param n number to check + * @returns 0 if not divisible + * @returns 1 if divisible + */ +static char check_number(unsigned long long n) +{ + for (unsigned long long i = 1; i <= 20; ++i) + { + if (n % i != 0) + { + return 0; + } + } + + return 1; +} + +/** + * @brief Main function + * + * @return 0 on exit + */ +int main(void) +{ + for (unsigned long long n = 1;; ++n) + { + if (check_number(n)) + { + printf("Result: %llu\n", n); + break; + } + } + + return 0; +} diff --git a/project_euler/problem_5/sol2.c b/project_euler/problem_5/sol2.c new file mode 100644 index 0000000000..96ad71c730 --- /dev/null +++ b/project_euler/problem_5/sol2.c @@ -0,0 +1,59 @@ +/** + * \file + * \brief [Problem 5](https://projecteuler.net/problem=5) solution - Naive + * algorithm (Improved over problem_5/sol1.c) + * @details Little bit improved version of the naive `problem_5/sol1.c`. Since + * the number has to be divisable by 20, we can start at 20 and go in 20 steps. + * Also we don't have to check against any number, since most of them are + * implied by other divisions (i.e. if a number is divisable by 20, it's also + * divisable by 2, 5, and 10). This all gives a 97% perfomance increase on my + * machine (9.562 vs 0.257) + * + * \see Slower: problem_5/sol1.c + * \see Faster: problem_5/sol3.c + */ +#include +#include + +/** + * @brief Hack to store divisors between 1 & 20 + */ +static unsigned int divisors[] = { + 11, 13, 14, 16, 17, 18, 19, 20, +}; + +/** Checks if a given number is devisable by every number between 1 and 20 + * @param n number to check + * @returns 0 if not divisible + * @returns 1 if divisible + */ +static int check_number(unsigned long long n) +{ + for (size_t i = 0; i < 7; ++i) + { + if (n % divisors[i] != 0) + { + return 0; + } + } + + return 1; +} + +/** + * @brief Main function + * + * @return 0 on exit + */ +int main(void) +{ + for (unsigned long long n = 20;; n += 20) + { + if (check_number(n)) + { + printf("Result: %llu\n", n); + break; + } + } + return 0; +} diff --git a/project_euler/problem_5/sol3.c b/project_euler/problem_5/sol3.c new file mode 100644 index 0000000000..d701276589 --- /dev/null +++ b/project_euler/problem_5/sol3.c @@ -0,0 +1,60 @@ +/** + * \file + * \brief [Problem 5](https://projecteuler.net/problem=5) solution (Fastest). + * @details Solution is the LCM of all numbers between 1 and 20. + * + * \see Slowest: problem_5/sol1.c + * \see Slower: problem_5/sol2.c + */ +#include + +/** Compute [Greatest Common Divisor + * (GCD)](https://en.wikipedia.org/wiki/Greatest_common_divisor) of two numbers + * using Euclids algorithm + * @param a first number + * @param b second number + * @return GCD of `a` and `b` + */ +unsigned long gcd(unsigned long a, unsigned long b) +{ + unsigned long r; + if (a > b) + { + unsigned long t = a; + a = b; + b = t; + } + while ((r = (a % b))) + { + a = b; + b = r; + } + return b; +} + +/** Compute [Least Common Multiple + * (LCM)](https://en.wikipedia.org/wiki/Least_common_multiple) of two numbers + * @param a first number + * @param b second number + * @return LCM of `a` and `b` + */ +unsigned long lcm(unsigned long a, unsigned long b) +{ + unsigned long long p = (unsigned long long)a * b; + return p / gcd(a, b); +} + +/** Main function + * @returns 0 on exit + */ +int main(void) +{ + unsigned long ans = 1; + unsigned long i; + for (i = 1; i <= 20; i++) + { + ans = lcm(ans, i); + } + printf("%lu\n", ans); + return 0; +} diff --git a/project_euler/problem_6/sol.c b/project_euler/problem_6/sol.c new file mode 100644 index 0000000000..5530880a57 --- /dev/null +++ b/project_euler/problem_6/sol.c @@ -0,0 +1,19 @@ +/** + * \file + * \brief [Problem 6](https://projecteuler.net/problem=6) solution + */ +#include + +/** Main function */ +int main(void) +{ + unsigned s1 = 0, s2 = 0, i; + for (i = 1; i <= 100; i++) + { + s1 += i * i; + s2 += i; + } + unsigned ans = s2 * s2 - s1; + printf("%u\n", ans); + return 0; +} diff --git a/project_euler/problem_7/sol.c b/project_euler/problem_7/sol.c new file mode 100644 index 0000000000..406ece7a83 --- /dev/null +++ b/project_euler/problem_7/sol.c @@ -0,0 +1,40 @@ +/** + * \file + * \brief [Problem 7](https://projecteuler.net/problem=7) solution. + * @see Another version: problem_7/sol2.c + */ +#include +#include + +/** Main function + * @return 0 on exit + */ +int main(void) +{ + char *sieve; + size_t i; + unsigned count = 0; + size_t n = 1000000; + const unsigned target = 10001; + + sieve = (char *)calloc(n, sizeof(char)); + for (i = 2; i < n; i++) + { + if (!sieve[i]) + { + size_t j; + count++; + if (count == target) + { + printf("%lu\n", i); + break; + } + for (j = i * 2; j < n; j += i) + { + sieve[j] = 1; + } + } + } + free(sieve); + return 0; +} diff --git a/project_euler/problem_7/sol2.c b/project_euler/problem_7/sol2.c new file mode 100644 index 0000000000..c5eebad400 --- /dev/null +++ b/project_euler/problem_7/sol2.c @@ -0,0 +1,38 @@ +/** + * \file + * \brief [Problem 7](https://projecteuler.net/problem=7) solution. + * @see Faster version problem_7/sol.c + */ +#include + +/** Main function + * @return 0 on exit + */ +int main() +{ + int n; + scanf("%d", &n); + int number_of_prime = 0; + for (int i = 2;; i++) + { + int divisors = 0; + for (int j = 1; j <= i; j++) + { + if (i % j == 0) + { + divisors++; + } + } + if (divisors == 2) + { + number_of_prime++; + if (number_of_prime == n) + { + printf("%d", i); + break; + } + } + } + + return 0; +} diff --git a/project_euler/problem_8/digits.txt b/project_euler/problem_8/digits.txt new file mode 100644 index 0000000000..dfd915301e --- /dev/null +++ b/project_euler/problem_8/digits.txt @@ -0,0 +1,20 @@ +73167176531330624919225119674426574742355349194934 +96983520312774506326239578318016984801869478851843 +85861560789112949495459501737958331952853208805511 +12540698747158523863050715693290963295227443043557 +66896648950445244523161731856403098711121722383113 +62229893423380308135336276614282806444486645238749 +30358907296290491560440772390713810515859307960866 +70172427121883998797908792274921901699720888093776 +65727333001053367881220235421809751254540594752243 +52584907711670556013604839586446706324415722155397 +53697817977846174064955149290862569321978468622482 +83972241375657056057490261407972968652414535100474 +82166370484403199890008895243450658541227588666881 +16427171479924442928230863465674813919123162824586 +17866458359124566529476545682848912883142607690042 +24219022671055626321111109370544217506941658960408 +07198403850962455444362981230987879927244284909188 +84580156166097919133875499200524063689912560717606 +05886116467109405077541002256983155200055935729725 +71636269561882670428252483600823257530420752963450 diff --git a/project_euler/problem_8/sol1.c b/project_euler/problem_8/sol1.c new file mode 100644 index 0000000000..012594897d --- /dev/null +++ b/project_euler/problem_8/sol1.c @@ -0,0 +1,116 @@ +/** + * \file + * \brief [Problem 8](https://projecteuler.net/problem=8) solution + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include +#include + +/** Compute the product of two numbers in a file + * + * \param[in] fp pointer to file that is already open + * \param[in] start_pos line number of the first numer + * \param[in] num_digits number of digits on the line to multiply + * \returns expected product + */ +long long int get_product(FILE *fp, long start_pos, int num_digits) +{ + char ch = ' '; /* temporary variable to store character read from file */ + unsigned char num = 0; /* temporary variable to store digit read */ + long long int prod = 1; /* product accumulator */ + int count = + 0; /* we use this variable to count number of bytes of file read */ + + /* accumulate product for num_digits */ + for (int i = 0; i < num_digits; i++, count++) + { + /* get character from file */ + ch = getc(fp); + + /* the ASCII codes of digits is between 0x30 and 0x39. + * any character not in this range implies an invalid character + */ + if (ch < 0x30 || ch > 0x39) + { + if (ch == EOF) + return 0; + i--; + continue; + } + + num = ch - 0x30; /* convert character digit to number */ + if (num == 0) + { + /* If number is zero, we can skip the next 'num_digits' + * because this '0' will repeat in the next 'num_digit' + * multiplications. Hence, we also do not update the file position + */ + /* NOTE: this is not needed but helps get results faster :) */ + return 0; + } + + prod *= num; /* accumulate product */ + } + + /* set file position to the next starting character + 1 */ + fseek(fp, -count + 1, SEEK_CUR); + + return prod; +} + +/** Main function */ +int main(int argc, char *argv[]) +{ + int position = 0; + int num_digits = 4; + long long int prod, max_prod = 0; + + /* if second command-line argument is ge=iven, + * use it as the number of digits to compute + * successive product for + */ + if (argc == 2) + num_digits = atoi(argv[1]); + + /* open file to read digits from */ + FILE *fp = fopen("digits.txt", "rt"); + if (!fp) + { + perror("Unable to open file"); + return -1; + } + + /* loop through all digits in the file */ + do + { + /* get product of 'num_digits' from current position in file */ + prod = get_product(fp, ftell(fp), num_digits); + + if (prod > max_prod) + { + max_prod = prod; + position = ftell(fp) - 1; + } + } while (!feof(fp)); /* loop till end of file is reached */ + + printf("Maximum product: %lld\t Location: %d^th position\n\t", max_prod, + position); + fseek(fp, position, + SEEK_SET); /* move cursor to identified position in file */ + /* loop through all digits */ + for (; num_digits > 0; num_digits--) + { + char ch = getc(fp); /* get character */ + /* skip invalid character */ + if (ch < 0x30 || ch > 0x39) + continue; + if (num_digits > 1) + printf("%c x ", ch); + else + printf("%c = %lld\n", ch, max_prod); + } + + fclose(fp); /* close file */ + + return 0; +} diff --git a/project_euler/problem_8/sol2.c b/project_euler/problem_8/sol2.c new file mode 100644 index 0000000000..4656911999 --- /dev/null +++ b/project_euler/problem_8/sol2.c @@ -0,0 +1,128 @@ +/** + * \file + * \brief [Problem 8](https://projecteuler.net/problem=8) solution + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include +#include +#include /* for memmove */ + +/** Main function */ +int main(int argc, char *argv[]) +{ + int position = 0, num_bad_chars = 0; + int num_digits = 4; + char ch; + unsigned char num, num_prev; + unsigned char *buffer = NULL; + long long int prod = 1, max_prod = 0; + + /* if second command-line argument is given, + * use it as the number of digits to compute + * successive product for + */ + if (argc == 2) + num_digits = atoi(argv[1]); + + /* allocate memory to store past values */ + buffer = calloc(num_digits, sizeof(unsigned char)); + if (!buffer) + { + perror("Unable to allocate memory for buffer"); + return -1; + } + + /* open file to read digits from */ + FILE *fp = fopen("digits.txt", "rt"); + if (!fp) + { + perror("Unable to open file"); + free(buffer); /* free allocated memory */ + return -1; + } + + /* loop through all digits in the file */ + do + { + /* get character from file */ + ch = getc(fp); + + /* the ASCII codes of digits is between 0x30 and 0x39. + * any character not in this range implies an invalid character + */ + if (ch < 0x30 || ch > 0x39) + { + num_bad_chars++; /* this is used to get the bad characters in the + sequence of 13 characters */ + continue; + } + else if (num_bad_chars > 0) + num_bad_chars--; + + num = ch - 0x30; /* convert character digit to number */ + num_prev = buffer[0]; /* previous n^th digit */ + + /* left shift the buffer - + * using a for loop or a faster memory move + */ + memmove(buffer, buffer + 1, num_digits - 1); + /* + for (int i = 1; i < num_digits; i++) + buffer[i-1] = buffer[i]; + */ + + buffer[num_digits - 1] = num; /* save the latest number in buffer */ + + if (num_prev != 0) + { + /* since product is accumulated, the new product can be obtained by + * simply multiplying the new digit and dividing with the oldest + * digit + */ + prod /= num_prev; /* divide first to avoid over-flows */ + prod *= num; + } + else + { + prod = 1; + for (int i = 0; i < num_digits; i++) + { + if (buffer[i] == 0) + { + prod = 0; + break; /* break innermost for-loop */ + } + prod *= buffer[i]; + } + } + + /* check if a new maxima was found */ + if (prod > max_prod) + { + max_prod = prod; + position = ftell(fp) - num_bad_chars - num_digits - 1; + } + } while (!feof(fp)); /* loop till end of file is reached */ + + printf("Maximum product: %lld\t Location: %d^th position\n\t", max_prod, + position); + fseek(fp, position, + SEEK_SET); /* move cursor to identified position in file */ + /* loop through all digits */ + for (; num_digits > 0; num_digits--) + { + char ch = getc(fp); /* get character */ + /* skip invalid character */ + if (ch < 0x30 || ch > 0x39) + continue; + if (num_digits > 1) + printf("%c x ", ch); + else + printf("%c = %lld\n", ch, max_prod); + } + + fclose(fp); /* close file */ + free(buffer); /* free allocated memory */ + + return 0; +} diff --git a/project_euler/problem_9/sol1.c b/project_euler/problem_9/sol1.c new file mode 100644 index 0000000000..cba1a89a5a --- /dev/null +++ b/project_euler/problem_9/sol1.c @@ -0,0 +1,26 @@ +/** + * \file + * \brief [Problem 9](https://projecteuler.net/problem=9) solution - A naive + * implementation + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include + +/** Main function */ +int main(void) +{ + for (int a = 1; a < 300; a++) + for (int b = a + 1; b < 400; b++) + for (int c = b + 1; c < 500; c++) + { + if (a * a + b * b == c * c) + if (a + b + c == 1000) + { + printf("%d x %d x %d = %ld\n", a, b, c, + (long int)a * b * c); + return 0; + } + } + + return 0; +} diff --git a/project_euler/problem_9/sol2.c b/project_euler/problem_9/sol2.c new file mode 100644 index 0000000000..4afe69d5ac --- /dev/null +++ b/project_euler/problem_9/sol2.c @@ -0,0 +1,43 @@ +/** + * \file + * \brief [Problem 9](https://projecteuler.net/problem=9) solution + * \author [Krishna Vedala](https://github.com/kvedala) + * + Problem Statement: + A Pythagorean triplet is a set of three natural numbers, \f$a < b < c\f$, + for which, \f$a^2 + b^2 = c^2\f$. For example, \f$3^2 + 4^2 = 9 + 16 = 25 = + 5^2\f$. There exists exactly one Pythagorean triplet for which \f$a + b + c = + 1000\f$. Find the product abc. + + + Given \f$a^2 + b^2 = c^2\f$ and \f$a+b+c = n\f$, we can write: + \f{eqnarray*}{ + b &=& \frac{n^2 - 2an}{2n - 2a}\\ + c &=& n - a - b + \f} + */ +#include +#include + +/** Main function */ +int main(void) +{ + int N = 1000; + + for (int a = 1; a < 300; a++) + { + long tmp1 = N * N - 2 * a * N; + long tmp2 = 2 * (N - a); + div_t tmp3 = div(tmp1, tmp2); + int b = tmp3.quot; + int c = N - a - b; + + if (a * a + b * b == c * c) + { + printf("%d x %d x %d = %ld\n", a, b, c, (long int)a * b * c); + return 0; + } + } + + return 0; +} \ No newline at end of file diff --git a/scripts/file_linter.py b/scripts/file_linter.py new file mode 100644 index 0000000000..bce3ad86fb --- /dev/null +++ b/scripts/file_linter.py @@ -0,0 +1,40 @@ +import os +import subprocess +import sys + +print("Python {}.{}.{}".format(*sys.version_info)) # Python 3.8 +with open("git_diff.txt") as in_file: + modified_files = sorted(in_file.read().splitlines()) + print("{} files were modified.".format(len(modified_files))) + + cpp_exts = tuple(".c .c++ .cc .cpp .cu .cuh .cxx .h .h++ .hh .hpp .hxx".split()) + cpp_files = [file for file in modified_files if file.lower().endswith(cpp_exts)] + print(f"{len(cpp_files)} C++ files were modified.") + if not cpp_files: + sys.exit(0) + subprocess.run(["clang-tidy", "-p=build", "--fix", *cpp_files, "--"], + check=True, text=True, stderr=subprocess.STDOUT) + subprocess.run(["clang-format", "-i", *cpp_files], + check=True, text=True, stderr=subprocess.STDOUT) + + upper_files = [file for file in cpp_files if file != file.lower()] + if upper_files: + print(f"{len(upper_files)} files contain uppercase characters:") + print("\n".join(upper_files) + "\n") + + space_files = [file for file in cpp_files if " " in file or "-" in file] + if space_files: + print(f"{len(space_files)} files contain space or dash characters:") + print("\n".join(space_files) + "\n") + + nodir_files = [file for file in cpp_files if file.count(os.sep) != 1 and "project_euler" not in file and "data_structure" not in file] + if len(nodir_files) > 1: + nodir_file_bad_files = len(nodir_files) - 1 + print(f"{len(nodir_files)} files are not in one and only one directory:") + print("\n".join(nodir_files) + "\n") + else: + nodir_file_bad_files = 0 + bad_files = nodir_file_bad_files + len(upper_files + space_files) + + if bad_files: + sys.exit(bad_files) diff --git a/scripts/leetcode_directory_md.py b/scripts/leetcode_directory_md.py new file mode 100644 index 0000000000..4c9a7dc01b --- /dev/null +++ b/scripts/leetcode_directory_md.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 + +from dataclasses import dataclass +from os import listdir +from pathlib import Path + +import requests + + +@dataclass +class Task: + """The task dataclass. Container for task info""" + + id: str + title: str + solution: str + difficulty: str + + +def fetch_leetcode_folder_tasks(solutions_folder: Path) -> list[Task]: + """Fetch leetcode tasks from the Leetcode""" + + # Fetch tasks info from the leetcode API. + resp = requests.get("https://leetcode.com/api/problems/algorithms/", timeout=10) + content_dict = resp.json() + + raw_tasks_id_dict = {} + + for task in content_dict["stat_status_pairs"]: + task_stat = task["stat"] + raw_tasks_id_dict[str(task_stat["frontend_question_id"])] = task + + # Generate result tasks info to be inserted into the document + tasks_list = [] + + difficulty = {1: "Easy", 2: "Medium", 3: "Hard"} + + for fl in listdir(solutions_folder): + task_id = fl.split(".")[0] + + raw_task = raw_tasks_id_dict.get(task_id, None) + if raw_task is None: + continue + + raw_task_stat = raw_task["stat"] + tasks_list.append( + Task( + id=f'{raw_task_stat["frontend_question_id"]}', + title=f'[{raw_task_stat["question__title"]}](https://leetcode.com/problems/{raw_task_stat["question__title_slug"]})', + solution=f"[C](./src/{fl})", + difficulty=f'{difficulty.get(raw_task["difficulty"]["level"], "")}', + ) + ) + + return tasks_list + + +HEADER_ID = "#" +HEADER_TITLE = "Title" +HEADER_SOLUTION = "Solution" +HEADER_DIFFICULTY = "Difficulty" +SEPARATOR = "-" + + +def print_directory_md(tasks_list: list[Task]) -> None: + """Print tasks into the stdout""" + + def get_max_len(get_item): + return max(list(map(lambda x: len(get_item(x)), tasks_list))) + + id_max_length = max(get_max_len(lambda x: x.id), len(HEADER_ID)) + title_max_length = max(get_max_len(lambda x: x.title), len(HEADER_TITLE)) + solution_max_length = max(get_max_len(lambda x: x.solution), len(HEADER_SOLUTION)) + difficulty_max_length = max( + get_max_len(lambda x: x.difficulty), len(HEADER_DIFFICULTY) + ) + + def formatted_string(header, title, solution, difficulty): + return ( + f"| {header.rjust(id_max_length)} " + + f"| {title.ljust(title_max_length)} " + + f"| {solution.ljust(solution_max_length)} " + + f"| {difficulty.ljust(difficulty_max_length)} |" + ) + + tasks_rows = [] + + tasks_rows.append( + formatted_string(HEADER_ID, HEADER_TITLE, HEADER_SOLUTION, HEADER_DIFFICULTY) + ) + tasks_rows.append( + formatted_string( + id_max_length * SEPARATOR, + title_max_length * SEPARATOR, + solution_max_length * SEPARATOR, + difficulty_max_length * SEPARATOR, + ) + ) + + tasks_list.sort(key=lambda x: int(x.id.strip())) + + for task in tasks_list: + tasks_rows.append( + formatted_string(task.id, task.title, task.solution, task.difficulty) + ) + + print( + """ +# LeetCode + +### LeetCode Algorithm +""" + ) + + for item in tasks_rows: + print(item) + + +if __name__ == "__main__": + top_dir = Path(".") + solutions_folder = top_dir / "leetcode" / "src" + + tasks_list = fetch_leetcode_folder_tasks(solutions_folder) + print_directory_md(tasks_list) diff --git a/searching/Binary_Search.c b/searching/Binary_Search.c deleted file mode 100644 index 9fa0dc2d78..0000000000 --- a/searching/Binary_Search.c +++ /dev/null @@ -1,39 +0,0 @@ -#include - -// Recursive Function- It returns location of x assumiung array arr[l..r] is present, otherwise -1 - -int binarysearch(int arr[], int l, int r, int x) -{ - if (r >= l) - { - int mid = l + (r - l)/2; - - // If element is present at middle - if (arr[mid] == x) return mid; - - // If element is smaller than middle - if (arr[mid] > x) return binarysearch(arr, l, mid-1, x); - - // Else element is in right subarray - return binarysearch(arr, mid+1, r, x); - } - - // When element is not present in array - return -1; -} - -int main(void) -{ - // give function an array to work with - int arr[] = {2, 3, 4, 10, 40}; - // get size of array - int n = sizeof(arr)/ sizeof(arr[0]); - //set value to look for - int x = 10; - // set result to what is returned from binarysearch - int result = binarysearch(arr, 0, n-1, x); - // print out result - (result == -1) ? printf("Element is not in the array\n") - : printf("Element is present at index %d\n", result); - return 0; -} diff --git a/searching/CMakeLists.txt b/searching/CMakeLists.txt new file mode 100644 index 0000000000..9053dbb241 --- /dev/null +++ b/searching/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} *.c ) +# 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 ".c" "" testname ${testsourcefile} ) + add_executable( ${testname} ${testsourcefile} ) + + if(OpenMP_C_FOUND) + target_link_libraries(${testname} OpenMP::OpenMP_C) + endif() + if(MATH_LIBRARY) + target_link_libraries(${testname} ${MATH_LIBRARY}) + endif() + install(TARGETS ${testname} DESTINATION "bin/searching") + +endforeach( testsourcefile ${APP_SOURCES} ) diff --git a/searching/Jump_Search.c b/searching/Jump_Search.c deleted file mode 100644 index 0afb8b77e9..0000000000 --- a/searching/Jump_Search.c +++ /dev/null @@ -1,33 +0,0 @@ -#include -#include -#define min(X,Y) ((X) < (Y) ? (X) : (Y)) -int jump_search(int* arr, int x); -int n; - -int main() { - int arr[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610 }; - n = sizeof(arr) / sizeof(int); - int x = 55; - int index = jump_search(arr, x); - printf("\nNumber %d is at index %d\n", x, index); -} - -int jump_search(int* arr, int x) { - int step = floor(sqrt(n)); - int prev = 0; - while (*(arr + (min(step, n) - 1)) < x) { - prev = step; - step += floor(sqrt(n)); - if (prev >= n) - return -1; - } - - while (*(arr + prev) < x) { - prev = prev + 1; - if (prev == fmin(step, n)) - return -1; - } - if (*(arr + prev) == x) - return prev; - return -1; -} diff --git a/searching/LinearSearch.c b/searching/LinearSearch.c deleted file mode 100644 index 6a3eabbd22..0000000000 --- a/searching/LinearSearch.c +++ /dev/null @@ -1,27 +0,0 @@ -#include - -int linearsearch(int *arr, int size, int val){ - int i; - for (i = 0; i < size; i++){ - if (arr[i] == val) - return 1; - } - return 0; -} - -void main(){ - int s,i,v; - printf("Enter the size of the array:\n"); - scanf("%d",&s); - - int a[s]; - printf("Enter the contents for an array of size %d:\n", s); - for (i = 0; i < s; i++) scanf("%d", &a[i]);// accepts the values of array elements until the loop terminates// - - printf("Enter the value to be searched:\n"); - scanf("%d", &v); - if (linearsearch(a, s, v)) - printf("Value %d is in the array.\n", v); - else - printf("Value %d is not in the array.\n", v); -} diff --git a/searching/Other_Binary_Search.c b/searching/Other_Binary_Search.c deleted file mode 100644 index cef27daa71..0000000000 --- a/searching/Other_Binary_Search.c +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include -#define len 5 - - -int binarySearch(int array[], int leng, int searchX) -{ - int pos = -1, right, left, i = 0; - - left = 0; - right = leng - 1; - - for (i = 0; i < leng; i++) - { - pos = (left + right) / 2; - - if (array[pos] == searchX) - return pos; - else - { - if (array[pos] < searchX) - left = pos + 1; - else - { - right = pos - 1; - } - } - } - - - -} - - -void main(int argc, char *argv[]) -{ - int array[len] = { 5, 8 , 10 , 14 ,16 }; - - int position; - position = binarySearch(array, len, 5); - - if (position < 0) - printf("The number %d doesnt exist in array\n", 5); - else - { - printf("The number %d exist in array at position : %d \n", 5, position); - } - - -} diff --git a/searching/binary_search.c b/searching/binary_search.c new file mode 100644 index 0000000000..b1fab1f74a --- /dev/null +++ b/searching/binary_search.c @@ -0,0 +1,109 @@ +/** + * @file + * @brief Program to perform [binary + * search](https://en.wikipedia.org/wiki/Binary_search_algorithm) of a target + * value in a given *sorted* array. + * @authors [James McDermott](https://github.com/theycallmemac) - recursive + * algorithm + * @authors [Krishna Vedala](https://github.com/kvedala) - iterative algorithm + */ +#include +#include + +/** Recursive implementation + * \param[in] arr array to search + * \param l left index of search range + * \param r right index of search range + * \param x target value to search for + * \returns location of x assuming array arr[l..r] is present + * \returns -1 otherwise + */ +int binarysearch1(const int *arr, int l, int r, int x) +{ + if (r >= l) + { + int mid = l + (r - l) / 2; + + // If element is present at middle + if (arr[mid] == x) + return mid; + + // If element is smaller than middle + if (arr[mid] > x) + return binarysearch1(arr, l, mid - 1, x); + + // Else element is in right subarray + return binarysearch1(arr, mid + 1, r, x); + } + + // When element is not present in array + return -1; +} + +/** Iterative implementation + * \param[in] arr array to search + * \param l left index of search range + * \param r right index of search range + * \param x target value to search for + * \returns location of x assuming array arr[l..r] is present + * \returns -1 otherwise + */ +int binarysearch2(const int *arr, int l, int r, int x) +{ + int mid = l + (r - l) / 2; + + while (arr[mid] != x) + { + if (r <= l || r < 0) + return -1; + + if (arr[mid] > x) + // If element is smaller than middle + r = mid - 1; + else + // Else element is in right subarray + l = mid + 1; + + mid = l + (r - l) / 2; + } + + // When element is not present in array + return mid; +} + +/** Test implementations */ +void test() +{ + // give function an array to work with + int arr[] = {2, 3, 4, 10, 40}; + // get size of array + int n = sizeof(arr) / sizeof(arr[0]); + + printf("Test 1.... "); + // set value to look for + int x = 10; + // set result to what is returned from binarysearch + int result = binarysearch1(arr, 0, n - 1, x); + assert(result == 3); + printf("passed recursive... "); + result = binarysearch2(arr, 0, n - 1, x); + assert(result == 3); + printf("passed iterative...\n"); + + printf("Test 2.... "); + x = 5; + // set result to what is returned from binarysearch + result = binarysearch1(arr, 0, n - 1, x); + assert(result == -1); + printf("passed recursive... "); + result = binarysearch2(arr, 0, n - 1, x); + assert(result == -1); + printf("passed iterative...\n"); +} + +/** Main function */ +int main(void) +{ + test(); + return 0; +} diff --git a/searching/binarys.c b/searching/binarys.c deleted file mode 100644 index 9e64089ba8..0000000000 --- a/searching/binarys.c +++ /dev/null @@ -1,38 +0,0 @@ - #include - - int main() - { - int c, first, last, middle, n, search, array[100]; - - printf("Enter number of elements\n"); - scanf("%d",&n); - - printf("Enter %d integers\n", n); - - for (c = 0; c < n; c++) - scanf("%d",&array[c]); - - printf("Enter value to find\n"); - scanf("%d", &search); - - first = 0; - last = n - 1; - middle = (first+last)/2; - - while (first <= last) { - if (array[middle] < search) - first = middle + 1; - else if (array[middle] == search) { - printf("%d found at location %d.\n", search, middle+1); - break; - } - else - last = middle - 1; - - middle = (first + last)/2; - } - if (first > last) - printf("Not found! %d isn't present in the list.\n", search); - - return 0; - } diff --git a/searching/exponential_search.c b/searching/exponential_search.c new file mode 100644 index 0000000000..efb1ec7105 --- /dev/null +++ b/searching/exponential_search.c @@ -0,0 +1,110 @@ +/** + * \file + * \brief [Exponential Search](https://github.com/TheAlgorithms/Algorithms-Explanation/blob/master/en/Search%20Algorithms/Exponential%20Search.md) + * \author [Alessio Farinelli](https://github.com/faridevnz) + */ +#include /// for assert +#include /// for int64_t, uint16_t +#include /// for printf + +#define ELEMENT -10 + +int64_t binary_search(const int64_t* arr, const uint16_t l_index, const uint16_t r_index, const int64_t n); ///< used to perform the binary search over the given array +int64_t exponential_search(const int64_t* arr, const uint16_t length, const int64_t n); ///< used to perform the exponential search over the given array +static void test(); ///< used to run the self-test implementations + +/** + * Function: exponential_search + * \brief algorithm that search the index of the given item + * \details recursive function that take an array and quickly find the range + * where to apply the binary search algorithm to find the given element + * ---------------------------- + * \param arr array where search the element + * \param length the total length of the given array (arr) + * \param n element to find in the array (arr) + * + * \returns the index of the element (n) in the array (arr) + * \returns -1 if the element wasn't found + */ +int64_t exponential_search(const int64_t* arr, const uint16_t length, const int64_t n) +{ + if ( length == 0 ) { return -1; } + // find the upperbound + uint32_t upper_bound = 1; + while ( upper_bound <= length && arr[upper_bound] < n ) { upper_bound = upper_bound * 2; } + // calculate the range ( between lower_boud and upper_bound ) + uint16_t lower_bound = upper_bound/2; + if ( upper_bound > length ) { upper_bound = length; } + // apply the binary search in the range + return binary_search(arr, lower_bound, upper_bound, n); +} + +/** + * Function: binary_search + * \brief algorithm that search the index of the given item + * \details recursive function that search the given element in + * the array using the [Binary Search](https://github.com/TheAlgorithms/Algorithms-Explanation/blob/master/en/Search%20Algorithms/Binary%20Search.md) + * ---------------------------- + * \param arr array where search the element + * \param l_index start index of the array (arr) to apply the algorithm + * \param r_index end index of the array (arr) to apply the algorithm + * \param n element to find in the array (arr) + * + * \returns the index of the element (n) in the array (arr) + * \returns -1 if the n element wasn't found + */ +int64_t binary_search(const int64_t* arr, const uint16_t l_index, const uint16_t r_index, const int64_t n) +{ + // calculate the middle index of the array + uint16_t middle_index = l_index + ( r_index - l_index ) / 2; + // base cases + if ( l_index > r_index ) { return -1; } + if ( arr[middle_index] == n ) { return middle_index; } + // recursion + if ( arr[middle_index] > n ) { return binary_search(arr, l_index, middle_index-1, n); } // left + return binary_search(arr, middle_index+1, r_index, n); // right +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + test(); // run self-test implementations + return 0; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() +{ + // empty array + int64_t arr_empty[] = { 0 }; + assert(exponential_search(arr_empty, 0, 10) == -1); + // elent not found + int64_t arr_found[] = {1, 2, 3}; + assert(exponential_search(arr_found, 3, 10) == -1); + // element found in an array of length 1 + int64_t arr_one[] = {1}; + assert(exponential_search(arr_found, 1, 1) == 0); + // find the first element in an array of length 2 + int64_t arr_first_2[] = {1, 2}; + assert(exponential_search(arr_first_2, 2, 1) == 0); + // find the last element in an array of length 2 + int64_t arr_last_2[] = {1, 2}; + assert(exponential_search(arr_last_2, 2, 2) == 1); + // find the first element in an array of length n + int64_t arr_first_n[] = {-1, 2, 4, 6, 8}; + assert(exponential_search(arr_first_n, 5, -1) == 0); + // find the last element in an array of length n + int64_t arr_last_n[] = {-1, 2, 4, 6, 8}; + assert(exponential_search(arr_last_n, 5, 8) == 4); + // find an element in an array of length n + int64_t arr_middle[] = {-1, 2, 4, 6, 8}; + assert(exponential_search(arr_middle, 5, 6) == 3); + + printf("All tests have successfully passed!\n"); +} diff --git a/searching/fibonacciSearch.c b/searching/fibonacci_search.c similarity index 71% rename from searching/fibonacciSearch.c rename to searching/fibonacci_search.c index 35f63b987b..cc6b35540b 100644 --- a/searching/fibonacciSearch.c +++ b/searching/fibonacci_search.c @@ -4,8 +4,8 @@ int fibMonaccianSearch(int arr[], int x, int n) { /* Initialize fibonacci numbers */ - int fibMMm2 = 0; // (m-2)'th Fibonacci No. - int fibMMm1 = 1; // (m-1)'th Fibonacci No. + int fibMMm2 = 0; // (m-2)'th Fibonacci No. + int fibMMm1 = 1; // (m-1)'th Fibonacci No. int fibM = fibMMm2 + fibMMm1; // m'th Fibonacci /* fibM is going to store the smallest Fibonacci @@ -14,7 +14,7 @@ int fibMonaccianSearch(int arr[], int x, int n) { fibMMm2 = fibMMm1; fibMMm1 = fibM; - fibM = fibMMm2 + fibMMm1; + fibM = fibMMm2 + fibMMm1; } // Marks the eliminated range from front @@ -28,13 +28,13 @@ int fibMonaccianSearch(int arr[], int x, int n) // Check if fibMm2 is a valid location // sets i to the min. of (offset+fibMMm2) and (n-1) - int i = ((offset+fibMMm2) < (n-1)) ? (offset+fibMMm2) : (n-1); + int i = ((offset + fibMMm2) < (n - 1)) ? (offset + fibMMm2) : (n - 1); /* If x is greater than the value at index fibMm2, cut the subarray array from offset to i */ if (arr[i] < x) { - fibM = fibMMm1; + fibM = fibMMm1; fibMMm1 = fibMMm2; fibMMm2 = fibM - fibMMm1; offset = i; @@ -44,30 +44,29 @@ int fibMonaccianSearch(int arr[], int x, int n) cut the subarray after i+1 */ else if (arr[i] > x) { - fibM = fibMMm2; + fibM = fibMMm2; fibMMm1 = fibMMm1 - fibMMm2; fibMMm2 = fibM - fibMMm1; } /* element found. return index */ - else return i; + else + return i; } /* comparing the last element with x */ - if(fibMMm1 && arr[offset+1]==x)return offset+1; + if (fibMMm1 && arr[offset + 1] == x) + return offset + 1; /*element not found. return -1 */ return -1; } - int main(void) { - int arr[] = {10, 22, 35, 40, 45, 50, 80, 82, - 85, 90, 100}; - int n = sizeof(arr)/sizeof(arr[0]); + int arr[] = {10, 22, 35, 40, 45, 50, 80, 82, 85, 90, 100}; + int n = sizeof(arr) / sizeof(arr[0]); int x = 85; - printf("Found at index: %d", - fibMonaccianSearch(arr, x, n)); + printf("Found at index: %d", fibMonaccianSearch(arr, x, n)); return 0; } diff --git a/searching/floyd_cycle_detection_algorithm.c b/searching/floyd_cycle_detection_algorithm.c new file mode 100644 index 0000000000..285a72c637 --- /dev/null +++ b/searching/floyd_cycle_detection_algorithm.c @@ -0,0 +1,68 @@ +/** + * @file + * @brief Implementation of [Floyd's Cycle + * Detection](https://en.wikipedia.org/wiki/Cycle_detection) algorithm + * @details + * Given an array of integers containing `n + 1` integers, where each + * integer is in the range [1, n] inclusive. If there is only one duplicate + * number in the input array, this algorithm returns the duplicate number in + * O(1) space and the time complexity is less than O(n^2) without modifying the + * original array, otherwise, it returns -1. + * @author [Swastika Gupta](https://github.com/Swastyy) + */ + +#include /// for assert +#include /// for uint32_t +#include /// for IO operations + +/** + * @brief The main function implements the search algorithm + * @tparam T type of array + * @param in_arr the input array + * @param n size of the array + * @returns the duplicate number + */ +uint32_t duplicateNumber(const uint32_t *in_arr, size_t n) +{ + if (n <= 1) { // to find duplicate in an array its size should be at least 2 + return -1; + } + uint32_t tortoise = in_arr[0]; ///< variable tortoise is used for the longer + ///< jumps in the array + uint32_t hare = in_arr[0]; ///< variable hare is used for shorter jumps in the array + do { // loop to enter the cycle + tortoise = in_arr[tortoise]; // tortoise is moving by one step + hare = in_arr[in_arr[hare]]; // hare is moving by two steps + } while (tortoise != hare); + tortoise = in_arr[0]; + while (tortoise != hare) { // loop to find the entry point of cycle + tortoise = in_arr[tortoise]; + hare = in_arr[hare]; + } + return tortoise; +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() +{ + uint32_t arr[] = {1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610}; // input array + size_t n = sizeof(arr) / sizeof(int); + + printf("1st test... "); + uint32_t index = duplicateNumber(arr, n); // calling the duplicateNumber function to check which number occurs twice in the array + assert(index == 1); // the number which occurs twice is 1 or not + printf("passed\n"); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + test(); // run self-test implementations + return 0; +} diff --git a/searching/interpolation_search.c b/searching/interpolation_search.c index f6a340eeee..595f3d8776 100644 --- a/searching/interpolation_search.c +++ b/searching/interpolation_search.c @@ -1,35 +1,55 @@ -#include -int interpolationSearch(int arr[], int n, int x) -{ - int q=NULL; - while(q + +/* By comparison, binary search always chooses the middle of the remaining + * search space, discarding one half or the other, depending on the comparison + * between the key found at the estimated position and the key sought. The + * remaining search space is reduced to the part before or after the estimated + * position. The linear search uses equality only as it compares elements + * one-by-one from the start, ignoring any sorting. On average the interpolation + * search makes about log(log(n)) comparisons (if the elements are uniformly + * distributed), where n is the number of elements to be searched. In the worst + * case (for instance where the numerical values of the keys increase + * exponentially) it can make up to O(n) comparisons. In + * interpolation-sequential search, interpolation is used to find an item near + * the one being searched for, then linear search is used to find the exact + * item. */ + +int interpolationSearch(int arr[], int n, int key) +{ + int low = 0, high = n - 1; + while (low <= high && key >= arr[low] && key <= arr[high]) { - if(arr[q]==x) - return q; - q++; + /* Calculate the nearest posible position of key */ + int pos = + low + ((key - arr[low]) * (high - low)) / (arr[high] - arr[low]); + if (key > arr[pos]) + low = pos + 1; + else if (key < arr[pos]) + high = pos - 1; + else /* Found */ + return pos; } + /* Not found */ return -1; } - int main() { - // Array of items on which search will - // be conducted. int x; - int arr[] = {10, 12, 13, 16, 18, 19, 20, 21, 22, 23, - 24, 33, 35, 42, 47}; - int n = sizeof(arr)/sizeof(arr[0]); //To get length of an array - - printf("Enter the no, to be searched"); - scanf("%d",&x); // Element to be searched - + int arr[] = {10, 12, 13, 16, 18, 19, 20, 21, 22, 23, 24, 33, 35, 42, 47}; + int n = sizeof(arr) / sizeof(arr[0]); + + printf("Array: "); + for (int i = 0; i < n; i++) printf("%d ", arr[i]); + printf("\nEnter the number to be searched: "); + scanf("%d", &x); /* Element to be searched */ + int index = interpolationSearch(arr, n, x); - - // If element was found + + /* If element was found */ if (index != -1) - printf("Element found at position %d", index+1); + printf("Element found at position: %d\n", index); else - printf("Element not found."); + printf("Element not found.\n"); return 0; } diff --git a/searching/jump_search.c b/searching/jump_search.c new file mode 100644 index 0000000000..7359655410 --- /dev/null +++ b/searching/jump_search.c @@ -0,0 +1,85 @@ +/** + * @file jump_search.c + * @brief Implementation of [jump + * search](https://en.wikipedia.org/wiki/Jump_search) algorithm. + */ +#include +#include +#include + +/** + * @brief Macro to return the minimum of two values + */ +#define min(X, Y) ((X) < (Y) ? (X) : (Y)) + +/** + * @brief Implement Jump-search algorithm + * + * @param [in] arr Array to search within + * @param x value to search for + * @param n length of array + * @return index where the value was found + * @return -1 if value not found + */ +int jump_search(const int *arr, int x, size_t n) +{ + int step = floor(sqrt(n)); + int prev = 0; + + while (arr[min(step, n) - 1] < x) + { + prev = step; + step += floor(sqrt(n)); + if (prev >= n) + { + return -1; + } + } + + while (arr[prev] < x) + { + prev = prev + 1; + if (prev == min(step, n)) + { + return -1; + } + } + if (arr[prev] == x) + { + return prev; + } + return -1; +} + +/** + * @brief Test implementation of the function + * + */ +void test() +{ + int arr[] = {0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610}; + size_t n = sizeof(arr) / sizeof(int); + + int x = 55; + printf("Test 1.... "); + int index = jump_search(arr, x, n); + assert(index == 10); + printf("passed\nTest 2.... "); + x = 56; + index = jump_search(arr, x, n); + assert(index == -1); + printf("passed\nTest 3.... "); + x = 13; + index = jump_search(arr, x, n); + assert(index == 7); + printf("passed\n"); +} + +/** + * @brief Main function + */ +int main() +{ + test(); + return 0; +} diff --git a/searching/linear_search.c b/searching/linear_search.c new file mode 100644 index 0000000000..6982512cc4 --- /dev/null +++ b/searching/linear_search.c @@ -0,0 +1,36 @@ +#include +#include + +int linearsearch(int *arr, int size, int val) +{ + int i; + for (i = 0; i < size; i++) + { + if (arr[i] == val) + return 1; + } + return 0; +} + +int main() +{ + int n, i, v; + printf("Enter the size of the array:\n"); + scanf("%d", &n); // Taking input for the size of Array + + int *a = (int *)malloc(n * sizeof(int)); + printf("Enter the contents for an array of size %d:\n", n); + for (i = 0; i < n; i++) + scanf("%d", &a[i]); // accepts the values of array elements until the + // loop terminates// + + printf("Enter the value to be searched:\n"); + scanf("%d", &v); // Taking input the value to be searched + if (linearsearch(a, n, v)) + printf("Value %d is in the array.\n", v); + else + printf("Value %d is not in the array.\n", v); + + free(a); + return 0; +} diff --git a/searching/modifiedBinarySearch.c b/searching/modifiedBinarySearch.c deleted file mode 100644 index 60b47424eb..0000000000 --- a/searching/modifiedBinarySearch.c +++ /dev/null @@ -1,86 +0,0 @@ -#include - -int n,m; //size of the matrix - -// This function does Binary search for x in i-th row from j_low to j_high. -void binarySearch(int mat[n][m], int i, int j_low,int j_high, int x) -{ - while (j_low <= j_high) - { - int j_mid = (j_low + j_high) / 2; - - // Element found - if (mat[i][j_mid] == x){ - printf("Found at (%d,%d)\n",i,j_mid); - return ; - } - else if (mat[i][j_mid] > x) - j_high = j_mid - 1; - else - j_low = j_mid + 1; - } - // element not found - printf("element not found\n"); -} - -// Function to perform binary search on the mid values of row to get the desired pair of rows -// where the element can be found -void modifiedBinarySearch(int mat[n][m], int n, int m, int x) -{ // If Single row matrix - if (n == 1){ - binarySearch(mat, 0, 0, m-1, x); - return; - } - - // Do binary search in middle column. - // Condition to terminate the loop when the 2 desired rows are found. - int i_low = 0, i_high = n-1, j_mid = m/2; - while ((i_low+1) < i_high) - { - int i_mid = (i_low + i_high) / 2; - // element found - if (mat[i_mid][j_mid] == x){ - printf("Found at (%d,%d)\n",i_mid,j_mid); - return; - } - else if (mat[i_mid][j_mid] > x) - i_high = i_mid; - else - i_low = i_mid; - } - // If element is present on the mid of the two rows - if (mat[i_low][j_mid] == x) - printf("Found at (%d,%d)\n",i_low,j_mid); - else if (mat[i_low+1][j_mid] == x) - printf("Found at (%d,%d)\n",i_low+1,j_mid); - - // Search element on 1st half of 1st row - else if (x <= mat[i_low][j_mid-1]) - binarySearch(mat, i_low, 0, j_mid-1, x); - - // Search element on 2nd half of 1st row - else if (x >= mat[i_low][j_mid+1] && x <= mat[i_low][m-1]) - binarySearch(mat, i_low, j_mid+1, m-1, x); - - // Search element on 1st half of 2nd row - else if (x <= mat[i_low+1][j_mid-1]) - binarySearch(mat, i_low+1, 0, j_mid-1, x); - - // search element on 2nd half of 2nd row - else - binarySearch(mat, i_low+1, j_mid+1, m-1, x); -} - -int main() -{ - int x; //element to be searched - scanf("%d %d %d\n",&n,&m,&x); - int mat[n][m]; - for(int i=0; i +#include + +/** This function does Binary search for `x` in `i`-th row from `j_low` to + * `j_high`. + * @param mat 2D matrix to search within + * @param i row to search in + * @param j_low start column index + * @param j_high end column index + * @param x value to search for + * @return column where `x` was found + * @return -1 if value not found + */ +int binarySearch(const int **mat, int i, int j_low, int j_high, int x) +{ + while (j_low <= j_high) + { + int j_mid = (j_low + j_high) / 2; + + // Element found + if (mat[i][j_mid] == x) + { + printf("Found at (%d,%d)\n", i, j_mid); + return j_mid; + } + else if (mat[i][j_mid] > x) + j_high = j_mid - 1; + else + j_low = j_mid + 1; + } + + // element not found + printf("element not found\n"); + return -1; +} + +/** Function to perform binary search on the mid values of row to get the + * desired pair of rows where the element can be found + * @param [in] mat matrix to search for the value in + * @param n number of rows in the matrix + * @param m number of columns in the matrix + * @param x value to search for + */ +void modifiedBinarySearch(const int **mat, int n, int m, int x) +{ // If Single row matrix + if (n == 1) + { + binarySearch(mat, 0, 0, m - 1, x); + return; + } + + // Do binary search in middle column. + // Condition to terminate the loop when the 2 desired rows are found. + int i_low = 0, i_high = n - 1, j_mid = m / 2; + while ((i_low + 1) < i_high) + { + int i_mid = (i_low + i_high) / 2; + // element found + if (mat[i_mid][j_mid] == x) + { + printf("Found at (%d,%d)\n", i_mid, j_mid); + return; + } + else if (mat[i_mid][j_mid] > x) + i_high = i_mid; + else + i_low = i_mid; + } + // If element is present on the mid of the two rows + if (mat[i_low][j_mid] == x) + printf("Found at (%d,%d)\n", i_low, j_mid); + else if (mat[i_low + 1][j_mid] == x) + printf("Found at (%d,%d)\n", i_low + 1, j_mid); + + // Search element on 1st half of 1st row + else if (x <= mat[i_low][j_mid - 1]) + binarySearch(mat, i_low, 0, j_mid - 1, x); + + // Search element on 2nd half of 1st row + else if (x >= mat[i_low][j_mid + 1] && x <= mat[i_low][m - 1]) + binarySearch(mat, i_low, j_mid + 1, m - 1, x); + + // Search element on 1st half of 2nd row + else if (x <= mat[i_low + 1][j_mid - 1]) + binarySearch(mat, i_low + 1, 0, j_mid - 1, x); + + // search element on 2nd half of 2nd row + else + binarySearch(mat, i_low + 1, j_mid + 1, m - 1, x); +} + +/** Main function */ +int main() +{ + int x; // element to be searched + int m, n; // m = columns, n = rows + + scanf("%d %d %d\n", &n, &m, &x); + + int **mat = (int **)malloc(n * sizeof(int *)); + for (int i = 0; i < m; i++) mat[i] = (int *)malloc(m * sizeof(int)); + + for (int i = 0; i < n; i++) + { + for (int j = 0; j < m; j++) + { + scanf("%d", &mat[i][j]); + } + } + + modifiedBinarySearch(mat, n, m, x); + + for (int i = 0; i < n; i++) free(mat[i]); + free(mat); + return 0; +} diff --git a/searching/other_binary_search.c b/searching/other_binary_search.c new file mode 100644 index 0000000000..5d75a95bd0 --- /dev/null +++ b/searching/other_binary_search.c @@ -0,0 +1,46 @@ +#include +#include +#define len 5 + +int binarySearch(int array[], int leng, int searchX) +{ + int pos = -1, right, left, i = 0; + + left = 0; + right = leng - 1; + + while (left <= right) + { + pos = left + (right - left) / 2; + if (array[pos] == searchX) + { + return pos; + } + else if (array[pos] > searchX) + { + right = pos - 1; + } + else + { + left = pos + 1; + } + } + return -1; /* not found */ +} + +int main(int argc, char *argv[]) +{ + int array[len] = {5, 8, 10, 14, 16}; + + int position; + position = binarySearch(array, len, 5); + + if (position < 0) + printf("The number %d doesnt exist in array\n", 5); + else + { + printf("The number %d exist in array at position : %d \n", 5, position); + } + + return 0; +} diff --git a/searching/pattern_search/CMakeLists.txt b/searching/pattern_search/CMakeLists.txt new file mode 100644 index 0000000000..f23ecb5b93 --- /dev/null +++ b/searching/pattern_search/CMakeLists.txt @@ -0,0 +1,23 @@ +if(USE_OPENMP) + find_package(OpenMP) +endif() + +# 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} *.c ) +# 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 ".c" "" testname ${testsourcefile} ) + add_executable( ${testname} ${testsourcefile} ) + # Make sure YourLib is linked to each app + target_link_libraries( ${testname} function_timer ) + set_target_properties(${testname} PROPERTIES LINKER_LANGUAGE C) + if(OpenMP_C_FOUND) + target_link_libraries(${testname} OpenMP::OpenMP_C) + endif() + install(TARGETS ${testname} DESTINATION "bin/searching/pattern") + +endforeach( testsourcefile ${APP_SOURCES} ) diff --git a/searching/pattern_search/Makefile b/searching/pattern_search/Makefile deleted file mode 100644 index b8c8aeb17a..0000000000 --- a/searching/pattern_search/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -CC = gcc -FLAG = -o - -all: naive_search rabin_karp_search boyer_moore_search - -naive_search : naive_search.c - $(CC) $(FLAG) naive_search naive_search.c -rabin_karp_search : rabin_karp_search - $(CC) $(FLAG) rabin_karp_search rabin_karp_search.c -boyer_moore_search: boyer_moore_search boyer_moore_search.c - $(CC) $(FLAG) boyer_moore_search boyer_moore_search.c - -clean: - rm naive_search rabin_karp_search boyer_moore_search diff --git a/searching/pattern_search/boyer_moore_search.c b/searching/pattern_search/boyer_moore_search.c index 9d71990188..a803e032b2 100644 --- a/searching/pattern_search/boyer_moore_search.c +++ b/searching/pattern_search/boyer_moore_search.c @@ -3,17 +3,15 @@ #define NUM_OF_CHARS 256 -int max(int a, int b) {return (a>b)? a:b;} +int max(int a, int b) { return (a > b) ? a : b; } void computeArray(char *pattern, int size, int arr[NUM_OF_CHARS]) { int i; - for(i = 0; i < NUM_OF_CHARS; i++) - arr[i] = -1; + for (i = 0; i < NUM_OF_CHARS; i++) arr[i] = -1; /* Fill the actual value of last occurrence of a character */ - for(i = 0; i < size; i++) - arr[(int) pattern[i]] = i; + for (i = 0; i < size; i++) arr[(int)pattern[i]] = i; } /* Boyer Moore Search algorithm */ void boyer_moore_search(char *str, char *pattern) @@ -24,17 +22,18 @@ void boyer_moore_search(char *str, char *pattern) int arr[NUM_OF_CHARS]; computeArray(pattern, m, arr); - while(shift <= (n - m)) + while (shift <= (n - m)) { int j = m - 1; - while (j >= 0 && pattern[j] == str[shift + j]) - j--; + while (j >= 0 && pattern[j] == str[shift + j]) j--; if (j < 0) { printf("--Pattern is found at: %d\n", shift); shift += (shift + m < n) ? m - arr[str[shift + m]] : 1; - } else { - shift += max(1, j - arr[str[shift +j]]); + } + else + { + shift += max(1, j - arr[str[shift + j]]); } } } diff --git a/searching/pattern_search/rabin_karp_search.c b/searching/pattern_search/rabin_karp_search.c index ea4d4cd2be..c86a988b9f 100644 --- a/searching/pattern_search/rabin_karp_search.c +++ b/searching/pattern_search/rabin_karp_search.c @@ -13,8 +13,7 @@ void rabin_karp_search(char *str, char *pattern, int d, int q) int hash_p = 0; /* hash value for pattern */ /* h = pow(d, len_pat - 1) % q */ - for (i = 0; i < len_pat - 1; i++) - h = d * h % q; + for (i = 0; i < len_pat - 1; i++) h = d * h % q; /* Calculating hashing of pattern and the 1st window of text */ for (i = 0; i < len_pat; i++) { diff --git a/searching/sentinel_linear_search.c b/searching/sentinel_linear_search.c new file mode 100644 index 0000000000..43def0e311 --- /dev/null +++ b/searching/sentinel_linear_search.c @@ -0,0 +1,79 @@ +/** + * @file + * @brief [Linear Search with Sentinel](https://en.wikipedia.org/wiki/Linear_search#With_a_sentinel) algorithm implementation + * @details + * This algorithm saves the last element of the array, + * then replaces it with the value to be found and sets it as the sentinel. + * When searching, compares each element with the sentinel. + * If the same, returns the index. If the index is the index of the sentinel, it means it was not found. + * Of course, if the value to be found is the last element, we return the index of the last element. + * @author [Regan Yue](https://github.com/ReganYue) + * Time Complexity: O(N) + */ + +#include /// for IO operations +#include /// for assert + +/** + * @brief Utility function to search for an element in the array and return the index of the element + * @details + * The so-called "sentinel" is to use a special value as the boundary key of the array. + * One less judgment statement can be used. + * The purpose is to avoid checking whether the entire array is searched at each step in the search + * process, so as to improve the efficiency of the program. + * We can use the last value of the array as the "sentinel", the data storage index i + * starts from 0 and ends at len-1, then the position where the index of arr is n-1 indicates + * that there is no data temporarily, which is the "sentinel" key. + * If the last element of the array is equal to the key, directly return the index of the last element. + * Before setting the last element of the array as the key, we hand over the last element of the array to temp for temporary storage. + * Then go to the array to find the key. If the key is found, stop the search, and then compare the found element index with len-1. + * If it is equal, it means it was not found. If it is not equal, it is found. + * @param arr this is an array containing elements + * @param len this is the number of elements in the array + * @param key the value we want to search + * @return i if found, otherwise -1 is returned. + */ +int sentinel_linear_search( int arr[], int len, int key ){ + if(key == arr[len-1]){ + return len-1; + } + + int temp = arr[len-1]; + arr[len-1] = key; + + int i = 0; + while (arr[len-1] != arr[i]) { + i++; + } + + arr[len-1] = temp; + + return i != len-1 ? i : -1; + +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test(){ + int n,i; + n = 5; + /* init array */ + int arr[] = { 1, 2, 2, 6, 99, 100, 999 }; + + assert(sentinel_linear_search( arr, n, 1 )==0); + assert(sentinel_linear_search( arr, n, 2 )==1); + assert(sentinel_linear_search( arr, n, 6 )==3); + assert(sentinel_linear_search( arr, n, 101 )==-1); + printf("All test cases have successfully passed!\n"); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main(){ + test(); // run self-test implementations + return 0; +} diff --git a/searching/ternary_search.c b/searching/ternary_search.c new file mode 100644 index 0000000000..bce2ebe06d --- /dev/null +++ b/searching/ternary_search.c @@ -0,0 +1,85 @@ + +#include + +// Function to perform Ternary Search +int ternarySearch(int l, int r, int key, int ar[]) +{ + if (r >= l) + { + // Find the mid1 and mid2 + int mid1 = l + (r - l) / 3; + int mid2 = r - (r - l) / 3; + + // Check if key is present at any mid + if (ar[mid1] == key) + { + return mid1; + } + if (ar[mid2] == key) + { + return mid2; + } + + // Since key is not present at mid, + // check in which region it is present + // then repeat the Search operation + // in that region + + if (key < ar[mid1]) + { + // The key lies in between l and mid1 + return ternarySearch(l, mid1 - 1, key, ar); + } + else if (key > ar[mid2]) + { + // The key lies in between mid2 and r + return ternarySearch(mid2 + 1, r, key, ar); + } + else + { + // The key lies in between mid1 and mid2 + return ternarySearch(mid1 + 1, mid2 - 1, key, ar); + } + } + + // Key not found + return -1; +} + +// Driver code +int main() +{ + int l, r, p, key; + + // Get the array + // Sort the array if not sorted + int ar[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + + // Starting index + l = 0; + + // length of array + r = 9; + + // Checking for 5 + + // Key to be searched in the array + key = 5; + + // Search the key using ternarySearch + p = ternarySearch(l, r, key, ar); + + // Print the result + printf("Index of %d is %d\n", key, p); + + // Checking for 50 + + // Key to be searched in the array + key = 50; + + // Search the key using ternarySearch + p = ternarySearch(l, r, key, ar); + + // Print the result + printf("Index of %d is %d", key, p); +} \ No newline at end of file diff --git a/sorting/BogoSort.c b/sorting/BogoSort.c deleted file mode 100644 index 8ad36b40a4..0000000000 --- a/sorting/BogoSort.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include -#include - -bool check_sorted(int *a, int n) -{ - while ( --n >= 1 ) { - if ( a[n] < a[n-1] ) return false; - } - return true; -} - -void shuffle(int *a, int n) -{ - int i, t, r; - for(i=0; i < n; i++) { - t = a[i]; - r = rand() % n; - a[i] = a[r]; - a[r] = t; - } -} - -void sort(int *a, int n) -{ - while ( !check_sorted(a, n) ) shuffle(a, n); -} - -int main() -{ - int numbers[6]; - int i; - printf("Enter 6 numbers unsorted \n\n"); - for(i=0;i<6;i++){ - scanf("%d",&numbers[i]); - } - sort(numbers, 6); - for (i=0; i < 6; i++) printf("%d ", numbers[i]); - printf("\n"); -} diff --git a/sorting/BubbleSort.c b/sorting/BubbleSort.c deleted file mode 100644 index 0b6a1879ff..0000000000 --- a/sorting/BubbleSort.c +++ /dev/null @@ -1,62 +0,0 @@ -//sorting of array list using bubble sort -#include - -/*Displays the array, passed to this method*/ -void display(int arr[], int n){ - - int i; - for(i = 0; i < n; i++){ - printf("%d ", arr[i]); - } - - printf("\n"); - -} - -/*Swap function to swap two values*/ -void swap(int *first, int *second){ - - int temp = *first; - *first = *second; - *second = temp; - -} - -/*This is where the sorting of the array takes place - arr[] --- Array to be sorted - size --- Array Size - */ -void bubbleSort(int arr[], int size){ - - for(int i=0; iarr[j+1]) { - swap(&arr[j], &arr[j+1]); - } - } - } -} - -int main(int argc, const char * argv[]) { - int n; - printf("Enter size of array:\n"); - scanf("%d", &n); // E.g. 8 - - printf("Enter the elements of the array\n"); - int i; - int arr[n]; - for(i = 0; i < n; i++){ - scanf("%d", &arr[i] ); - } - - printf("Original array: "); - display(arr, n); // Original array : 10 11 9 8 4 7 3 8 - - bubbleSort(arr, n); - - printf("Sorted array: "); - display(arr, n); // Sorted array : 3 4 7 8 8 9 10 11 - - return 0; -} - diff --git a/sorting/CMakeLists.txt b/sorting/CMakeLists.txt new file mode 100644 index 0000000000..2c9e74eccf --- /dev/null +++ b/sorting/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} *.c ) +# 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 ".c" "" testname ${testsourcefile} ) + add_executable( ${testname} ${testsourcefile} ) + + if(OpenMP_C_FOUND) + target_link_libraries(${testname} OpenMP::OpenMP_C) + endif() + if(MATH_LIBRARY) + target_link_libraries(${testname} ${MATH_LIBRARY}) + endif() + install(TARGETS ${testname} DESTINATION "bin/sorting") + +endforeach( testsourcefile ${APP_SOURCES} ) diff --git a/sorting/HeapSort.c b/sorting/HeapSort.c deleted file mode 100644 index 0010091a3e..0000000000 --- a/sorting/HeapSort.c +++ /dev/null @@ -1,62 +0,0 @@ -#include - -void heapify(int *unsorted, int index, int heap_size); -void heap_sort(int *unsorted, int n); - -int main() { - int n = 0; - int i = 0; - char oper; - - int* unsorted; - printf("Enter the size of the array you want\n"); - scanf("%d", &n); - unsorted = (int*)malloc(sizeof(int) * n); - while (getchar() != '\n'); - printf("Enter numbers separated by a comma:\n"); - while (i != n) { - scanf("%d,", (unsorted + i)); - i++; - } - heap_sort(unsorted, n); - - printf("["); - printf("%d", *(unsorted)); - for (int i = 1; i < n; i++) { - printf(", %d", *(unsorted + i)); - } - printf("]"); -} - -void heapify(int *unsorted, int index, int heap_size) { - int temp; - int largest = index; - int left_index = 2 * index; - int right_index = 2 * index + 1; - if (left_index < heap_size && *(unsorted + left_index) > *(unsorted + largest)) { - largest = left_index; - } - if (right_index < heap_size && *(unsorted + right_index) > *(unsorted + largest)) { - largest = right_index; - } - - if (largest != index) { - temp = *(unsorted + largest); - *(unsorted + largest) = *(unsorted + index); - *(unsorted + index) = temp; - heapify(unsorted, largest, heap_size); - } -} - -void heap_sort(int *unsorted, int n) { - int temp; - for (int i = n / 2 - 1; i > -1; i--) { - heapify(unsorted, i, n); - } - for (int i = n - 1; i > 0; i--) { - temp = *(unsorted); - *(unsorted) = *(unsorted + i); - *(unsorted + i) = temp; - heapify(unsorted, 0, i); - } -} diff --git a/sorting/InsertionSort.c b/sorting/InsertionSort.c deleted file mode 100644 index 961ddebb41..0000000000 --- a/sorting/InsertionSort.c +++ /dev/null @@ -1,53 +0,0 @@ -//sorting of array list using insertion sort -#include - -/*Displays the array, passed to this method*/ -void display(int arr[], int n){ - - int i; - for(i = 0; i < n; i++){ - printf("%d ", arr[i]); - } - - printf("\n"); - -} - -/*This is where the sorting of the array takes place - arr[] --- Array to be sorted - size --- Array Size - */ -void insertionSort(int arr[], int size){ - int j,temp,i; - for(i=0; i= 0 && temp < arr[j]) { - arr[j+1] = arr[j]; - arr[j] = temp; - } - } -} - -int main(int argc, const char * argv[]) { - int n; - printf("Enter size of array:\n"); - scanf("%d", &n); // E.g. 8 - - printf("Enter the elements of the array\n"); - int i; - int arr[n]; - for(i = 0; i < n; i++){ - scanf("%d", &arr[i] ); - } - - printf("Original array: "); - display(arr, n); // Original array : 10 11 9 8 4 7 3 8 - - insertionSort(arr, n); - - printf("Sorted array: "); - display(arr, n); // Sorted array : 3 4 7 8 8 9 10 11 - - return 0; -} - diff --git a/sorting/OtherBubbleSort.c b/sorting/OtherBubbleSort.c deleted file mode 100644 index f11fd63ea6..0000000000 --- a/sorting/OtherBubbleSort.c +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include -#define MAX 20 -#define TRUE 1 -#define FALSE 0 - - -int main() -{ - - int i , arraySort[MAX] ={0} , isSort = FALSE, changePlace; - - - /* For example - Insertion random values in array to test - */ - - - for(i = 0 ; i < MAX; i++) - { - arraySort[i] = rand()%101 ; - } - - -/* Algorithm of bubble methods */ - - while(isSort) - { - isSort = FALSE; - - for( i = 0 ; i < MAX - 1 ; i++) - { - if(arraySort[i] > arraySort[i+1]) - { - changePlace = arratSort[i]; - arraySort[i] = arraySort[i+1]; - arraySort[i+1] = changePlace ; - isSort = TRUE; - } - - } - } - - /* See if it works */ - - for(i = 0 ; i < MAX; i++) - { - printf("%d\n", arraySort[i]); - } - - - - - return EXIT_SUCCESS; - -} diff --git a/sorting/SelectionSort.c b/sorting/SelectionSort.c deleted file mode 100644 index cff71b4dee..0000000000 --- a/sorting/SelectionSort.c +++ /dev/null @@ -1,64 +0,0 @@ -//sorting of array list using selection sort -#include - -/*Displays the array, passed to this method*/ -void display(int arr[], int n){ - - int i; - for(i = 0; i < n; i++){ - printf("%d ", arr[i]); - } - - printf("\n"); - -} - -/*Swap function to swap two values*/ -void swap(int *first, int *second){ - - int temp = *first; - *first = *second; - *second = temp; - -} - -/*This is where the sorting of the array takes place - arr[] --- Array to be sorted - size --- Array Size - */ -void selectionSort(int arr[], int size){ - - for(int i=0; i arr[j]) { - min_index = j; - } - } - swap(&arr[i], &arr[min_index]); - } -} - -int main(int argc, const char * argv[]) { - int n; - printf("Enter size of array:\n"); - scanf("%d", &n); // E.g. 8 - - printf("Enter the elements of the array\n"); - int i; - int arr[n]; - for(i = 0; i < n; i++){ - scanf("%d", &arr[i] ); - } - - printf("Original array: "); - display(arr, n); // Original array : 10 11 9 8 4 7 3 8 - - selectionSort(arr, n); - - printf("Sorted array: "); - display(arr, n); // Sorted array : 3 4 7 8 8 9 10 11 - - return 0; -} - diff --git a/sorting/bead_sort.c b/sorting/bead_sort.c new file mode 100644 index 0000000000..2af975ef90 --- /dev/null +++ b/sorting/bead_sort.c @@ -0,0 +1,99 @@ +/** + * @file + * @brief Sorting of array list using [bead + * sort](https://en.wikipedia.org/wiki/Bead_sort) + */ +#include +#include + +/** + * @addtogroup sorting Sorting algorithms + * @{ + */ +/** Create easy access of elements from a 2D matrix stored in memory as a 1D + * array + */ +#define BEAD(i, j) beads[i * max + j] + +/** + * Displays the array, passed to this method + * @param [in] arr array to display + * @param [in] n number of elements in the array + */ +void display(const int *arr, int n) +{ + for (int i = 0; i < n; i++) + { + printf("%d ", arr[i]); + } + + printf("\n"); +} + +/** This is where the sorting of the array takes place + * @param [in,out] a array to be sorted + * @param [in] len Array Size + */ +void bead_sort(int *a, size_t len) +{ + int i, j, max, sum; + unsigned char *beads; + + for (i = 1, max = a[0]; i < len; i++) + if (a[i] > max) + max = a[i]; + + beads = calloc(1, max * len); + + /* mark the beads */ + for (i = 0; i < len; i++) + for (j = 0; j < a[i]; j++) BEAD(i, j) = 1; + + for (j = 0; j < max; j++) + { + /* count how many beads are on each post */ + for (sum = i = 0; i < len; i++) + { + sum += BEAD(i, j); + BEAD(i, j) = 0; + } + /* mark bottom sum beads */ + for (i = len - sum; i < len; i++) BEAD(i, j) = 1; + } + + for (i = 0; i < len; i++) + { + for (j = 0; j < max && BEAD(i, j); j++) + ; + a[i] = j; + } + free(beads); +} +/** @} */ + +/** Main function */ +int main(int argc, const char *argv[]) +{ + int n; + printf("Enter size of array:\n"); + scanf("%d", &n); // E.g. 8 1 2 3 + + printf("Enter the elements of the array\n"); + int i; + int *arr = (int *)malloc(n * sizeof(int)); + for (i = 0; i < n; i++) + { + scanf("%d", &arr[i]); + } + + printf("Original array: "); + display(arr, n); + + bead_sort(arr, n); + + printf("Sorted array: "); + display(arr, n); + + free(arr); + return 0; +} diff --git a/sorting/binary_insertion_sort.c b/sorting/binary_insertion_sort.c index 6888417d3a..a111e2843e 100644 --- a/sorting/binary_insertion_sort.c +++ b/sorting/binary_insertion_sort.c @@ -1,62 +1,79 @@ -/* -Binary Insertion sort is a variant of Insertion sorting in which proper location to insert the selected element is found using the binary search. -*/ +/* Sorting of array list using binary insertion sort + * Using binary search to find the proper location for + * inserting the selected item at each iteration. */ +#include +#include -#include +/*Displays the array, passed to this method*/ +void display(int *arr, int n) +{ + int i; + for (i = 0; i < n; i++) + { + printf("%d ", arr[i]); + } + printf("\n"); +} -int binarySearch(int a[], int item, int low, int high) +int binarySearch(int *arr, int key, int low, int high) { - if (high <= low) - return (item > a[low])? (low + 1): low; - - int mid = (low + high)/2; - - if(item == a[mid]) - return mid+1; - - if(item > a[mid]) - return binarySearch(a, item, mid+1, high); - return binarySearch(a, item, low, mid-1); + if (low >= high) + return (key > arr[low]) ? (low + 1) : low; + int mid = low + (high - 1) / 2; + if (arr[mid] == key) + return mid + 1; + else if (arr[mid] > key) + return binarySearch(arr, key, low, mid - 1); + else + return binarySearch(arr, key, mid + 1, high); } - -// Function to sort an array a[] of size 'n' -void insertionSort(int a[], int n) +/*This is where the sorting of the array takes place + arr[] --- Array to be sorted + size --- Array Size + */ +void insertionSort(int *arr, int size) { - int i, loc, j, k, selected; - - for (i = 1; i < n; ++i) + int i, j, key, index; + for (i = 0; i < size; i++) { j = i - 1; - selected = a[i]; - - // find location where selected sould be inseretd - loc = binarySearch(a, selected, 0, j); - - // Move all elements after location to create space - while (j >= loc) + key = arr[i]; + /* Use binrary search to find exact key's index */ + index = binarySearch(arr, key, 0, j); + /* Move all elements greater than key from [index...j] + * to one position */ + while (j >= index) { - a[j+1] = a[j]; - j--; + arr[j + 1] = arr[j]; + j = j - 1; } - a[j+1] = selected; + /* Insert key value in right place */ + arr[j + 1] = key; } } - -int main() + +int main(int argc, const char *argv[]) { int n; - scanf("%d",&n) ; - int a[n],i; - for(i = 0; i +#include +#include + +bool check_sorted(int *a, int n) +{ + while (--n >= 1) + { + if (a[n] < a[n - 1]) + return false; + } + return true; +} + +void shuffle(int *a, int n) +{ + int i, t, r; + for (i = 0; i < n; i++) + { + t = a[i]; + r = rand() % n; + a[i] = a[r]; + a[r] = t; + } +} + +void sort(int *a, int n) +{ + while (!check_sorted(a, n)) shuffle(a, n); +} + +int main() +{ + int numbers[6]; + int i; + printf("Enter 6 numbers unsorted \n\n"); + for (i = 0; i < 6; i++) + { + scanf("%d", &numbers[i]); + } + sort(numbers, 6); + for (i = 0; i < 6; i++) printf("%d ", numbers[i]); + printf("\n"); +} diff --git a/sorting/bubble_sort.c b/sorting/bubble_sort.c new file mode 100644 index 0000000000..8bd4edf296 --- /dev/null +++ b/sorting/bubble_sort.c @@ -0,0 +1,95 @@ +/** + * @file + * @brief [Bubble sort](https://en.wikipedia.org/wiki/Bubble_sort) algorithm + * implementation + */ +#include +#include +#include +#include +#include + +/** + * Display elements of array + * @param arr array to be display + * @param n length of array + */ +void display(const int *arr, int n) +{ + for (int i = 0; i < n; i++) + { + printf("%d ", arr[i]); + } + printf("\n"); +} + +/** + * Swap two values by using pointer + * @param first first pointer of first number + * @param second second pointer of second number + */ +void swap(int *first, int *second) +{ + int temp = *first; + *first = *second; + *second = temp; +} + +/** + * Bubble sort algorithm implementation + * @param arr array to be sorted + * @param size size of array + */ +void bubbleSort(int *arr, int size) +{ + for (int i = 0; i < size - 1; i++) + { /* for each array index */ + bool swapped = false; /* flag to check if any changes had to be made */ + /* perform iterations until no more changes were made or outer loop + executed for all array indices */ + for (int j = 0; j < size - 1 - i; j++) + { /* for each element in the array */ + if (arr[j] > arr[j + 1]) + { /* if the order of successive elements needs update */ + swap(&arr[j], &arr[j + 1]); + swapped = true; /* set flag */ + } + } + if (!swapped) + { + /* since no more updates we made, the array is already sorted + this is an optimization for early termination */ + break; + } + } +} + +/** + * Test function + */ +void test() +{ + const int size = 10; + int *arr = (int *)calloc(size, sizeof(int)); + + /* generate size random numbers from 0 to 100 */ + for (int i = 0; i < size; i++) + { + arr[i] = rand() % 100; + } + bubbleSort(arr, size); + for (int i = 0; i < size - 1; ++i) + { + assert(arr[i] <= arr[i + 1]); + } + free(arr); +} + +/** Driver Code */ +int main(int argc, const char *argv[]) +{ + /* Intializes random number generator */ + srand(time(NULL)); + test(); + return 0; +} diff --git a/sorting/bubble_sort_2.c b/sorting/bubble_sort_2.c new file mode 100644 index 0000000000..26bbb52622 --- /dev/null +++ b/sorting/bubble_sort_2.c @@ -0,0 +1,87 @@ +/** + * @file + * @brief implementation of [Bubble sort](https://en.wikipedia.org/wiki/Bubble_sort) algorithm + * @details + * worst-case: O(n^2) + * best-case: O(n) + * average-complexity: O(n^2) + + * @author Unknown author + * @author [Gabriel Fioravante](https://github.com/northernSage) + */ + +#include /// for rand() calls +#include /// for assert() +#include /// for boolean values: true, false + +#define MAX 20 + +/** + * @brief Bubble sort implementation + * @param array_sort the array to be sorted + * @returns void + */ +void bubble_sort(int* array_sort) +{ + bool is_sorted = false; + + /* keep iterating over entire array + * and swaping elements out of order + * until it is sorted */ + while (!is_sorted) + { + is_sorted = true; + + /* iterate over all elements */ + for (int i = 0; i < MAX - 1; i++) + { + /* check if adjacent elements are out of order */ + if (array_sort[i] > array_sort[i + 1]) + { + /* swap elements */ + int change_place = array_sort[i]; + array_sort[i] = array_sort[i + 1]; + array_sort[i + 1] = change_place; + /* elements out of order were found + * so we reset the flag to keep ordering + * until no swap operations are executed */ + is_sorted = false; + } + } + } +} + +/** + * @brief Test implementations + * @returns void + */ +static void test() { + /* simple int array for testing */ + int array_sort[MAX] = {0}; + + /* populate our test array with + * random integer numbers */ + for (int i = 0; i < MAX; i++) + { + array_sort[i] = rand() % 101; + } + + /* sort array */ + bubble_sort(array_sort); + + /* check if array ir correctly ordered */ + for (int i = 0; i < MAX - 1; i++) + { + assert(array_sort[i] <= array_sort[i+1]); + } +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + test(); // run self-test implementations + return 0; +} diff --git a/sorting/bubble_sort_recursion.c b/sorting/bubble_sort_recursion.c new file mode 100644 index 0000000000..ce6f73e0eb --- /dev/null +++ b/sorting/bubble_sort_recursion.c @@ -0,0 +1,78 @@ +/** + * @file + * @brief [Bubble sort](https://en.wikipedia.org/wiki/Bubble_sort) algorithm + * implementation using recursion. + */ +#include +#include +#include +#include +#include + +/** + * Swapped two numbers using pointer + * @param first first pointer of first number + * @param second second pointer of second number + */ +void swap(int *first, int *second) +{ + int temp = *first; + *first = *second; + *second = temp; +} + +/** + * Bubble sort algorithm implements using recursion + * @param arr array to be sorted + * @param size size of array + */ +void bubbleSort(int *arr, int size) +{ + if (size == 1) + { + return; + } + bool swapped = false; + for (int i = 0; i < size - 1; ++i) + { + if (arr[i] > arr[i + 1]) + { + swap(arr + i, arr + i + 1); + swapped = true; + } + } + if (swapped) + { + bubbleSort(arr, size - 1); + } +} + +/** + * Test function + */ +void test() +{ + const int size = 10; + int *arr = (int *)calloc(size, sizeof(int)); + + /* generate size random numbers from 0 to 100 */ + for (int i = 0; i < size; i++) + { + arr[i] = rand() % 100; + } + bubbleSort(arr, size); + for (int i = 0; i < size - 1; ++i) + { + assert(arr[i] <= arr[i + 1]); + } + free(arr); +} + +/** Driver Code */ +int main() +{ + /* Intializes random number generator */ + srand(time(NULL)); + test(); + return 0; +} diff --git a/sorting/BucketSort.c b/sorting/bucket_sort.c similarity index 72% rename from sorting/BucketSort.c rename to sorting/bucket_sort.c index 12b5eb7eaf..8417a9817c 100644 --- a/sorting/BucketSort.c +++ b/sorting/bucket_sort.c @@ -1,13 +1,13 @@ /* -* Algorithm : Bucket Sort -* Time-Complexity : O(n) -*/ + * Algorithm : Bucket Sort + * Time-Complexity : O(n) + */ +#include #include #include -#include -#define NARRAY 8 /* array size */ -#define NBUCKET 5 /* bucket size */ +#define NARRAY 8 /* array size */ +#define NBUCKET 5 /* bucket size */ #define INTERVAL 10 /* bucket range */ struct Node @@ -24,32 +24,32 @@ int getBucketIndex(int value); void BucketSort(int arr[]) { - int i,j; + int i, j; struct Node **buckets; /* allocate memory for array of pointers to the buckets */ - buckets = (struct Node **)malloc(sizeof(struct Node*) * NBUCKET); + buckets = (struct Node **)malloc(sizeof(struct Node *) * NBUCKET); /* initialize pointers to the buckets */ - for(i = 0; i < NBUCKET; ++i) + for (i = 0; i < NBUCKET; ++i) { buckets[i] = NULL; } /* put items into the buckets */ /* creates a link list in each bucket slot */ - for(i = 0; i < NARRAY; ++i) + for (i = 0; i < NARRAY; ++i) { struct Node *current; int pos = getBucketIndex(arr[i]); - current = (struct Node *) malloc(sizeof(struct Node)); + current = (struct Node *)malloc(sizeof(struct Node)); current->data = arr[i]; current->next = buckets[pos]; buckets[pos] = current; } /* check what's in each bucket */ - for(i = 0; i < NBUCKET; i++) + for (i = 0; i < NBUCKET; i++) { printf("Bucket[\"%d\"] : ", i); printBuckets(buckets[i]); @@ -57,7 +57,7 @@ void BucketSort(int arr[]) } /* sorting bucket using Insertion Sort */ - for(i = 0; i < NBUCKET; ++i) + for (i = 0; i < NBUCKET; ++i) { buckets[i] = InsertionSort(buckets[i]); } @@ -65,7 +65,7 @@ void BucketSort(int arr[]) /* check what's in each bucket */ printf("--------------\n"); printf("Buckets after sorted\n"); - for(i = 0; i < NBUCKET; i++) + for (i = 0; i < NBUCKET; i++) { printf("Bucket[\"%d\"] : ", i); printBuckets(buckets[i]); @@ -73,13 +73,12 @@ void BucketSort(int arr[]) } /* put items back to original array */ - for(j =0, i = 0; i < NBUCKET; ++i) + for (j = 0, i = 0; i < NBUCKET; ++i) { struct Node *node; node = buckets[i]; - while(node) + while (node) { - // precondition for avoiding out of bounds by the array assert(j < NARRAY); arr[j++] = node->data; @@ -88,11 +87,11 @@ void BucketSort(int arr[]) } /* free memory */ - for(i = 0; i < NBUCKET; ++i) + for (i = 0; i < NBUCKET; ++i) { struct Node *node; node = buckets[i]; - while(node) + while (node) { struct Node *tmp; tmp = node; @@ -107,9 +106,9 @@ void BucketSort(int arr[]) /* Insertion Sort */ struct Node *InsertionSort(struct Node *list) { - struct Node *k,*nodeList; + struct Node *k, *nodeList; /* need at least two items to sort */ - if(list == NULL || list->next == NULL) + if (list == NULL || list->next == NULL) { return list; } @@ -117,15 +116,15 @@ struct Node *InsertionSort(struct Node *list) nodeList = list; k = list->next; nodeList->next = NULL; /* 1st node is new list */ - while(k != NULL) + while (k != NULL) { struct Node *ptr; /* check if insert before first */ - if(nodeList->data > k->data) + if (nodeList->data > k->data) { struct Node *tmp; tmp = k; - k = k->next; // important for the while + k = k->next; // important for the while tmp->next = nodeList; nodeList = tmp; continue; @@ -133,17 +132,18 @@ struct Node *InsertionSort(struct Node *list) // from begin up to end // finds [i] > [i+1] - for(ptr = nodeList; ptr->next != NULL; ptr = ptr->next) + for (ptr = nodeList; ptr->next != NULL; ptr = ptr->next) { - if(ptr->next->data > k->data) break; + if (ptr->next->data > k->data) + break; } // if found (above) - if(ptr->next != NULL) + if (ptr->next != NULL) { struct Node *tmp; tmp = k; - k = k->next; // important for the while + k = k->next; // important for the while tmp->next = ptr->next; ptr->next = tmp; continue; @@ -151,7 +151,7 @@ struct Node *InsertionSort(struct Node *list) else { ptr->next = k; - k = k->next; // important for the while + k = k->next; // important for the while ptr->next->next = NULL; continue; } @@ -159,15 +159,12 @@ struct Node *InsertionSort(struct Node *list) return nodeList; } -int getBucketIndex(int value) -{ - return value/INTERVAL; -} +int getBucketIndex(int value) { return value / INTERVAL; } void print(int ar[]) { int i; - for(i = 0; i < NARRAY; ++i) + for (i = 0; i < NARRAY; ++i) { printf("%d ", ar[i]); } @@ -177,7 +174,7 @@ void print(int ar[]) void printBuckets(struct Node *list) { struct Node *cur = list; - while(cur) + while (cur) { printf("%d ", cur->data); cur = cur->next; @@ -186,7 +183,7 @@ void printBuckets(struct Node *list) int main(void) { - int array[NARRAY] = {29,25,-1,49,9,37,21,43}; + int array[NARRAY] = {29, 25, -1, 49, 9, 37, 21, 43}; printf("Initial array\n"); print(array); diff --git a/sorting/cocktail_sort.c b/sorting/cocktail_sort.c new file mode 100644 index 0000000000..504621b8c8 --- /dev/null +++ b/sorting/cocktail_sort.c @@ -0,0 +1,75 @@ +#include +#include + +#define TRUE 1 +#define FALSE 0 + +void cocktailSort(int arr[], int size) +{ + int i, changed = TRUE, temp, start = 0, end = size - 1; + + while (changed) + { + changed = FALSE; + for (i = start; i < end; i++) + { + if (arr[i] > arr[i + 1]) + { + temp = arr[i]; + arr[i] = arr[i + 1]; + arr[i + 1] = temp; + changed = TRUE; + } + } + end--; + + if (changed == FALSE) + { + break; + } + changed = FALSE; + + for (i = end - 1; i >= start; i--) + { + if (arr[i + 1] < arr[i]) + { + temp = arr[i + 1]; + arr[i + 1] = arr[i]; + arr[i] = temp; + changed = TRUE; + } + } + start++; + } +} + +int main() +{ + int i, n; + + printf("Enter the size of the array: "); + scanf("%d", &n); + int *arr = (int *)malloc(sizeof(int) * n); + + for (i = 0; i < n; i++) + { + printf("Number #%d: ", i + 1); + scanf("%d", &arr[i]); + } + + printf("You entered: "); + for (i = 0; i < n; i++) + { + printf("%d ", arr[i]); + } + cocktailSort(arr, n); + printf("\nSorted array: "); + for (i = 0; i < n; i++) + { + printf("%d ", arr[i]); + } + printf("\n"); + + free(arr); + return 0; +} \ No newline at end of file diff --git a/sorting/comb_sort.c b/sorting/comb_sort.c new file mode 100644 index 0000000000..7d2234c5c1 --- /dev/null +++ b/sorting/comb_sort.c @@ -0,0 +1,46 @@ +#include +#include +#define SHRINK 1.3 // suggested shrink factor value + +void sort(int *numbers, int size) +{ + int gap = size; + while (gap > 1) // gap = 1 means that the array is sorted + { + gap = gap / SHRINK; + int i = 0; + while ((i + gap) < size) + { // similiar to the Shell Sort + if (numbers[i] > numbers[i + gap]) + { + int tmp = numbers[i]; + numbers[i] = numbers[i + gap]; + numbers[i + gap] = tmp; + } + i++; + } + } +} + +void display(int *array, int n) +{ + int i; + for (i = 0; i < n; ++i) printf("%d ", array[i]); + printf("\n"); +} + +int main() +{ + int size = 6; + int *numbers = malloc(size * sizeof(int)); + printf("Insert %d unsorted numbers: \n", size); + int i; + for (i = 0; i < size; ++i) scanf("%d", &numbers[i]); + printf("Initial array: "); + display(numbers, size); + sort(numbers, size); + printf("Sorted array: "); + display(numbers, size); + free(numbers); + return 0; +} diff --git a/sorting/countingSort.c b/sorting/countingSort.c deleted file mode 100644 index 40c80c9f8d..0000000000 --- a/sorting/countingSort.c +++ /dev/null @@ -1,28 +0,0 @@ -#include - int main() - { - int i,n,l=0; - scanf("%d",&n); - int a[n]; - for(i=0;il) - l=a[i]; - } - int b[l+1]={0}; - for(i=0;i0) - { - while(b[i]!=0) //for case when number exists more than once - { - printf("%d ",i); - b[i]--; - } - } - } - return 0; - } \ No newline at end of file diff --git a/sorting/counting_sort.c b/sorting/counting_sort.c new file mode 100644 index 0000000000..fff5aa26bd --- /dev/null +++ b/sorting/counting_sort.c @@ -0,0 +1,48 @@ +/* + > Counting sort is a sorting technique based on keys between a specific range. + > integer sorting algorithm + > Worst-case performance O(n+k) + > Stabilized by prefix sum array +*/ + +#include +#include +#include + +int main() +{ + int i, n, l = 0; + + printf("Enter size of array = "); + scanf("%d", &n); + + int *a = (int *)malloc(n * sizeof(int)); + printf("Enter %d elements in array :\n", n); + for (i = 0; i < n; i++) + { + scanf("%d", &a[i]); + if (a[i] > l) + l = a[i]; + } + + int *b = (int *)malloc((l + 1) * sizeof(int)); + memset(b, 0, (l + 1) * sizeof(b[0])); + + for (i = 0; i < n; i++) b[a[i]]++; // hashing number to array index + + for (i = 0; i < (l + 1); i++) // unstable , stabilized by prefix sum array + { + if (b[i] > 0) + { + while (b[i] != 0) // for case when number exists more than once + { + printf("%d ", i); + b[i]--; + } + } + } + + free(a); + free(b); + return 0; +} diff --git a/sorting/cycle_sort.c b/sorting/cycle_sort.c new file mode 100644 index 0000000000..16fdf7dfbd --- /dev/null +++ b/sorting/cycle_sort.c @@ -0,0 +1,107 @@ +// Sorting of array list using cycle sort +#include +#include + +// Displays the array, passed to this method +void display(int *arr, int n) +{ + int i; + for (i = 0; i < n; i++) + { + printf("%d ", arr[i]); + } + + printf("\n"); +} + +// Swap function to swap two values +void swap(int *first, int *second) +{ + int temp = *first; + *first = *second; + *second = temp; +} + +// Function sort the array using Cycle sort +void cycleSort(int *arr, int n) +{ + // count number of memory writes + int writes = 0; + + // traverse array elements and put it to on + // the right place + for (int cycle_start = 0; cycle_start <= n - 2; cycle_start++) + { + // initialize item as starting point + int item = arr[cycle_start]; + + // Find position where we put the item. We basically + // count all smaller elements on right side of item. + int pos = cycle_start; + for (int i = cycle_start + 1; i < n; i++) + if (arr[i] < item) + pos++; + + // If item is already in correct position + if (pos == cycle_start) + continue; + + // ignore all duplicate elements + while (item == arr[pos]) pos += 1; + + // put the item to it's right position + if (pos != cycle_start) + { + swap(&item, &arr[pos]); + writes++; + } + + // Rotate rest of the cycle + while (pos != cycle_start) + { + pos = cycle_start; + + // Find position where we put the element + for (int i = cycle_start + 1; i < n; i++) + if (arr[i] < item) + pos += 1; + + // ignore all duplicate elements + while (item == arr[pos]) pos += 1; + + // put the item to it's right position + if (item != arr[pos]) + { + swap(&item, &arr[pos]); + writes++; + } + } + } +} + +// Driver program to test above function +int main() +{ + int n; // Size of array elements + + printf("Enter size of array:\n"); + scanf("%d", &n); // E.g. 8 + + printf("Enter the elements of the array\n"); + int i; + int *arr = (int *)malloc(n * sizeof(int)); + for (i = 0; i < n; i++) + { + scanf("%d", &arr[i]); + } + + printf("Original array: "); + display(arr, n); + + cycleSort(arr, n); + printf("Sorted array: "); + display(arr, n); + + free(arr); + return 0; +} diff --git a/sorting/gnome_sort.c b/sorting/gnome_sort.c new file mode 100644 index 0000000000..9345cee584 --- /dev/null +++ b/sorting/gnome_sort.c @@ -0,0 +1,45 @@ +#include +#include + +void sort(int *numbers, int size) +{ + int pos = 0; + while (pos < size) + { + if (numbers[pos] >= numbers[pos - 1]) + pos++; + else + { + int tmp = numbers[pos - 1]; + numbers[pos - 1] = numbers[pos]; + numbers[pos] = tmp; + pos--; + + if (pos == 0) + pos = 1; + } + } +} + +void display(int *array, int n) +{ + int i; + for (i = 0; i < n; ++i) printf("%d ", array[i]); + printf("\n"); +} + +int main() +{ + int size = 6; + int i; + int *numbers = malloc(size * sizeof(int)); + printf("Insert %d unsorted numbers: \n", size); + for (i = 0; i < size; ++i) scanf("%d", &numbers[i]); + printf("Initial array: "); + display(numbers, size); + sort(numbers, size); + printf("Sorted array: "); + display(numbers, size); + free(numbers); + return 0; +} diff --git a/sorting/heap_sort.c b/sorting/heap_sort.c new file mode 100644 index 0000000000..d4c2a5636d --- /dev/null +++ b/sorting/heap_sort.c @@ -0,0 +1,72 @@ +#include + +void max_heapify(int *a, int i, int n); +void heapsort(int *a, int n); +void build_maxheap(int *a, int n); + +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; + printf("Enter number of elements of array\n"); + scanf("%d", &n); + int a[20]; + for (i = 1; i <= n; i++) + { + printf("Enter Element %d\n", i); + scanf("%d", a + i); + } + + build_maxheap(a, n); + heapsort(a, n); + printf("Sorted Output\n"); + for (i = 1; i <= n; i++) + { + printf("%d\n", a[i]); + } + + getchar(); +} diff --git a/sorting/heap_sort_2.c b/sorting/heap_sort_2.c new file mode 100644 index 0000000000..1cce1ec604 --- /dev/null +++ b/sorting/heap_sort_2.c @@ -0,0 +1,156 @@ +/** + * @file + * @author [Dhruv Pasricha](https://github.com/DhruvPasricha) + * @brief [Heap Sort](https://en.wikipedia.org/wiki/Heapsort) implementation + * @details + * Heap-sort is a comparison-based sorting algorithm. + * Heap-sort can be thought of as an improved selection sort: + * like selection sort, heap sort divides its input into a sorted + * and an unsorted region, and it iteratively shrinks the unsorted + * region by extracting the largest element from it and inserting + * it into the sorted region. + * + * Unlike selection sort, + * heap sort does not waste time with a linear-time scan of the + * unsorted region; rather, heap sort maintains the unsorted region + * in a heap data structure to more quickly find the largest element + * in each step. + * Time Complexity : O(Nlog(N)) + */ + +#include /// for assert +#include /// for IO operations +#include /// for dynamic memory allocation +#include /// for random numbers generation +#include /// for uint8_t, int8_t + +/** + * @brief Swapped two numbers using pointer + * @param first pointer of first number + * @param second pointer of second number + */ +void swap(int8_t *first, int8_t *second) +{ + int8_t temp = *first; + *first = *second; + *second = temp; +} + +/** + * @brief heapifyDown Adjusts new root to the correct position in the heap + * This heapify procedure can be thought of as building a heap from + * the top down by successively shifting downward to establish the + * heap property. + * @param arr array to be sorted + * @param size size of array + * @return void +*/ +void heapifyDown(int8_t *arr, const uint8_t size) +{ + uint8_t i = 0; + + while (2 * i + 1 < size) + { + uint8_t maxChild = 2 * i + 1; + + if (2 * i + 2 < size && arr[2 * i + 2] > arr[maxChild]) + { + maxChild = 2 * i + 2; + } + + if (arr[maxChild] > arr[i]) + { + swap(&arr[i], &arr[maxChild]); + i = maxChild; + } + else + { + break; + } + } +} + +/** + * @brief heapifyUp Adjusts arr[i] to the correct position in the heap + * This heapify procedure can be thought of as building a heap from + * the bottom up by successively shifting upward to establish the + * heap property. + * @param arr array to be sorted + * @param i index of the pushed element + * @return void +*/ +void heapifyUp(int8_t *arr, uint8_t i) +{ + while (i > 0 && arr[(i - 1) / 2] < arr[i]) + { + swap(&arr[(i - 1) / 2], &arr[i]); + i = (i - 1) / 2; + } +} + +/** + * @brief Heap Sort algorithm + * @param arr array to be sorted + * @param size size of the array + * @returns void + */ +void heapSort(int8_t *arr, const uint8_t size) +{ + if (size <= 1) + { + return; + } + + for (uint8_t i = 0; i < size; i++) + { + // Pushing `arr[i]` to the heap + + /*heapifyUp Adjusts arr[i] to the correct position in the heap*/ + heapifyUp(arr, i); + } + + for (uint8_t i = size - 1; i >= 1; i--) + { + // Moving current root to the end + swap(&arr[0], &arr[i]); + + // `heapifyDown` adjusts new root to the correct position in the heap + heapifyDown(arr, i); + + } +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() +{ + const uint8_t size = 10; + int8_t *arr = (int8_t *)calloc(size, sizeof(int8_t)); + + /* generate size random numbers from 0 to 100 */ + for (uint8_t i = 0; i < size; i++) + { + arr[i] = rand() % 100; + } + heapSort(arr, size); + for (uint8_t i = 0; i < size - 1; ++i) + { + assert(arr[i] <= arr[i + 1]); + } + free(arr); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + // Intializes random number generator + srand(time(NULL)); + + test(); // run self-test implementations + return 0; +} diff --git a/sorting/insertion_sort.c b/sorting/insertion_sort.c new file mode 100644 index 0000000000..501e869053 --- /dev/null +++ b/sorting/insertion_sort.c @@ -0,0 +1,59 @@ +/** + * @file + * @brief [Insertion sort](https://en.wikipedia.org/wiki/Insertion_sort) + * algorithm implementation. + */ +#include +#include +#include +#include + +/** + * Insertion sort algorithm implements + * @param arr array to be sorted + * @param size size of array + */ +void insertionSort(int *arr, int size) +{ + for (int i = 1; i < size; i++) + { + int j = i - 1; + int key = arr[i]; + /* Move all elements greater than key to one position */ + while (j >= 0 && key < arr[j]) + { + arr[j + 1] = arr[j]; + j = j - 1; + } + /* Find a correct position for key */ + arr[j + 1] = key; + } +} + +/** Test function + * @returns None + */ +static void test() +{ + const int size = rand() % 500; /* random array size */ + int *arr = (int *)calloc(size, sizeof(int)); + + /* generate size random numbers from -50 to 49 */ + for (int i = 0; i < size; i++) + { + arr[i] = (rand() % 100) - 50; /* signed random numbers */ + } + insertionSort(arr, size); + for (int i = 0; i < size - 1; ++i) + { + assert(arr[i] <= arr[i + 1]); + } + free(arr); +} +int main(int argc, const char *argv[]) +{ + /* Intializes random number generator */ + srand(time(NULL)); + test(); + return 0; +} diff --git a/sorting/insertion_sort_recursive.c b/sorting/insertion_sort_recursive.c new file mode 100644 index 0000000000..ff79ea2ba1 --- /dev/null +++ b/sorting/insertion_sort_recursive.c @@ -0,0 +1,71 @@ +/** + * @file + * @brief [Insertion sort](https://en.wikipedia.org/wiki/Insertion_sort) + * algorithm implementation. + */ +#include +#include +#include +#include + +/** + * @addtogroup sorting Sorting algorithms + * @{ + */ +/** + * Insertion sort algorithm implements using Recursion + * @param arr array to be sorted + * @param size size of array + */ +void RecursionInsertionSort(int *arr, int size) +{ + if(size <= 0) + { + return; + } + + // marking recursive call to reach starting element + RecursionInsertionSort(arr,size-1); + + int key = arr[size-1]; + int j = size-2; + // swapping logic for insertion sort + while(j >= 0 && arr[j] > key) + { + arr[j+1] = arr[j]; + j--; + } + arr[j+1] = key; +} +/** @} */ +/** Test function + * @returns None + */ +static void test() +{ + const int size = rand() % 500; /* random array size */ + int *arr = (int *)calloc(size, sizeof(int)); + + /* generate size random numbers from -50 to 49 */ + for (int i = 0; i < size; i++) + { + arr[i] = (rand() % 100) - 50;/* signed random numbers */ + } + RecursionInsertionSort(arr, size); + for (int i = 0; i < size ; ++i) + { + assert(arr[i] <= arr[i + 1]); + } + free(arr); +} + +/** Main function + * @returns integer 0 + */ +int main(int argc, const char *argv[]) +{ + /* Intializes random number generator */ + srand(time(NULL)); + test(); + return 0; +} diff --git a/sorting/merge_sort.c b/sorting/merge_sort.c new file mode 100644 index 0000000000..ac1046f489 --- /dev/null +++ b/sorting/merge_sort.c @@ -0,0 +1,139 @@ +/** + * @file + * @brief Implementation of [merge + * sort](https://en.wikipedia.org/wiki/Merge_sort) algorithm + */ +#include +#include + +/** + * @addtogroup sorting Sorting algorithms + * @{ + */ +/** Swap two integer variables + * @param [in,out] a pointer to first variable + * @param [in,out] b pointer to second variable + */ +void swap(int *a, int *b) +{ + int t; + t = *a; + *a = *b; + *b = t; +} + +/** + * @brief Perform merge of segments. + * + * @param a array to sort + * @param l left index for merge + * @param r right index for merge + * @param n total number of elements in the array + */ +void merge(int *a, int l, int r, int n) +{ + int *b = (int *)malloc(n * sizeof(int)); /* dynamic memory must be freed */ + if (b == NULL) + { + printf("Can't Malloc! Please try again."); + exit(EXIT_FAILURE); + } + int c = l; + int p1, p2; + p1 = l; + p2 = ((l + r) / 2) + 1; + while ((p1 < ((l + r) / 2) + 1) && (p2 < r + 1)) + { + if (a[p1] <= a[p2]) + { + b[c++] = a[p1]; + p1++; + } + else + { + b[c++] = a[p2]; + p2++; + } + } + + if (p2 == r + 1) + { + while ((p1 < ((l + r) / 2) + 1)) + { + b[c++] = a[p1]; + p1++; + } + } + else + { + while ((p2 < r + 1)) + { + b[c++] = a[p2]; + p2++; + } + } + + for (c = l; c < r + 1; c++) a[c] = b[c]; + + free(b); +} + +/** Merge sort algorithm implementation + * @param a array to sort + * @param n number of elements in the array + * @param l index to sort from + * @param r index to sort till + */ +void merge_sort(int *a, int n, int l, int r) +{ + if (r - l == 1) + { + if (a[l] > a[r]) + swap(&a[l], &a[r]); + } + else if (l != r) + { + merge_sort(a, n, l, (l + r) / 2); + merge_sort(a, n, ((l + r) / 2) + 1, r); + merge(a, l, r, n); + } + + /* no change if l == r */ +} +/** @} */ + +/** Main function */ +int main(void) +{ + int *a, n, i; + printf("Enter Array size: "); + scanf("%d", &n); + if (n <= 0) /* exit program if arraysize is not greater than 0 */ + { + printf("Array size must be Greater than 0!\n"); + return 1; + } + a = (int *)malloc(n * sizeof(int)); + if (a == NULL) /* exit program if can't malloc memory */ + { + printf("Can't Malloc! Please try again."); + return 1; + } + for (i = 0; i < n; i++) + { + printf("Enter number[%d]: ", i); + scanf("%d", &a[i]); + } + + merge_sort(a, n, 0, n - 1); + printf("Sorted Array: "); + for (i = 0; i < n; i++) + { + printf("%d ", a[i]); + } + printf("\n"); + + free(a); + + return 0; +} diff --git a/sorting/merge_sort_nr.c b/sorting/merge_sort_nr.c new file mode 100644 index 0000000000..fdbce7cd47 --- /dev/null +++ b/sorting/merge_sort_nr.c @@ -0,0 +1,103 @@ +/* Program to demonstrate non recursive merge sort */ + +/* Merge sort is an effective sorting algorithm which falls under divide and +conquer paradigm and produces a stable sort. Merge sort repeatedly breaks down a +list into several sublists until each sublist consists of a single element and +merging those sublists in a manner that results into a sorted list. + +Bottom-Up Merge Sort Implementation: +The Bottom-Up merge sort approach uses iterative methodology. It starts with the +“single-element” array, and combines two adjacent elements and also sorting the +two at the same time. The combined-sorted arrays are again combined and sorted +with each other until one single unit of sorted array is achieved. */ + +#include + +void mergesort(int x[], int n); +void show(int x[], int n); + +void mergesort(int x[], int n) +{ + int temp[50], i, j, k, lb1, lb2, ub1, ub2, size; + + size = 1; + while (size < n) + { + lb1 = 0; + k = 0; + + while (lb1 + size < n) + { + lb2 = lb1 + size; + ub1 = lb2 - 1; + if (ub1 + size < n) + ub2 = ub1 + size; + else + ub2 = n - 1; + + i = lb1; + j = lb2; + + while (i <= ub1 && j <= ub2) + if (x[i] < x[j]) + temp[k++] = x[i++]; + else + temp[k++] = x[j++]; + + while (i <= ub1) temp[k++] = x[i++]; + + while (j <= ub2) temp[k++] = x[j++]; + + lb1 = ub2 + 1; + } + + for (i = 0; i <= ub2; i++) x[i] = temp[i]; + + size = size * 2; + + show(x, n); + } +} + +// function to show each pass +void show(int x[], int n) +{ + int i; + for (i = 0; i < n; i++) printf("%d ", x[i]); + printf("\n\n"); +} + +int main() // main function +{ + int i, n, x[20]; + + printf("Enter the number of elements: "); + scanf("%d", &n); + printf("Enter the elements:\n"); + for (i = 0; i < n; i++) scanf("%d", &x[i]); + + mergesort(x, n); + + printf("Sorted array is as shown:\n"); + for (i = 0; i < n; i++) printf("%d ", x[i]); + return 0; +} + +/* Output of the Program*/ +/* +Enter the number of elements: 5 +Enter the elements: +15 +14 +13 +12 +11 +14 15 12 13 11 + +12 13 14 15 11 + +11 12 13 14 15 + +Sorted array is as shown: +11 12 13 14 15 +*/ diff --git a/sorting/mergesort.c b/sorting/mergesort.c deleted file mode 100644 index 6533713fa5..0000000000 --- a/sorting/mergesort.c +++ /dev/null @@ -1,91 +0,0 @@ -#include - -void swap (int *a,int *b)//To swap the variables// -{ - int t; - t= *a; - *a=*b; - *b=t; - -} - -void merge(int a[],int l,int r,int n)//To merge // -{ int *b = (int*)malloc(n*sizeof(int)); -int c=l; - int p1,p2; - p1 = l;p2=((l+r)/2)+1; - while ((p1<((l+r)/2)+1) &&(p2a[r]) - swap(&a[l],&a[r]); - - } - else if(l==r) - {} - else - {mergesort(a,n,l,(l+r)/2); - mergesort(a,n,((l+r)/2)+1,r); - merge(a,l,r,n); - - } - -} -int main(void) { //main function// -int *a,n,i; -scanf("%d",&n); -a = (int*)malloc(n*sizeof(int)); -for (i=0;i Run basic timings on + demo trysearch Interactive pm and nn search on + demo nncost Run near neigbhor expers on + demo pmcost Interactive partial match expers on + */ + +#include +#include +#include +#include + +// MULTIKEY QUICKSORT + +#ifndef min +#define min(a, b) ((a) <= (b) ? (a) : (b)) +#endif + +#define swap(a, b) \ + { \ + char *t = x[a]; \ + x[a] = x[b]; \ + x[b] = t; \ + } +#define i2c(i) x[i][depth] + +void vecswap(int i, int j, int n, char *x[]) +{ + while (n-- > 0) + { + swap(i, j); + i++; + j++; + } +} + +void ssort1(char *x[], int n, int depth) +{ + int a, b, c, d, r, v; + if (n <= 1) + return; + a = rand() % n; + swap(0, a); + v = i2c(0); + a = b = 1; + c = d = n - 1; + for (;;) + { + while (b <= c && (r = i2c(b) - v) <= 0) + { + if (r == 0) + { + swap(a, b); + a++; + } + b++; + } + while (b <= c && (r = i2c(c) - v) >= 0) + { + if (r == 0) + { + swap(c, d); + d--; + } + c--; + } + if (b > c) + break; + swap(b, c); + b++; + c--; + } + r = min(a, b - a); + vecswap(0, b - r, r, x); + r = min(d - c, n - d - 1); + vecswap(b, n - r, r, x); + r = b - a; + ssort1(x, r, depth); + if (i2c(r) != 0) + ssort1(x + r, a + n - d - 1, depth + 1); + r = d - c; + ssort1(x + n - r, r, depth); +} + +void ssort1main(char *x[], int n) { ssort1(x, n, 0); } + +// ssort2 -- Faster Version of Multikey Quicksort + +void vecswap2(char **a, char **b, int n) +{ + while (n-- > 0) + { + char *t = *a; + *a++ = *b; + *b++ = t; + } +} + +#define swap2(a, b) \ + { \ + t = *(a); \ + *(a) = *(b); \ + *(b) = t; \ + } +#define ptr2char(i) (*(*(i) + depth)) + +char **med3func(char **a, char **b, char **c, int depth) +{ + int va, vb, vc; + if ((va = ptr2char(a)) == (vb = ptr2char(b))) + return a; + if ((vc = ptr2char(c)) == va || vc == vb) + return c; + return va < vb ? (vb < vc ? b : (va < vc ? c : a)) + : (vb > vc ? b : (va < vc ? a : c)); +} +#define med3(a, b, c) med3func(a, b, c, depth) + +void inssort(char **a, int n, int d) +{ + char **pi, **pj, *s, *t; + for (pi = a + 1; --n > 0; pi++) + for (pj = pi; pj > a; pj--) + { + // Inline strcmp: break if *(pj-1) <= *pj + for (s = *(pj - 1) + d, t = *pj + d; *s == *t && *s != 0; s++, t++) + ; + if (*s <= *t) + break; + swap2(pj, pj - 1); + } +} + +void ssort2(char **a, int n, int depth) +{ + int d, r, partval; + char **pa, **pb, **pc, **pd, **pl, **pm, **pn, *t; + if (n < 10) + { + inssort(a, n, depth); + return; + } + pl = a; + pm = a + (n / 2); + pn = a + (n - 1); + if (n > 30) + { // On big arrays, pseudomedian of 9 + d = (n / 8); + pl = med3(pl, pl + d, pl + 2 * d); + pm = med3(pm - d, pm, pm + d); + pn = med3(pn - 2 * d, pn - d, pn); + } + pm = med3(pl, pm, pn); + swap2(a, pm); + partval = ptr2char(a); + pa = pb = a + 1; + pc = pd = a + n - 1; + for (;;) + { + while (pb <= pc && (r = ptr2char(pb) - partval) <= 0) + { + if (r == 0) + { + swap2(pa, pb); + pa++; + } + pb++; + } + while (pb <= pc && (r = ptr2char(pc) - partval) >= 0) + { + if (r == 0) + { + swap2(pc, pd); + pd--; + } + pc--; + } + if (pb > pc) + break; + swap2(pb, pc); + pb++; + pc--; + } + pn = a + n; + r = min(pa - a, pb - pa); + vecswap2(a, pb - r, r); + r = min(pd - pc, pn - pd - 1); + vecswap2(pb, pn - r, r); + if ((r = pb - pa) > 1) + ssort2(a, r, depth); + if (ptr2char(a + r) != 0) + ssort2(a + r, pa - a + pn - pd - 1, depth + 1); + if ((r = pd - pc) > 1) + ssort2(a + n - r, r, depth); +} + +void ssort2main(char **a, int n) { ssort2(a, n, 0); } + +// TERNARY SEARCH TREE ALGS + +typedef struct tnode *Tptr; +typedef struct tnode +{ + char splitchar; + Tptr lokid, eqkid, hikid; +} Tnode; +Tptr root; + +// Insert 1 -- Simple Insertion Algorithm + +Tptr insert1(Tptr p, char *s) +{ + if (p == 0) + { + p = (Tptr)malloc(sizeof(Tnode)); + p->splitchar = *s; + p->lokid = p->eqkid = p->hikid = 0; + } + if (*s < p->splitchar) + p->lokid = insert1(p->lokid, s); + else if (*s == p->splitchar) + { + if (*s != 0) + p->eqkid = insert1(p->eqkid, ++s); + } + else + p->hikid = insert1(p->hikid, s); + return p; +} + +void cleanup1(Tptr p) +{ + if (p) + { + cleanup1(p->lokid); + cleanup1(p->eqkid); + cleanup1(p->hikid); + free(p); + } +} + +// Insert 2 -- Faster version of Insert + +#define BUFSIZE 1000 +Tptr buffer; +int bufn, freen; +void *freearr[10000]; +int storestring = 0; + +void insert2(char *s) +{ + int d; + char *instr = s; + + Tptr pp, *p; + p = &root; + pp = *p; + while (pp == *p) + { + if ((d = *s - pp->splitchar) == 0) + { + if (*s++ == 0) + return; + p = &(pp->eqkid); + } + else if (d < 0) + p = &(pp->lokid); + else + p = &(pp->hikid); + } + for (;;) + { + // *p = (Tptr) malloc(sizeof(Tnode)); + if (bufn-- == 0) + { + buffer = (Tptr)malloc(BUFSIZE * sizeof(Tnode)); + freearr[freen++] = (void *)buffer; + bufn = BUFSIZE - 1; + } + *p = buffer++; + pp = *p; + pp->splitchar = *s; + pp->lokid = pp->eqkid = pp->hikid = 0; + if (*s++ == 0) + { + if (storestring) + pp->eqkid = (Tptr)instr; + return; + } + p = &(pp->eqkid); + } +} +void cleanup2() +{ + int i; + for (i = 0; i < freen; i++) free(freearr[i]); +} + +// Search Algorithms + +int search1(char *s) +{ + Tptr p; + p = root; + while (p) + { + if (*s < p->splitchar) + p = p->lokid; + else if (*s == p->splitchar) + { + if (*s++ == 0) + return 1; + p = p->eqkid; + } + else + p = p->hikid; + } + return 0; +} + +int search2(char *s) +{ + int d, sc; + Tptr p; + sc = *s; + p = root; + while (p) + { + if ((d = sc - p->splitchar) == 0) + { + if (sc == 0) + return 1; + sc = *++s; + p = p->eqkid; + } + else if (d < 0) + p = p->lokid; + else + p = p->hikid; + } + return 0; +} + +// Advanced searching: Partial match, near words + +int nodecnt; +char *srcharr[100000]; +int srchtop; + +void pmsearch(Tptr p, char *s) +{ + if (!p) + return; + nodecnt++; + if (*s == '.' || *s < p->splitchar) + pmsearch(p->lokid, s); + if (*s == '.' || *s == p->splitchar) + if (p->splitchar && *s) + pmsearch(p->eqkid, s + 1); + if (*s == 0 && p->splitchar == 0) + srcharr[srchtop++] = (char *)p->eqkid; + if (*s == '.' || *s > p->splitchar) + pmsearch(p->hikid, s); +} + +void nearsearch(Tptr p, char *s, int d) +{ + if (!p || d < 0) + return; + nodecnt++; + if (d > 0 || *s < p->splitchar) + nearsearch(p->lokid, s, d); + if (p->splitchar == 0) + { + if ((int)strlen(s) <= d) + srcharr[srchtop++] = (char *)p->eqkid; + } + else + nearsearch(p->eqkid, *s ? s + 1 : s, (*s == p->splitchar) ? d : d - 1); + if (d > 0 || *s > p->splitchar) + nearsearch(p->hikid, s, d); +} + +#define NUMBER_OF_STRING 3 + +int main(int argc, char *argv[]) +{ + char *arr[NUMBER_OF_STRING] = {"apple", "cat", "boy"}; + + ssort1main(arr, NUMBER_OF_STRING); + + for (int i = 0; i < NUMBER_OF_STRING; i++) + { + printf("%s ", arr[i]); + } +} diff --git a/sorting/odd_even_sort.c b/sorting/odd_even_sort.c new file mode 100644 index 0000000000..217f3e00ef --- /dev/null +++ b/sorting/odd_even_sort.c @@ -0,0 +1,120 @@ +/** + * @file + * @author [Edwin Ajong](https://github.com/eddybruv) + * @brief [Odd Even Sort](https://en.wikipedia.org/wiki/Odd%E2%80%93even_sort) implementation + * @details + * This algorithm is divided into two phases- Odd and Even Phase. + * The algorithm runs until the array elements are sorted and in each iteration two phases occurs- Odd and Even Phases. + * In the odd phase, we perform a bubble sort on odd indexed elements and in the even phase, + * we perform a bubble sort on even indexed elements. + * Time Complexity: O(N ^ 2) + */ + +#include /// for assert +#include /// for bool +#include /// for IO operations +#include /// for dynammic memory allocation +#include /// for random number generation +#include /// for int32_t types + +/** + * @brief Swap numbers by reference(using pointers) + * @param first pointer to first number + * @param second pointer to second number + * @returns void + */ +void swap(int32_t *first, int32_t *second) +{ + int32_t temp = *first; + *first = *second; + *second = temp; +} + +/** + * @brief oddEvenSort sorts the array using the algorithm described above. + * @details + * A boolean varaible(isSorted) is declared and initialised to "false". + * In the while loop, the variable(isSorted) is then set to "true". + * During even phase the for loop loops through the array, touching just the even indexes. + * i.e arr[0], arr[2], arr[4] and so on. + * While during the odd phase, the for loop loops through the array, touching just the odd indexes. + * i.e arr[1], arr[3], arr[5] and so on. + * During these phases, if the if statement check if the interger at the current position in the array + * is greater than the interger at the next array index (i.e arr[index + 2], to make sure the index is odd + * during the odd phase and even during the even phase). + * If the condition is true, the function "swap" is called and address of the intergers in question are passed as + * parameters. After the swap is completed, "isSorted" is set to "false". + * The while loop will keep running till the array is propertly sorted. + * @param arr array to be sorted + * @param size the size of the array + * @returns void + */ +void oddEvenSort(int *arr, int size) +{ + bool isSorted = false; + while(!isSorted) + { + isSorted = true; + int32_t i; + + // Even phase + for(i = 0; i <= size - 2; i += 2) + { + if(arr[i] > arr[i + 1]) + { + swap(&arr[i], &arr[i + 1]); + isSorted = false; + } + } + + // Odd phase + for(i = 1; i <= size - 2; i += 2) + { + if(arr[i] > arr[i + 1]) + { + swap(&arr[i], &arr[i + 1]); + isSorted = false; + } + } + } +} + +/** + * @brief Self-test implementations + * @details Two tests (unsorted) arrays were created and their corresponding solution(sorted) arrays were also created. + * The test arrays and their respective sizes are then passed in to the oddEvenSort function. + * To test if the algorithm works, a for loop is assigned to loop through the both arrays(test and solution) and check if the array elements + * of the test array correspond to the elements of the solution array. + * @returns void + */ +static void test() +{ + int32_t arr1[] = {-9, 2, 3, 1}; + int32_t arr1Soln[] = {-9, 1, 2, 3}; + int32_t arr2[] = {9, 7, 5, 3, 8, 2, 1, 4, 0, 6}; + int32_t arr2Soln[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + + oddEvenSort(arr1, 4); + oddEvenSort(arr2, 10); + + for (int32_t i = 0; i < 4; i++) + { + assert(arr1[i] == arr1Soln[i]); + } + + for (int32_t i = 0; i < 10; i++) + { + assert(arr2[i] == arr2Soln[i]); + } + printf("All tests have passed!\n"); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + test(); // run self-test implementations + return 0; +} diff --git a/sorting/pancake_sort.c b/sorting/pancake_sort.c new file mode 100644 index 0000000000..904b253eea --- /dev/null +++ b/sorting/pancake_sort.c @@ -0,0 +1,82 @@ +// Sorting of array list using pancake sort +#include +#include + +/* Reverses the array */ +void flip(int arr[], int i) +{ + int temp, start = 0; + + while (start < i) + { + temp = arr[start]; + arr[start] = arr[i]; + arr[i] = temp; + start++; + i--; + } +} + +// Returns index of the maximum element in arr[0..n-1] +int findMax(int arr[], int n) +{ + int maxElementIdx, i; + + for (maxElementIdx = 0, i = 0; i < n; ++i) + if (arr[i] > arr[maxElementIdx]) + maxElementIdx = i; + + return maxElementIdx; +} + +// Sorts the array using flip operations +void pancakeSort(int *arr, int n) +{ + // Start from the complete array and one by one reduce current size by one + for (int curr_size = n; curr_size > 1; --curr_size) + { + // Find index of the maximum element in arr[0..curr_size-1] + int maxElementIdx = findMax(arr, curr_size); + + // Move the maximum element to end of current array if it's not already + // at the end + if (maxElementIdx != curr_size - 1) + { + // To move at the end, first move maximum number to beginning + flip(arr, maxElementIdx); + + // Now move the maximum number to end by reversing current array + flip(arr, curr_size - 1); + } + } +} + +// Displays the array, passed to this method +void display(int arr[], int n) +{ + for (int i = 0; i < n; i++) + { + printf("%d ", arr[i]); + } + + printf("\n"); +} + +#define N 50 + +// Driver program to test above function +int main() +{ + int arr[N]; + for (int i = 0; i < N; i++) + arr[i] = rand() % (N << 1); /* random numbers from 0 to 2N */ + + printf("Original array: "); + display(arr, N); + + pancakeSort(arr, N); + printf("Sorted array: "); + display(arr, N); + + return 0; +} \ No newline at end of file diff --git a/sorting/partitionSort.c b/sorting/partition_sort.c similarity index 95% rename from sorting/partitionSort.c rename to sorting/partition_sort.c index a0b9f57558..fc7a3430cb 100644 --- a/sorting/partitionSort.c +++ b/sorting/partition_sort.c @@ -1,5 +1,5 @@ -#include #include +#include void swap(int *a, int *b) { @@ -48,8 +48,7 @@ void partitionSort(int arr[], int low, int high) void printArray(int arr[], int n) { int i; - for (i = 0; i < n; i++) - printf("%d ", arr[i]); + for (i = 0; i < n; i++) printf("%d ", arr[i]); printf("\n"); } diff --git a/sorting/patience_sort.c b/sorting/patience_sort.c new file mode 100644 index 0000000000..5e069bf240 --- /dev/null +++ b/sorting/patience_sort.c @@ -0,0 +1,160 @@ +/** + * @file + * @brief [Patience Sort](https://en.wikipedia.org/wiki/Patience_sorting) + * @details From Wikipedia: + * In computer science, patience sorting is a sorting algorithm inspired by, and named after, the card game patience. + * Given an array of n elements from some totally ordered domain, consider this array as a collection of cards and simulate the patience sorting game. + * When the game is over, recover the sorted sequence by repeatedly picking off the minimum visible card; + * in other words, perform a k-way merge of the p piles, each of which is internally sorted. + * @author [CascadingCascade](https://github.com/CascadingCascade) + */ + +#include /// for assertions +#include /// for IO operations +#include /// for memory management + +/** + * @brief Sorts the target array by dividing it into a variable number of internally sorted piles then merge the piles + * @param array pointer to the array to be sorted + * @param length length of the target array + * @returns void + */ +void patienceSort(int *array, int length) { + // An array of pointers used to store each pile + int* *piles = (int* *) malloc(sizeof(int*) * length); + for (int i = 0; i < length; ++i) { + piles[i] = malloc(sizeof(int) * length); + } + + // pileSizes keep track of the indices of each pile's topmost element, hence 0 means only one element + // Note how calloc() is used to initialize the sizes of all piles to zero + int *pileSizes = (int*) calloc(length,sizeof(int)); + + // This initializes the first pile, note how using an array of pointers allowed us to access elements through two subscripts + // The first subscript indicates which pile we are accessing, the second subscript indicates the location being accessed in that pile + piles[0][0] = array[0]; + int pileCount = 1; + + for (int i = 1; i < length; ++i) { + // This will be used to keep track whether an element has been added to an existing pile + int flag = 1; + + for (int j = 0; j < pileCount; ++j) { + if(piles[j][pileSizes[j]] > array[i]) { + // We have found a pile this element can be added to + piles[j][pileSizes[j] + 1] = array[i]; + pileSizes[j]++; + flag--; + break; + } + } + + if(flag) { + // The element in question can not be added to any existing piles, creating a new pile + piles[pileCount][0] = array[i]; + pileCount++; + } + } + + // This will keep track of the minimum value of all 'exposed' elements and which pile that value is from + int min, minLocation; + + for (int i = 0; i < length; ++i) { + // Since there's no guarantee the first pile will be depleted slower than other piles, + // Example: when all elements are equal, in that case the first pile will be depleted immediately + // We can't simply initialize min to the top most element of the first pile, + // this loop finds a value to initialize min to. + for (int j = 0; j < pileCount; ++j) { + if(pileSizes[j] < 0) { + continue; + } + min = piles[j][pileSizes[j]]; + minLocation = j; + break; + } + + for (int j = 0; j < pileCount; ++j) { + if(pileSizes[j] < 0) { + continue; + } + if(piles[j][pileSizes[j]] < min) { + min = piles[j][pileSizes[j]]; + minLocation = j; + } + } + + array[i] = min; + pileSizes[minLocation]--; + } + + // Deallocate memory + free(pileSizes); + for (int i = 0; i < length; ++i) { + free(piles[i]); + } + free(piles); +} + +/** + * @brief Helper function to print an array + * @param array pointer to the array + * @param length length of the target array + * @returns void + */ +void printArray(int *array,int length) { + printf("Array:"); + for (int i = 0; i < length; ++i) { + printf("%d",array[i]); + if (i != length - 1) putchar(','); + } + putchar('\n'); +} + +/** + * @brief Testing Helper function + * @param array pointer to the array to be used for testing + * @param length length of the target array + * @returns void + */ + +void testArray(int *array,int length) { + printf("Before sorting:\n"); + printArray(array,length); + + patienceSort(array,length); + + printf("After sorting:\n"); + printArray(array,length); + + for (int i = 0; i < length - 1; ++i) { + assert(array[i] <= array[i + 1]); + } + printf("All assertions have passed!\n\n"); +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() { + int testArray1[] = {2,8,7,1,3,5,6,4}; + int testArray2[] = {2,2,5,1,3,5,6,4}; + int testArray3[] = {1,2,3,4,5,6,7,8}; + int testArray4[] = {8,7,6,5,4,3,2,1}; + + testArray(testArray1,8); + testArray(testArray2,8); + testArray(testArray3,8); + testArray(testArray4,8); + + printf("Testing successfully completed!\n"); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() { + test(); // run self-test implementations + return 0; +} diff --git a/sorting/pigeonhole_sort.c b/sorting/pigeonhole_sort.c new file mode 100644 index 0000000000..8d882a26d3 --- /dev/null +++ b/sorting/pigeonhole_sort.c @@ -0,0 +1,73 @@ +#include +#include + +void pigeonholeSort(int arr[], int size) +{ + int i, j, min = arr[0], max = arr[0], range; + + // Getting range of the array using max and min + for (i = 1; i < size; i++) + { + if (arr[i] < min) + min = arr[i]; + if (arr[i] > max) + max = arr[i]; + } + range = max - min + 1; + + // Make 'holes' and put array's numbers in holes + int *holes = (int *)malloc(sizeof(int) * range); + for (i = 0; i < range; i++) + { + holes[i] = 0; + } + for (i = 0; i < size; i++) + { + holes[arr[i] - min]++; + } + + // Copy the numbers back to the original array + j = 0; + for (i = 0; i < range; i++) + { + while (holes[i] > 0) + { + arr[j] = i + min; + holes[i]--; + j++; + } + } + + free(holes); +} + +int main() +{ + int i, n; + + printf("Enter the size of the array: "); + scanf("%d", &n); + int *arr = (int *)malloc(sizeof(int) * n); + + for (i = 0; i < n; i++) + { + printf("Number #%d: ", i + 1); + scanf("%d", &arr[i]); + } + + printf("You entered: "); + for (i = 0; i < n; i++) + { + printf("%d ", arr[i]); + } + pigeonholeSort(arr, n); + printf("\nSorted array: "); + for (i = 0; i < n; i++) + { + printf("%d ", arr[i]); + } + printf("\n"); + + free(arr); + return 0; +} \ No newline at end of file diff --git a/sorting/QuickSort.c b/sorting/quick_sort.c similarity index 70% rename from sorting/QuickSort.c rename to sorting/quick_sort.c index b69f8aec2e..886cd0f8b1 100644 --- a/sorting/QuickSort.c +++ b/sorting/quick_sort.c @@ -4,7 +4,6 @@ /*Displays the array, passed to this method*/ void display(int arr[], int n) { - int i; for (i = 0; i < n; i++) { @@ -17,7 +16,6 @@ void display(int arr[], int n) /*Swap function to swap two values*/ void swap(int *first, int *second) { - int temp = *first; *first = *second; *second = temp; @@ -27,45 +25,43 @@ void swap(int *first, int *second) and places each element which is less than the pivot value to its left and the elements greater than the pivot value to its right arr[] --- array to be partitioned - lower --- lower index + lower --- lower index upper --- upper index */ int partition(int arr[], int lower, int upper) { - int i = (lower - 1); - int pivot = arr[upper]; // Selects last element as the pivot value + int pivot = arr[upper]; // Selects last element as the pivot value int j; for (j = lower; j < upper; j++) { - if (arr[j] <= pivot) - { // if current element is smaller than the pivot + { // if current element is smaller than the pivot - i++; // increment the index of smaller element + i++; // increment the index of smaller element swap(&arr[i], &arr[j]); } } - swap(&arr[i + 1], &arr[upper]); // places the last element i.e, the pivot to its correct position + swap(&arr[i + 1], &arr[upper]); // places the last element i.e, the pivot + // to its correct position return (i + 1); } /*This is where the sorting of the array takes place - arr[] --- Array to be sorted - lower --- Starting index - upper --- Ending index + arr[] --- Array to be sorted + lower --- Starting index + upper --- Ending index */ void quickSort(int arr[], int lower, int upper) { - if (upper > lower) { - - // partitioning index is returned by the partition method , partition element is at its correct poition + // partitioning index is returned by the partition method , partition + // element is at its correct poition int partitionIndex = partition(arr, lower, upper); @@ -77,10 +73,9 @@ void quickSort(int arr[], int lower, int upper) int main() { - int n; printf("Enter size of array:\n"); - scanf("%d", &n); // E.g. 8 + scanf("%d", &n); // E.g. 8 printf("Enter the elements of the array\n"); int i; @@ -91,12 +86,13 @@ int main() } printf("Original array: "); - display(arr, n); // Original array : 10 11 9 8 4 7 3 8 + display(arr, n); // Original array : 10 11 9 8 4 7 3 8 quickSort(arr, 0, n - 1); printf("Sorted array: "); - display(arr, n); // Sorted array : 3 4 7 8 8 9 10 11 + display(arr, n); // Sorted array : 3 4 7 8 8 9 10 11 getchar(); + free(arr); return 0; } diff --git a/sorting/radix_sort.c b/sorting/radix_sort.c new file mode 100644 index 0000000000..364a3917a1 --- /dev/null +++ b/sorting/radix_sort.c @@ -0,0 +1,71 @@ +#include + +int largest(int a[], int n) +{ + int large = a[0], i; + for (i = 1; i < n; i++) + { + if (large < a[i]) + large = a[i]; + } + return large; +} + +void RadixSort(int a[], int n) +{ + int bucket[10][10], bucket_count[10]; + int i, j, k, remainder, NOP = 0, divisor = 1, large, pass; + + large = largest(a, n); + printf("The large element %d\n", large); + while (large > 0) + { + NOP++; + large /= 10; + } + + for (pass = 0; pass < NOP; pass++) + { + for (i = 0; i < 10; i++) + { + bucket_count[i] = 0; + } + for (i = 0; i < n; i++) + { + remainder = (a[i] / divisor) % 10; + bucket[remainder][bucket_count[remainder]] = a[i]; + bucket_count[remainder] += 1; + } + + i = 0; + for (k = 0; k < 10; k++) + { + for (j = 0; j < bucket_count[k]; j++) + { + a[i] = bucket[k][j]; + i++; + } + } + divisor *= 10; + + for (i = 0; i < n; i++) printf("%d ", a[i]); + printf("\n"); + } +} + +int main() +{ + int i, n, a[10]; + printf("Enter the number of elements :: "); + scanf("%d", &n); + printf("Enter the elements :: "); + for (i = 0; i < n; i++) + { + scanf("%d", &a[i]); + } + RadixSort(a, n); + printf("The sorted elements are :: "); + for (i = 0; i < n; i++) printf("%d ", a[i]); + printf("\n"); + return 0; +} diff --git a/sorting/radix_sort_2.c b/sorting/radix_sort_2.c new file mode 100644 index 0000000000..e527e92fba --- /dev/null +++ b/sorting/radix_sort_2.c @@ -0,0 +1,95 @@ +// sorting of array list using Radix sort +#include +#include + +#define range 10 // Range for integers is 10 as digits range from 0-9 + +// Utility function to get the maximum value in ar[] +int MAX(int *ar, int size) +{ + int i, max = ar[0]; + for (i = 0; i < size; i++) + { + if (ar[i] > max) + max = ar[i]; + } + return max; +} + +// Counting sort according to the digit represented by place +void countSort(int *arr, int n, int place) +{ + int i, freq[range] = {0}; + int *output = (int *)malloc(n * sizeof(int)); + + // Store count of occurrences in freq[] + for (i = 0; i < n; i++) freq[(arr[i] / place) % range]++; + + // Change freq[i] so that it contains the actual position of the digit in + // output[] + for (i = 1; i < range; i++) freq[i] += freq[i - 1]; + + // Build the output array + for (i = n - 1; i >= 0; i--) + { + output[freq[(arr[i] / place) % range] - 1] = arr[i]; + freq[(arr[i] / place) % range]--; + } + + // Copy the output array to arr[], so it contains numbers according to the + // current digit + for (i = 0; i < n; i++) arr[i] = output[i]; + free(output); +} + +/*This is where the sorting of the array takes place + arr[] --- Array to be sorted + n --- Array Size + max --- Maximum element in Array + */ +void radixsort2(int *arr, int n, + int max) // max is the maximum element in the array +{ + int mul = 1; + while (max) + { + countSort(arr, n, mul); + mul *= 10; + max /= 10; + } +} + +void display(int *arr, int N) +{ + for (int i = 0; i < N; i++) printf("%d, ", arr[i]); + putchar('\n'); +} + +int main(int argc, const char *argv[]) +{ + int n; + printf("Enter size of array:\n"); + scanf("%d", &n); // E.g. 8 + + printf("Enter the elements of the array\n"); + int i; + int *arr = (int *)malloc(n * sizeof(int)); + for (i = 0; i < n; i++) + { + scanf("%d", &arr[i]); + } + + printf("Original array: "); + display(arr, n); // Original array : 10 11 9 8 4 7 3 8 + + int max; + max = MAX(arr, n); + + radixsort2(arr, n, max); + + printf("Sorted array: "); + display(arr, n); // Sorted array : 3 4 7 8 8 9 10 11 + + free(arr); + return 0; +} diff --git a/sorting/random_quick_sort.c b/sorting/random_quick_sort.c new file mode 100644 index 0000000000..71cac3617c --- /dev/null +++ b/sorting/random_quick_sort.c @@ -0,0 +1,99 @@ +/* +Randomised quick sort implementation in C language. +In normal quick sort, pivot chosen to partition is either the first or the last +element of the array. This can take time O(n*n) to sort in the worst case. Now +in randomised quick sort, pivot is randomly chosen and then recursively sort the +left and right sub-arrays. The expected running time of the algorithm is +O(nlog(n)). +*/ +#include +#include +#include + +int getBig(int *a, int i, int right, int pivot) +{ + for (int k = i; k <= right; k++) + { + if (a[k] > pivot) + return k; + } + return right + 1; +} + +int getSmall(int *a, int j, int left, int pivot) +{ + for (int k = j; k >= left; k--) + { + if (a[k] < pivot) + return k; + } + return -1; +} + +void swap(int *a, int *b) +{ + int t = *a; + *a = *b; + *b = t; +} + +void random_quick(int *a, int left, int right) +{ + if (left >= right) + return; + int index = left + (rand() % (right - left)), i = left, j = right; + int pivot_index = index; + int pivot = a[index]; + // storing index of element greater than pivot + i = getBig(a, i, right, pivot); + // storing index of element smaller than pivot + j = getSmall(a, j, left, pivot); + while (i <= j) + { + swap(&a[i], &a[j]); + i = getBig(a, i, right, pivot); + j = getSmall(a, j, left, pivot); + } + // after separating the smaller and greater elements, there are 3 cases + // possible + if (pivot_index > j && pivot_index > i) + { + // case 1. When the pivot element index is greater than both i and j + swap(&a[i], &a[pivot_index]); + random_quick(a, left, i - 1); + random_quick(a, i + 1, right); + } + else if (pivot_index < j && pivot_index < i) + { + // case 2. When the pivot element index is smaller than both i and j + swap(&a[j], &a[pivot_index]); + random_quick(a, left, j - 1); + random_quick(a, j + 1, right); + } + else + { + // the pivot element is at its origin position. + random_quick(a, left, pivot_index - 1); + random_quick(a, pivot_index + 1, right); + } +} + +int main() +{ + srand(time(0)); + int num; + scanf("%d", &num); + int *arr = (int *)malloc(num * sizeof(int)); + for (int i = 0; i < num; i++) + { + scanf("%d", &arr[i]); + } + random_quick(arr, 0, num - 1); + for (int i = 0; i < num; i++) + { + printf("%d ", arr[i]); + } + + free(arr); + printf("\n"); +} diff --git a/sorting/selection_sort.c b/sorting/selection_sort.c new file mode 100644 index 0000000000..c7547608c7 --- /dev/null +++ b/sorting/selection_sort.c @@ -0,0 +1,75 @@ +/** + * @file + * @brief [Selection sort](https://en.wikipedia.org/wiki/Selection_sort) + * algorithm implementation. + */ +#include +#include +#include +#include + +/** + * Swapped two numbers using pointer + * @param first first pointer of first number + * @param second second pointer of second number + */ +void swap(int *first, int *second) +{ + int temp = *first; + *first = *second; + *second = temp; +} + +/** + * Selection sort algorithm implements + * @param arr array to be sorted + * @param size size of array + */ +void selectionSort(int *arr, int size) +{ + for (int i = 0; i < size - 1; i++) + { + int min_index = i; + for (int j = i + 1; j < size; j++) + { + if (arr[min_index] > arr[j]) + { + min_index = j; + } + } + if (min_index != i) + { + swap(arr + i, arr + min_index); + } + } +} + +/** Test function + * @returns None + */ +static void test() +{ + const int size = rand() % 500; /* random array size */ + int *arr = (int *)calloc(size, sizeof(int)); + + /* generate size random numbers from -50 to 49 */ + for (int i = 0; i < size; i++) + { + arr[i] = (rand() % 100) - 50; /* signed random numbers */ + } + selectionSort(arr, size); + for (int i = 0; i < size - 1; ++i) + { + assert(arr[i] <= arr[i + 1]); + } + free(arr); +} + +/** Driver Code */ +int main(int argc, const char *argv[]) +{ + /* Intializes random number generator */ + srand(time(NULL)); + test(); + return 0; +} diff --git a/sorting/selection_sort_recursive.c b/sorting/selection_sort_recursive.c new file mode 100644 index 0000000000..660a32a8e5 --- /dev/null +++ b/sorting/selection_sort_recursive.c @@ -0,0 +1,109 @@ +/** + * @file + * @author [Dhruv Pasricha](https://github.com/DhruvPasricha) + * @brief [Selection Sort](https://en.wikipedia.org/wiki/Selection_sort) + * implementation using recursion. + */ + +#include /// for assert +#include /// for IO operations +#include /// for dynamic memory allocation +#include /// for random numbers generation +#include /// for uint8_t, int8_t + +/** + * @brief Swapped two numbers using pointer + * @param first pointer of first number + * @param second pointer of second number + */ +void swap(int8_t *first, int8_t *second) +{ + int8_t temp = *first; + *first = *second; + *second = temp; +} + +/** + * @brief Returns the index having minimum value using recursion + * @param arr array to be sorted + * @param size size of array + * @return min_index index of an element having a minimum value +*/ +uint8_t findIndex(const int8_t *arr, const uint8_t size) +{ + if (size == 1) + { + return 0; + } + + // marking recursive call to reach starting element + uint8_t min_index = findIndex(arr, size - 1); + + if (arr[size - 1] < arr[min_index]) + { + min_index = size - 1; + } + + return min_index; +} + +/** + * @brief Selection Sort algorithm implemented using recursion + * @param arr array to be sorted + * @param size size of the array + * @returns void + */ +void selectionSort(int8_t *arr, const uint8_t size) +{ + if (size <= 1) + { + return; + } + + /* findIndex(arr, size) returned the index having min value*/ + uint8_t min_index = findIndex(arr, size); + /* arr[min_index] is the minimum value in the array*/ + + if (min_index != 0) + { + swap(&arr[0], &arr[min_index]); + } + + /*sorted the remaining array recursively*/ + selectionSort(arr + 1, size - 1); +} + +/** + * @brief Self-test implementations + * @returns void + */ +static void test() +{ + const uint8_t size = 10; + int8_t *arr = (int8_t *)calloc(size, sizeof(int8_t)); + + /* generate size random numbers from 0 to 100 */ + for (uint8_t i = 0; i < size; i++) + { + arr[i] = rand() % 100; + } + selectionSort(arr, size); + for (uint8_t i = 0; i < size - 1; ++i) + { + assert(arr[i] <= arr[i + 1]); + } + free(arr); +} + +/** + * @brief Main function + * @returns 0 on exit + */ +int main() +{ + /* Intializes random number generator */ + srand(time(NULL)); + + test(); // run self-test implementations + return 0; +} diff --git a/sorting/shaker_sort.c b/sorting/shaker_sort.c index cfd8dfcdf3..9f9a0b6d29 100644 --- a/sorting/shaker_sort.c +++ b/sorting/shaker_sort.c @@ -1,35 +1,39 @@ #include +#include -void swap(int *a, int *b){ +void swap(int *a, int *b) +{ int temp; temp = *a; *a = *b; *b = temp; } -void shakersort(int a[], int n) +void shakersort(int *a, int n) { int p, i; for (p = 1; p <= n / 2; p++) { for (i = p - 1; i < n - p; i++) - if (a[i] > a[i+1]){ + if (a[i] > a[i + 1]) + { swap(&a[i], &a[i + 1]); - } + } for (i = n - p - 1; i >= p; i--) - if (a[i] < a[i-1]){ + if (a[i] < a[i - 1]) + { swap(&a[i], &a[i - 1]); - } + } } } int main() { int n; - scanf("%d",&n); - int arr[n] ,i; - for (i = 0 ; i < n; i++) - scanf("%d ", &arr[i]); + scanf("%d", &n); + int *arr = (int *)malloc(n * sizeof(int)); + int i; + for (i = 0; i < n; i++) scanf("%d ", &arr[i]); shakersort(arr, n); - for (i = 0 ; i < n; i++) - printf("%d ", arr[i]); + for (i = 0; i < n; i++) printf("%d ", arr[i]); + free(arr); return 0; } diff --git a/sorting/shellSort.c b/sorting/shell_sort.c similarity index 77% rename from sorting/shellSort.c rename to sorting/shell_sort.c index c332647d6b..4c22c3d491 100644 --- a/sorting/shellSort.c +++ b/sorting/shell_sort.c @@ -1,68 +1,67 @@ -#include -#include -#include - -#define ELEMENT_NR 20 -#define ARRAY_LEN(x) (sizeof(x) / sizeof((x)[0])) -const char *notation = "Shell Sort Big O Notation:\ - \n--> Best Case: O(n log(n)) \ - \n--> Average Case: depends on gap sequence \ - \n--> Worst Case: O(n)"; - -void show_data(int arr[], int len) -{ - int i; - - for (i = 0; i < len; i++) - printf("%3d ", arr[i]); - printf("\n"); -} - -void swap(int *a, int *b) -{ - int tmp; - - tmp = *a; - *a = *b; - *b = tmp; -} - -void shellSort(int array[], int len) -{ - int i, j, gap; - - for (gap = len / 2; gap > 0; gap = gap / 2) - for (i = gap; i < len; i++) - for (j = i - gap; j >= 0 && array[j] > array[j + gap]; j = j - gap) - swap(&array[j], &array[j + gap]); -} - -int main(int argc, char *argv[]) -{ - int i; - int array[ELEMENT_NR]; - int range = 500; - int size; - clock_t start, end; - double time_spent; - - srand(time(NULL)); - for (i = 0; i < ELEMENT_NR; i++) - array[i] = rand() % range + 1; - - size = ARRAY_LEN(array); - - show_data(array, size); - start = clock(); - shellSort(array, size); - end = clock(); - time_spent = (double)(end - start) / CLOCKS_PER_SEC; - - printf("Data Sorted\n"); - show_data(array, size); - - printf("%s\n", notation); - printf("Time spent sorting: %f\n", time_spent); - - return 0; -} +#include +#include +#include + +#define ELEMENT_NR 20000 +#define ARRAY_LEN(x) (sizeof(x) / sizeof((x)[0])) +const char *notation = + "Shell Sort Big O Notation:\ + \n--> Best Case: O(n log(n)) \ + \n--> Average Case: depends on gap sequence \ + \n--> Worst Case: O(n)"; + +void show_data(int arr[], int len) +{ + int i; + + for (i = 0; i < len; i++) printf("%3d ", arr[i]); + printf("\n"); +} + +void swap(int *a, int *b) +{ + int tmp; + + tmp = *a; + *a = *b; + *b = tmp; +} + +void shellSort(int array[], int len) +{ + int i, j, gap; + + for (gap = len / 2; gap > 0; gap = gap / 2) + for (i = gap; i < len; i++) + for (j = i - gap; j >= 0 && array[j] > array[j + gap]; j = j - gap) + swap(&array[j], &array[j + gap]); +} + +int main(int argc, char *argv[]) +{ + int i; + int array[ELEMENT_NR]; + int range = 500; + int size; + clock_t start, end; + double time_spent; + + srand(time(NULL)); + for (i = 0; i < ELEMENT_NR; i++) array[i] = rand() % range + 1; + + size = ARRAY_LEN(array); + + show_data(array, size); + start = clock(); + shellSort(array, size); + end = clock(); + time_spent = (double)(end - start) / CLOCKS_PER_SEC; + + printf("Data Sorted\n"); + show_data(array, size); + + printf("%s\n", notation); + printf("Time spent sorting: %.4g ms\n", time_spent * 1e3); + + return 0; +} diff --git a/sorting/shell_sort2.c b/sorting/shell_sort2.c new file mode 100644 index 0000000000..a470e3af8e --- /dev/null +++ b/sorting/shell_sort2.c @@ -0,0 +1,96 @@ +/** + * \file + * \brief [Shell sort algorithm](https://en.wikipedia.org/wiki/Shell_sort) + * implementation. + * \author [Krishna Vedala](https://github.com/kvedala) + */ +#include +#include +#include + +/** + * @addtogroup sorting Sorting algorithms + * @{ + */ +/** Helper function to print array values */ +void show_data(int *arr, long len) +{ + for (long i = 0; i < len; i++) printf("%3d ", arr[i]); + printf("\n"); +} + +/** Function to swap values of two integers + * @param [in,out] a reference to first variable + * @param [in,out] b reference to second variable + */ +inline void swap(int *a, int *b) +{ + int tmp; + + tmp = *a; + *a = *b; + *b = tmp; +} + +/** + * Shell sort algorithm.\n + * Optimized algorithm - takes half the time as other + * @param [in,out] array array to sort + * @param [in] LEN length of the array + */ +void shell_sort(int *array, long LEN) +{ + const int gaps[] = {701, 301, 132, 57, 23, 10, 4, 1}; + const int gap_len = 8; + long i, j, g; + + for (g = 0; g < gap_len; g++) + { // for each gap + int gap = gaps[g]; + for (i = gap; i < LEN; i++) + { // from gap position to the end + int tmp = array[i]; + + for (j = i; j >= gap && (array[j - gap] - tmp) > 0; j -= gap) + array[j] = array[j - gap]; + array[j] = tmp; + } + } +#ifdef DEBUG + for (i = 0; i < LEN; i++) printf("%s\t", data[i]); +#endif +} +/** @} */ + +/** Main function */ +int main(int argc, char *argv[]) +{ + int i; + long size = 500; + if (argc == 2) + size = atol(argv[1]); + else if (argc > 2) + fprintf(stderr, "Usage: ./shell_sort [number of values]\n"); + + int *array = (int *)malloc(size * sizeof(int)); + int range = 500; // range of array values + double time_spent; + + srand(time(NULL)); // initialize random number generator + for (i = 0; i < size; i++) + // fill array with random integers + array[i] = rand() % range + 1; + + show_data(array, size); // show array before sorting + clock_t t1 = clock(); // start timer + shell_sort(array, size); // sort the array + clock_t t2 = clock(); // end timer + + printf("Data Sorted\n"); + show_data(array, size); // display array after sorting + + printf("Time spent sorting: %.4g s\n", (t2 - t1) / CLOCKS_PER_SEC); + + free(array); + return 0; +} diff --git a/sorting/stooge_sort.c b/sorting/stooge_sort.c new file mode 100644 index 0000000000..0072adb725 --- /dev/null +++ b/sorting/stooge_sort.c @@ -0,0 +1,36 @@ +#include +void stoogesort(int[], int, int); + +int main() +{ + int arr[100], i, n; + + printf("How many elements do you want to sort: "); + scanf("%d", &n); + for (i = 0; i < n; i++) scanf(" %d", &arr[i]); + stoogesort(arr, 0, n - 1); + printf("Sorted array : \n"); + for (i = 0; i < n; i++) + { + printf("%d ", arr[i]); + } + printf("\n"); + return 0; +} + +void stoogesort(int arr[], int i, int j) +{ + int temp, k; + if (arr[i] > arr[j]) + { + temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } + if ((i + 1) >= j) + return; + k = (int)((j - i + 1) / 3); + stoogesort(arr, i, j - k); + stoogesort(arr, i + k, j); + stoogesort(arr, i, j - k); +}