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.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 8d00ac28ce..0000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve. Report bugs found while using the project -title: "[BUG]" -labels: bug -assignees: '' - ---- - - - -## Description - - -## Expected Behavior - - -## Actual Behavior - - -## Possible Fix - - -## Steps to Reproduce - - - -1. -2. -3. -4. - -## Context - 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.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 2d16962616..0000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest features, propose improvements, discuss new ideas. -title: "[FEATURE]" -labels: enhancement -assignees: '' - ---- - - - -## Detailed Description - - -## Context - - - -## Possible Implementation - 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/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 index 184dee4c71..d57946e53c 100644 --- a/.github/workflows/awesome_workflow.yml +++ b/.github/workflows/awesome_workflow.yml @@ -1,100 +1,34 @@ name: Awesome CI Workflow - on: [push, pull_request] -# push: -# branches: [ master ] -# pull_request: -# branches: [ master ] +permissions: + contents: write jobs: MainSequence: name: Code Formatter runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 # v2 is broken for git diff - - uses: actions/setup-python@v2 + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - uses: actions/setup-python@v4 - name: requirements run: | - sudo apt -qq -y update - sudo apt -qq install clang-tidy-10 clang-format-10 + 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 - 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 + git config --global user.name github-actions[bot] + git config --global user.email 'github-actions@users.noreply.github.com' - name: Filename Formatter - run: | - IFS=$'\n' - for fname in `find . -type f -name '*.c' -o -name '*.h'` - do - echo "${fname}" - new_fname=`echo ${fname} | tr ' ' '_'` - echo " ${new_fname}" - new_fname=`echo ${new_fname} | tr 'A-Z' 'a-z'` - echo " ${new_fname}" - new_fname=`echo ${new_fname} | tr '-' '_'` - echo " ${new_fname}" - if [ ${fname} != ${new_fname} ] - then - echo " ${fname} --> ${new_fname}" - git "mv" "${fname}" ${new_fname} - fi - done - git commit -am "formatting filenames ${GITHUB_SHA::8}" || true - - name: Update DIRECTORY.md - shell: python - run: | - import os - from typing import Iterator - - URL_BASE = "https://github.com/TheAlgorithms/C/blob/master" - g_output = [] - - def good_filepaths(top_dir: str = ".") -> Iterator[str]: - cpp_exts = tuple(".c .c++ .cc .cpp .cu .cuh .cxx .h .h++ .hh .hpp .hxx".split()) - for dirpath, dirnames, filenames in os.walk(top_dir): - dirnames[:] = [d for d in dirnames if d[0] not in "._"] - for filename in filenames: - if os.path.splitext(filename)[1].lower() in cpp_exts: - yield os.path.join(dirpath, filename).lstrip("./") - - def md_prefix(i): - return f"{i * ' '}*" if i else "\n##" - - def print_path(old_path: str, new_path: str) -> str: - global g_output - old_parts = old_path.split(os.sep) - for i, new_part in enumerate(new_path.split(os.sep)): - if i + 1 > len(old_parts) or old_parts[i] != new_part: - if new_part: - g_output.append(f"{md_prefix(i)} {new_part.replace('_', ' ').title()}") - return new_path - - def build_directory_md(top_dir: str = ".") -> str: - global g_output - old_path = "" - for filepath in sorted(good_filepaths(), key=str.lower): - filepath, filename = os.path.split(filepath) - if filepath != old_path: - old_path = print_path(old_path, filepath) - indent = (filepath.count(os.sep) + 1) if filepath else 0 - url = "/".join((URL_BASE, filepath, filename)).replace(" ", "%20") - filename = os.path.splitext(filename.replace("_", " ").title())[0] - g_output.append(f"{md_prefix(indent)} [{filename}]({url})") - return "# List of all files\n" + "\n".join(g_output) - - with open("DIRECTORY.md", "w") as out_file: - out_file.write(build_directory_md(".") + "\n") - - name: Commit DIRECTORY.md - run: | - git diff DIRECTORY.md - git add DIRECTORY.md - git commit -m "updating DIRECTORY.md" || true + uses: TheAlgorithms/scripts/formatter@main + with: + filetypes: .c,.h - name: Get file changes run: | - git remote -v git branch - git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY 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 @@ -103,62 +37,37 @@ jobs: # be able to catch any errors for other platforms. run: cmake -B build -S . -DCMAKE_EXPORT_COMPILE_COMMANDS=ON - name: Lint modified files - shell: python - run: | - 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-10", "-p=build", "--fix", *cpp_files, "--"], - check=True, text=True, stderr=subprocess.STDOUT) - - subprocess.run(["clang-format-10", "-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 nodir_files: - print(f"{len(nodir_files)} files are not in one and only one directory:") - print("\n".join(nodir_files) + "\n") - - bad_files = len(upper_files + space_files + nodir_files) - if bad_files: - sys.exit(bad_files) + shell: bash + run: python3 scripts/file_linter.py - name: Commit and push changes run: | - git commit -am "clang-format and clang-tidy fixes for ${GITHUB_SHA::8}" || true - git push --force origin HEAD:$GITHUB_REF || true - + 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: [ubuntu-latest, macOS-latest] + os: [windows-latest, ubuntu-latest, macOS-latest] steps: - - uses: actions/checkout@master + - uses: actions/checkout@v3 with: submodules: true - - run: cmake -B ./build -S . - - run: cmake --build build + - 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/codeql_analysis.yml b/.github/workflows/codeql_analysis.yml deleted file mode 100644 index aa3ddbd7f7..0000000000 --- a/.github/workflows/codeql_analysis.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: "CodeQL" -on: [push, pull_request] - -jobs: - analyze: - name: Analyze - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - language: [ 'cpp' ] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more: - # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed - - steps: - - name: Checkout repository - uses: actions/checkout@main - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@main - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - - # Autobuild attempts to build any compiled languages (C/C++, C#, 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@main - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ 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@main 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 index 881ea1c337..134c04bb13 100644 --- a/.github/workflows/gh-pages.yml +++ b/.github/workflows/gh-pages.yml @@ -8,7 +8,7 @@ jobs: build: runs-on: macos-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@v3 with: submodules: true - name: Install requirements @@ -19,7 +19,7 @@ jobs: - name: build run: cmake --build build -t doc - name: gh-pages - uses: actions/checkout@master + uses: actions/checkout@v3 with: ref: "gh-pages" clean: false 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 index 59f569ad15..8b6b444d53 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ *.out .vscode/ build/ +git_diff.txt diff --git a/.gitpod.yml b/.gitpod.yml index 40750258c2..4b0332719c 100644 --- a/.gitpod.yml +++ b/.gitpod.yml @@ -7,11 +7,14 @@ github: addComment: false addCheck: false master: true + branches: true pullRequestsFromForks: true vscode: extensions: - - ms-vscode.cpptools@0.28.3:mjRj37VUK0nY2ZeDXzxOJA== - - twxs.cmake@0.0.17:9s7m9CWOr6i6NZ7CNNF4kw== - - ms-vscode.cmake-tools@1.4.0:eP3hU/MFme+CcSL21Klk1w== - - mhutchie.git-graph@1.23.0:TM9ShNmBn94aUJMJusCJlg== + # - ms-vscode.cpptools + - twxs.cmake + - ms-vscode.cmake-tools + - mhutchie.git-graph + - notskm.clang-tidy + - mitaki28.vscode-clang diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a680b18d9..01a43e6617 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,24 +1,23 @@ -cmake_minimum_required(VERSION 3.6) +cmake_minimum_required(VERSION 3.22) project(Algorithms_in_C - LANGUAGES C - VERSION 1.0.0 - DESCRIPTION "Set of algorithms implemented 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) +if (MSVC) add_compile_definitions(_CRT_SECURE_NO_WARNINGS) # add_compile_options(/Za) -endif(MSVC) +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 +# Optional flag - can be set by user # Default "ON" option(USE_OPENMP "flag to use OpenMP for multithreading" ON) if(USE_OPENMP) @@ -46,12 +45,13 @@ if (NOT HAS_INTTYPES_H) message(FATAL_ERROR "Missing required header: 'inttypes.h'") endif() -## Add subdirectories containing CMakeLists.txt +## 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) @@ -60,7 +60,11 @@ 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) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 535cbef328..c89771e8fe 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -2,75 +2,131 @@ ## Our Pledge -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, sex characteristics, gender identity and expression, -level of experience, education, socio-economic status, nationality, personal -appearance, race, religion, or sexual identity and orientation. +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 creating a positive environment -include: +Examples of behavior that contributes to a positive environment for our +community include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +* 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 by participants include: +Examples of unacceptable behavior include: -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks +* 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 electronic - address, without explicit permission +* 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 + professional setting -## Our Responsibilities +## Enforcement Responsibilities -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. +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. -Project maintainers 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, or to ban temporarily or -permanently any contributor for other behaviors 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 both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. +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 by contacting the project team at 1anuppanwar@gmail.com, dynamitechetan@gmail.com, nikhilkala8@gmail.com. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. +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. -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. +**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 1.4, -available at +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]. -[homepage]: https://www.contributor-covenant.org +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 - +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 index e1f689f1d9..01638a59c4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,83 +2,175 @@ ## 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) and clearly state your concerns. +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/developer +### Maintainer/reviewer -If you are a maintainer of this repository, please consider the following: - -- It is a protocol to contribute via pull requests. - - Reviewers will advise and guide you up to make the code refined and documented. -- When reviewing pull requests, be sure to: - - Be kind. - - Be respectful. - - Make useful suggestions/comments. - - Be sure not to make invalid suggestions/comments. - - Guide and advise up the pull request author. +**Please check the [reviewer code](https://github.com/TheAlgorithms/C/blob/master/REVIEWER_CODE.md) file for maintainers and reviewers.** ### Contributor -We are very happy that you consider implementing algorithms and data structures for others! This repository is referred to and used by learners from around the globe. Being one of our contributors, you agree and confirm that: +Being a contributor at The Algorithms, we request you to follow the points mentioned below: - You did your own work. - - No plagiarism allowed. Any plagiarized work will not be merged. + - 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. -- You submitted work fulfils or mostly fulfils our styles and standards. +- Please follow the repository guidelines and standards mentioned below. + +**New implementation** New implementations are welcome! -**New implementation** New implementation 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) -**Improving comments** and **adding tests** to existing algorithms are much appreciated. +**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. -**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. -- File extension for code should be `*.h` `*.c` -- Organize your code using **`struct`** keywords +- 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 pull requests so please be sure that your code passes before submitting. -- Please conform to [doxygen](https://www.doxygen.nl/manual/docblocks.html) standard and document the code as much as possible. This not only facilitates the readers but also generates the correct info on website. -- **Be consistent in use of these guidelines.** +- 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 things that are obvious. +- 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 contains no grammar errors. -- Do not update 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 -- 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. Sample implementation is given below. +- 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 any 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 expected output. Use `assert()` function to confirm that the tests will pass. Requires adding the `assert.h` library. +- 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 + * @brief Add one line description here. Should contain a Wikipedia + * link or another source explaining the algorithm/implementation. * @details - * This is a multi line + * This is a multi-line * description containing links, references, - * math equations, etc + * math equations, etc. * @author [Name](https://github.com/handle) * @see related_file.c, another_file.c */ -#include -#include +#include /// for assert +#include /// for `some function here` /** * @brief Struct documentation @@ -89,7 +181,7 @@ struct struct_name { }; /** - * Function documentation + * @brief Function documentation * @param param1 one-line info about param1 * @param param2 one-line info about param2 * @returns `true` if ... @@ -105,7 +197,7 @@ bool func(int param1, int param2) { } /** - * @brief Test function + * @brief Self-test implementations * @returns void */ static void test() { @@ -113,6 +205,9 @@ static void 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"); } /** @@ -120,7 +215,7 @@ static void test() { * @returns 0 on exit */ int main() { - test(); // execute the tests + test(); // run self-test implementations // code here return 0; } @@ -128,7 +223,7 @@ int main() { #### File name guidelines -- Use lowercase words with ``"_"`` as separator +- Use lowercase words with ``"_"`` as a separator - For instance ```markdown @@ -137,13 +232,13 @@ 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 the validity. -- If an implementation of the algorithm already exists and your version is different from that implemented, please use incremental numeric digit as a suffix. For example, if `median_search.c` already exists in the `search` folder and you are contributing a new implementation, the filename should be `median_search2.c` and for a third implementation, `median_search3.c`. +- 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 separator ( no spaces or ```"-"``` allowed ) +- Use lowercase words with ``"_"`` as a separator ( no spaces or ```"-"``` allowed ) - For instance ```markdown @@ -154,9 +249,45 @@ 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 spilt across multiple commits. Try to modify just one or two files in the same directory. Pull requests that span multiple directories are often rejected. +- 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 @@ -170,6 +301,7 @@ 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: @@ -178,6 +310,7 @@ Common prefixes: - 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 @@ -193,7 +326,7 @@ 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). +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 -- @@ -201,7 +334,7 @@ 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 forrmating. +[**`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` @@ -213,14 +346,14 @@ clang-tidy --fix --quiet -p build subfolder/file_to_check.c -- #### GitHub Actions - Enable GitHub Actions on your fork of the repository. -After enabling it will execute `clang-tidy` and `clang-format` after every a push (not a commit). +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 in order to avoid merge conflicts. +- Run `git pull` in your local clone if these actions made many changes to avoid merge conflicts. Most importantly, diff --git a/DIRECTORY.md b/DIRECTORY.md index da3be30425..1339bc6ffc 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -1,401 +1,361 @@ -# List of all files + +## 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 - * [Client](https://github.com/TheAlgorithms/C/blob/master/client_server/client.c) - * [Server](https://github.com/TheAlgorithms/C/blob/master/client_server/server.c) - * [Udp Client](https://github.com/TheAlgorithms/C/blob/master/client_server/udp_client.c) - * [Udp Server](https://github.com/TheAlgorithms/C/blob/master/client_server/udp_server.c) + * [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/master/conversions/binary_to_decimal.c) - * [Binary To Hexadecimal](https://github.com/TheAlgorithms/C/blob/master/conversions/binary_to_hexadecimal.c) - * [Binary To Octal](https://github.com/TheAlgorithms/C/blob/master/conversions/binary_to_octal.c) - * [C Atoi Str To Integer](https://github.com/TheAlgorithms/C/blob/master/conversions/c_atoi_str_to_integer.c) - * [Decimal To Binary](https://github.com/TheAlgorithms/C/blob/master/conversions/decimal_to_binary.c) - * [Decimal To Binary Recursion](https://github.com/TheAlgorithms/C/blob/master/conversions/decimal_to_binary_recursion.c) - * [Decimal To Hexa](https://github.com/TheAlgorithms/C/blob/master/conversions/decimal_to_hexa.c) - * [Decimal To Octal](https://github.com/TheAlgorithms/C/blob/master/conversions/decimal_to_octal.c) - * [Decimal To Octal Recursion](https://github.com/TheAlgorithms/C/blob/master/conversions/decimal_to_octal_recursion.c) - * [Hexadecimal To Octal](https://github.com/TheAlgorithms/C/blob/master/conversions/hexadecimal_to_octal.c) - * [Hexadecimal To Octal2](https://github.com/TheAlgorithms/C/blob/master/conversions/hexadecimal_to_octal2.c) - * [Infix To Postfix](https://github.com/TheAlgorithms/C/blob/master/conversions/infix_to_postfix.c) - * [Int To String](https://github.com/TheAlgorithms/C/blob/master/conversions/int_to_string.c) - * [Octal To Binary](https://github.com/TheAlgorithms/C/blob/master/conversions/octal_to_binary.c) - * [Octal To Decimal](https://github.com/TheAlgorithms/C/blob/master/conversions/octal_to_decimal.c) - * [Octal To Hexadecimal](https://github.com/TheAlgorithms/C/blob/master/conversions/octal_to_hexadecimal.c) - * [To Decimal](https://github.com/TheAlgorithms/C/blob/master/conversions/to_decimal.c) + * [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/master/data_structures/array/carray.c) - * [Carray](https://github.com/TheAlgorithms/C/blob/master/data_structures/array/carray.h) - * [Carray Tests](https://github.com/TheAlgorithms/C/blob/master/data_structures/array/carray_tests.c) + * [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/master/data_structures/binary_trees/avl_tree.c) - * [Binary Search Tree](https://github.com/TheAlgorithms/C/blob/master/data_structures/binary_trees/binary_search_tree.c) - * [Create Node](https://github.com/TheAlgorithms/C/blob/master/data_structures/binary_trees/create_node.c) - * [Recursive Traversals](https://github.com/TheAlgorithms/C/blob/master/data_structures/binary_trees/recursive_traversals.c) - * [Red Black Tree](https://github.com/TheAlgorithms/C/blob/master/data_structures/binary_trees/red_black_tree.c) - * [Segment Tree](https://github.com/TheAlgorithms/C/blob/master/data_structures/binary_trees/segment_tree.c) - * [Threaded Binary Trees](https://github.com/TheAlgorithms/C/blob/master/data_structures/binary_trees/threaded_binary_trees.c) + * [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/master/data_structures/dictionary/dict.c) - * [Dict](https://github.com/TheAlgorithms/C/blob/master/data_structures/dictionary/dict.h) - * [Test Program](https://github.com/TheAlgorithms/C/blob/master/data_structures/dictionary/test_program.c) + * [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/master/data_structures/dynamic_array/dynamic_array.c) - * [Dynamic Array](https://github.com/TheAlgorithms/C/blob/master/data_structures/dynamic_array/dynamic_array.h) - * [Main](https://github.com/TheAlgorithms/C/blob/master/data_structures/dynamic_array/main.c) + * [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/master/data_structures/graphs/bellman_ford.c) - * [Bfs](https://github.com/TheAlgorithms/C/blob/master/data_structures/graphs/bfs.c) - * [Bfs Queue](https://github.com/TheAlgorithms/C/blob/master/data_structures/graphs/bfs_queue.c) - * [Dfs](https://github.com/TheAlgorithms/C/blob/master/data_structures/graphs/dfs.c) - * [Dfs Recursive](https://github.com/TheAlgorithms/C/blob/master/data_structures/graphs/dfs_recursive.c) - * [Dijkstra](https://github.com/TheAlgorithms/C/blob/master/data_structures/graphs/dijkstra.c) - * [Euler](https://github.com/TheAlgorithms/C/blob/master/data_structures/graphs/euler.c) - * [Floyd Warshall](https://github.com/TheAlgorithms/C/blob/master/data_structures/graphs/floyd_warshall.c) - * [Graph](https://github.com/TheAlgorithms/C/blob/master/data_structures/graphs/graph.c) - * [Graph](https://github.com/TheAlgorithms/C/blob/master/data_structures/graphs/graph.h) - * [Hamiltonian](https://github.com/TheAlgorithms/C/blob/master/data_structures/graphs/hamiltonian.c) - * [Kruskal](https://github.com/TheAlgorithms/C/blob/master/data_structures/graphs/kruskal.c) - * [Queue](https://github.com/TheAlgorithms/C/blob/master/data_structures/graphs/queue.c) - * [Queue](https://github.com/TheAlgorithms/C/blob/master/data_structures/graphs/queue.h) - * [Strongly Connected Components](https://github.com/TheAlgorithms/C/blob/master/data_structures/graphs/strongly_connected_components.c) - * [Topological Sort](https://github.com/TheAlgorithms/C/blob/master/data_structures/graphs/topological_sort.c) - * [Transitive Closure](https://github.com/TheAlgorithms/C/blob/master/data_structures/graphs/transitive_closure.c) + * [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/master/data_structures/hash_set/hash_set.c) - * [Hash Set](https://github.com/TheAlgorithms/C/blob/master/data_structures/hash_set/hash_set.h) - * [Main](https://github.com/TheAlgorithms/C/blob/master/data_structures/hash_set/main.c) + * [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/master/data_structures/heap/max_heap.c) - * [Min Heap](https://github.com/TheAlgorithms/C/blob/master/data_structures/heap/min_heap.c) + * [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/master/data_structures/linked_list/ascending_priority_queue.c) - * [Circular Linked List](https://github.com/TheAlgorithms/C/blob/master/data_structures/linked_list/circular_linked_list.c) - * [Doubly Linked List](https://github.com/TheAlgorithms/C/blob/master/data_structures/linked_list/doubly_linked_list.c) - * [Merge Linked Lists](https://github.com/TheAlgorithms/C/blob/master/data_structures/linked_list/merge_linked_lists.c) - * [Middle Element In List](https://github.com/TheAlgorithms/C/blob/master/data_structures/linked_list/middle_element_in_list.c) - * [Queue Linked List](https://github.com/TheAlgorithms/C/blob/master/data_structures/linked_list/queue_linked_list.c) - * [Singly Link List Deletion](https://github.com/TheAlgorithms/C/blob/master/data_structures/linked_list/singly_link_list_deletion.c) - * [Stack Using Linked Lists](https://github.com/TheAlgorithms/C/blob/master/data_structures/linked_list/stack_using_linked_lists.c) + * [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/master/data_structures/list/list.c) - * [List](https://github.com/TheAlgorithms/C/blob/master/data_structures/list/list.h) - * [Main](https://github.com/TheAlgorithms/C/blob/master/data_structures/list/main.c) - * [Queue](https://github.com/TheAlgorithms/C/blob/master/data_structures/queue.c) - * [Stack](https://github.com/TheAlgorithms/C/blob/master/data_structures/stack.c) + * [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 - * [Main](https://github.com/TheAlgorithms/C/blob/master/data_structures/stack/main.c) - * [Parenthesis](https://github.com/TheAlgorithms/C/blob/master/data_structures/stack/parenthesis.c) - * [Stack](https://github.com/TheAlgorithms/C/blob/master/data_structures/stack/stack.c) - * [Stack](https://github.com/TheAlgorithms/C/blob/master/data_structures/stack/stack.h) + * [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/master/data_structures/stack/stack_linked_list/main.c) - * [Stack](https://github.com/TheAlgorithms/C/blob/master/data_structures/stack/stack_linked_list/stack.c) - * [Stack](https://github.com/TheAlgorithms/C/blob/master/data_structures/stack/stack_linked_list/stack.h) + * [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/master/data_structures/trie/trie.c) + * [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/master/developer_tools/malloc_dbg.c) - * [Malloc Dbg](https://github.com/TheAlgorithms/C/blob/master/developer_tools/malloc_dbg.h) - * [Min Printf](https://github.com/TheAlgorithms/C/blob/master/developer_tools/min_printf.h) - * [Test Malloc Dbg](https://github.com/TheAlgorithms/C/blob/master/developer_tools/test_malloc_dbg.c) - * [Test Min Printf](https://github.com/TheAlgorithms/C/blob/master/developer_tools/test_min_printf.c) + * [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/master/exercism/acronym/acronym.c) - * [Acronym](https://github.com/TheAlgorithms/C/blob/master/exercism/acronym/acronym.h) + * [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/master/exercism/hello_world/hello_world.c) - * [Hello World](https://github.com/TheAlgorithms/C/blob/master/exercism/hello_world/hello_world.h) + * [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/master/exercism/isogram/isogram.c) - * [Isogram](https://github.com/TheAlgorithms/C/blob/master/exercism/isogram/isogram.h) + * [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/master/exercism/rna_transcription/rna_transcription.c) - * [Rna Transcription](https://github.com/TheAlgorithms/C/blob/master/exercism/rna_transcription/rna_transcription.h) + * [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/master/exercism/word_count/word_count.c) - * [Word Count](https://github.com/TheAlgorithms/C/blob/master/exercism/word_count/word_count.h) + * [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 - * [Naval Battle](https://github.com/TheAlgorithms/C/blob/master/games/naval_battle.c) - * [Tic Tac Toe](https://github.com/TheAlgorithms/C/blob/master/games/tic_tac_toe.c) + * [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/master/geometry/geometry_datatypes.h) - * [Quaternions](https://github.com/TheAlgorithms/C/blob/master/geometry/quaternions.c) - * [Vectors 3D](https://github.com/TheAlgorithms/C/blob/master/geometry/vectors_3d.c) + * [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/master/graphics/spirograph.c) + * [Spirograph](https://github.com/TheAlgorithms/C/blob/HEAD/graphics/spirograph.c) ## Greedy Approach - * [Djikstra](https://github.com/TheAlgorithms/C/blob/master/greedy_approach/djikstra.c) - * [Prim](https://github.com/TheAlgorithms/C/blob/master/greedy_approach/prim.c) + * [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/master/hash/hash_adler32.c) - * [Hash Crc32](https://github.com/TheAlgorithms/C/blob/master/hash/hash_crc32.c) - * [Hash Djb2](https://github.com/TheAlgorithms/C/blob/master/hash/hash_djb2.c) - * [Hash Sdbm](https://github.com/TheAlgorithms/C/blob/master/hash/hash_sdbm.c) - * [Hash Xor8](https://github.com/TheAlgorithms/C/blob/master/hash/hash_xor8.c) - -## Leetcode - * Src - * [1](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/1.c) - * [101](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/101.c) - * [104](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/104.c) - * [108](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/108.c) - * [1089](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/1089.c) - * [109](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/109.c) - * [11](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/11.c) - * [110](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/110.c) - * [112](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/112.c) - * [1184](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/1184.c) - * [1189](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/1189.c) - * [12](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/12.c) - * [1207](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/1207.c) - * [121](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/121.c) - * [125](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/125.c) - * [13](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/13.c) - * [136](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/136.c) - * [141](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/141.c) - * [142](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/142.c) - * [153](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/153.c) - * [160](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/160.c) - * [169](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/169.c) - * [173](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/173.c) - * [189](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/189.c) - * [190](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/190.c) - * [191](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/191.c) - * [2](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/2.c) - * [20](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/20.c) - * [201](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/201.c) - * [203](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/203.c) - * [206](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/206.c) - * [21](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/21.c) - * [215](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/215.c) - * [217](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/217.c) - * [226](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/226.c) - * [231](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/231.c) - * [234](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/234.c) - * [24](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/24.c) - * [242](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/242.c) - * [26](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/26.c) - * [268](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/268.c) - * [27](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/27.c) - * [278](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/278.c) - * [28](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/28.c) - * [283](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/283.c) - * [287](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/287.c) - * [29](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/29.c) - * [3](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/3.c) - * [344](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/344.c) - * [35](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/35.c) - * [367](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/367.c) - * [38](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/38.c) - * [387](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/387.c) - * [389](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/389.c) - * [4](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/4.c) - * [404](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/404.c) - * [442](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/442.c) - * [461](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/461.c) - * [476](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/476.c) - * [509](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/509.c) - * [520](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/520.c) - * [53](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/53.c) - * [561](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/561.c) - * [617](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/617.c) - * [647](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/647.c) - * [66](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/66.c) - * [674](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/674.c) - * [7](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/7.c) - * [700](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/700.c) - * [701](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/701.c) - * [704](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/704.c) - * [709](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/709.c) - * [771](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/771.c) - * [8](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/8.c) - * [82](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/82.c) - * [83](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/83.c) - * [852](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/852.c) - * [876](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/876.c) - * [9](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/9.c) - * [905](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/905.c) - * [917](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/917.c) - * [938](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/938.c) - * [94](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/94.c) - * [965](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/965.c) - * [977](https://github.com/TheAlgorithms/C/blob/master/leetcode/src/977.c) + * [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/master/machine_learning/adaline_learning.c) - * [K Means Clustering](https://github.com/TheAlgorithms/C/blob/master/machine_learning/k_means_clustering.c) - * [Kohonen Som Topology](https://github.com/TheAlgorithms/C/blob/master/machine_learning/kohonen_som_topology.c) - * [Kohonen Som Trace](https://github.com/TheAlgorithms/C/blob/master/machine_learning/kohonen_som_trace.c) + * [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 - * [Armstrong Number](https://github.com/TheAlgorithms/C/blob/master/misc/armstrong_number.c) - * [Cantor Set](https://github.com/TheAlgorithms/C/blob/master/misc/cantor_set.c) - * [Cartesian To Polar](https://github.com/TheAlgorithms/C/blob/master/misc/cartesian_to_polar.c) - * [Catalan](https://github.com/TheAlgorithms/C/blob/master/misc/catalan.c) - * [Collatz](https://github.com/TheAlgorithms/C/blob/master/misc/collatz.c) - * [Demonetization](https://github.com/TheAlgorithms/C/blob/master/misc/demonetization.c) - * [Factorial](https://github.com/TheAlgorithms/C/blob/master/misc/factorial.c) - * [Factorial Large Number](https://github.com/TheAlgorithms/C/blob/master/misc/factorial_large_number.c) - * [Factorial Trailing Zeroes](https://github.com/TheAlgorithms/C/blob/master/misc/factorial_trailing_zeroes.c) - * [Fibonacci](https://github.com/TheAlgorithms/C/blob/master/misc/fibonacci.c) - * [Fibonacci Dp](https://github.com/TheAlgorithms/C/blob/master/misc/fibonacci_dp.c) - * [Fibonacci Fast](https://github.com/TheAlgorithms/C/blob/master/misc/fibonacci_fast.c) - * [Gcd](https://github.com/TheAlgorithms/C/blob/master/misc/gcd.c) - * [Is Armstrong](https://github.com/TheAlgorithms/C/blob/master/misc/is_armstrong.c) - * [Large Factorials](https://github.com/TheAlgorithms/C/blob/master/misc/large_factorials.c) - * [Lcm](https://github.com/TheAlgorithms/C/blob/master/misc/lcm.c) - * [Lerp](https://github.com/TheAlgorithms/C/blob/master/misc/lerp.c) - * [Lexicographic Permutations](https://github.com/TheAlgorithms/C/blob/master/misc/lexicographic_permutations.c) - * [Longest Subsequence](https://github.com/TheAlgorithms/C/blob/master/misc/longest_subsequence.c) - * [Mirror](https://github.com/TheAlgorithms/C/blob/master/misc/mirror.c) - * [Palindrome](https://github.com/TheAlgorithms/C/blob/master/misc/palindrome.c) - * [Pid](https://github.com/TheAlgorithms/C/blob/master/misc/pid.c) - * [Poly Add](https://github.com/TheAlgorithms/C/blob/master/misc/poly_add.c) - * [Prime](https://github.com/TheAlgorithms/C/blob/master/misc/prime.c) - * [Prime Factoriziation](https://github.com/TheAlgorithms/C/blob/master/misc/prime_factoriziation.c) - * [Prime Seive](https://github.com/TheAlgorithms/C/blob/master/misc/prime_seive.c) - * [Quartile](https://github.com/TheAlgorithms/C/blob/master/misc/quartile.c) - * [Rselect](https://github.com/TheAlgorithms/C/blob/master/misc/rselect.c) - * [Strong Number](https://github.com/TheAlgorithms/C/blob/master/misc/strong_number.c) - * [Sudoku Solver](https://github.com/TheAlgorithms/C/blob/master/misc/sudoku_solver.c) - * [Tower Of Hanoi](https://github.com/TheAlgorithms/C/blob/master/misc/tower_of_hanoi.c) - * [Union Find](https://github.com/TheAlgorithms/C/blob/master/misc/union_find.c) + * [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 - * [Durand Kerner Roots](https://github.com/TheAlgorithms/C/blob/master/numerical_methods/durand_kerner_roots.c) - * [Gauss Elimination](https://github.com/TheAlgorithms/C/blob/master/numerical_methods/gauss_elimination.c) - * [Gauss Seidel Method](https://github.com/TheAlgorithms/C/blob/master/numerical_methods/gauss_seidel_method.c) - * [Lagrange Theorem](https://github.com/TheAlgorithms/C/blob/master/numerical_methods/lagrange_theorem.c) - * [Lu Decompose](https://github.com/TheAlgorithms/C/blob/master/numerical_methods/lu_decompose.c) - * [Mean](https://github.com/TheAlgorithms/C/blob/master/numerical_methods/mean.c) - * [Median](https://github.com/TheAlgorithms/C/blob/master/numerical_methods/median.c) - * [Newton Raphson Root](https://github.com/TheAlgorithms/C/blob/master/numerical_methods/newton_raphson_root.c) - * [Ode Forward Euler](https://github.com/TheAlgorithms/C/blob/master/numerical_methods/ode_forward_euler.c) - * [Ode Midpoint Euler](https://github.com/TheAlgorithms/C/blob/master/numerical_methods/ode_midpoint_euler.c) - * [Ode Semi Implicit Euler](https://github.com/TheAlgorithms/C/blob/master/numerical_methods/ode_semi_implicit_euler.c) - * [Qr Decompose](https://github.com/TheAlgorithms/C/blob/master/numerical_methods/qr_decompose.h) - * [Qr Decomposition](https://github.com/TheAlgorithms/C/blob/master/numerical_methods/qr_decomposition.c) - * [Qr Eigen Values](https://github.com/TheAlgorithms/C/blob/master/numerical_methods/qr_eigen_values.c) - * [Realtime Stats](https://github.com/TheAlgorithms/C/blob/master/numerical_methods/realtime_stats.c) - * [Simpsons 1 3Rd Rule](https://github.com/TheAlgorithms/C/blob/master/numerical_methods/simpsons_1_3rd_rule.c) - * [Variance](https://github.com/TheAlgorithms/C/blob/master/numerical_methods/variance.c) + * [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/master/project_euler/problem_1/sol1.c) - * [Sol2](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_1/sol2.c) - * [Sol3](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_1/sol3.c) - * [Sol4](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_1/sol4.c) + * [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/master/project_euler/problem_10/sol1.c) - * [Sol2](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_10/sol2.c) + * [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/master/project_euler/problem_12/sol1.c) + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_12/sol1.c) * Problem 13 - * [Sol1](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_13/sol1.c) + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_13/sol1.c) * Problem 14 - * [Sol1](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_14/sol1.c) + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_14/sol1.c) * Problem 15 - * [Sol1](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_15/sol1.c) + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_15/sol1.c) * Problem 16 - * [Sol1](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_16/sol1.c) + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_16/sol1.c) * Problem 19 - * [Sol1](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_19/sol1.c) + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_19/sol1.c) * Problem 2 - * [So1](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_2/so1.c) + * [So1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_2/so1.c) * Problem 20 - * [Sol1](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_20/sol1.c) + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_20/sol1.c) * Problem 21 - * [Sol1](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_21/sol1.c) + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_21/sol1.c) * Problem 22 - * [Sol1](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_22/sol1.c) + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_22/sol1.c) * Problem 23 - * [Sol1](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_23/sol1.c) - * [Sol2](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_23/sol2.c) + * [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/master/project_euler/problem_25/sol1.c) + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_25/sol1.c) * Problem 26 - * [Sol1](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_26/sol1.c) + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_26/sol1.c) * Problem 3 - * [Sol1](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_3/sol1.c) - * [Sol2](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_3/sol2.c) + * [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/master/project_euler/problem_4/sol.c) + * [Sol](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_4/sol.c) * Problem 401 - * [Sol1](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_401/sol1.c) + * [Sol1](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_401/sol1.c) * Problem 5 - * [Sol1](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_5/sol1.c) - * [Sol2](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_5/sol2.c) - * [Sol3](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_5/sol3.c) + * [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/master/project_euler/problem_6/sol.c) + * [Sol](https://github.com/TheAlgorithms/C/blob/HEAD/project_euler/problem_6/sol.c) * Problem 7 - * [Sol](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_7/sol.c) - * [Sol2](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_7/sol2.c) + * [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/master/project_euler/problem_8/sol1.c) - * [Sol2](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_8/sol2.c) + * [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/master/project_euler/problem_9/sol1.c) - * [Sol2](https://github.com/TheAlgorithms/C/blob/master/project_euler/problem_9/sol2.c) + * [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/master/searching/binary_search.c) - * [Exponential Search](https://github.com/TheAlgorithms/C/blob/master/searching/exponential_search.c) - * [Fibonacci Search](https://github.com/TheAlgorithms/C/blob/master/searching/fibonacci_search.c) - * [Interpolation Search](https://github.com/TheAlgorithms/C/blob/master/searching/interpolation_search.c) - * [Jump Search](https://github.com/TheAlgorithms/C/blob/master/searching/jump_search.c) - * [Linear Search](https://github.com/TheAlgorithms/C/blob/master/searching/linear_search.c) - * [Modified Binary Search](https://github.com/TheAlgorithms/C/blob/master/searching/modified_binary_search.c) - * [Other Binary Search](https://github.com/TheAlgorithms/C/blob/master/searching/other_binary_search.c) + * [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/master/searching/pattern_search/boyer_moore_search.c) - * [Naive Search](https://github.com/TheAlgorithms/C/blob/master/searching/pattern_search/naive_search.c) - * [Rabin Karp Search](https://github.com/TheAlgorithms/C/blob/master/searching/pattern_search/rabin_karp_search.c) - * [Ternary Search](https://github.com/TheAlgorithms/C/blob/master/searching/ternary_search.c) + * [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/master/sorting/bead_sort.c) - * [Binary Insertion Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/binary_insertion_sort.c) - * [Bogo Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/bogo_sort.c) - * [Bubble Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/bubble_sort.c) - * [Bubble Sort 2](https://github.com/TheAlgorithms/C/blob/master/sorting/bubble_sort_2.c) - * [Bubble Sort Recursion](https://github.com/TheAlgorithms/C/blob/master/sorting/bubble_sort_recursion.c) - * [Bucket Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/bucket_sort.c) - * [Cocktail Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/cocktail_sort.c) - * [Comb Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/comb_sort.c) - * [Counting Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/counting_sort.c) - * [Cycle Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/cycle_sort.c) - * [Gnome Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/gnome_sort.c) - * [Heap Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/heap_sort.c) - * [Heap Sort 2](https://github.com/TheAlgorithms/C/blob/master/sorting/heap_sort_2.c) - * [Insertion Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/insertion_sort.c) - * [Insertion Sort Recursive](https://github.com/TheAlgorithms/C/blob/master/sorting/insertion_sort_recursive.c) - * [Merge Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/merge_sort.c) - * [Merge Sort Nr](https://github.com/TheAlgorithms/C/blob/master/sorting/merge_sort_nr.c) - * [Multikey Quick Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/multikey_quick_sort.c) - * [Pancake Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/pancake_sort.c) - * [Partition Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/partition_sort.c) - * [Pigeonhole Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/pigeonhole_sort.c) - * [Quick Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/quick_sort.c) - * [Radix Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/radix_sort.c) - * [Radix Sort 2](https://github.com/TheAlgorithms/C/blob/master/sorting/radix_sort_2.c) - * [Random Quick Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/random_quick_sort.c) - * [Selection Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/selection_sort.c) - * [Selection Sort Recursive](https://github.com/TheAlgorithms/C/blob/master/sorting/selection_sort_recursive.c) - * [Shaker Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/shaker_sort.c) - * [Shell Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/shell_sort.c) - * [Shell Sort2](https://github.com/TheAlgorithms/C/blob/master/sorting/shell_sort2.c) - * [Stooge Sort](https://github.com/TheAlgorithms/C/blob/master/sorting/stooge_sort.c) + * [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/LICENSE b/LICENSE index 055562a218..1e132df443 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2016-2021 TheAlgorithms and contributors +Copyright (C) 2016-2023 TheAlgorithms and contributors GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 diff --git a/README.md b/README.md index 55fdf9d84e..9670d2bb07 100644 --- a/README.md +++ b/README.md @@ -2,26 +2,26 @@ [![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/TheAlgorithms/C) -[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/TheAlgorithms/C.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/TheAlgorithms/C/context:cpp) -[![CodeQL CI](https://github.com/TheAlgorithms/C/actions/workflows/codeql_analysis.yml/badge.svg)](https://github.com/TheAlgorithms/C/actions/workflows/codeql_analysis.yml) +[![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) ## Overview -The repository is a collection of open-source implementation 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 the associated documentation are meant to provide a learning resource for educators and students. Hence, one may find more than one implementation for the same objective but using a different algorithm strategies and optimizations. +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 * 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 three major operating systems viz., Windows, MacOS and Ubuntu (Linux) using MSVC 16 2019, AppleClang 11.0 and GNU 7.5.0 respectively. +* 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. 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 index 66a6b04392..58d0aeb87c 100644 --- a/client_server/CMakeLists.txt +++ b/client_server/CMakeLists.txt @@ -1,9 +1,12 @@ +include(CheckIncludeFile) + if(WIN32) - check_include_file(winsock2.h WINSOCK_HEADER) + CHECK_INCLUDE_FILE(winsock2.h WINSOCK_HEADER) else() - check_include_file(arpa/inet.h ARPA_HEADERS) + 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 @@ -13,16 +16,21 @@ if(ARPA_HEADERS OR WINSOCK_HEADER) # 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} PRIVATE OpenMP::OpenMP_C) + string(REPLACE ".c" "" testname ${testsourcefile}) + + if(NOT WIN32) + if(${testname} STREQUAL "fork" OR ${testname} STREQUAL "bool") + continue() + endif() endif() - if(MATH_LIBRARY) + 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() - + endif () # if(HAS_UNISTD) # target_compile_definitions(${testname} PRIVATE HAS_UNISTD) # endif() @@ -32,7 +40,7 @@ if(ARPA_HEADERS OR WINSOCK_HEADER) # target_compile_definitions(${testname} PRIVATE WINSOCK_HEADER) # endif() - if(WINSOCK_HEADER) + if (WINSOCK_HEADER) target_link_libraries(${testname} PRIVATE ws2_32) # link winsock library on windows endif() 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/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/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/conversions/binary_to_decimal.c b/conversions/binary_to_decimal.c index 352d07c160..41721e5d9c 100644 --- a/conversions/binary_to_decimal.c +++ b/conversions/binary_to_decimal.c @@ -1,24 +1,68 @@ /** - * Modified 07/12/2017, Kyler Smith + * @brief Converts a number from [Binary to Decimal](https://en.wikipedia.org/wiki/Binary-coded_decimal). + * @details * - */ + * Binary to decimal conversion is a process to convert a number + * having a binary representation to its equivalent decimal representation. + * + * The base of both number systems is different. + * Binary number system is base 2 number system while decimal number system is base 10 number system. + * The numbers used in binary number system are 0 and 1 while decimal number system has numbers from 0 to 9. + * The conversion of binary number to decimal number is done by multiplying + * each digit of the binary number, starting from the rightmost digit, with the power of 2 and adding the result. + * + * @author [Anup Kumar Pawar](https://github.com/AnupKumarPanwar) + * @author [David Leal](https://github.com/Panquesito7) +*/ -#include +#include /// for IO operations +#include /// for assert +#include /// for pow +#include /// for uint64_t -int main() -{ - int remainder, number = 0, decimal_number = 0, temp = 1; - printf("\n Enter any binary number= "); - scanf("%d", &number); +/** + * @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; - // Iterate over the number until the end. - while (number > 0) - { - remainder = number % 10; + while (number > 0) { + decimal_number += (number % 10) * pow(2, i); number = number / 10; - decimal_number += remainder * temp; - temp = temp * 2; // used as power of 2 + i++; } - printf("%d\n", decimal_number); + return decimal_number; +} + +/** + * @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("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/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/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/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/data_structures/array/carray.c b/data_structures/array/carray.c index 4d75ed5411..7b812eb7ac 100644 --- a/data_structures/array/carray.c +++ b/data_structures/array/carray.c @@ -100,6 +100,8 @@ int updateValueCArray(CArray *array, int position, int value) { if (array->array[position] != 0) { + array->array[position] = value; + return SUCCESS; } else @@ -126,6 +128,7 @@ int switchValuesCArray(CArray *array, int position1, int position2) int temp = array->array[position1]; array->array[position1] = array->array[position2]; array->array[position2] = temp; + return SUCCESS; } return INVALID_POSITION; } diff --git a/data_structures/binary_trees/avl_tree.c b/data_structures/binary_trees/avl_tree.c index 67d24ae0c6..604638735d 100644 --- a/data_structures/binary_trees/avl_tree.c +++ b/data_structures/binary_trees/avl_tree.c @@ -169,12 +169,12 @@ avlNode *delete (avlNode *node, int queryNum) delete (node->right, queryNum); /*Recursive deletion in R subtree*/ else { - /*Single or No Child*/ + /*Single or No Children*/ if ((node->left == NULL) || (node->right == NULL)) { avlNode *temp = node->left ? node->left : node->right; - /* No Child*/ + /* No Children*/ if (temp == NULL) { temp = node; @@ -187,7 +187,7 @@ avlNode *delete (avlNode *node, int queryNum) } else { - /*Two Child*/ + /*Two Children*/ /*Get the smallest key in the R subtree*/ avlNode *temp = minNode(node->right); 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/dynamic_array/dynamic_array.c b/data_structures/dynamic_array/dynamic_array.c index 7ecf359ccb..19631cb1d1 100644 --- a/data_structures/dynamic_array/dynamic_array.c +++ b/data_structures/dynamic_array/dynamic_array.c @@ -18,7 +18,6 @@ void *add(dynamic_array_t *da, const void *value) { void **newItems = realloc(da->items, (da->capacity <<= 1) * sizeof(void **)); - free(da->items); da->items = newItems; } @@ -79,4 +78,4 @@ void *retrive_copy_of_value(const void *value) memcpy(value_copy, value, sizeof(void *)); return value_copy; -} \ No newline at end of file +} diff --git a/data_structures/graphs/dijkstra.c b/data_structures/graphs/dijkstra.c index b1faa47260..f15de53069 100644 --- a/data_structures/graphs/dijkstra.c +++ b/data_structures/graphs/dijkstra.c @@ -32,7 +32,8 @@ void addEdge(struct Graph *G, int src, int dst, int weight) // Utility function to find minimum distance vertex in mdist int minDistance(int mdist[], int vset[], int V) { - int minVal = INT_MAX, minInd; + 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) { diff --git a/data_structures/graphs/kruskal.c b/data_structures/graphs/kruskal.c index 49d1c54c9f..0f72c6b52f 100644 --- a/data_structures/graphs/kruskal.c +++ b/data_structures/graphs/kruskal.c @@ -27,11 +27,11 @@ struct Graph // Creates a graph with V vertices and E edges struct Graph *createGraph(int V, int E) { - struct Graph *graph = new Graph(); + struct Graph* graph = (struct Graph*)(malloc(sizeof(struct Graph))); graph->V = V; graph->E = E; - graph->edge = new Edge[E]; + graph->edge = (struct Edge*)malloc(sizeof(struct Edge) * E); return graph; } 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 index 7297217a25..6d923ae705 100644 --- a/data_structures/linked_list/circular_linked_list.c +++ b/data_structures/linked_list/circular_linked_list.c @@ -16,7 +16,7 @@ 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 BEGINING. */ +/* This function is responsible for creating the Circularly Linked List right from the BEGINNING. */ void create() { int i , n ; diff --git a/data_structures/linked_list/singly_link_list_deletion.c b/data_structures/linked_list/singly_link_list_deletion.c index 2df425ce01..f94aef54ba 100644 --- a/data_structures/linked_list/singly_link_list_deletion.c +++ b/data_structures/linked_list/singly_link_list_deletion.c @@ -4,39 +4,64 @@ when passed with a key of the node. */ #include +#include +#include struct node { int info; struct node *link; }; struct node *start = NULL; -/////////////////////////////////////////////////////////// -struct node *createnode() // function to create node +////////////////////////////////////////////////////////////////// +struct node *createnode() // function to create node { 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) + struct node *new; + new = createnode(); + new->info = d; + if (pos == 1) { - start = p; + new->link = NULL; + if (start == NULL) + { + start = new; + } + else + { + new->link = start; + start = new; + } } else { - p->link = start; - start = p; + 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; } -} -/////////////////////////////////////////////////////////// -void deletion() // function to delete from first position + return 0; + } + +/////////////////////////////////////////////////////////////////// +int deletion(int pos) // function to delete from any position { struct node *t; if (start == NULL) @@ -45,14 +70,34 @@ void deletion() // function to delete from first position } 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) @@ -69,32 +114,64 @@ void viewlist() // function to display values } } } -////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////// +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: - deletion(); - 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 index bf16ec2fab..a3c473a72c 100644 --- a/data_structures/linked_list/stack_using_linked_lists.c +++ b/data_structures/linked_list/stack_using_linked_lists.c @@ -48,7 +48,7 @@ void push(struct node *p) temp->link = top; top = temp; - printf("Inserted succesfully.\n"); + printf("Inserted successfully.\n"); } void pop(struct node *p) { diff --git a/data_structures/list/list.c b/data_structures/list/list.c index 9731acf0a8..762ffdfaad 100644 --- a/data_structures/list/list.c +++ b/data_structures/list/list.c @@ -30,13 +30,13 @@ int List_length(L list) { int n; for (n = 0; list; list = list->next) n++; - return n; + return n - 1; } /* Convert list to array */ void **List_toArray(L list) { - int i, n = List_length(list); + int i, n = List_length(list) + 1; void **array = (void **)malloc((n + 1) * sizeof(*array)); for (i = 0; i < n; i++) 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.c b/data_structures/queue/queue.c similarity index 64% rename from data_structures/queue.c rename to data_structures/queue/queue.c index 35020037d4..2b936be088 100644 --- a/data_structures/queue.c +++ b/data_structures/queue/queue.c @@ -1,36 +1,11 @@ //////////////////////////////////////////////////////////////////////////////// // INCLUDES -#include -#include - -//////////////////////////////////////////////////////////////////////////////// -// MACROS: CONSTANTS - -//////////////////////////////////////////////////////////////////////////////// -// 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; +#include "include.h"; //////////////////////////////////////////////////////////////////////////////// // GLOBAL VARIABLES int count; -//////////////////////////////////////////////////////////////////////////////// -// FORWARD DECLARATIONS -void create(); -void enque(int x); -int deque(); -int peek(); -int size(); -int isEmpty(); - //////////////////////////////////////////////////////////////////////////////// // MAIN ENTRY POINT 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 ebdabc4670..d3f20c0a93 100644 --- a/data_structures/stack/main.c +++ b/data_structures/stack/main.c @@ -1,11 +1,11 @@ // program for stack using array - #include void push(); void pop(); void peek(); void update(); +void display(); int a[100], top = -1; @@ -14,12 +14,13 @@ 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) { @@ -37,8 +38,11 @@ int main() case 4: update(); break; + case 5: + display(); + break; default: - printf("\ninvalid choice"); + printf("\nInvalid choice,\nPlease try again.\n"); } } return (0); @@ -48,7 +52,7 @@ int main() 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; @@ -59,14 +63,14 @@ 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); } } @@ -74,25 +78,40 @@ void pop() 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 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/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 787ee1f501..78ab9d9d82 100644 --- a/data_structures/trie/trie.c +++ b/data_structures/trie/trie.c @@ -3,6 +3,9 @@ /*-----character - 97 used for get the character from the ASCII value-----*/ +// needed for strnlen +#define _POSIX_C_SOURCE 200809L + #include #include #include @@ -11,177 +14,193 @@ #define ALPHABET_SIZE 26 /*--Node in the Trie--*/ -typedef struct TrieNode -{ - struct TrieNode *children[ALPHABET_SIZE]; - char character; - bool isEndOfWord; +struct trie { + struct trie *children[ALPHABET_SIZE]; + bool end_of_word; +}; -} TrieNode; -/*--Create new node--*/ -TrieNode *createTrieNode() +/*--Create new trie node--*/ +int trie_new ( + struct trie ** trie +) { - TrieNode *node; - node = malloc(sizeof(TrieNode)); - node->isEndOfWord = false; - int i = 0; - while (i < ALPHABET_SIZE) - { - node->children[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); + 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; } - else - { - root->isEndOfWord = true; + + // 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; } - return; -} -/*--Search a word in the Trie--*/ -TrieNode *search(TrieNode *root, char *word) -{ - 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; + // 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; } } - return root; + + // recurse into the child node + return trie_insert( + /* trie = */ trie->children[index], + /* word = */ word + 1, + /* word_len = */ word_len - 1 + ); } -/*---Print a word in the array--*/ -void printArray(char chars[], int len) -{ - int i; - for (i = 0; i < len; i++) - { - printf("%c", chars[i]); - } - printf("\n"); -} -/*---Return all the related words------*/ -void printPathsRecur(TrieNode *node, char prefix[], int filledLen) +/*--Search a word in the Trie--*/ +int trie_search( + struct trie * trie, + char *word, + unsigned word_len, + struct trie ** result +) { - if (node == NULL) - return; + // we found a match + if (0 == word_len) { + *result = trie; + return 0; + } - prefix[filledLen] = node->character; - filledLen++; + // same here as in trie_insert, if you have a separate index mapping, add + // it here. In this example, we just subtract 'a'. + const unsigned int index = word[0] - 'a'; - if (node->isEndOfWord) - { - printArray(prefix, filledLen); + // This word contains letters outside the alphabet length; it's invalid. + // Remember to do this to prevent buffer overflows. + if (ALPHABET_SIZE <= index) { + return -1; } - int i; - for (i = 0; i < ALPHABET_SIZE; i++) - { - printPathsRecur(node->children[i], prefix, filledLen); + // No match + if (NULL == trie->children[index]) { + return -1; } + + // traverse the trie + return trie_search( + /* trie = */ trie->children[index], + /* word = */ word + 1, + /* word_len = */ word_len - 1, + /* result = */ result + ); } -/*--Travel through the Trie and return words from it--*/ -void traverse(char prefix[], TrieNode *root) +/*---Return all the related words------*/ +void trie_print ( + struct trie * trie, + char prefix[], + unsigned prefix_len +) { - TrieNode *temp = NULL; - temp = search(root, prefix); - int j = 0; - while (prefix[j] != '\0') - { - j++; + + // 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); } - printPathsRecur(temp, prefix, j - 1); -} -/*------Demonstrate purposes uses text file called dictionary -------*/ + // However, there can be longer words with the same prefix; traverse into + // those as well. + for (int i = 0; i < ALPHABET_SIZE; i++) { -#define NUMBER_OF_WORDS (354935) -#define INPUT_WORD_SIZE (100) + // No words on this character + if (NULL == trie->children[i]) { + continue; + } -/*----Get input from the user------*/ -char *receiveInput(char *s) -{ - scanf("%99s", s); - return s; + // 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'; + + // traverse the print into the child + trie_print(trie->children[i], prefix, prefix_len + 1); + } } -int main() -{ - // Read the file dictionary - int word_count = 0; - char *words[NUMBER_OF_WORDS]; - FILE *fp = fopen("dictionary.txt", "r"); - if (fp == 0) - { - fprintf(stderr, "Error while opening dictionary file"); +/*------Demonstrate purposes uses text file called dictionary -------*/ + +int main() { + int ret = 0; + struct trie * root = NULL; + struct trie * trie = NULL; + char word[100] = {0}; + + // Create a root trie + ret = trie_new(&root); + if (-1 == ret) { + fprintf(stderr, "Could not create trie\n"); 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); + // open the dictionary file + FILE *fp = fopen("dictionary.txt", "r"); + if (NULL == fp) { + fprintf(stderr, "Error while opening dictionary file"); + exit(1); } - // Push the words in to Trie - TrieNode *root = NULL; - root = createTrieNode(); - int i; - for (i = 0; i < NUMBER_OF_WORDS; i++) - { - insert(root, words[i]); + // insert all the words from the dictionary + while (1 == fscanf(fp, "%100s\n", word)) { + ret = trie_insert(root, word, strnlen(word, 100)); + if (-1 == ret) { + fprintf(stderr, "Could not insert word into trie\n"); + exit(1); + } } - while (1) - { + while (1) { printf("Enter keyword: "); - char str[100]; - receiveInput(str); + if (1 != scanf("%100s", word)) { + break; + } + printf( "\n==========================================================\n"); printf("\n********************* Possible Words ********************\n"); - // Find the word through the Trie - traverse(str, root); + ret = trie_search(root, word, strnlen(word, 100), &trie); + if (-1 == ret) { + printf("No results\n"); + continue; + } - printf( - "\n==========================================================\n"); + trie_print(trie, word, strnlen(word, 100)); + + printf("\n==========================================================\n"); } } diff --git a/data_structures/vector.c b/data_structures/vector.c new file mode 100644 index 0000000000..ed3b930e36 --- /dev/null +++ b/data_structures/vector.c @@ -0,0 +1,168 @@ +/** + * @file + * @brief This is a vector implemenation in C. A vector is an expandable array. + * @details This vector implementation in C comes with some wrapper functions that lets the user work with data without having to worrying about memory. + */ + +#include /// 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/min_printf.h b/developer_tools/min_printf.h index 69dec7a61b..395331c18f 100644 --- a/developer_tools/min_printf.h +++ b/developer_tools/min_printf.h @@ -19,7 +19,11 @@ #define MIN_PRINTF_H #include /// for `malloc` and `free` functions -#include /// for `write` function +#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 @@ -159,7 +163,7 @@ void print_int_value(int n, int width, int precision) 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 occured + ++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'; 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/word_count/word_count.c b/exercism/word_count/word_count.c index 206a16dc6c..ac2ceea479 100644 --- a/exercism/word_count/word_count.c +++ b/exercism/word_count/word_count.c @@ -70,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.*/ @@ -88,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/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 index 6e02762cdf..ec7f540c6e 100644 --- a/games/naval_battle.c +++ b/games/naval_battle.c @@ -885,7 +885,7 @@ int main() if (plays % 2 != 0) { printMessageScore(pts1, pts2); - printMessage("Player's turn 1"); + printMessage("Player 1's turn"); printsTray(Player2, 1); scanf("%d %c", &line, &column); @@ -911,7 +911,7 @@ int main() else { printMessageScore(pts1, pts2); - printMessage("Player's turn 1"); + printMessage("Player 2's turn"); printsTray(Player1, 1); scanf("%d %c", &line, &column); diff --git a/games/tic_tac_toe.c b/games/tic_tac_toe.c index d8b2f42136..fbaf0e22be 100644 --- a/games/tic_tac_toe.c +++ b/games/tic_tac_toe.c @@ -4,8 +4,8 @@ * @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 + * @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. @@ -283,7 +283,7 @@ void place() int e = rand() % 9; - if (e >= 0 && e <= 8) + if (e >= 0) { if (game_table[e] != 'x' && game_table[e] != 'o') { 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/vectors_3d.c b/geometry/vectors_3d.c index c1ff02428a..90ea1f009b 100644 --- a/geometry/vectors_3d.c +++ b/geometry/vectors_3d.c @@ -191,6 +191,29 @@ mat_3x3 get_cross_matrix(const vec_3d *a) 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 +} + /** @} */ /** @@ -223,6 +246,10 @@ static void test() 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); } /** diff --git a/graphics/CMakeLists.txt b/graphics/CMakeLists.txt index 046160b60f..89fc65659b 100644 --- a/graphics/CMakeLists.txt +++ b/graphics/CMakeLists.txt @@ -6,9 +6,9 @@ if(OpenGL_FOUND) include(ExternalProject) ExternalProject_Add ( FREEGLUT-PRJ - URL https://sourceforge.net/projects/freeglut/files/freeglut/3.2.1/freeglut-3.2.1.tar.gz + URL https://github.com/FreeGLUTProject/freeglut/releases/download/v3.2.1/freeglut-3.2.1.tar.gz URL_MD5 cd5c670c1086358598a6d4a9d166949d - CMAKE_GENERATOR ${CMAKE_GENERATOR} --config Release + CMAKE_GENERATOR ${CMAKE_GENERATOR} CMAKE_GENERATOR_TOOLSET ${CMAKE_GENERATOR_TOOLSET} CMAKE_GENERATOR_PLATFORM ${CMAKE_GENERATOR_PLATFORM} CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release diff --git a/graphics/spirograph.c b/graphics/spirograph.c index 2a4aebc15f..2615bf7d5b 100644 --- a/graphics/spirograph.c +++ b/graphics/spirograph.c @@ -131,7 +131,7 @@ static inline void glutBitmapString(void *font, char *string) * * @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 the arrays + * @param N number of points in the arrays */ void display_graph(const double *x, const double *y, size_t N, double l, double k) diff --git a/greedy_approach/djikstra.c b/greedy_approach/dijkstra.c similarity index 100% rename from greedy_approach/djikstra.c rename to greedy_approach/dijkstra.c diff --git a/hash/README.md b/hash/README.md index 20e201edf8..90942636cf 100644 --- a/hash/README.md +++ b/hash/README.md @@ -5,3 +5,4 @@ * xor8 (8 bit) * adler_32 (32 bit) * crc32 (32 bit) +* BLAKE2b 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 index 31d0d42741..ec905dc942 100644 --- a/hash/hash_crc32.c +++ b/hash/hash_crc32.c @@ -45,10 +45,6 @@ void test_crc32() assert(crc32("Hello World!") == 472456355); assert(crc32("Hello world") == 2346098258); assert(crc32("Hello world!") == 461707669); - // printf("%" PRIu32 "\n", crc32("Hello World")); - // printf("%" PRIu32 "\n", crc32("Hello World!")); - // printf("%" PRIu32 "\n", crc32("Hello world")); - // printf("%" PRIX32 "\n", crc32("Hello world!")); printf("Tests passed\n"); } 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 index ef59a3c41e..8f938b440a 100644 --- a/leetcode/README.md +++ b/leetcode/README.md @@ -1,93 +1,69 @@ -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| -|7|[Reverse Integer](https://leetcode.com/problems/reverse-integer/) | [C](./src/7.c)|Easy| -|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| -|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| -|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|[Implement strStr()](https://leetcode.com/problems/implement-strstr/) | [C](./src/28.c)|Easy| -|29|[Divide Two Integers](https://leetcode.com/problems/divide-two-integers/) | [C](./src/29.c)|Medium| -|35|[Search Insert Position](https://leetcode.com/problems/search-insert-position/) | [C](./src/35.c)|Easy| -|38|[Count and Say](https://leetcode.com/problems/count-and-say/) | [C](./src/38.c)|Easy| -|53|[Maximum Subarray](https://leetcode.com/problems/maximum-subarray/) | [C](./src/53.c)|Easy| -|66|[Plus One](https://leetcode.com/problems/plus-one/) | [C](./src/66.c)|Easy| -|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)|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| -|121|[Best Time to Buy and Sell Stock](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/) | [C](./src/121.c)|Easy| -|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)|Easy| -|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| -|226|[Invert Binary Tree](https://leetcode.com/problems/invert-binary-tree/) | [C](./src/226.c)|Easy| -|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| -|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| -|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| -|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| -|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| -|561|[Array Partition I](https://leetcode.com/problems/array-partition-i/) | [C](./src/561.c)|Easy| -|617|[Merge Two Binary Trees](https://leetcode.com/problems/merge-two-binary-trees/) | [C](./src/617.c)|Easy| -|647|[Palindromic Substring](https://leetcode.com/problems/palindromic-substrings/) | [C](./src/647.c)|Medium| -|674|[Longest Continuous Increasing Subsequence](https://leetcode.com/problems/longest-continuous-increasing-subsequence/) | [C](./src/674.c)|Easy| -|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| -|852|[Peak Index in a Mountain Array](https://leetcode.com/problems/peak-index-in-a-mountain-array/) | [C](./src/852.c)|Easy| -|876|[Middle of the Linked List](https://leetcode.com/problems/middle-of-the-linked-list/) | [C](./src/876.c)|Easy| -|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| -|938|[Range Sum of BST](https://leetcode.com/problems/range-sum-of-bst/) | [C](./src/938.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| -|1089|[Duplicate Zeros](https://leetcode.com/problems/duplicate-zeros/) | [C](./src/1089.c)|Easy| -|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| +# 📚 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/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/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/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 0; c--) + { + ans[c] = ans[c] + ans[c-1]; + } + } + + return ans; +} 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/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/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(i // 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/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/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/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/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/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/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/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/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/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 index a2d3b1e7c6..81ea2b0454 100644 --- a/leetcode/src/231.c +++ b/leetcode/src/231.c @@ -1,7 +1,6 @@ -bool isPowerOfTwo(int n) -{ - if (!n) - return false; - while (n % 2 == 0) n /= 2; - return n == 1; -} \ No newline at end of file +// 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/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/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/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/3.c b/leetcode/src/3.c index 2acd08233d..f47cf518f3 100644 --- a/leetcode/src/3.c +++ b/leetcode/src/3.c @@ -5,8 +5,8 @@ int lengthOfLongestSubstring(char *str) if (!n) return 0; - int L_len = 1; // lenght of longest substring - int C_len = 1; // lenght of current substring + 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 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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/adaline_learning.c b/machine_learning/adaline_learning.c index f8181aa5e4..b81cccd945 100644 --- a/machine_learning/adaline_learning.c +++ b/machine_learning/adaline_learning.c @@ -240,20 +240,20 @@ void test1(double eta) } printf("------- Test 1 -------\n"); - printf("Model before fit: %s", adaline_get_weights_str(&ada)); + 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", pred); + 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", pred); + printf("Predict for x=(5, 8): % d\n", pred); assert(pred == 1); printf(" ...passed\n"); @@ -294,7 +294,7 @@ void test2(double eta) } printf("------- Test 2 -------\n"); - printf("Model before fit: %s", adaline_get_weights_str(&ada)); + 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)); @@ -309,7 +309,7 @@ void test2(double eta) 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", x0, x1, pred); + 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); @@ -362,7 +362,7 @@ void test3(double eta) } printf("------- Test 3 -------\n"); - printf("Model before fit: %s", adaline_get_weights_str(&ada)); + 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)); @@ -381,7 +381,7 @@ void test3(double eta) 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", x0, x1, pred); + 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); diff --git a/machine_learning/kohonen_som_trace.c b/machine_learning/kohonen_som_trace.c index c893bd02d2..8ca54218ba 100644 --- a/machine_learning/kohonen_som_trace.c +++ b/machine_learning/kohonen_som_trace.c @@ -6,7 +6,7 @@ * \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 this creates a chain of nodes that + * 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 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/misc/armstrong_number.c b/math/armstrong_number.c similarity index 100% rename from misc/armstrong_number.c rename to math/armstrong_number.c diff --git a/misc/cantor_set.c b/math/cantor_set.c similarity index 100% rename from misc/cantor_set.c rename to math/cantor_set.c diff --git a/misc/cartesian_to_polar.c b/math/cartesian_to_polar.c similarity index 100% rename from misc/cartesian_to_polar.c rename to math/cartesian_to_polar.c diff --git a/misc/catalan.c b/math/catalan.c similarity index 100% rename from misc/catalan.c rename to math/catalan.c diff --git a/misc/collatz.c b/math/collatz.c similarity index 100% rename from misc/collatz.c rename to math/collatz.c 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/misc/factorial.c b/math/factorial.c similarity index 100% rename from misc/factorial.c rename to math/factorial.c diff --git a/misc/factorial_large_number.c b/math/factorial_large_number.c similarity index 100% rename from misc/factorial_large_number.c rename to math/factorial_large_number.c diff --git a/misc/factorial_trailing_zeroes.c b/math/factorial_trailing_zeroes.c similarity index 100% rename from misc/factorial_trailing_zeroes.c rename to math/factorial_trailing_zeroes.c 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/misc/fibonacci_dp.c b/math/fibonacci_dp.c similarity index 100% rename from misc/fibonacci_dp.c rename to math/fibonacci_dp.c diff --git a/misc/fibonacci_fast.c b/math/fibonacci_fast.c similarity index 100% rename from misc/fibonacci_fast.c rename to math/fibonacci_fast.c 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 100% rename from misc/gcd.c rename to math/gcd.c diff --git a/misc/is_armstrong.c b/math/is_armstrong.c similarity index 100% rename from misc/is_armstrong.c rename to math/is_armstrong.c diff --git a/misc/large_factorials.c b/math/large_factorials.c similarity index 100% rename from misc/large_factorials.c rename to math/large_factorials.c diff --git a/misc/lcm.c b/math/lcm.c similarity index 100% rename from misc/lcm.c rename to math/lcm.c diff --git a/misc/lerp.c b/math/lerp.c similarity index 100% rename from misc/lerp.c rename to math/lerp.c diff --git a/misc/palindrome.c b/math/palindrome.c similarity index 100% rename from misc/palindrome.c rename to math/palindrome.c diff --git a/misc/prime.c b/math/prime.c similarity index 100% rename from misc/prime.c rename to math/prime.c diff --git a/misc/prime_factoriziation.c b/math/prime_factoriziation.c similarity index 100% rename from misc/prime_factoriziation.c rename to math/prime_factoriziation.c diff --git a/misc/prime_seive.c b/math/prime_sieve.c similarity index 96% rename from misc/prime_seive.c rename to math/prime_sieve.c index 6287bfff3c..c7a32c6502 100644 --- a/misc/prime_seive.c +++ b/math/prime_sieve.c @@ -1,6 +1,6 @@ /** * @file - * @brief [Prime Seive](https://leetcode.com/problems/count-primes/) + * @brief [Prime Sieve](https://leetcode.com/problems/count-primes/) * algorithm implementation. * @author [Divyansh Kushwaha](https://github.com/webdesignbydivyansh) */ diff --git a/misc/strong_number.c b/math/strong_number.c similarity index 100% rename from misc/strong_number.c rename to math/strong_number.c diff --git a/misc/fibonacci.c b/misc/fibonacci.c deleted file mode 100644 index 3af489624d..0000000000 --- a/misc/fibonacci.c +++ /dev/null @@ -1,23 +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/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/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/poly_add.c b/misc/poly_add.c index 53e76c3967..8280315e09 100644 --- a/misc/poly_add.c +++ b/misc/poly_add.c @@ -30,17 +30,11 @@ struct term */ void free_poly(struct term *poly) { - if (!poly) + while (poly) { - return; // NULL pointer does not need delete - } - else - { - while (!poly->next) - { - free(poly->next); // Deletes next term - } - free(poly); // delete the current term + struct term *next = poly->next; + free(poly); + poly = next; } } @@ -54,31 +48,19 @@ void free_poly(struct term *poly) void create_polynomial(struct term **poly, int coef, int pow) { // Creating the polynomial using temporary linked lists - struct term *temp1, *temp2; - temp1 = *poly; // Contains the null pointer + struct term **temp1 = poly; - // Initiating first term - if (temp1 == NULL) + while (*temp1) { - temp2 = (struct term *)malloc( - sizeof(struct term)); // Dynamic node creation - temp2->coef = coef; - temp2->pow = pow; - // Updating the null pointer with the address of the first node of the - // polynomial just created - *poly = temp2; - temp2->next = NULL; // Increasing the pointer temp2 - } - // Creating the rest of the nodes - else - { - temp2->next = (struct term *)malloc( - sizeof(struct term)); // Dynamic node creation - temp2 = temp2->next; // Increasing the pointer temp2 - temp2->coef = coef; - temp2->pow = pow; - temp2->next = NULL; + 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; } /** 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/run_length_encoding.c b/misc/run_length_encoding.c new file mode 100644 index 0000000000..59e3342fb1 --- /dev/null +++ b/misc/run_length_encoding.c @@ -0,0 +1,92 @@ +/** + * @file + * @author [serturx](https://github.com/serturx/) + * @brief Encode a null terminated string using [Run-length encoding](https://en.wikipedia.org/wiki/Run-length_encoding) + * @details + * Run-length encoding is a lossless compression algorithm. + * It works by counting the consecutive occurences symbols + * and encodes that series of consecutive symbols into the + * counted symbol and a number denoting the number of + * consecutive occorences. + * + * For example the string "AAAABBCCD" gets encoded into "4A2B2C1D" + * + */ + +#include /// 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/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/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/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/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/exponential_search.c b/searching/exponential_search.c index 7f30b4430c..efb1ec7105 100644 --- a/searching/exponential_search.c +++ b/searching/exponential_search.c @@ -3,8 +3,9 @@ * \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 assert #include /// for int64_t, uint16_t +#include /// for printf #define ELEMENT -10 @@ -81,7 +82,7 @@ int main() static void test() { // empty array - int64_t arr_empty[] = {}; + int64_t arr_empty[] = { 0 }; assert(exponential_search(arr_empty, 0, 10) == -1); // elent not found int64_t arr_found[] = {1, 2, 3}; @@ -104,4 +105,6 @@ static void test() // 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/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/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/sorting/heap_sort_2.c b/sorting/heap_sort_2.c index b93205e126..1cce1ec604 100644 --- a/sorting/heap_sort_2.c +++ b/sorting/heap_sort_2.c @@ -81,10 +81,10 @@ void heapifyDown(int8_t *arr, const uint8_t size) */ void heapifyUp(int8_t *arr, uint8_t i) { - while (i > 0 && arr[i / 2] < arr[i]) + while (i > 0 && arr[(i - 1) / 2] < arr[i]) { - swap(&arr[i / 2], &arr[i]); - i /= 2; + swap(&arr[(i - 1) / 2], &arr[i]); + i = (i - 1) / 2; } } diff --git a/sorting/merge_sort.c b/sorting/merge_sort.c index bd317ec965..ac1046f489 100644 --- a/sorting/merge_sort.c +++ b/sorting/merge_sort.c @@ -33,6 +33,11 @@ void swap(int *a, int *b) 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; @@ -68,7 +73,7 @@ void merge(int *a, int l, int r, int n) } } - for (c = l; c < r - l + 1; c++) a[c] = b[c]; + for (c = l; c < r + 1; c++) a[c] = b[c]; free(b); } @@ -101,18 +106,32 @@ void merge_sort(int *a, int n, int l, int r) 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("%d ", a[i]); } + printf("\n"); free(a); 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/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/quick_sort.c b/sorting/quick_sort.c index 6a0c8768ba..886cd0f8b1 100644 --- a/sorting/quick_sort.c +++ b/sorting/quick_sort.c @@ -93,5 +93,6 @@ int main() printf("Sorted array: "); display(arr, n); // Sorted array : 3 4 7 8 8 9 10 11 getchar(); + free(arr); return 0; } diff --git a/sorting/radix_sort_2.c b/sorting/radix_sort_2.c index 9d6cabb2f2..e527e92fba 100644 --- a/sorting/radix_sort_2.c +++ b/sorting/radix_sort_2.c @@ -22,7 +22,7 @@ void countSort(int *arr, int n, int place) int i, freq[range] = {0}; int *output = (int *)malloc(n * sizeof(int)); - // Store count of occurences in freq[] + // 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