diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0a19890aed44..9a0617e18a06 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1 @@ -* @yanglbme @vil02 @BamaCharanChhandogi @alxkm @siriak +* @DenizAltunkapan @yanglbme @vil02 @alxkm diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b3969075d668..3918e89533d5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,9 @@ name: Build on: [push, pull_request] +permissions: + contents: read + jobs: build: runs-on: ubuntu-latest diff --git a/.github/workflows/clang-format-lint.yml b/.github/workflows/clang-format-lint.yml index 588c05e42e8f..6f23946db999 100644 --- a/.github/workflows/clang-format-lint.yml +++ b/.github/workflows/clang-format-lint.yml @@ -3,13 +3,16 @@ on: push: {} pull_request: {} +permissions: + contents: read + jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: DoozyX/clang-format-lint-action@v0.18 + - uses: DoozyX/clang-format-lint-action@v0.20 with: source: './src' extensions: 'java' diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index a0908a2b57d9..d1133c251b65 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -10,12 +10,9 @@ on: schedule: - cron: '53 3 * * 0' -env: - LANGUAGE: 'java-kotlin' - jobs: - analyze: - name: Analyze + analyzeJava: + name: AnalyzeJava runs-on: 'ubuntu-latest' permissions: actions: read @@ -35,7 +32,7 @@ jobs: - name: Initialize CodeQL uses: github/codeql-action/init@v3 with: - languages: ${{ env.LANGUAGE }} + languages: 'java-kotlin' - name: Build run: mvn --batch-mode --update-snapshots verify @@ -43,5 +40,27 @@ jobs: - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v3 with: - category: "/language:${{env.LANGUAGE}}" + category: "/language:java-kotlin" + + analyzeActions: + name: AnalyzeActions + runs-on: 'ubuntu-latest' + permissions: + actions: read + contents: read + security-events: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: 'actions' + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:actions" ... diff --git a/.github/workflows/infer.yml b/.github/workflows/infer.yml index a07c6f458083..b0ee2fee8243 100644 --- a/.github/workflows/infer.yml +++ b/.github/workflows/infer.yml @@ -8,6 +8,9 @@ name: Infer - master pull_request: +permissions: + contents: read + jobs: run_infer: runs-on: ubuntu-latest @@ -41,6 +44,7 @@ jobs: cd .. git clone https://github.com/facebook/infer.git cd infer + git checkout 01aaa268f9d38723ba69c139e10f9e2a04b40b1c ./build-infer.sh java cp -r infer ../Java diff --git a/.github/workflows/project_structure.yml b/.github/workflows/project_structure.yml new file mode 100644 index 000000000000..dbc725655721 --- /dev/null +++ b/.github/workflows/project_structure.yml @@ -0,0 +1,25 @@ +--- +name: ProjectStructure + +'on': + workflow_dispatch: + push: + branches: + - master + pull_request: + +permissions: + contents: read + +jobs: + check_structure: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.13' + + - name: Check project structure + run: python3 .github/workflows/scripts/check_structure.py +... diff --git a/.github/workflows/scripts/check_structure.py b/.github/workflows/scripts/check_structure.py new file mode 100644 index 000000000000..914f64369207 --- /dev/null +++ b/.github/workflows/scripts/check_structure.py @@ -0,0 +1,27 @@ +import pathlib +import sys + + +def _is_java_file_properly_located(java_file: pathlib.Path) -> bool: + main_parents = java_file.parent.parents + return ( + pathlib.Path("src/main/java/com/thealgorithms/") in main_parents + or pathlib.Path("src/test/java/com/thealgorithms/") in main_parents + ) + + +def _find_misplaced_java_files() -> list[pathlib.Path]: + return [ + java_file + for java_file in pathlib.Path(".").rglob("*.java") + if not _is_java_file_properly_located(java_file) + ] + + +if __name__ == "__main__": + misplaced_files = _find_misplaced_java_files() + if misplaced_files: + print("The following java files are not located in the correct directory:") + for _ in misplaced_files: + print(_) + sys.exit(1) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 6fb47c5d2dc9..186b3e1d2f5a 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -2,8 +2,13 @@ name: 'Close stale issues and PRs' on: schedule: - cron: '0 0 * * *' +permissions: + contents: read jobs: stale: + permissions: + issues: write + pull-requests: write runs-on: ubuntu-latest steps: - uses: actions/stale@v9 diff --git a/.github/workflows/update-directorymd.yml b/.github/workflows/update-directorymd.yml new file mode 100644 index 000000000000..53ad221e7742 --- /dev/null +++ b/.github/workflows/update-directorymd.yml @@ -0,0 +1,42 @@ +name: Generate Directory Markdown + +on: + push: + branches: [master] + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + generate-directory: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Run Directory Tree Generator + uses: DenizAltunkapan/directory-tree-generator@v2 + with: + path: src + extensions: .java + show-extensions: false + + - name: Commit changes + run: | + git config --global user.name "$GITHUB_ACTOR" + git config --global user.email "$GITHUB_ACTOR@users.noreply.github.com" + git add DIRECTORY.md + git diff --cached --quiet || git commit -m "Update DIRECTORY.md" + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.REPO_SCOPED_TOKEN }} + branch: update-directory + base: master + title: "Update DIRECTORY.md" + body: "Automatically generated update of the directory tree." + commit-message: "Update DIRECTORY.md" + draft: false diff --git a/.github/workflows/update_directory.yml b/.github/workflows/update_directory.yml deleted file mode 100644 index c811d244e54b..000000000000 --- a/.github/workflows/update_directory.yml +++ /dev/null @@ -1,92 +0,0 @@ -# This GitHub Action updates the DIRECTORY.md file (if needed) when doing a git push or pull_request -name: Update Directory -permissions: - contents: write -on: - push: - paths: - - 'src/**' - pull_request: - paths: - - 'src/**' - workflow_dispatch: - inputs: - logLevel: - description: 'Log level' - required: true - default: 'info' - type: choice - options: - - info - - warning - - debug -jobs: - update_directory_md: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - uses: actions/setup-python@v5 - with: - python-version: '3.x' - - name: Update Directory - shell: python - run: | - import os - from typing import Iterator - - URL_BASE = "https://github.com/TheAlgorithms/Java/blob/master" - g_output = [] - - - def good_filepaths(top_dir: str = ".") -> Iterator[str]: - 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() == ".java": - 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) - mid_diff = False - new_parts = new_path.split(os.sep) - for i, new_part in enumerate(new_parts): - if i + 1 > len(old_parts) or old_parts[i] != new_part or mid_diff: - if i + 1 < len(new_parts): - mid_diff = True - if new_part: - g_output.append(f"{md_prefix(i)} {new_part.replace('_', ' ')}") - return new_path - - - def build_directory_md(top_dir: str = ".") -> str: - global g_output - old_path = "" - for filepath in sorted(good_filepaths(top_dir), 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("_", " "))[0] - g_output.append(f"{md_prefix(indent)} [{filename}]({url})") - return "\n".join(g_output) - - - with open("DIRECTORY.md", "w") as out_file: - out_file.write(build_directory_md(".") + "\n") - - - name: Update DIRECTORY.md - run: | - cat DIRECTORY.md - git config --global user.name "$GITHUB_ACTOR" - git config --global user.email "$GITHUB_ACTOR@users.noreply.github.com" - git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY - git add DIRECTORY.md - git commit -am "Update directory" || true - git push --force origin HEAD:$GITHUB_REF || true diff --git a/.gitpod.dockerfile b/.gitpod.dockerfile index 4b1885ffa388..b912ecb35256 100644 --- a/.gitpod.dockerfile +++ b/.gitpod.dockerfile @@ -1,4 +1,4 @@ -FROM gitpod/workspace-java-21:2024-11-26-08-43-19 +FROM gitpod/workspace-java-21:2025-06-18-16-47-14 ENV LLVM_SCRIPT="tmp_llvm.sh" diff --git a/DIRECTORY.md b/DIRECTORY.md index 01e031b58581..71d4b7d013cb 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -1,1348 +1,1420 @@ +# Project Structure ## src - * main - * java - * com - * thealgorithms - * audiofilters - * [IIRFilter](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/audiofilters/IIRFilter.java) - * backtracking - * [AllPathsFromSourceToTarget](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java) - * [ArrayCombination](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java) - * [Combination](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/Combination.java) - * [CrosswordSolver](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/CrosswordSolver.java) - * [FloodFill](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/FloodFill.java) - * [KnightsTour](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/KnightsTour.java) - * [MazeRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/MazeRecursion.java) - * [MColoring](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/MColoring.java) - * [NQueens](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/NQueens.java) - * [ParenthesesGenerator](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/ParenthesesGenerator.java) - * [Permutation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/Permutation.java) - * [PowerSum](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/PowerSum.java) - * [SubsequenceFinder](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/SubsequenceFinder.java) - * [WordPatternMatcher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/WordPatternMatcher.java) - * [WordSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/backtracking/WordSearch.java) - * bitmanipulation - * [BcdConversion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/BcdConversion.java) - * [BinaryPalindromeCheck](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheck.java) - * [BitSwap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java) - * [BooleanAlgebraGates](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGates.java) - * [ClearLeftmostSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBit.java) - * [CountLeadingZeros](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/CountLeadingZeros.java) - * [CountSetBits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java) - * [FindNthBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/FindNthBit.java) - * [FirstDifferentBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/FirstDifferentBit.java) - * [GenerateSubsets](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/GenerateSubsets.java) - * [GrayCodeConversion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/GrayCodeConversion.java) - * [HammingDistance](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/HammingDistance.java) - * [HigherLowerPowerOfTwo](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwo.java) - * [HighestSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/HighestSetBit.java) - * [IndexOfRightMostSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBit.java) - * [IsEven](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/IsEven.java) - * [IsPowerTwo](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/IsPowerTwo.java) - * [LowestSetBit](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/LowestSetBit.java) - * [ModuloPowerOfTwo](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/ModuloPowerOfTwo.java) - * [NextHigherSameBitCount](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/NextHigherSameBitCount.java) - * [NonRepeatingNumberFinder](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/NonRepeatingNumberFinder.java) - * [NumberAppearingOddTimes](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimes.java) - * [NumbersDifferentSigns](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/NumbersDifferentSigns.java) - * [OneBitDifference](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/OneBitDifference.java) - * [OnesComplement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java) - * [ParityCheck](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/ParityCheck.java) - * [ReverseBits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/ReverseBits.java) - * [SingleBitOperations](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/SingleBitOperations.java) - * [SingleElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/SingleElement.java) - * [SwapAdjacentBits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/SwapAdjacentBits.java) - * [TwosComplement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java) - * [Xs3Conversion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/bitmanipulation/Xs3Conversion.java) - * ciphers - * a5 - * [A5Cipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/a5/A5Cipher.java) - * [A5KeyStreamGenerator](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/a5/A5KeyStreamGenerator.java) - * [BaseLFSR](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/a5/BaseLFSR.java) - * [CompositeLFSR](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/a5/CompositeLFSR.java) - * [LFSR](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/a5/LFSR.java) - * [Utils](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/a5/Utils.java) - * [ADFGVXCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/ADFGVXCipher.java) - * [AES](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/AES.java) - * [AESEncryption](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/AESEncryption.java) - * [AffineCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/AffineCipher.java) - * [AtbashCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/AtbashCipher.java) - * [Autokey](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Autokey.java) - * [BaconianCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/BaconianCipher.java) - * [Blowfish](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Blowfish.java) - * [Caesar](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Caesar.java) - * [ColumnarTranspositionCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/ColumnarTranspositionCipher.java) - * [DES](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/DES.java) - * [DiffieHellman](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/DiffieHellman.java) - * [ECC](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/ECC.java) - * [HillCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/HillCipher.java) - * [MonoAlphabetic](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/MonoAlphabetic.java) - * [PlayfairCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/PlayfairCipher.java) - * [Polybius](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Polybius.java) - * [ProductCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/ProductCipher.java) - * [RailFenceCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/RailFenceCipher.java) - * [RSA](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/RSA.java) - * [SimpleSubCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/SimpleSubCipher.java) - * [Vigenere](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Vigenere.java) - * [XORCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/XORCipher.java) - * conversions - * [AffineConverter](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/AffineConverter.java) - * [AnyBaseToAnyBase](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/AnyBaseToAnyBase.java) - * [AnyBaseToDecimal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/AnyBaseToDecimal.java) - * [AnytoAny](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/AnytoAny.java) - * [BinaryToDecimal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/BinaryToDecimal.java) - * [BinaryToHexadecimal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/BinaryToHexadecimal.java) - * [BinaryToOctal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/BinaryToOctal.java) - * [DecimalToAnyBase](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/DecimalToAnyBase.java) - * [DecimalToBinary](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/DecimalToBinary.java) - * [DecimalToHexadecimal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/DecimalToHexadecimal.java) - * [DecimalToOctal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/DecimalToOctal.java) - * [EndianConverter](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/EndianConverter.java) - * [HexaDecimalToBinary](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/HexaDecimalToBinary.java) - * [HexaDecimalToDecimal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/HexaDecimalToDecimal.java) - * [HexToOct](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/HexToOct.java) - * [IntegerToEnglish](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/IntegerToEnglish.java) - * [IntegerToRoman](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/IntegerToRoman.java) - * [IPConverter](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/IPConverter.java) - * [IPv6Converter](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/IPv6Converter.java) - * [MorseCodeConverter](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/MorseCodeConverter.java) - * [OctalToBinary](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/OctalToBinary.java) - * [OctalToDecimal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/OctalToDecimal.java) - * [OctalToHexadecimal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/OctalToHexadecimal.java) - * [PhoneticAlphabetConverter](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/PhoneticAlphabetConverter.java) - * [RgbHsvConversion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/RgbHsvConversion.java) - * [RomanToInteger](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/RomanToInteger.java) - * [TurkishToLatinConversion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java) - * [UnitConversions](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/UnitConversions.java) - * [UnitsConverter](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/conversions/UnitsConverter.java) - * datastructures - * bags - * [Bag](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/bags/Bag.java) - * bloomfilter - * [BloomFilter](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/bloomfilter/BloomFilter.java) - * buffers - * [CircularBuffer](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/buffers/CircularBuffer.java) - * caches - * [LFUCache](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/caches/LFUCache.java) - * [LRUCache](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/caches/LRUCache.java) - * [MRUCache](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/caches/MRUCache.java) - * crdt - * [GCounter](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/crdt/GCounter.java) - * [GSet](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/crdt/GSet.java) - * [LWWElementSet](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java) - * [ORSet](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/crdt/ORSet.java) - * [PNCounter](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/crdt/PNCounter.java) - * [TwoPSet](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/crdt/TwoPSet.java) - * disjointsetunion - * [DisjointSetUnion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnion.java) - * [Node](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/disjointsetunion/Node.java) - * dynamicarray - * [DynamicArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/dynamicarray/DynamicArray.java) - * graphs - * [AStar](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/AStar.java) - * [BellmanFord](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/BellmanFord.java) - * [BipartiteGraphDFS](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/BipartiteGraphDFS.java) - * [BoruvkaAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/BoruvkaAlgorithm.java) - * [ConnectedComponent](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/ConnectedComponent.java) - * [Cycles](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/Cycles.java) - * [DijkstraAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithm.java) - * [EdmondsBlossomAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java) - * [FloydWarshall](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/FloydWarshall.java) - * [FordFulkerson](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/FordFulkerson.java) - * [Graphs](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/Graphs.java) - * [HamiltonianCycle](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/HamiltonianCycle.java) - * [JohnsonsAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithm.java) - * [KahnsAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/KahnsAlgorithm.java) - * [Kosaraju](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/Kosaraju.java) - * [Kruskal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/Kruskal.java) - * [MatrixGraphs](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/MatrixGraphs.java) - * [PrimMST](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/PrimMST.java) - * [TarjansAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/TarjansAlgorithm.java) - * [WelshPowell](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/WelshPowell.java) - * hashmap - * hashing - * [GenericHashMapUsingArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java) - * [GenericHashMapUsingArrayList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayList.java) - * [HashMap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/HashMap.java) - * [HashMapCuckooHashing](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/HashMapCuckooHashing.java) - * [Intersection](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/Intersection.java) - * [LinearProbingHashMap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMap.java) - * [MainCuckooHashing](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/MainCuckooHashing.java) - * [MajorityElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/MajorityElement.java) - * [Map](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/Map.java) - * heaps - * [EmptyHeapException](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/heaps/EmptyHeapException.java) - * [FibonacciHeap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/heaps/FibonacciHeap.java) - * [GenericHeap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/heaps/GenericHeap.java) - * [Heap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/heaps/Heap.java) - * [HeapElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/heaps/HeapElement.java) - * [KthElementFinder](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/heaps/KthElementFinder.java) - * [LeftistHeap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/heaps/LeftistHeap.java) - * [MaxHeap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/heaps/MaxHeap.java) - * [MedianFinder](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/heaps/MedianFinder.java) - * [MergeKSortedArrays](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/heaps/MergeKSortedArrays.java) - * [MinHeap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/heaps/MinHeap.java) - * [MinPriorityQueue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/heaps/MinPriorityQueue.java) - * lists - * [CircleLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java) - * [CountSinglyLinkedListRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/CountSinglyLinkedListRecursion.java) - * [CreateAndDetectLoop](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/CreateAndDetectLoop.java) - * [CursorLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/CursorLinkedList.java) - * [DoublyLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/DoublyLinkedList.java) - * [MergeKSortedLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/MergeKSortedLinkedList.java) - * [MergeSortedArrayList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/MergeSortedArrayList.java) - * [MergeSortedSinglyLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/MergeSortedSinglyLinkedList.java) - * [QuickSortLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/QuickSortLinkedList.java) - * [RandomNode](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/RandomNode.java) - * [ReverseKGroup](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/ReverseKGroup.java) - * [RotateSinglyLinkedLists](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/RotateSinglyLinkedLists.java) - * [SearchSinglyLinkedListRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/SearchSinglyLinkedListRecursion.java) - * [SinglyLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/SinglyLinkedList.java) - * [SkipList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/SkipList.java) - * [SortedLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/lists/SortedLinkedList.java) - * [Node](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/Node.java) - * queues - * [CircularQueue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/CircularQueue.java) - * [Deque](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/Deque.java) - * [GenericArrayListQueue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/GenericArrayListQueue.java) - * [LinkedQueue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/LinkedQueue.java) - * [PriorityQueues](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/PriorityQueues.java) - * [Queue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/Queue.java) - * [QueueByTwoStacks](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/QueueByTwoStacks.java) - * [SlidingWindowMaximum](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/SlidingWindowMaximum.java) - * [TokenBucket](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/queues/TokenBucket.java) - * stacks - * [NodeStack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/NodeStack.java) - * [ReverseStack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/ReverseStack.java) - * [Stack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/Stack.java) - * [StackArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/StackArray.java) - * [StackArrayList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/StackArrayList.java) - * [StackOfLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/stacks/StackOfLinkedList.java) - * trees - * [AVLSimple](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java) - * [AVLTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/AVLTree.java) - * [BinaryTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/BinaryTree.java) - * [BoundaryTraversal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java) - * [BSTFromSortedArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/BSTFromSortedArray.java) - * [BSTIterative](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/BSTIterative.java) - * [BSTRecursive](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/BSTRecursive.java) - * [BSTRecursiveGeneric](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java) - * [CeilInBinarySearchTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTree.java) - * [CheckBinaryTreeIsValidBST](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/CheckBinaryTreeIsValidBST.java) - * [CheckIfBinaryTreeBalanced](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/CheckIfBinaryTreeBalanced.java) - * [CheckTreeIsSymmetric](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/CheckTreeIsSymmetric.java) - * [CreateBinaryTreeFromInorderPreorder](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/CreateBinaryTreeFromInorderPreorder.java) - * [FenwickTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/FenwickTree.java) - * [GenericTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/GenericTree.java) - * [InorderTraversal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/InorderTraversal.java) - * [KDTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/KDTree.java) - * [LazySegmentTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/LazySegmentTree.java) - * [LCA](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/LCA.java) - * [LevelOrderTraversal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/LevelOrderTraversal.java) - * [nearestRightKey](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/nearestRightKey.java) - * [PostOrderTraversal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/PostOrderTraversal.java) - * [PreOrderTraversal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/PreOrderTraversal.java) - * [PrintTopViewofTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/PrintTopViewofTree.java) - * [QuadTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java) - * [RedBlackBST](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/RedBlackBST.java) - * [SameTreesCheck](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/SameTreesCheck.java) - * [SegmentTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/SegmentTree.java) - * [SplayTree](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/SplayTree.java) - * [Treap](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/Treap.java) - * [TreeRandomNode](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/TreeRandomNode.java) - * [Trie](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/Trie.java) - * [VerticalOrderTraversal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/VerticalOrderTraversal.java) - * [ZigzagTraversal](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/trees/ZigzagTraversal.java) - * devutils - * entities - * [ProcessDetails](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/devutils/entities/ProcessDetails.java) - * nodes - * [LargeTreeNode](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/devutils/nodes/LargeTreeNode.java) - * [Node](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/devutils/nodes/Node.java) - * [SimpleNode](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/devutils/nodes/SimpleNode.java) - * [SimpleTreeNode](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/devutils/nodes/SimpleTreeNode.java) - * [TreeNode](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/devutils/nodes/TreeNode.java) - * searches - * [MatrixSearchAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/devutils/searches/MatrixSearchAlgorithm.java) - * [SearchAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/devutils/searches/SearchAlgorithm.java) - * divideandconquer - * [BinaryExponentiation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/BinaryExponentiation.java) - * [ClosestPair](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java) - * [CountingInversions](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/CountingInversions.java) - * [MedianOfTwoSortedArrays](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArrays.java) - * [SkylineAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java) - * [StrassenMatrixMultiplication](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplication.java) - * [TilingProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/divideandconquer/TilingProblem.java) - * dynamicprogramming - * [Abbreviation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/Abbreviation.java) - * [AllConstruct](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/AllConstruct.java) - * [AssignmentUsingBitmask](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/AssignmentUsingBitmask.java) - * [BoardPath](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/BoardPath.java) - * [BoundaryFill](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java) - * [BruteForceKnapsack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/BruteForceKnapsack.java) - * [CatalanNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/CatalanNumber.java) - * [ClimbingStairs](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/ClimbingStairs.java) - * [CoinChange](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/CoinChange.java) - * [CountFriendsPairing](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/CountFriendsPairing.java) - * [DiceThrow](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/DiceThrow.java) - * [EditDistance](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/EditDistance.java) - * [EggDropping](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/EggDropping.java) - * [Fibonacci](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/Fibonacci.java) - * [KadaneAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/KadaneAlgorithm.java) - * [Knapsack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/Knapsack.java) - * [KnapsackMemoization](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/KnapsackMemoization.java) - * [LevenshteinDistance](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/LevenshteinDistance.java) - * [LongestAlternatingSubsequence](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/LongestAlternatingSubsequence.java) - * [LongestArithmeticSubsequence](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequence.java) - * [LongestCommonSubsequence](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequence.java) - * [LongestIncreasingSubsequence](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequence.java) - * [LongestPalindromicSubsequence](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubsequence.java) - * [LongestPalindromicSubstring](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubstring.java) - * [LongestValidParentheses](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/LongestValidParentheses.java) - * [MatrixChainMultiplication](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplication.java) - * [MatrixChainRecursiveTopDownMemoisation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainRecursiveTopDownMemoisation.java) - * [MaximumSumOfNonAdjacentElements](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/MaximumSumOfNonAdjacentElements.java) - * [MinimumPathSum](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/MinimumPathSum.java) - * [MinimumSumPartition](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/MinimumSumPartition.java) - * [NewManShanksPrime](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/NewManShanksPrime.java) - * [OptimalJobScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/OptimalJobScheduling.java) - * [PalindromicPartitioning](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/PalindromicPartitioning.java) - * [PartitionProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/PartitionProblem.java) - * [RegexMatching](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/RegexMatching.java) - * [RodCutting](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/RodCutting.java) - * [ShortestCommonSupersequenceLength](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/ShortestCommonSupersequenceLength.java) - * [SubsetCount](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/SubsetCount.java) - * [SubsetSum](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/SubsetSum.java) - * [SubsetSumSpaceOptimized](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimized.java) - * [SumOfSubset](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/SumOfSubset.java) - * [Tribonacci](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/Tribonacci.java) - * [UniquePaths](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/UniquePaths.java) - * [UniqueSubsequencesCount](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCount.java) - * [WildcardMatching](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/WildcardMatching.java) - * [WineProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/dynamicprogramming/WineProblem.java) - * geometry - * [BresenhamLine](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/geometry/BresenhamLine.java) - * [ConvexHull](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/geometry/ConvexHull.java) - * [GrahamScan](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/geometry/GrahamScan.java) - * [MidpointCircle](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/geometry/MidpointCircle.java) - * [MidpointEllipse](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/geometry/MidpointEllipse.java) - * [Point](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/geometry/Point.java) - * graph - * [StronglyConnectedComponentOptimized](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/graph/StronglyConnectedComponentOptimized.java) - * greedyalgorithms - * [ActivitySelection](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/ActivitySelection.java) - * [BandwidthAllocation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/BandwidthAllocation.java) - * [BinaryAddition](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/BinaryAddition.java) - * [CoinChange](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/CoinChange.java) - * [DigitSeparation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/DigitSeparation.java) - * [EgyptianFraction](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/EgyptianFraction.java) - * [FractionalKnapsack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/FractionalKnapsack.java) - * [GaleShapley](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/GaleShapley.java) - * [JobSequencing](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/JobSequencing.java) - * [KCenters](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/KCenters.java) - * [MergeIntervals](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/MergeIntervals.java) - * [MinimizingLateness](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/MinimizingLateness.java) - * [MinimumWaitingTime](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/MinimumWaitingTime.java) - * [OptimalFileMerging](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/OptimalFileMerging.java) - * [StockProfitCalculator](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/greedyalgorithms/StockProfitCalculator.java) - * io - * [BufferedReader](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/io/BufferedReader.java) - * lineclipping - * [CohenSutherland](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/lineclipping/CohenSutherland.java) - * [LiangBarsky](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/lineclipping/LiangBarsky.java) - * utils - * [Line](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/lineclipping/utils/Line.java) - * [Point](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/lineclipping/utils/Point.java) - * maths - * [AbsoluteMax](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/AbsoluteMax.java) - * [AbsoluteMin](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/AbsoluteMin.java) - * [AbsoluteValue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/AbsoluteValue.java) - * [ADTFraction](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/ADTFraction.java) - * [AliquotSum](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/AliquotSum.java) - * [AmicableNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/AmicableNumber.java) - * [Area](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Area.java) - * [Armstrong](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Armstrong.java) - * [AutoCorrelation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/AutoCorrelation.java) - * [AutomorphicNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/AutomorphicNumber.java) - * [Average](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Average.java) - * [BinaryPow](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/BinaryPow.java) - * [BinomialCoefficient](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/BinomialCoefficient.java) - * [CatalanNumbers](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/CatalanNumbers.java) - * [Ceil](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Ceil.java) - * [ChineseRemainderTheorem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/ChineseRemainderTheorem.java) - * [CircularConvolutionFFT](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/CircularConvolutionFFT.java) - * [CollatzConjecture](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/CollatzConjecture.java) - * [Combinations](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Combinations.java) - * [Convolution](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Convolution.java) - * [ConvolutionFFT](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/ConvolutionFFT.java) - * [CrossCorrelation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/CrossCorrelation.java) - * [DeterminantOfMatrix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/DeterminantOfMatrix.java) - * [DigitalRoot](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/DigitalRoot.java) - * [DistanceFormula](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/DistanceFormula.java) - * [DudeneyNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/DudeneyNumber.java) - * [EulerMethod](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/EulerMethod.java) - * [EulersFunction](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/EulersFunction.java) - * [Factorial](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Factorial.java) - * [FactorialRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FactorialRecursion.java) - * [FastExponentiation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FastExponentiation.java) - * [FastInverseSqrt](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FastInverseSqrt.java) - * [FFT](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FFT.java) - * [FFTBluestein](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FFTBluestein.java) - * [FibonacciJavaStreams](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FibonacciJavaStreams.java) - * [FibonacciLoop](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FibonacciLoop.java) - * [FibonacciNumberCheck](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FibonacciNumberCheck.java) - * [FibonacciNumberGoldenRation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FibonacciNumberGoldenRation.java) - * [FindKthNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FindKthNumber.java) - * [FindMax](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FindMax.java) - * [FindMaxRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FindMaxRecursion.java) - * [FindMin](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FindMin.java) - * [FindMinRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FindMinRecursion.java) - * [Floor](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Floor.java) - * [FrizzyNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/FrizzyNumber.java) - * [Gaussian](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Gaussian.java) - * [GCD](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/GCD.java) - * [GCDRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/GCDRecursion.java) - * [GenericRoot](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/GenericRoot.java) - * [HarshadNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/HarshadNumber.java) - * [HeronsFormula](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/HeronsFormula.java) - * [JosephusProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/JosephusProblem.java) - * [JugglerSequence](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/JugglerSequence.java) - * [KaprekarNumbers](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/KaprekarNumbers.java) - * [KaratsubaMultiplication](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/KaratsubaMultiplication.java) - * [KeithNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/KeithNumber.java) - * [KrishnamurthyNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/KrishnamurthyNumber.java) - * [LeastCommonMultiple](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/LeastCommonMultiple.java) - * [LeonardoNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/LeonardoNumber.java) - * [LinearDiophantineEquationsSolver](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/LinearDiophantineEquationsSolver.java) - * [LiouvilleLambdaFunction](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/LiouvilleLambdaFunction.java) - * [LongDivision](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/LongDivision.java) - * [LucasSeries](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/LucasSeries.java) - * [MagicSquare](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/MagicSquare.java) - * [MatrixRank](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/MatrixRank.java) - * [MatrixUtil](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/MatrixUtil.java) - * [MaxValue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/MaxValue.java) - * [Means](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Means.java) - * [Median](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Median.java) - * [MillerRabinPrimalityCheck](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/MillerRabinPrimalityCheck.java) - * [MinValue](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/MinValue.java) - * [MobiusFunction](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/MobiusFunction.java) - * [Mode](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Mode.java) - * [NonRepeatingElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/NonRepeatingElement.java) - * [NthUglyNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/NthUglyNumber.java) - * [NumberOfDigits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/NumberOfDigits.java) - * [PalindromeNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PalindromeNumber.java) - * [ParseInteger](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/ParseInteger.java) - * [PascalTriangle](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PascalTriangle.java) - * [PerfectCube](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PerfectCube.java) - * [PerfectNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PerfectNumber.java) - * [PerfectSquare](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PerfectSquare.java) - * [Perimeter](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Perimeter.java) - * [PiNilakantha](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PiNilakantha.java) - * [PollardRho](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PollardRho.java) - * [Pow](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Pow.java) - * [PowerOfTwoOrNot](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PowerOfTwoOrNot.java) - * [PowerUsingRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PowerUsingRecursion.java) - * [PrimeCheck](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PrimeCheck.java) - * [PrimeFactorization](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PrimeFactorization.java) - * [PronicNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PronicNumber.java) - * [PythagoreanTriple](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/PythagoreanTriple.java) - * [QuadraticEquationSolver](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/QuadraticEquationSolver.java) - * [ReverseNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/ReverseNumber.java) - * [RomanNumeralUtil](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/RomanNumeralUtil.java) - * [SecondMinMax](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SecondMinMax.java) - * [SieveOfEratosthenes](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SieveOfEratosthenes.java) - * [SimpsonIntegration](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SimpsonIntegration.java) - * [SolovayStrassenPrimalityTest](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SolovayStrassenPrimalityTest.java) - * [SquareFreeInteger](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SquareFreeInteger.java) - * [SquareRootWithBabylonianMethod](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SquareRootWithBabylonianMethod.java) - * [SquareRootWithNewtonRaphsonMethod](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SquareRootWithNewtonRaphsonMethod.java) - * [StandardDeviation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/StandardDeviation.java) - * [StandardScore](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/StandardScore.java) - * [StrobogrammaticNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/StrobogrammaticNumber.java) - * [SumOfArithmeticSeries](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SumOfArithmeticSeries.java) - * [SumOfDigits](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SumOfDigits.java) - * [SumOfOddNumbers](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SumOfOddNumbers.java) - * [SumWithoutArithmeticOperators](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/SumWithoutArithmeticOperators.java) - * [TrinomialTriangle](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/TrinomialTriangle.java) - * [TwinPrime](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/TwinPrime.java) - * [UniformNumbers](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/UniformNumbers.java) - * [VampireNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/VampireNumber.java) - * [VectorCrossProduct](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/VectorCrossProduct.java) - * [Volume](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/maths/Volume.java) - * matrixexponentiation - * [Fibonacci](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/matrixexponentiation/Fibonacci.java) - * misc - * [ColorContrastRatio](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/ColorContrastRatio.java) - * [InverseOfMatrix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/InverseOfMatrix.java) - * [MapReduce](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/MapReduce.java) - * [MatrixTranspose](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/MatrixTranspose.java) - * [MedianOfMatrix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/MedianOfMatrix.java) - * [MedianOfRunningArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/MedianOfRunningArray.java) - * [MedianOfRunningArrayByte](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayByte.java) - * [MedianOfRunningArrayDouble](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayDouble.java) - * [MedianOfRunningArrayFloat](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayFloat.java) - * [MedianOfRunningArrayInteger](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayInteger.java) - * [MedianOfRunningArrayLong](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/MedianOfRunningArrayLong.java) - * [MirrorOfMatrix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/MirrorOfMatrix.java) - * [PalindromePrime](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/PalindromePrime.java) - * [PalindromeSinglyLinkedList](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/PalindromeSinglyLinkedList.java) - * [RangeInSortedArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/RangeInSortedArray.java) - * [ShuffleArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/ShuffleArray.java) - * [Sparsity](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/Sparsity.java) - * [ThreeSumProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/ThreeSumProblem.java) - * [TwoSumProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/TwoSumProblem.java) - * [WordBoggle](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/misc/WordBoggle.java) - * others - * [ArrayLeftRotation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/ArrayLeftRotation.java) - * [ArrayRightRotation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/ArrayRightRotation.java) - * [BankersAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/BankersAlgorithm.java) - * [BFPRT](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/BFPRT.java) - * [BoyerMoore](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/BoyerMoore.java) - * [BrianKernighanAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/BrianKernighanAlgorithm.java) - * cn - * [HammingDistance](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/cn/HammingDistance.java) - * [Conway](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Conway.java) - * [CRC16](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/CRC16.java) - * [CRC32](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/CRC32.java) - * [CRCAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/CRCAlgorithm.java) - * [Damm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Damm.java) - * [Dijkstra](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Dijkstra.java) - * [FibbonaciSeries](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/FibbonaciSeries.java) - * [FloydTriangle](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/FloydTriangle.java) - * [GaussLegendre](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/GaussLegendre.java) - * [HappyNumbersSeq](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/HappyNumbersSeq.java) - * [Huffman](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Huffman.java) - * [Implementing auto completing features using trie](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Implementing_auto_completing_features_using_trie.java) - * [InsertDeleteInArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/InsertDeleteInArray.java) - * [KochSnowflake](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/KochSnowflake.java) - * [Krishnamurthy](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Krishnamurthy.java) - * [LinearCongruentialGenerator](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/LinearCongruentialGenerator.java) - * [LineSweep](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/LineSweep.java) - * [LowestBasePalindrome](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/LowestBasePalindrome.java) - * [Luhn](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Luhn.java) - * [Mandelbrot](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Mandelbrot.java) - * [MaximumSlidingWindow](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/MaximumSlidingWindow.java) - * [MaximumSumOfDistinctSubarraysWithLengthK](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/MaximumSumOfDistinctSubarraysWithLengthK.java) - * [MemoryManagementAlgorithms](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/MemoryManagementAlgorithms.java) - * [MiniMaxAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/MiniMaxAlgorithm.java) - * [PageRank](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/PageRank.java) - * [PasswordGen](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/PasswordGen.java) - * [PerlinNoise](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/PerlinNoise.java) - * [PrintAMatrixInSpiralOrder](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/PrintAMatrixInSpiralOrder.java) - * [QueueUsingTwoStacks](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/QueueUsingTwoStacks.java) - * [RemoveDuplicateFromString](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/RemoveDuplicateFromString.java) - * [ReverseStackUsingRecursion](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/ReverseStackUsingRecursion.java) - * [RotateMatrixBy90Degrees](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/RotateMatrixBy90Degrees.java) - * [SkylineProblem](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/SkylineProblem.java) - * [Sudoku](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Sudoku.java) - * [TowerOfHanoi](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/TowerOfHanoi.java) - * [TwoPointers](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/TwoPointers.java) - * [Verhoeff](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/others/Verhoeff.java) - * Recursion - * [GenerateSubsets](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/Recursion/GenerateSubsets.java) - * scheduling - * [AgingScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/AgingScheduling.java) - * diskscheduling - * [CircularLookScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularLookScheduling.java) - * [CircularScanScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularScanScheduling.java) - * [LookScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/diskscheduling/LookScheduling.java) - * [ScanScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/diskscheduling/ScanScheduling.java) - * [SSFScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/diskscheduling/SSFScheduling.java) - * [EDFScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/EDFScheduling.java) - * [FairShareScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/FairShareScheduling.java) - * [FCFSScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/FCFSScheduling.java) - * [GangScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/GangScheduling.java) - * [HighestResponseRatioNextScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/HighestResponseRatioNextScheduling.java) - * [JobSchedulingWithDeadline](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/JobSchedulingWithDeadline.java) - * [LotteryScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/LotteryScheduling.java) - * [MLFQScheduler](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/MLFQScheduler.java) - * [MultiAgentScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/MultiAgentScheduling.java) - * [NonPreemptivePriorityScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/NonPreemptivePriorityScheduling.java) - * [PreemptivePriorityScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/PreemptivePriorityScheduling.java) - * [ProportionalFairScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/ProportionalFairScheduling.java) - * [RandomScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/RandomScheduling.java) - * [RRScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/RRScheduling.java) - * [SelfAdjustingScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/SelfAdjustingScheduling.java) - * [SJFScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/SJFScheduling.java) - * [SlackTimeScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/SlackTimeScheduling.java) - * [SRTFScheduling](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/scheduling/SRTFScheduling.java) - * searches - * [BinarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/BinarySearch.java) - * [BinarySearch2dArray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/BinarySearch2dArray.java) - * [BM25InvertedIndex](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/BM25InvertedIndex.java) - * [BreadthFirstSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/BreadthFirstSearch.java) - * [DepthFirstSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/DepthFirstSearch.java) - * [ExponentalSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/ExponentalSearch.java) - * [FibonacciSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/FibonacciSearch.java) - * [HowManyTimesRotated](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/HowManyTimesRotated.java) - * [InterpolationSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/InterpolationSearch.java) - * [IterativeBinarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/IterativeBinarySearch.java) - * [IterativeTernarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/IterativeTernarySearch.java) - * [JumpSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/JumpSearch.java) - * [KMPSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/KMPSearch.java) - * [LinearSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/LinearSearch.java) - * [LinearSearchThread](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/LinearSearchThread.java) - * [LowerBound](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/LowerBound.java) - * [MonteCarloTreeSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/MonteCarloTreeSearch.java) - * [OrderAgnosticBinarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/OrderAgnosticBinarySearch.java) - * [PerfectBinarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/PerfectBinarySearch.java) - * [QuickSelect](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/QuickSelect.java) - * [RabinKarpAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/RabinKarpAlgorithm.java) - * [RandomSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/RandomSearch.java) - * [RecursiveBinarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/RecursiveBinarySearch.java) - * [RowColumnWiseSorted2dArrayBinarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearch.java) - * [SaddlebackSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/SaddlebackSearch.java) - * [SearchInARowAndColWiseSortedMatrix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrix.java) - * [SortOrderAgnosticBinarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearch.java) - * [SquareRootBinarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/SquareRootBinarySearch.java) - * [TernarySearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/TernarySearch.java) - * [UnionFind](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/UnionFind.java) - * [UpperBound](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/searches/UpperBound.java) - * slidingwindow - * [LongestSubarrayWithSumLessOrEqualToK](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/slidingwindow/LongestSubarrayWithSumLessOrEqualToK.java) - * [LongestSubstringWithoutRepeatingCharacters](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/slidingwindow/LongestSubstringWithoutRepeatingCharacters.java) - * [MaxSumKSizeSubarray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/slidingwindow/MaxSumKSizeSubarray.java) - * [MinSumKSizeSubarray](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/slidingwindow/MinSumKSizeSubarray.java) - * sorts - * [AdaptiveMergeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/AdaptiveMergeSort.java) - * [BeadSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/BeadSort.java) - * [BinaryInsertionSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/BinaryInsertionSort.java) - * [BitonicSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/BitonicSort.java) - * [BogoSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/BogoSort.java) - * [BubbleSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/BubbleSort.java) - * [BubbleSortRecursive](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/BubbleSortRecursive.java) - * [BucketSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/BucketSort.java) - * [CircleSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CircleSort.java) - * [CocktailShakerSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CocktailShakerSort.java) - * [CombSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CombSort.java) - * [CountingSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CountingSort.java) - * [CycleSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/CycleSort.java) - * [DualPivotQuickSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/DualPivotQuickSort.java) - * [DutchNationalFlagSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/DutchNationalFlagSort.java) - * [ExchangeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/ExchangeSort.java) - * [FlashSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/FlashSort.java) - * [GnomeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/GnomeSort.java) - * [HeapSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/HeapSort.java) - * [InsertionSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/InsertionSort.java) - * [IntrospectiveSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/IntrospectiveSort.java) - * [LinkListSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/LinkListSort.java) - * [MergeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/MergeSort.java) - * [MergeSortNoExtraSpace](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/MergeSortNoExtraSpace.java) - * [MergeSortRecursive](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/MergeSortRecursive.java) - * [OddEvenSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/OddEvenSort.java) - * [PancakeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/PancakeSort.java) - * [PatienceSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/PatienceSort.java) - * [PigeonholeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/PigeonholeSort.java) - * [QuickSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/QuickSort.java) - * [RadixSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/RadixSort.java) - * [SelectionSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/SelectionSort.java) - * [SelectionSortRecursive](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/SelectionSortRecursive.java) - * [ShellSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/ShellSort.java) - * [SimpleSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/SimpleSort.java) - * [SlowSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/SlowSort.java) - * [SortAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/SortAlgorithm.java) - * [SortUtils](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/SortUtils.java) - * [SortUtilsRandomGenerator](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/SortUtilsRandomGenerator.java) - * [SpreadSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/SpreadSort.java) - * [StalinSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/StalinSort.java) - * [StoogeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/StoogeSort.java) - * [StrandSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/StrandSort.java) - * [SwapSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/SwapSort.java) - * [TimSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/TimSort.java) - * [TopologicalSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/TopologicalSort.java) - * [TreeSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/TreeSort.java) - * [WaveSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/WaveSort.java) - * [WiggleSort](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/sorts/WiggleSort.java) - * stacks - * [BalancedBrackets](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/BalancedBrackets.java) - * [CelebrityFinder](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/CelebrityFinder.java) - * [DecimalToAnyUsingStack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/DecimalToAnyUsingStack.java) - * [DuplicateBrackets](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/DuplicateBrackets.java) - * [GreatestElementConstantTime](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/GreatestElementConstantTime.java) - * [InfixToPostfix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/InfixToPostfix.java) - * [InfixToPrefix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/InfixToPrefix.java) - * [LargestRectangle](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/LargestRectangle.java) - * [MaximumMinimumWindow](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/MaximumMinimumWindow.java) - * [MinStackUsingSingleStack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/MinStackUsingSingleStack.java) - * [MinStackUsingTwoStacks](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/MinStackUsingTwoStacks.java) - * [NextGreaterElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/NextGreaterElement.java) - * [NextSmallerElement](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/NextSmallerElement.java) - * [PalindromeWithStack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/PalindromeWithStack.java) - * [PostfixEvaluator](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/PostfixEvaluator.java) - * [PostfixToInfix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/PostfixToInfix.java) - * [PrefixEvaluator](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/PrefixEvaluator.java) - * [PrefixToInfix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/PrefixToInfix.java) - * [SmallestElementConstantTime](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/SmallestElementConstantTime.java) - * [SortStack](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/SortStack.java) - * [StackPostfixNotation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/StackPostfixNotation.java) - * [StackUsingTwoQueues](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/stacks/StackUsingTwoQueues.java) - * strings - * [AhoCorasick](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/AhoCorasick.java) - * [Alphabetical](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Alphabetical.java) - * [Anagrams](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Anagrams.java) - * [CharactersSame](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/CharactersSame.java) - * [CheckAnagrams](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/CheckAnagrams.java) - * [CheckVowels](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/CheckVowels.java) - * [CountChar](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/CountChar.java) - * [CountWords](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/CountWords.java) - * [HammingDistance](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/HammingDistance.java) - * [HorspoolSearch](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/HorspoolSearch.java) - * [Isomorphic](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Isomorphic.java) - * [KMP](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/KMP.java) - * [LetterCombinationsOfPhoneNumber](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/LetterCombinationsOfPhoneNumber.java) - * [LongestCommonPrefix](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/LongestCommonPrefix.java) - * [LongestNonRepetitiveSubstring](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/LongestNonRepetitiveSubstring.java) - * [LongestPalindromicSubstring](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/LongestPalindromicSubstring.java) - * [Lower](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Lower.java) - * [Manacher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Manacher.java) - * [MyAtoi](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/MyAtoi.java) - * [Palindrome](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Palindrome.java) - * [Pangram](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Pangram.java) - * [PermuteString](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/PermuteString.java) - * [RabinKarp](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/RabinKarp.java) - * [ReturnSubsequence](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/ReturnSubsequence.java) - * [ReverseString](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/ReverseString.java) - * [ReverseStringRecursive](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/ReverseStringRecursive.java) - * [ReverseWordsInString](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/ReverseWordsInString.java) - * [Rotation](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Rotation.java) - * [StringCompression](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/StringCompression.java) - * [StringMatchFiniteAutomata](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/StringMatchFiniteAutomata.java) - * [Upper](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Upper.java) - * [ValidParentheses](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/ValidParentheses.java) - * [WordLadder](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/WordLadder.java) - * zigZagPattern - * [ZigZagPattern](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/zigZagPattern/ZigZagPattern.java) - * test - * java - * com - * thealgorithms - * audiofilters - * [IIRFilterTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/audiofilters/IIRFilterTest.java) - * backtracking - * [AllPathsFromSourceToTargetTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/AllPathsFromSourceToTargetTest.java) - * [ArrayCombinationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java) - * [CombinationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/CombinationTest.java) - * [CrosswordSolverTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/CrosswordSolverTest.java) - * [FloodFillTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/FloodFillTest.java) - * [KnightsTourTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/KnightsTourTest.java) - * [MazeRecursionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/MazeRecursionTest.java) - * [MColoringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/MColoringTest.java) - * [NQueensTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/NQueensTest.java) - * [ParenthesesGeneratorTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/ParenthesesGeneratorTest.java) - * [PermutationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/PermutationTest.java) - * [PowerSumTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/PowerSumTest.java) - * [SubsequenceFinderTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/SubsequenceFinderTest.java) - * [WordPatternMatcherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/WordPatternMatcherTest.java) - * [WordSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/backtracking/WordSearchTest.java) - * bitmanipulation - * [BcdConversionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/BcdConversionTest.java) - * [BinaryPalindromeCheckTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheckTest.java) - * [BitSwapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/BitSwapTest.java) - * [BooleanAlgebraGatesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGatesTest.java) - * [ClearLeftmostSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBitTest.java) - * [CountLeadingZerosTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/CountLeadingZerosTest.java) - * [CountSetBitsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java) - * [FindNthBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/FindNthBitTest.java) - * [FirstDifferentBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/FirstDifferentBitTest.java) - * [GenerateSubsetsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/GenerateSubsetsTest.java) - * [GrayCodeConversionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/GrayCodeConversionTest.java) - * [HammingDistanceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/HammingDistanceTest.java) - * [HigherLowerPowerOfTwoTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwoTest.java) - * [HighestSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/HighestSetBitTest.java) - * [IndexOfRightMostSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBitTest.java) - * [IsEvenTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/IsEvenTest.java) - * [IsPowerTwoTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/IsPowerTwoTest.java) - * [LowestSetBitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/LowestSetBitTest.java) - * [ModuloPowerOfTwoTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/ModuloPowerOfTwoTest.java) - * [NextHigherSameBitCountTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/NextHigherSameBitCountTest.java) - * [NonRepeatingNumberFinderTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/NonRepeatingNumberFinderTest.java) - * [NumberAppearingOddTimesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimesTest.java) - * [NumbersDifferentSignsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/NumbersDifferentSignsTest.java) - * [OneBitDifferenceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/OneBitDifferenceTest.java) - * [OnesComplementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/OnesComplementTest.java) - * [ParityCheckTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/ParityCheckTest.java) - * [ReverseBitsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/ReverseBitsTest.java) - * [SingleBitOperationsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/SingleBitOperationsTest.java) - * [SingleElementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/SingleElementTest.java) - * [SwapAdjacentBitsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/SwapAdjacentBitsTest.java) - * [TwosComplementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/TwosComplementTest.java) - * [Xs3ConversionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/bitmanipulation/Xs3ConversionTest.java) - * ciphers - * a5 - * [A5CipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/a5/A5CipherTest.java) - * [A5KeyStreamGeneratorTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/a5/A5KeyStreamGeneratorTest.java) - * [LFSRTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/a5/LFSRTest.java) - * [ADFGVXCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/ADFGVXCipherTest.java) - * [AESEncryptionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/AESEncryptionTest.java) - * [AffineCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/AffineCipherTest.java) - * [AtbashTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/AtbashTest.java) - * [AutokeyTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/AutokeyTest.java) - * [BaconianCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/BaconianCipherTest.java) - * [BlowfishTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/BlowfishTest.java) - * [CaesarTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/CaesarTest.java) - * [ColumnarTranspositionCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/ColumnarTranspositionCipherTest.java) - * [DESTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/DESTest.java) - * [DiffieHellmanTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/DiffieHellmanTest.java) - * [ECCTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/ECCTest.java) - * [HillCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/HillCipherTest.java) - * [MonoAlphabeticTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/MonoAlphabeticTest.java) - * [PlayfairTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/PlayfairTest.java) - * [PolybiusTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/PolybiusTest.java) - * [RailFenceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/RailFenceTest.java) - * [RSATest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/RSATest.java) - * [SimpleSubCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/SimpleSubCipherTest.java) - * [VigenereTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/VigenereTest.java) - * [XORCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/XORCipherTest.java) - * conversions - * [AffineConverterTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/AffineConverterTest.java) - * [AnyBaseToDecimalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/AnyBaseToDecimalTest.java) - * [AnytoAnyTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/AnytoAnyTest.java) - * [BinaryToDecimalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/BinaryToDecimalTest.java) - * [BinaryToHexadecimalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/BinaryToHexadecimalTest.java) - * [BinaryToOctalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/BinaryToOctalTest.java) - * [DecimalToAnyBaseTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/DecimalToAnyBaseTest.java) - * [DecimalToBinaryTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/DecimalToBinaryTest.java) - * [DecimalToHexadecimalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/DecimalToHexadecimalTest.java) - * [DecimalToOctalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/DecimalToOctalTest.java) - * [EndianConverterTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/EndianConverterTest.java) - * [HexaDecimalToBinaryTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/HexaDecimalToBinaryTest.java) - * [HexaDecimalToDecimalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/HexaDecimalToDecimalTest.java) - * [HexToOctTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/HexToOctTest.java) - * [IntegerToEnglishTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/IntegerToEnglishTest.java) - * [IntegerToRomanTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/IntegerToRomanTest.java) - * [IPConverterTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/IPConverterTest.java) - * [IPv6ConverterTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/IPv6ConverterTest.java) - * [MorseCodeConverterTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/MorseCodeConverterTest.java) - * [OctalToBinaryTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/OctalToBinaryTest.java) - * [OctalToDecimalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/OctalToDecimalTest.java) - * [OctalToHexadecimalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/OctalToHexadecimalTest.java) - * [PhoneticAlphabetConverterTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/PhoneticAlphabetConverterTest.java) - * [RomanToIntegerTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/RomanToIntegerTest.java) - * [TurkishToLatinConversionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/TurkishToLatinConversionTest.java) - * [UnitConversionsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/UnitConversionsTest.java) - * [UnitsConverterTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/conversions/UnitsConverterTest.java) - * datastructures - * bag - * [BagTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/bag/BagTest.java) - * bloomfilter - * [BloomFilterTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/bloomfilter/BloomFilterTest.java) - * buffers - * [CircularBufferTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/buffers/CircularBufferTest.java) - * caches - * [LFUCacheTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/caches/LFUCacheTest.java) - * [LRUCacheTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/caches/LRUCacheTest.java) - * [MRUCacheTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/caches/MRUCacheTest.java) - * crdt - * [GCounterTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/crdt/GCounterTest.java) - * [GSetTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/crdt/GSetTest.java) - * [LWWElementSetTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java) - * [ORSetTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/crdt/ORSetTest.java) - * [PNCounterTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/crdt/PNCounterTest.java) - * [TwoPSetTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/crdt/TwoPSetTest.java) - * disjointsetunion - * [DisjointSetUnionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionTest.java) - * dynamicarray - * [DynamicArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/dynamicarray/DynamicArrayTest.java) - * graphs - * [AStarTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/AStarTest.java) - * [BipartiteGraphDFSTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/BipartiteGraphDFSTest.java) - * [BoruvkaAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/BoruvkaAlgorithmTest.java) - * [DijkstraAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java) - * [EdmondsBlossomAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java) - * [FloydWarshallTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/FloydWarshallTest.java) - * [FordFulkersonTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/FordFulkersonTest.java) - * [HamiltonianCycleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/HamiltonianCycleTest.java) - * [JohnsonsAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithmTest.java) - * [KahnsAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/KahnsAlgorithmTest.java) - * [KosarajuTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/KosarajuTest.java) - * [KruskalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/KruskalTest.java) - * [MatrixGraphsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/MatrixGraphsTest.java) - * [PrimMSTTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/PrimMSTTest.java) - * [TarjansAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/TarjansAlgorithmTest.java) - * [WelshPowellTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/WelshPowellTest.java) - * hashmap - * hashing - * [GenericHashMapUsingArrayListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayListTest.java) - * [GenericHashMapUsingArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayTest.java) - * [HashMapCuckooHashingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/HashMapCuckooHashingTest.java) - * [HashMapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/HashMapTest.java) - * [IntersectionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/IntersectionTest.java) - * [LinearProbingHashMapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMapTest.java) - * [MajorityElementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/MajorityElementTest.java) - * [MapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/hashmap/hashing/MapTest.java) - * heaps - * [FibonacciHeapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/FibonacciHeapTest.java) - * [GenericHeapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/GenericHeapTest.java) - * [HeapElementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/HeapElementTest.java) - * [KthElementFinderTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/KthElementFinderTest.java) - * [LeftistHeapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/LeftistHeapTest.java) - * [MaxHeapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/MaxHeapTest.java) - * [MedianFinderTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/MedianFinderTest.java) - * [MergeKSortedArraysTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/MergeKSortedArraysTest.java) - * [MinHeapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/MinHeapTest.java) - * [MinPriorityQueueTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/heaps/MinPriorityQueueTest.java) - * lists - * [CircleLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/CircleLinkedListTest.java) - * [CountSinglyLinkedListRecursionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/CountSinglyLinkedListRecursionTest.java) - * [CreateAndDetectLoopTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/CreateAndDetectLoopTest.java) - * [CursorLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/CursorLinkedListTest.java) - * [MergeKSortedLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/MergeKSortedLinkedListTest.java) - * [MergeSortedArrayListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/MergeSortedArrayListTest.java) - * [MergeSortedSinglyLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/MergeSortedSinglyLinkedListTest.java) - * [QuickSortLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/QuickSortLinkedListTest.java) - * [ReverseKGroupTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/ReverseKGroupTest.java) - * [RotateSinglyLinkedListsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/RotateSinglyLinkedListsTest.java) - * [SearchSinglyLinkedListRecursionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/SearchSinglyLinkedListRecursionTest.java) - * [SinglyLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/SinglyLinkedListTest.java) - * [SkipListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/SkipListTest.java) - * [SortedLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/lists/SortedLinkedListTest.java) - * queues - * [CircularQueueTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/CircularQueueTest.java) - * [DequeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/DequeTest.java) - * [GenericArrayListQueueTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/GenericArrayListQueueTest.java) - * [LinkedQueueTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/LinkedQueueTest.java) - * [PriorityQueuesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/PriorityQueuesTest.java) - * [QueueByTwoStacksTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/QueueByTwoStacksTest.java) - * [QueueTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/QueueTest.java) - * [SlidingWindowMaximumTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/SlidingWindowMaximumTest.java) - * [TokenBucketTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/queues/TokenBucketTest.java) - * stacks - * [NodeStackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/stacks/NodeStackTest.java) - * [ReverseStackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/stacks/ReverseStackTest.java) - * [StackArrayListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/stacks/StackArrayListTest.java) - * [StackArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/stacks/StackArrayTest.java) - * [StackOfLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/stacks/StackOfLinkedListTest.java) - * trees - * [AVLTreeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/AVLTreeTest.java) - * [BinaryTreeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/BinaryTreeTest.java) - * [BoundaryTraversalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java) - * [BSTFromSortedArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/BSTFromSortedArrayTest.java) - * [BSTIterativeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/BSTIterativeTest.java) - * [BSTRecursiveTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/BSTRecursiveTest.java) - * [CeilInBinarySearchTreeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTreeTest.java) - * [CheckBinaryTreeIsValidBSTTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/CheckBinaryTreeIsValidBSTTest.java) - * [CheckIfBinaryTreeBalancedTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/CheckIfBinaryTreeBalancedTest.java) - * [CheckTreeIsSymmetricTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/CheckTreeIsSymmetricTest.java) - * [CreateBinaryTreeFromInorderPreorderTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/CreateBinaryTreeFromInorderPreorderTest.java) - * [InorderTraversalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/InorderTraversalTest.java) - * [KDTreeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/KDTreeTest.java) - * [LazySegmentTreeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/LazySegmentTreeTest.java) - * [LevelOrderTraversalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/LevelOrderTraversalTest.java) - * [PostOrderTraversalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/PostOrderTraversalTest.java) - * [PreOrderTraversalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/PreOrderTraversalTest.java) - * [QuadTreeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java) - * [SameTreesCheckTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/SameTreesCheckTest.java) - * [SplayTreeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/SplayTreeTest.java) - * [TreapTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/TreapTest.java) - * [TreeTestUtils](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/TreeTestUtils.java) - * [TrieTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/TrieTest.java) - * [VerticalOrderTraversalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/VerticalOrderTraversalTest.java) - * [ZigzagTraversalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/trees/ZigzagTraversalTest.java) - * divideandconquer - * [BinaryExponentiationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/BinaryExponentiationTest.java) - * [ClosestPairTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/ClosestPairTest.java) - * [CountingInversionsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/CountingInversionsTest.java) - * [MedianOfTwoSortedArraysTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArraysTest.java) - * [SkylineAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/SkylineAlgorithmTest.java) - * [StrassenMatrixMultiplicationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplicationTest.java) - * [TilingProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/divideandconquer/TilingProblemTest.java) - * dynamicprogramming - * [AbbreviationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/AbbreviationTest.java) - * [AllConstructTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/AllConstructTest.java) - * [AssignmentUsingBitmaskTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/AssignmentUsingBitmaskTest.java) - * [BoardPathTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/BoardPathTest.java) - * [BoundaryFillTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/BoundaryFillTest.java) - * [BruteForceKnapsackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/BruteForceKnapsackTest.java) - * [CatalanNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/CatalanNumberTest.java) - * [ClimbStairsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/ClimbStairsTest.java) - * [CoinChangeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/CoinChangeTest.java) - * [CountFriendsPairingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/CountFriendsPairingTest.java) - * [DPTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/DPTest.java) - * [EditDistanceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/EditDistanceTest.java) - * [EggDroppingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/EggDroppingTest.java) - * [FibonacciTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/FibonacciTest.java) - * [KadaneAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/KadaneAlgorithmTest.java) - * [KnapsackMemoizationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/KnapsackMemoizationTest.java) - * [KnapsackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/KnapsackTest.java) - * [LevenshteinDistanceTests](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LevenshteinDistanceTests.java) - * [LongestAlternatingSubsequenceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LongestAlternatingSubsequenceTest.java) - * [LongestArithmeticSubsequenceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequenceTest.java) - * [LongestCommonSubsequenceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequenceTest.java) - * [LongestIncreasingSubsequenceTests](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequenceTests.java) - * [LongestPalindromicSubstringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubstringTest.java) - * [LongestValidParenthesesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/LongestValidParenthesesTest.java) - * [MatrixChainMultiplicationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplicationTest.java) - * [MatrixChainRecursiveTopDownMemoisationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/MatrixChainRecursiveTopDownMemoisationTest.java) - * [MaximumSumOfNonAdjacentElementsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/MaximumSumOfNonAdjacentElementsTest.java) - * [MinimumPathSumTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/MinimumPathSumTest.java) - * [MinimumSumPartitionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/MinimumSumPartitionTest.java) - * [NewManShanksPrimeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/NewManShanksPrimeTest.java) - * [OptimalJobSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/OptimalJobSchedulingTest.java) - * [PalindromicPartitioningTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/PalindromicPartitioningTest.java) - * [PartitionProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/PartitionProblemTest.java) - * [RegexMatchingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/RegexMatchingTest.java) - * [RodCuttingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/RodCuttingTest.java) - * [ShortestCommonSupersequenceLengthTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/ShortestCommonSupersequenceLengthTest.java) - * [SubsetCountTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/SubsetCountTest.java) - * [SubsetSumSpaceOptimizedTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimizedTest.java) - * [SubsetSumTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/SubsetSumTest.java) - * [SumOfSubsetTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/SumOfSubsetTest.java) - * [TribonacciTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/TribonacciTest.java) - * [UniquePathsTests](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/UniquePathsTests.java) - * [UniqueSubsequencesCountTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCountTest.java) - * [WildcardMatchingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/WildcardMatchingTest.java) - * [WineProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/dynamicprogramming/WineProblemTest.java) - * geometry - * [BresenhamLineTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/geometry/BresenhamLineTest.java) - * [ConvexHullTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/geometry/ConvexHullTest.java) - * [GrahamScanTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/geometry/GrahamScanTest.java) - * [MidpointCircleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/geometry/MidpointCircleTest.java) - * [MidpointEllipseTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/geometry/MidpointEllipseTest.java) - * graph - * [StronglyConnectedComponentOptimizedTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/graph/StronglyConnectedComponentOptimizedTest.java) - * greedyalgorithms - * [ActivitySelectionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/ActivitySelectionTest.java) - * [BandwidthAllocationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/BandwidthAllocationTest.java) - * [BinaryAdditionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/BinaryAdditionTest.java) - * [CoinChangeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/CoinChangeTest.java) - * [DigitSeparationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/DigitSeparationTest.java) - * [EgyptianFractionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/EgyptianFractionTest.java) - * [FractionalKnapsackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/FractionalKnapsackTest.java) - * [GaleShapleyTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/GaleShapleyTest.java) - * [JobSequencingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/JobSequencingTest.java) - * [KCentersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/KCentersTest.java) - * [MergeIntervalsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/MergeIntervalsTest.java) - * [MinimizingLatenessTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/MinimizingLatenessTest.java) - * [MinimumWaitingTimeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/MinimumWaitingTimeTest.java) - * [OptimalFileMergingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/OptimalFileMergingTest.java) - * [StockProfitCalculatorTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/greedyalgorithms/StockProfitCalculatorTest.java) - * io - * [BufferedReaderTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/io/BufferedReaderTest.java) - * lineclipping - * [CohenSutherlandTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/lineclipping/CohenSutherlandTest.java) - * [LiangBarskyTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/lineclipping/LiangBarskyTest.java) - * maths - * [AbsoluteMaxTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/AbsoluteMaxTest.java) - * [AbsoluteMinTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/AbsoluteMinTest.java) - * [AbsoluteValueTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/AbsoluteValueTest.java) - * [ADTFractionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/ADTFractionTest.java) - * [AliquotSumTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/AliquotSumTest.java) - * [AmicableNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/AmicableNumberTest.java) - * [AreaTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/AreaTest.java) - * [ArmstrongTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/ArmstrongTest.java) - * [AutoCorrelationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/AutoCorrelationTest.java) - * [AutomorphicNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/AutomorphicNumberTest.java) - * [AverageTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/AverageTest.java) - * [BinaryPowTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/BinaryPowTest.java) - * [BinomialCoefficientTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/BinomialCoefficientTest.java) - * [CatalanNumbersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/CatalanNumbersTest.java) - * [CeilTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/CeilTest.java) - * [ChineseRemainderTheoremTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/ChineseRemainderTheoremTest.java) - * [CollatzConjectureTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/CollatzConjectureTest.java) - * [CombinationsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/CombinationsTest.java) - * [ConvolutionFFTTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/ConvolutionFFTTest.java) - * [ConvolutionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/ConvolutionTest.java) - * [CrossCorrelationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/CrossCorrelationTest.java) - * [DeterminantOfMatrixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/DeterminantOfMatrixTest.java) - * [DigitalRootTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/DigitalRootTest.java) - * [DistanceFormulaTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/DistanceFormulaTest.java) - * [DudeneyNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/DudeneyNumberTest.java) - * [EulerMethodTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/EulerMethodTest.java) - * [EulersFunctionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/EulersFunctionTest.java) - * [FactorialRecursionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/FactorialRecursionTest.java) - * [FactorialTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/FactorialTest.java) - * [FastExponentiationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/FastExponentiationTest.java) - * [FastInverseSqrtTests](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/FastInverseSqrtTests.java) - * [FFTTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/FFTTest.java) - * [FibonacciJavaStreamsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/FibonacciJavaStreamsTest.java) - * [FibonacciLoopTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/FibonacciLoopTest.java) - * [FibonacciNumberCheckTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/FibonacciNumberCheckTest.java) - * [FibonacciNumberGoldenRationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/FibonacciNumberGoldenRationTest.java) - * [FindKthNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/FindKthNumberTest.java) - * [FindMaxRecursionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/FindMaxRecursionTest.java) - * [FindMaxTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/FindMaxTest.java) - * [FindMinRecursionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/FindMinRecursionTest.java) - * [FindMinTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/FindMinTest.java) - * [FloorTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/FloorTest.java) - * [FrizzyNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/FrizzyNumberTest.java) - * [GaussianTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/GaussianTest.java) - * [GCDRecursionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/GCDRecursionTest.java) - * [GCDTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/GCDTest.java) - * [GenericRootTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/GenericRootTest.java) - * [HarshadNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/HarshadNumberTest.java) - * [HeronsFormulaTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/HeronsFormulaTest.java) - * [JosephusProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/JosephusProblemTest.java) - * [KaprekarNumbersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/KaprekarNumbersTest.java) - * [KaratsubaMultiplicationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/KaratsubaMultiplicationTest.java) - * [KrishnamurthyNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/KrishnamurthyNumberTest.java) - * [LeastCommonMultipleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/LeastCommonMultipleTest.java) - * [LeonardoNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/LeonardoNumberTest.java) - * [LiouvilleLambdaFunctionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/LiouvilleLambdaFunctionTest.java) - * [LongDivisionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/LongDivisionTest.java) - * [LucasSeriesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/LucasSeriesTest.java) - * [MatrixRankTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/MatrixRankTest.java) - * [MatrixUtilTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/MatrixUtilTest.java) - * [MaxValueTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/MaxValueTest.java) - * [MeansTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/MeansTest.java) - * [MedianTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/MedianTest.java) - * [MillerRabinPrimalityCheckTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/MillerRabinPrimalityCheckTest.java) - * [MinValueTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/MinValueTest.java) - * [MobiusFunctionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/MobiusFunctionTest.java) - * [ModeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/ModeTest.java) - * [NonRepeatingElementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/NonRepeatingElementTest.java) - * [NthUglyNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/NthUglyNumberTest.java) - * [NumberOfDigitsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/NumberOfDigitsTest.java) - * [PalindromeNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PalindromeNumberTest.java) - * [ParseIntegerTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/ParseIntegerTest.java) - * [PascalTriangleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PascalTriangleTest.java) - * [PerfectCubeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PerfectCubeTest.java) - * [PerfectNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PerfectNumberTest.java) - * [PerfectSquareTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PerfectSquareTest.java) - * [PerimeterTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PerimeterTest.java) - * [PollardRhoTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PollardRhoTest.java) - * [PowerOfTwoOrNotTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PowerOfTwoOrNotTest.java) - * [PowerUsingRecursionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PowerUsingRecursionTest.java) - * [PowTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PowTest.java) - * [PrimeCheckTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PrimeCheckTest.java) - * [PrimeFactorizationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PrimeFactorizationTest.java) - * [PronicNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PronicNumberTest.java) - * [PythagoreanTripleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/PythagoreanTripleTest.java) - * [QuadraticEquationSolverTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/QuadraticEquationSolverTest.java) - * [ReverseNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/ReverseNumberTest.java) - * [SecondMinMaxTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SecondMinMaxTest.java) - * [SieveOfEratosthenesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SieveOfEratosthenesTest.java) - * [SolovayStrassenPrimalityTestTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SolovayStrassenPrimalityTestTest.java) - * [SquareFreeIntegerTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SquareFreeIntegerTest.java) - * [SquareRootwithBabylonianMethodTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SquareRootwithBabylonianMethodTest.java) - * [SquareRootWithNewtonRaphsonTestMethod](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SquareRootWithNewtonRaphsonTestMethod.java) - * [StandardDeviationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/StandardDeviationTest.java) - * [StandardScoreTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/StandardScoreTest.java) - * [StrobogrammaticNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/StrobogrammaticNumberTest.java) - * [SumOfArithmeticSeriesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SumOfArithmeticSeriesTest.java) - * [SumOfDigitsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SumOfDigitsTest.java) - * [SumOfOddNumbersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SumOfOddNumbersTest.java) - * [SumWithoutArithmeticOperatorsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/SumWithoutArithmeticOperatorsTest.java) - * [TestArmstrong](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/TestArmstrong.java) - * [TwinPrimeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/TwinPrimeTest.java) - * [UniformNumbersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/UniformNumbersTest.java) - * [VolumeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/VolumeTest.java) - * misc - * [ColorContrastRatioTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/ColorContrastRatioTest.java) - * [InverseOfMatrixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/InverseOfMatrixTest.java) - * [MapReduceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/MapReduceTest.java) - * [MatrixTransposeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/MatrixTransposeTest.java) - * [MedianOfMatrixtest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/MedianOfMatrixtest.java) - * [MedianOfRunningArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java) - * [MirrorOfMatrixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/MirrorOfMatrixTest.java) - * [PalindromePrimeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/PalindromePrimeTest.java) - * [PalindromeSinglyLinkedListTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/PalindromeSinglyLinkedListTest.java) - * [RangeInSortedArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/RangeInSortedArrayTest.java) - * [ShuffleArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/ShuffleArrayTest.java) - * [SparsityTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/SparsityTest.java) - * [ThreeSumProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/ThreeSumProblemTest.java) - * [TwoSumProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/TwoSumProblemTest.java) - * [WordBoggleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/WordBoggleTest.java) - * others - * [ArrayLeftRotationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/ArrayLeftRotationTest.java) - * [ArrayRightRotationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/ArrayRightRotationTest.java) - * [BestFitCPUTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/BestFitCPUTest.java) - * [BFPRTTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/BFPRTTest.java) - * [BoyerMooreTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/BoyerMooreTest.java) - * cn - * [HammingDistanceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/cn/HammingDistanceTest.java) - * [ConwayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/ConwayTest.java) - * [CountFriendsPairingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/CountFriendsPairingTest.java) - * [CRC16Test](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/CRC16Test.java) - * [CRCAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/CRCAlgorithmTest.java) - * [FirstFitCPUTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/FirstFitCPUTest.java) - * [FloydTriangleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/FloydTriangleTest.java) - * [KadaneAlogrithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/KadaneAlogrithmTest.java) - * [LineSweepTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/LineSweepTest.java) - * [LinkListSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/LinkListSortTest.java) - * [LowestBasePalindromeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/LowestBasePalindromeTest.java) - * [MaximumSlidingWindowTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/MaximumSlidingWindowTest.java) - * [MaximumSumOfDistinctSubarraysWithLengthKTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/MaximumSumOfDistinctSubarraysWithLengthKTest.java) - * [NewManShanksPrimeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/NewManShanksPrimeTest.java) - * [NextFitTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/NextFitTest.java) - * [PasswordGenTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/PasswordGenTest.java) - * [QueueUsingTwoStacksTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/QueueUsingTwoStacksTest.java) - * [RemoveDuplicateFromStringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/RemoveDuplicateFromStringTest.java) - * [ReverseStackUsingRecursionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/ReverseStackUsingRecursionTest.java) - * [SkylineProblemTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/SkylineProblemTest.java) - * [SudokuTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/SudokuTest.java) - * [TestPrintMatrixInSpiralOrder](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/TestPrintMatrixInSpiralOrder.java) - * [TowerOfHanoiTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/TowerOfHanoiTest.java) - * [TwoPointersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/TwoPointersTest.java) - * [WorstFitCPUTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/WorstFitCPUTest.java) - * Recursion - * [GenerateSubsetsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/Recursion/GenerateSubsetsTest.java) - * scheduling - * [AgingSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/AgingSchedulingTest.java) - * diskscheduling - * [CircularLookSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularLookSchedulingTest.java) - * [CircularScanSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularScanSchedulingTest.java) - * [LookSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/diskscheduling/LookSchedulingTest.java) - * [ScanSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/diskscheduling/ScanSchedulingTest.java) - * [SSFSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/diskscheduling/SSFSchedulingTest.java) - * [EDFSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/EDFSchedulingTest.java) - * [FairShareSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/FairShareSchedulingTest.java) - * [FCFSSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/FCFSSchedulingTest.java) - * [GangSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/GangSchedulingTest.java) - * [HighestResponseRatioNextSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/HighestResponseRatioNextSchedulingTest.java) - * [JobSchedulingWithDeadlineTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/JobSchedulingWithDeadlineTest.java) - * [LotterySchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/LotterySchedulingTest.java) - * [MLFQSchedulerTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/MLFQSchedulerTest.java) - * [MultiAgentSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/MultiAgentSchedulingTest.java) - * [NonPreemptivePrioritySchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/NonPreemptivePrioritySchedulingTest.java) - * [PreemptivePrioritySchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/PreemptivePrioritySchedulingTest.java) - * [ProportionalFairSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/ProportionalFairSchedulingTest.java) - * [RandomSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/RandomSchedulingTest.java) - * [RRSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/RRSchedulingTest.java) - * [SelfAdjustingSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/SelfAdjustingSchedulingTest.java) - * [SJFSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java) - * [SlackTimeSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/SlackTimeSchedulingTest.java) - * [SRTFSchedulingTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/scheduling/SRTFSchedulingTest.java) - * searches - * [BinarySearch2dArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/BinarySearch2dArrayTest.java) - * [BinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/BinarySearchTest.java) - * [BM25InvertedIndexTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/BM25InvertedIndexTest.java) - * [BreadthFirstSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/BreadthFirstSearchTest.java) - * [DepthFirstSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/DepthFirstSearchTest.java) - * [ExponentialSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/ExponentialSearchTest.java) - * [FibonacciSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/FibonacciSearchTest.java) - * [HowManyTimesRotatedTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/HowManyTimesRotatedTest.java) - * [InterpolationSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/InterpolationSearchTest.java) - * [IterativeBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/IterativeBinarySearchTest.java) - * [IterativeTernarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/IterativeTernarySearchTest.java) - * [JumpSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/JumpSearchTest.java) - * [KMPSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/KMPSearchTest.java) - * [LinearSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/LinearSearchTest.java) - * [LinearSearchThreadTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/LinearSearchThreadTest.java) - * [LowerBoundTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/LowerBoundTest.java) - * [MonteCarloTreeSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/MonteCarloTreeSearchTest.java) - * [OrderAgnosticBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/OrderAgnosticBinarySearchTest.java) - * [PerfectBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java) - * [QuickSelectTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/QuickSelectTest.java) - * [RabinKarpAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/RabinKarpAlgorithmTest.java) - * [RandomSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/RandomSearchTest.java) - * [RecursiveBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/RecursiveBinarySearchTest.java) - * [RowColumnWiseSorted2dArrayBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearchTest.java) - * [SaddlebackSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SaddlebackSearchTest.java) - * [SearchInARowAndColWiseSortedMatrixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrixTest.java) - * [SortOrderAgnosticBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearchTest.java) - * [SquareRootBinarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/SquareRootBinarySearchTest.java) - * [TernarySearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/TernarySearchTest.java) - * [TestSearchInARowAndColWiseSortedMatrix](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/TestSearchInARowAndColWiseSortedMatrix.java) - * [UnionFindTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/UnionFindTest.java) - * [UpperBoundTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/searches/UpperBoundTest.java) - * slidingwindow - * [LongestSubarrayWithSumLessOrEqualToKTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/slidingwindow/LongestSubarrayWithSumLessOrEqualToKTest.java) - * [LongestSubstringWithoutRepeatingCharactersTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/slidingwindow/LongestSubstringWithoutRepeatingCharactersTest.java) - * [MaxSumKSizeSubarrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/slidingwindow/MaxSumKSizeSubarrayTest.java) - * [MinSumKSizeSubarrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/slidingwindow/MinSumKSizeSubarrayTest.java) - * sorts - * [AdaptiveMergeSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/AdaptiveMergeSortTest.java) - * [BeadSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/BeadSortTest.java) - * [BinaryInsertionSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/BinaryInsertionSortTest.java) - * [BitonicSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/BitonicSortTest.java) - * [BogoSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/BogoSortTest.java) - * [BubbleSortRecursiveTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/BubbleSortRecursiveTest.java) - * [BubbleSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/BubbleSortTest.java) - * [BucketSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/BucketSortTest.java) - * [CircleSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/CircleSortTest.java) - * [CocktailShakerSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/CocktailShakerSortTest.java) - * [CombSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/CombSortTest.java) - * [CountingSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/CountingSortTest.java) - * [CycleSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/CycleSortTest.java) - * [DualPivotQuickSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/DualPivotQuickSortTest.java) - * [DutchNationalFlagSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/DutchNationalFlagSortTest.java) - * [ExchangeSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/ExchangeSortTest.java) - * [FlashSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/FlashSortTest.java) - * [GnomeSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/GnomeSortTest.java) - * [HeapSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/HeapSortTest.java) - * [InsertionSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/InsertionSortTest.java) - * [IntrospectiveSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/IntrospectiveSortTest.java) - * [MergeSortNoExtraSpaceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/MergeSortNoExtraSpaceTest.java) - * [MergeSortRecursiveTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/MergeSortRecursiveTest.java) - * [MergeSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/MergeSortTest.java) - * [OddEvenSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/OddEvenSortTest.java) - * [PancakeSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/PancakeSortTest.java) - * [PatienceSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/PatienceSortTest.java) - * [PigeonholeSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/PigeonholeSortTest.java) - * [QuickSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/QuickSortTest.java) - * [RadixSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/RadixSortTest.java) - * [SelectionSortRecursiveTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/SelectionSortRecursiveTest.java) - * [SelectionSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/SelectionSortTest.java) - * [ShellSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/ShellSortTest.java) - * [SimpleSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/SimpleSortTest.java) - * [SlowSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/SlowSortTest.java) - * [SortingAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/SortingAlgorithmTest.java) - * [SortUtilsRandomGeneratorTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/SortUtilsRandomGeneratorTest.java) - * [SortUtilsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/SortUtilsTest.java) - * [SpreadSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/SpreadSortTest.java) - * [StalinSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/StalinSortTest.java) - * [StoogeSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/StoogeSortTest.java) - * [StrandSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/StrandSortTest.java) - * [SwapSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/SwapSortTest.java) - * [TimSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/TimSortTest.java) - * [TopologicalSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/TopologicalSortTest.java) - * [TreeSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/TreeSortTest.java) - * [WaveSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/WaveSortTest.java) - * [WiggleSortTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/sorts/WiggleSortTest.java) - * stacks - * [BalancedBracketsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/BalancedBracketsTest.java) - * [CelebrityFinderTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/CelebrityFinderTest.java) - * [DecimalToAnyUsingStackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/DecimalToAnyUsingStackTest.java) - * [DuplicateBracketsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/DuplicateBracketsTest.java) - * [GreatestElementConstantTimeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/GreatestElementConstantTimeTest.java) - * [InfixToPostfixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/InfixToPostfixTest.java) - * [InfixToPrefixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/InfixToPrefixTest.java) - * [LargestRectangleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/LargestRectangleTest.java) - * [MinStackUsingSingleStackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/MinStackUsingSingleStackTest.java) - * [MinStackUsingTwoStacksTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/MinStackUsingTwoStacksTest.java) - * [NextGreaterElementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/NextGreaterElementTest.java) - * [NextSmallerElementTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/NextSmallerElementTest.java) - * [PalindromeWithStackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/PalindromeWithStackTest.java) - * [PostfixEvaluatorTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/PostfixEvaluatorTest.java) - * [PostfixToInfixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/PostfixToInfixTest.java) - * [PrefixEvaluatorTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/PrefixEvaluatorTest.java) - * [PrefixToInfixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/PrefixToInfixTest.java) - * [SmallestElementConstantTimeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/SmallestElementConstantTimeTest.java) - * [SortStackTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/SortStackTest.java) - * [StackPostfixNotationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/StackPostfixNotationTest.java) - * [StackUsingTwoQueuesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/stacks/StackUsingTwoQueuesTest.java) - * strings - * [AhoCorasickTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/AhoCorasickTest.java) - * [AlphabeticalTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/AlphabeticalTest.java) - * [AnagramsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/AnagramsTest.java) - * [CharacterSameTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/CharacterSameTest.java) - * [CheckAnagramsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/CheckAnagramsTest.java) - * [CheckVowelsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/CheckVowelsTest.java) - * [CountCharTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/CountCharTest.java) - * [CountWordsTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/CountWordsTest.java) - * [HammingDistanceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/HammingDistanceTest.java) - * [HorspoolSearchTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/HorspoolSearchTest.java) - * [IsomorphicTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/IsomorphicTest.java) - * [LetterCombinationsOfPhoneNumberTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/LetterCombinationsOfPhoneNumberTest.java) - * [LongestCommonPrefixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/LongestCommonPrefixTest.java) - * [LongestNonRepetitiveSubstringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/LongestNonRepetitiveSubstringTest.java) - * [LongestPalindromicSubstringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/LongestPalindromicSubstringTest.java) - * [LowerTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/LowerTest.java) - * [ManacherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/ManacherTest.java) - * [MyAtoiTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/MyAtoiTest.java) - * [PalindromeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/PalindromeTest.java) - * [PangramTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/PangramTest.java) - * [PermuteStringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/PermuteStringTest.java) - * [ReturnSubsequenceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/ReturnSubsequenceTest.java) - * [ReverseStringRecursiveTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/ReverseStringRecursiveTest.java) - * [ReverseStringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/ReverseStringTest.java) - * [ReverseWordsInStringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/ReverseWordsInStringTest.java) - * [RotationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/RotationTest.java) - * [StringCompressionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/StringCompressionTest.java) - * [StringMatchFiniteAutomataTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/StringMatchFiniteAutomataTest.java) - * [UpperTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/UpperTest.java) - * [ValidParenthesesTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java) - * [WordLadderTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/WordLadderTest.java) - * zigZagPattern - * [ZigZagPatternTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/zigZagPattern/ZigZagPatternTest.java) + +- 📁 **main** + - 📁 **java** + - 📁 **com** + - 📁 **thealgorithms** + - 📁 **audiofilters** + - 📄 [EMAFilter](src/main/java/com/thealgorithms/audiofilters/EMAFilter.java) + - 📄 [IIRFilter](src/main/java/com/thealgorithms/audiofilters/IIRFilter.java) + - 📁 **backtracking** + - 📄 [AllPathsFromSourceToTarget](src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java) + - 📄 [ArrayCombination](src/main/java/com/thealgorithms/backtracking/ArrayCombination.java) + - 📄 [Combination](src/main/java/com/thealgorithms/backtracking/Combination.java) + - 📄 [CrosswordSolver](src/main/java/com/thealgorithms/backtracking/CrosswordSolver.java) + - 📄 [FloodFill](src/main/java/com/thealgorithms/backtracking/FloodFill.java) + - 📄 [KnightsTour](src/main/java/com/thealgorithms/backtracking/KnightsTour.java) + - 📄 [MColoring](src/main/java/com/thealgorithms/backtracking/MColoring.java) + - 📄 [MazeRecursion](src/main/java/com/thealgorithms/backtracking/MazeRecursion.java) + - 📄 [NQueens](src/main/java/com/thealgorithms/backtracking/NQueens.java) + - 📄 [ParenthesesGenerator](src/main/java/com/thealgorithms/backtracking/ParenthesesGenerator.java) + - 📄 [Permutation](src/main/java/com/thealgorithms/backtracking/Permutation.java) + - 📄 [PowerSum](src/main/java/com/thealgorithms/backtracking/PowerSum.java) + - 📄 [SubsequenceFinder](src/main/java/com/thealgorithms/backtracking/SubsequenceFinder.java) + - 📄 [WordPatternMatcher](src/main/java/com/thealgorithms/backtracking/WordPatternMatcher.java) + - 📄 [WordSearch](src/main/java/com/thealgorithms/backtracking/WordSearch.java) + - 📁 **bitmanipulation** + - 📄 [BcdConversion](src/main/java/com/thealgorithms/bitmanipulation/BcdConversion.java) + - 📄 [BinaryPalindromeCheck](src/main/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheck.java) + - 📄 [BitSwap](src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java) + - 📄 [BooleanAlgebraGates](src/main/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGates.java) + - 📄 [ClearLeftmostSetBit](src/main/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBit.java) + - 📄 [CountLeadingZeros](src/main/java/com/thealgorithms/bitmanipulation/CountLeadingZeros.java) + - 📄 [CountSetBits](src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java) + - 📄 [FindNthBit](src/main/java/com/thealgorithms/bitmanipulation/FindNthBit.java) + - 📄 [FirstDifferentBit](src/main/java/com/thealgorithms/bitmanipulation/FirstDifferentBit.java) + - 📄 [GenerateSubsets](src/main/java/com/thealgorithms/bitmanipulation/GenerateSubsets.java) + - 📄 [GrayCodeConversion](src/main/java/com/thealgorithms/bitmanipulation/GrayCodeConversion.java) + - 📄 [HammingDistance](src/main/java/com/thealgorithms/bitmanipulation/HammingDistance.java) + - 📄 [HigherLowerPowerOfTwo](src/main/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwo.java) + - 📄 [HighestSetBit](src/main/java/com/thealgorithms/bitmanipulation/HighestSetBit.java) + - 📄 [IndexOfRightMostSetBit](src/main/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBit.java) + - 📄 [IsEven](src/main/java/com/thealgorithms/bitmanipulation/IsEven.java) + - 📄 [IsPowerTwo](src/main/java/com/thealgorithms/bitmanipulation/IsPowerTwo.java) + - 📄 [LowestSetBit](src/main/java/com/thealgorithms/bitmanipulation/LowestSetBit.java) + - 📄 [ModuloPowerOfTwo](src/main/java/com/thealgorithms/bitmanipulation/ModuloPowerOfTwo.java) + - 📄 [NextHigherSameBitCount](src/main/java/com/thealgorithms/bitmanipulation/NextHigherSameBitCount.java) + - 📄 [NonRepeatingNumberFinder](src/main/java/com/thealgorithms/bitmanipulation/NonRepeatingNumberFinder.java) + - 📄 [NumberAppearingOddTimes](src/main/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimes.java) + - 📄 [NumbersDifferentSigns](src/main/java/com/thealgorithms/bitmanipulation/NumbersDifferentSigns.java) + - 📄 [OneBitDifference](src/main/java/com/thealgorithms/bitmanipulation/OneBitDifference.java) + - 📄 [OnesComplement](src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java) + - 📄 [ParityCheck](src/main/java/com/thealgorithms/bitmanipulation/ParityCheck.java) + - 📄 [ReverseBits](src/main/java/com/thealgorithms/bitmanipulation/ReverseBits.java) + - 📄 [SingleBitOperations](src/main/java/com/thealgorithms/bitmanipulation/SingleBitOperations.java) + - 📄 [SingleElement](src/main/java/com/thealgorithms/bitmanipulation/SingleElement.java) + - 📄 [SwapAdjacentBits](src/main/java/com/thealgorithms/bitmanipulation/SwapAdjacentBits.java) + - 📄 [TwosComplement](src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java) + - 📄 [Xs3Conversion](src/main/java/com/thealgorithms/bitmanipulation/Xs3Conversion.java) + - 📁 **ciphers** + - 📄 [ADFGVXCipher](src/main/java/com/thealgorithms/ciphers/ADFGVXCipher.java) + - 📄 [AES](src/main/java/com/thealgorithms/ciphers/AES.java) + - 📄 [AESEncryption](src/main/java/com/thealgorithms/ciphers/AESEncryption.java) + - 📄 [AffineCipher](src/main/java/com/thealgorithms/ciphers/AffineCipher.java) + - 📄 [AtbashCipher](src/main/java/com/thealgorithms/ciphers/AtbashCipher.java) + - 📄 [Autokey](src/main/java/com/thealgorithms/ciphers/Autokey.java) + - 📄 [BaconianCipher](src/main/java/com/thealgorithms/ciphers/BaconianCipher.java) + - 📄 [Blowfish](src/main/java/com/thealgorithms/ciphers/Blowfish.java) + - 📄 [Caesar](src/main/java/com/thealgorithms/ciphers/Caesar.java) + - 📄 [ColumnarTranspositionCipher](src/main/java/com/thealgorithms/ciphers/ColumnarTranspositionCipher.java) + - 📄 [DES](src/main/java/com/thealgorithms/ciphers/DES.java) + - 📄 [DiffieHellman](src/main/java/com/thealgorithms/ciphers/DiffieHellman.java) + - 📄 [ECC](src/main/java/com/thealgorithms/ciphers/ECC.java) + - 📄 [HillCipher](src/main/java/com/thealgorithms/ciphers/HillCipher.java) + - 📄 [MonoAlphabetic](src/main/java/com/thealgorithms/ciphers/MonoAlphabetic.java) + - 📄 [PlayfairCipher](src/main/java/com/thealgorithms/ciphers/PlayfairCipher.java) + - 📄 [Polybius](src/main/java/com/thealgorithms/ciphers/Polybius.java) + - 📄 [ProductCipher](src/main/java/com/thealgorithms/ciphers/ProductCipher.java) + - 📄 [RSA](src/main/java/com/thealgorithms/ciphers/RSA.java) + - 📄 [RailFenceCipher](src/main/java/com/thealgorithms/ciphers/RailFenceCipher.java) + - 📄 [SimpleSubCipher](src/main/java/com/thealgorithms/ciphers/SimpleSubCipher.java) + - 📄 [Vigenere](src/main/java/com/thealgorithms/ciphers/Vigenere.java) + - 📄 [XORCipher](src/main/java/com/thealgorithms/ciphers/XORCipher.java) + - 📁 **a5** + - 📄 [A5Cipher](src/main/java/com/thealgorithms/ciphers/a5/A5Cipher.java) + - 📄 [A5KeyStreamGenerator](src/main/java/com/thealgorithms/ciphers/a5/A5KeyStreamGenerator.java) + - 📄 [BaseLFSR](src/main/java/com/thealgorithms/ciphers/a5/BaseLFSR.java) + - 📄 [CompositeLFSR](src/main/java/com/thealgorithms/ciphers/a5/CompositeLFSR.java) + - 📄 [LFSR](src/main/java/com/thealgorithms/ciphers/a5/LFSR.java) + - 📄 [Utils](src/main/java/com/thealgorithms/ciphers/a5/Utils.java) + - 📁 **conversions** + - 📄 [AffineConverter](src/main/java/com/thealgorithms/conversions/AffineConverter.java) + - 📄 [AnyBaseToAnyBase](src/main/java/com/thealgorithms/conversions/AnyBaseToAnyBase.java) + - 📄 [AnyBaseToDecimal](src/main/java/com/thealgorithms/conversions/AnyBaseToDecimal.java) + - 📄 [AnytoAny](src/main/java/com/thealgorithms/conversions/AnytoAny.java) + - 📄 [BinaryToDecimal](src/main/java/com/thealgorithms/conversions/BinaryToDecimal.java) + - 📄 [BinaryToHexadecimal](src/main/java/com/thealgorithms/conversions/BinaryToHexadecimal.java) + - 📄 [BinaryToOctal](src/main/java/com/thealgorithms/conversions/BinaryToOctal.java) + - 📄 [DecimalToAnyBase](src/main/java/com/thealgorithms/conversions/DecimalToAnyBase.java) + - 📄 [DecimalToBinary](src/main/java/com/thealgorithms/conversions/DecimalToBinary.java) + - 📄 [DecimalToHexadecimal](src/main/java/com/thealgorithms/conversions/DecimalToHexadecimal.java) + - 📄 [DecimalToOctal](src/main/java/com/thealgorithms/conversions/DecimalToOctal.java) + - 📄 [EndianConverter](src/main/java/com/thealgorithms/conversions/EndianConverter.java) + - 📄 [HexToOct](src/main/java/com/thealgorithms/conversions/HexToOct.java) + - 📄 [HexaDecimalToBinary](src/main/java/com/thealgorithms/conversions/HexaDecimalToBinary.java) + - 📄 [HexaDecimalToDecimal](src/main/java/com/thealgorithms/conversions/HexaDecimalToDecimal.java) + - 📄 [IPConverter](src/main/java/com/thealgorithms/conversions/IPConverter.java) + - 📄 [IPv6Converter](src/main/java/com/thealgorithms/conversions/IPv6Converter.java) + - 📄 [IntegerToEnglish](src/main/java/com/thealgorithms/conversions/IntegerToEnglish.java) + - 📄 [IntegerToRoman](src/main/java/com/thealgorithms/conversions/IntegerToRoman.java) + - 📄 [MorseCodeConverter](src/main/java/com/thealgorithms/conversions/MorseCodeConverter.java) + - 📄 [NumberToWords](src/main/java/com/thealgorithms/conversions/NumberToWords.java) + - 📄 [OctalToBinary](src/main/java/com/thealgorithms/conversions/OctalToBinary.java) + - 📄 [OctalToDecimal](src/main/java/com/thealgorithms/conversions/OctalToDecimal.java) + - 📄 [OctalToHexadecimal](src/main/java/com/thealgorithms/conversions/OctalToHexadecimal.java) + - 📄 [PhoneticAlphabetConverter](src/main/java/com/thealgorithms/conversions/PhoneticAlphabetConverter.java) + - 📄 [RgbHsvConversion](src/main/java/com/thealgorithms/conversions/RgbHsvConversion.java) + - 📄 [RomanToInteger](src/main/java/com/thealgorithms/conversions/RomanToInteger.java) + - 📄 [TurkishToLatinConversion](src/main/java/com/thealgorithms/conversions/TurkishToLatinConversion.java) + - 📄 [UnitConversions](src/main/java/com/thealgorithms/conversions/UnitConversions.java) + - 📄 [UnitsConverter](src/main/java/com/thealgorithms/conversions/UnitsConverter.java) + - 📄 [WordsToNumber](src/main/java/com/thealgorithms/conversions/WordsToNumber.java) + - 📁 **datastructures** + - 📄 [Node](src/main/java/com/thealgorithms/datastructures/Node.java) + - 📁 **bags** + - 📄 [Bag](src/main/java/com/thealgorithms/datastructures/bags/Bag.java) + - 📁 **bloomfilter** + - 📄 [BloomFilter](src/main/java/com/thealgorithms/datastructures/bloomfilter/BloomFilter.java) + - 📁 **buffers** + - 📄 [CircularBuffer](src/main/java/com/thealgorithms/datastructures/buffers/CircularBuffer.java) + - 📁 **caches** + - 📄 [FIFOCache](src/main/java/com/thealgorithms/datastructures/caches/FIFOCache.java) + - 📄 [LFUCache](src/main/java/com/thealgorithms/datastructures/caches/LFUCache.java) + - 📄 [LIFOCache](src/main/java/com/thealgorithms/datastructures/caches/LIFOCache.java) + - 📄 [LRUCache](src/main/java/com/thealgorithms/datastructures/caches/LRUCache.java) + - 📄 [MRUCache](src/main/java/com/thealgorithms/datastructures/caches/MRUCache.java) + - 📄 [RRCache](src/main/java/com/thealgorithms/datastructures/caches/RRCache.java) + - 📁 **crdt** + - 📄 [GCounter](src/main/java/com/thealgorithms/datastructures/crdt/GCounter.java) + - 📄 [GSet](src/main/java/com/thealgorithms/datastructures/crdt/GSet.java) + - 📄 [LWWElementSet](src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java) + - 📄 [ORSet](src/main/java/com/thealgorithms/datastructures/crdt/ORSet.java) + - 📄 [PNCounter](src/main/java/com/thealgorithms/datastructures/crdt/PNCounter.java) + - 📄 [TwoPSet](src/main/java/com/thealgorithms/datastructures/crdt/TwoPSet.java) + - 📁 **disjointsetunion** + - 📄 [DisjointSetUnion](src/main/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnion.java) + - 📄 [Node](src/main/java/com/thealgorithms/datastructures/disjointsetunion/Node.java) + - 📁 **dynamicarray** + - 📄 [DynamicArray](src/main/java/com/thealgorithms/datastructures/dynamicarray/DynamicArray.java) + - 📁 **graphs** + - 📄 [AStar](src/main/java/com/thealgorithms/datastructures/graphs/AStar.java) + - 📄 [BellmanFord](src/main/java/com/thealgorithms/datastructures/graphs/BellmanFord.java) + - 📄 [BipartiteGraphDFS](src/main/java/com/thealgorithms/datastructures/graphs/BipartiteGraphDFS.java) + - 📄 [BoruvkaAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/BoruvkaAlgorithm.java) + - 📄 [ConnectedComponent](src/main/java/com/thealgorithms/datastructures/graphs/ConnectedComponent.java) + - 📄 [Cycles](src/main/java/com/thealgorithms/datastructures/graphs/Cycles.java) + - 📄 [DijkstraAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithm.java) + - 📄 [DijkstraOptimizedAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/DijkstraOptimizedAlgorithm.java) + - 📄 [EdmondsBlossomAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java) + - 📄 [FloydWarshall](src/main/java/com/thealgorithms/datastructures/graphs/FloydWarshall.java) + - 📄 [FordFulkerson](src/main/java/com/thealgorithms/datastructures/graphs/FordFulkerson.java) + - 📄 [Graphs](src/main/java/com/thealgorithms/datastructures/graphs/Graphs.java) + - 📄 [HamiltonianCycle](src/main/java/com/thealgorithms/datastructures/graphs/HamiltonianCycle.java) + - 📄 [JohnsonsAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithm.java) + - 📄 [KahnsAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/KahnsAlgorithm.java) + - 📄 [Kosaraju](src/main/java/com/thealgorithms/datastructures/graphs/Kosaraju.java) + - 📄 [Kruskal](src/main/java/com/thealgorithms/datastructures/graphs/Kruskal.java) + - 📄 [MatrixGraphs](src/main/java/com/thealgorithms/datastructures/graphs/MatrixGraphs.java) + - 📄 [PrimMST](src/main/java/com/thealgorithms/datastructures/graphs/PrimMST.java) + - 📄 [TarjansAlgorithm](src/main/java/com/thealgorithms/datastructures/graphs/TarjansAlgorithm.java) + - 📄 [UndirectedAdjacencyListGraph](src/main/java/com/thealgorithms/datastructures/graphs/UndirectedAdjacencyListGraph.java) + - 📄 [WelshPowell](src/main/java/com/thealgorithms/datastructures/graphs/WelshPowell.java) + - 📁 **hashmap** + - 📁 **hashing** + - 📄 [GenericHashMapUsingArray](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java) + - 📄 [GenericHashMapUsingArrayList](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayList.java) + - 📄 [HashMap](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/HashMap.java) + - 📄 [HashMapCuckooHashing](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/HashMapCuckooHashing.java) + - 📄 [Intersection](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/Intersection.java) + - 📄 [LinearProbingHashMap](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMap.java) + - 📄 [MainCuckooHashing](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/MainCuckooHashing.java) + - 📄 [MajorityElement](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/MajorityElement.java) + - 📄 [Map](src/main/java/com/thealgorithms/datastructures/hashmap/hashing/Map.java) + - 📁 **heaps** + - 📄 [EmptyHeapException](src/main/java/com/thealgorithms/datastructures/heaps/EmptyHeapException.java) + - 📄 [FibonacciHeap](src/main/java/com/thealgorithms/datastructures/heaps/FibonacciHeap.java) + - 📄 [GenericHeap](src/main/java/com/thealgorithms/datastructures/heaps/GenericHeap.java) + - 📄 [Heap](src/main/java/com/thealgorithms/datastructures/heaps/Heap.java) + - 📄 [HeapElement](src/main/java/com/thealgorithms/datastructures/heaps/HeapElement.java) + - 📄 [KthElementFinder](src/main/java/com/thealgorithms/datastructures/heaps/KthElementFinder.java) + - 📄 [LeftistHeap](src/main/java/com/thealgorithms/datastructures/heaps/LeftistHeap.java) + - 📄 [MaxHeap](src/main/java/com/thealgorithms/datastructures/heaps/MaxHeap.java) + - 📄 [MedianFinder](src/main/java/com/thealgorithms/datastructures/heaps/MedianFinder.java) + - 📄 [MergeKSortedArrays](src/main/java/com/thealgorithms/datastructures/heaps/MergeKSortedArrays.java) + - 📄 [MinHeap](src/main/java/com/thealgorithms/datastructures/heaps/MinHeap.java) + - 📄 [MinPriorityQueue](src/main/java/com/thealgorithms/datastructures/heaps/MinPriorityQueue.java) + - 📁 **lists** + - 📄 [CircleLinkedList](src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java) + - 📄 [CountSinglyLinkedListRecursion](src/main/java/com/thealgorithms/datastructures/lists/CountSinglyLinkedListRecursion.java) + - 📄 [CreateAndDetectLoop](src/main/java/com/thealgorithms/datastructures/lists/CreateAndDetectLoop.java) + - 📄 [CursorLinkedList](src/main/java/com/thealgorithms/datastructures/lists/CursorLinkedList.java) + - 📄 [DoublyLinkedList](src/main/java/com/thealgorithms/datastructures/lists/DoublyLinkedList.java) + - 📄 [MergeKSortedLinkedList](src/main/java/com/thealgorithms/datastructures/lists/MergeKSortedLinkedList.java) + - 📄 [MergeSortedArrayList](src/main/java/com/thealgorithms/datastructures/lists/MergeSortedArrayList.java) + - 📄 [MergeSortedSinglyLinkedList](src/main/java/com/thealgorithms/datastructures/lists/MergeSortedSinglyLinkedList.java) + - 📄 [QuickSortLinkedList](src/main/java/com/thealgorithms/datastructures/lists/QuickSortLinkedList.java) + - 📄 [RandomNode](src/main/java/com/thealgorithms/datastructures/lists/RandomNode.java) + - 📄 [ReverseKGroup](src/main/java/com/thealgorithms/datastructures/lists/ReverseKGroup.java) + - 📄 [RotateSinglyLinkedLists](src/main/java/com/thealgorithms/datastructures/lists/RotateSinglyLinkedLists.java) + - 📄 [SearchSinglyLinkedListRecursion](src/main/java/com/thealgorithms/datastructures/lists/SearchSinglyLinkedListRecursion.java) + - 📄 [SinglyLinkedList](src/main/java/com/thealgorithms/datastructures/lists/SinglyLinkedList.java) + - 📄 [SinglyLinkedListNode](src/main/java/com/thealgorithms/datastructures/lists/SinglyLinkedListNode.java) + - 📄 [SkipList](src/main/java/com/thealgorithms/datastructures/lists/SkipList.java) + - 📄 [SortedLinkedList](src/main/java/com/thealgorithms/datastructures/lists/SortedLinkedList.java) + - 📁 **queues** + - 📄 [CircularQueue](src/main/java/com/thealgorithms/datastructures/queues/CircularQueue.java) + - 📄 [Deque](src/main/java/com/thealgorithms/datastructures/queues/Deque.java) + - 📄 [GenericArrayListQueue](src/main/java/com/thealgorithms/datastructures/queues/GenericArrayListQueue.java) + - 📄 [LinkedQueue](src/main/java/com/thealgorithms/datastructures/queues/LinkedQueue.java) + - 📄 [PriorityQueues](src/main/java/com/thealgorithms/datastructures/queues/PriorityQueues.java) + - 📄 [Queue](src/main/java/com/thealgorithms/datastructures/queues/Queue.java) + - 📄 [QueueByTwoStacks](src/main/java/com/thealgorithms/datastructures/queues/QueueByTwoStacks.java) + - 📄 [SlidingWindowMaximum](src/main/java/com/thealgorithms/datastructures/queues/SlidingWindowMaximum.java) + - 📄 [TokenBucket](src/main/java/com/thealgorithms/datastructures/queues/TokenBucket.java) + - 📁 **stacks** + - 📄 [NodeStack](src/main/java/com/thealgorithms/datastructures/stacks/NodeStack.java) + - 📄 [ReverseStack](src/main/java/com/thealgorithms/datastructures/stacks/ReverseStack.java) + - 📄 [Stack](src/main/java/com/thealgorithms/datastructures/stacks/Stack.java) + - 📄 [StackArray](src/main/java/com/thealgorithms/datastructures/stacks/StackArray.java) + - 📄 [StackArrayList](src/main/java/com/thealgorithms/datastructures/stacks/StackArrayList.java) + - 📄 [StackOfLinkedList](src/main/java/com/thealgorithms/datastructures/stacks/StackOfLinkedList.java) + - 📁 **trees** + - 📄 [AVLSimple](src/main/java/com/thealgorithms/datastructures/trees/AVLSimple.java) + - 📄 [AVLTree](src/main/java/com/thealgorithms/datastructures/trees/AVLTree.java) + - 📄 [BSTFromSortedArray](src/main/java/com/thealgorithms/datastructures/trees/BSTFromSortedArray.java) + - 📄 [BSTIterative](src/main/java/com/thealgorithms/datastructures/trees/BSTIterative.java) + - 📄 [BSTRecursive](src/main/java/com/thealgorithms/datastructures/trees/BSTRecursive.java) + - 📄 [BSTRecursiveGeneric](src/main/java/com/thealgorithms/datastructures/trees/BSTRecursiveGeneric.java) + - 📄 [BTree](src/main/java/com/thealgorithms/datastructures/trees/BTree.java) + - 📄 [BinaryTree](src/main/java/com/thealgorithms/datastructures/trees/BinaryTree.java) + - 📄 [BoundaryTraversal](src/main/java/com/thealgorithms/datastructures/trees/BoundaryTraversal.java) + - 📄 [CeilInBinarySearchTree](src/main/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTree.java) + - 📄 [CheckBinaryTreeIsValidBST](src/main/java/com/thealgorithms/datastructures/trees/CheckBinaryTreeIsValidBST.java) + - 📄 [CheckIfBinaryTreeBalanced](src/main/java/com/thealgorithms/datastructures/trees/CheckIfBinaryTreeBalanced.java) + - 📄 [CheckTreeIsSymmetric](src/main/java/com/thealgorithms/datastructures/trees/CheckTreeIsSymmetric.java) + - 📄 [CreateBinaryTreeFromInorderPreorder](src/main/java/com/thealgorithms/datastructures/trees/CreateBinaryTreeFromInorderPreorder.java) + - 📄 [FenwickTree](src/main/java/com/thealgorithms/datastructures/trees/FenwickTree.java) + - 📄 [GenericTree](src/main/java/com/thealgorithms/datastructures/trees/GenericTree.java) + - 📄 [InorderTraversal](src/main/java/com/thealgorithms/datastructures/trees/InorderTraversal.java) + - 📄 [KDTree](src/main/java/com/thealgorithms/datastructures/trees/KDTree.java) + - 📄 [LCA](src/main/java/com/thealgorithms/datastructures/trees/LCA.java) + - 📄 [LazySegmentTree](src/main/java/com/thealgorithms/datastructures/trees/LazySegmentTree.java) + - 📄 [LevelOrderTraversal](src/main/java/com/thealgorithms/datastructures/trees/LevelOrderTraversal.java) + - 📄 [PostOrderTraversal](src/main/java/com/thealgorithms/datastructures/trees/PostOrderTraversal.java) + - 📄 [PreOrderTraversal](src/main/java/com/thealgorithms/datastructures/trees/PreOrderTraversal.java) + - 📄 [PrintTopViewofTree](src/main/java/com/thealgorithms/datastructures/trees/PrintTopViewofTree.java) + - 📄 [QuadTree](src/main/java/com/thealgorithms/datastructures/trees/QuadTree.java) + - 📄 [RedBlackBST](src/main/java/com/thealgorithms/datastructures/trees/RedBlackBST.java) + - 📄 [SameTreesCheck](src/main/java/com/thealgorithms/datastructures/trees/SameTreesCheck.java) + - 📄 [SegmentTree](src/main/java/com/thealgorithms/datastructures/trees/SegmentTree.java) + - 📄 [SplayTree](src/main/java/com/thealgorithms/datastructures/trees/SplayTree.java) + - 📄 [Treap](src/main/java/com/thealgorithms/datastructures/trees/Treap.java) + - 📄 [TreeRandomNode](src/main/java/com/thealgorithms/datastructures/trees/TreeRandomNode.java) + - 📄 [Trie](src/main/java/com/thealgorithms/datastructures/trees/Trie.java) + - 📄 [VerticalOrderTraversal](src/main/java/com/thealgorithms/datastructures/trees/VerticalOrderTraversal.java) + - 📄 [ZigzagTraversal](src/main/java/com/thealgorithms/datastructures/trees/ZigzagTraversal.java) + - 📄 [nearestRightKey](src/main/java/com/thealgorithms/datastructures/trees/nearestRightKey.java) + - 📁 **devutils** + - 📁 **entities** + - 📄 [ProcessDetails](src/main/java/com/thealgorithms/devutils/entities/ProcessDetails.java) + - 📁 **nodes** + - 📄 [LargeTreeNode](src/main/java/com/thealgorithms/devutils/nodes/LargeTreeNode.java) + - 📄 [Node](src/main/java/com/thealgorithms/devutils/nodes/Node.java) + - 📄 [SimpleNode](src/main/java/com/thealgorithms/devutils/nodes/SimpleNode.java) + - 📄 [SimpleTreeNode](src/main/java/com/thealgorithms/devutils/nodes/SimpleTreeNode.java) + - 📄 [TreeNode](src/main/java/com/thealgorithms/devutils/nodes/TreeNode.java) + - 📁 **searches** + - 📄 [MatrixSearchAlgorithm](src/main/java/com/thealgorithms/devutils/searches/MatrixSearchAlgorithm.java) + - 📄 [SearchAlgorithm](src/main/java/com/thealgorithms/devutils/searches/SearchAlgorithm.java) + - 📁 **divideandconquer** + - 📄 [BinaryExponentiation](src/main/java/com/thealgorithms/divideandconquer/BinaryExponentiation.java) + - 📄 [ClosestPair](src/main/java/com/thealgorithms/divideandconquer/ClosestPair.java) + - 📄 [CountingInversions](src/main/java/com/thealgorithms/divideandconquer/CountingInversions.java) + - 📄 [MedianOfTwoSortedArrays](src/main/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArrays.java) + - 📄 [SkylineAlgorithm](src/main/java/com/thealgorithms/divideandconquer/SkylineAlgorithm.java) + - 📄 [StrassenMatrixMultiplication](src/main/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplication.java) + - 📄 [TilingProblem](src/main/java/com/thealgorithms/divideandconquer/TilingProblem.java) + - 📁 **dynamicprogramming** + - 📄 [Abbreviation](src/main/java/com/thealgorithms/dynamicprogramming/Abbreviation.java) + - 📄 [AllConstruct](src/main/java/com/thealgorithms/dynamicprogramming/AllConstruct.java) + - 📄 [AssignmentUsingBitmask](src/main/java/com/thealgorithms/dynamicprogramming/AssignmentUsingBitmask.java) + - 📄 [BoardPath](src/main/java/com/thealgorithms/dynamicprogramming/BoardPath.java) + - 📄 [BoundaryFill](src/main/java/com/thealgorithms/dynamicprogramming/BoundaryFill.java) + - 📄 [BruteForceKnapsack](src/main/java/com/thealgorithms/dynamicprogramming/BruteForceKnapsack.java) + - 📄 [CatalanNumber](src/main/java/com/thealgorithms/dynamicprogramming/CatalanNumber.java) + - 📄 [ClimbingStairs](src/main/java/com/thealgorithms/dynamicprogramming/ClimbingStairs.java) + - 📄 [CoinChange](src/main/java/com/thealgorithms/dynamicprogramming/CoinChange.java) + - 📄 [CountFriendsPairing](src/main/java/com/thealgorithms/dynamicprogramming/CountFriendsPairing.java) + - 📄 [DiceThrow](src/main/java/com/thealgorithms/dynamicprogramming/DiceThrow.java) + - 📄 [EditDistance](src/main/java/com/thealgorithms/dynamicprogramming/EditDistance.java) + - 📄 [EggDropping](src/main/java/com/thealgorithms/dynamicprogramming/EggDropping.java) + - 📄 [Fibonacci](src/main/java/com/thealgorithms/dynamicprogramming/Fibonacci.java) + - 📄 [KadaneAlgorithm](src/main/java/com/thealgorithms/dynamicprogramming/KadaneAlgorithm.java) + - 📄 [Knapsack](src/main/java/com/thealgorithms/dynamicprogramming/Knapsack.java) + - 📄 [KnapsackMemoization](src/main/java/com/thealgorithms/dynamicprogramming/KnapsackMemoization.java) + - 📄 [KnapsackZeroOne](src/main/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOne.java) + - 📄 [KnapsackZeroOneTabulation](src/main/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOneTabulation.java) + - 📄 [LevenshteinDistance](src/main/java/com/thealgorithms/dynamicprogramming/LevenshteinDistance.java) + - 📄 [LongestAlternatingSubsequence](src/main/java/com/thealgorithms/dynamicprogramming/LongestAlternatingSubsequence.java) + - 📄 [LongestArithmeticSubsequence](src/main/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequence.java) + - 📄 [LongestCommonSubsequence](src/main/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequence.java) + - 📄 [LongestIncreasingSubsequence](src/main/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequence.java) + - 📄 [LongestIncreasingSubsequenceNLogN](src/main/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequenceNLogN.java) + - 📄 [LongestPalindromicSubsequence](src/main/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubsequence.java) + - 📄 [LongestPalindromicSubstring](src/main/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubstring.java) + - 📄 [LongestValidParentheses](src/main/java/com/thealgorithms/dynamicprogramming/LongestValidParentheses.java) + - 📄 [MatrixChainMultiplication](src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplication.java) + - 📄 [MatrixChainRecursiveTopDownMemoisation](src/main/java/com/thealgorithms/dynamicprogramming/MatrixChainRecursiveTopDownMemoisation.java) + - 📄 [MaximumSumOfNonAdjacentElements](src/main/java/com/thealgorithms/dynamicprogramming/MaximumSumOfNonAdjacentElements.java) + - 📄 [MinimumPathSum](src/main/java/com/thealgorithms/dynamicprogramming/MinimumPathSum.java) + - 📄 [MinimumSumPartition](src/main/java/com/thealgorithms/dynamicprogramming/MinimumSumPartition.java) + - 📄 [NewManShanksPrime](src/main/java/com/thealgorithms/dynamicprogramming/NewManShanksPrime.java) + - 📄 [OptimalJobScheduling](src/main/java/com/thealgorithms/dynamicprogramming/OptimalJobScheduling.java) + - 📄 [PalindromicPartitioning](src/main/java/com/thealgorithms/dynamicprogramming/PalindromicPartitioning.java) + - 📄 [PartitionProblem](src/main/java/com/thealgorithms/dynamicprogramming/PartitionProblem.java) + - 📄 [RegexMatching](src/main/java/com/thealgorithms/dynamicprogramming/RegexMatching.java) + - 📄 [RodCutting](src/main/java/com/thealgorithms/dynamicprogramming/RodCutting.java) + - 📄 [ShortestCommonSupersequenceLength](src/main/java/com/thealgorithms/dynamicprogramming/ShortestCommonSupersequenceLength.java) + - 📄 [SubsetCount](src/main/java/com/thealgorithms/dynamicprogramming/SubsetCount.java) + - 📄 [SubsetSum](src/main/java/com/thealgorithms/dynamicprogramming/SubsetSum.java) + - 📄 [SubsetSumSpaceOptimized](src/main/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimized.java) + - 📄 [SumOfSubset](src/main/java/com/thealgorithms/dynamicprogramming/SumOfSubset.java) + - 📄 [TreeMatching](src/main/java/com/thealgorithms/dynamicprogramming/TreeMatching.java) + - 📄 [Tribonacci](src/main/java/com/thealgorithms/dynamicprogramming/Tribonacci.java) + - 📄 [UniquePaths](src/main/java/com/thealgorithms/dynamicprogramming/UniquePaths.java) + - 📄 [UniqueSubsequencesCount](src/main/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCount.java) + - 📄 [WildcardMatching](src/main/java/com/thealgorithms/dynamicprogramming/WildcardMatching.java) + - 📄 [WineProblem](src/main/java/com/thealgorithms/dynamicprogramming/WineProblem.java) + - 📁 **geometry** + - 📄 [BresenhamLine](src/main/java/com/thealgorithms/geometry/BresenhamLine.java) + - 📄 [ConvexHull](src/main/java/com/thealgorithms/geometry/ConvexHull.java) + - 📄 [GrahamScan](src/main/java/com/thealgorithms/geometry/GrahamScan.java) + - 📄 [MidpointCircle](src/main/java/com/thealgorithms/geometry/MidpointCircle.java) + - 📄 [MidpointEllipse](src/main/java/com/thealgorithms/geometry/MidpointEllipse.java) + - 📄 [Point](src/main/java/com/thealgorithms/geometry/Point.java) + - 📁 **graph** + - 📄 [ConstrainedShortestPath](src/main/java/com/thealgorithms/graph/ConstrainedShortestPath.java) + - 📄 [StronglyConnectedComponentOptimized](src/main/java/com/thealgorithms/graph/StronglyConnectedComponentOptimized.java) + - 📄 [TravelingSalesman](src/main/java/com/thealgorithms/graph/TravelingSalesman.java) + - 📁 **greedyalgorithms** + - 📄 [ActivitySelection](src/main/java/com/thealgorithms/greedyalgorithms/ActivitySelection.java) + - 📄 [BandwidthAllocation](src/main/java/com/thealgorithms/greedyalgorithms/BandwidthAllocation.java) + - 📄 [BinaryAddition](src/main/java/com/thealgorithms/greedyalgorithms/BinaryAddition.java) + - 📄 [CoinChange](src/main/java/com/thealgorithms/greedyalgorithms/CoinChange.java) + - 📄 [DigitSeparation](src/main/java/com/thealgorithms/greedyalgorithms/DigitSeparation.java) + - 📄 [EgyptianFraction](src/main/java/com/thealgorithms/greedyalgorithms/EgyptianFraction.java) + - 📄 [FractionalKnapsack](src/main/java/com/thealgorithms/greedyalgorithms/FractionalKnapsack.java) + - 📄 [GaleShapley](src/main/java/com/thealgorithms/greedyalgorithms/GaleShapley.java) + - 📄 [JobSequencing](src/main/java/com/thealgorithms/greedyalgorithms/JobSequencing.java) + - 📄 [KCenters](src/main/java/com/thealgorithms/greedyalgorithms/KCenters.java) + - 📄 [MergeIntervals](src/main/java/com/thealgorithms/greedyalgorithms/MergeIntervals.java) + - 📄 [MinimizingLateness](src/main/java/com/thealgorithms/greedyalgorithms/MinimizingLateness.java) + - 📄 [MinimumWaitingTime](src/main/java/com/thealgorithms/greedyalgorithms/MinimumWaitingTime.java) + - 📄 [OptimalFileMerging](src/main/java/com/thealgorithms/greedyalgorithms/OptimalFileMerging.java) + - 📄 [StockProfitCalculator](src/main/java/com/thealgorithms/greedyalgorithms/StockProfitCalculator.java) + - 📁 **io** + - 📄 [BufferedReader](src/main/java/com/thealgorithms/io/BufferedReader.java) + - 📁 **lineclipping** + - 📄 [CohenSutherland](src/main/java/com/thealgorithms/lineclipping/CohenSutherland.java) + - 📄 [LiangBarsky](src/main/java/com/thealgorithms/lineclipping/LiangBarsky.java) + - 📁 **utils** + - 📄 [Line](src/main/java/com/thealgorithms/lineclipping/utils/Line.java) + - 📄 [Point](src/main/java/com/thealgorithms/lineclipping/utils/Point.java) + - 📁 **maths** + - 📄 [ADTFraction](src/main/java/com/thealgorithms/maths/ADTFraction.java) + - 📄 [AbsoluteMax](src/main/java/com/thealgorithms/maths/AbsoluteMax.java) + - 📄 [AbsoluteMin](src/main/java/com/thealgorithms/maths/AbsoluteMin.java) + - 📄 [AbsoluteValue](src/main/java/com/thealgorithms/maths/AbsoluteValue.java) + - 📄 [AliquotSum](src/main/java/com/thealgorithms/maths/AliquotSum.java) + - 📄 [AmicableNumber](src/main/java/com/thealgorithms/maths/AmicableNumber.java) + - 📄 [Area](src/main/java/com/thealgorithms/maths/Area.java) + - 📄 [Armstrong](src/main/java/com/thealgorithms/maths/Armstrong.java) + - 📄 [AutoCorrelation](src/main/java/com/thealgorithms/maths/AutoCorrelation.java) + - 📄 [AutomorphicNumber](src/main/java/com/thealgorithms/maths/AutomorphicNumber.java) + - 📄 [Average](src/main/java/com/thealgorithms/maths/Average.java) + - 📄 [BinaryPow](src/main/java/com/thealgorithms/maths/BinaryPow.java) + - 📄 [BinomialCoefficient](src/main/java/com/thealgorithms/maths/BinomialCoefficient.java) + - 📄 [CatalanNumbers](src/main/java/com/thealgorithms/maths/CatalanNumbers.java) + - 📄 [Ceil](src/main/java/com/thealgorithms/maths/Ceil.java) + - 📄 [ChineseRemainderTheorem](src/main/java/com/thealgorithms/maths/ChineseRemainderTheorem.java) + - 📄 [CircularConvolutionFFT](src/main/java/com/thealgorithms/maths/CircularConvolutionFFT.java) + - 📄 [CollatzConjecture](src/main/java/com/thealgorithms/maths/CollatzConjecture.java) + - 📄 [Combinations](src/main/java/com/thealgorithms/maths/Combinations.java) + - 📄 [Convolution](src/main/java/com/thealgorithms/maths/Convolution.java) + - 📄 [ConvolutionFFT](src/main/java/com/thealgorithms/maths/ConvolutionFFT.java) + - 📄 [CrossCorrelation](src/main/java/com/thealgorithms/maths/CrossCorrelation.java) + - 📄 [DeterminantOfMatrix](src/main/java/com/thealgorithms/maths/DeterminantOfMatrix.java) + - 📄 [DigitalRoot](src/main/java/com/thealgorithms/maths/DigitalRoot.java) + - 📄 [DistanceFormula](src/main/java/com/thealgorithms/maths/DistanceFormula.java) + - 📄 [DudeneyNumber](src/main/java/com/thealgorithms/maths/DudeneyNumber.java) + - 📄 [EulerMethod](src/main/java/com/thealgorithms/maths/EulerMethod.java) + - 📄 [EulersFunction](src/main/java/com/thealgorithms/maths/EulersFunction.java) + - 📄 [FFT](src/main/java/com/thealgorithms/maths/FFT.java) + - 📄 [FFTBluestein](src/main/java/com/thealgorithms/maths/FFTBluestein.java) + - 📄 [Factorial](src/main/java/com/thealgorithms/maths/Factorial.java) + - 📄 [FactorialRecursion](src/main/java/com/thealgorithms/maths/FactorialRecursion.java) + - 📄 [FastExponentiation](src/main/java/com/thealgorithms/maths/FastExponentiation.java) + - 📄 [FastInverseSqrt](src/main/java/com/thealgorithms/maths/FastInverseSqrt.java) + - 📄 [FibonacciJavaStreams](src/main/java/com/thealgorithms/maths/FibonacciJavaStreams.java) + - 📄 [FibonacciLoop](src/main/java/com/thealgorithms/maths/FibonacciLoop.java) + - 📄 [FibonacciNumberCheck](src/main/java/com/thealgorithms/maths/FibonacciNumberCheck.java) + - 📄 [FibonacciNumberGoldenRation](src/main/java/com/thealgorithms/maths/FibonacciNumberGoldenRation.java) + - 📄 [FindKthNumber](src/main/java/com/thealgorithms/maths/FindKthNumber.java) + - 📄 [FindMax](src/main/java/com/thealgorithms/maths/FindMax.java) + - 📄 [FindMaxRecursion](src/main/java/com/thealgorithms/maths/FindMaxRecursion.java) + - 📄 [FindMin](src/main/java/com/thealgorithms/maths/FindMin.java) + - 📄 [FindMinRecursion](src/main/java/com/thealgorithms/maths/FindMinRecursion.java) + - 📄 [Floor](src/main/java/com/thealgorithms/maths/Floor.java) + - 📄 [FrizzyNumber](src/main/java/com/thealgorithms/maths/FrizzyNumber.java) + - 📄 [GCD](src/main/java/com/thealgorithms/maths/GCD.java) + - 📄 [GCDRecursion](src/main/java/com/thealgorithms/maths/GCDRecursion.java) + - 📄 [Gaussian](src/main/java/com/thealgorithms/maths/Gaussian.java) + - 📄 [GenericRoot](src/main/java/com/thealgorithms/maths/GenericRoot.java) + - 📄 [GoldbachConjecture](src/main/java/com/thealgorithms/maths/GoldbachConjecture.java) + - 📄 [HarshadNumber](src/main/java/com/thealgorithms/maths/HarshadNumber.java) + - 📄 [HeronsFormula](src/main/java/com/thealgorithms/maths/HeronsFormula.java) + - 📄 [JosephusProblem](src/main/java/com/thealgorithms/maths/JosephusProblem.java) + - 📄 [JugglerSequence](src/main/java/com/thealgorithms/maths/JugglerSequence.java) + - 📄 [KaprekarNumbers](src/main/java/com/thealgorithms/maths/KaprekarNumbers.java) + - 📄 [KaratsubaMultiplication](src/main/java/com/thealgorithms/maths/KaratsubaMultiplication.java) + - 📄 [KeithNumber](src/main/java/com/thealgorithms/maths/KeithNumber.java) + - 📄 [KrishnamurthyNumber](src/main/java/com/thealgorithms/maths/KrishnamurthyNumber.java) + - 📄 [LeastCommonMultiple](src/main/java/com/thealgorithms/maths/LeastCommonMultiple.java) + - 📄 [LeonardoNumber](src/main/java/com/thealgorithms/maths/LeonardoNumber.java) + - 📄 [LinearDiophantineEquationsSolver](src/main/java/com/thealgorithms/maths/LinearDiophantineEquationsSolver.java) + - 📄 [LongDivision](src/main/java/com/thealgorithms/maths/LongDivision.java) + - 📄 [LucasSeries](src/main/java/com/thealgorithms/maths/LucasSeries.java) + - 📄 [MagicSquare](src/main/java/com/thealgorithms/maths/MagicSquare.java) + - 📄 [MathBuilder](src/main/java/com/thealgorithms/maths/MathBuilder.java) + - 📄 [MaxValue](src/main/java/com/thealgorithms/maths/MaxValue.java) + - 📄 [Means](src/main/java/com/thealgorithms/maths/Means.java) + - 📄 [Median](src/main/java/com/thealgorithms/maths/Median.java) + - 📄 [MinValue](src/main/java/com/thealgorithms/maths/MinValue.java) + - 📄 [Mode](src/main/java/com/thealgorithms/maths/Mode.java) + - 📄 [NonRepeatingElement](src/main/java/com/thealgorithms/maths/NonRepeatingElement.java) + - 📄 [NthUglyNumber](src/main/java/com/thealgorithms/maths/NthUglyNumber.java) + - 📄 [NumberOfDigits](src/main/java/com/thealgorithms/maths/NumberOfDigits.java) + - 📄 [PalindromeNumber](src/main/java/com/thealgorithms/maths/PalindromeNumber.java) + - 📄 [ParseInteger](src/main/java/com/thealgorithms/maths/ParseInteger.java) + - 📄 [PascalTriangle](src/main/java/com/thealgorithms/maths/PascalTriangle.java) + - 📄 [PerfectCube](src/main/java/com/thealgorithms/maths/PerfectCube.java) + - 📄 [PerfectNumber](src/main/java/com/thealgorithms/maths/PerfectNumber.java) + - 📄 [PerfectSquare](src/main/java/com/thealgorithms/maths/PerfectSquare.java) + - 📄 [Perimeter](src/main/java/com/thealgorithms/maths/Perimeter.java) + - 📄 [PiNilakantha](src/main/java/com/thealgorithms/maths/PiNilakantha.java) + - 📄 [PollardRho](src/main/java/com/thealgorithms/maths/PollardRho.java) + - 📄 [Pow](src/main/java/com/thealgorithms/maths/Pow.java) + - 📄 [PowerOfTwoOrNot](src/main/java/com/thealgorithms/maths/PowerOfTwoOrNot.java) + - 📄 [PowerUsingRecursion](src/main/java/com/thealgorithms/maths/PowerUsingRecursion.java) + - 📁 **Prime** + - 📄 [LiouvilleLambdaFunction](src/main/java/com/thealgorithms/maths/Prime/LiouvilleLambdaFunction.java) + - 📄 [MillerRabinPrimalityCheck](src/main/java/com/thealgorithms/maths/Prime/MillerRabinPrimalityCheck.java) + - 📄 [MobiusFunction](src/main/java/com/thealgorithms/maths/Prime/MobiusFunction.java) + - 📄 [PrimeCheck](src/main/java/com/thealgorithms/maths/Prime/PrimeCheck.java) + - 📄 [PrimeFactorization](src/main/java/com/thealgorithms/maths/Prime/PrimeFactorization.java) + - 📄 [SquareFreeInteger](src/main/java/com/thealgorithms/maths/Prime/SquareFreeInteger.java) + - 📄 [PronicNumber](src/main/java/com/thealgorithms/maths/PronicNumber.java) + - 📄 [PythagoreanTriple](src/main/java/com/thealgorithms/maths/PythagoreanTriple.java) + - 📄 [QuadraticEquationSolver](src/main/java/com/thealgorithms/maths/QuadraticEquationSolver.java) + - 📄 [ReverseNumber](src/main/java/com/thealgorithms/maths/ReverseNumber.java) + - 📄 [RomanNumeralUtil](src/main/java/com/thealgorithms/maths/RomanNumeralUtil.java) + - 📄 [SecondMinMax](src/main/java/com/thealgorithms/maths/SecondMinMax.java) + - 📄 [SieveOfEratosthenes](src/main/java/com/thealgorithms/maths/SieveOfEratosthenes.java) + - 📄 [SimpsonIntegration](src/main/java/com/thealgorithms/maths/SimpsonIntegration.java) + - 📄 [SolovayStrassenPrimalityTest](src/main/java/com/thealgorithms/maths/SolovayStrassenPrimalityTest.java) + - 📄 [SquareRootWithBabylonianMethod](src/main/java/com/thealgorithms/maths/SquareRootWithBabylonianMethod.java) + - 📄 [SquareRootWithNewtonRaphsonMethod](src/main/java/com/thealgorithms/maths/SquareRootWithNewtonRaphsonMethod.java) + - 📄 [StandardDeviation](src/main/java/com/thealgorithms/maths/StandardDeviation.java) + - 📄 [StandardScore](src/main/java/com/thealgorithms/maths/StandardScore.java) + - 📄 [StrobogrammaticNumber](src/main/java/com/thealgorithms/maths/StrobogrammaticNumber.java) + - 📄 [SumOfArithmeticSeries](src/main/java/com/thealgorithms/maths/SumOfArithmeticSeries.java) + - 📄 [SumOfDigits](src/main/java/com/thealgorithms/maths/SumOfDigits.java) + - 📄 [SumOfOddNumbers](src/main/java/com/thealgorithms/maths/SumOfOddNumbers.java) + - 📄 [SumWithoutArithmeticOperators](src/main/java/com/thealgorithms/maths/SumWithoutArithmeticOperators.java) + - 📄 [TrinomialTriangle](src/main/java/com/thealgorithms/maths/TrinomialTriangle.java) + - 📄 [TwinPrime](src/main/java/com/thealgorithms/maths/TwinPrime.java) + - 📄 [UniformNumbers](src/main/java/com/thealgorithms/maths/UniformNumbers.java) + - 📄 [VampireNumber](src/main/java/com/thealgorithms/maths/VampireNumber.java) + - 📄 [VectorCrossProduct](src/main/java/com/thealgorithms/maths/VectorCrossProduct.java) + - 📄 [Volume](src/main/java/com/thealgorithms/maths/Volume.java) + - 📁 **matrix** + - 📄 [InverseOfMatrix](src/main/java/com/thealgorithms/matrix/InverseOfMatrix.java) + - 📄 [MatrixMultiplication](src/main/java/com/thealgorithms/matrix/MatrixMultiplication.java) + - 📄 [MatrixRank](src/main/java/com/thealgorithms/matrix/MatrixRank.java) + - 📄 [MatrixTranspose](src/main/java/com/thealgorithms/matrix/MatrixTranspose.java) + - 📄 [MedianOfMatrix](src/main/java/com/thealgorithms/matrix/MedianOfMatrix.java) + - 📄 [MirrorOfMatrix](src/main/java/com/thealgorithms/matrix/MirrorOfMatrix.java) + - 📄 [PrintAMatrixInSpiralOrder](src/main/java/com/thealgorithms/matrix/PrintAMatrixInSpiralOrder.java) + - 📄 [RotateMatrixBy90Degrees](src/main/java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java) + - 📄 [SolveSystem](src/main/java/com/thealgorithms/matrix/SolveSystem.java) + - 📁 **matrixexponentiation** + - 📄 [Fibonacci](src/main/java/com/thealgorithms/matrix/matrixexponentiation/Fibonacci.java) + - 📁 **utils** + - 📄 [MatrixUtil](src/main/java/com/thealgorithms/matrix/utils/MatrixUtil.java) + - 📁 **misc** + - 📄 [ColorContrastRatio](src/main/java/com/thealgorithms/misc/ColorContrastRatio.java) + - 📄 [MapReduce](src/main/java/com/thealgorithms/misc/MapReduce.java) + - 📄 [MedianOfRunningArray](src/main/java/com/thealgorithms/misc/MedianOfRunningArray.java) + - 📄 [MedianOfRunningArrayByte](src/main/java/com/thealgorithms/misc/MedianOfRunningArrayByte.java) + - 📄 [MedianOfRunningArrayDouble](src/main/java/com/thealgorithms/misc/MedianOfRunningArrayDouble.java) + - 📄 [MedianOfRunningArrayFloat](src/main/java/com/thealgorithms/misc/MedianOfRunningArrayFloat.java) + - 📄 [MedianOfRunningArrayInteger](src/main/java/com/thealgorithms/misc/MedianOfRunningArrayInteger.java) + - 📄 [MedianOfRunningArrayLong](src/main/java/com/thealgorithms/misc/MedianOfRunningArrayLong.java) + - 📄 [PalindromePrime](src/main/java/com/thealgorithms/misc/PalindromePrime.java) + - 📄 [PalindromeSinglyLinkedList](src/main/java/com/thealgorithms/misc/PalindromeSinglyLinkedList.java) + - 📄 [RangeInSortedArray](src/main/java/com/thealgorithms/misc/RangeInSortedArray.java) + - 📄 [ShuffleArray](src/main/java/com/thealgorithms/misc/ShuffleArray.java) + - 📄 [Sparsity](src/main/java/com/thealgorithms/misc/Sparsity.java) + - 📄 [ThreeSumProblem](src/main/java/com/thealgorithms/misc/ThreeSumProblem.java) + - 📄 [TwoSumProblem](src/main/java/com/thealgorithms/misc/TwoSumProblem.java) + - 📁 **others** + - 📄 [ArrayLeftRotation](src/main/java/com/thealgorithms/others/ArrayLeftRotation.java) + - 📄 [ArrayRightRotation](src/main/java/com/thealgorithms/others/ArrayRightRotation.java) + - 📄 [BFPRT](src/main/java/com/thealgorithms/others/BFPRT.java) + - 📄 [BankersAlgorithm](src/main/java/com/thealgorithms/others/BankersAlgorithm.java) + - 📄 [BoyerMoore](src/main/java/com/thealgorithms/others/BoyerMoore.java) + - 📄 [BrianKernighanAlgorithm](src/main/java/com/thealgorithms/others/BrianKernighanAlgorithm.java) + - 📄 [CRC16](src/main/java/com/thealgorithms/others/CRC16.java) + - 📄 [CRC32](src/main/java/com/thealgorithms/others/CRC32.java) + - 📄 [CRCAlgorithm](src/main/java/com/thealgorithms/others/CRCAlgorithm.java) + - 📄 [Conway](src/main/java/com/thealgorithms/others/Conway.java) + - 📄 [Damm](src/main/java/com/thealgorithms/others/Damm.java) + - 📄 [Dijkstra](src/main/java/com/thealgorithms/others/Dijkstra.java) + - 📄 [FloydTriangle](src/main/java/com/thealgorithms/others/FloydTriangle.java) + - 📄 [GaussLegendre](src/main/java/com/thealgorithms/others/GaussLegendre.java) + - 📄 [HappyNumbersSeq](src/main/java/com/thealgorithms/others/HappyNumbersSeq.java) + - 📄 [Huffman](src/main/java/com/thealgorithms/others/Huffman.java) + - 📄 [Implementing_auto_completing_features_using_trie](src/main/java/com/thealgorithms/others/Implementing_auto_completing_features_using_trie.java) + - 📄 [InsertDeleteInArray](src/main/java/com/thealgorithms/others/InsertDeleteInArray.java) + - 📄 [KochSnowflake](src/main/java/com/thealgorithms/others/KochSnowflake.java) + - 📄 [Krishnamurthy](src/main/java/com/thealgorithms/others/Krishnamurthy.java) + - 📄 [LineSweep](src/main/java/com/thealgorithms/others/LineSweep.java) + - 📄 [LinearCongruentialGenerator](src/main/java/com/thealgorithms/others/LinearCongruentialGenerator.java) + - 📄 [LowestBasePalindrome](src/main/java/com/thealgorithms/others/LowestBasePalindrome.java) + - 📄 [Luhn](src/main/java/com/thealgorithms/others/Luhn.java) + - 📄 [Mandelbrot](src/main/java/com/thealgorithms/others/Mandelbrot.java) + - 📄 [MaximumSlidingWindow](src/main/java/com/thealgorithms/others/MaximumSlidingWindow.java) + - 📄 [MaximumSumOfDistinctSubarraysWithLengthK](src/main/java/com/thealgorithms/others/MaximumSumOfDistinctSubarraysWithLengthK.java) + - 📄 [MemoryManagementAlgorithms](src/main/java/com/thealgorithms/others/MemoryManagementAlgorithms.java) + - 📄 [MiniMaxAlgorithm](src/main/java/com/thealgorithms/others/MiniMaxAlgorithm.java) + - 📄 [PageRank](src/main/java/com/thealgorithms/others/PageRank.java) + - 📄 [PasswordGen](src/main/java/com/thealgorithms/others/PasswordGen.java) + - 📄 [PerlinNoise](src/main/java/com/thealgorithms/others/PerlinNoise.java) + - 📄 [PrintAMatrixInSpiralOrder](src/main/java/com/thealgorithms/others/PrintAMatrixInSpiralOrder.java) + - 📄 [QueueUsingTwoStacks](src/main/java/com/thealgorithms/others/QueueUsingTwoStacks.java) + - 📄 [RemoveDuplicateFromString](src/main/java/com/thealgorithms/others/RemoveDuplicateFromString.java) + - 📄 [ReverseStackUsingRecursion](src/main/java/com/thealgorithms/others/ReverseStackUsingRecursion.java) + - 📄 [SkylineProblem](src/main/java/com/thealgorithms/others/SkylineProblem.java) + - 📄 [TwoPointers](src/main/java/com/thealgorithms/others/TwoPointers.java) + - 📄 [Verhoeff](src/main/java/com/thealgorithms/others/Verhoeff.java) + - 📁 **cn** + - 📄 [HammingDistance](src/main/java/com/thealgorithms/others/cn/HammingDistance.java) + - 📁 **puzzlesandgames** + - 📄 [Sudoku](src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java) + - 📄 [TowerOfHanoi](src/main/java/com/thealgorithms/puzzlesandgames/TowerOfHanoi.java) + - 📄 [WordBoggle](src/main/java/com/thealgorithms/puzzlesandgames/WordBoggle.java) + - 📁 **randomized** + - 📄 [KargerMinCut](src/main/java/com/thealgorithms/randomized/KargerMinCut.java) + - 📄 [MonteCarloIntegration](src/main/java/com/thealgorithms/randomized/MonteCarloIntegration.java) + - 📄 [RandomizedClosestPair](src/main/java/com/thealgorithms/randomized/RandomizedClosestPair.java) + - 📄 [RandomizedMatrixMultiplicationVerification](src/main/java/com/thealgorithms/randomized/RandomizedMatrixMultiplicationVerification.java) + - 📄 [RandomizedQuickSort](src/main/java/com/thealgorithms/randomized/RandomizedQuickSort.java) + - 📄 [ReservoirSampling](src/main/java/com/thealgorithms/randomized/ReservoirSampling.java) + - 📁 **recursion** + - 📄 [FibonacciSeries](src/main/java/com/thealgorithms/recursion/FibonacciSeries.java) + - 📄 [GenerateSubsets](src/main/java/com/thealgorithms/recursion/GenerateSubsets.java) + - 📁 **scheduling** + - 📄 [AgingScheduling](src/main/java/com/thealgorithms/scheduling/AgingScheduling.java) + - 📄 [EDFScheduling](src/main/java/com/thealgorithms/scheduling/EDFScheduling.java) + - 📄 [FCFSScheduling](src/main/java/com/thealgorithms/scheduling/FCFSScheduling.java) + - 📄 [FairShareScheduling](src/main/java/com/thealgorithms/scheduling/FairShareScheduling.java) + - 📄 [GangScheduling](src/main/java/com/thealgorithms/scheduling/GangScheduling.java) + - 📄 [HighestResponseRatioNextScheduling](src/main/java/com/thealgorithms/scheduling/HighestResponseRatioNextScheduling.java) + - 📄 [JobSchedulingWithDeadline](src/main/java/com/thealgorithms/scheduling/JobSchedulingWithDeadline.java) + - 📄 [LotteryScheduling](src/main/java/com/thealgorithms/scheduling/LotteryScheduling.java) + - 📄 [MLFQScheduler](src/main/java/com/thealgorithms/scheduling/MLFQScheduler.java) + - 📄 [MultiAgentScheduling](src/main/java/com/thealgorithms/scheduling/MultiAgentScheduling.java) + - 📄 [NonPreemptivePriorityScheduling](src/main/java/com/thealgorithms/scheduling/NonPreemptivePriorityScheduling.java) + - 📄 [PreemptivePriorityScheduling](src/main/java/com/thealgorithms/scheduling/PreemptivePriorityScheduling.java) + - 📄 [ProportionalFairScheduling](src/main/java/com/thealgorithms/scheduling/ProportionalFairScheduling.java) + - 📄 [RRScheduling](src/main/java/com/thealgorithms/scheduling/RRScheduling.java) + - 📄 [RandomScheduling](src/main/java/com/thealgorithms/scheduling/RandomScheduling.java) + - 📄 [SJFScheduling](src/main/java/com/thealgorithms/scheduling/SJFScheduling.java) + - 📄 [SRTFScheduling](src/main/java/com/thealgorithms/scheduling/SRTFScheduling.java) + - 📄 [SelfAdjustingScheduling](src/main/java/com/thealgorithms/scheduling/SelfAdjustingScheduling.java) + - 📄 [SlackTimeScheduling](src/main/java/com/thealgorithms/scheduling/SlackTimeScheduling.java) + - 📁 **diskscheduling** + - 📄 [CircularLookScheduling](src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularLookScheduling.java) + - 📄 [CircularScanScheduling](src/main/java/com/thealgorithms/scheduling/diskscheduling/CircularScanScheduling.java) + - 📄 [LookScheduling](src/main/java/com/thealgorithms/scheduling/diskscheduling/LookScheduling.java) + - 📄 [SSFScheduling](src/main/java/com/thealgorithms/scheduling/diskscheduling/SSFScheduling.java) + - 📄 [ScanScheduling](src/main/java/com/thealgorithms/scheduling/diskscheduling/ScanScheduling.java) + - 📁 **searches** + - 📄 [BM25InvertedIndex](src/main/java/com/thealgorithms/searches/BM25InvertedIndex.java) + - 📄 [BinarySearch](src/main/java/com/thealgorithms/searches/BinarySearch.java) + - 📄 [BinarySearch2dArray](src/main/java/com/thealgorithms/searches/BinarySearch2dArray.java) + - 📄 [BoyerMoore](src/main/java/com/thealgorithms/searches/BoyerMoore.java) + - 📄 [BreadthFirstSearch](src/main/java/com/thealgorithms/searches/BreadthFirstSearch.java) + - 📄 [DepthFirstSearch](src/main/java/com/thealgorithms/searches/DepthFirstSearch.java) + - 📄 [ExponentalSearch](src/main/java/com/thealgorithms/searches/ExponentalSearch.java) + - 📄 [FibonacciSearch](src/main/java/com/thealgorithms/searches/FibonacciSearch.java) + - 📄 [HowManyTimesRotated](src/main/java/com/thealgorithms/searches/HowManyTimesRotated.java) + - 📄 [InterpolationSearch](src/main/java/com/thealgorithms/searches/InterpolationSearch.java) + - 📄 [IterativeBinarySearch](src/main/java/com/thealgorithms/searches/IterativeBinarySearch.java) + - 📄 [IterativeTernarySearch](src/main/java/com/thealgorithms/searches/IterativeTernarySearch.java) + - 📄 [JumpSearch](src/main/java/com/thealgorithms/searches/JumpSearch.java) + - 📄 [KMPSearch](src/main/java/com/thealgorithms/searches/KMPSearch.java) + - 📄 [LinearSearch](src/main/java/com/thealgorithms/searches/LinearSearch.java) + - 📄 [LinearSearchThread](src/main/java/com/thealgorithms/searches/LinearSearchThread.java) + - 📄 [LowerBound](src/main/java/com/thealgorithms/searches/LowerBound.java) + - 📄 [MonteCarloTreeSearch](src/main/java/com/thealgorithms/searches/MonteCarloTreeSearch.java) + - 📄 [OrderAgnosticBinarySearch](src/main/java/com/thealgorithms/searches/OrderAgnosticBinarySearch.java) + - 📄 [PerfectBinarySearch](src/main/java/com/thealgorithms/searches/PerfectBinarySearch.java) + - 📄 [QuickSelect](src/main/java/com/thealgorithms/searches/QuickSelect.java) + - 📄 [RabinKarpAlgorithm](src/main/java/com/thealgorithms/searches/RabinKarpAlgorithm.java) + - 📄 [RandomSearch](src/main/java/com/thealgorithms/searches/RandomSearch.java) + - 📄 [RecursiveBinarySearch](src/main/java/com/thealgorithms/searches/RecursiveBinarySearch.java) + - 📄 [RowColumnWiseSorted2dArrayBinarySearch](src/main/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearch.java) + - 📄 [SaddlebackSearch](src/main/java/com/thealgorithms/searches/SaddlebackSearch.java) + - 📄 [SearchInARowAndColWiseSortedMatrix](src/main/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrix.java) + - 📄 [SortOrderAgnosticBinarySearch](src/main/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearch.java) + - 📄 [SquareRootBinarySearch](src/main/java/com/thealgorithms/searches/SquareRootBinarySearch.java) + - 📄 [TernarySearch](src/main/java/com/thealgorithms/searches/TernarySearch.java) + - 📄 [UnionFind](src/main/java/com/thealgorithms/searches/UnionFind.java) + - 📄 [UpperBound](src/main/java/com/thealgorithms/searches/UpperBound.java) + - 📁 **slidingwindow** + - 📄 [LongestSubarrayWithSumLessOrEqualToK](src/main/java/com/thealgorithms/slidingwindow/LongestSubarrayWithSumLessOrEqualToK.java) + - 📄 [LongestSubstringWithoutRepeatingCharacters](src/main/java/com/thealgorithms/slidingwindow/LongestSubstringWithoutRepeatingCharacters.java) + - 📄 [MaxSumKSizeSubarray](src/main/java/com/thealgorithms/slidingwindow/MaxSumKSizeSubarray.java) + - 📄 [MinSumKSizeSubarray](src/main/java/com/thealgorithms/slidingwindow/MinSumKSizeSubarray.java) + - 📄 [ShortestCoprimeSegment](src/main/java/com/thealgorithms/slidingwindow/ShortestCoprimeSegment.java) + - 📁 **sorts** + - 📄 [AdaptiveMergeSort](src/main/java/com/thealgorithms/sorts/AdaptiveMergeSort.java) + - 📄 [BeadSort](src/main/java/com/thealgorithms/sorts/BeadSort.java) + - 📄 [BinaryInsertionSort](src/main/java/com/thealgorithms/sorts/BinaryInsertionSort.java) + - 📄 [BitonicSort](src/main/java/com/thealgorithms/sorts/BitonicSort.java) + - 📄 [BogoSort](src/main/java/com/thealgorithms/sorts/BogoSort.java) + - 📄 [BubbleSort](src/main/java/com/thealgorithms/sorts/BubbleSort.java) + - 📄 [BubbleSortRecursive](src/main/java/com/thealgorithms/sorts/BubbleSortRecursive.java) + - 📄 [BucketSort](src/main/java/com/thealgorithms/sorts/BucketSort.java) + - 📄 [CircleSort](src/main/java/com/thealgorithms/sorts/CircleSort.java) + - 📄 [CocktailShakerSort](src/main/java/com/thealgorithms/sorts/CocktailShakerSort.java) + - 📄 [CombSort](src/main/java/com/thealgorithms/sorts/CombSort.java) + - 📄 [CountingSort](src/main/java/com/thealgorithms/sorts/CountingSort.java) + - 📄 [CycleSort](src/main/java/com/thealgorithms/sorts/CycleSort.java) + - 📄 [DarkSort](src/main/java/com/thealgorithms/sorts/DarkSort.java) + - 📄 [DualPivotQuickSort](src/main/java/com/thealgorithms/sorts/DualPivotQuickSort.java) + - 📄 [DutchNationalFlagSort](src/main/java/com/thealgorithms/sorts/DutchNationalFlagSort.java) + - 📄 [ExchangeSort](src/main/java/com/thealgorithms/sorts/ExchangeSort.java) + - 📄 [FlashSort](src/main/java/com/thealgorithms/sorts/FlashSort.java) + - 📄 [GnomeSort](src/main/java/com/thealgorithms/sorts/GnomeSort.java) + - 📄 [HeapSort](src/main/java/com/thealgorithms/sorts/HeapSort.java) + - 📄 [InsertionSort](src/main/java/com/thealgorithms/sorts/InsertionSort.java) + - 📄 [IntrospectiveSort](src/main/java/com/thealgorithms/sorts/IntrospectiveSort.java) + - 📄 [LinkListSort](src/main/java/com/thealgorithms/sorts/LinkListSort.java) + - 📄 [MergeSort](src/main/java/com/thealgorithms/sorts/MergeSort.java) + - 📄 [MergeSortNoExtraSpace](src/main/java/com/thealgorithms/sorts/MergeSortNoExtraSpace.java) + - 📄 [MergeSortRecursive](src/main/java/com/thealgorithms/sorts/MergeSortRecursive.java) + - 📄 [OddEvenSort](src/main/java/com/thealgorithms/sorts/OddEvenSort.java) + - 📄 [PancakeSort](src/main/java/com/thealgorithms/sorts/PancakeSort.java) + - 📄 [PatienceSort](src/main/java/com/thealgorithms/sorts/PatienceSort.java) + - 📄 [PigeonholeSort](src/main/java/com/thealgorithms/sorts/PigeonholeSort.java) + - 📄 [QuickSort](src/main/java/com/thealgorithms/sorts/QuickSort.java) + - 📄 [RadixSort](src/main/java/com/thealgorithms/sorts/RadixSort.java) + - 📄 [SelectionSort](src/main/java/com/thealgorithms/sorts/SelectionSort.java) + - 📄 [SelectionSortRecursive](src/main/java/com/thealgorithms/sorts/SelectionSortRecursive.java) + - 📄 [ShellSort](src/main/java/com/thealgorithms/sorts/ShellSort.java) + - 📄 [SlowSort](src/main/java/com/thealgorithms/sorts/SlowSort.java) + - 📄 [SortAlgorithm](src/main/java/com/thealgorithms/sorts/SortAlgorithm.java) + - 📄 [SortUtils](src/main/java/com/thealgorithms/sorts/SortUtils.java) + - 📄 [SortUtilsRandomGenerator](src/main/java/com/thealgorithms/sorts/SortUtilsRandomGenerator.java) + - 📄 [SpreadSort](src/main/java/com/thealgorithms/sorts/SpreadSort.java) + - 📄 [StalinSort](src/main/java/com/thealgorithms/sorts/StalinSort.java) + - 📄 [StoogeSort](src/main/java/com/thealgorithms/sorts/StoogeSort.java) + - 📄 [StrandSort](src/main/java/com/thealgorithms/sorts/StrandSort.java) + - 📄 [SwapSort](src/main/java/com/thealgorithms/sorts/SwapSort.java) + - 📄 [TimSort](src/main/java/com/thealgorithms/sorts/TimSort.java) + - 📄 [TopologicalSort](src/main/java/com/thealgorithms/sorts/TopologicalSort.java) + - 📄 [TreeSort](src/main/java/com/thealgorithms/sorts/TreeSort.java) + - 📄 [WaveSort](src/main/java/com/thealgorithms/sorts/WaveSort.java) + - 📄 [WiggleSort](src/main/java/com/thealgorithms/sorts/WiggleSort.java) + - 📁 **stacks** + - 📄 [BalancedBrackets](src/main/java/com/thealgorithms/stacks/BalancedBrackets.java) + - 📄 [CelebrityFinder](src/main/java/com/thealgorithms/stacks/CelebrityFinder.java) + - 📄 [DecimalToAnyUsingStack](src/main/java/com/thealgorithms/stacks/DecimalToAnyUsingStack.java) + - 📄 [DuplicateBrackets](src/main/java/com/thealgorithms/stacks/DuplicateBrackets.java) + - 📄 [GreatestElementConstantTime](src/main/java/com/thealgorithms/stacks/GreatestElementConstantTime.java) + - 📄 [InfixToPostfix](src/main/java/com/thealgorithms/stacks/InfixToPostfix.java) + - 📄 [InfixToPrefix](src/main/java/com/thealgorithms/stacks/InfixToPrefix.java) + - 📄 [LargestRectangle](src/main/java/com/thealgorithms/stacks/LargestRectangle.java) + - 📄 [MaximumMinimumWindow](src/main/java/com/thealgorithms/stacks/MaximumMinimumWindow.java) + - 📄 [MinStackUsingSingleStack](src/main/java/com/thealgorithms/stacks/MinStackUsingSingleStack.java) + - 📄 [MinStackUsingTwoStacks](src/main/java/com/thealgorithms/stacks/MinStackUsingTwoStacks.java) + - 📄 [NextGreaterElement](src/main/java/com/thealgorithms/stacks/NextGreaterElement.java) + - 📄 [NextSmallerElement](src/main/java/com/thealgorithms/stacks/NextSmallerElement.java) + - 📄 [PalindromeWithStack](src/main/java/com/thealgorithms/stacks/PalindromeWithStack.java) + - 📄 [PostfixEvaluator](src/main/java/com/thealgorithms/stacks/PostfixEvaluator.java) + - 📄 [PostfixToInfix](src/main/java/com/thealgorithms/stacks/PostfixToInfix.java) + - 📄 [PrefixEvaluator](src/main/java/com/thealgorithms/stacks/PrefixEvaluator.java) + - 📄 [PrefixToInfix](src/main/java/com/thealgorithms/stacks/PrefixToInfix.java) + - 📄 [SmallestElementConstantTime](src/main/java/com/thealgorithms/stacks/SmallestElementConstantTime.java) + - 📄 [SortStack](src/main/java/com/thealgorithms/stacks/SortStack.java) + - 📄 [StackPostfixNotation](src/main/java/com/thealgorithms/stacks/StackPostfixNotation.java) + - 📄 [StackUsingTwoQueues](src/main/java/com/thealgorithms/stacks/StackUsingTwoQueues.java) + - 📁 **strings** + - 📄 [AhoCorasick](src/main/java/com/thealgorithms/strings/AhoCorasick.java) + - 📄 [Alphabetical](src/main/java/com/thealgorithms/strings/Alphabetical.java) + - 📄 [Anagrams](src/main/java/com/thealgorithms/strings/Anagrams.java) + - 📄 [CharactersSame](src/main/java/com/thealgorithms/strings/CharactersSame.java) + - 📄 [CheckVowels](src/main/java/com/thealgorithms/strings/CheckVowels.java) + - 📄 [CountChar](src/main/java/com/thealgorithms/strings/CountChar.java) + - 📄 [CountWords](src/main/java/com/thealgorithms/strings/CountWords.java) + - 📄 [HammingDistance](src/main/java/com/thealgorithms/strings/HammingDistance.java) + - 📄 [HorspoolSearch](src/main/java/com/thealgorithms/strings/HorspoolSearch.java) + - 📄 [Isomorphic](src/main/java/com/thealgorithms/strings/Isomorphic.java) + - 📄 [KMP](src/main/java/com/thealgorithms/strings/KMP.java) + - 📄 [LetterCombinationsOfPhoneNumber](src/main/java/com/thealgorithms/strings/LetterCombinationsOfPhoneNumber.java) + - 📄 [LongestCommonPrefix](src/main/java/com/thealgorithms/strings/LongestCommonPrefix.java) + - 📄 [LongestNonRepetitiveSubstring](src/main/java/com/thealgorithms/strings/LongestNonRepetitiveSubstring.java) + - 📄 [LongestPalindromicSubstring](src/main/java/com/thealgorithms/strings/LongestPalindromicSubstring.java) + - 📄 [Lower](src/main/java/com/thealgorithms/strings/Lower.java) + - 📄 [Manacher](src/main/java/com/thealgorithms/strings/Manacher.java) + - 📄 [MyAtoi](src/main/java/com/thealgorithms/strings/MyAtoi.java) + - 📄 [Palindrome](src/main/java/com/thealgorithms/strings/Palindrome.java) + - 📄 [Pangram](src/main/java/com/thealgorithms/strings/Pangram.java) + - 📄 [PermuteString](src/main/java/com/thealgorithms/strings/PermuteString.java) + - 📄 [RabinKarp](src/main/java/com/thealgorithms/strings/RabinKarp.java) + - 📄 [ReturnSubsequence](src/main/java/com/thealgorithms/strings/ReturnSubsequence.java) + - 📄 [ReverseString](src/main/java/com/thealgorithms/strings/ReverseString.java) + - 📄 [ReverseStringRecursive](src/main/java/com/thealgorithms/strings/ReverseStringRecursive.java) + - 📄 [ReverseWordsInString](src/main/java/com/thealgorithms/strings/ReverseWordsInString.java) + - 📄 [Rotation](src/main/java/com/thealgorithms/strings/Rotation.java) + - 📄 [StringCompression](src/main/java/com/thealgorithms/strings/StringCompression.java) + - 📄 [StringMatchFiniteAutomata](src/main/java/com/thealgorithms/strings/StringMatchFiniteAutomata.java) + - 📄 [Upper](src/main/java/com/thealgorithms/strings/Upper.java) + - 📄 [ValidParentheses](src/main/java/com/thealgorithms/strings/ValidParentheses.java) + - 📄 [WordLadder](src/main/java/com/thealgorithms/strings/WordLadder.java) + - 📁 **zigZagPattern** + - 📄 [ZigZagPattern](src/main/java/com/thealgorithms/strings/zigZagPattern/ZigZagPattern.java) + - 📁 **tree** + - 📄 [HeavyLightDecomposition](src/main/java/com/thealgorithms/tree/HeavyLightDecomposition.java) +- 📁 **test** + - 📁 **java** + - 📁 **com** + - 📁 **thealgorithms** + - 📁 **audiofilters** + - 📄 [EMAFilterTest](src/test/java/com/thealgorithms/audiofilters/EMAFilterTest.java) + - 📄 [IIRFilterTest](src/test/java/com/thealgorithms/audiofilters/IIRFilterTest.java) + - 📁 **backtracking** + - 📄 [AllPathsFromSourceToTargetTest](src/test/java/com/thealgorithms/backtracking/AllPathsFromSourceToTargetTest.java) + - 📄 [ArrayCombinationTest](src/test/java/com/thealgorithms/backtracking/ArrayCombinationTest.java) + - 📄 [CombinationTest](src/test/java/com/thealgorithms/backtracking/CombinationTest.java) + - 📄 [CrosswordSolverTest](src/test/java/com/thealgorithms/backtracking/CrosswordSolverTest.java) + - 📄 [FloodFillTest](src/test/java/com/thealgorithms/backtracking/FloodFillTest.java) + - 📄 [KnightsTourTest](src/test/java/com/thealgorithms/backtracking/KnightsTourTest.java) + - 📄 [MColoringTest](src/test/java/com/thealgorithms/backtracking/MColoringTest.java) + - 📄 [MazeRecursionTest](src/test/java/com/thealgorithms/backtracking/MazeRecursionTest.java) + - 📄 [NQueensTest](src/test/java/com/thealgorithms/backtracking/NQueensTest.java) + - 📄 [ParenthesesGeneratorTest](src/test/java/com/thealgorithms/backtracking/ParenthesesGeneratorTest.java) + - 📄 [PermutationTest](src/test/java/com/thealgorithms/backtracking/PermutationTest.java) + - 📄 [PowerSumTest](src/test/java/com/thealgorithms/backtracking/PowerSumTest.java) + - 📄 [SubsequenceFinderTest](src/test/java/com/thealgorithms/backtracking/SubsequenceFinderTest.java) + - 📄 [WordPatternMatcherTest](src/test/java/com/thealgorithms/backtracking/WordPatternMatcherTest.java) + - 📄 [WordSearchTest](src/test/java/com/thealgorithms/backtracking/WordSearchTest.java) + - 📁 **bitmanipulation** + - 📄 [BcdConversionTest](src/test/java/com/thealgorithms/bitmanipulation/BcdConversionTest.java) + - 📄 [BinaryPalindromeCheckTest](src/test/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheckTest.java) + - 📄 [BitSwapTest](src/test/java/com/thealgorithms/bitmanipulation/BitSwapTest.java) + - 📄 [BooleanAlgebraGatesTest](src/test/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGatesTest.java) + - 📄 [ClearLeftmostSetBitTest](src/test/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBitTest.java) + - 📄 [CountLeadingZerosTest](src/test/java/com/thealgorithms/bitmanipulation/CountLeadingZerosTest.java) + - 📄 [CountSetBitsTest](src/test/java/com/thealgorithms/bitmanipulation/CountSetBitsTest.java) + - 📄 [FindNthBitTest](src/test/java/com/thealgorithms/bitmanipulation/FindNthBitTest.java) + - 📄 [FirstDifferentBitTest](src/test/java/com/thealgorithms/bitmanipulation/FirstDifferentBitTest.java) + - 📄 [GenerateSubsetsTest](src/test/java/com/thealgorithms/bitmanipulation/GenerateSubsetsTest.java) + - 📄 [GrayCodeConversionTest](src/test/java/com/thealgorithms/bitmanipulation/GrayCodeConversionTest.java) + - 📄 [HammingDistanceTest](src/test/java/com/thealgorithms/bitmanipulation/HammingDistanceTest.java) + - 📄 [HigherLowerPowerOfTwoTest](src/test/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwoTest.java) + - 📄 [HighestSetBitTest](src/test/java/com/thealgorithms/bitmanipulation/HighestSetBitTest.java) + - 📄 [IndexOfRightMostSetBitTest](src/test/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBitTest.java) + - 📄 [IsEvenTest](src/test/java/com/thealgorithms/bitmanipulation/IsEvenTest.java) + - 📄 [IsPowerTwoTest](src/test/java/com/thealgorithms/bitmanipulation/IsPowerTwoTest.java) + - 📄 [LowestSetBitTest](src/test/java/com/thealgorithms/bitmanipulation/LowestSetBitTest.java) + - 📄 [ModuloPowerOfTwoTest](src/test/java/com/thealgorithms/bitmanipulation/ModuloPowerOfTwoTest.java) + - 📄 [NextHigherSameBitCountTest](src/test/java/com/thealgorithms/bitmanipulation/NextHigherSameBitCountTest.java) + - 📄 [NonRepeatingNumberFinderTest](src/test/java/com/thealgorithms/bitmanipulation/NonRepeatingNumberFinderTest.java) + - 📄 [NumberAppearingOddTimesTest](src/test/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimesTest.java) + - 📄 [NumbersDifferentSignsTest](src/test/java/com/thealgorithms/bitmanipulation/NumbersDifferentSignsTest.java) + - 📄 [OneBitDifferenceTest](src/test/java/com/thealgorithms/bitmanipulation/OneBitDifferenceTest.java) + - 📄 [OnesComplementTest](src/test/java/com/thealgorithms/bitmanipulation/OnesComplementTest.java) + - 📄 [ParityCheckTest](src/test/java/com/thealgorithms/bitmanipulation/ParityCheckTest.java) + - 📄 [ReverseBitsTest](src/test/java/com/thealgorithms/bitmanipulation/ReverseBitsTest.java) + - 📄 [SingleBitOperationsTest](src/test/java/com/thealgorithms/bitmanipulation/SingleBitOperationsTest.java) + - 📄 [SingleElementTest](src/test/java/com/thealgorithms/bitmanipulation/SingleElementTest.java) + - 📄 [SwapAdjacentBitsTest](src/test/java/com/thealgorithms/bitmanipulation/SwapAdjacentBitsTest.java) + - 📄 [TwosComplementTest](src/test/java/com/thealgorithms/bitmanipulation/TwosComplementTest.java) + - 📄 [Xs3ConversionTest](src/test/java/com/thealgorithms/bitmanipulation/Xs3ConversionTest.java) + - 📁 **ciphers** + - 📄 [ADFGVXCipherTest](src/test/java/com/thealgorithms/ciphers/ADFGVXCipherTest.java) + - 📄 [AESEncryptionTest](src/test/java/com/thealgorithms/ciphers/AESEncryptionTest.java) + - 📄 [AffineCipherTest](src/test/java/com/thealgorithms/ciphers/AffineCipherTest.java) + - 📄 [AtbashTest](src/test/java/com/thealgorithms/ciphers/AtbashTest.java) + - 📄 [AutokeyTest](src/test/java/com/thealgorithms/ciphers/AutokeyTest.java) + - 📄 [BaconianCipherTest](src/test/java/com/thealgorithms/ciphers/BaconianCipherTest.java) + - 📄 [BlowfishTest](src/test/java/com/thealgorithms/ciphers/BlowfishTest.java) + - 📄 [CaesarTest](src/test/java/com/thealgorithms/ciphers/CaesarTest.java) + - 📄 [ColumnarTranspositionCipherTest](src/test/java/com/thealgorithms/ciphers/ColumnarTranspositionCipherTest.java) + - 📄 [DESTest](src/test/java/com/thealgorithms/ciphers/DESTest.java) + - 📄 [DiffieHellmanTest](src/test/java/com/thealgorithms/ciphers/DiffieHellmanTest.java) + - 📄 [ECCTest](src/test/java/com/thealgorithms/ciphers/ECCTest.java) + - 📄 [HillCipherTest](src/test/java/com/thealgorithms/ciphers/HillCipherTest.java) + - 📄 [MonoAlphabeticTest](src/test/java/com/thealgorithms/ciphers/MonoAlphabeticTest.java) + - 📄 [PlayfairTest](src/test/java/com/thealgorithms/ciphers/PlayfairTest.java) + - 📄 [PolybiusTest](src/test/java/com/thealgorithms/ciphers/PolybiusTest.java) + - 📄 [RSATest](src/test/java/com/thealgorithms/ciphers/RSATest.java) + - 📄 [RailFenceTest](src/test/java/com/thealgorithms/ciphers/RailFenceTest.java) + - 📄 [SimpleSubCipherTest](src/test/java/com/thealgorithms/ciphers/SimpleSubCipherTest.java) + - 📄 [VigenereTest](src/test/java/com/thealgorithms/ciphers/VigenereTest.java) + - 📄 [XORCipherTest](src/test/java/com/thealgorithms/ciphers/XORCipherTest.java) + - 📁 **a5** + - 📄 [A5CipherTest](src/test/java/com/thealgorithms/ciphers/a5/A5CipherTest.java) + - 📄 [A5KeyStreamGeneratorTest](src/test/java/com/thealgorithms/ciphers/a5/A5KeyStreamGeneratorTest.java) + - 📄 [LFSRTest](src/test/java/com/thealgorithms/ciphers/a5/LFSRTest.java) + - 📁 **conversions** + - 📄 [AffineConverterTest](src/test/java/com/thealgorithms/conversions/AffineConverterTest.java) + - 📄 [AnyBaseToDecimalTest](src/test/java/com/thealgorithms/conversions/AnyBaseToDecimalTest.java) + - 📄 [AnytoAnyTest](src/test/java/com/thealgorithms/conversions/AnytoAnyTest.java) + - 📄 [BinaryToDecimalTest](src/test/java/com/thealgorithms/conversions/BinaryToDecimalTest.java) + - 📄 [BinaryToHexadecimalTest](src/test/java/com/thealgorithms/conversions/BinaryToHexadecimalTest.java) + - 📄 [BinaryToOctalTest](src/test/java/com/thealgorithms/conversions/BinaryToOctalTest.java) + - 📄 [DecimalToAnyBaseTest](src/test/java/com/thealgorithms/conversions/DecimalToAnyBaseTest.java) + - 📄 [DecimalToBinaryTest](src/test/java/com/thealgorithms/conversions/DecimalToBinaryTest.java) + - 📄 [DecimalToHexadecimalTest](src/test/java/com/thealgorithms/conversions/DecimalToHexadecimalTest.java) + - 📄 [DecimalToOctalTest](src/test/java/com/thealgorithms/conversions/DecimalToOctalTest.java) + - 📄 [EndianConverterTest](src/test/java/com/thealgorithms/conversions/EndianConverterTest.java) + - 📄 [HexToOctTest](src/test/java/com/thealgorithms/conversions/HexToOctTest.java) + - 📄 [HexaDecimalToBinaryTest](src/test/java/com/thealgorithms/conversions/HexaDecimalToBinaryTest.java) + - 📄 [HexaDecimalToDecimalTest](src/test/java/com/thealgorithms/conversions/HexaDecimalToDecimalTest.java) + - 📄 [IPConverterTest](src/test/java/com/thealgorithms/conversions/IPConverterTest.java) + - 📄 [IPv6ConverterTest](src/test/java/com/thealgorithms/conversions/IPv6ConverterTest.java) + - 📄 [IntegerToEnglishTest](src/test/java/com/thealgorithms/conversions/IntegerToEnglishTest.java) + - 📄 [IntegerToRomanTest](src/test/java/com/thealgorithms/conversions/IntegerToRomanTest.java) + - 📄 [MorseCodeConverterTest](src/test/java/com/thealgorithms/conversions/MorseCodeConverterTest.java) + - 📄 [NumberToWordsTest](src/test/java/com/thealgorithms/conversions/NumberToWordsTest.java) + - 📄 [OctalToBinaryTest](src/test/java/com/thealgorithms/conversions/OctalToBinaryTest.java) + - 📄 [OctalToDecimalTest](src/test/java/com/thealgorithms/conversions/OctalToDecimalTest.java) + - 📄 [OctalToHexadecimalTest](src/test/java/com/thealgorithms/conversions/OctalToHexadecimalTest.java) + - 📄 [PhoneticAlphabetConverterTest](src/test/java/com/thealgorithms/conversions/PhoneticAlphabetConverterTest.java) + - 📄 [RomanToIntegerTest](src/test/java/com/thealgorithms/conversions/RomanToIntegerTest.java) + - 📄 [TurkishToLatinConversionTest](src/test/java/com/thealgorithms/conversions/TurkishToLatinConversionTest.java) + - 📄 [UnitConversionsTest](src/test/java/com/thealgorithms/conversions/UnitConversionsTest.java) + - 📄 [UnitsConverterTest](src/test/java/com/thealgorithms/conversions/UnitsConverterTest.java) + - 📄 [WordsToNumberTest](src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java) + - 📁 **datastructures** + - 📁 **bag** + - 📄 [BagTest](src/test/java/com/thealgorithms/datastructures/bag/BagTest.java) + - 📁 **bloomfilter** + - 📄 [BloomFilterTest](src/test/java/com/thealgorithms/datastructures/bloomfilter/BloomFilterTest.java) + - 📁 **buffers** + - 📄 [CircularBufferTest](src/test/java/com/thealgorithms/datastructures/buffers/CircularBufferTest.java) + - 📁 **caches** + - 📄 [FIFOCacheTest](src/test/java/com/thealgorithms/datastructures/caches/FIFOCacheTest.java) + - 📄 [LFUCacheTest](src/test/java/com/thealgorithms/datastructures/caches/LFUCacheTest.java) + - 📄 [LIFOCacheTest](src/test/java/com/thealgorithms/datastructures/caches/LIFOCacheTest.java) + - 📄 [LRUCacheTest](src/test/java/com/thealgorithms/datastructures/caches/LRUCacheTest.java) + - 📄 [MRUCacheTest](src/test/java/com/thealgorithms/datastructures/caches/MRUCacheTest.java) + - 📄 [RRCacheTest](src/test/java/com/thealgorithms/datastructures/caches/RRCacheTest.java) + - 📁 **crdt** + - 📄 [GCounterTest](src/test/java/com/thealgorithms/datastructures/crdt/GCounterTest.java) + - 📄 [GSetTest](src/test/java/com/thealgorithms/datastructures/crdt/GSetTest.java) + - 📄 [LWWElementSetTest](src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java) + - 📄 [ORSetTest](src/test/java/com/thealgorithms/datastructures/crdt/ORSetTest.java) + - 📄 [PNCounterTest](src/test/java/com/thealgorithms/datastructures/crdt/PNCounterTest.java) + - 📄 [TwoPSetTest](src/test/java/com/thealgorithms/datastructures/crdt/TwoPSetTest.java) + - 📁 **disjointsetunion** + - 📄 [DisjointSetUnionTest](src/test/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionTest.java) + - 📁 **dynamicarray** + - 📄 [DynamicArrayTest](src/test/java/com/thealgorithms/datastructures/dynamicarray/DynamicArrayTest.java) + - 📁 **graphs** + - 📄 [AStarTest](src/test/java/com/thealgorithms/datastructures/graphs/AStarTest.java) + - 📄 [BipartiteGraphDFSTest](src/test/java/com/thealgorithms/datastructures/graphs/BipartiteGraphDFSTest.java) + - 📄 [BoruvkaAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/BoruvkaAlgorithmTest.java) + - 📄 [DijkstraAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java) + - 📄 [DijkstraOptimizedAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/DijkstraOptimizedAlgorithmTest.java) + - 📄 [EdmondsBlossomAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java) + - 📄 [FloydWarshallTest](src/test/java/com/thealgorithms/datastructures/graphs/FloydWarshallTest.java) + - 📄 [FordFulkersonTest](src/test/java/com/thealgorithms/datastructures/graphs/FordFulkersonTest.java) + - 📄 [HamiltonianCycleTest](src/test/java/com/thealgorithms/datastructures/graphs/HamiltonianCycleTest.java) + - 📄 [JohnsonsAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/JohnsonsAlgorithmTest.java) + - 📄 [KahnsAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/KahnsAlgorithmTest.java) + - 📄 [KosarajuTest](src/test/java/com/thealgorithms/datastructures/graphs/KosarajuTest.java) + - 📄 [KruskalTest](src/test/java/com/thealgorithms/datastructures/graphs/KruskalTest.java) + - 📄 [MatrixGraphsTest](src/test/java/com/thealgorithms/datastructures/graphs/MatrixGraphsTest.java) + - 📄 [PrimMSTTest](src/test/java/com/thealgorithms/datastructures/graphs/PrimMSTTest.java) + - 📄 [TarjansAlgorithmTest](src/test/java/com/thealgorithms/datastructures/graphs/TarjansAlgorithmTest.java) + - 📄 [WelshPowellTest](src/test/java/com/thealgorithms/datastructures/graphs/WelshPowellTest.java) + - 📁 **hashmap** + - 📁 **hashing** + - 📄 [GenericHashMapUsingArrayListTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayListTest.java) + - 📄 [GenericHashMapUsingArrayTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArrayTest.java) + - 📄 [HashMapCuckooHashingTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/HashMapCuckooHashingTest.java) + - 📄 [HashMapTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/HashMapTest.java) + - 📄 [IntersectionTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/IntersectionTest.java) + - 📄 [LinearProbingHashMapTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMapTest.java) + - 📄 [MajorityElementTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/MajorityElementTest.java) + - 📄 [MapTest](src/test/java/com/thealgorithms/datastructures/hashmap/hashing/MapTest.java) + - 📁 **heaps** + - 📄 [FibonacciHeapTest](src/test/java/com/thealgorithms/datastructures/heaps/FibonacciHeapTest.java) + - 📄 [GenericHeapTest](src/test/java/com/thealgorithms/datastructures/heaps/GenericHeapTest.java) + - 📄 [HeapElementTest](src/test/java/com/thealgorithms/datastructures/heaps/HeapElementTest.java) + - 📄 [KthElementFinderTest](src/test/java/com/thealgorithms/datastructures/heaps/KthElementFinderTest.java) + - 📄 [LeftistHeapTest](src/test/java/com/thealgorithms/datastructures/heaps/LeftistHeapTest.java) + - 📄 [MaxHeapTest](src/test/java/com/thealgorithms/datastructures/heaps/MaxHeapTest.java) + - 📄 [MedianFinderTest](src/test/java/com/thealgorithms/datastructures/heaps/MedianFinderTest.java) + - 📄 [MergeKSortedArraysTest](src/test/java/com/thealgorithms/datastructures/heaps/MergeKSortedArraysTest.java) + - 📄 [MinHeapTest](src/test/java/com/thealgorithms/datastructures/heaps/MinHeapTest.java) + - 📄 [MinPriorityQueueTest](src/test/java/com/thealgorithms/datastructures/heaps/MinPriorityQueueTest.java) + - 📁 **lists** + - 📄 [CircleLinkedListTest](src/test/java/com/thealgorithms/datastructures/lists/CircleLinkedListTest.java) + - 📄 [CountSinglyLinkedListRecursionTest](src/test/java/com/thealgorithms/datastructures/lists/CountSinglyLinkedListRecursionTest.java) + - 📄 [CreateAndDetectLoopTest](src/test/java/com/thealgorithms/datastructures/lists/CreateAndDetectLoopTest.java) + - 📄 [CursorLinkedListTest](src/test/java/com/thealgorithms/datastructures/lists/CursorLinkedListTest.java) + - 📄 [MergeKSortedLinkedListTest](src/test/java/com/thealgorithms/datastructures/lists/MergeKSortedLinkedListTest.java) + - 📄 [MergeSortedArrayListTest](src/test/java/com/thealgorithms/datastructures/lists/MergeSortedArrayListTest.java) + - 📄 [MergeSortedSinglyLinkedListTest](src/test/java/com/thealgorithms/datastructures/lists/MergeSortedSinglyLinkedListTest.java) + - 📄 [QuickSortLinkedListTest](src/test/java/com/thealgorithms/datastructures/lists/QuickSortLinkedListTest.java) + - 📄 [ReverseKGroupTest](src/test/java/com/thealgorithms/datastructures/lists/ReverseKGroupTest.java) + - 📄 [RotateSinglyLinkedListsTest](src/test/java/com/thealgorithms/datastructures/lists/RotateSinglyLinkedListsTest.java) + - 📄 [SearchSinglyLinkedListRecursionTest](src/test/java/com/thealgorithms/datastructures/lists/SearchSinglyLinkedListRecursionTest.java) + - 📄 [SinglyLinkedListTest](src/test/java/com/thealgorithms/datastructures/lists/SinglyLinkedListTest.java) + - 📄 [SkipListTest](src/test/java/com/thealgorithms/datastructures/lists/SkipListTest.java) + - 📄 [SortedLinkedListTest](src/test/java/com/thealgorithms/datastructures/lists/SortedLinkedListTest.java) + - 📁 **queues** + - 📄 [CircularQueueTest](src/test/java/com/thealgorithms/datastructures/queues/CircularQueueTest.java) + - 📄 [DequeTest](src/test/java/com/thealgorithms/datastructures/queues/DequeTest.java) + - 📄 [GenericArrayListQueueTest](src/test/java/com/thealgorithms/datastructures/queues/GenericArrayListQueueTest.java) + - 📄 [LinkedQueueTest](src/test/java/com/thealgorithms/datastructures/queues/LinkedQueueTest.java) + - 📄 [PriorityQueuesTest](src/test/java/com/thealgorithms/datastructures/queues/PriorityQueuesTest.java) + - 📄 [QueueByTwoStacksTest](src/test/java/com/thealgorithms/datastructures/queues/QueueByTwoStacksTest.java) + - 📄 [QueueTest](src/test/java/com/thealgorithms/datastructures/queues/QueueTest.java) + - 📄 [SlidingWindowMaximumTest](src/test/java/com/thealgorithms/datastructures/queues/SlidingWindowMaximumTest.java) + - 📄 [TokenBucketTest](src/test/java/com/thealgorithms/datastructures/queues/TokenBucketTest.java) + - 📁 **stacks** + - 📄 [NodeStackTest](src/test/java/com/thealgorithms/datastructures/stacks/NodeStackTest.java) + - 📄 [ReverseStackTest](src/test/java/com/thealgorithms/datastructures/stacks/ReverseStackTest.java) + - 📄 [StackArrayListTest](src/test/java/com/thealgorithms/datastructures/stacks/StackArrayListTest.java) + - 📄 [StackArrayTest](src/test/java/com/thealgorithms/datastructures/stacks/StackArrayTest.java) + - 📄 [StackOfLinkedListTest](src/test/java/com/thealgorithms/datastructures/stacks/StackOfLinkedListTest.java) + - 📁 **trees** + - 📄 [AVLTreeTest](src/test/java/com/thealgorithms/datastructures/trees/AVLTreeTest.java) + - 📄 [BSTFromSortedArrayTest](src/test/java/com/thealgorithms/datastructures/trees/BSTFromSortedArrayTest.java) + - 📄 [BSTIterativeTest](src/test/java/com/thealgorithms/datastructures/trees/BSTIterativeTest.java) + - 📄 [BSTRecursiveTest](src/test/java/com/thealgorithms/datastructures/trees/BSTRecursiveTest.java) + - 📄 [BTreeTest](src/test/java/com/thealgorithms/datastructures/trees/BTreeTest.java) + - 📄 [BinaryTreeTest](src/test/java/com/thealgorithms/datastructures/trees/BinaryTreeTest.java) + - 📄 [BoundaryTraversalTest](src/test/java/com/thealgorithms/datastructures/trees/BoundaryTraversalTest.java) + - 📄 [CeilInBinarySearchTreeTest](src/test/java/com/thealgorithms/datastructures/trees/CeilInBinarySearchTreeTest.java) + - 📄 [CheckBinaryTreeIsValidBSTTest](src/test/java/com/thealgorithms/datastructures/trees/CheckBinaryTreeIsValidBSTTest.java) + - 📄 [CheckIfBinaryTreeBalancedTest](src/test/java/com/thealgorithms/datastructures/trees/CheckIfBinaryTreeBalancedTest.java) + - 📄 [CheckTreeIsSymmetricTest](src/test/java/com/thealgorithms/datastructures/trees/CheckTreeIsSymmetricTest.java) + - 📄 [CreateBinaryTreeFromInorderPreorderTest](src/test/java/com/thealgorithms/datastructures/trees/CreateBinaryTreeFromInorderPreorderTest.java) + - 📄 [InorderTraversalTest](src/test/java/com/thealgorithms/datastructures/trees/InorderTraversalTest.java) + - 📄 [KDTreeTest](src/test/java/com/thealgorithms/datastructures/trees/KDTreeTest.java) + - 📄 [LazySegmentTreeTest](src/test/java/com/thealgorithms/datastructures/trees/LazySegmentTreeTest.java) + - 📄 [LevelOrderTraversalTest](src/test/java/com/thealgorithms/datastructures/trees/LevelOrderTraversalTest.java) + - 📄 [PostOrderTraversalTest](src/test/java/com/thealgorithms/datastructures/trees/PostOrderTraversalTest.java) + - 📄 [PreOrderTraversalTest](src/test/java/com/thealgorithms/datastructures/trees/PreOrderTraversalTest.java) + - 📄 [QuadTreeTest](src/test/java/com/thealgorithms/datastructures/trees/QuadTreeTest.java) + - 📄 [SameTreesCheckTest](src/test/java/com/thealgorithms/datastructures/trees/SameTreesCheckTest.java) + - 📄 [SplayTreeTest](src/test/java/com/thealgorithms/datastructures/trees/SplayTreeTest.java) + - 📄 [TreapTest](src/test/java/com/thealgorithms/datastructures/trees/TreapTest.java) + - 📄 [TreeTestUtils](src/test/java/com/thealgorithms/datastructures/trees/TreeTestUtils.java) + - 📄 [TrieTest](src/test/java/com/thealgorithms/datastructures/trees/TrieTest.java) + - 📄 [VerticalOrderTraversalTest](src/test/java/com/thealgorithms/datastructures/trees/VerticalOrderTraversalTest.java) + - 📄 [ZigzagTraversalTest](src/test/java/com/thealgorithms/datastructures/trees/ZigzagTraversalTest.java) + - 📁 **divideandconquer** + - 📄 [BinaryExponentiationTest](src/test/java/com/thealgorithms/divideandconquer/BinaryExponentiationTest.java) + - 📄 [ClosestPairTest](src/test/java/com/thealgorithms/divideandconquer/ClosestPairTest.java) + - 📄 [CountingInversionsTest](src/test/java/com/thealgorithms/divideandconquer/CountingInversionsTest.java) + - 📄 [MedianOfTwoSortedArraysTest](src/test/java/com/thealgorithms/divideandconquer/MedianOfTwoSortedArraysTest.java) + - 📄 [SkylineAlgorithmTest](src/test/java/com/thealgorithms/divideandconquer/SkylineAlgorithmTest.java) + - 📄 [StrassenMatrixMultiplicationTest](src/test/java/com/thealgorithms/divideandconquer/StrassenMatrixMultiplicationTest.java) + - 📄 [TilingProblemTest](src/test/java/com/thealgorithms/divideandconquer/TilingProblemTest.java) + - 📁 **dynamicprogramming** + - 📄 [AbbreviationTest](src/test/java/com/thealgorithms/dynamicprogramming/AbbreviationTest.java) + - 📄 [AllConstructTest](src/test/java/com/thealgorithms/dynamicprogramming/AllConstructTest.java) + - 📄 [AssignmentUsingBitmaskTest](src/test/java/com/thealgorithms/dynamicprogramming/AssignmentUsingBitmaskTest.java) + - 📄 [BoardPathTest](src/test/java/com/thealgorithms/dynamicprogramming/BoardPathTest.java) + - 📄 [BoundaryFillTest](src/test/java/com/thealgorithms/dynamicprogramming/BoundaryFillTest.java) + - 📄 [BruteForceKnapsackTest](src/test/java/com/thealgorithms/dynamicprogramming/BruteForceKnapsackTest.java) + - 📄 [CatalanNumberTest](src/test/java/com/thealgorithms/dynamicprogramming/CatalanNumberTest.java) + - 📄 [ClimbStairsTest](src/test/java/com/thealgorithms/dynamicprogramming/ClimbStairsTest.java) + - 📄 [CoinChangeTest](src/test/java/com/thealgorithms/dynamicprogramming/CoinChangeTest.java) + - 📄 [CountFriendsPairingTest](src/test/java/com/thealgorithms/dynamicprogramming/CountFriendsPairingTest.java) + - 📄 [DPTest](src/test/java/com/thealgorithms/dynamicprogramming/DPTest.java) + - 📄 [EditDistanceTest](src/test/java/com/thealgorithms/dynamicprogramming/EditDistanceTest.java) + - 📄 [EggDroppingTest](src/test/java/com/thealgorithms/dynamicprogramming/EggDroppingTest.java) + - 📄 [FibonacciTest](src/test/java/com/thealgorithms/dynamicprogramming/FibonacciTest.java) + - 📄 [KadaneAlgorithmTest](src/test/java/com/thealgorithms/dynamicprogramming/KadaneAlgorithmTest.java) + - 📄 [KnapsackMemoizationTest](src/test/java/com/thealgorithms/dynamicprogramming/KnapsackMemoizationTest.java) + - 📄 [KnapsackTest](src/test/java/com/thealgorithms/dynamicprogramming/KnapsackTest.java) + - 📄 [KnapsackZeroOneTabulationTest](src/test/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOneTabulationTest.java) + - 📄 [KnapsackZeroOneTest](src/test/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOneTest.java) + - 📄 [LevenshteinDistanceTests](src/test/java/com/thealgorithms/dynamicprogramming/LevenshteinDistanceTests.java) + - 📄 [LongestAlternatingSubsequenceTest](src/test/java/com/thealgorithms/dynamicprogramming/LongestAlternatingSubsequenceTest.java) + - 📄 [LongestArithmeticSubsequenceTest](src/test/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequenceTest.java) + - 📄 [LongestCommonSubsequenceTest](src/test/java/com/thealgorithms/dynamicprogramming/LongestCommonSubsequenceTest.java) + - 📄 [LongestIncreasingSubsequenceNLogNTest](src/test/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequenceNLogNTest.java) + - 📄 [LongestIncreasingSubsequenceTests](src/test/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequenceTests.java) + - 📄 [LongestPalindromicSubstringTest](src/test/java/com/thealgorithms/dynamicprogramming/LongestPalindromicSubstringTest.java) + - 📄 [LongestValidParenthesesTest](src/test/java/com/thealgorithms/dynamicprogramming/LongestValidParenthesesTest.java) + - 📄 [MatrixChainMultiplicationTest](src/test/java/com/thealgorithms/dynamicprogramming/MatrixChainMultiplicationTest.java) + - 📄 [MatrixChainRecursiveTopDownMemoisationTest](src/test/java/com/thealgorithms/dynamicprogramming/MatrixChainRecursiveTopDownMemoisationTest.java) + - 📄 [MaximumSumOfNonAdjacentElementsTest](src/test/java/com/thealgorithms/dynamicprogramming/MaximumSumOfNonAdjacentElementsTest.java) + - 📄 [MinimumPathSumTest](src/test/java/com/thealgorithms/dynamicprogramming/MinimumPathSumTest.java) + - 📄 [MinimumSumPartitionTest](src/test/java/com/thealgorithms/dynamicprogramming/MinimumSumPartitionTest.java) + - 📄 [NewManShanksPrimeTest](src/test/java/com/thealgorithms/dynamicprogramming/NewManShanksPrimeTest.java) + - 📄 [OptimalJobSchedulingTest](src/test/java/com/thealgorithms/dynamicprogramming/OptimalJobSchedulingTest.java) + - 📄 [PalindromicPartitioningTest](src/test/java/com/thealgorithms/dynamicprogramming/PalindromicPartitioningTest.java) + - 📄 [PartitionProblemTest](src/test/java/com/thealgorithms/dynamicprogramming/PartitionProblemTest.java) + - 📄 [RegexMatchingTest](src/test/java/com/thealgorithms/dynamicprogramming/RegexMatchingTest.java) + - 📄 [RodCuttingTest](src/test/java/com/thealgorithms/dynamicprogramming/RodCuttingTest.java) + - 📄 [ShortestCommonSupersequenceLengthTest](src/test/java/com/thealgorithms/dynamicprogramming/ShortestCommonSupersequenceLengthTest.java) + - 📄 [SubsetCountTest](src/test/java/com/thealgorithms/dynamicprogramming/SubsetCountTest.java) + - 📄 [SubsetSumSpaceOptimizedTest](src/test/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimizedTest.java) + - 📄 [SubsetSumTest](src/test/java/com/thealgorithms/dynamicprogramming/SubsetSumTest.java) + - 📄 [SumOfSubsetTest](src/test/java/com/thealgorithms/dynamicprogramming/SumOfSubsetTest.java) + - 📄 [TreeMatchingTest](src/test/java/com/thealgorithms/dynamicprogramming/TreeMatchingTest.java) + - 📄 [TribonacciTest](src/test/java/com/thealgorithms/dynamicprogramming/TribonacciTest.java) + - 📄 [UniquePathsTests](src/test/java/com/thealgorithms/dynamicprogramming/UniquePathsTests.java) + - 📄 [UniqueSubsequencesCountTest](src/test/java/com/thealgorithms/dynamicprogramming/UniqueSubsequencesCountTest.java) + - 📄 [WildcardMatchingTest](src/test/java/com/thealgorithms/dynamicprogramming/WildcardMatchingTest.java) + - 📄 [WineProblemTest](src/test/java/com/thealgorithms/dynamicprogramming/WineProblemTest.java) + - 📁 **geometry** + - 📄 [BresenhamLineTest](src/test/java/com/thealgorithms/geometry/BresenhamLineTest.java) + - 📄 [ConvexHullTest](src/test/java/com/thealgorithms/geometry/ConvexHullTest.java) + - 📄 [GrahamScanTest](src/test/java/com/thealgorithms/geometry/GrahamScanTest.java) + - 📄 [MidpointCircleTest](src/test/java/com/thealgorithms/geometry/MidpointCircleTest.java) + - 📄 [MidpointEllipseTest](src/test/java/com/thealgorithms/geometry/MidpointEllipseTest.java) + - 📄 [PointTest](src/test/java/com/thealgorithms/geometry/PointTest.java) + - 📁 **graph** + - 📄 [ConstrainedShortestPathTest](src/test/java/com/thealgorithms/graph/ConstrainedShortestPathTest.java) + - 📄 [StronglyConnectedComponentOptimizedTest](src/test/java/com/thealgorithms/graph/StronglyConnectedComponentOptimizedTest.java) + - 📄 [TravelingSalesmanTest](src/test/java/com/thealgorithms/graph/TravelingSalesmanTest.java) + - 📁 **greedyalgorithms** + - 📄 [ActivitySelectionTest](src/test/java/com/thealgorithms/greedyalgorithms/ActivitySelectionTest.java) + - 📄 [BandwidthAllocationTest](src/test/java/com/thealgorithms/greedyalgorithms/BandwidthAllocationTest.java) + - 📄 [BinaryAdditionTest](src/test/java/com/thealgorithms/greedyalgorithms/BinaryAdditionTest.java) + - 📄 [CoinChangeTest](src/test/java/com/thealgorithms/greedyalgorithms/CoinChangeTest.java) + - 📄 [DigitSeparationTest](src/test/java/com/thealgorithms/greedyalgorithms/DigitSeparationTest.java) + - 📄 [EgyptianFractionTest](src/test/java/com/thealgorithms/greedyalgorithms/EgyptianFractionTest.java) + - 📄 [FractionalKnapsackTest](src/test/java/com/thealgorithms/greedyalgorithms/FractionalKnapsackTest.java) + - 📄 [GaleShapleyTest](src/test/java/com/thealgorithms/greedyalgorithms/GaleShapleyTest.java) + - 📄 [JobSequencingTest](src/test/java/com/thealgorithms/greedyalgorithms/JobSequencingTest.java) + - 📄 [KCentersTest](src/test/java/com/thealgorithms/greedyalgorithms/KCentersTest.java) + - 📄 [MergeIntervalsTest](src/test/java/com/thealgorithms/greedyalgorithms/MergeIntervalsTest.java) + - 📄 [MinimizingLatenessTest](src/test/java/com/thealgorithms/greedyalgorithms/MinimizingLatenessTest.java) + - 📄 [MinimumWaitingTimeTest](src/test/java/com/thealgorithms/greedyalgorithms/MinimumWaitingTimeTest.java) + - 📄 [OptimalFileMergingTest](src/test/java/com/thealgorithms/greedyalgorithms/OptimalFileMergingTest.java) + - 📄 [StockProfitCalculatorTest](src/test/java/com/thealgorithms/greedyalgorithms/StockProfitCalculatorTest.java) + - 📁 **io** + - 📄 [BufferedReaderTest](src/test/java/com/thealgorithms/io/BufferedReaderTest.java) + - 📁 **lineclipping** + - 📄 [CohenSutherlandTest](src/test/java/com/thealgorithms/lineclipping/CohenSutherlandTest.java) + - 📄 [LiangBarskyTest](src/test/java/com/thealgorithms/lineclipping/LiangBarskyTest.java) + - 📁 **maths** + - 📄 [ADTFractionTest](src/test/java/com/thealgorithms/maths/ADTFractionTest.java) + - 📄 [AbsoluteMaxTest](src/test/java/com/thealgorithms/maths/AbsoluteMaxTest.java) + - 📄 [AbsoluteMinTest](src/test/java/com/thealgorithms/maths/AbsoluteMinTest.java) + - 📄 [AbsoluteValueTest](src/test/java/com/thealgorithms/maths/AbsoluteValueTest.java) + - 📄 [AliquotSumTest](src/test/java/com/thealgorithms/maths/AliquotSumTest.java) + - 📄 [AmicableNumberTest](src/test/java/com/thealgorithms/maths/AmicableNumberTest.java) + - 📄 [AreaTest](src/test/java/com/thealgorithms/maths/AreaTest.java) + - 📄 [ArmstrongTest](src/test/java/com/thealgorithms/maths/ArmstrongTest.java) + - 📄 [AutoCorrelationTest](src/test/java/com/thealgorithms/maths/AutoCorrelationTest.java) + - 📄 [AutomorphicNumberTest](src/test/java/com/thealgorithms/maths/AutomorphicNumberTest.java) + - 📄 [AverageTest](src/test/java/com/thealgorithms/maths/AverageTest.java) + - 📄 [BinaryPowTest](src/test/java/com/thealgorithms/maths/BinaryPowTest.java) + - 📄 [BinomialCoefficientTest](src/test/java/com/thealgorithms/maths/BinomialCoefficientTest.java) + - 📄 [CatalanNumbersTest](src/test/java/com/thealgorithms/maths/CatalanNumbersTest.java) + - 📄 [CeilTest](src/test/java/com/thealgorithms/maths/CeilTest.java) + - 📄 [ChineseRemainderTheoremTest](src/test/java/com/thealgorithms/maths/ChineseRemainderTheoremTest.java) + - 📄 [CollatzConjectureTest](src/test/java/com/thealgorithms/maths/CollatzConjectureTest.java) + - 📄 [CombinationsTest](src/test/java/com/thealgorithms/maths/CombinationsTest.java) + - 📄 [ConvolutionFFTTest](src/test/java/com/thealgorithms/maths/ConvolutionFFTTest.java) + - 📄 [ConvolutionTest](src/test/java/com/thealgorithms/maths/ConvolutionTest.java) + - 📄 [CrossCorrelationTest](src/test/java/com/thealgorithms/maths/CrossCorrelationTest.java) + - 📄 [DeterminantOfMatrixTest](src/test/java/com/thealgorithms/maths/DeterminantOfMatrixTest.java) + - 📄 [DigitalRootTest](src/test/java/com/thealgorithms/maths/DigitalRootTest.java) + - 📄 [DistanceFormulaTest](src/test/java/com/thealgorithms/maths/DistanceFormulaTest.java) + - 📄 [DudeneyNumberTest](src/test/java/com/thealgorithms/maths/DudeneyNumberTest.java) + - 📄 [EulerMethodTest](src/test/java/com/thealgorithms/maths/EulerMethodTest.java) + - 📄 [EulersFunctionTest](src/test/java/com/thealgorithms/maths/EulersFunctionTest.java) + - 📄 [FFTTest](src/test/java/com/thealgorithms/maths/FFTTest.java) + - 📄 [FactorialRecursionTest](src/test/java/com/thealgorithms/maths/FactorialRecursionTest.java) + - 📄 [FactorialTest](src/test/java/com/thealgorithms/maths/FactorialTest.java) + - 📄 [FastExponentiationTest](src/test/java/com/thealgorithms/maths/FastExponentiationTest.java) + - 📄 [FastInverseSqrtTests](src/test/java/com/thealgorithms/maths/FastInverseSqrtTests.java) + - 📄 [FibonacciJavaStreamsTest](src/test/java/com/thealgorithms/maths/FibonacciJavaStreamsTest.java) + - 📄 [FibonacciLoopTest](src/test/java/com/thealgorithms/maths/FibonacciLoopTest.java) + - 📄 [FibonacciNumberCheckTest](src/test/java/com/thealgorithms/maths/FibonacciNumberCheckTest.java) + - 📄 [FibonacciNumberGoldenRationTest](src/test/java/com/thealgorithms/maths/FibonacciNumberGoldenRationTest.java) + - 📄 [FindKthNumberTest](src/test/java/com/thealgorithms/maths/FindKthNumberTest.java) + - 📄 [FindMaxRecursionTest](src/test/java/com/thealgorithms/maths/FindMaxRecursionTest.java) + - 📄 [FindMaxTest](src/test/java/com/thealgorithms/maths/FindMaxTest.java) + - 📄 [FindMinRecursionTest](src/test/java/com/thealgorithms/maths/FindMinRecursionTest.java) + - 📄 [FindMinTest](src/test/java/com/thealgorithms/maths/FindMinTest.java) + - 📄 [FloorTest](src/test/java/com/thealgorithms/maths/FloorTest.java) + - 📄 [FrizzyNumberTest](src/test/java/com/thealgorithms/maths/FrizzyNumberTest.java) + - 📄 [GCDRecursionTest](src/test/java/com/thealgorithms/maths/GCDRecursionTest.java) + - 📄 [GCDTest](src/test/java/com/thealgorithms/maths/GCDTest.java) + - 📄 [GaussianTest](src/test/java/com/thealgorithms/maths/GaussianTest.java) + - 📄 [GenericRootTest](src/test/java/com/thealgorithms/maths/GenericRootTest.java) + - 📄 [GoldbachConjectureTest](src/test/java/com/thealgorithms/maths/GoldbachConjectureTest.java) + - 📄 [HarshadNumberTest](src/test/java/com/thealgorithms/maths/HarshadNumberTest.java) + - 📄 [HeronsFormulaTest](src/test/java/com/thealgorithms/maths/HeronsFormulaTest.java) + - 📄 [JosephusProblemTest](src/test/java/com/thealgorithms/maths/JosephusProblemTest.java) + - 📄 [KaprekarNumbersTest](src/test/java/com/thealgorithms/maths/KaprekarNumbersTest.java) + - 📄 [KaratsubaMultiplicationTest](src/test/java/com/thealgorithms/maths/KaratsubaMultiplicationTest.java) + - 📄 [KrishnamurthyNumberTest](src/test/java/com/thealgorithms/maths/KrishnamurthyNumberTest.java) + - 📄 [LeastCommonMultipleTest](src/test/java/com/thealgorithms/maths/LeastCommonMultipleTest.java) + - 📄 [LeonardoNumberTest](src/test/java/com/thealgorithms/maths/LeonardoNumberTest.java) + - 📄 [LongDivisionTest](src/test/java/com/thealgorithms/maths/LongDivisionTest.java) + - 📄 [LucasSeriesTest](src/test/java/com/thealgorithms/maths/LucasSeriesTest.java) + - 📄 [MathBuilderTest](src/test/java/com/thealgorithms/maths/MathBuilderTest.java) + - 📄 [MaxValueTest](src/test/java/com/thealgorithms/maths/MaxValueTest.java) + - 📄 [MeansTest](src/test/java/com/thealgorithms/maths/MeansTest.java) + - 📄 [MedianTest](src/test/java/com/thealgorithms/maths/MedianTest.java) + - 📄 [MinValueTest](src/test/java/com/thealgorithms/maths/MinValueTest.java) + - 📄 [ModeTest](src/test/java/com/thealgorithms/maths/ModeTest.java) + - 📄 [NonRepeatingElementTest](src/test/java/com/thealgorithms/maths/NonRepeatingElementTest.java) + - 📄 [NthUglyNumberTest](src/test/java/com/thealgorithms/maths/NthUglyNumberTest.java) + - 📄 [NumberOfDigitsTest](src/test/java/com/thealgorithms/maths/NumberOfDigitsTest.java) + - 📄 [PalindromeNumberTest](src/test/java/com/thealgorithms/maths/PalindromeNumberTest.java) + - 📄 [ParseIntegerTest](src/test/java/com/thealgorithms/maths/ParseIntegerTest.java) + - 📄 [PascalTriangleTest](src/test/java/com/thealgorithms/maths/PascalTriangleTest.java) + - 📄 [PerfectCubeTest](src/test/java/com/thealgorithms/maths/PerfectCubeTest.java) + - 📄 [PerfectNumberTest](src/test/java/com/thealgorithms/maths/PerfectNumberTest.java) + - 📄 [PerfectSquareTest](src/test/java/com/thealgorithms/maths/PerfectSquareTest.java) + - 📄 [PerimeterTest](src/test/java/com/thealgorithms/maths/PerimeterTest.java) + - 📄 [PollardRhoTest](src/test/java/com/thealgorithms/maths/PollardRhoTest.java) + - 📄 [PowTest](src/test/java/com/thealgorithms/maths/PowTest.java) + - 📄 [PowerOfTwoOrNotTest](src/test/java/com/thealgorithms/maths/PowerOfTwoOrNotTest.java) + - 📄 [PowerUsingRecursionTest](src/test/java/com/thealgorithms/maths/PowerUsingRecursionTest.java) + - 📄 [PronicNumberTest](src/test/java/com/thealgorithms/maths/PronicNumberTest.java) + - 📄 [PythagoreanTripleTest](src/test/java/com/thealgorithms/maths/PythagoreanTripleTest.java) + - 📄 [QuadraticEquationSolverTest](src/test/java/com/thealgorithms/maths/QuadraticEquationSolverTest.java) + - 📄 [ReverseNumberTest](src/test/java/com/thealgorithms/maths/ReverseNumberTest.java) + - 📄 [SecondMinMaxTest](src/test/java/com/thealgorithms/maths/SecondMinMaxTest.java) + - 📄 [SieveOfEratosthenesTest](src/test/java/com/thealgorithms/maths/SieveOfEratosthenesTest.java) + - 📄 [SolovayStrassenPrimalityTestTest](src/test/java/com/thealgorithms/maths/SolovayStrassenPrimalityTestTest.java) + - 📄 [SquareFreeIntegerTest](src/test/java/com/thealgorithms/maths/SquareFreeIntegerTest.java) + - 📄 [SquareRootWithNewtonRaphsonTestMethod](src/test/java/com/thealgorithms/maths/SquareRootWithNewtonRaphsonTestMethod.java) + - 📄 [SquareRootwithBabylonianMethodTest](src/test/java/com/thealgorithms/maths/SquareRootwithBabylonianMethodTest.java) + - 📄 [StandardDeviationTest](src/test/java/com/thealgorithms/maths/StandardDeviationTest.java) + - 📄 [StandardScoreTest](src/test/java/com/thealgorithms/maths/StandardScoreTest.java) + - 📄 [StrobogrammaticNumberTest](src/test/java/com/thealgorithms/maths/StrobogrammaticNumberTest.java) + - 📄 [SumOfArithmeticSeriesTest](src/test/java/com/thealgorithms/maths/SumOfArithmeticSeriesTest.java) + - 📄 [SumOfDigitsTest](src/test/java/com/thealgorithms/maths/SumOfDigitsTest.java) + - 📄 [SumOfOddNumbersTest](src/test/java/com/thealgorithms/maths/SumOfOddNumbersTest.java) + - 📄 [SumWithoutArithmeticOperatorsTest](src/test/java/com/thealgorithms/maths/SumWithoutArithmeticOperatorsTest.java) + - 📄 [TestArmstrong](src/test/java/com/thealgorithms/maths/TestArmstrong.java) + - 📄 [TwinPrimeTest](src/test/java/com/thealgorithms/maths/TwinPrimeTest.java) + - 📄 [UniformNumbersTest](src/test/java/com/thealgorithms/maths/UniformNumbersTest.java) + - 📄 [VampireNumberTest](src/test/java/com/thealgorithms/maths/VampireNumberTest.java) + - 📄 [VolumeTest](src/test/java/com/thealgorithms/maths/VolumeTest.java) + - 📁 **prime** + - 📄 [LiouvilleLambdaFunctionTest](src/test/java/com/thealgorithms/maths/prime/LiouvilleLambdaFunctionTest.java) + - 📄 [MillerRabinPrimalityCheckTest](src/test/java/com/thealgorithms/maths/prime/MillerRabinPrimalityCheckTest.java) + - 📄 [MobiusFunctionTest](src/test/java/com/thealgorithms/maths/prime/MobiusFunctionTest.java) + - 📄 [PrimeCheckTest](src/test/java/com/thealgorithms/maths/prime/PrimeCheckTest.java) + - 📄 [PrimeFactorizationTest](src/test/java/com/thealgorithms/maths/prime/PrimeFactorizationTest.java) + - 📁 **matrix** + - 📄 [InverseOfMatrixTest](src/test/java/com/thealgorithms/matrix/InverseOfMatrixTest.java) + - 📄 [MatrixMultiplicationTest](src/test/java/com/thealgorithms/matrix/MatrixMultiplicationTest.java) + - 📄 [MatrixRankTest](src/test/java/com/thealgorithms/matrix/MatrixRankTest.java) + - 📄 [MatrixTransposeTest](src/test/java/com/thealgorithms/matrix/MatrixTransposeTest.java) + - 📄 [MatrixUtilTest](src/test/java/com/thealgorithms/matrix/MatrixUtilTest.java) + - 📄 [MedianOfMatrixTest](src/test/java/com/thealgorithms/matrix/MedianOfMatrixTest.java) + - 📄 [MirrorOfMatrixTest](src/test/java/com/thealgorithms/matrix/MirrorOfMatrixTest.java) + - 📄 [SolveSystemTest](src/test/java/com/thealgorithms/matrix/SolveSystemTest.java) + - 📄 [TestPrintMatrixInSpiralOrder](src/test/java/com/thealgorithms/matrix/TestPrintMatrixInSpiralOrder.java) + - 📁 **misc** + - 📄 [ColorContrastRatioTest](src/test/java/com/thealgorithms/misc/ColorContrastRatioTest.java) + - 📄 [MapReduceTest](src/test/java/com/thealgorithms/misc/MapReduceTest.java) + - 📄 [MedianOfRunningArrayTest](src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java) + - 📄 [PalindromePrimeTest](src/test/java/com/thealgorithms/misc/PalindromePrimeTest.java) + - 📄 [PalindromeSinglyLinkedListTest](src/test/java/com/thealgorithms/misc/PalindromeSinglyLinkedListTest.java) + - 📄 [RangeInSortedArrayTest](src/test/java/com/thealgorithms/misc/RangeInSortedArrayTest.java) + - 📄 [ShuffleArrayTest](src/test/java/com/thealgorithms/misc/ShuffleArrayTest.java) + - 📄 [SparsityTest](src/test/java/com/thealgorithms/misc/SparsityTest.java) + - 📄 [ThreeSumProblemTest](src/test/java/com/thealgorithms/misc/ThreeSumProblemTest.java) + - 📄 [TwoSumProblemTest](src/test/java/com/thealgorithms/misc/TwoSumProblemTest.java) + - 📁 **others** + - 📄 [ArrayLeftRotationTest](src/test/java/com/thealgorithms/others/ArrayLeftRotationTest.java) + - 📄 [ArrayRightRotationTest](src/test/java/com/thealgorithms/others/ArrayRightRotationTest.java) + - 📄 [BFPRTTest](src/test/java/com/thealgorithms/others/BFPRTTest.java) + - 📄 [BestFitCPUTest](src/test/java/com/thealgorithms/others/BestFitCPUTest.java) + - 📄 [BoyerMooreTest](src/test/java/com/thealgorithms/others/BoyerMooreTest.java) + - 📄 [CRC16Test](src/test/java/com/thealgorithms/others/CRC16Test.java) + - 📄 [CRCAlgorithmTest](src/test/java/com/thealgorithms/others/CRCAlgorithmTest.java) + - 📄 [ConwayTest](src/test/java/com/thealgorithms/others/ConwayTest.java) + - 📄 [CountFriendsPairingTest](src/test/java/com/thealgorithms/others/CountFriendsPairingTest.java) + - 📄 [FirstFitCPUTest](src/test/java/com/thealgorithms/others/FirstFitCPUTest.java) + - 📄 [FloydTriangleTest](src/test/java/com/thealgorithms/others/FloydTriangleTest.java) + - 📄 [KadaneAlogrithmTest](src/test/java/com/thealgorithms/others/KadaneAlogrithmTest.java) + - 📄 [LineSweepTest](src/test/java/com/thealgorithms/others/LineSweepTest.java) + - 📄 [LinkListSortTest](src/test/java/com/thealgorithms/others/LinkListSortTest.java) + - 📄 [LowestBasePalindromeTest](src/test/java/com/thealgorithms/others/LowestBasePalindromeTest.java) + - 📄 [MaximumSlidingWindowTest](src/test/java/com/thealgorithms/others/MaximumSlidingWindowTest.java) + - 📄 [MaximumSumOfDistinctSubarraysWithLengthKTest](src/test/java/com/thealgorithms/others/MaximumSumOfDistinctSubarraysWithLengthKTest.java) + - 📄 [NewManShanksPrimeTest](src/test/java/com/thealgorithms/others/NewManShanksPrimeTest.java) + - 📄 [NextFitTest](src/test/java/com/thealgorithms/others/NextFitTest.java) + - 📄 [PasswordGenTest](src/test/java/com/thealgorithms/others/PasswordGenTest.java) + - 📄 [QueueUsingTwoStacksTest](src/test/java/com/thealgorithms/others/QueueUsingTwoStacksTest.java) + - 📄 [RemoveDuplicateFromStringTest](src/test/java/com/thealgorithms/others/RemoveDuplicateFromStringTest.java) + - 📄 [ReverseStackUsingRecursionTest](src/test/java/com/thealgorithms/others/ReverseStackUsingRecursionTest.java) + - 📄 [SkylineProblemTest](src/test/java/com/thealgorithms/others/SkylineProblemTest.java) + - 📄 [TestPrintMatrixInSpiralOrder](src/test/java/com/thealgorithms/others/TestPrintMatrixInSpiralOrder.java) + - 📄 [TwoPointersTest](src/test/java/com/thealgorithms/others/TwoPointersTest.java) + - 📄 [WorstFitCPUTest](src/test/java/com/thealgorithms/others/WorstFitCPUTest.java) + - 📁 **cn** + - 📄 [HammingDistanceTest](src/test/java/com/thealgorithms/others/cn/HammingDistanceTest.java) + - 📁 **puzzlesandgames** + - 📄 [SudokuTest](src/test/java/com/thealgorithms/puzzlesandgames/SudokuTest.java) + - 📄 [TowerOfHanoiTest](src/test/java/com/thealgorithms/puzzlesandgames/TowerOfHanoiTest.java) + - 📄 [WordBoggleTest](src/test/java/com/thealgorithms/puzzlesandgames/WordBoggleTest.java) + - 📁 **randomized** + - 📄 [KargerMinCutTest](src/test/java/com/thealgorithms/randomized/KargerMinCutTest.java) + - 📄 [MonteCarloIntegrationTest](src/test/java/com/thealgorithms/randomized/MonteCarloIntegrationTest.java) + - 📄 [RandomizedClosestPairTest](src/test/java/com/thealgorithms/randomized/RandomizedClosestPairTest.java) + - 📄 [RandomizedMatrixMultiplicationVerificationTest](src/test/java/com/thealgorithms/randomized/RandomizedMatrixMultiplicationVerificationTest.java) + - 📄 [RandomizedQuickSortTest](src/test/java/com/thealgorithms/randomized/RandomizedQuickSortTest.java) + - 📄 [ReservoirSamplingTest](src/test/java/com/thealgorithms/randomized/ReservoirSamplingTest.java) + - 📁 **recursion** + - 📄 [FibonacciSeriesTest](src/test/java/com/thealgorithms/recursion/FibonacciSeriesTest.java) + - 📄 [GenerateSubsetsTest](src/test/java/com/thealgorithms/recursion/GenerateSubsetsTest.java) + - 📁 **scheduling** + - 📄 [AgingSchedulingTest](src/test/java/com/thealgorithms/scheduling/AgingSchedulingTest.java) + - 📄 [EDFSchedulingTest](src/test/java/com/thealgorithms/scheduling/EDFSchedulingTest.java) + - 📄 [FCFSSchedulingTest](src/test/java/com/thealgorithms/scheduling/FCFSSchedulingTest.java) + - 📄 [FairShareSchedulingTest](src/test/java/com/thealgorithms/scheduling/FairShareSchedulingTest.java) + - 📄 [GangSchedulingTest](src/test/java/com/thealgorithms/scheduling/GangSchedulingTest.java) + - 📄 [HighestResponseRatioNextSchedulingTest](src/test/java/com/thealgorithms/scheduling/HighestResponseRatioNextSchedulingTest.java) + - 📄 [JobSchedulingWithDeadlineTest](src/test/java/com/thealgorithms/scheduling/JobSchedulingWithDeadlineTest.java) + - 📄 [LotterySchedulingTest](src/test/java/com/thealgorithms/scheduling/LotterySchedulingTest.java) + - 📄 [MLFQSchedulerTest](src/test/java/com/thealgorithms/scheduling/MLFQSchedulerTest.java) + - 📄 [MultiAgentSchedulingTest](src/test/java/com/thealgorithms/scheduling/MultiAgentSchedulingTest.java) + - 📄 [NonPreemptivePrioritySchedulingTest](src/test/java/com/thealgorithms/scheduling/NonPreemptivePrioritySchedulingTest.java) + - 📄 [PreemptivePrioritySchedulingTest](src/test/java/com/thealgorithms/scheduling/PreemptivePrioritySchedulingTest.java) + - 📄 [ProportionalFairSchedulingTest](src/test/java/com/thealgorithms/scheduling/ProportionalFairSchedulingTest.java) + - 📄 [RRSchedulingTest](src/test/java/com/thealgorithms/scheduling/RRSchedulingTest.java) + - 📄 [RandomSchedulingTest](src/test/java/com/thealgorithms/scheduling/RandomSchedulingTest.java) + - 📄 [SJFSchedulingTest](src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java) + - 📄 [SRTFSchedulingTest](src/test/java/com/thealgorithms/scheduling/SRTFSchedulingTest.java) + - 📄 [SelfAdjustingSchedulingTest](src/test/java/com/thealgorithms/scheduling/SelfAdjustingSchedulingTest.java) + - 📄 [SlackTimeSchedulingTest](src/test/java/com/thealgorithms/scheduling/SlackTimeSchedulingTest.java) + - 📁 **diskscheduling** + - 📄 [CircularLookSchedulingTest](src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularLookSchedulingTest.java) + - 📄 [CircularScanSchedulingTest](src/test/java/com/thealgorithms/scheduling/diskscheduling/CircularScanSchedulingTest.java) + - 📄 [LookSchedulingTest](src/test/java/com/thealgorithms/scheduling/diskscheduling/LookSchedulingTest.java) + - 📄 [SSFSchedulingTest](src/test/java/com/thealgorithms/scheduling/diskscheduling/SSFSchedulingTest.java) + - 📄 [ScanSchedulingTest](src/test/java/com/thealgorithms/scheduling/diskscheduling/ScanSchedulingTest.java) + - 📁 **searches** + - 📄 [BM25InvertedIndexTest](src/test/java/com/thealgorithms/searches/BM25InvertedIndexTest.java) + - 📄 [BinarySearch2dArrayTest](src/test/java/com/thealgorithms/searches/BinarySearch2dArrayTest.java) + - 📄 [BinarySearchTest](src/test/java/com/thealgorithms/searches/BinarySearchTest.java) + - 📄 [BoyerMooreTest](src/test/java/com/thealgorithms/searches/BoyerMooreTest.java) + - 📄 [BreadthFirstSearchTest](src/test/java/com/thealgorithms/searches/BreadthFirstSearchTest.java) + - 📄 [DepthFirstSearchTest](src/test/java/com/thealgorithms/searches/DepthFirstSearchTest.java) + - 📄 [ExponentialSearchTest](src/test/java/com/thealgorithms/searches/ExponentialSearchTest.java) + - 📄 [FibonacciSearchTest](src/test/java/com/thealgorithms/searches/FibonacciSearchTest.java) + - 📄 [HowManyTimesRotatedTest](src/test/java/com/thealgorithms/searches/HowManyTimesRotatedTest.java) + - 📄 [InterpolationSearchTest](src/test/java/com/thealgorithms/searches/InterpolationSearchTest.java) + - 📄 [IterativeBinarySearchTest](src/test/java/com/thealgorithms/searches/IterativeBinarySearchTest.java) + - 📄 [IterativeTernarySearchTest](src/test/java/com/thealgorithms/searches/IterativeTernarySearchTest.java) + - 📄 [JumpSearchTest](src/test/java/com/thealgorithms/searches/JumpSearchTest.java) + - 📄 [KMPSearchTest](src/test/java/com/thealgorithms/searches/KMPSearchTest.java) + - 📄 [LinearSearchTest](src/test/java/com/thealgorithms/searches/LinearSearchTest.java) + - 📄 [LinearSearchThreadTest](src/test/java/com/thealgorithms/searches/LinearSearchThreadTest.java) + - 📄 [LowerBoundTest](src/test/java/com/thealgorithms/searches/LowerBoundTest.java) + - 📄 [MonteCarloTreeSearchTest](src/test/java/com/thealgorithms/searches/MonteCarloTreeSearchTest.java) + - 📄 [OrderAgnosticBinarySearchTest](src/test/java/com/thealgorithms/searches/OrderAgnosticBinarySearchTest.java) + - 📄 [PerfectBinarySearchTest](src/test/java/com/thealgorithms/searches/PerfectBinarySearchTest.java) + - 📄 [QuickSelectTest](src/test/java/com/thealgorithms/searches/QuickSelectTest.java) + - 📄 [RabinKarpAlgorithmTest](src/test/java/com/thealgorithms/searches/RabinKarpAlgorithmTest.java) + - 📄 [RandomSearchTest](src/test/java/com/thealgorithms/searches/RandomSearchTest.java) + - 📄 [RecursiveBinarySearchTest](src/test/java/com/thealgorithms/searches/RecursiveBinarySearchTest.java) + - 📄 [RowColumnWiseSorted2dArrayBinarySearchTest](src/test/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearchTest.java) + - 📄 [SaddlebackSearchTest](src/test/java/com/thealgorithms/searches/SaddlebackSearchTest.java) + - 📄 [SearchInARowAndColWiseSortedMatrixTest](src/test/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrixTest.java) + - 📄 [SortOrderAgnosticBinarySearchTest](src/test/java/com/thealgorithms/searches/SortOrderAgnosticBinarySearchTest.java) + - 📄 [SquareRootBinarySearchTest](src/test/java/com/thealgorithms/searches/SquareRootBinarySearchTest.java) + - 📄 [TernarySearchTest](src/test/java/com/thealgorithms/searches/TernarySearchTest.java) + - 📄 [TestSearchInARowAndColWiseSortedMatrix](src/test/java/com/thealgorithms/searches/TestSearchInARowAndColWiseSortedMatrix.java) + - 📄 [UnionFindTest](src/test/java/com/thealgorithms/searches/UnionFindTest.java) + - 📄 [UpperBoundTest](src/test/java/com/thealgorithms/searches/UpperBoundTest.java) + - 📁 **slidingwindow** + - 📄 [LongestSubarrayWithSumLessOrEqualToKTest](src/test/java/com/thealgorithms/slidingwindow/LongestSubarrayWithSumLessOrEqualToKTest.java) + - 📄 [LongestSubstringWithoutRepeatingCharactersTest](src/test/java/com/thealgorithms/slidingwindow/LongestSubstringWithoutRepeatingCharactersTest.java) + - 📄 [MaxSumKSizeSubarrayTest](src/test/java/com/thealgorithms/slidingwindow/MaxSumKSizeSubarrayTest.java) + - 📄 [MinSumKSizeSubarrayTest](src/test/java/com/thealgorithms/slidingwindow/MinSumKSizeSubarrayTest.java) + - 📄 [ShortestCoprimeSegmentTest](src/test/java/com/thealgorithms/slidingwindow/ShortestCoprimeSegmentTest.java) + - 📁 **sorts** + - 📄 [AdaptiveMergeSortTest](src/test/java/com/thealgorithms/sorts/AdaptiveMergeSortTest.java) + - 📄 [BeadSortTest](src/test/java/com/thealgorithms/sorts/BeadSortTest.java) + - 📄 [BinaryInsertionSortTest](src/test/java/com/thealgorithms/sorts/BinaryInsertionSortTest.java) + - 📄 [BitonicSortTest](src/test/java/com/thealgorithms/sorts/BitonicSortTest.java) + - 📄 [BogoSortTest](src/test/java/com/thealgorithms/sorts/BogoSortTest.java) + - 📄 [BubbleSortRecursiveTest](src/test/java/com/thealgorithms/sorts/BubbleSortRecursiveTest.java) + - 📄 [BubbleSortTest](src/test/java/com/thealgorithms/sorts/BubbleSortTest.java) + - 📄 [BucketSortTest](src/test/java/com/thealgorithms/sorts/BucketSortTest.java) + - 📄 [CircleSortTest](src/test/java/com/thealgorithms/sorts/CircleSortTest.java) + - 📄 [CocktailShakerSortTest](src/test/java/com/thealgorithms/sorts/CocktailShakerSortTest.java) + - 📄 [CombSortTest](src/test/java/com/thealgorithms/sorts/CombSortTest.java) + - 📄 [CountingSortTest](src/test/java/com/thealgorithms/sorts/CountingSortTest.java) + - 📄 [CycleSortTest](src/test/java/com/thealgorithms/sorts/CycleSortTest.java) + - 📄 [DarkSortTest](src/test/java/com/thealgorithms/sorts/DarkSortTest.java) + - 📄 [DualPivotQuickSortTest](src/test/java/com/thealgorithms/sorts/DualPivotQuickSortTest.java) + - 📄 [DutchNationalFlagSortTest](src/test/java/com/thealgorithms/sorts/DutchNationalFlagSortTest.java) + - 📄 [ExchangeSortTest](src/test/java/com/thealgorithms/sorts/ExchangeSortTest.java) + - 📄 [FlashSortTest](src/test/java/com/thealgorithms/sorts/FlashSortTest.java) + - 📄 [GnomeSortTest](src/test/java/com/thealgorithms/sorts/GnomeSortTest.java) + - 📄 [HeapSortTest](src/test/java/com/thealgorithms/sorts/HeapSortTest.java) + - 📄 [InsertionSortTest](src/test/java/com/thealgorithms/sorts/InsertionSortTest.java) + - 📄 [IntrospectiveSortTest](src/test/java/com/thealgorithms/sorts/IntrospectiveSortTest.java) + - 📄 [MergeSortNoExtraSpaceTest](src/test/java/com/thealgorithms/sorts/MergeSortNoExtraSpaceTest.java) + - 📄 [MergeSortRecursiveTest](src/test/java/com/thealgorithms/sorts/MergeSortRecursiveTest.java) + - 📄 [MergeSortTest](src/test/java/com/thealgorithms/sorts/MergeSortTest.java) + - 📄 [OddEvenSortTest](src/test/java/com/thealgorithms/sorts/OddEvenSortTest.java) + - 📄 [PancakeSortTest](src/test/java/com/thealgorithms/sorts/PancakeSortTest.java) + - 📄 [PatienceSortTest](src/test/java/com/thealgorithms/sorts/PatienceSortTest.java) + - 📄 [PigeonholeSortTest](src/test/java/com/thealgorithms/sorts/PigeonholeSortTest.java) + - 📄 [QuickSortTest](src/test/java/com/thealgorithms/sorts/QuickSortTest.java) + - 📄 [RadixSortTest](src/test/java/com/thealgorithms/sorts/RadixSortTest.java) + - 📄 [SelectionSortRecursiveTest](src/test/java/com/thealgorithms/sorts/SelectionSortRecursiveTest.java) + - 📄 [SelectionSortTest](src/test/java/com/thealgorithms/sorts/SelectionSortTest.java) + - 📄 [ShellSortTest](src/test/java/com/thealgorithms/sorts/ShellSortTest.java) + - 📄 [SlowSortTest](src/test/java/com/thealgorithms/sorts/SlowSortTest.java) + - 📄 [SortUtilsRandomGeneratorTest](src/test/java/com/thealgorithms/sorts/SortUtilsRandomGeneratorTest.java) + - 📄 [SortUtilsTest](src/test/java/com/thealgorithms/sorts/SortUtilsTest.java) + - 📄 [SortingAlgorithmTest](src/test/java/com/thealgorithms/sorts/SortingAlgorithmTest.java) + - 📄 [SpreadSortTest](src/test/java/com/thealgorithms/sorts/SpreadSortTest.java) + - 📄 [StalinSortTest](src/test/java/com/thealgorithms/sorts/StalinSortTest.java) + - 📄 [StoogeSortTest](src/test/java/com/thealgorithms/sorts/StoogeSortTest.java) + - 📄 [StrandSortTest](src/test/java/com/thealgorithms/sorts/StrandSortTest.java) + - 📄 [SwapSortTest](src/test/java/com/thealgorithms/sorts/SwapSortTest.java) + - 📄 [TimSortTest](src/test/java/com/thealgorithms/sorts/TimSortTest.java) + - 📄 [TopologicalSortTest](src/test/java/com/thealgorithms/sorts/TopologicalSortTest.java) + - 📄 [TreeSortTest](src/test/java/com/thealgorithms/sorts/TreeSortTest.java) + - 📄 [WaveSortTest](src/test/java/com/thealgorithms/sorts/WaveSortTest.java) + - 📄 [WiggleSortTest](src/test/java/com/thealgorithms/sorts/WiggleSortTest.java) + - 📁 **stacks** + - 📄 [BalancedBracketsTest](src/test/java/com/thealgorithms/stacks/BalancedBracketsTest.java) + - 📄 [CelebrityFinderTest](src/test/java/com/thealgorithms/stacks/CelebrityFinderTest.java) + - 📄 [DecimalToAnyUsingStackTest](src/test/java/com/thealgorithms/stacks/DecimalToAnyUsingStackTest.java) + - 📄 [DuplicateBracketsTest](src/test/java/com/thealgorithms/stacks/DuplicateBracketsTest.java) + - 📄 [GreatestElementConstantTimeTest](src/test/java/com/thealgorithms/stacks/GreatestElementConstantTimeTest.java) + - 📄 [InfixToPostfixTest](src/test/java/com/thealgorithms/stacks/InfixToPostfixTest.java) + - 📄 [InfixToPrefixTest](src/test/java/com/thealgorithms/stacks/InfixToPrefixTest.java) + - 📄 [LargestRectangleTest](src/test/java/com/thealgorithms/stacks/LargestRectangleTest.java) + - 📄 [MinStackUsingSingleStackTest](src/test/java/com/thealgorithms/stacks/MinStackUsingSingleStackTest.java) + - 📄 [MinStackUsingTwoStacksTest](src/test/java/com/thealgorithms/stacks/MinStackUsingTwoStacksTest.java) + - 📄 [NextGreaterElementTest](src/test/java/com/thealgorithms/stacks/NextGreaterElementTest.java) + - 📄 [NextSmallerElementTest](src/test/java/com/thealgorithms/stacks/NextSmallerElementTest.java) + - 📄 [PalindromeWithStackTest](src/test/java/com/thealgorithms/stacks/PalindromeWithStackTest.java) + - 📄 [PostfixEvaluatorTest](src/test/java/com/thealgorithms/stacks/PostfixEvaluatorTest.java) + - 📄 [PostfixToInfixTest](src/test/java/com/thealgorithms/stacks/PostfixToInfixTest.java) + - 📄 [PrefixEvaluatorTest](src/test/java/com/thealgorithms/stacks/PrefixEvaluatorTest.java) + - 📄 [PrefixToInfixTest](src/test/java/com/thealgorithms/stacks/PrefixToInfixTest.java) + - 📄 [SmallestElementConstantTimeTest](src/test/java/com/thealgorithms/stacks/SmallestElementConstantTimeTest.java) + - 📄 [SortStackTest](src/test/java/com/thealgorithms/stacks/SortStackTest.java) + - 📄 [StackPostfixNotationTest](src/test/java/com/thealgorithms/stacks/StackPostfixNotationTest.java) + - 📄 [StackUsingTwoQueuesTest](src/test/java/com/thealgorithms/stacks/StackUsingTwoQueuesTest.java) + - 📁 **strings** + - 📄 [AhoCorasickTest](src/test/java/com/thealgorithms/strings/AhoCorasickTest.java) + - 📄 [AlphabeticalTest](src/test/java/com/thealgorithms/strings/AlphabeticalTest.java) + - 📄 [AnagramsTest](src/test/java/com/thealgorithms/strings/AnagramsTest.java) + - 📄 [CharactersSameTest](src/test/java/com/thealgorithms/strings/CharactersSameTest.java) + - 📄 [CheckVowelsTest](src/test/java/com/thealgorithms/strings/CheckVowelsTest.java) + - 📄 [CountCharTest](src/test/java/com/thealgorithms/strings/CountCharTest.java) + - 📄 [CountWordsTest](src/test/java/com/thealgorithms/strings/CountWordsTest.java) + - 📄 [HammingDistanceTest](src/test/java/com/thealgorithms/strings/HammingDistanceTest.java) + - 📄 [HorspoolSearchTest](src/test/java/com/thealgorithms/strings/HorspoolSearchTest.java) + - 📄 [IsomorphicTest](src/test/java/com/thealgorithms/strings/IsomorphicTest.java) + - 📄 [LetterCombinationsOfPhoneNumberTest](src/test/java/com/thealgorithms/strings/LetterCombinationsOfPhoneNumberTest.java) + - 📄 [LongestCommonPrefixTest](src/test/java/com/thealgorithms/strings/LongestCommonPrefixTest.java) + - 📄 [LongestNonRepetitiveSubstringTest](src/test/java/com/thealgorithms/strings/LongestNonRepetitiveSubstringTest.java) + - 📄 [LongestPalindromicSubstringTest](src/test/java/com/thealgorithms/strings/LongestPalindromicSubstringTest.java) + - 📄 [LowerTest](src/test/java/com/thealgorithms/strings/LowerTest.java) + - 📄 [ManacherTest](src/test/java/com/thealgorithms/strings/ManacherTest.java) + - 📄 [MyAtoiTest](src/test/java/com/thealgorithms/strings/MyAtoiTest.java) + - 📄 [PalindromeTest](src/test/java/com/thealgorithms/strings/PalindromeTest.java) + - 📄 [PangramTest](src/test/java/com/thealgorithms/strings/PangramTest.java) + - 📄 [PermuteStringTest](src/test/java/com/thealgorithms/strings/PermuteStringTest.java) + - 📄 [ReturnSubsequenceTest](src/test/java/com/thealgorithms/strings/ReturnSubsequenceTest.java) + - 📄 [ReverseStringRecursiveTest](src/test/java/com/thealgorithms/strings/ReverseStringRecursiveTest.java) + - 📄 [ReverseStringTest](src/test/java/com/thealgorithms/strings/ReverseStringTest.java) + - 📄 [ReverseWordsInStringTest](src/test/java/com/thealgorithms/strings/ReverseWordsInStringTest.java) + - 📄 [RotationTest](src/test/java/com/thealgorithms/strings/RotationTest.java) + - 📄 [StringCompressionTest](src/test/java/com/thealgorithms/strings/StringCompressionTest.java) + - 📄 [StringMatchFiniteAutomataTest](src/test/java/com/thealgorithms/strings/StringMatchFiniteAutomataTest.java) + - 📄 [UpperTest](src/test/java/com/thealgorithms/strings/UpperTest.java) + - 📄 [ValidParenthesesTest](src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java) + - 📄 [WordLadderTest](src/test/java/com/thealgorithms/strings/WordLadderTest.java) + - 📁 **zigZagPattern** + - 📄 [ZigZagPatternTest](src/test/java/com/thealgorithms/strings/zigZagPattern/ZigZagPatternTest.java) + - 📁 **tree** + - 📄 [HeavyLightDecompositionTest](src/test/java/com/thealgorithms/tree/HeavyLightDecompositionTest.java) diff --git a/pmd-custom_ruleset.xml b/pmd-custom_ruleset.xml new file mode 100644 index 000000000000..19bb1c7968f0 --- /dev/null +++ b/pmd-custom_ruleset.xml @@ -0,0 +1,28 @@ + + + + Custom PMD checks for TheAlgorithms/Java + + + + Avoid using the main method. + + 3 + + + + + + + + + diff --git a/pmd-exclude.properties b/pmd-exclude.properties index f6ee88196962..4c0ed625d884 100644 --- a/pmd-exclude.properties +++ b/pmd-exclude.properties @@ -1,90 +1,120 @@ -com.thealgorithms.bitmanipulation.SingleBitOperations=UselessParentheses +com.thealgorithms.ciphers.AES=UselessMainMethod +com.thealgorithms.ciphers.AESEncryption=UselessMainMethod com.thealgorithms.ciphers.AffineCipher=UselessParentheses -com.thealgorithms.ciphers.ColumnarTranspositionCipher=UnnecessaryFullyQualifiedName com.thealgorithms.ciphers.DES=UselessParentheses -com.thealgorithms.ciphers.HillCipher=UselessParentheses +com.thealgorithms.ciphers.ProductCipher=UselessMainMethod com.thealgorithms.ciphers.RSA=UselessParentheses -com.thealgorithms.conversions.AnyBaseToAnyBase=UselessParentheses +com.thealgorithms.conversions.AnyBaseToAnyBase=UselessMainMethod,UselessParentheses com.thealgorithms.conversions.AnytoAny=UselessParentheses -com.thealgorithms.conversions.HexToOct=UselessParentheses -com.thealgorithms.conversions.IntegerToRoman=UnnecessaryFullyQualifiedName -com.thealgorithms.datastructures.crdt.LWWElementSet=UselessParentheses +com.thealgorithms.conversions.RgbHsvConversion=UselessMainMethod com.thealgorithms.datastructures.crdt.Pair=UnusedPrivateField com.thealgorithms.datastructures.graphs.AStar=UselessParentheses com.thealgorithms.datastructures.graphs.AdjacencyMatrixGraph=CollapsibleIfStatements,UnnecessaryFullyQualifiedName,UselessParentheses +com.thealgorithms.datastructures.graphs.BellmanFord=UselessMainMethod com.thealgorithms.datastructures.graphs.BipartiteGraphDFS=CollapsibleIfStatements -com.thealgorithms.datastructures.graphs.Kruskal=UselessParentheses +com.thealgorithms.datastructures.graphs.ConnectedComponent=UselessMainMethod +com.thealgorithms.datastructures.graphs.Cycles=UselessMainMethod +com.thealgorithms.datastructures.graphs.Graphs=UselessMainMethod +com.thealgorithms.datastructures.graphs.KahnsAlgorithm=UselessMainMethod +com.thealgorithms.datastructures.graphs.MatrixGraphs=UselessMainMethod com.thealgorithms.datastructures.hashmap.hashing.HashMapCuckooHashing=UselessParentheses +com.thealgorithms.datastructures.hashmap.hashing.MainCuckooHashing=UselessMainMethod com.thealgorithms.datastructures.heaps.FibonacciHeap=UselessParentheses -com.thealgorithms.datastructures.heaps.HeapElement=UselessParentheses com.thealgorithms.datastructures.heaps.HeapNode=UselessParentheses com.thealgorithms.datastructures.lists.DoublyLinkedList=UselessParentheses +com.thealgorithms.datastructures.lists.Link=UselessMainMethod +com.thealgorithms.datastructures.lists.RandomNode=UselessMainMethod com.thealgorithms.datastructures.lists.SearchSinglyLinkedListRecursion=UselessParentheses -com.thealgorithms.datastructures.lists.SinglyLinkedList=UnusedLocalVariable +com.thealgorithms.datastructures.lists.SinglyLinkedList=UnusedLocalVariable,UselessMainMethod +com.thealgorithms.datastructures.queues.Deque=UselessMainMethod com.thealgorithms.datastructures.queues.PriorityQueue=UselessParentheses -com.thealgorithms.datastructures.stacks.NodeStack=UnnecessaryFullyQualifiedName,UnusedFormalParameter -com.thealgorithms.datastructures.stacks.StackArray=UselessParentheses +com.thealgorithms.datastructures.trees.BSTRecursiveGeneric=UselessMainMethod com.thealgorithms.datastructures.trees.CheckBinaryTreeIsValidBST=UselessParentheses +com.thealgorithms.datastructures.trees.LCA=UselessMainMethod +com.thealgorithms.datastructures.trees.NearestRightKey=UselessMainMethod +com.thealgorithms.datastructures.trees.PrintTopViewofTree=UselessMainMethod com.thealgorithms.datastructures.trees.SegmentTree=UselessParentheses com.thealgorithms.devutils.nodes.LargeTreeNode=UselessParentheses com.thealgorithms.devutils.nodes.SimpleNode=UselessParentheses com.thealgorithms.devutils.nodes.SimpleTreeNode=UselessParentheses com.thealgorithms.devutils.nodes.TreeNode=UselessParentheses -com.thealgorithms.divideandconquer.ClosestPair=UnnecessaryFullyQualifiedName,UselessParentheses +com.thealgorithms.divideandconquer.ClosestPair=UnnecessaryFullyQualifiedName,UselessMainMethod,UselessParentheses com.thealgorithms.divideandconquer.Point=UselessParentheses -com.thealgorithms.dynamicprogramming.MatrixChainMultiplication=UselessParentheses -com.thealgorithms.dynamicprogramming.ShortestSuperSequence=UselessParentheses -com.thealgorithms.dynamicprogramming.UniquePaths=UnnecessarySemicolon +com.thealgorithms.dynamicprogramming.CatalanNumber=UselessMainMethod +com.thealgorithms.dynamicprogramming.EggDropping=UselessMainMethod +com.thealgorithms.dynamicprogramming.LongestPalindromicSubsequence=UselessMainMethod com.thealgorithms.dynamicprogramming.WineProblem=UselessParentheses com.thealgorithms.maths.BinomialCoefficient=UselessParentheses com.thealgorithms.maths.Complex=UselessParentheses com.thealgorithms.maths.DistanceFormulaTest=UnnecessaryFullyQualifiedName +com.thealgorithms.maths.EulerMethod=UselessMainMethod +com.thealgorithms.maths.GCDRecursion=UselessMainMethod com.thealgorithms.maths.Gaussian=UselessParentheses com.thealgorithms.maths.GcdSolutionWrapper=UselessParentheses com.thealgorithms.maths.HeronsFormula=UselessParentheses +com.thealgorithms.maths.JugglerSequence=UselessMainMethod com.thealgorithms.maths.KaprekarNumbers=UselessParentheses -com.thealgorithms.maths.KeithNumber=UselessParentheses +com.thealgorithms.maths.KeithNumber=UselessMainMethod,UselessParentheses com.thealgorithms.maths.LeonardoNumber=UselessParentheses -com.thealgorithms.maths.LinearDiophantineEquationsSolver=UselessParentheses -com.thealgorithms.maths.MatrixUtil=UselessParentheses +com.thealgorithms.maths.LinearDiophantineEquationsSolver=UselessMainMethod,UselessParentheses +com.thealgorithms.maths.MagicSquare=UselessMainMethod +com.thealgorithms.maths.PiNilakantha=UselessMainMethod +com.thealgorithms.maths.Prime.PrimeCheck=UselessMainMethod +com.thealgorithms.maths.PythagoreanTriple=UselessMainMethod com.thealgorithms.maths.RomanNumeralUtil=UselessParentheses com.thealgorithms.maths.SecondMinMax=UselessParentheses com.thealgorithms.maths.SecondMinMaxTest=UnnecessaryFullyQualifiedName +com.thealgorithms.maths.SimpsonIntegration=UselessMainMethod com.thealgorithms.maths.StandardDeviation=UselessParentheses com.thealgorithms.maths.SumOfArithmeticSeries=UselessParentheses -com.thealgorithms.maths.TrinomialTriangle=UselessParentheses -com.thealgorithms.maths.VampireNumber=CollapsibleIfStatements +com.thealgorithms.maths.TrinomialTriangle=UselessMainMethod,UselessParentheses +com.thealgorithms.maths.VectorCrossProduct=UselessMainMethod com.thealgorithms.maths.Volume=UselessParentheses -com.thealgorithms.matrixexponentiation.Fibonacci=UnnecessaryFullyQualifiedName +com.thealgorithms.matrix.RotateMatrixBy90Degrees=UselessMainMethod com.thealgorithms.misc.Sparsity=UselessParentheses -com.thealgorithms.misc.ThreeSumProblem=UselessParentheses -com.thealgorithms.misc.WordBoggle=UselessParentheses -com.thealgorithms.others.CRC16=UselessParentheses -com.thealgorithms.others.Damm=UnnecessaryFullyQualifiedName -com.thealgorithms.others.Luhn=UnnecessaryFullyQualifiedName -com.thealgorithms.others.Mandelbrot=UselessParentheses -com.thealgorithms.others.MaximumSumOfDistinctSubarraysWithLengthK=CollapsibleIfStatements -com.thealgorithms.others.MiniMaxAlgorithm=UselessParentheses -com.thealgorithms.others.PageRank=UselessParentheses -com.thealgorithms.others.PerlinNoise=UselessParentheses +com.thealgorithms.others.BankersAlgorithm=UselessMainMethod +com.thealgorithms.others.BrianKernighanAlgorithm=UselessMainMethod +com.thealgorithms.others.CRC16=UselessMainMethod,UselessParentheses +com.thealgorithms.others.CRC32=UselessMainMethod +com.thealgorithms.others.Damm=UnnecessaryFullyQualifiedName,UselessMainMethod +com.thealgorithms.others.Dijkstra=UselessMainMethod +com.thealgorithms.others.GaussLegendre=UselessMainMethod +com.thealgorithms.others.HappyNumbersSeq=UselessMainMethod +com.thealgorithms.others.Huffman=UselessMainMethod +com.thealgorithms.others.InsertDeleteInArray=UselessMainMethod +com.thealgorithms.others.KochSnowflake=UselessMainMethod +com.thealgorithms.others.Krishnamurthy=UselessMainMethod +com.thealgorithms.others.LinearCongruentialGenerator=UselessMainMethod +com.thealgorithms.others.Luhn=UnnecessaryFullyQualifiedName,UselessMainMethod +com.thealgorithms.others.Mandelbrot=UselessMainMethod,UselessParentheses +com.thealgorithms.others.MiniMaxAlgorithm=UselessMainMethod,UselessParentheses +com.thealgorithms.others.PageRank=UselessMainMethod,UselessParentheses +com.thealgorithms.others.PerlinNoise=UselessMainMethod,UselessParentheses com.thealgorithms.others.QueueUsingTwoStacks=UselessParentheses -com.thealgorithms.others.QueueWithStack=UselessParentheses -com.thealgorithms.others.Trieac=UselessParentheses -com.thealgorithms.others.Verhoeff=UnnecessaryFullyQualifiedName +com.thealgorithms.others.Trieac=UselessMainMethod,UselessParentheses +com.thealgorithms.others.Verhoeff=UnnecessaryFullyQualifiedName,UselessMainMethod +com.thealgorithms.puzzlesandgames.Sudoku=UselessMainMethod +com.thealgorithms.searches.HowManyTimesRotated=UselessMainMethod com.thealgorithms.searches.InterpolationSearch=UselessParentheses com.thealgorithms.searches.KMPSearch=UselessParentheses -com.thealgorithms.searches.LinearSearchThread=EmptyCatchBlock com.thealgorithms.searches.RabinKarpAlgorithm=UselessParentheses +com.thealgorithms.searches.RecursiveBinarySearch=UselessMainMethod +com.thealgorithms.sorts.BogoSort=UselessMainMethod com.thealgorithms.sorts.CircleSort=EmptyControlStatement -com.thealgorithms.sorts.CombSort=UselessParentheses com.thealgorithms.sorts.DutchNationalFlagSort=UselessParentheses -com.thealgorithms.sorts.LinkListSort=EmptyControlStatement,UnusedLocalVariable com.thealgorithms.sorts.MergeSortNoExtraSpace=UselessParentheses -com.thealgorithms.sorts.PigeonholeSort=UselessParentheses com.thealgorithms.sorts.RadixSort=UselessParentheses +com.thealgorithms.sorts.TreeSort=UselessMainMethod com.thealgorithms.sorts.WiggleSort=UselessParentheses +com.thealgorithms.stacks.LargestRectangle=UselessMainMethod +com.thealgorithms.stacks.MaximumMinimumWindow=UselessMainMethod com.thealgorithms.stacks.PostfixToInfix=UselessParentheses +com.thealgorithms.strings.Alphabetical=UselessMainMethod com.thealgorithms.strings.HorspoolSearch=UnnecessaryFullyQualifiedName,UselessParentheses -com.thealgorithms.strings.MyAtoi=UselessParentheses +com.thealgorithms.strings.KMP=UselessMainMethod +com.thealgorithms.strings.Lower=UselessMainMethod com.thealgorithms.strings.Palindrome=UselessParentheses -com.thealgorithms.strings.Solution=CollapsibleIfStatements +com.thealgorithms.strings.Pangram=UselessMainMethod +com.thealgorithms.strings.RabinKarp=UselessMainMethod +com.thealgorithms.strings.Rotation=UselessMainMethod +com.thealgorithms.strings.Upper=UselessMainMethod diff --git a/pom.xml b/pom.xml index b52e125a91e0..eff6b935e0fc 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ UTF-8 21 21 - 3.27.1 + 3.27.3 @@ -20,7 +20,7 @@ org.junit junit-bom - 5.11.4 + 5.13.4 pom import @@ -31,7 +31,6 @@ org.junit.jupiter junit-jupiter - 5.11.4 test @@ -43,26 +42,18 @@ org.mockito mockito-core - 5.15.2 - test - - - - - org.junit.jupiter - junit-jupiter-api - 5.11.4 + 5.18.0 test org.apache.commons commons-lang3 - 3.17.0 + 3.18.0 org.apache.commons commons-collections4 - 4.5.0-M3 + 4.5.0 @@ -70,7 +61,7 @@ maven-surefire-plugin - 3.5.2 + 3.5.3 @@ -78,16 +69,13 @@ org.apache.maven.plugins maven-compiler-plugin - 3.13.0 + 3.14.0 21 21 -Xlint:all -Xlint:-auxiliaryclass - -Xlint:-rawtypes - -Xlint:-unchecked - -Xlint:-lossy-conversions -Werror @@ -95,7 +83,7 @@ org.jacoco jacoco-maven-plugin - 0.8.12 + 0.8.13 @@ -125,14 +113,14 @@ com.puppycrawl.tools checkstyle - 10.21.1 + 10.26.1 com.github.spotbugs spotbugs-maven-plugin - 4.8.6.6 + 4.9.3.2 spotbugs-exclude.xml true @@ -140,12 +128,12 @@ com.mebigfatguy.fb-contrib fb-contrib - 7.6.9 + 7.6.12 com.h3xstream.findsecbugs findsecbugs-plugin - 1.13.0 + 1.14.0 @@ -153,8 +141,13 @@ org.apache.maven.plugins maven-pmd-plugin - 3.26.0 + 3.27.0 + + /rulesets/java/maven-pmd-plugin-default.xml + /category/java/security.xml + file://${basedir}/pmd-custom_ruleset.xml + true true false diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml index 14bc5dfe9439..bcc053611de6 100644 --- a/spotbugs-exclude.xml +++ b/spotbugs-exclude.xml @@ -41,9 +41,6 @@ - - - @@ -86,6 +83,9 @@ + + + @@ -117,9 +117,6 @@ - - - @@ -198,9 +195,6 @@ - - - diff --git a/src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java b/src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java index 6f93b704ffb2..c35a36d97a57 100644 --- a/src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java +++ b/src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java @@ -9,6 +9,7 @@ * * @author Siddhant Swarup Mallick */ +@SuppressWarnings({"rawtypes", "unchecked"}) public class AllPathsFromSourceToTarget { // No. of vertices in graph diff --git a/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java b/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java index 6569896bd1b7..f8cd0c40c20e 100644 --- a/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java +++ b/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java @@ -48,7 +48,7 @@ private static void combine(List> combinations, List curr for (int i = start; i < n; i++) { current.add(i); combine(combinations, current, i + 1, n, k); - current.removeLast(); // Backtrack + current.remove(current.size() - 1); // Backtrack } } } diff --git a/src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java b/src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java index 40b3097b1276..d8c207567ba6 100644 --- a/src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java +++ b/src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java @@ -1,12 +1,27 @@ package com.thealgorithms.bitmanipulation; +/** + * Utility class for performing bit-swapping operations on integers. + * This class cannot be instantiated. + */ public final class BitSwap { private BitSwap() { } - /* - * @brief Swaps the bits at the position posA and posB from data + + /** + * Swaps two bits at specified positions in an integer. + * + * @param data The input integer whose bits need to be swapped + * @param posA The position of the first bit (0-based, from least significant) + * @param posB The position of the second bit (0-based, from least significant) + * @return The modified value with swapped bits + * @throws IllegalArgumentException if either position is negative or ≥ 32 */ public static int bitSwap(int data, final int posA, final int posB) { + if (posA < 0 || posA >= Integer.SIZE || posB < 0 || posB >= Integer.SIZE) { + throw new IllegalArgumentException("Bit positions must be between 0 and 31"); + } + if (SingleBitOperations.getBit(data, posA) != SingleBitOperations.getBit(data, posB)) { data ^= (1 << posA) ^ (1 << posB); } diff --git a/src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java b/src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java index c5c068422113..aae3a996e49d 100644 --- a/src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java +++ b/src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java @@ -12,15 +12,24 @@ public final class OnesComplement { private OnesComplement() { } - // Function to get the 1's complement of a binary number + /** + * Returns the 1's complement of a binary string. + * + * @param binary A string representing a binary number (e.g., "1010"). + * @return A string representing the 1's complement. + * @throws IllegalArgumentException if the input is null or contains characters other than '0' or '1'. + */ public static String onesComplement(String binary) { - StringBuilder complement = new StringBuilder(); - // Invert each bit to get the 1's complement - for (int i = 0; i < binary.length(); i++) { - if (binary.charAt(i) == '0') { - complement.append('1'); - } else { - complement.append('0'); + if (binary == null || binary.isEmpty()) { + throw new IllegalArgumentException("Input must be a non-empty binary string."); + } + + StringBuilder complement = new StringBuilder(binary.length()); + for (char bit : binary.toCharArray()) { + switch (bit) { + case '0' -> complement.append('1'); + case '1' -> complement.append('0'); + default -> throw new IllegalArgumentException("Input must contain only '0' and '1'. Found: " + bit); } } return complement.toString(); diff --git a/src/main/java/com/thealgorithms/ciphers/AffineCipher.java b/src/main/java/com/thealgorithms/ciphers/AffineCipher.java index b82681372f2b..979f18532eaa 100644 --- a/src/main/java/com/thealgorithms/ciphers/AffineCipher.java +++ b/src/main/java/com/thealgorithms/ciphers/AffineCipher.java @@ -68,6 +68,7 @@ static String decryptCipher(String cipher) { // then i will be the multiplicative inverse of a if (flag == 1) { aInv = i; + break; } } for (int i = 0; i < cipher.length(); i++) { @@ -83,16 +84,4 @@ static String decryptCipher(String cipher) { return msg.toString(); } - - // Driver code - public static void main(String[] args) { - String msg = "AFFINE CIPHER"; - - // Calling encryption function - String cipherText = encryptMessage(msg.toCharArray()); - System.out.println("Encrypted Message is : " + cipherText); - - // Calling Decryption function - System.out.println("Decrypted Message is: " + decryptCipher(cipherText)); - } } diff --git a/src/main/java/com/thealgorithms/ciphers/Caesar.java b/src/main/java/com/thealgorithms/ciphers/Caesar.java index 61c444cf6463..23535bc2b5d2 100644 --- a/src/main/java/com/thealgorithms/ciphers/Caesar.java +++ b/src/main/java/com/thealgorithms/ciphers/Caesar.java @@ -9,6 +9,9 @@ * @author khalil2535 */ public class Caesar { + private static char normalizeShift(final int shift) { + return (char) (shift % 26); + } /** * Encrypt text by shifting every Latin char by add number shift for ASCII @@ -19,7 +22,7 @@ public class Caesar { public String encode(String message, int shift) { StringBuilder encoded = new StringBuilder(); - shift %= 26; + final char shiftChar = normalizeShift(shift); final int length = message.length(); for (int i = 0; i < length; i++) { @@ -29,10 +32,10 @@ public String encode(String message, int shift) { char current = message.charAt(i); // Java law : char + int = char if (isCapitalLatinLetter(current)) { - current += shift; + current += shiftChar; encoded.append((char) (current > 'Z' ? current - 26 : current)); // 26 = number of latin letters } else if (isSmallLatinLetter(current)) { - current += shift; + current += shiftChar; encoded.append((char) (current > 'z' ? current - 26 : current)); // 26 = number of latin letters } else { encoded.append(current); @@ -50,16 +53,16 @@ public String encode(String message, int shift) { public String decode(String encryptedMessage, int shift) { StringBuilder decoded = new StringBuilder(); - shift %= 26; + final char shiftChar = normalizeShift(shift); final int length = encryptedMessage.length(); for (int i = 0; i < length; i++) { char current = encryptedMessage.charAt(i); if (isCapitalLatinLetter(current)) { - current -= shift; + current -= shiftChar; decoded.append((char) (current < 'A' ? current + 26 : current)); // 26 = number of latin letters } else if (isSmallLatinLetter(current)) { - current -= shift; + current -= shiftChar; decoded.append((char) (current < 'a' ? current + 26 : current)); // 26 = number of latin letters } else { decoded.append(current); diff --git a/src/main/java/com/thealgorithms/conversions/NumberToWords.java b/src/main/java/com/thealgorithms/conversions/NumberToWords.java new file mode 100644 index 000000000000..e39c5b2dea86 --- /dev/null +++ b/src/main/java/com/thealgorithms/conversions/NumberToWords.java @@ -0,0 +1,100 @@ +package com.thealgorithms.conversions; + +import java.math.BigDecimal; + +/** + A Java-based utility for converting numeric values into their English word + representations. Whether you need to convert a small number, a large number + with millions and billions, or even a number with decimal places, this utility + has you covered. + * + */ +public final class NumberToWords { + + private NumberToWords() { + } + + private static final String[] UNITS = {"", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"}; + + private static final String[] TENS = {"", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"}; + + private static final String[] POWERS = {"", "Thousand", "Million", "Billion", "Trillion"}; + + private static final String ZERO = "Zero"; + private static final String POINT = " Point"; + private static final String NEGATIVE = "Negative "; + + public static String convert(BigDecimal number) { + if (number == null) { + return "Invalid Input"; + } + + // Check for negative sign + boolean isNegative = number.signum() < 0; + + // Split the number into whole and fractional parts + BigDecimal[] parts = number.abs().divideAndRemainder(BigDecimal.ONE); + BigDecimal wholePart = parts[0]; // Keep whole part as BigDecimal + String fractionalPartStr = parts[1].compareTo(BigDecimal.ZERO) > 0 ? parts[1].toPlainString().substring(2) : ""; // Get fractional part only if it exists + + // Convert whole part to words + StringBuilder result = new StringBuilder(); + if (isNegative) { + result.append(NEGATIVE); + } + result.append(convertWholeNumberToWords(wholePart)); + + // Convert fractional part to words + if (!fractionalPartStr.isEmpty()) { + result.append(POINT); + for (char digit : fractionalPartStr.toCharArray()) { + int digitValue = Character.getNumericValue(digit); + result.append(" ").append(digitValue == 0 ? ZERO : UNITS[digitValue]); + } + } + + return result.toString().trim(); + } + + private static String convertWholeNumberToWords(BigDecimal number) { + if (number.compareTo(BigDecimal.ZERO) == 0) { + return ZERO; + } + + StringBuilder words = new StringBuilder(); + int power = 0; + + while (number.compareTo(BigDecimal.ZERO) > 0) { + // Get the last three digits + BigDecimal[] divisionResult = number.divideAndRemainder(BigDecimal.valueOf(1000)); + int chunk = divisionResult[1].intValue(); + + if (chunk > 0) { + String chunkWords = convertChunk(chunk); + if (power > 0) { + words.insert(0, POWERS[power] + " "); + } + words.insert(0, chunkWords + " "); + } + + number = divisionResult[0]; // Continue with the remaining part + power++; + } + + return words.toString().trim(); + } + + private static String convertChunk(int number) { + String chunkWords; + + if (number < 20) { + chunkWords = UNITS[number]; + } else if (number < 100) { + chunkWords = TENS[number / 10] + (number % 10 > 0 ? " " + UNITS[number % 10] : ""); + } else { + chunkWords = UNITS[number / 100] + " Hundred" + (number % 100 > 0 ? " " + convertChunk(number % 100) : ""); + } + + return chunkWords; + } +} diff --git a/src/main/java/com/thealgorithms/conversions/WordsToNumber.java b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java new file mode 100644 index 000000000000..e2b81a0f4b47 --- /dev/null +++ b/src/main/java/com/thealgorithms/conversions/WordsToNumber.java @@ -0,0 +1,343 @@ +package com.thealgorithms.conversions; + +import java.io.Serial; +import java.math.BigDecimal; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + A Java-based utility for converting English word representations of numbers + into their numeric form. This utility supports whole numbers, decimals, + large values up to trillions, and even scientific notation where applicable. + It ensures accurate parsing while handling edge cases like negative numbers, + improper word placements, and ambiguous inputs. + * + */ + +public final class WordsToNumber { + + private WordsToNumber() { + } + + private enum NumberWord { + ZERO("zero", 0), + ONE("one", 1), + TWO("two", 2), + THREE("three", 3), + FOUR("four", 4), + FIVE("five", 5), + SIX("six", 6), + SEVEN("seven", 7), + EIGHT("eight", 8), + NINE("nine", 9), + TEN("ten", 10), + ELEVEN("eleven", 11), + TWELVE("twelve", 12), + THIRTEEN("thirteen", 13), + FOURTEEN("fourteen", 14), + FIFTEEN("fifteen", 15), + SIXTEEN("sixteen", 16), + SEVENTEEN("seventeen", 17), + EIGHTEEN("eighteen", 18), + NINETEEN("nineteen", 19), + TWENTY("twenty", 20), + THIRTY("thirty", 30), + FORTY("forty", 40), + FIFTY("fifty", 50), + SIXTY("sixty", 60), + SEVENTY("seventy", 70), + EIGHTY("eighty", 80), + NINETY("ninety", 90); + + private final String word; + private final int value; + + NumberWord(String word, int value) { + this.word = word; + this.value = value; + } + + public static Integer getValue(String word) { + for (NumberWord num : values()) { + if (word.equals(num.word)) { + return num.value; + } + } + return null; + } + } + + private enum PowerOfTen { + THOUSAND("thousand", new BigDecimal("1000")), + MILLION("million", new BigDecimal("1000000")), + BILLION("billion", new BigDecimal("1000000000")), + TRILLION("trillion", new BigDecimal("1000000000000")); + + private final String word; + private final BigDecimal value; + + PowerOfTen(String word, BigDecimal value) { + this.word = word; + this.value = value; + } + + public static BigDecimal getValue(String word) { + for (PowerOfTen power : values()) { + if (word.equals(power.word)) { + return power.value; + } + } + return null; + } + } + + public static String convert(String numberInWords) { + if (numberInWords == null) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.NULL_INPUT, ""); + } + + ArrayDeque wordDeque = preprocessWords(numberInWords); + BigDecimal completeNumber = convertWordQueueToBigDecimal(wordDeque); + + return completeNumber.toString(); + } + + public static BigDecimal convertToBigDecimal(String numberInWords) { + String conversionResult = convert(numberInWords); + return new BigDecimal(conversionResult); + } + + private static ArrayDeque preprocessWords(String numberInWords) { + String[] wordSplitArray = numberInWords.trim().split("[ ,-]"); + ArrayDeque wordDeque = new ArrayDeque<>(); + for (String word : wordSplitArray) { + if (word.isEmpty()) { + continue; + } + wordDeque.add(word.toLowerCase()); + } + if (wordDeque.isEmpty()) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.NULL_INPUT, ""); + } + return wordDeque; + } + + private static void handleConjunction(boolean prevNumWasHundred, boolean prevNumWasPowerOfTen, ArrayDeque wordDeque) { + if (wordDeque.isEmpty()) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.INVALID_CONJUNCTION, ""); + } + + String nextWord = wordDeque.pollFirst(); + String afterNextWord = wordDeque.peekFirst(); + + wordDeque.addFirst(nextWord); + + Integer number = NumberWord.getValue(nextWord); + + boolean isPrevWordValid = prevNumWasHundred || prevNumWasPowerOfTen; + boolean isNextWordValid = number != null && (number >= 10 || afterNextWord == null || "point".equals(afterNextWord)); + + if (!isPrevWordValid || !isNextWordValid) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.INVALID_CONJUNCTION, ""); + } + } + + private static BigDecimal handleHundred(BigDecimal currentChunk, String word, boolean prevNumWasPowerOfTen) { + boolean currentChunkIsZero = currentChunk.compareTo(BigDecimal.ZERO) == 0; + if (currentChunk.compareTo(BigDecimal.TEN) >= 0 || prevNumWasPowerOfTen) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD, word); + } + if (currentChunkIsZero) { + currentChunk = currentChunk.add(BigDecimal.ONE); + } + return currentChunk.multiply(BigDecimal.valueOf(100)); + } + + private static void handlePowerOfTen(List chunks, BigDecimal currentChunk, BigDecimal powerOfTen, String word, boolean prevNumWasPowerOfTen) { + boolean currentChunkIsZero = currentChunk.compareTo(BigDecimal.ZERO) == 0; + if (currentChunkIsZero || prevNumWasPowerOfTen) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD, word); + } + BigDecimal nextChunk = currentChunk.multiply(powerOfTen); + + if (!(chunks.isEmpty() || isAdditionSafe(chunks.getLast(), nextChunk))) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD, word); + } + chunks.add(nextChunk); + } + + private static BigDecimal handleNumber(Collection chunks, BigDecimal currentChunk, String word, Integer number) { + boolean currentChunkIsZero = currentChunk.compareTo(BigDecimal.ZERO) == 0; + if (number == 0 && !(currentChunkIsZero && chunks.isEmpty())) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD, word); + } + BigDecimal bigDecimalNumber = BigDecimal.valueOf(number); + + if (!currentChunkIsZero && !isAdditionSafe(currentChunk, bigDecimalNumber)) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD, word); + } + return currentChunk.add(bigDecimalNumber); + } + + private static void handlePoint(Collection chunks, BigDecimal currentChunk, ArrayDeque wordDeque) { + boolean currentChunkIsZero = currentChunk.compareTo(BigDecimal.ZERO) == 0; + if (!currentChunkIsZero) { + chunks.add(currentChunk); + } + + String decimalPart = convertDecimalPart(wordDeque); + chunks.add(new BigDecimal(decimalPart)); + } + + private static void handleNegative(boolean isNegative) { + if (isNegative) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.MULTIPLE_NEGATIVES, ""); + } + throw new WordsToNumberException(WordsToNumberException.ErrorType.INVALID_NEGATIVE, ""); + } + + private static BigDecimal convertWordQueueToBigDecimal(ArrayDeque wordDeque) { + BigDecimal currentChunk = BigDecimal.ZERO; + List chunks = new ArrayList<>(); + + boolean isNegative = "negative".equals(wordDeque.peek()); + if (isNegative) { + wordDeque.poll(); + } + + boolean prevNumWasHundred = false; + boolean prevNumWasPowerOfTen = false; + + while (!wordDeque.isEmpty()) { + String word = wordDeque.poll(); + + switch (word) { + case "and" -> { + handleConjunction(prevNumWasHundred, prevNumWasPowerOfTen, wordDeque); + continue; + } + case "hundred" -> { + currentChunk = handleHundred(currentChunk, word, prevNumWasPowerOfTen); + prevNumWasHundred = true; + continue; + } + default -> { + + } + } + prevNumWasHundred = false; + + BigDecimal powerOfTen = PowerOfTen.getValue(word); + if (powerOfTen != null) { + handlePowerOfTen(chunks, currentChunk, powerOfTen, word, prevNumWasPowerOfTen); + currentChunk = BigDecimal.ZERO; + prevNumWasPowerOfTen = true; + continue; + } + prevNumWasPowerOfTen = false; + + Integer number = NumberWord.getValue(word); + if (number != null) { + currentChunk = handleNumber(chunks, currentChunk, word, number); + continue; + } + + switch (word) { + case "point" -> { + handlePoint(chunks, currentChunk, wordDeque); + currentChunk = BigDecimal.ZERO; + continue; + } + case "negative" -> { + handleNegative(isNegative); + } + default -> { + + } + } + + throw new WordsToNumberException(WordsToNumberException.ErrorType.UNKNOWN_WORD, word); + } + + if (currentChunk.compareTo(BigDecimal.ZERO) != 0) { + chunks.add(currentChunk); + } + + BigDecimal completeNumber = combineChunks(chunks); + return isNegative ? completeNumber.multiply(BigDecimal.valueOf(-1)) + : + completeNumber; + } + + private static boolean isAdditionSafe(BigDecimal currentChunk, BigDecimal number) { + int chunkDigitCount = currentChunk.toString().length(); + int numberDigitCount = number.toString().length(); + return chunkDigitCount > numberDigitCount; + } + + private static String convertDecimalPart(ArrayDeque wordDeque) { + StringBuilder decimalPart = new StringBuilder("."); + + while (!wordDeque.isEmpty()) { + String word = wordDeque.poll(); + Integer number = NumberWord.getValue(word); + if (number == null) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.UNEXPECTED_WORD_AFTER_POINT, word); + } + decimalPart.append(number); + } + + boolean missingNumbers = decimalPart.length() == 1; + if (missingNumbers) { + throw new WordsToNumberException(WordsToNumberException.ErrorType.MISSING_DECIMAL_NUMBERS, ""); + } + return decimalPart.toString(); + } + + private static BigDecimal combineChunks(List chunks) { + BigDecimal completeNumber = BigDecimal.ZERO; + for (BigDecimal chunk : chunks) { + completeNumber = completeNumber.add(chunk); + } + return completeNumber; + } + } + + class WordsToNumberException extends RuntimeException { + + @Serial private static final long serialVersionUID = 1L; + + enum ErrorType { + NULL_INPUT("'null' or empty input provided"), + UNKNOWN_WORD("Unknown Word: "), + UNEXPECTED_WORD("Unexpected Word: "), + UNEXPECTED_WORD_AFTER_POINT("Unexpected Word (after Point): "), + MISSING_DECIMAL_NUMBERS("Decimal part is missing numbers."), + MULTIPLE_NEGATIVES("Multiple 'Negative's detected."), + INVALID_NEGATIVE("Incorrect 'negative' placement"), + INVALID_CONJUNCTION("Incorrect 'and' placement"); + + private final String message; + + ErrorType(String message) { + this.message = message; + } + + public String formatMessage(String details) { + return "Invalid Input. " + message + (details.isEmpty() ? "" : details); + } + } + + public final ErrorType errorType; + + WordsToNumberException(ErrorType errorType, String details) { + super(errorType.formatMessage(details)); + this.errorType = errorType; + } + + public ErrorType getErrorType() { + return errorType; + } + } diff --git a/src/main/java/com/thealgorithms/datastructures/bloomfilter/BloomFilter.java b/src/main/java/com/thealgorithms/datastructures/bloomfilter/BloomFilter.java index a2edd3db2d8e..d60b95110fc2 100644 --- a/src/main/java/com/thealgorithms/datastructures/bloomfilter/BloomFilter.java +++ b/src/main/java/com/thealgorithms/datastructures/bloomfilter/BloomFilter.java @@ -12,6 +12,7 @@ * * @param The type of elements to be stored in the Bloom filter. */ +@SuppressWarnings("rawtypes") public class BloomFilter { private final int numberOfHashFunctions; diff --git a/src/main/java/com/thealgorithms/datastructures/buffers/CircularBuffer.java b/src/main/java/com/thealgorithms/datastructures/buffers/CircularBuffer.java index b709e16fd1f6..3b89c2119ae0 100644 --- a/src/main/java/com/thealgorithms/datastructures/buffers/CircularBuffer.java +++ b/src/main/java/com/thealgorithms/datastructures/buffers/CircularBuffer.java @@ -10,6 +10,7 @@ * * @param The type of elements stored in the circular buffer. */ +@SuppressWarnings("unchecked") public class CircularBuffer { private final Item[] buffer; private final CircularPointer putPointer; diff --git a/src/main/java/com/thealgorithms/datastructures/caches/FIFOCache.java b/src/main/java/com/thealgorithms/datastructures/caches/FIFOCache.java new file mode 100644 index 000000000000..fa048434a187 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/caches/FIFOCache.java @@ -0,0 +1,549 @@ +package com.thealgorithms.datastructures.caches; + +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.BiConsumer; + +/** + * A thread-safe generic cache implementation using the First-In-First-Out eviction policy. + *

+ * The cache holds a fixed number of entries, defined by its capacity. When the cache is full and a + * new entry is added, the oldest entry in the cache is selected and evicted to make space. + *

+ * Optionally, entries can have a time-to-live (TTL) in milliseconds. If a TTL is set, entries will + * automatically expire and be removed upon access or insertion attempts. + *

+ * Features: + *

    + *
  • Removes oldest entry when capacity is exceeded
  • + *
  • Optional TTL (time-to-live in milliseconds) per entry or default TTL for all entries
  • + *
  • Thread-safe access using locking
  • + *
  • Hit and miss counters for cache statistics
  • + *
  • Eviction listener callback support
  • + *
+ * + * @param the type of keys maintained by this cache + * @param the type of mapped values + * See FIFO + * @author Kevin Babu (GitHub) + */ +public final class FIFOCache { + + private final int capacity; + private final long defaultTTL; + private final Map> cache; + private final Lock lock; + + private long hits = 0; + private long misses = 0; + private final BiConsumer evictionListener; + private final EvictionStrategy evictionStrategy; + + /** + * Internal structure to store value + expiry timestamp. + * + * @param the type of the value being cached + */ + private static class CacheEntry { + V value; + long expiryTime; + + /** + * Constructs a new {@code CacheEntry} with the specified value and time-to-live (TTL). + * If TTL is 0, the entry is kept indefinitely, that is, unless it is the first value, + * then it will be removed according to the FIFO principle + * + * @param value the value to cache + * @param ttlMillis the time-to-live in milliseconds + */ + CacheEntry(V value, long ttlMillis) { + this.value = value; + if (ttlMillis == 0) { + this.expiryTime = Long.MAX_VALUE; + } else { + this.expiryTime = System.currentTimeMillis() + ttlMillis; + } + } + + /** + * Checks if the cache entry has expired. + * + * @return {@code true} if the current time is past the expiration time; {@code false} otherwise + */ + boolean isExpired() { + return System.currentTimeMillis() > expiryTime; + } + } + + /** + * Constructs a new {@code FIFOCache} instance using the provided {@link Builder}. + * + *

This constructor initializes the cache with the specified capacity and default TTL, + * sets up internal data structures (a {@code LinkedHashMap} for cache entries and configures eviction. + * + * @param builder the {@code Builder} object containing configuration parameters + */ + private FIFOCache(Builder builder) { + this.capacity = builder.capacity; + this.defaultTTL = builder.defaultTTL; + this.cache = new LinkedHashMap<>(); + this.lock = new ReentrantLock(); + this.evictionListener = builder.evictionListener; + this.evictionStrategy = builder.evictionStrategy; + } + + /** + * Retrieves the value associated with the specified key from the cache. + * + *

If the key is not present or the corresponding entry has expired, this method + * returns {@code null}. If an expired entry is found, it will be removed and the + * eviction listener (if any) will be notified. Cache hit-and-miss statistics are + * also updated accordingly. + * + * @param key the key whose associated value is to be returned; must not be {@code null} + * @return the cached value associated with the key, or {@code null} if not present or expired + * @throws IllegalArgumentException if {@code key} is {@code null} + */ + public V get(K key) { + if (key == null) { + throw new IllegalArgumentException("Key must not be null"); + } + + lock.lock(); + try { + evictionStrategy.onAccess(this); + + CacheEntry entry = cache.get(key); + if (entry == null || entry.isExpired()) { + if (entry != null) { + cache.remove(key); + notifyEviction(key, entry.value); + } + misses++; + return null; + } + hits++; + return entry.value; + } finally { + lock.unlock(); + } + } + + /** + * Adds a key-value pair to the cache using the default time-to-live (TTL). + * + *

The key may overwrite an existing entry. The actual insertion is delegated + * to the overloaded {@link #put(K, V, long)} method. + * + * @param key the key to cache the value under + * @param value the value to be cached + */ + public void put(K key, V value) { + put(key, value, defaultTTL); + } + + /** + * Adds a key-value pair to the cache with a specified time-to-live (TTL). + * + *

If the key already exists, its value is removed, re-inserted at tail and its TTL is reset. + * If the key does not exist and the cache is full, the oldest entry is evicted to make space. + * Expired entries are also cleaned up prior to any eviction. The eviction listener + * is notified when an entry gets evicted. + * + * @param key the key to associate with the cached value; must not be {@code null} + * @param value the value to be cached; must not be {@code null} + * @param ttlMillis the time-to-live for this entry in milliseconds; must be >= 0 + * @throws IllegalArgumentException if {@code key} or {@code value} is {@code null}, or if {@code ttlMillis} is negative + */ + public void put(K key, V value, long ttlMillis) { + if (key == null || value == null) { + throw new IllegalArgumentException("Key and value must not be null"); + } + if (ttlMillis < 0) { + throw new IllegalArgumentException("TTL must be >= 0"); + } + + lock.lock(); + try { + // If key already exists, remove it + CacheEntry oldEntry = cache.remove(key); + if (oldEntry != null && !oldEntry.isExpired()) { + notifyEviction(key, oldEntry.value); + } + + // Evict expired entries to make space for new entry + evictExpired(); + + // If no expired entry was removed, remove the oldest + if (cache.size() >= capacity) { + Iterator>> it = cache.entrySet().iterator(); + if (it.hasNext()) { + Map.Entry> eldest = it.next(); + it.remove(); + notifyEviction(eldest.getKey(), eldest.getValue().value); + } + } + + // Insert new entry at tail + cache.put(key, new CacheEntry<>(value, ttlMillis)); + } finally { + lock.unlock(); + } + } + + /** + * Removes all expired entries from the cache. + * + *

This method iterates through the list of cached keys and checks each associated + * entry for expiration. Expired entries are removed the cache map. For each eviction, + * the eviction listener is notified. + */ + private int evictExpired() { + int count = 0; + Iterator>> it = cache.entrySet().iterator(); + + while (it.hasNext()) { + Map.Entry> entry = it.next(); + if (entry != null && entry.getValue().isExpired()) { + it.remove(); + notifyEviction(entry.getKey(), entry.getValue().value); + count++; + } + } + + return count; + } + + /** + * Removes the specified key and its associated entry from the cache. + * + * @param key the key to remove from the cache; + * @return the value associated with the key; or {@code null} if no such key exists + */ + public V removeKey(K key) { + if (key == null) { + throw new IllegalArgumentException("Key cannot be null"); + } + CacheEntry entry = cache.remove(key); + + // No such key in cache + if (entry == null) { + return null; + } + + notifyEviction(key, entry.value); + return entry.value; + } + + /** + * Notifies the eviction listener, if one is registered, that a key-value pair has been evicted. + * + *

If the {@code evictionListener} is not {@code null}, it is invoked with the provided key + * and value. Any exceptions thrown by the listener are caught and logged to standard error, + * preventing them from disrupting cache operations. + * + * @param key the key that was evicted + * @param value the value that was associated with the evicted key + */ + private void notifyEviction(K key, V value) { + if (evictionListener != null) { + try { + evictionListener.accept(key, value); + } catch (Exception e) { + System.err.println("Eviction listener failed: " + e.getMessage()); + } + } + } + + /** + * Returns the number of successful cache lookups (hits). + * + * @return the number of cache hits + */ + public long getHits() { + lock.lock(); + try { + return hits; + } finally { + lock.unlock(); + } + } + + /** + * Returns the number of failed cache lookups (misses), including expired entries. + * + * @return the number of cache misses + */ + public long getMisses() { + lock.lock(); + try { + return misses; + } finally { + lock.unlock(); + } + } + + /** + * Returns the current number of entries in the cache, excluding expired ones. + * + * @return the current cache size + */ + public int size() { + lock.lock(); + try { + evictionStrategy.onAccess(this); + + int count = 0; + for (CacheEntry entry : cache.values()) { + if (!entry.isExpired()) { + ++count; + } + } + return count; + } finally { + lock.unlock(); + } + } + + /** + * Removes all entries from the cache, regardless of their expiration status. + * + *

This method clears the internal cache map entirely, resets the hit-and-miss counters, + * and notifies the eviction listener (if any) for each removed entry. + * Note that expired entries are treated the same as active ones for the purpose of clearing. + * + *

This operation acquires the internal lock to ensure thread safety. + */ + public void clear() { + lock.lock(); + try { + for (Map.Entry> entry : cache.entrySet()) { + notifyEviction(entry.getKey(), entry.getValue().value); + } + cache.clear(); + hits = 0; + misses = 0; + } finally { + lock.unlock(); + } + } + + /** + * Returns a set of all keys currently stored in the cache that have not expired. + * + *

This method iterates through the cache and collects the keys of all non-expired entries. + * Expired entries are ignored but not removed. If you want to ensure expired entries are cleaned up, + * consider invoking {@link EvictionStrategy#onAccess(FIFOCache)} or calling {@link #evictExpired()} manually. + * + *

This operation acquires the internal lock to ensure thread safety. + * + * @return a set containing all non-expired keys currently in the cache + */ + public Set getAllKeys() { + lock.lock(); + try { + Set keys = new LinkedHashSet<>(); + + for (Map.Entry> entry : cache.entrySet()) { + if (!entry.getValue().isExpired()) { + keys.add(entry.getKey()); + } + } + + return keys; + } finally { + lock.unlock(); + } + } + + /** + * Returns the current {@link EvictionStrategy} used by this cache instance. + + * @return the eviction strategy currently assigned to this cache + */ + public EvictionStrategy getEvictionStrategy() { + return evictionStrategy; + } + + /** + * Returns a string representation of the cache, including metadata and current non-expired entries. + * + *

The returned string includes the cache's capacity, current size (excluding expired entries), + * hit-and-miss counts, and a map of all non-expired key-value pairs. This method acquires a lock + * to ensure thread-safe access. + * + * @return a string summarizing the state of the cache + */ + @Override + public String toString() { + lock.lock(); + try { + Map visible = new LinkedHashMap<>(); + for (Map.Entry> entry : cache.entrySet()) { + if (!entry.getValue().isExpired()) { + visible.put(entry.getKey(), entry.getValue().value); + } + } + return String.format("Cache(capacity=%d, size=%d, hits=%d, misses=%d, entries=%s)", capacity, visible.size(), hits, misses, visible); + } finally { + lock.unlock(); + } + } + + /** + * A strategy interface for controlling when expired entries are evicted from the cache. + * + *

Implementations decide whether and when to trigger {@link FIFOCache#evictExpired()} based + * on cache usage patterns. This allows for flexible eviction behaviour such as periodic cleanup, + * or no automatic cleanup. + * + * @param the type of keys maintained by the cache + * @param the type of cached values + */ + public interface EvictionStrategy { + /** + * Called on each cache access (e.g., {@link FIFOCache#get(Object)}) to optionally trigger eviction. + * + * @param cache the cache instance on which this strategy is applied + * @return the number of expired entries evicted during this access + */ + int onAccess(FIFOCache cache); + } + + /** + * An eviction strategy that performs eviction of expired entries on each call. + * + * @param the type of keys + * @param the type of values + */ + public static class ImmediateEvictionStrategy implements EvictionStrategy { + @Override + public int onAccess(FIFOCache cache) { + return cache.evictExpired(); + } + } + + /** + * An eviction strategy that triggers eviction on every fixed number of accesses. + * + *

This deterministic strategy ensures cleanup occurs at predictable intervals, + * ideal for moderately active caches where memory usage is a concern. + * + * @param the type of keys + * @param the type of values + */ + public static class PeriodicEvictionStrategy implements EvictionStrategy { + private final int interval; + private final AtomicInteger counter = new AtomicInteger(); + + /** + * Constructs a periodic eviction strategy. + * + * @param interval the number of accesses between evictions; must be > 0 + * @throws IllegalArgumentException if {@code interval} is less than or equal to 0 + */ + public PeriodicEvictionStrategy(int interval) { + if (interval <= 0) { + throw new IllegalArgumentException("Interval must be > 0"); + } + this.interval = interval; + } + + @Override + public int onAccess(FIFOCache cache) { + if (counter.incrementAndGet() % interval == 0) { + return cache.evictExpired(); + } + + return 0; + } + } + + /** + * A builder for constructing a {@link FIFOCache} instance with customizable settings. + * + *

Allows configuring capacity, default TTL, eviction listener, and a pluggable eviction + * strategy. Call {@link #build()} to create the configured cache instance. + * + * @param the type of keys maintained by the cache + * @param the type of values stored in the cache + */ + public static class Builder { + private final int capacity; + private long defaultTTL = 0; + private BiConsumer evictionListener; + private EvictionStrategy evictionStrategy = new FIFOCache.ImmediateEvictionStrategy<>(); + /** + * Creates a new {@code Builder} with the specified cache capacity. + * + * @param capacity the maximum number of entries the cache can hold; must be > 0 + * @throws IllegalArgumentException if {@code capacity} is less than or equal to 0 + */ + public Builder(int capacity) { + if (capacity <= 0) { + throw new IllegalArgumentException("Capacity must be > 0"); + } + this.capacity = capacity; + } + + /** + * Sets the default time-to-live (TTL) in milliseconds for cache entries. + * + * @param ttlMillis the TTL duration in milliseconds; must be >= 0 + * @return this builder instance for chaining + * @throws IllegalArgumentException if {@code ttlMillis} is negative + */ + public Builder defaultTTL(long ttlMillis) { + if (ttlMillis < 0) { + throw new IllegalArgumentException("Default TTL must be >= 0"); + } + this.defaultTTL = ttlMillis; + return this; + } + + /** + * Sets an eviction listener to be notified when entries are evicted from the cache. + * + * @param listener a {@link BiConsumer} that accepts evicted keys and values; must not be {@code null} + * @return this builder instance for chaining + * @throws IllegalArgumentException if {@code listener} is {@code null} + */ + public Builder evictionListener(BiConsumer listener) { + if (listener == null) { + throw new IllegalArgumentException("Listener must not be null"); + } + this.evictionListener = listener; + return this; + } + + /** + * Builds and returns a new {@link FIFOCache} instance with the configured parameters. + * + * @return a fully configured {@code FIFOCache} instance + */ + public FIFOCache build() { + return new FIFOCache<>(this); + } + + /** + * Sets the eviction strategy used to determine when to clean up expired entries. + * + * @param strategy an {@link EvictionStrategy} implementation; must not be {@code null} + * @return this builder instance + * @throws IllegalArgumentException if {@code strategy} is {@code null} + */ + public Builder evictionStrategy(EvictionStrategy strategy) { + if (strategy == null) { + throw new IllegalArgumentException("Eviction strategy must not be null"); + } + this.evictionStrategy = strategy; + return this; + } + } +} diff --git a/src/main/java/com/thealgorithms/datastructures/caches/LIFOCache.java b/src/main/java/com/thealgorithms/datastructures/caches/LIFOCache.java new file mode 100644 index 000000000000..df3d4da912fe --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/caches/LIFOCache.java @@ -0,0 +1,563 @@ +package com.thealgorithms.datastructures.caches; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.BiConsumer; + +/** + * A thread-safe generic cache implementation using the Last-In-First-Out eviction policy. + *

+ * The cache holds a fixed number of entries, defined by its capacity. When the cache is full and a + * new entry is added, the youngest entry in the cache is selected and evicted to make space. + *

+ * Optionally, entries can have a time-to-live (TTL) in milliseconds. If a TTL is set, entries will + * automatically expire and be removed upon access or insertion attempts. + *

+ * Features: + *

    + *
  • Removes youngest entry when capacity is exceeded
  • + *
  • Optional TTL (time-to-live in milliseconds) per entry or default TTL for all entries
  • + *
  • Thread-safe access using locking
  • + *
  • Hit and miss counters for cache statistics
  • + *
  • Eviction listener callback support
  • + *
+ * + * @param the type of keys maintained by this cache + * @param the type of mapped values + * See LIFO + * @author Kevin Babu (GitHub) + */ +public final class LIFOCache { + + private final int capacity; + private final long defaultTTL; + private final Map> cache; + private final Lock lock; + private final Deque keys; + private long hits = 0; + private long misses = 0; + private final BiConsumer evictionListener; + private final EvictionStrategy evictionStrategy; + + /** + * Internal structure to store value + expiry timestamp. + * + * @param the type of the value being cached + */ + private static class CacheEntry { + V value; + long expiryTime; + + /** + * Constructs a new {@code CacheEntry} with the specified value and time-to-live (TTL). + * If TTL is 0, the entry is kept indefinitely, that is, unless it is the first value, + * then it will be removed according to the LIFO principle + * + * @param value the value to cache + * @param ttlMillis the time-to-live in milliseconds + */ + CacheEntry(V value, long ttlMillis) { + this.value = value; + if (ttlMillis == 0) { + this.expiryTime = Long.MAX_VALUE; + } else { + this.expiryTime = System.currentTimeMillis() + ttlMillis; + } + } + + /** + * Checks if the cache entry has expired. + * + * @return {@code true} if the current time is past the expiration time; {@code false} otherwise + */ + boolean isExpired() { + return System.currentTimeMillis() > expiryTime; + } + } + + /** + * Constructs a new {@code LIFOCache} instance using the provided {@link Builder}. + * + *

This constructor initializes the cache with the specified capacity and default TTL, + * sets up internal data structures (a {@code HashMap} for cache entries, + * {an @code ArrayDeque}, for key storage, and configures eviction. + * + * @param builder the {@code Builder} object containing configuration parameters + */ + private LIFOCache(Builder builder) { + this.capacity = builder.capacity; + this.defaultTTL = builder.defaultTTL; + this.cache = new HashMap<>(builder.capacity); + this.keys = new ArrayDeque<>(builder.capacity); + this.lock = new ReentrantLock(); + this.evictionListener = builder.evictionListener; + this.evictionStrategy = builder.evictionStrategy; + } + + /** + * Retrieves the value associated with the specified key from the cache. + * + *

If the key is not present or the corresponding entry has expired, this method + * returns {@code null}. If an expired entry is found, it will be removed and the + * eviction listener (if any) will be notified. Cache hit-and-miss statistics are + * also updated accordingly. + * + * @param key the key whose associated value is to be returned; must not be {@code null} + * @return the cached value associated with the key, or {@code null} if not present or expired + * @throws IllegalArgumentException if {@code key} is {@code null} + */ + public V get(K key) { + if (key == null) { + throw new IllegalArgumentException("Key must not be null"); + } + + lock.lock(); + try { + evictionStrategy.onAccess(this); + + final CacheEntry entry = cache.get(key); + if (entry == null || entry.isExpired()) { + if (entry != null) { + cache.remove(key); + keys.remove(key); + notifyEviction(key, entry.value); + } + misses++; + return null; + } + hits++; + return entry.value; + } finally { + lock.unlock(); + } + } + + /** + * Adds a key-value pair to the cache using the default time-to-live (TTL). + * + *

The key may overwrite an existing entry. The actual insertion is delegated + * to the overloaded {@link #put(K, V, long)} method. + * + * @param key the key to cache the value under + * @param value the value to be cached + */ + public void put(K key, V value) { + put(key, value, defaultTTL); + } + + /** + * Adds a key-value pair to the cache with a specified time-to-live (TTL). + * + *

If the key already exists, its value is removed, re-inserted at tail and its TTL is reset. + * If the key does not exist and the cache is full, the youngest entry is evicted to make space. + * Expired entries are also cleaned up prior to any eviction. The eviction listener + * is notified when an entry gets evicted. + * + * @param key the key to associate with the cached value; must not be {@code null} + * @param value the value to be cached; must not be {@code null} + * @param ttlMillis the time-to-live for this entry in milliseconds; must be >= 0 + * @throws IllegalArgumentException if {@code key} or {@code value} is {@code null}, or if {@code ttlMillis} is negative + */ + public void put(K key, V value, long ttlMillis) { + if (key == null || value == null) { + throw new IllegalArgumentException("Key and value must not be null"); + } + if (ttlMillis < 0) { + throw new IllegalArgumentException("TTL must be >= 0"); + } + + lock.lock(); + try { + // If key already exists, remove it. It will later be re-inserted at top of stack + keys.remove(key); + final CacheEntry oldEntry = cache.remove(key); + if (oldEntry != null && !oldEntry.isExpired()) { + notifyEviction(key, oldEntry.value); + } + + // Evict expired entries to make space for new entry + evictExpired(); + + // If no expired entry was removed, remove the youngest + if (cache.size() >= capacity) { + final K youngestKey = keys.pollLast(); + final CacheEntry youngestEntry = cache.remove(youngestKey); + notifyEviction(youngestKey, youngestEntry.value); + } + + // Insert new entry at tail + keys.add(key); + cache.put(key, new CacheEntry<>(value, ttlMillis)); + } finally { + lock.unlock(); + } + } + + /** + * Removes all expired entries from the cache. + * + *

This method iterates through the list of cached keys and checks each associated + * entry for expiration. Expired entries are removed the cache map. For each eviction, + * the eviction listener is notified. + */ + private int evictExpired() { + int count = 0; + final Iterator it = keys.iterator(); + + while (it.hasNext()) { + final K k = it.next(); + final CacheEntry entry = cache.get(k); + if (entry != null && entry.isExpired()) { + it.remove(); + cache.remove(k); + notifyEviction(k, entry.value); + count++; + } + } + + return count; + } + + /** + * Removes the specified key and its associated entry from the cache. + * + * @param key the key to remove from the cache; + * @return the value associated with the key; or {@code null} if no such key exists + */ + public V removeKey(K key) { + if (key == null) { + throw new IllegalArgumentException("Key cannot be null"); + } + lock.lock(); + try { + final CacheEntry entry = cache.remove(key); + keys.remove(key); + + // No such key in cache + if (entry == null) { + return null; + } + + notifyEviction(key, entry.value); + return entry.value; + } finally { + lock.unlock(); + } + } + + /** + * Notifies the eviction listener, if one is registered, that a key-value pair has been evicted. + * + *

If the {@code evictionListener} is not {@code null}, it is invoked with the provided key + * and value. Any exceptions thrown by the listener are caught and logged to standard error, + * preventing them from disrupting cache operations. + * + * @param key the key that was evicted + * @param value the value that was associated with the evicted key + */ + private void notifyEviction(K key, V value) { + if (evictionListener != null) { + try { + evictionListener.accept(key, value); + } catch (Exception e) { + System.err.println("Eviction listener failed: " + e.getMessage()); + } + } + } + + /** + * Returns the number of successful cache lookups (hits). + * + * @return the number of cache hits + */ + public long getHits() { + lock.lock(); + try { + return hits; + } finally { + lock.unlock(); + } + } + + /** + * Returns the number of failed cache lookups (misses), including expired entries. + * + * @return the number of cache misses + */ + public long getMisses() { + lock.lock(); + try { + return misses; + } finally { + lock.unlock(); + } + } + + /** + * Returns the current number of entries in the cache, excluding expired ones. + * + * @return the current cache size + */ + public int size() { + lock.lock(); + try { + evictionStrategy.onAccess(this); + + int count = 0; + for (CacheEntry entry : cache.values()) { + if (!entry.isExpired()) { + ++count; + } + } + return count; + } finally { + lock.unlock(); + } + } + + /** + * Removes all entries from the cache, regardless of their expiration status. + * + *

This method clears the internal cache map entirely, resets the hit-and-miss counters, + * and notifies the eviction listener (if any) for each removed entry. + * Note that expired entries are treated the same as active ones for the purpose of clearing. + * + *

This operation acquires the internal lock to ensure thread safety. + */ + public void clear() { + lock.lock(); + try { + for (Map.Entry> entry : cache.entrySet()) { + notifyEviction(entry.getKey(), entry.getValue().value); + } + keys.clear(); + cache.clear(); + hits = 0; + misses = 0; + } finally { + lock.unlock(); + } + } + + /** + * Returns a set of all keys currently stored in the cache that have not expired. + * + *

This method iterates through the cache and collects the keys of all non-expired entries. + * Expired entries are ignored but not removed. If you want to ensure expired entries are cleaned up, + * consider invoking {@link EvictionStrategy#onAccess(LIFOCache)} or calling {@link #evictExpired()} manually. + * + *

This operation acquires the internal lock to ensure thread safety. + * + * @return a set containing all non-expired keys currently in the cache + */ + public Set getAllKeys() { + lock.lock(); + try { + final Set result = new HashSet<>(); + + for (Map.Entry> entry : cache.entrySet()) { + if (!entry.getValue().isExpired()) { + result.add(entry.getKey()); + } + } + + return result; + } finally { + lock.unlock(); + } + } + + /** + * Returns the current {@link EvictionStrategy} used by this cache instance. + + * @return the eviction strategy currently assigned to this cache + */ + public EvictionStrategy getEvictionStrategy() { + return evictionStrategy; + } + + /** + * Returns a string representation of the cache, including metadata and current non-expired entries. + * + *

The returned string includes the cache's capacity, current size (excluding expired entries), + * hit-and-miss counts, and a map of all non-expired key-value pairs. This method acquires a lock + * to ensure thread-safe access. + * + * @return a string summarizing the state of the cache + */ + @Override + public String toString() { + lock.lock(); + try { + final Map visible = new LinkedHashMap<>(); + for (Map.Entry> entry : cache.entrySet()) { + if (!entry.getValue().isExpired()) { + visible.put(entry.getKey(), entry.getValue().value); + } + } + return String.format("Cache(capacity=%d, size=%d, hits=%d, misses=%d, entries=%s)", capacity, visible.size(), hits, misses, visible); + } finally { + lock.unlock(); + } + } + + /** + * A strategy interface for controlling when expired entries are evicted from the cache. + * + *

Implementations decide whether and when to trigger {@link LIFOCache#evictExpired()} based + * on cache usage patterns. This allows for flexible eviction behaviour such as periodic cleanup, + * or no automatic cleanup. + * + * @param the type of keys maintained by the cache + * @param the type of cached values + */ + public interface EvictionStrategy { + /** + * Called on each cache access (e.g., {@link LIFOCache#get(Object)}) to optionally trigger eviction. + * + * @param cache the cache instance on which this strategy is applied + * @return the number of expired entries evicted during this access + */ + int onAccess(LIFOCache cache); + } + + /** + * An eviction strategy that performs eviction of expired entries on each call. + * + * @param the type of keys + * @param the type of values + */ + public static class ImmediateEvictionStrategy implements EvictionStrategy { + @Override + public int onAccess(LIFOCache cache) { + return cache.evictExpired(); + } + } + + /** + * An eviction strategy that triggers eviction on every fixed number of accesses. + * + *

This deterministic strategy ensures cleanup occurs at predictable intervals, + * ideal for moderately active caches where memory usage is a concern. + * + * @param the type of keys + * @param the type of values + */ + public static class PeriodicEvictionStrategy implements EvictionStrategy { + private final int interval; + private final AtomicInteger counter = new AtomicInteger(); + + /** + * Constructs a periodic eviction strategy. + * + * @param interval the number of accesses between evictions; must be > 0 + * @throws IllegalArgumentException if {@code interval} is less than or equal to 0 + */ + public PeriodicEvictionStrategy(int interval) { + if (interval <= 0) { + throw new IllegalArgumentException("Interval must be > 0"); + } + this.interval = interval; + } + + @Override + public int onAccess(LIFOCache cache) { + if (counter.incrementAndGet() % interval == 0) { + return cache.evictExpired(); + } + + return 0; + } + } + + /** + * A builder for constructing a {@link LIFOCache} instance with customizable settings. + * + *

Allows configuring capacity, default TTL, eviction listener, and a pluggable eviction + * strategy. Call {@link #build()} to create the configured cache instance. + * + * @param the type of keys maintained by the cache + * @param the type of values stored in the cache + */ + public static class Builder { + private final int capacity; + private long defaultTTL = 0; + private BiConsumer evictionListener; + private EvictionStrategy evictionStrategy = new LIFOCache.ImmediateEvictionStrategy<>(); + /** + * Creates a new {@code Builder} with the specified cache capacity. + * + * @param capacity the maximum number of entries the cache can hold; must be > 0 + * @throws IllegalArgumentException if {@code capacity} is less than or equal to 0 + */ + public Builder(int capacity) { + if (capacity <= 0) { + throw new IllegalArgumentException("Capacity must be > 0"); + } + this.capacity = capacity; + } + + /** + * Sets the default time-to-live (TTL) in milliseconds for cache entries. + * + * @param ttlMillis the TTL duration in milliseconds; must be >= 0 + * @return this builder instance for chaining + * @throws IllegalArgumentException if {@code ttlMillis} is negative + */ + public Builder defaultTTL(long ttlMillis) { + if (ttlMillis < 0) { + throw new IllegalArgumentException("Default TTL must be >= 0"); + } + this.defaultTTL = ttlMillis; + return this; + } + + /** + * Sets an eviction listener to be notified when entries are evicted from the cache. + * + * @param listener a {@link BiConsumer} that accepts evicted keys and values; must not be {@code null} + * @return this builder instance for chaining + * @throws IllegalArgumentException if {@code listener} is {@code null} + */ + public Builder evictionListener(BiConsumer listener) { + if (listener == null) { + throw new IllegalArgumentException("Listener must not be null"); + } + this.evictionListener = listener; + return this; + } + + /** + * Builds and returns a new {@link LIFOCache} instance with the configured parameters. + * + * @return a fully configured {@code LIFOCache} instance + */ + public LIFOCache build() { + return new LIFOCache<>(this); + } + + /** + * Sets the eviction strategy used to determine when to clean up expired entries. + * + * @param strategy an {@link EvictionStrategy} implementation; must not be {@code null} + * @return this builder instance + * @throws IllegalArgumentException if {@code strategy} is {@code null} + */ + public Builder evictionStrategy(EvictionStrategy strategy) { + if (strategy == null) { + throw new IllegalArgumentException("Eviction strategy must not be null"); + } + this.evictionStrategy = strategy; + return this; + } + } +} diff --git a/src/main/java/com/thealgorithms/datastructures/caches/RRCache.java b/src/main/java/com/thealgorithms/datastructures/caches/RRCache.java new file mode 100644 index 000000000000..1821872be9cd --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/caches/RRCache.java @@ -0,0 +1,505 @@ +package com.thealgorithms.datastructures.caches; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.function.BiConsumer; + +/** + * A thread-safe generic cache implementation using the Random Replacement (RR) eviction policy. + *

+ * The cache holds a fixed number of entries, defined by its capacity. When the cache is full and a + * new entry is added, one of the existing entries is selected at random and evicted to make space. + *

+ * Optionally, entries can have a time-to-live (TTL) in milliseconds. If a TTL is set, entries will + * automatically expire and be removed upon access or insertion attempts. + *

+ * Features: + *

    + *
  • Random eviction when capacity is exceeded
  • + *
  • Optional TTL (time-to-live in milliseconds) per entry or default TTL for all entries
  • + *
  • Thread-safe access using locking
  • + *
  • Hit and miss counters for cache statistics
  • + *
  • Eviction listener callback support
  • + *
+ * + * @param the type of keys maintained by this cache + * @param the type of mapped values + * See Random Replacement + * @author Kevin Babu (GitHub) + */ +public final class RRCache { + + private final int capacity; + private final long defaultTTL; + private final Map> cache; + private final List keys; + private final Random random; + private final Lock lock; + + private long hits = 0; + private long misses = 0; + private final BiConsumer evictionListener; + private final EvictionStrategy evictionStrategy; + + /** + * Internal structure to store value + expiry timestamp. + * + * @param the type of the value being cached + */ + private static class CacheEntry { + V value; + long expiryTime; + + /** + * Constructs a new {@code CacheEntry} with the specified value and time-to-live (TTL). + * + * @param value the value to cache + * @param ttlMillis the time-to-live in milliseconds + */ + CacheEntry(V value, long ttlMillis) { + this.value = value; + this.expiryTime = System.currentTimeMillis() + ttlMillis; + } + + /** + * Checks if the cache entry has expired. + * + * @return {@code true} if the current time is past the expiration time; {@code false} otherwise + */ + boolean isExpired() { + return System.currentTimeMillis() > expiryTime; + } + } + + /** + * Constructs a new {@code RRCache} instance using the provided {@link Builder}. + * + *

This constructor initializes the cache with the specified capacity and default TTL, + * sets up internal data structures (a {@code HashMap} for cache entries and an {@code ArrayList} + * for key tracking), and configures eviction and randomization behavior. + * + * @param builder the {@code Builder} object containing configuration parameters + */ + private RRCache(Builder builder) { + this.capacity = builder.capacity; + this.defaultTTL = builder.defaultTTL; + this.cache = new HashMap<>(builder.capacity); + this.keys = new ArrayList<>(builder.capacity); + this.random = builder.random != null ? builder.random : new Random(); + this.lock = new ReentrantLock(); + this.evictionListener = builder.evictionListener; + this.evictionStrategy = builder.evictionStrategy; + } + + /** + * Retrieves the value associated with the specified key from the cache. + * + *

If the key is not present or the corresponding entry has expired, this method + * returns {@code null}. If an expired entry is found, it will be removed and the + * eviction listener (if any) will be notified. Cache hit-and-miss statistics are + * also updated accordingly. + * + * @param key the key whose associated value is to be returned; must not be {@code null} + * @return the cached value associated with the key, or {@code null} if not present or expired + * @throws IllegalArgumentException if {@code key} is {@code null} + */ + public V get(K key) { + if (key == null) { + throw new IllegalArgumentException("Key must not be null"); + } + + lock.lock(); + try { + evictionStrategy.onAccess(this); + + CacheEntry entry = cache.get(key); + if (entry == null || entry.isExpired()) { + if (entry != null) { + removeKey(key); + notifyEviction(key, entry.value); + } + misses++; + return null; + } + hits++; + return entry.value; + } finally { + lock.unlock(); + } + } + + /** + * Adds a key-value pair to the cache using the default time-to-live (TTL). + * + *

The key may overwrite an existing entry. The actual insertion is delegated + * to the overloaded {@link #put(K, V, long)} method. + * + * @param key the key to cache the value under + * @param value the value to be cached + */ + public void put(K key, V value) { + put(key, value, defaultTTL); + } + + /** + * Adds a key-value pair to the cache with a specified time-to-live (TTL). + * + *

If the key already exists, its value is updated and its TTL is reset. If the key + * does not exist and the cache is full, a random entry is evicted to make space. + * Expired entries are also cleaned up prior to any eviction. The eviction listener + * is notified when an entry gets evicted. + * + * @param key the key to associate with the cached value; must not be {@code null} + * @param value the value to be cached; must not be {@code null} + * @param ttlMillis the time-to-live for this entry in milliseconds; must be >= 0 + * @throws IllegalArgumentException if {@code key} or {@code value} is {@code null}, or if {@code ttlMillis} is negative + */ + public void put(K key, V value, long ttlMillis) { + if (key == null || value == null) { + throw new IllegalArgumentException("Key and value must not be null"); + } + if (ttlMillis < 0) { + throw new IllegalArgumentException("TTL must be >= 0"); + } + + lock.lock(); + try { + if (cache.containsKey(key)) { + cache.put(key, new CacheEntry<>(value, ttlMillis)); + return; + } + + evictExpired(); + + if (cache.size() >= capacity) { + int idx = random.nextInt(keys.size()); + K evictKey = keys.remove(idx); + CacheEntry evictVal = cache.remove(evictKey); + notifyEviction(evictKey, evictVal.value); + } + + cache.put(key, new CacheEntry<>(value, ttlMillis)); + keys.add(key); + } finally { + lock.unlock(); + } + } + + /** + * Removes all expired entries from the cache. + * + *

This method iterates through the list of cached keys and checks each associated + * entry for expiration. Expired entries are removed from both the key tracking list + * and the cache map. For each eviction, the eviction listener is notified. + */ + private int evictExpired() { + Iterator it = keys.iterator(); + int expiredCount = 0; + + while (it.hasNext()) { + K k = it.next(); + CacheEntry entry = cache.get(k); + if (entry != null && entry.isExpired()) { + it.remove(); + cache.remove(k); + ++expiredCount; + notifyEviction(k, entry.value); + } + } + return expiredCount; + } + + /** + * Removes the specified key and its associated entry from the cache. + * + *

This method deletes the key from both the cache map and the key tracking list. + * + * @param key the key to remove from the cache + */ + private void removeKey(K key) { + cache.remove(key); + keys.remove(key); + } + + /** + * Notifies the eviction listener, if one is registered, that a key-value pair has been evicted. + * + *

If the {@code evictionListener} is not {@code null}, it is invoked with the provided key + * and value. Any exceptions thrown by the listener are caught and logged to standard error, + * preventing them from disrupting cache operations. + * + * @param key the key that was evicted + * @param value the value that was associated with the evicted key + */ + private void notifyEviction(K key, V value) { + if (evictionListener != null) { + try { + evictionListener.accept(key, value); + } catch (Exception e) { + System.err.println("Eviction listener failed: " + e.getMessage()); + } + } + } + + /** + * Returns the number of successful cache lookups (hits). + * + * @return the number of cache hits + */ + public long getHits() { + lock.lock(); + try { + return hits; + } finally { + lock.unlock(); + } + } + + /** + * Returns the number of failed cache lookups (misses), including expired entries. + * + * @return the number of cache misses + */ + public long getMisses() { + lock.lock(); + try { + return misses; + } finally { + lock.unlock(); + } + } + + /** + * Returns the current number of entries in the cache, excluding expired ones. + * + * @return the current cache size + */ + public int size() { + lock.lock(); + try { + int cachedSize = cache.size(); + int evictedCount = evictionStrategy.onAccess(this); + if (evictedCount > 0) { + return cachedSize - evictedCount; + } + + // This runs if periodic eviction does not occur + int count = 0; + for (Map.Entry> entry : cache.entrySet()) { + if (!entry.getValue().isExpired()) { + ++count; + } + } + return count; + } finally { + lock.unlock(); + } + } + + /** + * Returns the current {@link EvictionStrategy} used by this cache instance. + + * @return the eviction strategy currently assigned to this cache + */ + public EvictionStrategy getEvictionStrategy() { + return evictionStrategy; + } + + /** + * Returns a string representation of the cache, including metadata and current non-expired entries. + * + *

The returned string includes the cache's capacity, current size (excluding expired entries), + * hit-and-miss counts, and a map of all non-expired key-value pairs. This method acquires a lock + * to ensure thread-safe access. + * + * @return a string summarizing the state of the cache + */ + @Override + public String toString() { + lock.lock(); + try { + Map visible = new HashMap<>(); + for (Map.Entry> entry : cache.entrySet()) { + if (!entry.getValue().isExpired()) { + visible.put(entry.getKey(), entry.getValue().value); + } + } + return String.format("Cache(capacity=%d, size=%d, hits=%d, misses=%d, entries=%s)", capacity, visible.size(), hits, misses, visible); + } finally { + lock.unlock(); + } + } + + /** + * A strategy interface for controlling when expired entries are evicted from the cache. + * + *

Implementations decide whether and when to trigger {@link RRCache#evictExpired()} based + * on cache usage patterns. This allows for flexible eviction behaviour such as periodic cleanup, + * or no automatic cleanup. + * + * @param the type of keys maintained by the cache + * @param the type of cached values + */ + public interface EvictionStrategy { + /** + * Called on each cache access (e.g., {@link RRCache#get(Object)}) to optionally trigger eviction. + * + * @param cache the cache instance on which this strategy is applied + * @return the number of expired entries evicted during this access + */ + int onAccess(RRCache cache); + } + + /** + * An eviction strategy that performs eviction of expired entries on each call. + * + * @param the type of keys + * @param the type of values + */ + public static class NoEvictionStrategy implements EvictionStrategy { + @Override + public int onAccess(RRCache cache) { + return cache.evictExpired(); + } + } + + /** + * An eviction strategy that triggers eviction every fixed number of accesses. + * + *

This deterministic strategy ensures cleanup occurs at predictable intervals, + * ideal for moderately active caches where memory usage is a concern. + * + * @param the type of keys + * @param the type of values + */ + public static class PeriodicEvictionStrategy implements EvictionStrategy { + private final int interval; + private int counter = 0; + + /** + * Constructs a periodic eviction strategy. + * + * @param interval the number of accesses between evictions; must be > 0 + * @throws IllegalArgumentException if {@code interval} is less than or equal to 0 + */ + public PeriodicEvictionStrategy(int interval) { + if (interval <= 0) { + throw new IllegalArgumentException("Interval must be > 0"); + } + this.interval = interval; + } + + @Override + public int onAccess(RRCache cache) { + if (++counter % interval == 0) { + return cache.evictExpired(); + } + + return 0; + } + } + + /** + * A builder for constructing an {@link RRCache} instance with customizable settings. + * + *

Allows configuring capacity, default TTL, random eviction behavior, eviction listener, + * and a pluggable eviction strategy. Call {@link #build()} to create the configured cache instance. + * + * @param the type of keys maintained by the cache + * @param the type of values stored in the cache + */ + public static class Builder { + private final int capacity; + private long defaultTTL = 0; + private Random random; + private BiConsumer evictionListener; + private EvictionStrategy evictionStrategy = new RRCache.PeriodicEvictionStrategy<>(100); + /** + * Creates a new {@code Builder} with the specified cache capacity. + * + * @param capacity the maximum number of entries the cache can hold; must be > 0 + * @throws IllegalArgumentException if {@code capacity} is less than or equal to 0 + */ + public Builder(int capacity) { + if (capacity <= 0) { + throw new IllegalArgumentException("Capacity must be > 0"); + } + this.capacity = capacity; + } + + /** + * Sets the default time-to-live (TTL) in milliseconds for cache entries. + * + * @param ttlMillis the TTL duration in milliseconds; must be >= 0 + * @return this builder instance for chaining + * @throws IllegalArgumentException if {@code ttlMillis} is negative + */ + public Builder defaultTTL(long ttlMillis) { + if (ttlMillis < 0) { + throw new IllegalArgumentException("Default TTL must be >= 0"); + } + this.defaultTTL = ttlMillis; + return this; + } + + /** + * Sets the {@link Random} instance to be used for random eviction selection. + * + * @param r a non-null {@code Random} instance + * @return this builder instance for chaining + * @throws IllegalArgumentException if {@code r} is {@code null} + */ + public Builder random(Random r) { + if (r == null) { + throw new IllegalArgumentException("Random must not be null"); + } + this.random = r; + return this; + } + + /** + * Sets an eviction listener to be notified when entries are evicted from the cache. + * + * @param listener a {@link BiConsumer} that accepts evicted keys and values; must not be {@code null} + * @return this builder instance for chaining + * @throws IllegalArgumentException if {@code listener} is {@code null} + */ + public Builder evictionListener(BiConsumer listener) { + if (listener == null) { + throw new IllegalArgumentException("Listener must not be null"); + } + this.evictionListener = listener; + return this; + } + + /** + * Builds and returns a new {@link RRCache} instance with the configured parameters. + * + * @return a fully configured {@code RRCache} instance + */ + public RRCache build() { + return new RRCache<>(this); + } + + /** + * Sets the eviction strategy used to determine when to clean up expired entries. + * + * @param strategy an {@link EvictionStrategy} implementation; must not be {@code null} + * @return this builder instance + * @throws IllegalArgumentException if {@code strategy} is {@code null} + */ + public Builder evictionStrategy(EvictionStrategy strategy) { + if (strategy == null) { + throw new IllegalArgumentException("Eviction strategy must not be null"); + } + this.evictionStrategy = strategy; + return this; + } + } +} diff --git a/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java b/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java index 2c6ce8a427d1..d33bd3ee84d9 100644 --- a/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java +++ b/src/main/java/com/thealgorithms/datastructures/crdt/LWWElementSet.java @@ -1,53 +1,33 @@ package com.thealgorithms.datastructures.crdt; +import java.time.Instant; import java.util.HashMap; import java.util.Map; /** - * Last-Write-Wins Element Set (LWWElementSet) is a state-based CRDT (Conflict-free Replicated Data Type) - * designed for managing sets in a distributed and concurrent environment. It supports the addition and removal - * of elements, using timestamps to determine the order of operations. The set is split into two subsets: - * the add set for elements to be added and the remove set for elements to be removed. + * Last-Write-Wins Element Set (LWWElementSet) is a state-based CRDT (Conflict-free Replicated Data + * Type) designed for managing sets in a distributed and concurrent environment. It supports the + * addition and removal of elements, using timestamps to determine the order of operations. The set + * is split into two subsets: the add set for elements to be added and the remove set for elements + * to be removed. The LWWElementSet ensures that the most recent operation (based on the timestamp) + * wins in the case of concurrent operations. * - * @author itakurah (Niklas Hoefflin) (https://github.com/itakurah) - * @see Conflict-free_replicated_data_type - * @see itakurah (Niklas Hoefflin) + * @param The type of the elements in the LWWElementSet. + * @author itakurah (GitHub), Niklas Hoefflin (LinkedIn) + * @see Conflict free + * replicated data type (Wikipedia) + * @see A comprehensive study of + * Convergent and Commutative Replicated Data Types */ - -class Element { - String key; - int timestamp; - Bias bias; +class LWWElementSet { + final Map> addSet; + final Map> removeSet; /** - * Constructs a new Element with the specified key, timestamp and bias. - * - * @param key The key of the element. - * @param timestamp The timestamp associated with the element. - * @param bias The bias of the element (ADDS or REMOVALS). - */ - Element(String key, int timestamp, Bias bias) { - this.key = key; - this.timestamp = timestamp; - this.bias = bias; - } -} - -enum Bias { - /** - * ADDS bias for the add set. - * REMOVALS bias for the remove set. - */ - ADDS, - REMOVALS -} - -class LWWElementSet { - private final Map addSet; - private final Map removeSet; - - /** - * Constructs an empty LWWElementSet. + * Constructs an empty LWWElementSet. This constructor initializes the addSet and removeSet as + * empty HashMaps. The addSet stores elements that are added, and the removeSet stores elements + * that are removed. */ LWWElementSet() { this.addSet = new HashMap<>(); @@ -55,84 +35,92 @@ class LWWElementSet { } /** - * Adds an element to the addSet. + * Adds an element to the addSet with the current timestamp. This method stores the element in the + * addSet, ensuring that the element is added to the set with an associated timestamp that + * represents the time of the addition. * - * @param e The element to be added. + * @param key The key of the element to be added. */ - public void add(Element e) { - addSet.put(e.key, e); + public void add(T key) { + addSet.put(key, new Element<>(key, Instant.now())); } /** - * Removes an element from the removeSet. + * Removes an element by adding it to the removeSet with the current timestamp. This method adds + * the element to the removeSet, marking it as removed with the current timestamp. * - * @param e The element to be removed. + * @param key The key of the element to be removed. */ - public void remove(Element e) { - if (lookup(e)) { - removeSet.put(e.key, e); - } + public void remove(T key) { + removeSet.put(key, new Element<>(key, Instant.now())); } /** - * Checks if an element is in the LWWElementSet by comparing timestamps in the addSet and removeSet. + * Checks if an element is in the LWWElementSet. An element is considered present if it exists in + * the addSet and either does not exist in the removeSet, or its add timestamp is later than any + * corresponding remove timestamp. * - * @param e The element to be checked. - * @return True if the element is present, false otherwise. + * @param key The key of the element to be checked. + * @return {@code true} if the element is present in the set (i.e., its add timestamp is later + * than its remove timestamp, or it is not in the remove set), {@code false} otherwise (i.e., + * the element has been removed or its remove timestamp is later than its add timestamp). */ - public boolean lookup(Element e) { - Element inAddSet = addSet.get(e.key); - Element inRemoveSet = removeSet.get(e.key); + public boolean lookup(T key) { + Element inAddSet = addSet.get(key); + Element inRemoveSet = removeSet.get(key); - return (inAddSet != null && (inRemoveSet == null || inAddSet.timestamp > inRemoveSet.timestamp)); + return inAddSet != null && (inRemoveSet == null || inAddSet.timestamp.isAfter(inRemoveSet.timestamp)); } /** - * Compares the LWWElementSet with another LWWElementSet to check if addSet and removeSet are a subset. + * Merges another LWWElementSet into this set. This method takes the union of both the add-sets + * and remove-sets from the two sets, resolving conflicts by keeping the element with the latest + * timestamp. If an element appears in both the add-set and remove-set of both sets, the one with + * the later timestamp will be retained. * - * @param other The LWWElementSet to compare. - * @return True if the set is subset, false otherwise. + * @param other The LWWElementSet to merge with the current set. */ - public boolean compare(LWWElementSet other) { - return other.addSet.keySet().containsAll(addSet.keySet()) && other.removeSet.keySet().containsAll(removeSet.keySet()); + public void merge(LWWElementSet other) { + for (Map.Entry> entry : other.addSet.entrySet()) { + addSet.merge(entry.getKey(), entry.getValue(), this::resolveConflict); + } + for (Map.Entry> entry : other.removeSet.entrySet()) { + removeSet.merge(entry.getKey(), entry.getValue(), this::resolveConflict); + } } /** - * Merges another LWWElementSet into this set by resolving conflicts based on timestamps. + * Resolves conflicts between two elements by selecting the one with the later timestamp. This + * method is used when merging two LWWElementSets to ensure that the most recent operation (based + * on timestamps) is kept. * - * @param other The LWWElementSet to merge. + * @param e1 The first element. + * @param e2 The second element. + * @return The element with the later timestamp. */ - public void merge(LWWElementSet other) { - for (Element e : other.addSet.values()) { - if (!addSet.containsKey(e.key) || compareTimestamps(addSet.get(e.key), e)) { - addSet.put(e.key, e); - } - } - - for (Element e : other.removeSet.values()) { - if (!removeSet.containsKey(e.key) || compareTimestamps(removeSet.get(e.key), e)) { - removeSet.put(e.key, e); - } - } + private Element resolveConflict(Element e1, Element e2) { + return e1.timestamp.isAfter(e2.timestamp) ? e1 : e2; } +} + +/** + * Represents an element in the LWWElementSet, consisting of a key and a timestamp. This class is + * used to store the elements in both the add and remove sets with their respective timestamps. + * + * @param The type of the key associated with the element. + */ +class Element { + T key; + Instant timestamp; /** - * Compares timestamps of two elements based on their bias (ADDS or REMOVALS). + * Constructs a new Element with the specified key and timestamp. * - * @param e The first element. - * @param other The second element. - * @return True if the first element's timestamp is greater or the bias is ADDS and timestamps are equal. + * @param key The key of the element. + * @param timestamp The timestamp associated with the element. */ - public boolean compareTimestamps(Element e, Element other) { - if (e.bias != other.bias) { - throw new IllegalArgumentException("Invalid bias value"); - } - Bias bias = e.bias; - int timestampComparison = Integer.compare(e.timestamp, other.timestamp); - - if (timestampComparison == 0) { - return bias != Bias.ADDS; - } - return timestampComparison < 0; + Element(T key, Instant timestamp) { + this.key = key; + this.timestamp = timestamp; } } diff --git a/src/main/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnion.java b/src/main/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnion.java index 583800998c81..55951be82c8a 100644 --- a/src/main/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnion.java +++ b/src/main/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnion.java @@ -1,53 +1,65 @@ package com.thealgorithms.datastructures.disjointsetunion; /** - * Disjoint Set Union or DSU is useful for solving problems related to connected components, - * cycle detection in graphs, and maintaining relationships in disjoint sets of data. - * It is commonly employed in graph algorithms and problems. + * Disjoint Set Union (DSU), also known as Union-Find, is a data structure that tracks a set of elements + * partitioned into disjoint (non-overlapping) subsets. It supports two primary operations efficiently: * - * @see Disjoint Set Union + *

    + *
  • Find: Determine which subset a particular element belongs to.
  • + *
  • Union: Merge two subsets into a single subset.
  • + *
+ * + * @see Disjoint Set Union (Wikipedia) */ public class DisjointSetUnion { /** - * Creates a new node of DSU with parent initialised as same node + * Creates a new disjoint set containing the single specified element. + * + * @param value the element to be placed in a new singleton set + * @return a node representing the new set */ - public Node makeSet(final T x) { - return new Node(x); + public Node makeSet(final T value) { + return new Node<>(value); } /** - * Finds and returns the representative (root) element of the set to which a given element belongs. - * This operation uses path compression to optimize future findSet operations. + * Finds and returns the representative (root) of the set containing the given node. + * This method applies path compression to flatten the tree structure for future efficiency. + * + * @param node the node whose set representative is to be found + * @return the representative (root) node of the set */ public Node findSet(Node node) { - while (node != node.parent) { - node = node.parent; + if (node != node.parent) { + node.parent = findSet(node.parent); } - return node; + return node.parent; } /** - * Unions two sets by merging their representative elements. The merge is performed based on the rank of each set - * to ensure efficient merging and path compression to optimize future findSet operations. + * Merges the sets containing the two given nodes. Union by rank is used to attach the smaller tree under the larger one. + * If both sets have the same rank, one becomes the parent and its rank is incremented. + * + * @param x a node in the first set + * @param y a node in the second set */ - public void unionSets(final Node x, final Node y) { - Node nx = findSet(x); - Node ny = findSet(y); + public void unionSets(Node x, Node y) { + Node rootX = findSet(x); + Node rootY = findSet(y); - if (nx == ny) { - return; // Both elements already belong to the same set. + if (rootX == rootY) { + return; // They are already in the same set } // Merging happens based on rank of node, this is done to avoid long chaining of nodes and reduce time // to find root of the component. Idea is to attach small components in big, instead of other way around. - if (nx.rank > ny.rank) { - ny.parent = nx; - } else if (ny.rank > nx.rank) { - nx.parent = ny; + if (rootX.rank > rootY.rank) { + rootY.parent = rootX; + } else if (rootY.rank > rootX.rank) { + rootX.parent = rootY; } else { - // Both sets have the same rank; choose one as the parent and increment the rank. - ny.parent = nx; - nx.rank++; + rootY.parent = rootX; + rootX.rank++; } } } diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/Kruskal.java b/src/main/java/com/thealgorithms/datastructures/graphs/Kruskal.java index 25c4548daa7a..331d7196b61c 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/Kruskal.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/Kruskal.java @@ -19,6 +19,7 @@ * *

Time Complexity: O(E log V), where E is the number of edges and V is the number of vertices.

*/ +@SuppressWarnings({"rawtypes", "unchecked"}) public class Kruskal { /** diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/UndirectedAdjacencyListGraph.java b/src/main/java/com/thealgorithms/datastructures/graphs/UndirectedAdjacencyListGraph.java new file mode 100644 index 000000000000..8aafc1ef3368 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/graphs/UndirectedAdjacencyListGraph.java @@ -0,0 +1,69 @@ +package com.thealgorithms.datastructures.graphs; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; + +public class UndirectedAdjacencyListGraph { + private ArrayList> adjacencyList = new ArrayList<>(); + + /** + * Adds a new node to the graph by adding an empty HashMap for its neighbors. + * @return the index of the newly added node in the adjacency list + */ + public int addNode() { + adjacencyList.add(new HashMap<>()); + return adjacencyList.size() - 1; + } + + /** + * Adds an undirected edge between the origin node (@orig) and the destination node (@dest) with the specified weight. + * If the edge already exists, no changes are made. + * @param orig the index of the origin node + * @param dest the index of the destination node + * @param weight the weight of the edge between @orig and @dest + * @return true if the edge was successfully added, false if the edge already exists or if any node index is invalid + */ + public boolean addEdge(int orig, int dest, int weight) { + int numNodes = adjacencyList.size(); + if (orig >= numNodes || dest >= numNodes || orig < 0 || dest < 0) { + return false; + } + + if (adjacencyList.get(orig).containsKey(dest)) { + return false; + } + + adjacencyList.get(orig).put(dest, weight); + adjacencyList.get(dest).put(orig, weight); + return true; + } + + /** + * Returns the set of all adjacent nodes (neighbors) for the given node. + * @param node the index of the node whose neighbors are to be retrieved + * @return a HashSet containing the indices of all neighboring nodes + */ + public HashSet getNeighbors(int node) { + return new HashSet<>(adjacencyList.get(node).keySet()); + } + + /** + * Returns the weight of the edge between the origin node (@orig) and the destination node (@dest). + * If no edge exists, returns null. + * @param orig the index of the origin node + * @param dest the index of the destination node + * @return the weight of the edge between @orig and @dest, or null if no edge exists + */ + public Integer getEdgeWeight(int orig, int dest) { + return adjacencyList.get(orig).getOrDefault(dest, null); + } + + /** + * Returns the number of nodes currently in the graph. + * @return the number of nodes in the graph + */ + public int size() { + return adjacencyList.size(); + } +} diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/WelshPowell.java b/src/main/java/com/thealgorithms/datastructures/graphs/WelshPowell.java index 26ca97736fe9..4bf21c7ed4c1 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/WelshPowell.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/WelshPowell.java @@ -22,6 +22,7 @@ * For more information, see Graph Coloring. *

*/ +@SuppressWarnings({"rawtypes", "unchecked"}) public final class WelshPowell { private static final int BLANK_COLOR = -1; // Constant representing an uncolored state diff --git a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java index 3637e323f097..36d2cc8df160 100644 --- a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java +++ b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/GenericHashMapUsingArray.java @@ -23,6 +23,7 @@ * @param the type of keys maintained by this hash map * @param the type of mapped values */ +@SuppressWarnings({"rawtypes", "unchecked"}) public class GenericHashMapUsingArray { private int size; // Total number of key-value pairs diff --git a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/HashMap.java b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/HashMap.java index aed39c941430..1b0792b8a738 100644 --- a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/HashMap.java +++ b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/HashMap.java @@ -8,6 +8,7 @@ * @param the type of keys maintained by this map * @param the type of mapped values */ +@SuppressWarnings("rawtypes") public class HashMap { private final int hashSize; private final LinkedList[] buckets; diff --git a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/Intersection.java b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/Intersection.java index 0e49218d6348..5760d39f1df7 100644 --- a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/Intersection.java +++ b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/Intersection.java @@ -8,60 +8,66 @@ /** * The {@code Intersection} class provides a method to compute the intersection of two integer arrays. - * The intersection is defined as the set of common elements present in both arrays. *

- * This class utilizes a HashMap to efficiently count occurrences of elements in the first array, - * allowing for an efficient lookup of common elements in the second array. + * This intersection includes duplicate values — meaning elements are included in the result + * as many times as they appear in both arrays (i.e., multiset intersection). *

* *

- * Example: - *

+ * The algorithm uses a {@link java.util.HashMap} to count occurrences of elements in the first array,
+ * then iterates through the second array to collect common elements based on these counts.
+ * 

+ * + *

+ * Example usage: + *

{@code
  * int[] array1 = {1, 2, 2, 1};
  * int[] array2 = {2, 2};
- * List result = Intersection.intersection(array1, array2); // result will contain [2, 2]
- * 
+ * List result = Intersection.intersection(array1, array2); // result: [2, 2] + * }
*

* *

- * Note: The order of the returned list may vary since it depends on the order of elements - * in the input arrays. + * Note: The order of elements in the returned list depends on the order in the second input array. *

*/ public final class Intersection { + private Intersection() { + // Utility class; prevent instantiation + } + /** - * Computes the intersection of two integer arrays. + * Computes the intersection of two integer arrays, preserving element frequency. + * For example, given [1,2,2,3] and [2,2,4], the result will be [2,2]. + * * Steps: - * 1. Count the occurrences of each element in the first array using a HashMap. - * 2. Iterate over the second array and check if the element is present in the HashMap. - * If it is, add it to the result list and decrement the count in the HashMap. - * 3. Return the result list containing the intersection of the two arrays. + * 1. Count the occurrences of each element in the first array using a map. + * 2. Iterate over the second array and collect common elements. * * @param arr1 the first array of integers * @param arr2 the second array of integers - * @return a list containing the intersection of the two arrays, or an empty list if either array is null or empty + * @return a list containing the intersection of the two arrays (with duplicates), + * or an empty list if either array is null or empty */ public static List intersection(int[] arr1, int[] arr2) { if (arr1 == null || arr2 == null || arr1.length == 0 || arr2.length == 0) { return Collections.emptyList(); } - Map cnt = new HashMap<>(16); - for (int v : arr1) { - cnt.put(v, cnt.getOrDefault(v, 0) + 1); + Map countMap = new HashMap<>(); + for (int num : arr1) { + countMap.put(num, countMap.getOrDefault(num, 0) + 1); } - List res = new ArrayList<>(); - for (int v : arr2) { - if (cnt.containsKey(v) && cnt.get(v) > 0) { - res.add(v); - cnt.put(v, cnt.get(v) - 1); + List result = new ArrayList<>(); + for (int num : arr2) { + if (countMap.getOrDefault(num, 0) > 0) { + result.add(num); + countMap.computeIfPresent(num, (k, v) -> v - 1); } } - return res; - } - private Intersection() { + return result; } } diff --git a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMap.java b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMap.java index 10d5dc7decae..761a5fe83d18 100644 --- a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMap.java +++ b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/LinearProbingHashMap.java @@ -34,6 +34,7 @@ * @param the type of keys maintained by this map * @param the type of mapped values */ +@SuppressWarnings("rawtypes") public class LinearProbingHashMap, Value> extends Map { private int hsize; // size of the hash table private Key[] keys; // array to store keys diff --git a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/MajorityElement.java b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/MajorityElement.java index 915e4228b618..5fd6b2e7f3cb 100644 --- a/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/MajorityElement.java +++ b/src/main/java/com/thealgorithms/datastructures/hashmap/hashing/MajorityElement.java @@ -1,8 +1,10 @@ package com.thealgorithms.datastructures.hashmap.hashing; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Map; /** * This class provides a method to find the majority element(s) in an array of integers. @@ -18,13 +20,18 @@ private MajorityElement() { * Returns a list of majority element(s) from the given array of integers. * * @param nums an array of integers - * @return a list containing the majority element(s); returns an empty list if none exist + * @return a list containing the majority element(s); returns an empty list if none exist or input is null/empty */ public static List majority(int[] nums) { - HashMap numToCount = new HashMap<>(); + if (nums == null || nums.length == 0) { + return Collections.emptyList(); + } + + Map numToCount = new HashMap<>(); for (final var num : nums) { numToCount.merge(num, 1, Integer::sum); } + List majorityElements = new ArrayList<>(); for (final var entry : numToCount.entrySet()) { if (entry.getValue() >= nums.length / 2) { diff --git a/src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java b/src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java index 422e8953625f..72a12cd58401 100644 --- a/src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java +++ b/src/main/java/com/thealgorithms/datastructures/lists/CircleLinkedList.java @@ -10,6 +10,7 @@ * * @param the type of elements held in this list */ +@SuppressWarnings("rawtypes") public class CircleLinkedList { /** diff --git a/src/main/java/com/thealgorithms/datastructures/lists/CountSinglyLinkedListRecursion.java b/src/main/java/com/thealgorithms/datastructures/lists/CountSinglyLinkedListRecursion.java index 4c1ffe9d3ea4..b58d51e7e5fe 100644 --- a/src/main/java/com/thealgorithms/datastructures/lists/CountSinglyLinkedListRecursion.java +++ b/src/main/java/com/thealgorithms/datastructures/lists/CountSinglyLinkedListRecursion.java @@ -12,7 +12,7 @@ public class CountSinglyLinkedListRecursion extends SinglyLinkedList { * @param head the head node of the list segment being counted. * @return the count of nodes from the given head node onward. */ - private int countRecursion(Node head) { + private int countRecursion(SinglyLinkedListNode head) { return head == null ? 0 : 1 + countRecursion(head.next); } diff --git a/src/main/java/com/thealgorithms/datastructures/lists/CursorLinkedList.java b/src/main/java/com/thealgorithms/datastructures/lists/CursorLinkedList.java index ff3d39115c3b..63bb29034df2 100644 --- a/src/main/java/com/thealgorithms/datastructures/lists/CursorLinkedList.java +++ b/src/main/java/com/thealgorithms/datastructures/lists/CursorLinkedList.java @@ -10,6 +10,7 @@ * * @param the type of elements in this list */ +@SuppressWarnings({"rawtypes", "unchecked"}) public class CursorLinkedList { /** diff --git a/src/main/java/com/thealgorithms/datastructures/lists/MergeSortedSinglyLinkedList.java b/src/main/java/com/thealgorithms/datastructures/lists/MergeSortedSinglyLinkedList.java index a16b202c4505..4e99642fccd8 100644 --- a/src/main/java/com/thealgorithms/datastructures/lists/MergeSortedSinglyLinkedList.java +++ b/src/main/java/com/thealgorithms/datastructures/lists/MergeSortedSinglyLinkedList.java @@ -42,12 +42,12 @@ public static SinglyLinkedList merge(SinglyLinkedList listA, SinglyLinkedList li throw new NullPointerException("Input lists must not be null."); } - Node headA = listA.getHead(); - Node headB = listB.getHead(); + SinglyLinkedListNode headA = listA.getHead(); + SinglyLinkedListNode headB = listB.getHead(); int size = listA.size() + listB.size(); - Node head = new Node(); - Node tail = head; + SinglyLinkedListNode head = new SinglyLinkedListNode(); + SinglyLinkedListNode tail = head; while (headA != null && headB != null) { if (headA.value <= headB.value) { tail.next = headA; diff --git a/src/main/java/com/thealgorithms/datastructures/lists/QuickSortLinkedList.java b/src/main/java/com/thealgorithms/datastructures/lists/QuickSortLinkedList.java index 08fe674b47f4..f018781ada70 100644 --- a/src/main/java/com/thealgorithms/datastructures/lists/QuickSortLinkedList.java +++ b/src/main/java/com/thealgorithms/datastructures/lists/QuickSortLinkedList.java @@ -105,7 +105,7 @@ public class QuickSortLinkedList { private final SinglyLinkedList list; // The linked list to be sorted - private Node head; // Head of the list + private SinglyLinkedListNode head; // Head of the list /** * Constructor that initializes the QuickSortLinkedList with a given linked list. @@ -136,19 +136,19 @@ public void sortList() { * @param head The head node of the list to sort * @return The head node of the sorted linked list */ - private Node sortList(Node head) { + private SinglyLinkedListNode sortList(SinglyLinkedListNode head) { if (head == null || head.next == null) { return head; } - Node pivot = head; + SinglyLinkedListNode pivot = head; head = head.next; pivot.next = null; - Node lessHead = new Node(); - Node lessTail = lessHead; - Node greaterHead = new Node(); - Node greaterTail = greaterHead; + SinglyLinkedListNode lessHead = new SinglyLinkedListNode(); + SinglyLinkedListNode lessTail = lessHead; + SinglyLinkedListNode greaterHead = new SinglyLinkedListNode(); + SinglyLinkedListNode greaterTail = greaterHead; while (head != null) { if (head.value < pivot.value) { @@ -164,14 +164,14 @@ private Node sortList(Node head) { lessTail.next = null; greaterTail.next = null; - Node sortedLess = sortList(lessHead.next); - Node sortedGreater = sortList(greaterHead.next); + SinglyLinkedListNode sortedLess = sortList(lessHead.next); + SinglyLinkedListNode sortedGreater = sortList(greaterHead.next); if (sortedLess == null) { pivot.next = sortedGreater; return pivot; } else { - Node current = sortedLess; + SinglyLinkedListNode current = sortedLess; while (current.next != null) { current = current.next; } diff --git a/src/main/java/com/thealgorithms/datastructures/lists/ReverseKGroup.java b/src/main/java/com/thealgorithms/datastructures/lists/ReverseKGroup.java index c9a5c1df9870..9b9464d388b5 100644 --- a/src/main/java/com/thealgorithms/datastructures/lists/ReverseKGroup.java +++ b/src/main/java/com/thealgorithms/datastructures/lists/ReverseKGroup.java @@ -14,10 +14,10 @@ *

*

* The implementation contains: - * - {@code length(Node head)}: A method to calculate the length of the linked list. - * - {@code reverse(Node head, int count, int k)}: A helper method that reverses the nodes + * - {@code length(SinglyLinkedListNode head)}: A method to calculate the length of the linked list. + * - {@code reverse(SinglyLinkedListNode head, int count, int k)}: A helper method that reverses the nodes * in the linked list in groups of k. - * - {@code reverseKGroup(Node head, int k)}: The main method that initiates the reversal + * - {@code reverseKGroup(SinglyLinkedListNode head, int k)}: The main method that initiates the reversal * process by calling the reverse method. *

*

@@ -38,8 +38,8 @@ public class ReverseKGroup { * @param head The head node of the linked list. * @return The total number of nodes in the linked list. */ - public int length(Node head) { - Node curr = head; + public int length(SinglyLinkedListNode head) { + SinglyLinkedListNode curr = head; int count = 0; while (curr != null) { curr = curr.next; @@ -56,14 +56,14 @@ public int length(Node head) { * @param k The size of the group to reverse. * @return The new head of the reversed linked list segment. */ - public Node reverse(Node head, int count, int k) { + public SinglyLinkedListNode reverse(SinglyLinkedListNode head, int count, int k) { if (count < k) { return head; } - Node prev = null; + SinglyLinkedListNode prev = null; int count1 = 0; - Node curr = head; - Node next = null; + SinglyLinkedListNode curr = head; + SinglyLinkedListNode next = null; while (curr != null && count1 < k) { next = curr.next; curr.next = prev; @@ -85,7 +85,7 @@ public Node reverse(Node head, int count, int k) { * @param k The size of the group to reverse. * @return The head of the modified linked list after reversal. */ - public Node reverseKGroup(Node head, int k) { + public SinglyLinkedListNode reverseKGroup(SinglyLinkedListNode head, int k) { int count = length(head); return reverse(head, count, k); } diff --git a/src/main/java/com/thealgorithms/datastructures/lists/RotateSinglyLinkedLists.java b/src/main/java/com/thealgorithms/datastructures/lists/RotateSinglyLinkedLists.java index 7676cc343653..47ee5397097c 100644 --- a/src/main/java/com/thealgorithms/datastructures/lists/RotateSinglyLinkedLists.java +++ b/src/main/java/com/thealgorithms/datastructures/lists/RotateSinglyLinkedLists.java @@ -38,12 +38,12 @@ public class RotateSinglyLinkedLists { * @param k The number of positions to rotate the list to the right. * @return The head of the rotated linked list. */ - public Node rotateRight(Node head, int k) { + public SinglyLinkedListNode rotateRight(SinglyLinkedListNode head, int k) { if (head == null || head.next == null || k == 0) { return head; } - Node curr = head; + SinglyLinkedListNode curr = head; int len = 1; while (curr.next != null) { curr = curr.next; diff --git a/src/main/java/com/thealgorithms/datastructures/lists/SearchSinglyLinkedListRecursion.java b/src/main/java/com/thealgorithms/datastructures/lists/SearchSinglyLinkedListRecursion.java index a40e9b2a1a66..4ac2de422595 100644 --- a/src/main/java/com/thealgorithms/datastructures/lists/SearchSinglyLinkedListRecursion.java +++ b/src/main/java/com/thealgorithms/datastructures/lists/SearchSinglyLinkedListRecursion.java @@ -30,7 +30,7 @@ public class SearchSinglyLinkedListRecursion extends SinglyLinkedList { * @param key the integer value to be searched for. * @return {@code true} if the value `key` is present in the list; otherwise, {@code false}. */ - private boolean searchRecursion(Node node, int key) { + private boolean searchRecursion(SinglyLinkedListNode node, int key) { return (node != null && (node.value == key || searchRecursion(node.next, key))); } diff --git a/src/main/java/com/thealgorithms/datastructures/lists/SinglyLinkedList.java b/src/main/java/com/thealgorithms/datastructures/lists/SinglyLinkedList.java index eb6cdf48f58b..ff4af4437cc7 100644 --- a/src/main/java/com/thealgorithms/datastructures/lists/SinglyLinkedList.java +++ b/src/main/java/com/thealgorithms/datastructures/lists/SinglyLinkedList.java @@ -12,7 +12,7 @@ public class SinglyLinkedList implements Iterable { /** * Head refer to the front of the list */ - private Node head; + private SinglyLinkedListNode head; /** * Size of SinglyLinkedList @@ -33,7 +33,7 @@ public SinglyLinkedList() { * @param head the head node of list * @param size the size of list */ - public SinglyLinkedList(Node head, int size) { + public SinglyLinkedList(SinglyLinkedListNode head, int size) { this.head = head; this.size = size; } @@ -44,8 +44,8 @@ public SinglyLinkedList(Node head, int size) { * */ public boolean detectLoop() { - Node currentNodeFast = head; - Node currentNodeSlow = head; + SinglyLinkedListNode currentNodeFast = head; + SinglyLinkedListNode currentNodeSlow = head; while (currentNodeFast != null && currentNodeFast.next != null) { currentNodeFast = currentNodeFast.next.next; currentNodeSlow = currentNodeSlow.next; @@ -61,12 +61,12 @@ public boolean detectLoop() { * If the length of the list is even then return item number length/2 * @return middle node of the list */ - public Node middle() { + public SinglyLinkedListNode middle() { if (head == null) { return null; } - Node firstCounter = head; - Node secondCounter = firstCounter.next; + SinglyLinkedListNode firstCounter = head; + SinglyLinkedListNode secondCounter = firstCounter.next; while (secondCounter != null && secondCounter.next != null) { firstCounter = firstCounter.next; secondCounter = secondCounter.next.next; @@ -82,15 +82,15 @@ public void swapNodes(int valueFirst, int valueSecond) { if (valueFirst == valueSecond) { return; } - Node previousA = null; - Node currentA = head; + SinglyLinkedListNode previousA = null; + SinglyLinkedListNode currentA = head; while (currentA != null && currentA.value != valueFirst) { previousA = currentA; currentA = currentA.next; } - Node previousB = null; - Node currentB = head; + SinglyLinkedListNode previousB = null; + SinglyLinkedListNode currentB = head; while (currentB != null && currentB.value != valueSecond) { previousB = currentB; currentB = currentB.next; @@ -117,7 +117,7 @@ public void swapNodes(int valueFirst, int valueSecond) { } // Swap next pointer - Node temp = currentA.next; + var temp = currentA.next; currentA.next = currentB.next; currentB.next = temp; } @@ -126,12 +126,12 @@ public void swapNodes(int valueFirst, int valueSecond) { * Reverse a singly linked list[Iterative] from a given node till the end * */ - public Node reverseListIter(Node node) { - Node prev = null; - Node curr = node; + public SinglyLinkedListNode reverseListIter(SinglyLinkedListNode node) { + SinglyLinkedListNode prev = null; + SinglyLinkedListNode curr = node; while (curr != null && curr.next != null) { - Node next = curr.next; + var next = curr.next; curr.next = prev; prev = curr; curr = next; @@ -149,13 +149,13 @@ public Node reverseListIter(Node node) { * Reverse a singly linked list[Recursive] from a given node till the end * */ - public Node reverseListRec(Node head) { + public SinglyLinkedListNode reverseListRec(SinglyLinkedListNode head) { if (head == null || head.next == null) { return head; } - Node prev = null; - Node h2 = reverseListRec(head.next); + SinglyLinkedListNode prev = null; + SinglyLinkedListNode h2 = reverseListRec(head.next); head.next.next = head; head.next = prev; @@ -167,7 +167,7 @@ public Node reverseListRec(Node head) { * Clear all nodes in the list */ public void clear() { - Node cur = head; + SinglyLinkedListNode cur = head; while (cur != null) { cur = cur.next; } @@ -198,7 +198,7 @@ public int size() { * * @return head of the list. */ - public Node getHead() { + public SinglyLinkedListNode getHead() { return head; } @@ -206,7 +206,7 @@ public Node getHead() { * Set head of the list. * */ - public void setHead(Node head) { + public void setHead(SinglyLinkedListNode head) { this.head = head; } @@ -249,10 +249,10 @@ public String toString() { } public void deleteDuplicates() { - Node pred = head; + SinglyLinkedListNode pred = head; // predecessor = the node // having sublist of its duplicates - Node newHead = head; + SinglyLinkedListNode newHead = head; while (newHead != null) { // if it's a beginning of duplicates sublist // skip all duplicates @@ -273,7 +273,7 @@ public void deleteDuplicates() { } public void print() { - Node temp = head; + SinglyLinkedListNode temp = head; while (temp != null && temp.next != null) { System.out.print(temp.value + "->"); temp = temp.next; @@ -310,7 +310,7 @@ public void insert(int data) { */ public void insertNth(int data, int position) { checkBounds(position, 0, size); - Node newNode = new Node(data); + SinglyLinkedListNode newNode = new SinglyLinkedListNode(data); if (head == null) { /* the list is empty */ head = newNode; @@ -325,7 +325,7 @@ public void insertNth(int data, int position) { return; } - Node cur = head; + SinglyLinkedListNode cur = head; for (int i = 0; i < position - 1; ++i) { cur = cur.next; } @@ -359,7 +359,7 @@ public void deleteNth(int position) { size--; return; } - Node cur = head; + SinglyLinkedListNode cur = head; for (int i = 0; i < position - 1; ++i) { cur = cur.next; } @@ -376,7 +376,7 @@ public void deleteNth(int position) { */ public int getNth(int index) { checkBounds(index, 0, size - 1); - Node cur = head; + SinglyLinkedListNode cur = head; for (int i = 0; i < index; ++i) { cur = cur.next; } @@ -440,7 +440,7 @@ public static void main(String[] arg) { } SinglyLinkedList instance = new SinglyLinkedList(); - Node head = new Node(0, new Node(2, new Node(3, new Node(3, new Node(4))))); + SinglyLinkedListNode head = new SinglyLinkedListNode(0, new SinglyLinkedListNode(2, new SinglyLinkedListNode(3, new SinglyLinkedListNode(3, new SinglyLinkedListNode(4))))); instance.setHead(head); instance.deleteDuplicates(); instance.print(); @@ -452,7 +452,7 @@ public Iterator iterator() { } private class SinglyLinkedListIterator implements Iterator { - private Node current; + private SinglyLinkedListNode current; SinglyLinkedListIterator() { current = head; @@ -474,43 +474,3 @@ public Integer next() { } } } - -/** - * This class is the nodes of the SinglyLinked List. They consist of a value and - * a pointer to the node after them. - */ -class Node { - - /** - * The value of the node - */ - int value; - - /** - * Point to the next node - */ - Node next; - - Node() { - } - - /** - * Constructor - * - * @param value Value to be put in the node - */ - Node(int value) { - this(value, null); - } - - /** - * Constructor - * - * @param value Value to be put in the node - * @param next Reference to the next node - */ - Node(int value, Node next) { - this.value = value; - this.next = next; - } -} diff --git a/src/main/java/com/thealgorithms/datastructures/lists/SinglyLinkedListNode.java b/src/main/java/com/thealgorithms/datastructures/lists/SinglyLinkedListNode.java new file mode 100644 index 000000000000..d0a06369215a --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/lists/SinglyLinkedListNode.java @@ -0,0 +1,34 @@ +package com.thealgorithms.datastructures.lists; + +/** + * This class is the nodes of the SinglyLinked List. They consist of a value and + * a pointer to the node after them. + */ +class SinglyLinkedListNode { + + int value; + SinglyLinkedListNode next = null; + + SinglyLinkedListNode() { + } + + /** + * Constructor + * + * @param value Value to be put in the node + */ + SinglyLinkedListNode(int value) { + this(value, null); + } + + /** + * Constructor + * + * @param value Value to be put in the node + * @param next Reference to the next node + */ + SinglyLinkedListNode(int value, SinglyLinkedListNode next) { + this.value = value; + this.next = next; + } +} diff --git a/src/main/java/com/thealgorithms/datastructures/lists/SkipList.java b/src/main/java/com/thealgorithms/datastructures/lists/SkipList.java index 3309ab24917d..0b4fcd91483c 100644 --- a/src/main/java/com/thealgorithms/datastructures/lists/SkipList.java +++ b/src/main/java/com/thealgorithms/datastructures/lists/SkipList.java @@ -29,6 +29,7 @@ * @param type of elements * @see Wiki. Skip list */ +@SuppressWarnings({"rawtypes", "unchecked"}) public class SkipList> { /** diff --git a/src/main/java/com/thealgorithms/datastructures/queues/QueueByTwoStacks.java b/src/main/java/com/thealgorithms/datastructures/queues/QueueByTwoStacks.java index 11e5e9b83892..981b3b32e0b2 100644 --- a/src/main/java/com/thealgorithms/datastructures/queues/QueueByTwoStacks.java +++ b/src/main/java/com/thealgorithms/datastructures/queues/QueueByTwoStacks.java @@ -11,6 +11,7 @@ * * @param The type of elements held in this queue. */ +@SuppressWarnings("unchecked") public class QueueByTwoStacks { private final Stack enqueueStk; diff --git a/src/main/java/com/thealgorithms/datastructures/trees/BTree.java b/src/main/java/com/thealgorithms/datastructures/trees/BTree.java new file mode 100644 index 000000000000..2c19253b45e7 --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/trees/BTree.java @@ -0,0 +1,323 @@ +package com.thealgorithms.datastructures.trees; + +import java.util.ArrayList; + +/** + * Implementation of a B-Tree, a self-balancing tree data structure that maintains sorted data + * and allows searches, sequential access, insertions, and deletions in logarithmic time. + * + * B-Trees are generalizations of binary search trees in that a node can have more than two children. + * They're widely used in databases and file systems. + * + * For more information: https://en.wikipedia.org/wiki/B-tree + */ + +public class BTree { + static class BTreeNode { + int[] keys; + int t; // Minimum degree (defines range for number of keys) + BTreeNode[] children; + int n; // Current number of keys + boolean leaf; + + BTreeNode(int t, boolean leaf) { + this.t = t; + this.leaf = leaf; + this.keys = new int[2 * t - 1]; + this.children = new BTreeNode[2 * t]; + this.n = 0; + } + + void traverse(ArrayList result) { + for (int i = 0; i < n; i++) { + if (!leaf) { + children[i].traverse(result); + } + result.add(keys[i]); + } + if (!leaf) { + children[n].traverse(result); + } + } + + BTreeNode search(int key) { + int i = 0; + while (i < n && key > keys[i]) { + i++; + } + if (i < n && keys[i] == key) { + return this; + } + if (leaf) { + return null; + } + return children[i].search(key); + } + + void insertNonFull(int key) { + int i = n - 1; + if (leaf) { + while (i >= 0 && keys[i] > key) { + keys[i + 1] = keys[i]; + i--; + } + keys[i + 1] = key; + n++; + } else { + while (i >= 0 && keys[i] > key) { + i--; + } + if (children[i + 1].n == 2 * t - 1) { + splitChild(i + 1, children[i + 1]); + if (keys[i + 1] < key) { + i++; + } + } + children[i + 1].insertNonFull(key); + } + } + + void splitChild(int i, BTreeNode y) { + BTreeNode z = new BTreeNode(y.t, y.leaf); + z.n = t - 1; + + System.arraycopy(y.keys, t, z.keys, 0, t - 1); + if (!y.leaf) { + System.arraycopy(y.children, t, z.children, 0, t); + } + y.n = t - 1; + + for (int j = n; j >= i + 1; j--) { + children[j + 1] = children[j]; + } + children[i + 1] = z; + + for (int j = n - 1; j >= i; j--) { + keys[j + 1] = keys[j]; + } + keys[i] = y.keys[t - 1]; + n++; + } + + void remove(int key) { + int idx = findKey(key); + + if (idx < n && keys[idx] == key) { + if (leaf) { + removeFromLeaf(idx); + } else { + removeFromNonLeaf(idx); + } + } else { + if (leaf) { + return; // Key not found + } + + boolean flag = idx == n; + if (children[idx].n < t) { + fill(idx); + } + + if (flag && idx > n) { + children[idx - 1].remove(key); + } else { + children[idx].remove(key); + } + } + } + + private int findKey(int key) { + int idx = 0; + while (idx < n && keys[idx] < key) { + ++idx; + } + return idx; + } + + private void removeFromLeaf(int idx) { + for (int i = idx + 1; i < n; ++i) { + keys[i - 1] = keys[i]; + } + n--; + } + + private void removeFromNonLeaf(int idx) { + int key = keys[idx]; + if (children[idx].n >= t) { + int pred = getPredecessor(idx); + keys[idx] = pred; + children[idx].remove(pred); + } else if (children[idx + 1].n >= t) { + int succ = getSuccessor(idx); + keys[idx] = succ; + children[idx + 1].remove(succ); + } else { + merge(idx); + children[idx].remove(key); + } + } + + private int getPredecessor(int idx) { + BTreeNode cur = children[idx]; + while (!cur.leaf) { + cur = cur.children[cur.n]; + } + return cur.keys[cur.n - 1]; + } + + private int getSuccessor(int idx) { + BTreeNode cur = children[idx + 1]; + while (!cur.leaf) { + cur = cur.children[0]; + } + return cur.keys[0]; + } + + private void fill(int idx) { + if (idx != 0 && children[idx - 1].n >= t) { + borrowFromPrev(idx); + } else if (idx != n && children[idx + 1].n >= t) { + borrowFromNext(idx); + } else { + if (idx != n) { + merge(idx); + } else { + merge(idx - 1); + } + } + } + + private void borrowFromPrev(int idx) { + BTreeNode child = children[idx]; + BTreeNode sibling = children[idx - 1]; + + for (int i = child.n - 1; i >= 0; --i) { + child.keys[i + 1] = child.keys[i]; + } + + if (!child.leaf) { + for (int i = child.n; i >= 0; --i) { + child.children[i + 1] = child.children[i]; + } + } + + child.keys[0] = keys[idx - 1]; + + if (!child.leaf) { + child.children[0] = sibling.children[sibling.n]; + } + + keys[idx - 1] = sibling.keys[sibling.n - 1]; + + child.n += 1; + sibling.n -= 1; + } + + private void borrowFromNext(int idx) { + BTreeNode child = children[idx]; + BTreeNode sibling = children[idx + 1]; + + child.keys[child.n] = keys[idx]; + + if (!child.leaf) { + child.children[child.n + 1] = sibling.children[0]; + } + + keys[idx] = sibling.keys[0]; + + for (int i = 1; i < sibling.n; ++i) { + sibling.keys[i - 1] = sibling.keys[i]; + } + + if (!sibling.leaf) { + for (int i = 1; i <= sibling.n; ++i) { + sibling.children[i - 1] = sibling.children[i]; + } + } + + child.n += 1; + sibling.n -= 1; + } + + private void merge(int idx) { + BTreeNode child = children[idx]; + BTreeNode sibling = children[idx + 1]; + + child.keys[t - 1] = keys[idx]; + + for (int i = 0; i < sibling.n; ++i) { + child.keys[i + t] = sibling.keys[i]; + } + + if (!child.leaf) { + for (int i = 0; i <= sibling.n; ++i) { + child.children[i + t] = sibling.children[i]; + } + } + + for (int i = idx + 1; i < n; ++i) { + keys[i - 1] = keys[i]; + } + + for (int i = idx + 2; i <= n; ++i) { + children[i - 1] = children[i]; + } + + child.n += sibling.n + 1; + n--; + } + } + + private BTreeNode root; + private final int t; + + public BTree(int t) { + this.root = null; + this.t = t; + } + + public void traverse(ArrayList result) { + if (root != null) { + root.traverse(result); + } + } + + public boolean search(int key) { + return root != null && root.search(key) != null; + } + + public void insert(int key) { + if (search(key)) { + return; + } + if (root == null) { + root = new BTreeNode(t, true); + root.keys[0] = key; + root.n = 1; + } else { + if (root.n == 2 * t - 1) { + BTreeNode s = new BTreeNode(t, false); + s.children[0] = root; + s.splitChild(0, root); + int i = 0; + if (s.keys[0] < key) { + i++; + } + s.children[i].insertNonFull(key); + root = s; + } else { + root.insertNonFull(key); + } + } + } + + public void delete(int key) { + if (root == null) { + return; + } + root.remove(key); + if (root.n == 0) { + root = root.leaf ? null : root.children[0]; + } + } +} diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOne.java b/src/main/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOne.java new file mode 100644 index 000000000000..abc1e321ca8f --- /dev/null +++ b/src/main/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOne.java @@ -0,0 +1,53 @@ +package com.thealgorithms.dynamicprogramming; + +/** + * The {@code KnapsackZeroOne} provides Recursive solution for the 0/1 Knapsack + * problem. Solves by exploring all combinations of items using recursion. No + * memoization or dynamic programming optimizations are applied. + * + * Time Complexity: O(2^n) — explores all subsets. + * Space Complexity: O(n) — due to recursive call stack. + * + * Problem Reference: https://en.wikipedia.org/wiki/Knapsack_problem + */ +public final class KnapsackZeroOne { + + private KnapsackZeroOne() { + // Prevent instantiation + } + + /** + * Solves the 0/1 Knapsack problem using recursion. + * + * @param values the array containing values of the items + * @param weights the array containing weights of the items + * @param capacity the total capacity of the knapsack + * @param n the number of items + * @return the maximum total value achievable within the given weight limit + * @throws IllegalArgumentException if input arrays are null, empty, or + * lengths mismatch + */ + public static int compute(final int[] values, final int[] weights, final int capacity, final int n) { + if (values == null || weights == null) { + throw new IllegalArgumentException("Input arrays cannot be null."); + } + if (values.length != weights.length) { + throw new IllegalArgumentException("Value and weight arrays must be of the same length."); + } + if (capacity < 0 || n < 0) { + throw new IllegalArgumentException("Invalid input: arrays must be non-empty and capacity/n " + + "non-negative."); + } + if (n == 0 || capacity == 0 || values.length == 0) { + return 0; + } + + if (weights[n - 1] <= capacity) { + final int include = values[n - 1] + compute(values, weights, capacity - weights[n - 1], n - 1); + final int exclude = compute(values, weights, capacity, n - 1); + return Math.max(include, exclude); + } else { + return compute(values, weights, capacity, n - 1); + } + } +} diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOneTabulation.java b/src/main/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOneTabulation.java new file mode 100644 index 000000000000..c560efc61c71 --- /dev/null +++ b/src/main/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOneTabulation.java @@ -0,0 +1,69 @@ +package com.thealgorithms.dynamicprogramming; + +/** + * Tabulation (Bottom-Up) Solution for 0-1 Knapsack Problem. + * This method uses dynamic programming to build up a solution iteratively, + * filling a 2-D array where each entry dp[i][w] represents the maximum value + * achievable with the first i items and a knapsack capacity of w. + * + * The tabulation approach is efficient because it avoids redundant calculations + * by solving all subproblems in advance and storing their results, ensuring + * each subproblem is solved only once. This is a key technique in dynamic programming, + * making it possible to solve problems that would otherwise be infeasible due to + * exponential time complexity in naive recursive solutions. + * + * Time Complexity: O(n * W), where n is the number of items and W is the knapsack capacity. + * Space Complexity: O(n * W) for the DP table. + * + * For more information, see: + * https://en.wikipedia.org/wiki/Knapsack_problem#Dynamic_programming + */ +public final class KnapsackZeroOneTabulation { + + private KnapsackZeroOneTabulation() { + // Prevent instantiation + } + + /** + * Solves the 0-1 Knapsack problem using the bottom-up tabulation technique. + * @param values the values of the items + * @param weights the weights of the items + * @param capacity the total capacity of the knapsack + * @param itemCount the number of items + * @return the maximum value that can be put in the knapsack + * @throws IllegalArgumentException if input arrays are null, of different lengths,or if capacity or itemCount is invalid + */ + public static int compute(final int[] values, final int[] weights, final int capacity, final int itemCount) { + if (values == null || weights == null) { + throw new IllegalArgumentException("Values and weights arrays must not be null."); + } + if (values.length != weights.length) { + throw new IllegalArgumentException("Values and weights arrays must be non-null and of same length."); + } + if (capacity < 0) { + throw new IllegalArgumentException("Capacity must not be negative."); + } + if (itemCount < 0 || itemCount > values.length) { + throw new IllegalArgumentException("Item count must be between 0 and the length of the values array."); + } + + final int[][] dp = new int[itemCount + 1][capacity + 1]; + + for (int i = 1; i <= itemCount; i++) { + final int currentValue = values[i - 1]; + final int currentWeight = weights[i - 1]; + + for (int w = 1; w <= capacity; w++) { + if (currentWeight <= w) { + final int includeItem = currentValue + dp[i - 1][w - currentWeight]; + final int excludeItem = dp[i - 1][w]; + dp[i][w] = Math.max(includeItem, excludeItem); + } else { + dp[i][w] = dp[i - 1][w]; + } + } + } + + return dp[itemCount][capacity]; + } +} diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequence.java b/src/main/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequence.java index b5ac62b4674b..ba1def551192 100644 --- a/src/main/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequence.java +++ b/src/main/java/com/thealgorithms/dynamicprogramming/LongestArithmeticSubsequence.java @@ -2,6 +2,7 @@ import java.util.HashMap; +@SuppressWarnings({"rawtypes", "unchecked"}) final class LongestArithmeticSubsequence { private LongestArithmeticSubsequence() { } diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequenceNLogN.java b/src/main/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequenceNLogN.java new file mode 100644 index 000000000000..7bc0855e0566 --- /dev/null +++ b/src/main/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequenceNLogN.java @@ -0,0 +1,75 @@ +package com.thealgorithms.dynamicprogramming; + +/** + * Implementation of the Longest Increasing Subsequence (LIS) problem using + * an O(n log n) dynamic programming solution enhanced with binary search. + * + * @author Vusal Huseynov (https://github.com/huseynovvusal) + */ +public final class LongestIncreasingSubsequenceNLogN { + private LongestIncreasingSubsequenceNLogN() { + } + + /** + * Finds the index of the smallest element in the array that is greater than + * or equal to the target using binary search. The search is restricted to + * the first `size` elements of the array. + * + * @param arr The array to search in (assumed to be sorted up to `size`). + * @param size The number of valid elements in the array. + * @param target The target value to find the lower bound for. + * @return The index of the lower bound. + */ + private static int lowerBound(int[] arr, int target, int size) { + int l = 0; + int r = size; + + while (l < r) { + int mid = l + (r - l) / 2; + + if (target > arr[mid]) { + // Move right if target is greater than mid element + l = mid + 1; + } else { + // Move left if target is less than or equal to mid element + r = mid; + } + } + + // Return the index where the target can be inserted + return l; + } + + /** + * Calculates the length of the Longest Increasing Subsequence (LIS) in the given array. + * + * @param arr The input array of integers. + * @return The length of the LIS. + */ + public static int lengthOfLIS(int[] arr) { + if (arr == null || arr.length == 0) { + return 0; // Return 0 for empty or null arrays + } + + // tails[i] - the smallest end element of an increasing subsequence of length i+1 + int[] tails = new int[arr.length]; + // size - the length of the longest increasing subsequence found so far + int size = 0; + + for (int x : arr) { + // Find the position to replace or extend the subsequence + int index = lowerBound(tails, x, size); + + // Update the tails array with the current element + tails[index] = x; + + // If the element extends the subsequence, increase the size + if (index == size) { + size++; + } + } + + // Return the length of the LIS + return size; + } +} diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimized.java b/src/main/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimized.java index 946da46cb292..5c0167977ae4 100644 --- a/src/main/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimized.java +++ b/src/main/java/com/thealgorithms/dynamicprogramming/SubsetSumSpaceOptimized.java @@ -1,35 +1,39 @@ package com.thealgorithms.dynamicprogramming; -/* -The Sum of Subset problem determines whether a subset of elements from a -given array sums up to a specific target value. -*/ + +/** + * Utility class for solving the Subset Sum problem using a space-optimized dynamic programming approach. + * + *

This algorithm determines whether any subset of a given array sums up to a specific target value.

+ * + *

Time Complexity: O(n * sum)

+ *

Space Complexity: O(sum)

+ */ public final class SubsetSumSpaceOptimized { private SubsetSumSpaceOptimized() { } + /** - * This method checks whether the subset of an array - * contains a given sum or not. This is an space - * optimized solution using 1D boolean array - * Time Complexity: O(n * sum), Space complexity: O(sum) + * Determines whether there exists a subset of the given array that adds up to the specified sum. + * This method uses a space-optimized dynamic programming approach with a 1D boolean array. * - * @param arr An array containing integers - * @param sum The target sum of the subset - * @return True or False + * @param nums The array of non-negative integers + * @param targetSum The desired subset sum + * @return {@code true} if such a subset exists, {@code false} otherwise */ - public static boolean isSubsetSum(int[] arr, int sum) { - int n = arr.length; - // Declare the boolean array with size sum + 1 - boolean[] dp = new boolean[sum + 1]; + public static boolean isSubsetSum(int[] nums, int targetSum) { + if (targetSum < 0) { + return false; // Subset sum can't be negative + } - // Initialize the first element as true - dp[0] = true; + boolean[] dp = new boolean[targetSum + 1]; + dp[0] = true; // Empty subset always sums to 0 - // Find the subset sum using 1D array - for (int i = 0; i < n; i++) { - for (int j = sum; j >= arr[i]; j--) { - dp[j] = dp[j] || dp[j - arr[i]]; + for (int number : nums) { + for (int j = targetSum; j >= number; j--) { + dp[j] = dp[j] || dp[j - number]; } } - return dp[sum]; + + return dp[targetSum]; } } diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/TreeMatching.java b/src/main/java/com/thealgorithms/dynamicprogramming/TreeMatching.java new file mode 100644 index 000000000000..9fd82ccaf078 --- /dev/null +++ b/src/main/java/com/thealgorithms/dynamicprogramming/TreeMatching.java @@ -0,0 +1,78 @@ +package com.thealgorithms.dynamicprogramming; + +import com.thealgorithms.datastructures.graphs.UndirectedAdjacencyListGraph; + +/** + * This class implements the algorithm for calculating the maximum weighted matching in a tree. + * The tree is represented as an undirected graph with weighted edges. + * + * Problem Description: + * Given an undirected tree G = (V, E) with edge weights γ: E → N and a root r ∈ V, + * the goal is to find a maximum weight matching M ⊆ E such that no two edges in M + * share a common vertex. The sum of the weights of the edges in M, ∑ e∈M γ(e), should be maximized. + * For more Information: Matching (graph theory) + * + * @author Deniz Altunkapan + */ +public class TreeMatching { + + private UndirectedAdjacencyListGraph graph; + private int[][] dp; + + /** + * Constructor that initializes the graph and the DP table. + * + * @param graph The graph that represents the tree and is used for the matching algorithm. + */ + public TreeMatching(UndirectedAdjacencyListGraph graph) { + this.graph = graph; + this.dp = new int[graph.size()][2]; + } + + /** + * Calculates the maximum weighted matching for the tree, starting from the given root node. + * + * @param root The index of the root node of the tree. + * @param parent The index of the parent node (used for recursion). + * @return The maximum weighted matching for the tree, starting from the root node. + * + */ + public int getMaxMatching(int root, int parent) { + if (root < 0 || root >= graph.size()) { + throw new IllegalArgumentException("Invalid root: " + root); + } + maxMatching(root, parent); + return Math.max(dp[root][0], dp[root][1]); + } + + /** + * Recursively computes the maximum weighted matching for a node, assuming that the node + * can either be included or excluded from the matching. + * + * @param node The index of the current node for which the matching is calculated. + * @param parent The index of the parent node (to avoid revisiting the parent node during recursion). + */ + private void maxMatching(int node, int parent) { + dp[node][0] = 0; + dp[node][1] = 0; + + int sumWithoutEdge = 0; + for (int adjNode : graph.getNeighbors(node)) { + if (adjNode == parent) { + continue; + } + maxMatching(adjNode, node); + sumWithoutEdge += Math.max(dp[adjNode][0], dp[adjNode][1]); + } + + dp[node][0] = sumWithoutEdge; + + for (int adjNode : graph.getNeighbors(node)) { + if (adjNode == parent) { + continue; + } + int weight = graph.getEdgeWeight(node, adjNode); + dp[node][1] = Math.max(dp[node][1], sumWithoutEdge - Math.max(dp[adjNode][0], dp[adjNode][1]) + dp[adjNode][0] + weight); + } + } +} diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/UniquePaths.java b/src/main/java/com/thealgorithms/dynamicprogramming/UniquePaths.java index 80b553f2744c..22ad8a7dd8e3 100644 --- a/src/main/java/com/thealgorithms/dynamicprogramming/UniquePaths.java +++ b/src/main/java/com/thealgorithms/dynamicprogramming/UniquePaths.java @@ -1,3 +1,7 @@ +package com.thealgorithms.dynamicprogramming; + +import java.util.Arrays; + /** * Author: Siddhant Swarup Mallick * Github: https://github.com/siddhant2002 @@ -12,11 +16,6 @@ * This program calculates the number of unique paths possible for a robot to reach the bottom-right corner * of an m x n grid using dynamic programming. */ - -package com.thealgorithms.dynamicprogramming; - -import java.util.Arrays; - public final class UniquePaths { private UniquePaths() { diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/WildcardMatching.java b/src/main/java/com/thealgorithms/dynamicprogramming/WildcardMatching.java index 8e8bf3cc6606..8658ea30af00 100644 --- a/src/main/java/com/thealgorithms/dynamicprogramming/WildcardMatching.java +++ b/src/main/java/com/thealgorithms/dynamicprogramming/WildcardMatching.java @@ -1,3 +1,5 @@ +package com.thealgorithms.dynamicprogramming; + /** * * Author: Janmesh Singh @@ -11,9 +13,6 @@ * Use DP to return True if the pattern matches the entire text and False otherwise * */ - -package com.thealgorithms.dynamicprogramming; - public final class WildcardMatching { private WildcardMatching() { } diff --git a/src/main/java/com/thealgorithms/graph/ConstrainedShortestPath.java b/src/main/java/com/thealgorithms/graph/ConstrainedShortestPath.java new file mode 100644 index 000000000000..f397989911d9 --- /dev/null +++ b/src/main/java/com/thealgorithms/graph/ConstrainedShortestPath.java @@ -0,0 +1,123 @@ +package com.thealgorithms.graph; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * This class implements a solution for the Constrained Shortest Path Problem (CSPP). + * also known as Shortest Path Problem with Resource Constraints (SPPRC). + * The goal is to find the shortest path between two nodes while ensuring that + * the resource constraint is not exceeded. + * + * @author Deniz Altunkapan + */ +public class ConstrainedShortestPath { + + /** + * Represents a graph using an adjacency list. + * This graph is designed for the Constrained Shortest Path Problem (CSPP). + */ + public static class Graph { + + private List> adjacencyList; + + public Graph(int numNodes) { + adjacencyList = new ArrayList<>(); + for (int i = 0; i < numNodes; i++) { + adjacencyList.add(new ArrayList<>()); + } + } + + /** + * Adds an edge to the graph. + * @param from the starting node + * @param to the ending node + * @param cost the cost of the edge + * @param resource the resource required to traverse the edge + */ + public void addEdge(int from, int to, int cost, int resource) { + adjacencyList.get(from).add(new Edge(from, to, cost, resource)); + } + + /** + * Gets the edges that are adjacent to a given node. + * @param node the node to get the edges for + * @return the list of edges adjacent to the node + */ + public List getEdges(int node) { + return adjacencyList.get(node); + } + + /** + * Gets the number of nodes in the graph. + * @return the number of nodes + */ + public int getNumNodes() { + return adjacencyList.size(); + } + + public record Edge(int from, int to, int cost, int resource) { + } + } + + private Graph graph; + private int maxResource; + + /** + * Constructs a CSPSolver with the given graph and maximum resource constraint. + * + * @param graph the graph representing the problem + * @param maxResource the maximum allowable resource + */ + public ConstrainedShortestPath(Graph graph, int maxResource) { + this.graph = graph; + this.maxResource = maxResource; + } + + /** + * Solves the CSP to find the shortest path from the start node to the target node + * without exceeding the resource constraint. + * + * @param start the starting node + * @param target the target node + * @return the minimum cost to reach the target node within the resource constraint, + * or -1 if no valid path exists + */ + public int solve(int start, int target) { + int numNodes = graph.getNumNodes(); + int[][] dp = new int[maxResource + 1][numNodes]; + + // Initialize dp table with maximum values + for (int i = 0; i <= maxResource; i++) { + Arrays.fill(dp[i], Integer.MAX_VALUE); + } + dp[0][start] = 0; + + // Dynamic Programming: Iterate over resources and nodes + for (int r = 0; r <= maxResource; r++) { + for (int u = 0; u < numNodes; u++) { + if (dp[r][u] == Integer.MAX_VALUE) { + continue; + } + for (Graph.Edge edge : graph.getEdges(u)) { + int v = edge.to(); + int cost = edge.cost(); + int resource = edge.resource(); + + if (r + resource <= maxResource) { + dp[r + resource][v] = Math.min(dp[r + resource][v], dp[r][u] + cost); + } + } + } + } + + // Find the minimum cost to reach the target node + int minCost = Integer.MAX_VALUE; + for (int r = 0; r <= maxResource; r++) { + minCost = Math.min(minCost, dp[r][target]); + } + + return minCost == Integer.MAX_VALUE ? -1 : minCost; + } +} diff --git a/src/main/java/com/thealgorithms/graph/TravelingSalesman.java b/src/main/java/com/thealgorithms/graph/TravelingSalesman.java new file mode 100644 index 000000000000..14bf89f57cf3 --- /dev/null +++ b/src/main/java/com/thealgorithms/graph/TravelingSalesman.java @@ -0,0 +1,155 @@ +package com.thealgorithms.graph; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * This class provides solutions to the Traveling Salesman Problem (TSP) using both brute-force and dynamic programming approaches. + * For more information, see Wikipedia. + * @author Deniz Altunkapan + */ + +public final class TravelingSalesman { + + // Private constructor to prevent instantiation + private TravelingSalesman() { + } + + /** + * Solves the Traveling Salesman Problem (TSP) using brute-force approach. + * This method generates all possible permutations of cities, calculates the total distance for each route, and returns the shortest distance found. + * + * @param distanceMatrix A square matrix where element [i][j] represents the distance from city i to city j. + * @return The shortest possible route distance visiting all cities exactly once and returning to the starting city. + */ + public static int bruteForce(int[][] distanceMatrix) { + if (distanceMatrix.length <= 1) { + return 0; + } + + List cities = new ArrayList<>(); + for (int i = 1; i < distanceMatrix.length; i++) { + cities.add(i); + } + + List> permutations = generatePermutations(cities); + int minDistance = Integer.MAX_VALUE; + + for (List permutation : permutations) { + List route = new ArrayList<>(); + route.add(0); + route.addAll(permutation); + int currentDistance = calculateDistance(distanceMatrix, route); + if (currentDistance < minDistance) { + minDistance = currentDistance; + } + } + + return minDistance; + } + + /** + * Computes the total distance of a given route. + * + * @param distanceMatrix A square matrix where element [i][j] represents the + * distance from city i to city j. + * @param route A list representing the order in which the cities are visited. + * @return The total distance of the route, or Integer.MAX_VALUE if the route is invalid. + */ + public static int calculateDistance(int[][] distanceMatrix, List route) { + int distance = 0; + for (int i = 0; i < route.size() - 1; i++) { + int d = distanceMatrix[route.get(i)][route.get(i + 1)]; + if (d == Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } + distance += d; + } + int returnDist = distanceMatrix[route.get(route.size() - 1)][route.get(0)]; + return (returnDist == Integer.MAX_VALUE) ? Integer.MAX_VALUE : distance + returnDist; + } + + /** + * Generates all permutations of a given list of cities. + * + * @param cities A list of cities to permute. + * @return A list of all possible permutations. + */ + private static List> generatePermutations(List cities) { + List> permutations = new ArrayList<>(); + permute(cities, 0, permutations); + return permutations; + } + + /** + * Recursively generates permutations using backtracking. + * + * @param arr The list of cities. + * @param k The current index in the permutation process. + * @param output The list to store generated permutations. + */ + private static void permute(List arr, int k, List> output) { + if (k == arr.size()) { + output.add(new ArrayList<>(arr)); + return; + } + for (int i = k; i < arr.size(); i++) { + Collections.swap(arr, i, k); + permute(arr, k + 1, output); + Collections.swap(arr, i, k); + } + } + + /** + * Solves the Traveling Salesman Problem (TSP) using dynamic programming with the Held-Karp algorithm. + * + * @param distanceMatrix A square matrix where element [i][j] represents the distance from city i to city j. + * @return The shortest possible route distance visiting all cities exactly once and returning to the starting city. + * @throws IllegalArgumentException if the input matrix is not square. + */ + public static int dynamicProgramming(int[][] distanceMatrix) { + if (distanceMatrix.length == 0) { + return 0; + } + int n = distanceMatrix.length; + + for (int[] row : distanceMatrix) { + if (row.length != n) { + throw new IllegalArgumentException("Matrix must be square"); + } + } + + int[][] dp = new int[n][1 << n]; + for (int[] row : dp) { + Arrays.fill(row, Integer.MAX_VALUE); + } + dp[0][1] = 0; + + for (int mask = 1; mask < (1 << n); mask++) { + for (int u = 0; u < n; u++) { + if ((mask & (1 << u)) == 0 || dp[u][mask] == Integer.MAX_VALUE) { + continue; + } + for (int v = 0; v < n; v++) { + if ((mask & (1 << v)) != 0 || distanceMatrix[u][v] == Integer.MAX_VALUE) { + continue; + } + int newMask = mask | (1 << v); + dp[v][newMask] = Math.min(dp[v][newMask], dp[u][mask] + distanceMatrix[u][v]); + } + } + } + + int minDistance = Integer.MAX_VALUE; + int fullMask = (1 << n) - 1; + for (int i = 1; i < n; i++) { + if (dp[i][fullMask] != Integer.MAX_VALUE && distanceMatrix[i][0] != Integer.MAX_VALUE) { + minDistance = Math.min(minDistance, dp[i][fullMask] + distanceMatrix[i][0]); + } + } + + return minDistance == Integer.MAX_VALUE ? 0 : minDistance; + } +} diff --git a/src/main/java/com/thealgorithms/maths/AbsoluteMax.java b/src/main/java/com/thealgorithms/maths/AbsoluteMax.java index d0c3db3790a3..c32a408b6609 100644 --- a/src/main/java/com/thealgorithms/maths/AbsoluteMax.java +++ b/src/main/java/com/thealgorithms/maths/AbsoluteMax.java @@ -17,7 +17,7 @@ public static int getMaxValue(int... numbers) { } int absMax = numbers[0]; for (int i = 1; i < numbers.length; i++) { - if (Math.abs(numbers[i]) > Math.abs(absMax)) { + if (Math.abs(numbers[i]) > Math.abs(absMax) || (Math.abs(numbers[i]) == Math.abs(absMax) && numbers[i] > absMax)) { absMax = numbers[i]; } } diff --git a/src/main/java/com/thealgorithms/maths/AbsoluteMin.java b/src/main/java/com/thealgorithms/maths/AbsoluteMin.java index 1ffe6d2e81bc..1b9575a330dd 100644 --- a/src/main/java/com/thealgorithms/maths/AbsoluteMin.java +++ b/src/main/java/com/thealgorithms/maths/AbsoluteMin.java @@ -19,7 +19,7 @@ public static int getMinValue(int... numbers) { var absMinWrapper = new Object() { int value = numbers[0]; }; - Arrays.stream(numbers).skip(1).filter(number -> Math.abs(number) < Math.abs(absMinWrapper.value)).forEach(number -> absMinWrapper.value = number); + Arrays.stream(numbers).skip(1).filter(number -> Math.abs(number) <= Math.abs(absMinWrapper.value)).forEach(number -> absMinWrapper.value = Math.min(absMinWrapper.value, number)); return absMinWrapper.value; } diff --git a/src/main/java/com/thealgorithms/maths/AliquotSum.java b/src/main/java/com/thealgorithms/maths/AliquotSum.java index 0dbc58bed605..996843b56826 100644 --- a/src/main/java/com/thealgorithms/maths/AliquotSum.java +++ b/src/main/java/com/thealgorithms/maths/AliquotSum.java @@ -56,7 +56,7 @@ public static int getAliquotSum(int n) { // if n is a perfect square then its root was added twice in above loop, so subtracting root // from sum if (root == (int) root) { - sum -= root; + sum -= (int) root; } return sum; } diff --git a/src/main/java/com/thealgorithms/maths/Armstrong.java b/src/main/java/com/thealgorithms/maths/Armstrong.java index ff4ae027a0b7..9a7a014ec99f 100644 --- a/src/main/java/com/thealgorithms/maths/Armstrong.java +++ b/src/main/java/com/thealgorithms/maths/Armstrong.java @@ -10,6 +10,7 @@ * An Armstrong number is often called a Narcissistic number. * * @author satyabarghav + * @modifier rahul katteda - (13/01/2025) - [updated the logic for getting total number of digits] */ public class Armstrong { @@ -20,14 +21,16 @@ public class Armstrong { * @return {@code true} if the given number is an Armstrong number, {@code false} otherwise */ public boolean isArmstrong(int number) { + if (number < 0) { + return false; // Negative numbers cannot be Armstrong numbers + } long sum = 0; - String temp = Integer.toString(number); // Convert the given number to a string - int power = temp.length(); // Extract the length of the number (number of digits) + int totalDigits = (int) Math.log10(number) + 1; // get the length of the number (number of digits) long originalNumber = number; while (originalNumber > 0) { long digit = originalNumber % 10; - sum += (long) Math.pow(digit, power); // The digit raised to the power of the number of digits and added to the sum. + sum += (long) Math.pow(digit, totalDigits); // The digit raised to the power of total number of digits and added to the sum. originalNumber /= 10; } diff --git a/src/main/java/com/thealgorithms/maths/Average.java b/src/main/java/com/thealgorithms/maths/Average.java index 6b9c20162da1..a550a7f6504d 100644 --- a/src/main/java/com/thealgorithms/maths/Average.java +++ b/src/main/java/com/thealgorithms/maths/Average.java @@ -37,7 +37,7 @@ public static double average(double[] numbers) { * @return the average of the given numbers * @throws IllegalArgumentException if the input array is {@code null} or empty */ - public static double average(int[] numbers) { + public static long average(int[] numbers) { if (numbers == null || numbers.length == 0) { throw new IllegalArgumentException("Numbers array cannot be empty or null"); } @@ -45,6 +45,6 @@ public static double average(int[] numbers) { for (int number : numbers) { sum += number; } - return (double) (sum / numbers.length); + return sum / numbers.length; } } diff --git a/src/main/java/com/thealgorithms/maths/Ceil.java b/src/main/java/com/thealgorithms/maths/Ceil.java index aacb9d969950..28804eb1c569 100644 --- a/src/main/java/com/thealgorithms/maths/Ceil.java +++ b/src/main/java/com/thealgorithms/maths/Ceil.java @@ -1,23 +1,34 @@ package com.thealgorithms.maths; +/** + * Utility class to compute the ceiling of a given number. + */ public final class Ceil { + private Ceil() { } /** - * Returns the smallest (closest to negative infinity) + * Returns the smallest double value that is greater than or equal to the input. + * Equivalent to mathematical ⌈x⌉ (ceiling function). * - * @param number the number - * @return the smallest (closest to negative infinity) of given - * {@code number} + * @param number the number to ceil + * @return the smallest double greater than or equal to {@code number} */ public static double ceil(double number) { - if (number - (int) number == 0) { + if (Double.isNaN(number) || Double.isInfinite(number) || number == 0.0 || number < Integer.MIN_VALUE || number > Integer.MAX_VALUE) { return number; - } else if (number - (int) number > 0) { - return (int) (number + 1); + } + + if (number < 0.0 && number > -1.0) { + return -0.0; + } + + long intPart = (long) number; + if (number > 0 && number != intPart) { + return intPart + 1.0; } else { - return (int) number; + return intPart; } } } diff --git a/src/main/java/com/thealgorithms/maths/Convolution.java b/src/main/java/com/thealgorithms/maths/Convolution.java index 93e103f8c7cf..a86ecabce933 100644 --- a/src/main/java/com/thealgorithms/maths/Convolution.java +++ b/src/main/java/com/thealgorithms/maths/Convolution.java @@ -23,24 +23,21 @@ public static double[] convolution(double[] a, double[] b) { double[] convolved = new double[a.length + b.length - 1]; /* - The discrete convolution of two signals A and B is defined as: - - A.length - C[i] = Σ (A[k]*B[i-k]) - k=0 - - It's obvious that: 0 <= k <= A.length , 0 <= i <= A.length + B.length - 2 and 0 <= i-k <= - B.length - 1 From the last inequality we get that: i - B.length + 1 <= k <= i and thus we get - the conditions below. + * Discrete convolution formula: + * C[i] = Σ A[k] * B[i - k] + * where k ranges over valid indices so that both A[k] and B[i-k] are in bounds. */ + for (int i = 0; i < convolved.length; i++) { - convolved[i] = 0; - int k = Math.max(i - b.length + 1, 0); + double sum = 0; + int kStart = Math.max(0, i - b.length + 1); + int kEnd = Math.min(i, a.length - 1); - while (k < i + 1 && k < a.length) { - convolved[i] += a[k] * b[i - k]; - k++; + for (int k = kStart; k <= kEnd; k++) { + sum += a[k] * b[i - k]; } + + convolved[i] = sum; } return convolved; diff --git a/src/main/java/com/thealgorithms/maths/DudeneyNumber.java b/src/main/java/com/thealgorithms/maths/DudeneyNumber.java index acf1e55d49c8..37f28e188663 100644 --- a/src/main/java/com/thealgorithms/maths/DudeneyNumber.java +++ b/src/main/java/com/thealgorithms/maths/DudeneyNumber.java @@ -1,11 +1,11 @@ +package com.thealgorithms.maths; + /** * A number is said to be Dudeney if the sum of the digits, is the cube root of the entered number. * Example- Let the number be 512, its sum of digits is 5+1+2=8. The cube root of 512 is also 8. * Since, the sum of the digits is equal to the cube root of the entered number; * it is a Dudeney Number. */ -package com.thealgorithms.maths; - public final class DudeneyNumber { private DudeneyNumber() { } diff --git a/src/main/java/com/thealgorithms/maths/GenericRoot.java b/src/main/java/com/thealgorithms/maths/GenericRoot.java index 07f4756f93f8..e13efe5a77e0 100644 --- a/src/main/java/com/thealgorithms/maths/GenericRoot.java +++ b/src/main/java/com/thealgorithms/maths/GenericRoot.java @@ -1,30 +1,48 @@ package com.thealgorithms.maths; -/* - * Algorithm explanation: - * https://technotip.com/6774/c-program-to-find-generic-root-of-a-number/#:~:text=Generic%20Root%3A%20of%20a%20number,get%20a%20single%2Ddigit%20output.&text=For%20Example%3A%20If%20user%20input,%2B%204%20%2B%205%20%3D%2015. +/** + * Calculates the generic root (repeated digital sum) of a non-negative integer. + *

+ * For example, the generic root of 12345 is calculated as: + * 1 + 2 + 3 + 4 + 5 = 15, + * then 1 + 5 = 6, so the generic root is 6. + *

+ * Reference: + * https://technotip.com/6774/c-program-to-find-generic-root-of-a-number/ */ public final class GenericRoot { + + private static final int BASE = 10; + private GenericRoot() { } - private static int base = 10; - + /** + * Computes the sum of the digits of a non-negative integer in base 10. + * + * @param n non-negative integer + * @return sum of digits of {@code n} + */ private static int sumOfDigits(final int n) { assert n >= 0; - if (n < base) { + if (n < BASE) { return n; } - return n % base + sumOfDigits(n / base); + return (n % BASE) + sumOfDigits(n / BASE); } + /** + * Computes the generic root (repeated digital sum) of an integer. + * For negative inputs, the absolute value is used. + * + * @param n integer input + * @return generic root of {@code n} + */ public static int genericRoot(final int n) { - if (n < 0) { - return genericRoot(-n); - } - if (n > base) { - return genericRoot(sumOfDigits(n)); + int number = Math.abs(n); + if (number < BASE) { + return number; } - return n; + return genericRoot(sumOfDigits(number)); } } diff --git a/src/main/java/com/thealgorithms/maths/GoldbachConjecture.java b/src/main/java/com/thealgorithms/maths/GoldbachConjecture.java new file mode 100644 index 000000000000..4e962722ba88 --- /dev/null +++ b/src/main/java/com/thealgorithms/maths/GoldbachConjecture.java @@ -0,0 +1,30 @@ +package com.thealgorithms.maths; + +import static com.thealgorithms.maths.Prime.PrimeCheck.isPrime; + +/** + * This is a representation of the unsolved problem of Goldbach's Projection, according to which every + * even natural number greater than 2 can be written as the sum of 2 prime numbers + * More info: https://en.wikipedia.org/wiki/Goldbach%27s_conjecture + * @author Vasilis Sarantidis (https://github.com/BILLSARAN) + */ + +public final class GoldbachConjecture { + private GoldbachConjecture() { + } + public record Result(int number1, int number2) { + } + + public static Result getPrimeSum(int number) { + if (number <= 2 || number % 2 != 0) { + throw new IllegalArgumentException("Number must be even and greater than 2."); + } + + for (int i = 0; i <= number / 2; i++) { + if (isPrime(i) && isPrime(number - i)) { + return new Result(i, number - i); + } + } + throw new IllegalStateException("No valid prime sum found."); // Should not occur + } +} diff --git a/src/main/java/com/thealgorithms/maths/MathBuilder.java b/src/main/java/com/thealgorithms/maths/MathBuilder.java new file mode 100644 index 000000000000..1cf3d8b7fc9a --- /dev/null +++ b/src/main/java/com/thealgorithms/maths/MathBuilder.java @@ -0,0 +1,503 @@ +package com.thealgorithms.maths; + +import java.text.DecimalFormat; +import java.util.Random; +import java.util.function.BiFunction; +import java.util.function.Function; + +/** + * Author: Sadiul Hakim : https://github.com/sadiul-hakim + * Profession: Backend Engineer + * Date: Oct 20, 2024 + */ +public final class MathBuilder { + private final double result; + + private MathBuilder(Builder builder) { + this.result = builder.number; + } + + // Returns final result + public double get() { + return result; + } + + // Return result in long + public long toLong() { + try { + if (Double.isNaN(result)) { + throw new IllegalArgumentException("Cannot convert NaN to long!"); + } + if (result == Double.POSITIVE_INFINITY) { + return Long.MAX_VALUE; + } + if (result == Double.NEGATIVE_INFINITY) { + return Long.MIN_VALUE; + } + if (result > Long.MAX_VALUE) { + return Long.MAX_VALUE; + } + if (result < Long.MIN_VALUE) { + return Long.MIN_VALUE; + } + return Math.round(result); + } catch (Exception ex) { + return 0; + } + } + + public static class Builder { + private double number; + private double sideNumber; + private boolean inParenthesis; + private double memory = 0; + + public Builder() { + number = 0; + } + + public Builder(double num) { + number = num; + } + + public Builder add(double num) { + if (inParenthesis) { + sideNumber += num; + } else { + number += num; + } + return this; + } + + // Takes a number and a condition, only does the operation if condition is true. + public Builder addIf(double num, BiFunction condition) { + if (!condition.apply(number, num)) { + return this; + } + if (inParenthesis) { + sideNumber += num; + } else { + number += num; + } + return this; + } + + public Builder minus(double num) { + if (inParenthesis) { + sideNumber -= num; + } else { + number -= num; + } + return this; + } + + // Takes a number and a condition, only does the operation if condition is true. + public Builder minusIf(double num, BiFunction condition) { + if (!condition.apply(number, num)) { + return this; + } + if (inParenthesis) { + sideNumber -= num; + } else { + number -= num; + } + return this; + } + + // Generates a random number and sets to NUMBER + public Builder rand(long seed) { + if (number != 0) { + throw new RuntimeException("Number must be zero for random assignment!"); + } + Random random = new Random(); + number = random.nextDouble(seed); + return this; + } + + // Takes PI value and sets to NUMBER + public Builder pi() { + if (number != 0) { + throw new RuntimeException("Number must be zero for PI assignment!"); + } + number = Math.PI; + return this; + } + + // Takes E value and sets to NUMBER + public Builder e() { + if (number != 0) { + throw new RuntimeException("Number must be zero for E assignment!"); + } + number = Math.E; + return this; + } + + public Builder randomInRange(double min, double max) { + if (number != 0) { + throw new RuntimeException("Number must be zero for random assignment!"); + } + Random random = new Random(); + number = min + (max - min) * random.nextDouble(); + return this; + } + + public Builder toDegrees() { + if (inParenthesis) { + sideNumber = Math.toDegrees(sideNumber); + } else { + number = Math.toDegrees(number); + } + return this; + } + + public Builder max(double num) { + if (inParenthesis) { + sideNumber = Math.max(sideNumber, num); + } else { + number = Math.max(number, num); + } + return this; + } + + public Builder min(double num) { + if (inParenthesis) { + sideNumber = Math.min(sideNumber, num); + } else { + number = Math.min(number, num); + } + return this; + } + + public Builder multiply(double num) { + if (inParenthesis) { + sideNumber *= num; + } else { + number *= num; + } + return this; + } + + // Takes a number and a condition, only does the operation if condition is true. + public Builder multiplyIf(double num, BiFunction condition) { + if (!condition.apply(number, num)) { + return this; + } + if (inParenthesis) { + sideNumber *= num; + } else { + number *= num; + } + return this; + } + + public Builder divide(double num) { + if (num == 0) { + return this; + } + if (inParenthesis) { + sideNumber /= num; + } else { + number /= num; + } + return this; + } + + // Takes a number and a condition, only does the operation if condition is true. + public Builder divideIf(double num, BiFunction condition) { + if (num == 0) { + return this; + } + if (!condition.apply(number, num)) { + return this; + } + if (inParenthesis) { + sideNumber /= num; + } else { + number /= num; + } + return this; + } + + public Builder mod(double num) { + if (inParenthesis) { + sideNumber %= num; + } else { + number %= num; + } + return this; + } + + // Takes a number and a condition, only does the operation if condition is true. + public Builder modIf(double num, BiFunction condition) { + if (!condition.apply(number, num)) { + return this; + } + if (inParenthesis) { + sideNumber %= num; + } else { + number %= num; + } + return this; + } + + public Builder pow(double num) { + if (inParenthesis) { + sideNumber = Math.pow(sideNumber, num); + } else { + number = Math.pow(number, num); + } + return this; + } + + public Builder sqrt() { + if (inParenthesis) { + sideNumber = Math.sqrt(sideNumber); + } else { + number = Math.sqrt(number); + } + return this; + } + + public Builder round() { + if (inParenthesis) { + sideNumber = Math.round(sideNumber); + } else { + number = Math.round(number); + } + return this; + } + + public Builder floor() { + if (inParenthesis) { + sideNumber = Math.floor(sideNumber); + } else { + number = Math.floor(number); + } + return this; + } + + public Builder ceil() { + if (inParenthesis) { + sideNumber = Math.ceil(sideNumber); + } else { + number = Math.ceil(number); + } + return this; + } + + public Builder abs() { + if (inParenthesis) { + sideNumber = Math.abs(sideNumber); + } else { + number = Math.abs(number); + } + return this; + } + + public Builder cbrt() { + if (inParenthesis) { + sideNumber = Math.cbrt(sideNumber); + } else { + number = Math.cbrt(number); + } + return this; + } + + public Builder log() { + if (inParenthesis) { + sideNumber = Math.log(sideNumber); + } else { + number = Math.log(number); + } + return this; + } + + public Builder log10() { + if (inParenthesis) { + sideNumber = Math.log10(sideNumber); + } else { + number = Math.log10(number); + } + return this; + } + + public Builder sin() { + if (inParenthesis) { + sideNumber = Math.sin(sideNumber); + } else { + number = Math.sin(number); + } + return this; + } + + public Builder cos() { + if (inParenthesis) { + sideNumber = Math.cos(sideNumber); + } else { + number = Math.cos(number); + } + return this; + } + + public Builder tan() { + if (inParenthesis) { + sideNumber = Math.tan(sideNumber); + } else { + number = Math.tan(number); + } + return this; + } + + public Builder sinh() { + if (inParenthesis) { + sideNumber = Math.sinh(sideNumber); + } else { + number = Math.sinh(number); + } + return this; + } + + public Builder cosh() { + if (inParenthesis) { + sideNumber = Math.cosh(sideNumber); + } else { + number = Math.cosh(number); + } + return this; + } + + public Builder tanh() { + if (inParenthesis) { + sideNumber = Math.tanh(sideNumber); + } else { + number = Math.tanh(number); + } + return this; + } + + public Builder exp() { + if (inParenthesis) { + sideNumber = Math.exp(sideNumber); + } else { + number = Math.exp(number); + } + return this; + } + + public Builder toRadians() { + if (inParenthesis) { + sideNumber = Math.toRadians(sideNumber); + } else { + number = Math.toRadians(number); + } + return this; + } + + // Remembers the NUMBER + public Builder remember() { + memory = number; + return this; + } + + // Recalls the NUMBER + public Builder recall(boolean cleanMemory) { + number = memory; + if (cleanMemory) { + memory = 0; + } + return this; + } + + // Recalls the NUMBER on condition + public Builder recallIf(Function condition, boolean cleanMemory) { + if (!condition.apply(number)) { + return this; + } + number = memory; + if (cleanMemory) { + memory = 0; + } + return this; + } + + // Replaces NUMBER with given number + public Builder set(double num) { + if (number != 0) { + throw new RuntimeException("Number must be zero to set!"); + } + number = num; + return this; + } + + // Replaces NUMBER with given number on condition + public Builder setIf(double num, BiFunction condition) { + if (number != 0) { + throw new RuntimeException("Number must be zero to set!"); + } + if (condition.apply(number, num)) { + number = num; + } + return this; + } + + // Prints current NUMBER + public Builder print() { + System.out.println("MathBuilder Result :: " + number); + return this; + } + + public Builder openParenthesis(double num) { + sideNumber = num; + inParenthesis = true; + return this; + } + + public Builder closeParenthesisAndPlus() { + number += sideNumber; + inParenthesis = false; + sideNumber = 0; + return this; + } + + public Builder closeParenthesisAndMinus() { + number -= sideNumber; + inParenthesis = false; + sideNumber = 0; + return this; + } + + public Builder closeParenthesisAndMultiply() { + number *= sideNumber; + inParenthesis = false; + sideNumber = 0; + return this; + } + + public Builder closeParenthesisAndDivide() { + number /= sideNumber; + inParenthesis = false; + sideNumber = 0; + return this; + } + + public Builder format(String format) { + DecimalFormat formater = new DecimalFormat(format); + String num = formater.format(number); + number = Double.parseDouble(num); + return this; + } + + public Builder format(int decimalPlace) { + String pattern = "." + + "#".repeat(decimalPlace); + DecimalFormat formater = new DecimalFormat(pattern); + String num = formater.format(number); + number = Double.parseDouble(num); + return this; + } + + public MathBuilder build() { + return new MathBuilder(this); + } + } +} diff --git a/src/main/java/com/thealgorithms/maths/Median.java b/src/main/java/com/thealgorithms/maths/Median.java index e4daec8fc11a..fd2aab84e4e9 100644 --- a/src/main/java/com/thealgorithms/maths/Median.java +++ b/src/main/java/com/thealgorithms/maths/Median.java @@ -13,8 +13,13 @@ private Median() { * Calculate average median * @param values sorted numbers to find median of * @return median of given {@code values} + * @throws IllegalArgumentException If the input array is empty or null. */ public static double median(int[] values) { + if (values == null || values.length == 0) { + throw new IllegalArgumentException("Values array cannot be empty or null"); + } + Arrays.sort(values); int length = values.length; return length % 2 == 0 ? (values[length / 2] + values[length / 2 - 1]) / 2.0 : values[length / 2]; diff --git a/src/main/java/com/thealgorithms/maths/Mode.java b/src/main/java/com/thealgorithms/maths/Mode.java index f0b747cf02ec..657f8ece2a50 100644 --- a/src/main/java/com/thealgorithms/maths/Mode.java +++ b/src/main/java/com/thealgorithms/maths/Mode.java @@ -3,46 +3,49 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.List; +import java.util.Map; -/* - * Find the mode of an array of numbers - * - * The mode of an array of numbers is the most frequently occurring number in the array, - * or the most frequently occurring numbers if there are multiple numbers with the same frequency +/** + * Utility class to calculate the mode(s) of an array of integers. + *

+ * The mode of an array is the integer value(s) that occur most frequently. + * If multiple values have the same highest frequency, all such values are returned. + *

*/ public final class Mode { private Mode() { } - /* - * Find the mode of an array of integers + /** + * Computes the mode(s) of the specified array of integers. + *

+ * If the input array is empty, this method returns {@code null}. + * If multiple numbers share the highest frequency, all are returned in the result array. + *

* - * @param numbers array of integers - * @return mode of the array + * @param numbers an array of integers to analyze + * @return an array containing the mode(s) of the input array, or {@code null} if the input is empty */ public static int[] mode(final int[] numbers) { if (numbers.length == 0) { return null; } - HashMap count = new HashMap<>(); + Map count = new HashMap<>(); for (int num : numbers) { - if (count.containsKey(num)) { - count.put(num, count.get(num) + 1); - } else { - count.put(num, 1); - } + count.put(num, count.getOrDefault(num, 0) + 1); } int max = Collections.max(count.values()); - ArrayList modes = new ArrayList<>(); + List modes = new ArrayList<>(); for (final var entry : count.entrySet()) { if (entry.getValue() == max) { modes.add(entry.getKey()); } } - return modes.stream().mapToInt(n -> n).toArray(); + return modes.stream().mapToInt(Integer::intValue).toArray(); } } diff --git a/src/main/java/com/thealgorithms/maths/PerfectNumber.java b/src/main/java/com/thealgorithms/maths/PerfectNumber.java index 2a935b067094..f299d08e5d27 100644 --- a/src/main/java/com/thealgorithms/maths/PerfectNumber.java +++ b/src/main/java/com/thealgorithms/maths/PerfectNumber.java @@ -63,7 +63,7 @@ public static boolean isPerfectNumber2(int n) { // if n is a perfect square then its root was added twice in above loop, so subtracting root // from sum if (root == (int) root) { - sum -= root; + sum -= (int) root; } return sum == n; diff --git a/src/main/java/com/thealgorithms/maths/LiouvilleLambdaFunction.java b/src/main/java/com/thealgorithms/maths/Prime/LiouvilleLambdaFunction.java similarity index 93% rename from src/main/java/com/thealgorithms/maths/LiouvilleLambdaFunction.java rename to src/main/java/com/thealgorithms/maths/Prime/LiouvilleLambdaFunction.java index c0f55f5e3485..73535b3aedae 100644 --- a/src/main/java/com/thealgorithms/maths/LiouvilleLambdaFunction.java +++ b/src/main/java/com/thealgorithms/maths/Prime/LiouvilleLambdaFunction.java @@ -1,4 +1,4 @@ -package com.thealgorithms.maths; +package com.thealgorithms.maths.Prime; /* * Java program for liouville lambda function @@ -24,7 +24,7 @@ private LiouvilleLambdaFunction() { * -1 when number has odd number of prime factors * @throws IllegalArgumentException when number is negative */ - static int liouvilleLambda(int number) { + public static int liouvilleLambda(int number) { if (number <= 0) { // throw exception when number is less than or is zero throw new IllegalArgumentException("Number must be greater than zero."); diff --git a/src/main/java/com/thealgorithms/maths/MillerRabinPrimalityCheck.java b/src/main/java/com/thealgorithms/maths/Prime/MillerRabinPrimalityCheck.java similarity index 98% rename from src/main/java/com/thealgorithms/maths/MillerRabinPrimalityCheck.java rename to src/main/java/com/thealgorithms/maths/Prime/MillerRabinPrimalityCheck.java index f889213abfcb..debe3a214a32 100644 --- a/src/main/java/com/thealgorithms/maths/MillerRabinPrimalityCheck.java +++ b/src/main/java/com/thealgorithms/maths/Prime/MillerRabinPrimalityCheck.java @@ -1,4 +1,4 @@ -package com.thealgorithms.maths; +package com.thealgorithms.maths.Prime; import java.util.Random; diff --git a/src/main/java/com/thealgorithms/maths/MobiusFunction.java b/src/main/java/com/thealgorithms/maths/Prime/MobiusFunction.java similarity index 96% rename from src/main/java/com/thealgorithms/maths/MobiusFunction.java rename to src/main/java/com/thealgorithms/maths/Prime/MobiusFunction.java index 915d0d9a6dae..3d4e4eff0f03 100644 --- a/src/main/java/com/thealgorithms/maths/MobiusFunction.java +++ b/src/main/java/com/thealgorithms/maths/Prime/MobiusFunction.java @@ -1,4 +1,4 @@ -package com.thealgorithms.maths; +package com.thealgorithms.maths.Prime; /* * Java program for mobius function @@ -25,7 +25,7 @@ private MobiusFunction() { * 0 when number has repeated prime factor * -1 when number has odd number of prime factors */ - static int mobius(int number) { + public static int mobius(int number) { if (number <= 0) { // throw exception when number is less than or is zero throw new IllegalArgumentException("Number must be greater than zero."); diff --git a/src/main/java/com/thealgorithms/maths/PrimeCheck.java b/src/main/java/com/thealgorithms/maths/Prime/PrimeCheck.java similarity index 98% rename from src/main/java/com/thealgorithms/maths/PrimeCheck.java rename to src/main/java/com/thealgorithms/maths/Prime/PrimeCheck.java index 628a819aeba4..91c490f70aef 100644 --- a/src/main/java/com/thealgorithms/maths/PrimeCheck.java +++ b/src/main/java/com/thealgorithms/maths/Prime/PrimeCheck.java @@ -1,4 +1,4 @@ -package com.thealgorithms.maths; +package com.thealgorithms.maths.Prime; import java.util.Scanner; diff --git a/src/main/java/com/thealgorithms/maths/PrimeFactorization.java b/src/main/java/com/thealgorithms/maths/Prime/PrimeFactorization.java similarity index 95% rename from src/main/java/com/thealgorithms/maths/PrimeFactorization.java rename to src/main/java/com/thealgorithms/maths/Prime/PrimeFactorization.java index 9ac50fd9043b..e12002b3d8c7 100644 --- a/src/main/java/com/thealgorithms/maths/PrimeFactorization.java +++ b/src/main/java/com/thealgorithms/maths/Prime/PrimeFactorization.java @@ -1,4 +1,4 @@ -package com.thealgorithms.maths; +package com.thealgorithms.maths.Prime; /* * Authors: diff --git a/src/main/java/com/thealgorithms/maths/SquareFreeInteger.java b/src/main/java/com/thealgorithms/maths/Prime/SquareFreeInteger.java similarity index 97% rename from src/main/java/com/thealgorithms/maths/SquareFreeInteger.java rename to src/main/java/com/thealgorithms/maths/Prime/SquareFreeInteger.java index 22e9fee00605..15c0a8a691cd 100644 --- a/src/main/java/com/thealgorithms/maths/SquareFreeInteger.java +++ b/src/main/java/com/thealgorithms/maths/Prime/SquareFreeInteger.java @@ -1,4 +1,4 @@ -package com.thealgorithms.maths; +package com.thealgorithms.maths.Prime; /* * Java program for Square free integer * This class has a function which checks diff --git a/src/main/java/com/thealgorithms/maths/PythagoreanTriple.java b/src/main/java/com/thealgorithms/maths/PythagoreanTriple.java index f535e9e6929b..2780b113d904 100644 --- a/src/main/java/com/thealgorithms/maths/PythagoreanTriple.java +++ b/src/main/java/com/thealgorithms/maths/PythagoreanTriple.java @@ -1,36 +1,43 @@ package com.thealgorithms.maths; /** - * https://en.wikipedia.org/wiki/Pythagorean_triple + * Utility class to check if three integers form a Pythagorean triple. + * A Pythagorean triple consists of three positive integers a, b, and c, + * such that a² + b² = c². + * + * Common examples: + * - (3, 4, 5) + * - (5, 12, 13) + * + * Reference: https://en.wikipedia.org/wiki/Pythagorean_triple */ public final class PythagoreanTriple { - private PythagoreanTriple() { - } - public static void main(String[] args) { - assert isPythagTriple(3, 4, 5); - assert isPythagTriple(5, 12, 13); - assert isPythagTriple(6, 8, 10); - assert !isPythagTriple(10, 20, 30); - assert !isPythagTriple(6, 8, 100); - assert !isPythagTriple(-1, -1, 1); + private PythagoreanTriple() { } /** - * Check if a,b,c are a Pythagorean Triple + * Checks whether three integers form a Pythagorean triple. + * The order of parameters does not matter. * - * @param a x/y component length of a right triangle - * @param b y/x component length of a right triangle - * @param c hypotenuse length of a right triangle - * @return boolean true if a, b, c satisfy the Pythagorean theorem, - * otherwise - * false + * @param a one side length + * @param b another side length + * @param c another side length + * @return {@code true} if (a, b, c) can form a Pythagorean triple, otherwise {@code false} */ public static boolean isPythagTriple(int a, int b, int c) { if (a <= 0 || b <= 0 || c <= 0) { return false; - } else { - return (a * a) + (b * b) == (c * c); } + + // Sort the sides so the largest is treated as hypotenuse + int[] sides = {a, b, c}; + java.util.Arrays.sort(sides); + + int x = sides[0]; + int y = sides[1]; + int hypotenuse = sides[2]; + + return x * x + y * y == hypotenuse * hypotenuse; } } diff --git a/src/main/java/com/thealgorithms/maths/TwinPrime.java b/src/main/java/com/thealgorithms/maths/TwinPrime.java index ef8de0d1018e..f4e546a2d7a4 100644 --- a/src/main/java/com/thealgorithms/maths/TwinPrime.java +++ b/src/main/java/com/thealgorithms/maths/TwinPrime.java @@ -9,6 +9,8 @@ * * */ +import com.thealgorithms.maths.Prime.PrimeCheck; + public final class TwinPrime { private TwinPrime() { } diff --git a/src/main/java/com/thealgorithms/misc/InverseOfMatrix.java b/src/main/java/com/thealgorithms/matrix/InverseOfMatrix.java similarity index 98% rename from src/main/java/com/thealgorithms/misc/InverseOfMatrix.java rename to src/main/java/com/thealgorithms/matrix/InverseOfMatrix.java index 706feab0c69d..13e795a91297 100644 --- a/src/main/java/com/thealgorithms/misc/InverseOfMatrix.java +++ b/src/main/java/com/thealgorithms/matrix/InverseOfMatrix.java @@ -1,4 +1,4 @@ -package com.thealgorithms.misc; +package com.thealgorithms.matrix; /** * This class provides methods to compute the inverse of a square matrix diff --git a/src/main/java/com/thealgorithms/matrix/MatrixMultiplication.java b/src/main/java/com/thealgorithms/matrix/MatrixMultiplication.java new file mode 100644 index 000000000000..6467a438577b --- /dev/null +++ b/src/main/java/com/thealgorithms/matrix/MatrixMultiplication.java @@ -0,0 +1,69 @@ +package com.thealgorithms.matrix; + +/** + * This class provides a method to perform matrix multiplication. + * + *

Matrix multiplication takes two 2D arrays (matrices) as input and + * produces their product, following the mathematical definition of + * matrix multiplication. + * + *

For more details: + * https://www.geeksforgeeks.org/java/java-program-to-multiply-two-matrices-of-any-size/ + * https://en.wikipedia.org/wiki/Matrix_multiplication + * + *

Time Complexity: O(n^3) – where n is the dimension of the matrices + * (assuming square matrices for simplicity). + * + *

Space Complexity: O(n^2) – for storing the result matrix. + * + * + * @author Nishitha Wihala Pitigala + * + */ + +public final class MatrixMultiplication { + private MatrixMultiplication() { + } + + /** + * Multiplies two matrices. + * + * @param matrixA the first matrix rowsA x colsA + * @param matrixB the second matrix rowsB x colsB + * @return the product of the two matrices rowsA x colsB + * @throws IllegalArgumentException if the matrices cannot be multiplied + */ + public static double[][] multiply(double[][] matrixA, double[][] matrixB) { + // Check the input matrices are not null + if (matrixA == null || matrixB == null) { + throw new IllegalArgumentException("Input matrices cannot be null"); + } + + // Check for empty matrices + if (matrixA.length == 0 || matrixB.length == 0 || matrixA[0].length == 0 || matrixB[0].length == 0) { + throw new IllegalArgumentException("Input matrices must not be empty"); + } + + // Validate the matrix dimensions + if (matrixA[0].length != matrixB.length) { + throw new IllegalArgumentException("Matrices cannot be multiplied: incompatible dimensions."); + } + + int rowsA = matrixA.length; + int colsA = matrixA[0].length; + int colsB = matrixB[0].length; + + // Initialize the result matrix with zeros + double[][] result = new double[rowsA][colsB]; + + // Perform matrix multiplication + for (int i = 0; i < rowsA; i++) { + for (int j = 0; j < colsB; j++) { + for (int k = 0; k < colsA; k++) { + result[i][j] += matrixA[i][k] * matrixB[k][j]; + } + } + } + return result; + } +} diff --git a/src/main/java/com/thealgorithms/maths/MatrixRank.java b/src/main/java/com/thealgorithms/matrix/MatrixRank.java similarity index 77% rename from src/main/java/com/thealgorithms/maths/MatrixRank.java rename to src/main/java/com/thealgorithms/matrix/MatrixRank.java index 7a628b92dccb..6692b6c37c60 100644 --- a/src/main/java/com/thealgorithms/maths/MatrixRank.java +++ b/src/main/java/com/thealgorithms/matrix/MatrixRank.java @@ -1,4 +1,6 @@ -package com.thealgorithms.maths; +package com.thealgorithms.matrix; + +import static com.thealgorithms.matrix.utils.MatrixUtil.validateInputMatrix; /** * This class provides a method to compute the rank of a matrix. @@ -63,47 +65,6 @@ private static double[][] deepCopy(double[][] matrix) { return matrixCopy; } - private static void validateInputMatrix(double[][] matrix) { - if (matrix == null) { - throw new IllegalArgumentException("The input matrix cannot be null"); - } - if (matrix.length == 0) { - throw new IllegalArgumentException("The input matrix cannot be empty"); - } - if (!hasValidRows(matrix)) { - throw new IllegalArgumentException("The input matrix cannot have null or empty rows"); - } - if (isJaggedMatrix(matrix)) { - throw new IllegalArgumentException("The input matrix cannot be jagged"); - } - } - - private static boolean hasValidRows(double[][] matrix) { - for (double[] row : matrix) { - if (row == null || row.length == 0) { - return false; - } - } - return true; - } - - /** - * @brief Checks if the input matrix is a jagged matrix. - * Jagged matrix is a matrix where the number of columns in each row is not the same. - * - * @param matrix The input matrix - * @return True if the input matrix is a jagged matrix, false otherwise - */ - private static boolean isJaggedMatrix(double[][] matrix) { - int numColumns = matrix[0].length; - for (double[] row : matrix) { - if (row.length != numColumns) { - return true; - } - } - return false; - } - /** * @brief The pivot row is the row in the matrix that is used to eliminate other rows and reduce the matrix to its row echelon form. * The pivot row is selected as the first row (from top to bottom) where the value in the current column (the pivot column) is not zero. diff --git a/src/main/java/com/thealgorithms/misc/MatrixTranspose.java b/src/main/java/com/thealgorithms/matrix/MatrixTranspose.java similarity index 97% rename from src/main/java/com/thealgorithms/misc/MatrixTranspose.java rename to src/main/java/com/thealgorithms/matrix/MatrixTranspose.java index 743682780b01..f91ebc10b8a9 100644 --- a/src/main/java/com/thealgorithms/misc/MatrixTranspose.java +++ b/src/main/java/com/thealgorithms/matrix/MatrixTranspose.java @@ -1,4 +1,4 @@ -package com.thealgorithms.misc; +package com.thealgorithms.matrix; /** * diff --git a/src/main/java/com/thealgorithms/misc/MedianOfMatrix.java b/src/main/java/com/thealgorithms/matrix/MedianOfMatrix.java similarity index 54% rename from src/main/java/com/thealgorithms/misc/MedianOfMatrix.java rename to src/main/java/com/thealgorithms/matrix/MedianOfMatrix.java index edeedbbee540..1ec977af07c6 100644 --- a/src/main/java/com/thealgorithms/misc/MedianOfMatrix.java +++ b/src/main/java/com/thealgorithms/matrix/MedianOfMatrix.java @@ -1,4 +1,4 @@ -package com.thealgorithms.misc; +package com.thealgorithms.matrix; import java.util.ArrayList; import java.util.Collections; @@ -14,19 +14,19 @@ private MedianOfMatrix() { } public static int median(Iterable> matrix) { - // Flatten the matrix into a 1D list - List linear = new ArrayList<>(); + List flattened = new ArrayList<>(); + for (List row : matrix) { - linear.addAll(row); + if (row != null) { + flattened.addAll(row); + } } - // Sort the 1D list - Collections.sort(linear); - - // Calculate the middle index - int mid = (0 + linear.size() - 1) / 2; + if (flattened.isEmpty()) { + throw new IllegalArgumentException("Matrix must contain at least one element."); + } - // Return the median - return linear.get(mid); + Collections.sort(flattened); + return flattened.get((flattened.size() - 1) / 2); } } diff --git a/src/main/java/com/thealgorithms/matrix/MirrorOfMatrix.java b/src/main/java/com/thealgorithms/matrix/MirrorOfMatrix.java new file mode 100644 index 000000000000..3a3055f38732 --- /dev/null +++ b/src/main/java/com/thealgorithms/matrix/MirrorOfMatrix.java @@ -0,0 +1,36 @@ +package com.thealgorithms.matrix; + +// Problem Statement + +import com.thealgorithms.matrix.utils.MatrixUtil; + +/* +We have given an array of m x n (where m is the number of rows and n is the number of columns). +Print the new matrix in such a way that the new matrix is the mirror image of the original matrix. + +The Original matrix is: | The Mirror matrix is: +1 2 3 | 3 2 1 +4 5 6 | 6 5 4 +7 8 9 | 9 8 7 + +@author - Aman (https://github.com/Aman28801) +*/ + +public final class MirrorOfMatrix { + private MirrorOfMatrix() { + } + + public static double[][] mirrorMatrix(final double[][] originalMatrix) { + MatrixUtil.validateInputMatrix(originalMatrix); + + int numRows = originalMatrix.length; + int numCols = originalMatrix[0].length; + + double[][] mirroredMatrix = new double[numRows][numCols]; + + for (int i = 0; i < numRows; i++) { + mirroredMatrix[i] = MatrixUtil.reverseRow(originalMatrix[i]); + } + return mirroredMatrix; + } +} diff --git a/src/main/java/com/thealgorithms/matrix/PrintAMatrixInSpiralOrder.java b/src/main/java/com/thealgorithms/matrix/PrintAMatrixInSpiralOrder.java new file mode 100644 index 000000000000..2757da1f9023 --- /dev/null +++ b/src/main/java/com/thealgorithms/matrix/PrintAMatrixInSpiralOrder.java @@ -0,0 +1,53 @@ +package com.thealgorithms.matrix; + +import java.util.ArrayList; +import java.util.List; + +public class PrintAMatrixInSpiralOrder { + /** + * Search a key in row and column wise sorted matrix + * + * @param matrix matrix to be searched + * @param row number of rows matrix has + * @param col number of columns matrix has + * @author Sadiul Hakim : https://github.com/sadiul-hakim + */ + public List print(int[][] matrix, int row, int col) { + + // r traverses matrix row wise from first + int r = 0; + // c traverses matrix column wise from first + int c = 0; + int i; + List result = new ArrayList<>(); + while (r < row && c < col) { + // print first row of matrix + for (i = c; i < col; i++) { + result.add(matrix[r][i]); + } + // increase r by one because first row printed + r++; + // print last column + for (i = r; i < row; i++) { + result.add(matrix[i][col - 1]); + } + // decrease col by one because last column has been printed + col--; + // print rows from last except printed elements + if (r < row) { + for (i = col - 1; i >= c; i--) { + result.add(matrix[row - 1][i]); + } + row--; + } + // print columns from first except printed elements + if (c < col) { + for (i = row - 1; i >= r; i--) { + result.add(matrix[i][c]); + } + c++; + } + } + return result; + } +} diff --git a/src/main/java/com/thealgorithms/others/RotateMatrixBy90Degrees.java b/src/main/java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java similarity index 98% rename from src/main/java/com/thealgorithms/others/RotateMatrixBy90Degrees.java rename to src/main/java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java index 6ad0ef024342..9a7f255282ac 100644 --- a/src/main/java/com/thealgorithms/others/RotateMatrixBy90Degrees.java +++ b/src/main/java/com/thealgorithms/matrix/RotateMatrixBy90Degrees.java @@ -1,4 +1,4 @@ -package com.thealgorithms.others; +package com.thealgorithms.matrix; import java.util.Scanner; /** diff --git a/src/main/java/com/thealgorithms/matrix/SolveSystem.java b/src/main/java/com/thealgorithms/matrix/SolveSystem.java new file mode 100644 index 000000000000..9e683bc4dc5c --- /dev/null +++ b/src/main/java/com/thealgorithms/matrix/SolveSystem.java @@ -0,0 +1,71 @@ +package com.thealgorithms.matrix; + +/** + * This class implements an algorithm for solving a system of equations of the form Ax=b using gaussian elimination and back substitution. + * + * @link Gaussian Elimination Wiki + * @see InverseOfMatrix finds the full of inverse of a matrice, but is not required to solve a system. + */ +public final class SolveSystem { + private SolveSystem() { + } + + /** + * Problem: Given a matrix A and vector b, solve the linear system Ax = b for the vector x.\ + *

+ * This OVERWRITES the input matrix to save on memory + * + * @param matrix - a square matrix of doubles + * @param constants - an array of constant + * @return solutions + */ + public static double[] solveSystem(double[][] matrix, double[] constants) { + final double tol = 0.00000001; // tolerance for round off + for (int k = 0; k < matrix.length - 1; k++) { + // find the largest value in column (to avoid zero pivots) + double maxVal = Math.abs(matrix[k][k]); + int maxIdx = k; + for (int j = k + 1; j < matrix.length; j++) { + if (Math.abs(matrix[j][k]) > maxVal) { + maxVal = matrix[j][k]; + maxIdx = j; + } + } + if (Math.abs(maxVal) < tol) { + // hope the matrix works out + continue; + } + // swap rows + double[] temp = matrix[k]; + matrix[k] = matrix[maxIdx]; + matrix[maxIdx] = temp; + double tempConst = constants[k]; + constants[k] = constants[maxIdx]; + constants[maxIdx] = tempConst; + for (int i = k + 1; i < matrix.length; i++) { + // compute multipliers and save them in the column + matrix[i][k] /= matrix[k][k]; + for (int j = k + 1; j < matrix.length; j++) { + matrix[i][j] -= matrix[i][k] * matrix[k][j]; + } + constants[i] -= matrix[i][k] * constants[k]; + } + } + // back substitution + double[] x = new double[constants.length]; + System.arraycopy(constants, 0, x, 0, constants.length); + for (int i = matrix.length - 1; i >= 0; i--) { + double sum = 0; + for (int j = i + 1; j < matrix.length; j++) { + sum += matrix[i][j] * x[j]; + } + x[i] = constants[i] - sum; + if (Math.abs(matrix[i][i]) > tol) { + x[i] /= matrix[i][i]; + } else { + throw new IllegalArgumentException("Matrix was found to be singular"); + } + } + return x; + } +} diff --git a/src/main/java/com/thealgorithms/matrix/matrixexponentiation/Fibonacci.java b/src/main/java/com/thealgorithms/matrix/matrixexponentiation/Fibonacci.java new file mode 100644 index 000000000000..85852713b9ba --- /dev/null +++ b/src/main/java/com/thealgorithms/matrix/matrixexponentiation/Fibonacci.java @@ -0,0 +1,42 @@ +package com.thealgorithms.matrix.matrixexponentiation; + +import com.thealgorithms.matrix.utils.MatrixUtil; +import java.math.BigDecimal; + +/** + * @author Anirudh Buvanesh (https://github.com/anirudhb11) For more information + * see https://www.geeksforgeeks.org/matrix-exponentiation/ + * + */ +public final class Fibonacci { + private Fibonacci() { + } + + // Exponentiation matrix for Fibonacci sequence + private static final BigDecimal ONE = BigDecimal.valueOf(1); + private static final BigDecimal ZERO = BigDecimal.valueOf(0); + + private static final BigDecimal[][] FIB_MATRIX = {{ONE, ONE}, {ONE, ZERO}}; + private static final BigDecimal[][] IDENTITY_MATRIX = {{ONE, ZERO}, {ZERO, ONE}}; + + /** + * Calculates the fibonacci number using matrix exponentiaition technique + * + * @param n The input n for which we have to determine the fibonacci number + * Outputs the nth * fibonacci number + * @return a 2 X 1 array as { {F_n+1}, {F_n} } + */ + public static BigDecimal[][] fib(int n) { + if (n == 0) { + return IDENTITY_MATRIX; + } else { + BigDecimal[][] cachedResult = fib(n / 2); + BigDecimal[][] matrixExpResult = MatrixUtil.multiply(cachedResult, cachedResult).get(); + if (n % 2 == 0) { + return matrixExpResult; + } else { + return MatrixUtil.multiply(FIB_MATRIX, matrixExpResult).get(); + } + } + } +} diff --git a/src/main/java/com/thealgorithms/maths/MatrixUtil.java b/src/main/java/com/thealgorithms/matrix/utils/MatrixUtil.java similarity index 62% rename from src/main/java/com/thealgorithms/maths/MatrixUtil.java rename to src/main/java/com/thealgorithms/matrix/utils/MatrixUtil.java index 7e462f92e185..5ff9e37f6b9a 100644 --- a/src/main/java/com/thealgorithms/maths/MatrixUtil.java +++ b/src/main/java/com/thealgorithms/matrix/utils/MatrixUtil.java @@ -1,4 +1,4 @@ -package com.thealgorithms.maths; +package com.thealgorithms.matrix.utils; import java.math.BigDecimal; import java.util.Optional; @@ -10,6 +10,7 @@ * @date: 31 October 2021 (Sunday) */ public final class MatrixUtil { + private MatrixUtil() { } @@ -18,11 +19,52 @@ private static boolean isValid(final BigDecimal[][] matrix) { } private static boolean hasEqualSizes(final BigDecimal[][] matrix1, final BigDecimal[][] matrix2) { - return (isValid(matrix1) && isValid(matrix2) && matrix1.length == matrix2.length && matrix1[0].length == matrix2[0].length); + return isValid(matrix1) && isValid(matrix2) && matrix1.length == matrix2.length && matrix1[0].length == matrix2[0].length; } private static boolean canMultiply(final BigDecimal[][] matrix1, final BigDecimal[][] matrix2) { - return (isValid(matrix1) && isValid(matrix2) && matrix1[0].length == matrix2.length); + return isValid(matrix1) && isValid(matrix2) && matrix1[0].length == matrix2.length; + } + + public static void validateInputMatrix(double[][] matrix) { + if (matrix == null) { + throw new IllegalArgumentException("The input matrix cannot be null"); + } + if (matrix.length == 0) { + throw new IllegalArgumentException("The input matrix cannot be empty"); + } + if (!hasValidRows(matrix)) { + throw new IllegalArgumentException("The input matrix cannot have null or empty rows"); + } + if (isJaggedMatrix(matrix)) { + throw new IllegalArgumentException("The input matrix cannot be jagged"); + } + } + + private static boolean hasValidRows(double[][] matrix) { + for (double[] row : matrix) { + if (row == null || row.length == 0) { + return false; + } + } + return true; + } + + /** + * @brief Checks if the input matrix is a jagged matrix. + * Jagged matrix is a matrix where the number of columns in each row is not the same. + * + * @param matrix The input matrix + * @return True if the input matrix is a jagged matrix, false otherwise + */ + private static boolean isJaggedMatrix(double[][] matrix) { + int numColumns = matrix[0].length; + for (double[] row : matrix) { + if (row.length != numColumns) { + return true; + } + } + return false; } private static Optional operate(final BigDecimal[][] matrix1, final BigDecimal[][] matrix2, final BiFunction operation) { @@ -80,4 +122,12 @@ public static Optional multiply(final BigDecimal[][] matrix1, fi return Optional.of(result); } + + public static double[] reverseRow(final double[] inRow) { + double[] res = new double[inRow.length]; + for (int i = 0; i < inRow.length; ++i) { + res[i] = inRow[inRow.length - 1 - i]; + } + return res; + } } diff --git a/src/main/java/com/thealgorithms/matrixexponentiation/Fibonacci.java b/src/main/java/com/thealgorithms/matrixexponentiation/Fibonacci.java deleted file mode 100644 index afd34933047a..000000000000 --- a/src/main/java/com/thealgorithms/matrixexponentiation/Fibonacci.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.thealgorithms.matrixexponentiation; - -import java.util.Scanner; - -/** - * @author Anirudh Buvanesh (https://github.com/anirudhb11) For more information - * see https://www.geeksforgeeks.org/matrix-exponentiation/ - * - */ -public final class Fibonacci { - private Fibonacci() { - } - - // Exponentiation matrix for Fibonacci sequence - private static final int[][] FIB_MATRIX = {{1, 1}, {1, 0}}; - private static final int[][] IDENTITY_MATRIX = {{1, 0}, {0, 1}}; - // First 2 fibonacci numbers - private static final int[][] BASE_FIB_NUMBERS = {{1}, {0}}; - - /** - * Performs multiplication of 2 matrices - * - * @param matrix1 - * @param matrix2 - * @return The product of matrix1 and matrix2 - */ - private static int[][] matrixMultiplication(int[][] matrix1, int[][] matrix2) { - // Check if matrices passed can be multiplied - int rowsInMatrix1 = matrix1.length; - int columnsInMatrix1 = matrix1[0].length; - - int rowsInMatrix2 = matrix2.length; - int columnsInMatrix2 = matrix2[0].length; - - assert columnsInMatrix1 == rowsInMatrix2; - int[][] product = new int[rowsInMatrix1][columnsInMatrix2]; - for (int rowIndex = 0; rowIndex < rowsInMatrix1; rowIndex++) { - for (int colIndex = 0; colIndex < columnsInMatrix2; colIndex++) { - int matrixEntry = 0; - for (int intermediateIndex = 0; intermediateIndex < columnsInMatrix1; intermediateIndex++) { - matrixEntry += matrix1[rowIndex][intermediateIndex] * matrix2[intermediateIndex][colIndex]; - } - product[rowIndex][colIndex] = matrixEntry; - } - } - return product; - } - - /** - * Calculates the fibonacci number using matrix exponentiaition technique - * - * @param n The input n for which we have to determine the fibonacci number - * Outputs the nth * fibonacci number - * @return a 2 X 1 array as { {F_n+1}, {F_n} } - */ - public static int[][] fib(int n) { - if (n == 0) { - return Fibonacci.IDENTITY_MATRIX; - } else { - int[][] cachedResult = fib(n / 2); - int[][] matrixExpResult = matrixMultiplication(cachedResult, cachedResult); - if (n % 2 == 0) { - return matrixExpResult; - } else { - return matrixMultiplication(Fibonacci.FIB_MATRIX, matrixExpResult); - } - } - } - - public static void main(String[] args) { - // Returns [0, 1, 1, 2, 3, 5 ..] for n = [0, 1, 2, 3, 4, 5.. ] - Scanner sc = new Scanner(System.in); - int n = sc.nextInt(); - int[][] result = matrixMultiplication(fib(n), BASE_FIB_NUMBERS); - System.out.println("Fib(" + n + ") = " + result[1][0]); - sc.close(); - } -} diff --git a/src/main/java/com/thealgorithms/misc/MapReduce.java b/src/main/java/com/thealgorithms/misc/MapReduce.java index c076957344f9..d98b2ee2dd03 100644 --- a/src/main/java/com/thealgorithms/misc/MapReduce.java +++ b/src/main/java/com/thealgorithms/misc/MapReduce.java @@ -7,35 +7,34 @@ import java.util.function.Function; import java.util.stream.Collectors; -/* -* MapReduce is a programming model for processing and generating large data sets with a parallel, -distributed algorithm on a cluster. -* It has two main steps: the Map step, where the data is divided into smaller chunks and processed in parallel, -and the Reduce step, where the results from the Map step are combined to produce the final output. -* Wikipedia link : https://en.wikipedia.org/wiki/MapReduce -*/ - +/** + * MapReduce is a programming model for processing and generating large data sets + * using a parallel, distributed algorithm on a cluster. + * It consists of two main phases: + * - Map: the input data is split into smaller chunks and processed in parallel. + * - Reduce: the results from the Map phase are aggregated to produce the final output. + * + * See also: https://en.wikipedia.org/wiki/MapReduce + */ public final class MapReduce { + private MapReduce() { } - /* - *Counting all the words frequency within a sentence. - */ - public static String mapreduce(String sentence) { - List wordList = Arrays.stream(sentence.split(" ")).toList(); - // Map step - Map wordCounts = wordList.stream().collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting())); - - // Reduce step - StringBuilder result = new StringBuilder(); - wordCounts.forEach((word, count) -> result.append(word).append(": ").append(count).append(",")); + /** + * Counts the frequency of each word in a given sentence using a simple MapReduce-style approach. + * + * @param sentence the input sentence + * @return a string representing word frequencies in the format "word: count,word: count,..." + */ + public static String countWordFrequencies(String sentence) { + // Map phase: split the sentence into words + List words = Arrays.asList(sentence.trim().split("\\s+")); - // Removing the last ',' if it exists - if (!result.isEmpty()) { - result.setLength(result.length() - 1); - } + // Group and count occurrences of each word, maintain insertion order + Map wordCounts = words.stream().collect(Collectors.groupingBy(Function.identity(), LinkedHashMap::new, Collectors.counting())); - return result.toString(); + // Reduce phase: format the result + return wordCounts.entrySet().stream().map(entry -> entry.getKey() + ": " + entry.getValue()).collect(Collectors.joining(",")); } } diff --git a/src/main/java/com/thealgorithms/misc/MedianOfRunningArray.java b/src/main/java/com/thealgorithms/misc/MedianOfRunningArray.java index 62013ee31183..95f86f63f720 100644 --- a/src/main/java/com/thealgorithms/misc/MedianOfRunningArray.java +++ b/src/main/java/com/thealgorithms/misc/MedianOfRunningArray.java @@ -4,50 +4,74 @@ import java.util.PriorityQueue; /** - * @author shrutisheoran + * A generic abstract class to compute the median of a dynamically growing stream of numbers. + * + * @param the number type, must extend Number and be Comparable + * + * Usage: + * Extend this class and implement {@code calculateAverage(T a, T b)} to define how averaging is done. */ public abstract class MedianOfRunningArray> { - private PriorityQueue maxHeap; - private PriorityQueue minHeap; + private final PriorityQueue maxHeap; // Lower half (max-heap) + private final PriorityQueue minHeap; // Upper half (min-heap) - // Constructor public MedianOfRunningArray() { - this.maxHeap = new PriorityQueue<>(Collections.reverseOrder()); // Max Heap - this.minHeap = new PriorityQueue<>(); // Min Heap + this.maxHeap = new PriorityQueue<>(Collections.reverseOrder()); + this.minHeap = new PriorityQueue<>(); } - /* - Inserting lower half of array to max Heap - and upper half to min heap + /** + * Inserts a new number into the data structure. + * + * @param element the number to insert */ - public void insert(final T e) { - if (!minHeap.isEmpty() && e.compareTo(minHeap.peek()) < 0) { - maxHeap.offer(e); - if (maxHeap.size() > minHeap.size() + 1) { - minHeap.offer(maxHeap.poll()); - } + public final void insert(final T element) { + if (!minHeap.isEmpty() && element.compareTo(minHeap.peek()) < 0) { + maxHeap.offer(element); + balanceHeapsIfNeeded(); } else { - minHeap.offer(e); - if (minHeap.size() > maxHeap.size() + 1) { - maxHeap.offer(minHeap.poll()); - } + minHeap.offer(element); + balanceHeapsIfNeeded(); } } - /* - Returns median at any given point + /** + * Returns the median of the current elements. + * + * @return the median value + * @throws IllegalArgumentException if no elements have been inserted */ - public T median() { + public final T getMedian() { if (maxHeap.isEmpty() && minHeap.isEmpty()) { - throw new IllegalArgumentException("Enter at least 1 element, Median of empty list is not defined!"); - } else if (maxHeap.size() == minHeap.size()) { - T maxHeapTop = maxHeap.peek(); - T minHeapTop = minHeap.peek(); - return calculateAverage(maxHeapTop, minHeapTop); + throw new IllegalArgumentException("Median is undefined for an empty data set."); } - return maxHeap.size() > minHeap.size() ? maxHeap.peek() : minHeap.peek(); + + if (maxHeap.size() == minHeap.size()) { + return calculateAverage(maxHeap.peek(), minHeap.peek()); + } + + return (maxHeap.size() > minHeap.size()) ? maxHeap.peek() : minHeap.peek(); } - public abstract T calculateAverage(T a, T b); + /** + * Calculates the average between two values. + * Concrete subclasses must define how averaging works (e.g., for Integer, Double, etc.). + * + * @param a first number + * @param b second number + * @return the average of a and b + */ + protected abstract T calculateAverage(T a, T b); + + /** + * Balances the two heaps so that their sizes differ by at most 1. + */ + private void balanceHeapsIfNeeded() { + if (maxHeap.size() > minHeap.size() + 1) { + minHeap.offer(maxHeap.poll()); + } else if (minHeap.size() > maxHeap.size() + 1) { + maxHeap.offer(minHeap.poll()); + } + } } diff --git a/src/main/java/com/thealgorithms/misc/MirrorOfMatrix.java b/src/main/java/com/thealgorithms/misc/MirrorOfMatrix.java deleted file mode 100644 index 89dfce3fe049..000000000000 --- a/src/main/java/com/thealgorithms/misc/MirrorOfMatrix.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.thealgorithms.misc; - -// Problem Statement -/* -We have given an array of m x n (where m is the number of rows and n is the number of columns). -Print the new matrix in such a way that the new matrix is the mirror image of the original matrix. - -The Original matrix is: | The Mirror matrix is: -1 2 3 | 3 2 1 -4 5 6 | 6 5 4 -7 8 9 | 9 8 7 - -@author - Aman (https://github.com/Aman28801) -*/ - -public final class MirrorOfMatrix { - private MirrorOfMatrix() { - } - - public static int[][] mirrorMatrix(final int[][] originalMatrix) { - if (originalMatrix == null) { - // Handle invalid input - return null; - } - if (originalMatrix.length == 0) { - return new int[0][0]; - } - - checkInput(originalMatrix); - - int numRows = originalMatrix.length; - int numCols = originalMatrix[0].length; - - int[][] mirroredMatrix = new int[numRows][numCols]; - - for (int i = 0; i < numRows; i++) { - mirroredMatrix[i] = reverseRow(originalMatrix[i]); - } - return mirroredMatrix; - } - private static int[] reverseRow(final int[] inRow) { - int[] res = new int[inRow.length]; - for (int i = 0; i < inRow.length; ++i) { - res[i] = inRow[inRow.length - 1 - i]; - } - return res; - } - - private static void checkInput(final int[][] matrix) { - // Check if all rows have the same number of columns - for (int i = 1; i < matrix.length; i++) { - if (matrix[i].length != matrix[0].length) { - throw new IllegalArgumentException("The input is not a matrix."); - } - } - } -} diff --git a/src/main/java/com/thealgorithms/misc/PalindromeSinglyLinkedList.java b/src/main/java/com/thealgorithms/misc/PalindromeSinglyLinkedList.java index 51dc099ba32e..c81476eaec32 100644 --- a/src/main/java/com/thealgorithms/misc/PalindromeSinglyLinkedList.java +++ b/src/main/java/com/thealgorithms/misc/PalindromeSinglyLinkedList.java @@ -10,6 +10,7 @@ * See more: * https://www.geeksforgeeks.org/function-to-check-if-a-singly-linked-list-is-palindrome/ */ +@SuppressWarnings("rawtypes") public final class PalindromeSinglyLinkedList { private PalindromeSinglyLinkedList() { } diff --git a/src/main/java/com/thealgorithms/misc/RangeInSortedArray.java b/src/main/java/com/thealgorithms/misc/RangeInSortedArray.java index 6d3caa1814b6..0ae73dd73f09 100644 --- a/src/main/java/com/thealgorithms/misc/RangeInSortedArray.java +++ b/src/main/java/com/thealgorithms/misc/RangeInSortedArray.java @@ -1,25 +1,46 @@ package com.thealgorithms.misc; +/** + * Utility class for operations to find the range of occurrences of a key + * in a sorted (non-decreasing) array, and to count elements less than or equal to a given key. + */ public final class RangeInSortedArray { + private RangeInSortedArray() { } - // Get the 1st and last occurrence index of a number 'key' in a non-decreasing array 'nums' - // Gives [-1, -1] in case element doesn't exist in array + /** + * Finds the first and last occurrence indices of the key in a sorted array. + * + * @param nums sorted array of integers (non-decreasing order) + * @param key the target value to search for + * @return int array of size two where + * - index 0 is the first occurrence of key, + * - index 1 is the last occurrence of key, + * or [-1, -1] if the key does not exist in the array. + */ public static int[] sortedRange(int[] nums, int key) { int[] range = new int[] {-1, -1}; - alteredBinSearchIter(nums, key, 0, nums.length - 1, range, true); - alteredBinSearchIter(nums, key, 0, nums.length - 1, range, false); + alteredBinSearchIter(nums, key, 0, nums.length - 1, range, true); // find left boundary + alteredBinSearchIter(nums, key, 0, nums.length - 1, range, false); // find right boundary return range; } - // Recursive altered binary search which searches for leftmost as well as rightmost occurrence - // of 'key' + /** + * Recursive altered binary search to find either the leftmost or rightmost occurrence of a key. + * + * @param nums the sorted array + * @param key the target to find + * @param left current left bound in search + * @param right current right bound in search + * @param range array to update with boundaries: range[0] for leftmost, range[1] for rightmost + * @param goLeft if true, searches for leftmost occurrence; if false, for rightmost occurrence + */ public static void alteredBinSearch(int[] nums, int key, int left, int right, int[] range, boolean goLeft) { if (left > right) { return; } - int mid = (left + right) >>> 1; + int mid = left + ((right - left) >>> 1); if (nums[mid] > key) { alteredBinSearch(nums, key, left, mid - 1, range, goLeft); } else if (nums[mid] < key) { @@ -41,11 +62,19 @@ public static void alteredBinSearch(int[] nums, int key, int left, int right, in } } - // Iterative altered binary search which searches for leftmost as well as rightmost occurrence - // of 'key' + /** + * Iterative altered binary search to find either the leftmost or rightmost occurrence of a key. + * + * @param nums the sorted array + * @param key the target to find + * @param left initial left bound + * @param right initial right bound + * @param range array to update with boundaries: range[0] for leftmost, range[1] for rightmost + * @param goLeft if true, searches for leftmost occurrence; if false, for rightmost occurrence + */ public static void alteredBinSearchIter(int[] nums, int key, int left, int right, int[] range, boolean goLeft) { while (left <= right) { - final int mid = (left + right) >>> 1; + int mid = left + ((right - left) >>> 1); if (nums[mid] > key) { right = mid - 1; } else if (nums[mid] < key) { @@ -55,33 +84,48 @@ public static void alteredBinSearchIter(int[] nums, int key, int left, int right if (mid == 0 || nums[mid - 1] != key) { range[0] = mid; return; - } else { - right = mid - 1; } + right = mid - 1; } else { if (mid == nums.length - 1 || nums[mid + 1] != key) { range[1] = mid; return; - } else { - left = mid + 1; } + left = mid + 1; } } } } + /** + * Counts the number of elements strictly less than the given key. + * + * @param nums sorted array + * @param key the key to compare + * @return the count of elements less than the key + */ public static int getCountLessThan(int[] nums, int key) { return getLessThan(nums, key, 0, nums.length - 1); } + /** + * Helper method using binary search to count elements less than or equal to the key. + * + * @param nums sorted array + * @param key the key to compare + * @param left current left bound + * @param right current right bound + * @return count of elements less than or equal to the key + */ public static int getLessThan(int[] nums, int key, int left, int right) { int count = 0; while (left <= right) { - final int mid = (left + right) >>> 1; + int mid = left + ((right - left) >>> 1); if (nums[mid] > key) { right = mid - 1; - } else if (nums[mid] <= key) { - count = mid + 1; // At least mid+1 elements exist which are <= key + } else { + // nums[mid] <= key + count = mid + 1; // all elements from 0 to mid inclusive are <= key left = mid + 1; } } diff --git a/src/main/java/com/thealgorithms/misc/ShuffleArray.java b/src/main/java/com/thealgorithms/misc/ShuffleArray.java index 65d38adfc37a..e07c8df771d3 100644 --- a/src/main/java/com/thealgorithms/misc/ShuffleArray.java +++ b/src/main/java/com/thealgorithms/misc/ShuffleArray.java @@ -17,19 +17,37 @@ * @author Rashi Dashore (https://github.com/rashi07dashore) */ public final class ShuffleArray { - // Prevent instantiation + private ShuffleArray() { } /** - * This method shuffles an array using the Fisher-Yates algorithm. + * Shuffles the provided array in-place using the Fisher–Yates algorithm. * - * @param arr is the input array to be shuffled + * @param arr the array to shuffle; must not be {@code null} + * @throws IllegalArgumentException if the input array is {@code null} */ public static void shuffle(int[] arr) { + if (arr == null) { + throw new IllegalArgumentException("Input array must not be null"); + } + Random random = new Random(); for (int i = arr.length - 1; i > 0; i--) { int j = random.nextInt(i + 1); + swap(arr, i, j); + } + } + + /** + * Swaps two elements in an array. + * + * @param arr the array + * @param i index of first element + * @param j index of second element + */ + private static void swap(int[] arr, int i, int j) { + if (i != j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; diff --git a/src/main/java/com/thealgorithms/misc/Sparsity.java b/src/main/java/com/thealgorithms/misc/Sparsity.java index 08e50a121da4..4a919e0e55c6 100644 --- a/src/main/java/com/thealgorithms/misc/Sparsity.java +++ b/src/main/java/com/thealgorithms/misc/Sparsity.java @@ -1,40 +1,46 @@ package com.thealgorithms.misc; -/* - *A matrix is sparse if many of its coefficients are zero (In general if 2/3rd of matrix elements - *are 0, it is considered as sparse). The interest in sparsity arises because its exploitation can - *lead to enormous computational savings and because many large matrix problems that occur in - *practice are sparse. +/** + * Utility class for calculating the sparsity of a matrix. + * A matrix is considered sparse if a large proportion of its elements are zero. + * Typically, if more than 2/3 of the elements are zero, the matrix is considered sparse. * - * @author Ojasva Jain + * Sparsity is defined as: + * sparsity = (number of zero elements) / (total number of elements) + * + * This can lead to significant computational optimizations. */ +public final class Sparsity { -final class Sparsity { private Sparsity() { } - /* - * @param mat the input matrix - * @return Sparsity of matrix - * - * where sparsity = number of zeroes/total elements in matrix + /** + * Calculates the sparsity of a given 2D matrix. * + * @param matrix the input matrix + * @return the sparsity value between 0 and 1 + * @throws IllegalArgumentException if the matrix is null, empty, or contains empty rows */ - static double sparsity(double[][] mat) { - if (mat == null || mat.length == 0) { + public static double sparsity(double[][] matrix) { + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { throw new IllegalArgumentException("Matrix cannot be null or empty"); } - int zero = 0; - // Traversing the matrix to count number of zeroes - for (int i = 0; i < mat.length; i++) { - for (int j = 0; j < mat[i].length; j++) { - if (mat[i][j] == 0) { - zero++; + int zeroCount = 0; + int totalElements = 0; + + // Count the number of zero elements and total elements + for (double[] row : matrix) { + for (double value : row) { + if (value == 0.0) { + zeroCount++; } + totalElements++; } } - // return sparsity - return ((double) zero / (mat.length * mat[0].length)); + + // Return sparsity as a double + return (double) zeroCount / totalElements; } } diff --git a/src/main/java/com/thealgorithms/others/CRCAlgorithm.java b/src/main/java/com/thealgorithms/others/CRCAlgorithm.java index 284a290a5af8..00ddc86be820 100644 --- a/src/main/java/com/thealgorithms/others/CRCAlgorithm.java +++ b/src/main/java/com/thealgorithms/others/CRCAlgorithm.java @@ -7,6 +7,7 @@ /** * @author dimgrichr */ +@SuppressWarnings("unchecked") public class CRCAlgorithm { private int correctMess; diff --git a/src/main/java/com/thealgorithms/others/KochSnowflake.java b/src/main/java/com/thealgorithms/others/KochSnowflake.java index 46b8edb1f177..10986aabec4f 100644 --- a/src/main/java/com/thealgorithms/others/KochSnowflake.java +++ b/src/main/java/com/thealgorithms/others/KochSnowflake.java @@ -105,7 +105,7 @@ public static BufferedImage getKochSnowflake(int imageWidth, int steps) { double offsetX = imageWidth / 10.; double offsetY = imageWidth / 3.7; Vector2 vector1 = new Vector2(offsetX, offsetY); - Vector2 vector2 = new Vector2(imageWidth / 2, Math.sin(Math.PI / 3) * imageWidth * 0.8 + offsetY); + Vector2 vector2 = new Vector2(imageWidth / 2.0, Math.sin(Math.PI / 3.0) * imageWidth * 0.8 + offsetY); Vector2 vector3 = new Vector2(imageWidth - offsetX, offsetY); ArrayList initialVectors = new ArrayList(); initialVectors.add(vector1); diff --git a/src/main/java/com/thealgorithms/others/PrintAMatrixInSpiralOrder.java b/src/main/java/com/thealgorithms/others/PrintAMatrixInSpiralOrder.java index ddc37a916cbf..abfdd006879e 100644 --- a/src/main/java/com/thealgorithms/others/PrintAMatrixInSpiralOrder.java +++ b/src/main/java/com/thealgorithms/others/PrintAMatrixInSpiralOrder.java @@ -12,43 +12,33 @@ public class PrintAMatrixInSpiralOrder { * @param col number of columns matrix has * @author Sadiul Hakim : https://github.com/sadiul-hakim */ - public List print(int[][] matrix, int row, int col) { - // r traverses matrix row wise from first int r = 0; // c traverses matrix column wise from first int c = 0; int i; - List result = new ArrayList<>(); - while (r < row && c < col) { // print first row of matrix for (i = c; i < col; i++) { result.add(matrix[r][i]); } - // increase r by one because first row printed r++; - // print last column for (i = r; i < row; i++) { result.add(matrix[i][col - 1]); } - // decrease col by one because last column has been printed col--; - // print rows from last except printed elements if (r < row) { for (i = col - 1; i >= c; i--) { result.add(matrix[row - 1][i]); } - row--; } - // print columns from first except printed elements if (c < col) { for (i = row - 1; i >= r; i--) { diff --git a/src/main/java/com/thealgorithms/others/TwoPointers.java b/src/main/java/com/thealgorithms/others/TwoPointers.java index c551408c38b9..c87e26269386 100644 --- a/src/main/java/com/thealgorithms/others/TwoPointers.java +++ b/src/main/java/com/thealgorithms/others/TwoPointers.java @@ -7,30 +7,37 @@ *

* Link: https://www.geeksforgeeks.org/two-pointers-technique/ */ -final class TwoPointers { +public final class TwoPointers { + private TwoPointers() { } /** - * Given a sorted array arr (sorted in ascending order), find if there exists - * any pair of elements such that their sum is equal to the key. + * Checks whether there exists a pair of elements in a sorted array whose sum equals the specified key. * - * @param arr the array containing elements (must be sorted in ascending order) - * @param key the number to search - * @return {@code true} if there exists a pair of elements, {@code false} otherwise. + * @param arr a sorted array of integers in ascending order (must not be null) + * @param key the target sum to find + * @return {@code true} if there exists at least one pair whose sum equals {@code key}, {@code false} otherwise + * @throws IllegalArgumentException if {@code arr} is {@code null} */ public static boolean isPairedSum(int[] arr, int key) { - int i = 0; // index of the first element - int j = arr.length - 1; // index of the last element + if (arr == null) { + throw new IllegalArgumentException("Input array must not be null."); + } + + int left = 0; + int right = arr.length - 1; + + while (left < right) { + int sum = arr[left] + arr[right]; - while (i < j) { - int sum = arr[i] + arr[j]; if (sum == key) { return true; - } else if (sum < key) { - i++; + } + if (sum < key) { + left++; } else { - j--; + right--; } } return false; diff --git a/src/main/java/com/thealgorithms/others/Sudoku.java b/src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java similarity index 99% rename from src/main/java/com/thealgorithms/others/Sudoku.java rename to src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java index 0e88aee46f4d..fce665c4de00 100644 --- a/src/main/java/com/thealgorithms/others/Sudoku.java +++ b/src/main/java/com/thealgorithms/puzzlesandgames/Sudoku.java @@ -1,4 +1,4 @@ -package com.thealgorithms.others; +package com.thealgorithms.puzzlesandgames; /** * A class that provides methods to solve Sudoku puzzles of any n x n size diff --git a/src/main/java/com/thealgorithms/others/TowerOfHanoi.java b/src/main/java/com/thealgorithms/puzzlesandgames/TowerOfHanoi.java similarity index 98% rename from src/main/java/com/thealgorithms/others/TowerOfHanoi.java rename to src/main/java/com/thealgorithms/puzzlesandgames/TowerOfHanoi.java index 7017ed03f843..72e9a14ac070 100644 --- a/src/main/java/com/thealgorithms/others/TowerOfHanoi.java +++ b/src/main/java/com/thealgorithms/puzzlesandgames/TowerOfHanoi.java @@ -1,4 +1,4 @@ -package com.thealgorithms.others; +package com.thealgorithms.puzzlesandgames; import java.util.List; diff --git a/src/main/java/com/thealgorithms/misc/WordBoggle.java b/src/main/java/com/thealgorithms/puzzlesandgames/WordBoggle.java similarity index 98% rename from src/main/java/com/thealgorithms/misc/WordBoggle.java rename to src/main/java/com/thealgorithms/puzzlesandgames/WordBoggle.java index 8b629d68209b..ca1430f744ab 100644 --- a/src/main/java/com/thealgorithms/misc/WordBoggle.java +++ b/src/main/java/com/thealgorithms/puzzlesandgames/WordBoggle.java @@ -1,4 +1,4 @@ -package com.thealgorithms.misc; +package com.thealgorithms.puzzlesandgames; import java.util.ArrayList; import java.util.HashMap; @@ -8,9 +8,9 @@ import java.util.Set; public final class WordBoggle { + private WordBoggle() { } - /** * O(nm * 8^s + ws) time where n = width of boggle board, m = height of * boggle board, s = length of longest word in string array, w = length of diff --git a/src/main/java/com/thealgorithms/randomized/KargerMinCut.java b/src/main/java/com/thealgorithms/randomized/KargerMinCut.java new file mode 100644 index 000000000000..14f1f97450a0 --- /dev/null +++ b/src/main/java/com/thealgorithms/randomized/KargerMinCut.java @@ -0,0 +1,195 @@ +package com.thealgorithms.randomized; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; + +/** + * Implementation of Karger's Minimum Cut algorithm. + * + *

Karger's algorithm is a randomized algorithm to compute the minimum cut of a connected graph. + * A minimum cut is the smallest set of edges that, if removed, would split the graph into two + * disconnected components. + * + *

The algorithm works by repeatedly contracting random edges in the graph until only two + * nodes remain. The edges between these two nodes represent a cut. By running the algorithm + * multiple times and keeping track of the smallest cut found, the probability of finding the + * true minimum cut increases. + * + *

Key steps of the algorithm: + *

    + *
  1. Randomly select an edge and contract it, merging the two nodes into one.
  2. + *
  3. Repeat the contraction process until only two nodes remain.
  4. + *
  5. Count the edges between the two remaining nodes to determine the cut size.
  6. + *
  7. Repeat the process multiple times to improve the likelihood of finding the true minimum cut.
  8. + *
+ *

+ * See more: Karger's algorithm + * + * @author MuhammadEzzatHBK + */ +public final class KargerMinCut { + + /** + * Output of the Karger algorithm. + * + * @param first The first set of nodes in the cut. + * @param second The second set of nodes in the cut. + * @param minCut The size of the minimum cut. + */ + public record KargerOutput(Set first, Set second, int minCut) { + } + + private KargerMinCut() { + } + + public static KargerOutput findMinCut(Collection nodeSet, List edges) { + return findMinCut(nodeSet, edges, 100); + } + + /** + * Finds the minimum cut of a graph using Karger's algorithm. + * + * @param nodeSet: Input graph nodes + * @param edges: Input graph edges + * @param iterations: Iterations to run the algorithms for, more iterations = more accuracy + * @return A KargerOutput object containing the two sets of nodes and the size of the minimum cut. + */ + public static KargerOutput findMinCut(Collection nodeSet, List edges, int iterations) { + Graph graph = new Graph(nodeSet, edges); + KargerOutput minCut = new KargerOutput(new HashSet<>(), new HashSet<>(), Integer.MAX_VALUE); + KargerOutput output; + + // Run the algorithm multiple times to increase the probability of finding + for (int i = 0; i < iterations; i++) { + Graph clone = graph.copy(); + output = clone.findMinCut(); + if (output.minCut < minCut.minCut) { + minCut = output; + } + } + return minCut; + } + + private static class DisjointSetUnion { + private final int[] parent; + int setCount; + + DisjointSetUnion(int size) { + parent = new int[size]; + for (int i = 0; i < size; i++) { + parent[i] = i; + } + setCount = size; + } + + int find(int i) { + // If it's not its own parent, then it's not the root of its set + if (parent[i] != i) { + // Recursively find the root of its parent + // and update i's parent to point directly to the root (path compression) + parent[i] = find(parent[i]); + } + + // Return the root (representative) of the set + return parent[i]; + } + + void union(int u, int v) { + // Find the root of each node + int rootU = find(u); + int rootV = find(v); + + // If they belong to different sets, merge them + if (rootU != rootV) { + // Make rootV point to rootU — merge the two sets + parent[rootV] = rootU; + + // Reduce the count of disjoint sets by 1 + setCount--; + } + } + + boolean inSameSet(int u, int v) { + return find(u) == find(v); + } + + /* + This is a verbosity method, it's not a part of the core algorithm, + But it helps us provide more useful output. + */ + Set getAnySet() { + int aRoot = find(0); // Get one of the two roots + + Set set = new HashSet<>(); + for (int i = 0; i < parent.length; i++) { + if (find(i) == aRoot) { + set.add(i); + } + } + + return set; + } + } + + private static class Graph { + private final List nodes; + private final List edges; + + Graph(Collection nodeSet, List edges) { + this.nodes = new ArrayList<>(nodeSet); + this.edges = new ArrayList<>(); + for (int[] e : edges) { + this.edges.add(new int[] {e[0], e[1]}); + } + } + + Graph copy() { + return new Graph(this.nodes, this.edges); + } + + KargerOutput findMinCut() { + DisjointSetUnion dsu = new DisjointSetUnion(nodes.size()); + List workingEdges = new ArrayList<>(edges); + + Random rand = new Random(); + + while (dsu.setCount > 2) { + int[] e = workingEdges.get(rand.nextInt(workingEdges.size())); + if (!dsu.inSameSet(e[0], e[1])) { + dsu.union(e[0], e[1]); + } + } + + int cutEdges = 0; + for (int[] e : edges) { + if (!dsu.inSameSet(e[0], e[1])) { + cutEdges++; + } + } + + return collectResult(dsu, cutEdges); + } + + /* + This is a verbosity method, it's not a part of the core algorithm, + But it helps us provide more useful output. + */ + private KargerOutput collectResult(DisjointSetUnion dsu, int cutEdges) { + Set firstIndices = dsu.getAnySet(); + Set firstSet = new HashSet<>(); + Set secondSet = new HashSet<>(); + for (int i = 0; i < nodes.size(); i++) { + if (firstIndices.contains(i)) { + firstSet.add(nodes.get(i)); + } else { + secondSet.add(nodes.get(i)); + } + } + return new KargerOutput(firstSet, secondSet, cutEdges); + } + } +} diff --git a/src/main/java/com/thealgorithms/randomized/MonteCarloIntegration.java b/src/main/java/com/thealgorithms/randomized/MonteCarloIntegration.java new file mode 100644 index 000000000000..05d7abbbcd6c --- /dev/null +++ b/src/main/java/com/thealgorithms/randomized/MonteCarloIntegration.java @@ -0,0 +1,82 @@ +package com.thealgorithms.randomized; + +import java.util.Random; +import java.util.function.Function; + +/** + * A demonstration of the Monte Carlo integration algorithm in Java. + * + *

This class estimates the value of definite integrals using randomized sampling, + * also known as the Monte Carlo method. It is particularly effective for: + *

    + *
  • Functions that are difficult or impossible to integrate analytically
  • + *
  • High-dimensional integrals where traditional methods are inefficient
  • + *
  • Simulation and probabilistic analysis tasks
  • + *
+ * + *

The core idea is to sample random points uniformly from the integration domain, + * evaluate the function at those points, and compute the scaled average to estimate the integral. + * + *

For a one-dimensional integral over [a, b], the approximation is the function range (b-a), + * multiplied by the function average result for a random sample. + * See more: Monte Carlo Integration + * + * @author: MuhammadEzzatHBK + */ + +public final class MonteCarloIntegration { + + private MonteCarloIntegration() { + } + + /** + * Approximates the definite integral of a given function over a specified + * interval using the Monte Carlo method with a fixed random seed for + * reproducibility. + * + * @param fx the function to integrate + * @param a the lower bound of the interval + * @param b the upper bound of the interval + * @param n the number of random samples to use + * @param seed the seed for the random number generator + * @return the approximate value of the integral + */ + public static double approximate(Function fx, double a, double b, int n, long seed) { + return doApproximate(fx, a, b, n, new Random(seed)); + } + + /** + * Approximates the definite integral of a given function over a specified + * interval using the Monte Carlo method with a random seed based on the + * current system time for more randomness. + * + * @param fx the function to integrate + * @param a the lower bound of the interval + * @param b the upper bound of the interval + * @param n the number of random samples to use + * @return the approximate value of the integral + */ + public static double approximate(Function fx, double a, double b, int n) { + return doApproximate(fx, a, b, n, new Random(System.currentTimeMillis())); + } + + private static double doApproximate(Function fx, double a, double b, int n, Random generator) { + if (!validate(fx, a, b, n)) { + throw new IllegalArgumentException("Invalid input parameters"); + } + double totalArea = 0.0; + double interval = b - a; + for (int i = 0; i < n; i++) { + double x = a + generator.nextDouble() * interval; + totalArea += fx.apply(x); + } + return interval * totalArea / n; + } + + private static boolean validate(Function fx, double a, double b, int n) { + boolean isFunctionValid = fx != null; + boolean isIntervalValid = a < b; + boolean isSampleSizeValid = n > 0; + return isFunctionValid && isIntervalValid && isSampleSizeValid; + } +} diff --git a/src/main/java/com/thealgorithms/randomized/RandomizedClosestPair.java b/src/main/java/com/thealgorithms/randomized/RandomizedClosestPair.java new file mode 100644 index 000000000000..616f7fb7d7cf --- /dev/null +++ b/src/main/java/com/thealgorithms/randomized/RandomizedClosestPair.java @@ -0,0 +1,113 @@ +package com.thealgorithms.randomized; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Random; + +/** + * Randomized Closest Pair of Points Algorithm + * + * Use Case: + * - Efficiently finds the closest pair of points in a 2D plane. + * - Applicable in computational geometry, clustering, and graphics. + * + * Time Complexity: + * - Expected: O(n log n) using randomized divide and conquer + * + * @see Closest Pair of Points - Wikipedia + */ +public final class RandomizedClosestPair { + + // Prevent instantiation of utility class + private RandomizedClosestPair() { + throw new UnsupportedOperationException("Utility class"); + } + + public static class Point { + public final double x; + public final double y; + + public Point(double x, double y) { + this.x = x; + this.y = y; + } + } + + public static double findClosestPairDistance(Point[] points) { + List shuffled = new ArrayList<>(Arrays.asList(points)); + Collections.shuffle(shuffled, new Random()); + + Point[] px = shuffled.toArray(new Point[0]); + Arrays.sort(px, Comparator.comparingDouble(p -> p.x)); + + Point[] py = px.clone(); + Arrays.sort(py, Comparator.comparingDouble(p -> p.y)); + + return closestPair(px, py); + } + + private static double closestPair(Point[] px, Point[] py) { + int n = px.length; + if (n <= 3) { + return bruteForce(px); + } + + int mid = n / 2; + Point midPoint = px[mid]; + + Point[] qx = Arrays.copyOfRange(px, 0, mid); + Point[] rx = Arrays.copyOfRange(px, mid, n); + + List qy = new ArrayList<>(); + List ry = new ArrayList<>(); + for (Point p : py) { + if (p.x <= midPoint.x) { + qy.add(p); + } else { + ry.add(p); + } + } + + double d1 = closestPair(qx, qy.toArray(new Point[0])); + double d2 = closestPair(rx, ry.toArray(new Point[0])); + + double d = Math.min(d1, d2); + + List strip = new ArrayList<>(); + for (Point p : py) { + if (Math.abs(p.x - midPoint.x) < d) { + strip.add(p); + } + } + + return Math.min(d, stripClosest(strip, d)); + } + + private static double bruteForce(Point[] points) { + double min = Double.POSITIVE_INFINITY; + for (int i = 0; i < points.length; i++) { + for (int j = i + 1; j < points.length; j++) { + min = Math.min(min, distance(points[i], points[j])); + } + } + return min; + } + + private static double stripClosest(List strip, double d) { + double min = d; + int n = strip.size(); + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n && (strip.get(j).y - strip.get(i).y) < min; j++) { + min = Math.min(min, distance(strip.get(i), strip.get(j))); + } + } + return min; + } + + private static double distance(Point p1, Point p2) { + return Math.hypot(p1.x - p2.x, p1.y - p2.y); + } +} diff --git a/src/main/java/com/thealgorithms/randomized/RandomizedMatrixMultiplicationVerification.java b/src/main/java/com/thealgorithms/randomized/RandomizedMatrixMultiplicationVerification.java new file mode 100644 index 000000000000..b5ac7076bfd6 --- /dev/null +++ b/src/main/java/com/thealgorithms/randomized/RandomizedMatrixMultiplicationVerification.java @@ -0,0 +1,64 @@ +package com.thealgorithms.randomized; + +import java.util.Random; + +public final class RandomizedMatrixMultiplicationVerification { + + private RandomizedMatrixMultiplicationVerification() { + // Prevent instantiation of utility class + } + + /** + * Verifies whether A × B == C using Freivalds' algorithm. + * @param A Left matrix + * @param B Right matrix + * @param C Product matrix to verify + * @param iterations Number of randomized checks + * @return true if likely A×B == C; false if definitely not + */ + public static boolean verify(int[][] a, int[][] b, int[][] c, int iterations) { + int n = a.length; + Random random = new Random(); + + for (int iter = 0; iter < iterations; iter++) { + // Step 1: Generate random 0/1 vector + int[] r = new int[n]; + for (int i = 0; i < n; i++) { + r[i] = random.nextInt(2); + } + + // Step 2: Compute br = b × r + int[] br = new int[n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + br[i] += b[i][j] * r[j]; + } + } + + // Step 3: Compute a(br) + int[] abr = new int[n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + abr[i] += a[i][j] * br[j]; + } + } + + // Step 4: Compute cr = c × r + int[] cr = new int[n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + cr[i] += c[i][j] * r[j]; + } + } + + // Step 5: Compare abr and cr + for (int i = 0; i < n; i++) { + if (abr[i] != cr[i]) { + return false; + } + } + } + + return true; + } +} diff --git a/src/main/java/com/thealgorithms/randomized/RandomizedQuickSort.java b/src/main/java/com/thealgorithms/randomized/RandomizedQuickSort.java new file mode 100644 index 000000000000..e9af223a0622 --- /dev/null +++ b/src/main/java/com/thealgorithms/randomized/RandomizedQuickSort.java @@ -0,0 +1,68 @@ +package com.thealgorithms.randomized; + +/** + * This class implements the Randomized QuickSort algorithm. + * It selects a pivot randomly to improve performance on sorted or nearly sorted data. + * @author Vibhu Khera + */ +public final class RandomizedQuickSort { + + private RandomizedQuickSort() { + throw new UnsupportedOperationException("Utility class"); + } + + /** + * Sorts the array using the randomized quicksort algorithm. + * + * @param arr the array to sort + * @param low the starting index of the array + * @param high the ending index of the array + */ + public static void randomizedQuickSort(int[] arr, int low, int high) { + if (low < high) { + int pivotIndex = partition(arr, low, high); + randomizedQuickSort(arr, low, pivotIndex - 1); + randomizedQuickSort(arr, pivotIndex + 1, high); + } + } + + /** + * Partitions the array around a pivot chosen randomly. + * + * @param arr the array to partition + * @param low the starting index + * @param high the ending index + * @return the index of the pivot after partitioning + */ + private static int partition(int[] arr, int low, int high) { + int pivotIndex = low + (int) (Math.random() * (high - low + 1)); + int pivotValue = arr[pivotIndex]; + swap(arr, pivotIndex, high); // Move pivot to end + int storeIndex = low; + for (int i = low; i < high; i++) { + if (arr[i] < pivotValue) { + swap(arr, storeIndex, i); + storeIndex++; + } + } + swap(arr, storeIndex, high); // Move pivot to its final place + return storeIndex; + } + + /** + * Swaps two elements in the array, only if the indices are different. + * + * @param arr the array in which elements are to be swapped + * @param i the first index + * @param j the second index + */ + private static void swap(int[] arr, int i, int j) { + // Skip if indices are the same + if (i == j) { + return; + } + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } +} diff --git a/src/main/java/com/thealgorithms/randomized/ReservoirSampling.java b/src/main/java/com/thealgorithms/randomized/ReservoirSampling.java new file mode 100644 index 000000000000..05e70f635055 --- /dev/null +++ b/src/main/java/com/thealgorithms/randomized/ReservoirSampling.java @@ -0,0 +1,55 @@ +package com.thealgorithms.randomized; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +/** + * Reservoir Sampling Algorithm + * + * Use Case: + * - Efficient for selecting k random items from a stream of unknown size + * - Used in streaming systems, big data, and memory-limited environments + * + * Time Complexity: O(n) + * Space Complexity: O(k) + * + * @author Michael Alexander Montoya (@cureprotocols) + * @see Reservoir Sampling - Wikipedia + */ +public final class ReservoirSampling { + + // Prevent instantiation of utility class + private ReservoirSampling() { + throw new UnsupportedOperationException("Utility class"); + } + + /** + * Selects k random elements from a stream using reservoir sampling. + * + * @param stream The input stream as an array of integers. + * @param sampleSize The number of elements to sample. + * @return A list containing k randomly selected elements. + */ + public static List sample(int[] stream, int sampleSize) { + if (sampleSize > stream.length) { + throw new IllegalArgumentException("Sample size cannot exceed stream size."); + } + + List reservoir = new ArrayList<>(sampleSize); + Random rand = new Random(); + + for (int i = 0; i < stream.length; i++) { + if (i < sampleSize) { + reservoir.add(stream[i]); + } else { + int j = rand.nextInt(i + 1); + if (j < sampleSize) { + reservoir.set(j, stream[i]); + } + } + } + + return reservoir; + } +} diff --git a/src/main/java/com/thealgorithms/recursion/GenerateSubsets.java b/src/main/java/com/thealgorithms/recursion/GenerateSubsets.java index 5a3ff2e88040..0114a55e5b75 100644 --- a/src/main/java/com/thealgorithms/recursion/GenerateSubsets.java +++ b/src/main/java/com/thealgorithms/recursion/GenerateSubsets.java @@ -1,36 +1,52 @@ package com.thealgorithms.recursion; -// program to find power set of a string - import java.util.ArrayList; import java.util.List; +/** + * Utility class to generate all subsets (power set) of a given string using recursion. + * + *

For example, the string "ab" will produce: ["ab", "a", "b", ""] + */ public final class GenerateSubsets { private GenerateSubsets() { - throw new UnsupportedOperationException("Utility class"); } + /** + * Generates all subsets (power set) of the given string using recursion. + * + * @param str the input string to generate subsets for + * @return a list of all subsets of the input string + */ public static List subsetRecursion(String str) { - return doRecursion("", str); + return generateSubsets("", str); } - private static List doRecursion(String p, String up) { - if (up.isEmpty()) { - List list = new ArrayList<>(); - list.add(p); - return list; + /** + * Recursive helper method to generate subsets by including or excluding characters. + * + * @param current the current prefix being built + * @param remaining the remaining string to process + * @return list of subsets formed from current and remaining + */ + private static List generateSubsets(String current, String remaining) { + if (remaining.isEmpty()) { + List result = new ArrayList<>(); + result.add(current); + return result; } - // Taking the character - char ch = up.charAt(0); - // Adding the character in the recursion - List left = doRecursion(p + ch, up.substring(1)); - // Not adding the character in the recursion - List right = doRecursion(p, up.substring(1)); + char ch = remaining.charAt(0); + String next = remaining.substring(1); + + // Include the character + List withChar = generateSubsets(current + ch, next); - left.addAll(right); + // Exclude the character + List withoutChar = generateSubsets(current, next); - return left; + withChar.addAll(withoutChar); + return withChar; } } diff --git a/src/main/java/com/thealgorithms/scheduling/RRScheduling.java b/src/main/java/com/thealgorithms/scheduling/RRScheduling.java index 110c97416a42..05efe1d59141 100644 --- a/src/main/java/com/thealgorithms/scheduling/RRScheduling.java +++ b/src/main/java/com/thealgorithms/scheduling/RRScheduling.java @@ -1,7 +1,3 @@ -/** - * @author Md Asif Joardar - */ - package com.thealgorithms.scheduling; import com.thealgorithms.devutils.entities.ProcessDetails; @@ -11,6 +7,7 @@ import java.util.Queue; /** + * @author Md Asif Joardar * The Round-robin scheduling algorithm is a kind of preemptive First come, First Serve CPU * Scheduling algorithm. This can be understood here - * https://www.scaler.com/topics/round-robin-scheduling-in-os/ diff --git a/src/main/java/com/thealgorithms/scheduling/SJFScheduling.java b/src/main/java/com/thealgorithms/scheduling/SJFScheduling.java index 6d105003e68f..e3f4a8d03d07 100644 --- a/src/main/java/com/thealgorithms/scheduling/SJFScheduling.java +++ b/src/main/java/com/thealgorithms/scheduling/SJFScheduling.java @@ -2,78 +2,62 @@ import com.thealgorithms.devutils.entities.ProcessDetails; import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; import java.util.List; /** - * Implementation of Shortest Job First Algorithm: The algorithm allows the waiting process with the - * minimal burst time to be executed first. see more here: - * https://www.guru99.com/shortest-job-first-sjf-scheduling.html + * Shortest Job First (SJF) Scheduling Algorithm: + * Executes processes with the shortest burst time first among the ones that have arrived. */ - public class SJFScheduling { - protected ArrayList processes; - protected ArrayList schedule; + private final List processes; + private final List schedule; - /** - * a simple constructor - * @param processes a list of processes the user wants to schedule - * it also sorts the processes based on the time of their arrival - */ - SJFScheduling(final ArrayList processes) { - this.processes = processes; - schedule = new ArrayList<>(); - sortByArrivalTime(); + public SJFScheduling(final List processes) { + this.processes = new ArrayList<>(processes); + this.schedule = new ArrayList<>(); + sortProcessesByArrivalTime(this.processes); } - protected void sortByArrivalTime() { - int size = processes.size(); - int i; - int j; - ProcessDetails temp; - for (i = 0; i < size; i++) { - for (j = i + 1; j < size - 1; j++) { - if (processes.get(j).getArrivalTime() > processes.get(j + 1).getArrivalTime()) { - temp = processes.get(j); - processes.set(j, processes.get(j + 1)); - processes.set(j + 1, temp); - } - } - } + + private static void sortProcessesByArrivalTime(List processes) { + processes.sort(Comparator.comparingInt(ProcessDetails::getArrivalTime)); } /** - * this functions returns the order of the executions + * Executes the SJF scheduling algorithm and builds the execution order. */ - public void scheduleProcesses() { - ArrayList ready = new ArrayList<>(); - + List ready = new ArrayList<>(); int size = processes.size(); - int runtime; int time = 0; int executed = 0; - int j; - int k = 0; - ProcessDetails running; - if (size == 0) { - return; + Iterator processIterator = processes.iterator(); + + // This will track the next process to be checked for arrival time + ProcessDetails nextProcess = null; + if (processIterator.hasNext()) { + nextProcess = processIterator.next(); } while (executed < size) { - while (k < size && processes.get(k).getArrivalTime() <= time) // here we find the processes that have arrived. - { - ready.add(processes.get(k)); - k++; + // Load all processes that have arrived by current time + while (nextProcess != null && nextProcess.getArrivalTime() <= time) { + ready.add(nextProcess); + if (processIterator.hasNext()) { + nextProcess = processIterator.next(); + } else { + nextProcess = null; + } } - running = findShortestJob(ready); + ProcessDetails running = findShortestJob(ready); if (running == null) { time++; } else { - runtime = running.getBurstTime(); - for (j = 0; j < runtime; j++) { - time++; - } + time += running.getBurstTime(); schedule.add(running.getProcessId()); ready.remove(running); executed++; @@ -82,30 +66,23 @@ public void scheduleProcesses() { } /** - * this function evaluates the shortest job of all the ready processes (based on a process - * burst time) + * Finds the process with the shortest job of all the ready processes (based on a process * @param readyProcesses an array list of ready processes * @return returns the process' with the shortest burst time OR NULL if there are no ready * processes */ - private ProcessDetails findShortestJob(List readyProcesses) { - if (readyProcesses.isEmpty()) { - return null; - } - int i; - int size = readyProcesses.size(); - int minBurstTime = readyProcesses.get(0).getBurstTime(); - int temp; - int positionOfShortestJob = 0; + private ProcessDetails findShortestJob(Collection readyProcesses) { + return readyProcesses.stream().min(Comparator.comparingInt(ProcessDetails::getBurstTime)).orElse(null); + } - for (i = 1; i < size; i++) { - temp = readyProcesses.get(i).getBurstTime(); - if (minBurstTime > temp) { - minBurstTime = temp; - positionOfShortestJob = i; - } - } + /** + * Returns the computed schedule after calling scheduleProcesses(). + */ + public List getSchedule() { + return schedule; + } - return readyProcesses.get(positionOfShortestJob); + public List getProcesses() { + return List.copyOf(processes); } } diff --git a/src/main/java/com/thealgorithms/searches/BoyerMoore.java b/src/main/java/com/thealgorithms/searches/BoyerMoore.java new file mode 100644 index 000000000000..6998021503cc --- /dev/null +++ b/src/main/java/com/thealgorithms/searches/BoyerMoore.java @@ -0,0 +1,58 @@ +package com.thealgorithms.searches; + +/** + * Boyer-Moore string search algorithm. + * Efficient algorithm for substring search. + * https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string-search_algorithm + */ +public class BoyerMoore { + + private final int radix; // Radix (number of possible characters) + private final int[] right; // Bad character rule table + private final String pattern; + + public BoyerMoore(String pat) { + this.pattern = pat; + this.radix = 256; + this.right = new int[radix]; + + for (int c = 0; c < radix; c++) { + right[c] = -1; + } + + for (int j = 0; j < pat.length(); j++) { + right[pat.charAt(j)] = j; + } + } + + public int search(String text) { + if (pattern.isEmpty()) { + return 0; + } + + int m = pattern.length(); + int n = text.length(); + + int skip; + for (int i = 0; i <= n - m; i += skip) { + skip = 0; + for (int j = m - 1; j >= 0; j--) { + char txtChar = text.charAt(i + j); + char patChar = pattern.charAt(j); + if (patChar != txtChar) { + skip = Math.max(1, j - right[txtChar]); + break; + } + } + if (skip == 0) { + return i; // Match found + } + } + + return -1; // No match + } + + public static int staticSearch(String text, String pattern) { + return new BoyerMoore(pattern).search(text); + } +} diff --git a/src/main/java/com/thealgorithms/searches/FibonacciSearch.java b/src/main/java/com/thealgorithms/searches/FibonacciSearch.java index 2124938bc258..78dac0f0a712 100644 --- a/src/main/java/com/thealgorithms/searches/FibonacciSearch.java +++ b/src/main/java/com/thealgorithms/searches/FibonacciSearch.java @@ -15,6 +15,7 @@ * Note: This algorithm requires that the input array be sorted. *

*/ +@SuppressWarnings({"rawtypes", "unchecked"}) public class FibonacciSearch implements SearchAlgorithm { /** diff --git a/src/main/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearch.java b/src/main/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearch.java index 3b4b0b08377f..b40c7554d84b 100644 --- a/src/main/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearch.java +++ b/src/main/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearch.java @@ -29,7 +29,7 @@ public > int[] find(T[][] matrix, T key) { public static > int[] search(T[][] matrix, T target) { int rowPointer = 0; // The pointer at 0th row - int colPointer = matrix.length - 1; // The pointer at end column + int colPointer = matrix[0].length - 1; // The pointer at end column while (rowPointer < matrix.length && colPointer >= 0) { int comp = target.compareTo(matrix[rowPointer][colPointer]); diff --git a/src/main/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrix.java b/src/main/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrix.java index 91fda373dca7..b53c7e5256ca 100644 --- a/src/main/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrix.java +++ b/src/main/java/com/thealgorithms/searches/SearchInARowAndColWiseSortedMatrix.java @@ -15,7 +15,6 @@ public int[] search(int[][] matrix, int value) { // This variable iterates over columns int j = n - 1; int[] result = {-1, -1}; - while (i < n && j >= 0) { if (matrix[i][j] == value) { result[0] = i; diff --git a/src/main/java/com/thealgorithms/slidingwindow/ShortestCoprimeSegment.java b/src/main/java/com/thealgorithms/slidingwindow/ShortestCoprimeSegment.java new file mode 100644 index 000000000000..b99f7ca7d62f --- /dev/null +++ b/src/main/java/com/thealgorithms/slidingwindow/ShortestCoprimeSegment.java @@ -0,0 +1,135 @@ +package com.thealgorithms.slidingwindow; + +import java.util.Arrays; +import java.util.LinkedList; + +/** + * The Sliding Window technique together with 2-stack technique is used to find coprime segment of minimal size in an array. + * Segment a[i],...,a[i+l] is coprime if gcd(a[i], a[i+1], ..., a[i+l]) = 1 + *

+ * Run-time complexity: O(n log n) + * What is special about this 2-stack technique is that it enables us to remove element a[i] and find gcd(a[i+1],...,a[i+l]) in amortized O(1) time. + * For 'remove' worst-case would be O(n) operation, but this happens rarely. + * Main observation is that each element gets processed a constant amount of times, hence complexity will be: + * O(n log n), where log n comes from complexity of gcd. + *

+ * More generally, the 2-stack technique enables us to 'remove' an element fast if it is known how to 'add' an element fast to the set. + * In our case 'adding' is calculating d' = gcd(a[i],...,a[i+l+1]), when d = gcd(a[i],...a[i]) with d' = gcd(d, a[i+l+1]). + * and removing is find gcd(a[i+1],...,a[i+l]). We don't calculate it explicitly, but it is pushed in the stack which we can pop in O(1). + *

+ * One can change methods 'legalSegment' and function 'f' in DoubleStack to adapt this code to other sliding-window type problems. + * I recommend this article for more explanations: "CF Article">Article 1 or USACO Article + *

+ * Another method to solve this problem is through segment trees. Then query operation would have O(log n), not O(1) time, but runtime complexity would still be O(n log n) + * + * @author DomTr (Github) + */ +public final class ShortestCoprimeSegment { + // Prevent instantiation + private ShortestCoprimeSegment() { + } + + /** + * @param arr is the input array + * @return shortest segment in the array which has gcd equal to 1. If no such segment exists or array is empty, returns empty array + */ + public static long[] shortestCoprimeSegment(long[] arr) { + if (arr == null || arr.length == 0) { + return new long[] {}; + } + DoubleStack front = new DoubleStack(); + DoubleStack back = new DoubleStack(); + int n = arr.length; + int l = 0; + int shortestLength = n + 1; + int beginsAt = -1; // beginning index of the shortest coprime segment + for (int i = 0; i < n; i++) { + back.push(arr[i]); + while (legalSegment(front, back)) { + remove(front, back); + if (shortestLength > i - l + 1) { + beginsAt = l; + shortestLength = i - l + 1; + } + l++; + } + } + if (shortestLength > n) { + shortestLength = -1; + } + if (shortestLength == -1) { + return new long[] {}; + } + return Arrays.copyOfRange(arr, beginsAt, beginsAt + shortestLength); + } + + private static boolean legalSegment(DoubleStack front, DoubleStack back) { + return gcd(front.top(), back.top()) == 1; + } + + private static long gcd(long a, long b) { + if (a < b) { + return gcd(b, a); + } else if (b == 0) { + return a; + } else { + return gcd(a % b, b); + } + } + + /** + * This solves the problem of removing elements quickly. + * Even though the worst case of 'remove' method is O(n), it is a very pessimistic view. + * We will need to empty out 'back', only when 'from' is empty. + * Consider element x when it is added to stack 'back'. + * After some time 'front' becomes empty and x goes to 'front'. Notice that in the for-loop we proceed further and x will never come back to any stacks 'back' or 'front'. + * In other words, every element gets processed by a constant number of operations. + * So 'remove' amortized runtime is actually O(n). + */ + private static void remove(DoubleStack front, DoubleStack back) { + if (front.isEmpty()) { + while (!back.isEmpty()) { + front.push(back.pop()); + } + } + front.pop(); + } + + /** + * DoubleStack serves as a collection of two stacks. One is a normal stack called 'stack', the other 'values' stores gcd-s up until some index. + */ + private static class DoubleStack { + LinkedList stack; + LinkedList values; + + DoubleStack() { + values = new LinkedList<>(); + stack = new LinkedList<>(); + values.add(0L); // Initialise with 0 which is neutral element in terms of gcd, i.e. gcd(a,0) = a + } + + long f(long a, long b) { // Can be replaced with other function + return gcd(a, b); + } + + public void push(long x) { + stack.addLast(x); + values.addLast(f(values.getLast(), x)); + } + + public long top() { + return values.getLast(); + } + + public long pop() { + long res = stack.getLast(); + stack.removeLast(); + values.removeLast(); + return res; + } + + public boolean isEmpty() { + return stack.isEmpty(); + } + } +} diff --git a/src/main/java/com/thealgorithms/sorts/AdaptiveMergeSort.java b/src/main/java/com/thealgorithms/sorts/AdaptiveMergeSort.java index 2c71bae8b557..09ea349875ac 100644 --- a/src/main/java/com/thealgorithms/sorts/AdaptiveMergeSort.java +++ b/src/main/java/com/thealgorithms/sorts/AdaptiveMergeSort.java @@ -30,7 +30,7 @@ private > void merge(T[] array, T[] aux, int low, int mi array[k] = aux[j++]; } else if (j > high) { array[k] = aux[i++]; - } else if (aux[j].compareTo(aux[i]) < 0) { + } else if (SortUtils.less(aux[j], aux[i])) { array[k] = aux[j++]; } else { array[k] = aux[i++]; diff --git a/src/main/java/com/thealgorithms/sorts/BinaryInsertionSort.java b/src/main/java/com/thealgorithms/sorts/BinaryInsertionSort.java index b6f5d92e7928..b8086bd0ebca 100644 --- a/src/main/java/com/thealgorithms/sorts/BinaryInsertionSort.java +++ b/src/main/java/com/thealgorithms/sorts/BinaryInsertionSort.java @@ -22,7 +22,7 @@ public > T[] sort(T[] array) { while (low <= high) { final int mid = (low + high) >>> 1; - if (temp.compareTo(array[mid]) < 0) { + if (SortUtils.less(temp, array[mid])) { high = mid - 1; } else { low = mid + 1; diff --git a/src/main/java/com/thealgorithms/sorts/BitonicSort.java b/src/main/java/com/thealgorithms/sorts/BitonicSort.java index 90d204818729..1c1a3ac45540 100644 --- a/src/main/java/com/thealgorithms/sorts/BitonicSort.java +++ b/src/main/java/com/thealgorithms/sorts/BitonicSort.java @@ -64,7 +64,7 @@ private > void bitonicMerge(T[] array, int low, int cnt, if (cnt > 1) { final int k = cnt / 2; - final BiPredicate areSorted = (direction == Direction.ASCENDING) ? (a, b) -> a.compareTo(b) < 0 : (a, b) -> a.compareTo(b) > 0; + final BiPredicate areSorted = (direction == Direction.ASCENDING) ? (a, b) -> SortUtils.less(a, b) : (a, b) -> SortUtils.greater(a, b); for (int i = low; i < low + k; i++) { if (!areSorted.test(array[i], array[i + k])) { SortUtils.swap(array, i, i + k); diff --git a/src/main/java/com/thealgorithms/sorts/BucketSort.java b/src/main/java/com/thealgorithms/sorts/BucketSort.java index 62c5e929593b..8882a1cb4bbd 100644 --- a/src/main/java/com/thealgorithms/sorts/BucketSort.java +++ b/src/main/java/com/thealgorithms/sorts/BucketSort.java @@ -111,7 +111,7 @@ private > int hash(final T element, final T min, final T private > T findMin(T[] array) { T min = array[0]; for (T element : array) { - if (element.compareTo(min) < 0) { + if (SortUtils.less(element, min)) { min = element; } } @@ -121,7 +121,7 @@ private > T findMin(T[] array) { private > T findMax(T[] array) { T max = array[0]; for (T element : array) { - if (element.compareTo(max) > 0) { + if (SortUtils.greater(element, max)) { max = element; } } diff --git a/src/main/java/com/thealgorithms/sorts/CircleSort.java b/src/main/java/com/thealgorithms/sorts/CircleSort.java index b9b41be16701..2863a40a2075 100644 --- a/src/main/java/com/thealgorithms/sorts/CircleSort.java +++ b/src/main/java/com/thealgorithms/sorts/CircleSort.java @@ -36,7 +36,7 @@ private > boolean doSort(final T[] array, final int left int high = right; while (low < high) { - if (array[low].compareTo(array[high]) > 0) { + if (SortUtils.greater(array[low], array[high])) { SortUtils.swap(array, low, high); swapped = true; } @@ -44,7 +44,7 @@ private > boolean doSort(final T[] array, final int left high--; } - if (low == high && array[low].compareTo(array[high + 1]) > 0) { + if (low == high && SortUtils.greater(array[low], array[high + 1])) { SortUtils.swap(array, low, high + 1); swapped = true; } diff --git a/src/main/java/com/thealgorithms/sorts/DarkSort.java b/src/main/java/com/thealgorithms/sorts/DarkSort.java new file mode 100644 index 000000000000..4887d7d124ba --- /dev/null +++ b/src/main/java/com/thealgorithms/sorts/DarkSort.java @@ -0,0 +1,59 @@ +package com.thealgorithms.sorts; + +/** + * Dark Sort algorithm implementation. + * + * Dark Sort uses a temporary array to count occurrences of elements and + * reconstructs the sorted array based on the counts. + */ +class DarkSort { + + /** + * Sorts the array using the Dark Sort algorithm. + * + * @param unsorted the array to be sorted + * @return sorted array + */ + public Integer[] sort(Integer[] unsorted) { + if (unsorted == null || unsorted.length <= 1) { + return unsorted; + } + + int max = findMax(unsorted); // Find the maximum value in the array + + // Create a temporary array for counting occurrences + int[] temp = new int[max + 1]; + + // Count occurrences of each element + for (int value : unsorted) { + temp[value]++; + } + + // Reconstruct the sorted array + int index = 0; + for (int i = 0; i < temp.length; i++) { + while (temp[i] > 0) { + unsorted[index++] = i; + temp[i]--; + } + } + + return unsorted; + } + + /** + * Helper method to find the maximum value in an array. + * + * @param arr the array + * @return the maximum value + */ + private int findMax(Integer[] arr) { + int max = arr[0]; + for (int value : arr) { + if (value > max) { + max = value; + } + } + return max; + } +} diff --git a/src/main/java/com/thealgorithms/sorts/DutchNationalFlagSort.java b/src/main/java/com/thealgorithms/sorts/DutchNationalFlagSort.java index abfcb452b29a..f7e12da06568 100644 --- a/src/main/java/com/thealgorithms/sorts/DutchNationalFlagSort.java +++ b/src/main/java/com/thealgorithms/sorts/DutchNationalFlagSort.java @@ -26,11 +26,11 @@ private > T[] dutchNationalFlagSort(final T[] array, fin int k = array.length - 1; while (j <= k) { - if (0 > array[j].compareTo(intendedMiddle)) { + if (SortUtils.less(array[j], intendedMiddle)) { SortUtils.swap(array, i, j); j++; i++; - } else if (0 < array[j].compareTo(intendedMiddle)) { + } else if (SortUtils.greater(array[j], intendedMiddle)) { SortUtils.swap(array, j, k); k--; } else { diff --git a/src/main/java/com/thealgorithms/sorts/ExchangeSort.java b/src/main/java/com/thealgorithms/sorts/ExchangeSort.java index 67e94b889671..a58caaf1031a 100644 --- a/src/main/java/com/thealgorithms/sorts/ExchangeSort.java +++ b/src/main/java/com/thealgorithms/sorts/ExchangeSort.java @@ -31,7 +31,7 @@ class ExchangeSort implements SortAlgorithm { public > T[] sort(T[] array) { for (int i = 0; i < array.length - 1; i++) { for (int j = i + 1; j < array.length; j++) { - if (array[i].compareTo(array[j]) > 0) { + if (SortUtils.greater(array[i], array[j])) { SortUtils.swap(array, i, j); } } diff --git a/src/main/java/com/thealgorithms/sorts/IntrospectiveSort.java b/src/main/java/com/thealgorithms/sorts/IntrospectiveSort.java index 12ef197b931b..6f846c7b9a8f 100644 --- a/src/main/java/com/thealgorithms/sorts/IntrospectiveSort.java +++ b/src/main/java/com/thealgorithms/sorts/IntrospectiveSort.java @@ -63,7 +63,7 @@ private static > int partition(T[] array, final int low, final T pivot = array[high]; int i = low - 1; for (int j = low; j < high; j++) { - if (array[j].compareTo(pivot) <= 0) { + if (SortUtils.greaterOrEqual(pivot, array[j])) { i++; SortUtils.swap(array, i, j); } @@ -84,7 +84,7 @@ private static > void insertionSort(T[] array, final int for (int i = low + 1; i <= high; i++) { final T key = array[i]; int j = i - 1; - while (j >= low && array[j].compareTo(key) > 0) { + while (j >= low && SortUtils.greater(array[j], key)) { array[j + 1] = array[j]; j--; } @@ -125,10 +125,10 @@ private static > void heapify(T[] array, final int i, fi final int right = 2 * i + 2; int largest = i; - if (left < n && array[low + left].compareTo(array[low + largest]) > 0) { + if (left < n && SortUtils.greater(array[low + left], array[low + largest])) { largest = left; } - if (right < n && array[low + right].compareTo(array[low + largest]) > 0) { + if (right < n && SortUtils.greater(array[low + right], array[low + largest])) { largest = right; } if (largest != i) { diff --git a/src/main/java/com/thealgorithms/sorts/MergeSort.java b/src/main/java/com/thealgorithms/sorts/MergeSort.java index 9949783ca21b..86a184f67b26 100644 --- a/src/main/java/com/thealgorithms/sorts/MergeSort.java +++ b/src/main/java/com/thealgorithms/sorts/MergeSort.java @@ -7,6 +7,7 @@ * * @see SortAlgorithm */ +@SuppressWarnings("rawtypes") class MergeSort implements SortAlgorithm { private Comparable[] aux; diff --git a/src/main/java/com/thealgorithms/sorts/OddEvenSort.java b/src/main/java/com/thealgorithms/sorts/OddEvenSort.java index ac94982c1474..b854842e9645 100644 --- a/src/main/java/com/thealgorithms/sorts/OddEvenSort.java +++ b/src/main/java/com/thealgorithms/sorts/OddEvenSort.java @@ -30,7 +30,7 @@ public > T[] sort(T[] array) { private > boolean performOddSort(T[] array) { boolean sorted = true; for (int i = 1; i < array.length - 1; i += 2) { - if (array[i].compareTo(array[i + 1]) > 0) { + if (SortUtils.greater(array[i], array[i + 1])) { SortUtils.swap(array, i, i + 1); sorted = false; } @@ -41,7 +41,7 @@ private > boolean performOddSort(T[] array) { private > boolean performEvenSort(T[] array) { boolean sorted = true; for (int i = 0; i < array.length - 1; i += 2) { - if (array[i].compareTo(array[i + 1]) > 0) { + if (SortUtils.greater(array[i], array[i + 1])) { SortUtils.swap(array, i, i + 1); sorted = false; } diff --git a/src/main/java/com/thealgorithms/sorts/SelectionSort.java b/src/main/java/com/thealgorithms/sorts/SelectionSort.java index dbb2b88ffcef..db7732d7e218 100644 --- a/src/main/java/com/thealgorithms/sorts/SelectionSort.java +++ b/src/main/java/com/thealgorithms/sorts/SelectionSort.java @@ -21,7 +21,7 @@ public > T[] sort(T[] array) { private static > int findIndexOfMin(T[] array, final int startIndex) { int minIndex = startIndex; for (int i = startIndex + 1; i < array.length; i++) { - if (array[i].compareTo(array[minIndex]) < 0) { + if (SortUtils.less(array[i], array[minIndex])) { minIndex = i; } } diff --git a/src/main/java/com/thealgorithms/sorts/SelectionSortRecursive.java b/src/main/java/com/thealgorithms/sorts/SelectionSortRecursive.java index 9d24542de592..f220c2d8f994 100644 --- a/src/main/java/com/thealgorithms/sorts/SelectionSortRecursive.java +++ b/src/main/java/com/thealgorithms/sorts/SelectionSortRecursive.java @@ -56,6 +56,6 @@ private static > int findMinIndex(T[] array, final int s final int minIndexInRest = findMinIndex(array, start + 1); // Return the index of the smaller element between array[start] and the minimum element in the rest of the array - return array[start].compareTo(array[minIndexInRest]) < 0 ? start : minIndexInRest; + return SortUtils.less(array[start], array[minIndexInRest]) ? start : minIndexInRest; } } diff --git a/src/main/java/com/thealgorithms/sorts/SimpleSort.java b/src/main/java/com/thealgorithms/sorts/SimpleSort.java deleted file mode 100644 index a03223cb01a1..000000000000 --- a/src/main/java/com/thealgorithms/sorts/SimpleSort.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.thealgorithms.sorts; - -public class SimpleSort implements SortAlgorithm { - @Override - public > T[] sort(T[] array) { - for (int i = 0; i < array.length; i++) { - for (int j = i + 1; j < array.length; j++) { - if (SortUtils.less(array[j], array[i])) { - SortUtils.swap(array, i, j); - } - } - } - return array; - } -} diff --git a/src/main/java/com/thealgorithms/sorts/SortAlgorithm.java b/src/main/java/com/thealgorithms/sorts/SortAlgorithm.java index 7a3ded37bf3f..72b046d12861 100644 --- a/src/main/java/com/thealgorithms/sorts/SortAlgorithm.java +++ b/src/main/java/com/thealgorithms/sorts/SortAlgorithm.java @@ -8,6 +8,7 @@ * * @author Podshivalov Nikita (https://github.com/nikitap492) */ +@SuppressWarnings("rawtypes") public interface SortAlgorithm { /** * Main method arrays sorting algorithms diff --git a/src/main/java/com/thealgorithms/sorts/SpreadSort.java b/src/main/java/com/thealgorithms/sorts/SpreadSort.java index f1fd24f4735d..1401f3d454a8 100644 --- a/src/main/java/com/thealgorithms/sorts/SpreadSort.java +++ b/src/main/java/com/thealgorithms/sorts/SpreadSort.java @@ -6,6 +6,7 @@ * It distributes elements into buckets and recursively sorts these buckets. * This implementation is generic and can sort any array of elements that extend Comparable. */ +@SuppressWarnings("rawtypes") public class SpreadSort implements SortAlgorithm { private static final int MAX_INSERTION_SORT_THRESHOLD = 1000; private static final int MAX_INITIAL_BUCKET_CAPACITY = 1000; diff --git a/src/main/java/com/thealgorithms/sorts/StalinSort.java b/src/main/java/com/thealgorithms/sorts/StalinSort.java index 5aaf530fd94c..fe07a6f6d986 100644 --- a/src/main/java/com/thealgorithms/sorts/StalinSort.java +++ b/src/main/java/com/thealgorithms/sorts/StalinSort.java @@ -8,7 +8,7 @@ public > T[] sort(T[] array) { } int currentIndex = 0; for (int i = 1; i < array.length; i++) { - if (array[i].compareTo(array[currentIndex]) >= 0) { + if (SortUtils.greaterOrEqual(array[i], array[currentIndex])) { currentIndex++; array[currentIndex] = array[i]; } diff --git a/src/main/java/com/thealgorithms/sorts/TimSort.java b/src/main/java/com/thealgorithms/sorts/TimSort.java index 2d5bca2ef6f3..13cd7fed35c7 100644 --- a/src/main/java/com/thealgorithms/sorts/TimSort.java +++ b/src/main/java/com/thealgorithms/sorts/TimSort.java @@ -7,6 +7,7 @@ *

* For more details @see TimSort Algorithm */ +@SuppressWarnings({"rawtypes", "unchecked"}) class TimSort implements SortAlgorithm { private static final int SUB_ARRAY_SIZE = 32; private Comparable[] aux; diff --git a/src/main/java/com/thealgorithms/stacks/DecimalToAnyUsingStack.java b/src/main/java/com/thealgorithms/stacks/DecimalToAnyUsingStack.java index ff6402c92695..2852454fd096 100644 --- a/src/main/java/com/thealgorithms/stacks/DecimalToAnyUsingStack.java +++ b/src/main/java/com/thealgorithms/stacks/DecimalToAnyUsingStack.java @@ -2,17 +2,29 @@ import java.util.Stack; +/** + * Utility class for converting a non-negative decimal (base-10) integer + * to its representation in another radix (base) between 2 and 16, inclusive. + * + *

This class uses a stack-based approach to reverse the digits obtained from + * successive divisions by the target radix. + * + *

This class cannot be instantiated.

+ */ public final class DecimalToAnyUsingStack { + private DecimalToAnyUsingStack() { } + private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + /** * Convert a decimal number to another radix. * * @param number the number to be converted * @param radix the radix * @return the number represented in the new radix as a String - * @throws IllegalArgumentException if number is negative or radix is not between 2 and 16 inclusive + * @throws IllegalArgumentException if number is negative or radix is not between 2 and 16 inclusive */ public static String convert(int number, int radix) { if (number < 0) { @@ -26,18 +38,17 @@ public static String convert(int number, int radix) { return "0"; } - char[] tables = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - - Stack bits = new Stack<>(); + Stack digitStack = new Stack<>(); while (number > 0) { - bits.push(tables[number % radix]); - number = number / radix; + digitStack.push(DIGITS[number % radix]); + number /= radix; } - StringBuilder result = new StringBuilder(); - while (!bits.isEmpty()) { - result.append(bits.pop()); + StringBuilder result = new StringBuilder(digitStack.size()); + while (!digitStack.isEmpty()) { + result.append(digitStack.pop()); } + return result.toString(); } } diff --git a/src/main/java/com/thealgorithms/stacks/InfixToPostfix.java b/src/main/java/com/thealgorithms/stacks/InfixToPostfix.java index 33611bd73dba..77ca3e70849f 100644 --- a/src/main/java/com/thealgorithms/stacks/InfixToPostfix.java +++ b/src/main/java/com/thealgorithms/stacks/InfixToPostfix.java @@ -4,54 +4,96 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +/** + * Utility class for converting an infix arithmetic expression + * into its equivalent postfix (Reverse Polish Notation) form. + *

+ * This class provides a static method to perform the conversion, + * validating balanced brackets before processing. + *

+ */ public final class InfixToPostfix { + private InfixToPostfix() { } - public static String infix2PostFix(String infixExpression) throws Exception { + /** + * Converts a given infix expression string to a postfix expression string. + *

+ * The method first checks if the brackets in the input expression are balanced + * by calling {@code BalancedBrackets.isBalanced} on the filtered brackets. + * If the brackets are not balanced, it throws an IllegalArgumentException. + *

+ *

+ * Supported operators are: {@code +, -, *, /, ^} + * and operands can be letters or digits. + *

+ * + * @param infixExpression the arithmetic expression in infix notation + * @return the equivalent postfix notation expression + * @throws IllegalArgumentException if the brackets in the expression are unbalanced + */ + public static String infix2PostFix(String infixExpression) { if (!BalancedBrackets.isBalanced(filterBrackets(infixExpression))) { - throw new Exception("invalid expression"); + throw new IllegalArgumentException("Invalid expression: unbalanced brackets."); } + StringBuilder output = new StringBuilder(); - Stack stack = new Stack<>(); - for (char element : infixExpression.toCharArray()) { - if (Character.isLetterOrDigit(element)) { - output.append(element); - } else if (element == '(') { - stack.push(element); - } else if (element == ')') { - while (!stack.isEmpty() && stack.peek() != '(') { - output.append(stack.pop()); + Stack operatorStack = new Stack<>(); + + for (char token : infixExpression.toCharArray()) { + if (Character.isLetterOrDigit(token)) { + // Append operands (letters or digits) directly to output + output.append(token); + } else if (token == '(') { + // Push '(' to stack + operatorStack.push(token); + } else if (token == ')') { + // Pop and append until '(' is found + while (!operatorStack.isEmpty() && operatorStack.peek() != '(') { + output.append(operatorStack.pop()); } - stack.pop(); + operatorStack.pop(); // Remove '(' from stack } else { - while (!stack.isEmpty() && precedence(element) <= precedence(stack.peek())) { - output.append(stack.pop()); + // Pop operators with higher or equal precedence and append them + while (!operatorStack.isEmpty() && precedence(token) <= precedence(operatorStack.peek())) { + output.append(operatorStack.pop()); } - stack.push(element); + operatorStack.push(token); } } - while (!stack.isEmpty()) { - output.append(stack.pop()); + + // Pop any remaining operators + while (!operatorStack.isEmpty()) { + output.append(operatorStack.pop()); } + return output.toString(); } + /** + * Returns the precedence level of the given operator. + * + * @param operator the operator character (e.g., '+', '-', '*', '/', '^') + * @return the precedence value: higher means higher precedence, + * or -1 if the character is not a recognized operator + */ private static int precedence(char operator) { - switch (operator) { - case '+': - case '-': - return 0; - case '*': - case '/': - return 1; - case '^': - return 2; - default: - return -1; - } + return switch (operator) { + case '+', '-' -> 0; + case '*', '/' -> 1; + case '^' -> 2; + default -> -1; + }; } + /** + * Extracts only the bracket characters from the input string. + * Supports parentheses (), curly braces {}, square brackets [], and angle brackets <>. + * + * @param input the original expression string + * @return a string containing only bracket characters from the input + */ private static String filterBrackets(String input) { Pattern pattern = Pattern.compile("[^(){}\\[\\]<>]"); Matcher matcher = pattern.matcher(input); diff --git a/src/main/java/com/thealgorithms/stacks/InfixToPrefix.java b/src/main/java/com/thealgorithms/stacks/InfixToPrefix.java index 3d90d14e0d1e..e9ee5e208df6 100644 --- a/src/main/java/com/thealgorithms/stacks/InfixToPrefix.java +++ b/src/main/java/com/thealgorithms/stacks/InfixToPrefix.java @@ -4,85 +4,109 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +/** + * Utility class for converting an infix arithmetic expression + * into its equivalent prefix notation expression. + *

+ * This class provides a static method to perform the conversion, + * validating balanced brackets before processing. + *

+ */ public final class InfixToPrefix { + private InfixToPrefix() { } /** - * Convert an infix expression to a prefix expression using stack. + * Converts a given infix expression string to a prefix expression string. + *

+ * The method validates that the input expression has balanced brackets using + * {@code BalancedBrackets.isBalanced} on the filtered bracket characters. + * It throws an {@code IllegalArgumentException} if the brackets are unbalanced, + * and a {@code NullPointerException} if the input is null. + *

+ *

+ * Supported operators: {@code +, -, *, /, ^} and operands can be letters or digits. + *

* - * @param infixExpression the infix expression to convert - * @return the prefix expression - * @throws IllegalArgumentException if the infix expression has unbalanced brackets - * @throws NullPointerException if the infix expression is null + * @param infixExpression the arithmetic expression in infix notation + * @return the equivalent prefix notation expression + * @throws IllegalArgumentException if brackets are unbalanced + * @throws NullPointerException if the input expression is null */ - public static String infix2Prefix(String infixExpression) throws IllegalArgumentException { + public static String infix2Prefix(String infixExpression) { if (infixExpression == null) { throw new NullPointerException("Input expression cannot be null."); } + infixExpression = infixExpression.trim(); if (infixExpression.isEmpty()) { return ""; } + if (!BalancedBrackets.isBalanced(filterBrackets(infixExpression))) { throw new IllegalArgumentException("Invalid expression: unbalanced brackets."); } StringBuilder output = new StringBuilder(); - Stack stack = new Stack<>(); - // Reverse the infix expression for prefix conversion + Stack operatorStack = new Stack<>(); + + // Reverse the infix expression to facilitate prefix conversion String reversedInfix = new StringBuilder(infixExpression).reverse().toString(); - for (char element : reversedInfix.toCharArray()) { - if (Character.isLetterOrDigit(element)) { - output.append(element); - } else if (element == ')') { - stack.push(element); - } else if (element == '(') { - while (!stack.isEmpty() && stack.peek() != ')') { - output.append(stack.pop()); + + for (char token : reversedInfix.toCharArray()) { + if (Character.isLetterOrDigit(token)) { + // Append operands directly to output + output.append(token); + } else if (token == ')') { + // Push ')' onto stack (since expression is reversed, '(' and ')' roles swapped) + operatorStack.push(token); + } else if (token == '(') { + // Pop operators until ')' is found + while (!operatorStack.isEmpty() && operatorStack.peek() != ')') { + output.append(operatorStack.pop()); } - stack.pop(); + operatorStack.pop(); // Remove the ')' } else { - while (!stack.isEmpty() && precedence(element) < precedence(stack.peek())) { - output.append(stack.pop()); + // Pop operators with higher precedence before pushing current operator + while (!operatorStack.isEmpty() && precedence(token) < precedence(operatorStack.peek())) { + output.append(operatorStack.pop()); } - stack.push(element); + operatorStack.push(token); } } - while (!stack.isEmpty()) { - output.append(stack.pop()); + + // Append any remaining operators in stack + while (!operatorStack.isEmpty()) { + output.append(operatorStack.pop()); } - // Reverse the result to get the prefix expression + // Reverse the output to obtain the final prefix expression return output.reverse().toString(); } /** - * Determines the precedence of an operator. + * Returns the precedence level of the given operator. * - * @param operator the operator whose precedence is to be determined - * @return the precedence of the operator + * @param operator the operator character (e.g., '+', '-', '*', '/', '^') + * @return the precedence value: higher means higher precedence, + * or -1 if the character is not a recognized operator */ private static int precedence(char operator) { - switch (operator) { - case '+': - case '-': - return 0; - case '*': - case '/': - return 1; - case '^': - return 2; - default: - return -1; - } + return switch (operator) { + case '+', '-' -> 0; + case '*', '/' -> 1; + case '^' -> 2; + default -> -1; + }; } /** - * Filters out all characters from the input string except brackets. + * Extracts only the bracket characters from the input string. + * Supports parentheses (), curly braces {}, square brackets [], and angle brackets <>. * - * @param input the input string to filter - * @return a string containing only brackets from the input string + * @param input the original expression string + * @return a string containing only bracket characters from the input */ private static String filterBrackets(String input) { Pattern pattern = Pattern.compile("[^(){}\\[\\]<>]"); diff --git a/src/main/java/com/thealgorithms/stacks/LargestRectangle.java b/src/main/java/com/thealgorithms/stacks/LargestRectangle.java index 006e03632e63..eb222c8c488e 100644 --- a/src/main/java/com/thealgorithms/stacks/LargestRectangle.java +++ b/src/main/java/com/thealgorithms/stacks/LargestRectangle.java @@ -3,36 +3,50 @@ import java.util.Stack; /** + * Utility class to calculate the largest rectangle area in a histogram. + * Each bar's width is assumed to be 1 unit. * - * @author mohd rameez github.com/rameez471 + *

This implementation uses a monotonic stack to efficiently calculate + * the area of the largest rectangle that can be formed from the histogram bars.

+ * + *

Example usage: + *

{@code
+ *     int[] heights = {2, 1, 5, 6, 2, 3};
+ *     String area = LargestRectangle.largestRectangleHistogram(heights);
+ *     // area is "10"
+ * }
*/ - public final class LargestRectangle { + private LargestRectangle() { } + /** + * Calculates the largest rectangle area in the given histogram. + * + * @param heights an array of non-negative integers representing bar heights + * @return the largest rectangle area as a {@link String} + */ public static String largestRectangleHistogram(int[] heights) { - int n = heights.length; int maxArea = 0; - Stack st = new Stack<>(); - for (int i = 0; i < n; i++) { + Stack stack = new Stack<>(); + + for (int i = 0; i < heights.length; i++) { int start = i; - while (!st.isEmpty() && st.peek()[1] > heights[i]) { - int[] tmp = st.pop(); - maxArea = Math.max(maxArea, tmp[1] * (i - tmp[0])); - start = tmp[0]; + while (!stack.isEmpty() && stack.peek()[1] > heights[i]) { + int[] popped = stack.pop(); + maxArea = Math.max(maxArea, popped[1] * (i - popped[0])); + start = popped[0]; } - st.push(new int[] {start, heights[i]}); + stack.push(new int[] {start, heights[i]}); } - while (!st.isEmpty()) { - int[] tmp = st.pop(); - maxArea = Math.max(maxArea, tmp[1] * (n - tmp[0])); + + int totalLength = heights.length; + while (!stack.isEmpty()) { + int[] remaining = stack.pop(); + maxArea = Math.max(maxArea, remaining[1] * (totalLength - remaining[0])); } - return Integer.toString(maxArea); - } - public static void main(String[] args) { - assert largestRectangleHistogram(new int[] {2, 1, 5, 6, 2, 3}).equals("10"); - assert largestRectangleHistogram(new int[] {2, 4}).equals("4"); + return Integer.toString(maxArea); } } diff --git a/src/main/java/com/thealgorithms/strings/Alphabetical.java b/src/main/java/com/thealgorithms/strings/Alphabetical.java index de07dde2d510..ef2974eb427d 100644 --- a/src/main/java/com/thealgorithms/strings/Alphabetical.java +++ b/src/main/java/com/thealgorithms/strings/Alphabetical.java @@ -1,36 +1,32 @@ package com.thealgorithms.strings; /** + * Utility class for checking if a string's characters are in alphabetical order. + *

* Alphabetical order is a system whereby character strings are placed in order * based on the position of the characters in the conventional ordering of an - * alphabet. Wikipedia: https://en.wikipedia.org/wiki/Alphabetical_order + * alphabet. + *

+ * Reference: Wikipedia: Alphabetical Order */ -final class Alphabetical { +public final class Alphabetical { private Alphabetical() { } - public static void main(String[] args) { - assert !isAlphabetical("123abc"); - assert isAlphabetical("aBC"); - assert isAlphabetical("abc"); - assert !isAlphabetical("xyzabc"); - assert isAlphabetical("abcxyz"); - } - /** - * Check if a string is alphabetical order or not + * Checks whether the characters in the given string are in alphabetical order. + * Non-letter characters will cause the check to fail. * - * @param s a string - * @return {@code true} if given string is alphabetical order, otherwise - * {@code false} + * @param s the input string + * @return {@code true} if all characters are in alphabetical order (case-insensitive), otherwise {@code false} */ public static boolean isAlphabetical(String s) { s = s.toLowerCase(); for (int i = 0; i < s.length() - 1; ++i) { - if (!Character.isLetter(s.charAt(i)) || !(s.charAt(i) <= s.charAt(i + 1))) { + if (!Character.isLetter(s.charAt(i)) || s.charAt(i) > s.charAt(i + 1)) { return false; } } - return true; + return !s.isEmpty() && Character.isLetter(s.charAt(s.length() - 1)); } } diff --git a/src/main/java/com/thealgorithms/strings/Anagrams.java b/src/main/java/com/thealgorithms/strings/Anagrams.java index 4b24979e2689..5b97af0758f2 100644 --- a/src/main/java/com/thealgorithms/strings/Anagrams.java +++ b/src/main/java/com/thealgorithms/strings/Anagrams.java @@ -23,7 +23,9 @@ private Anagrams() { * @param t the second string * @return true if the strings are anagrams, false otherwise */ - public static boolean approach1(String s, String t) { + public static boolean areAnagramsBySorting(String s, String t) { + s = s.toLowerCase().replaceAll("[^a-z]", ""); + t = t.toLowerCase().replaceAll("[^a-z]", ""); if (s.length() != t.length()) { return false; } @@ -43,17 +45,18 @@ public static boolean approach1(String s, String t) { * @param t the second string * @return true if the strings are anagrams, false otherwise */ - public static boolean approach2(String s, String t) { - if (s.length() != t.length()) { - return false; + public static boolean areAnagramsByCountingChars(String s, String t) { + s = s.toLowerCase().replaceAll("[^a-z]", ""); + t = t.toLowerCase().replaceAll("[^a-z]", ""); + int[] dict = new int[128]; + for (char ch : s.toCharArray()) { + dict[ch]++; } - int[] charCount = new int[26]; - for (int i = 0; i < s.length(); i++) { - charCount[s.charAt(i) - 'a']++; - charCount[t.charAt(i) - 'a']--; + for (char ch : t.toCharArray()) { + dict[ch]--; } - for (int count : charCount) { - if (count != 0) { + for (int e : dict) { + if (e != 0) { return false; } } @@ -70,7 +73,9 @@ public static boolean approach2(String s, String t) { * @param t the second string * @return true if the strings are anagrams, false otherwise */ - public static boolean approach3(String s, String t) { + public static boolean areAnagramsByCountingCharsSingleArray(String s, String t) { + s = s.toLowerCase().replaceAll("[^a-z]", ""); + t = t.toLowerCase().replaceAll("[^a-z]", ""); if (s.length() != t.length()) { return false; } @@ -96,7 +101,9 @@ public static boolean approach3(String s, String t) { * @param t the second string * @return true if the strings are anagrams, false otherwise */ - public static boolean approach4(String s, String t) { + public static boolean areAnagramsUsingHashMap(String s, String t) { + s = s.toLowerCase().replaceAll("[^a-z]", ""); + t = t.toLowerCase().replaceAll("[^a-z]", ""); if (s.length() != t.length()) { return false; } @@ -123,7 +130,9 @@ public static boolean approach4(String s, String t) { * @param t the second string * @return true if the strings are anagrams, false otherwise */ - public static boolean approach5(String s, String t) { + public static boolean areAnagramsBySingleFreqArray(String s, String t) { + s = s.toLowerCase().replaceAll("[^a-z]", ""); + t = t.toLowerCase().replaceAll("[^a-z]", ""); if (s.length() != t.length()) { return false; } diff --git a/src/main/java/com/thealgorithms/strings/CheckAnagrams.java b/src/main/java/com/thealgorithms/strings/CheckAnagrams.java deleted file mode 100644 index 7bf7cd9a7c66..000000000000 --- a/src/main/java/com/thealgorithms/strings/CheckAnagrams.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.thealgorithms.strings; - -import java.util.HashMap; -import java.util.Map; - -/** - * Two strings are anagrams if they are made of the same letters arranged - * differently (ignoring the case). - */ -public final class CheckAnagrams { - private CheckAnagrams() { - } - /** - * Check if two strings are anagrams or not - * - * @param s1 the first string - * @param s2 the second string - * @return {@code true} if two string are anagrams, otherwise {@code false} - */ - public static boolean isAnagrams(String s1, String s2) { - int l1 = s1.length(); - int l2 = s2.length(); - s1 = s1.toLowerCase(); - s2 = s2.toLowerCase(); - Map charAppearances = new HashMap<>(); - - for (int i = 0; i < l1; i++) { - char c = s1.charAt(i); - int numOfAppearances = charAppearances.getOrDefault(c, 0); - charAppearances.put(c, numOfAppearances + 1); - } - - for (int i = 0; i < l2; i++) { - char c = s2.charAt(i); - if (!charAppearances.containsKey(c)) { - return false; - } - charAppearances.put(c, charAppearances.get(c) - 1); - } - - for (int cnt : charAppearances.values()) { - if (cnt != 0) { - return false; - } - } - return true; - } - - /** - * If given strings contain Unicode symbols. - * The first 128 ASCII codes are identical to Unicode. - * This algorithm is case-sensitive. - * - * @param s1 the first string - * @param s2 the second string - * @return true if two string are anagrams, otherwise false - */ - public static boolean isAnagramsUnicode(String s1, String s2) { - int[] dict = new int[128]; - for (char ch : s1.toCharArray()) { - dict[ch]++; - } - for (char ch : s2.toCharArray()) { - dict[ch]--; - } - for (int e : dict) { - if (e != 0) { - return false; - } - } - return true; - } - - /** - * If given strings contain only lowercase English letters. - *

- * The main "trick": - * To map each character from the first string 's1' we need to subtract an integer value of 'a' character - * as 'dict' array starts with 'a' character. - * - * @param s1 the first string - * @param s2 the second string - * @return true if two string are anagrams, otherwise false - */ - public static boolean isAnagramsOptimised(String s1, String s2) { - // 26 - English alphabet length - int[] dict = new int[26]; - for (char ch : s1.toCharArray()) { - checkLetter(ch); - dict[ch - 'a']++; - } - for (char ch : s2.toCharArray()) { - checkLetter(ch); - dict[ch - 'a']--; - } - for (int e : dict) { - if (e != 0) { - return false; - } - } - return true; - } - - private static void checkLetter(char ch) { - int index = ch - 'a'; - if (index < 0 || index >= 26) { - throw new IllegalArgumentException("Strings must contain only lowercase English letters!"); - } - } -} diff --git a/src/main/java/com/thealgorithms/strings/Isomorphic.java b/src/main/java/com/thealgorithms/strings/Isomorphic.java index ccd686170715..7ee00e62e16b 100644 --- a/src/main/java/com/thealgorithms/strings/Isomorphic.java +++ b/src/main/java/com/thealgorithms/strings/Isomorphic.java @@ -5,35 +5,54 @@ import java.util.Map; import java.util.Set; +/** + * Utility class to check if two strings are isomorphic. + * + *

+ * Two strings {@code s} and {@code t} are isomorphic if the characters in {@code s} + * can be replaced to get {@code t}, while preserving the order of characters. + * Each character must map to exactly one character, and no two characters can map to the same character. + *

+ * + * @see Isomorphic Strings + */ public final class Isomorphic { + private Isomorphic() { } - public static boolean checkStrings(String s, String t) { + /** + * Checks if two strings are isomorphic. + * + * @param s the first input string + * @param t the second input string + * @return {@code true} if {@code s} and {@code t} are isomorphic; {@code false} otherwise + */ + public static boolean areIsomorphic(String s, String t) { if (s.length() != t.length()) { return false; } - // To mark the characters of string using MAP - // character of first string as KEY and another as VALUE - // now check occurence by keeping the track with SET data structure - Map characterMap = new HashMap<>(); - Set trackUniqueCharacter = new HashSet<>(); + Map map = new HashMap<>(); + Set usedCharacters = new HashSet<>(); for (int i = 0; i < s.length(); i++) { - if (characterMap.containsKey(s.charAt(i))) { - if (t.charAt(i) != characterMap.get(s.charAt(i))) { + char sourceChar = s.charAt(i); + char targetChar = t.charAt(i); + + if (map.containsKey(sourceChar)) { + if (map.get(sourceChar) != targetChar) { return false; } } else { - if (trackUniqueCharacter.contains(t.charAt(i))) { + if (usedCharacters.contains(targetChar)) { return false; } - - characterMap.put(s.charAt(i), t.charAt(i)); + map.put(sourceChar, targetChar); + usedCharacters.add(targetChar); } - trackUniqueCharacter.add(t.charAt(i)); } + return true; } } diff --git a/src/main/java/com/thealgorithms/strings/LongestCommonPrefix.java b/src/main/java/com/thealgorithms/strings/LongestCommonPrefix.java index 0fabdaa2658b..3348b9cf860c 100644 --- a/src/main/java/com/thealgorithms/strings/LongestCommonPrefix.java +++ b/src/main/java/com/thealgorithms/strings/LongestCommonPrefix.java @@ -2,21 +2,41 @@ import java.util.Arrays; +/** + * Utility class for string operations. + *

+ * This class provides a method to find the longest common prefix (LCP) + * among an array of strings. + *

+ * + * @see Longest Common Prefix - Wikipedia + */ public final class LongestCommonPrefix { - public String longestCommonPrefix(String[] strs) { + + private LongestCommonPrefix() { + } + + /** + * Finds the longest common prefix among a list of strings using lexicographical sorting. + * The prefix is common to the first and last elements after sorting the array. + * + * @param strs array of input strings + * @return the longest common prefix, or empty string if none exists + */ + public static String longestCommonPrefix(String[] strs) { if (strs == null || strs.length == 0) { return ""; } Arrays.sort(strs); - String shortest = strs[0]; - String longest = strs[strs.length - 1]; + String first = strs[0]; + String last = strs[strs.length - 1]; int index = 0; - while (index < shortest.length() && index < longest.length() && shortest.charAt(index) == longest.charAt(index)) { + while (index < first.length() && index < last.length() && first.charAt(index) == last.charAt(index)) { index++; } - return shortest.substring(0, index); + return first.substring(0, index); } } diff --git a/src/main/java/com/thealgorithms/strings/ReverseString.java b/src/main/java/com/thealgorithms/strings/ReverseString.java index 46a0494fcbb4..996aa68bb307 100644 --- a/src/main/java/com/thealgorithms/strings/ReverseString.java +++ b/src/main/java/com/thealgorithms/strings/ReverseString.java @@ -1,5 +1,7 @@ package com.thealgorithms.strings; +import java.util.Stack; + /** * Reverse String using different version */ @@ -36,4 +38,52 @@ public static String reverse2(String str) { } return new String(value); } + + /** + * Reverse version 3 the given string using a StringBuilder. + * This method converts the string to a character array, + * iterates through it in reverse order, and appends each character + * to a StringBuilder. + * + * @param string The input string to be reversed. + * @return The reversed string. + */ + public static String reverse3(String string) { + if (string.isEmpty()) { + return string; + } + char[] chars = string.toCharArray(); + StringBuilder sb = new StringBuilder(); + for (int i = string.length() - 1; i >= 0; i--) { + sb.append(chars[i]); + } + return sb.toString(); + } + /** + * Reverses the given string using a stack. + * This method uses a stack to reverse the characters of the string. + * * @param str The input string to be reversed. + * @return The reversed string. + */ + public static String reverseStringUsingStack(String str) { + // Check if the input string is null + if (str == null) { + throw new IllegalArgumentException("Input string cannot be null"); + } + Stack stack = new Stack<>(); + StringBuilder reversedString = new StringBuilder(); + // Check if the input string is empty + if (str.isEmpty()) { + return str; + } + // Push each character of the string onto the stack + for (char ch : str.toCharArray()) { + stack.push(ch); + } + // Pop each character from the stack and append to the StringBuilder + while (!stack.isEmpty()) { + reversedString.append(stack.pop()); + } + return reversedString.toString(); + } } diff --git a/src/main/java/com/thealgorithms/strings/Upper.java b/src/main/java/com/thealgorithms/strings/Upper.java index fa9a408416ea..5e248cb6ee39 100644 --- a/src/main/java/com/thealgorithms/strings/Upper.java +++ b/src/main/java/com/thealgorithms/strings/Upper.java @@ -21,15 +21,19 @@ public static void main(String[] args) { * @return the {@code String}, converted to uppercase. */ public static String toUpperCase(String s) { - if (s == null || s.isEmpty()) { + if (s == null) { + throw new IllegalArgumentException("Input string connot be null"); + } + if (s.isEmpty()) { return s; } - char[] values = s.toCharArray(); - for (int i = 0; i < values.length; ++i) { - if (Character.isLetter(values[i]) && Character.isLowerCase(values[i])) { - values[i] = Character.toUpperCase(values[i]); + StringBuilder result = new StringBuilder(s); + for (int i = 0; i < result.length(); ++i) { + char currentChar = result.charAt(i); + if (Character.isLetter(currentChar) && Character.isLowerCase(currentChar)) { + result.setCharAt(i, Character.toUpperCase(currentChar)); } } - return new String(values); + return result.toString(); } } diff --git a/src/main/java/com/thealgorithms/strings/ValidParentheses.java b/src/main/java/com/thealgorithms/strings/ValidParentheses.java index 629fee495d84..25a72f379dec 100644 --- a/src/main/java/com/thealgorithms/strings/ValidParentheses.java +++ b/src/main/java/com/thealgorithms/strings/ValidParentheses.java @@ -1,59 +1,53 @@ package com.thealgorithms.strings; -// Given a string s containing just the characters '(', ')', '{', '}', '[' and ']', determine -// if the input string is valid. An input string is valid if: Open brackets must be closed by -// the same type of brackets. Open brackets must be closed in the correct order. Every close -// bracket has a corresponding open bracket of the same type. +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Map; + +/** + * Validates if a given string has valid matching parentheses. + *

+ * A string is considered valid if: + *

    + *
  • Open brackets are closed by the same type of brackets.
  • + *
  • Brackets are closed in the correct order.
  • + *
  • Every closing bracket has a corresponding open bracket of the same type.
  • + *
+ * + * Allowed characters: '(', ')', '{', '}', '[', ']' + */ public final class ValidParentheses { private ValidParentheses() { } + + private static final Map BRACKET_PAIRS = Map.of(')', '(', '}', '{', ']', '['); + + /** + * Checks if the input string has valid parentheses. + * + * @param s the string containing only bracket characters + * @return true if valid, false otherwise + * @throws IllegalArgumentException if the string contains invalid characters or is null + */ public static boolean isValid(String s) { - char[] stack = new char[s.length()]; - int head = 0; + if (s == null) { + throw new IllegalArgumentException("Input string cannot be null"); + } + + Deque stack = new ArrayDeque<>(); + for (char c : s.toCharArray()) { - switch (c) { - case '{': - case '[': - case '(': - stack[head++] = c; - break; - case '}': - if (head == 0 || stack[--head] != '{') { - return false; - } - break; - case ')': - if (head == 0 || stack[--head] != '(') { - return false; - } - break; - case ']': - if (head == 0 || stack[--head] != '[') { + if (BRACKET_PAIRS.containsValue(c)) { + stack.push(c); // opening bracket + } else if (BRACKET_PAIRS.containsKey(c)) { + if (stack.isEmpty() || stack.pop() != BRACKET_PAIRS.get(c)) { return false; } - break; - default: - throw new IllegalArgumentException("Unexpected character: " + c); - } - } - return head == 0; - } - public static boolean isValidParentheses(String s) { - int i = -1; - char[] stack = new char[s.length()]; - String openBrackets = "({["; - String closeBrackets = ")}]"; - for (char ch : s.toCharArray()) { - if (openBrackets.indexOf(ch) != -1) { - stack[++i] = ch; } else { - if (i >= 0 && openBrackets.indexOf(stack[i]) == closeBrackets.indexOf(ch)) { - i--; - } else { - return false; - } + throw new IllegalArgumentException("Unexpected character: " + c); } } - return i == -1; + + return stack.isEmpty(); } } diff --git a/src/main/java/com/thealgorithms/strings/zigZagPattern/ZigZagPattern.java b/src/main/java/com/thealgorithms/strings/zigZagPattern/ZigZagPattern.java index 3f33fc17b9b0..ad7835bdbb97 100644 --- a/src/main/java/com/thealgorithms/strings/zigZagPattern/ZigZagPattern.java +++ b/src/main/java/com/thealgorithms/strings/zigZagPattern/ZigZagPattern.java @@ -1,41 +1,38 @@ package com.thealgorithms.strings.zigZagPattern; final class ZigZagPattern { + private ZigZagPattern() { } + /** + * Encodes a given string into a zig-zag pattern. + * + * @param s the input string to be encoded + * @param numRows the number of rows in the zigzag pattern + * @return the encoded string in zigzag pattern format + */ public static String encode(String s, int numRows) { if (numRows < 2 || s.length() < numRows) { return s; } - int start = 0; - int index = 0; - int height = 1; - int depth = numRows; - char[] zigZagedArray = new char[s.length()]; - while (depth != 0) { - int pointer = start; - int heightSpace = 2 + ((height - 2) * 2); - int depthSpace = 2 + ((depth - 2) * 2); - boolean bool = true; - while (pointer < s.length()) { - zigZagedArray[index++] = s.charAt(pointer); - if (heightSpace == 0) { - pointer += depthSpace; - } else if (depthSpace == 0) { - pointer += heightSpace; - } else if (bool) { - pointer += depthSpace; - bool = false; - } else { - pointer += heightSpace; - bool = true; + + StringBuilder result = new StringBuilder(s.length()); + int cycleLength = 2 * numRows - 2; + + for (int row = 0; row < numRows; row++) { + for (int j = row; j < s.length(); j += cycleLength) { + result.append(s.charAt(j)); + + if (row > 0 && row < numRows - 1) { + int diagonal = j + cycleLength - 2 * row; + if (diagonal < s.length()) { + result.append(s.charAt(diagonal)); + } } } - height++; - depth--; - start++; } - return new String(zigZagedArray); + + return result.toString(); } } diff --git a/src/main/java/com/thealgorithms/tree/HeavyLightDecomposition.java b/src/main/java/com/thealgorithms/tree/HeavyLightDecomposition.java new file mode 100644 index 000000000000..236a23205180 --- /dev/null +++ b/src/main/java/com/thealgorithms/tree/HeavyLightDecomposition.java @@ -0,0 +1,157 @@ +package com.thealgorithms.tree; + +import java.util.ArrayList; +import java.util.List; + +/** + * Heavy-Light Decomposition (HLD) implementation in Java. + * HLD is used to efficiently handle path queries on trees, such as maximum, + * sum, or updates. It decomposes the tree into heavy and light chains, + * enabling queries in O(log N) time. + * Wikipedia Reference: https://en.wikipedia.org/wiki/Heavy-light_decomposition + * Author: Nithin U. + * Github: https://github.com/NithinU2802 + */ + +public class HeavyLightDecomposition { + private List> tree; + private int[] parent; + private int[] depth; + private int[] subtreeSize; + private int[] chainHead; + private int[] position; + private int[] nodeValue; + private int[] segmentTree; + private int positionIndex; + + public HeavyLightDecomposition(int n) { + tree = new ArrayList<>(); + for (int i = 0; i <= n; i++) { + tree.add(new ArrayList<>()); + } + parent = new int[n + 1]; + depth = new int[n + 1]; + subtreeSize = new int[n + 1]; + chainHead = new int[n + 1]; + position = new int[n + 1]; + nodeValue = new int[n + 1]; + segmentTree = new int[4 * (n + 1)]; + for (int i = 0; i <= n; i++) { + chainHead[i] = -1; + } + positionIndex = 0; + } + + public int getPosition(int index) { + return position[index]; + } + + public int getPositionIndex() { + return positionIndex; + } + + public void addEdge(int u, int v) { + tree.get(u).add(v); + tree.get(v).add(u); + } + + private void dfsSize(int node, int parentNode) { + parent[node] = parentNode; + subtreeSize[node] = 1; + for (int child : tree.get(node)) { + if (child != parentNode) { + depth[child] = depth[node] + 1; + dfsSize(child, node); + subtreeSize[node] += subtreeSize[child]; + } + } + } + + private void decompose(int node, int head) { + chainHead[node] = head; + position[node] = positionIndex++; + int heavyChild = -1; + int maxSubtreeSize = -1; + for (int child : tree.get(node)) { + if (child != parent[node] && subtreeSize[child] > maxSubtreeSize) { + heavyChild = child; + maxSubtreeSize = subtreeSize[child]; + } + } + if (heavyChild != -1) { + decompose(heavyChild, head); + } + for (int child : tree.get(node)) { + if (child != parent[node] && child != heavyChild) { + decompose(child, child); + } + } + } + + private void buildSegmentTree(int node, int start, int end) { + if (start == end) { + segmentTree[node] = nodeValue[start]; + return; + } + int mid = (start + end) / 2; + buildSegmentTree(2 * node, start, mid); + buildSegmentTree(2 * node + 1, mid + 1, end); + segmentTree[node] = Math.max(segmentTree[2 * node], segmentTree[2 * node + 1]); + } + + public void updateSegmentTree(int node, int start, int end, int index, int value) { + if (start == end) { + segmentTree[node] = value; + return; + } + int mid = (start + end) / 2; + if (index <= mid) { + updateSegmentTree(2 * node, start, mid, index, value); + } else { + updateSegmentTree(2 * node + 1, mid + 1, end, index, value); + } + segmentTree[node] = Math.max(segmentTree[2 * node], segmentTree[2 * node + 1]); + } + + public int querySegmentTree(int node, int start, int end, int left, int right) { + if (left > end || right < start) { + return Integer.MIN_VALUE; + } + if (left <= start && end <= right) { + return segmentTree[node]; + } + int mid = (start + end) / 2; + int leftQuery = querySegmentTree(2 * node, start, mid, left, right); + int rightQuery = querySegmentTree(2 * node + 1, mid + 1, end, left, right); + return Math.max(leftQuery, rightQuery); + } + + public int queryMaxInPath(int u, int v) { + int result = Integer.MIN_VALUE; + while (chainHead[u] != chainHead[v]) { + if (depth[chainHead[u]] < depth[chainHead[v]]) { + int temp = u; + u = v; + v = temp; + } + result = Math.max(result, querySegmentTree(1, 0, positionIndex - 1, position[chainHead[u]], position[u])); + u = parent[chainHead[u]]; + } + if (depth[u] > depth[v]) { + int temp = u; + u = v; + v = temp; + } + result = Math.max(result, querySegmentTree(1, 0, positionIndex - 1, position[u], position[v])); + return result; + } + + public void initialize(int root, int[] values) { + dfsSize(root, -1); + decompose(root, root); + for (int i = 0; i < values.length; i++) { + nodeValue[position[i]] = values[i]; + } + buildSegmentTree(1, 0, positionIndex - 1); + } +} diff --git a/src/test/java/com/thealgorithms/bitmanipulation/BitSwapTest.java b/src/test/java/com/thealgorithms/bitmanipulation/BitSwapTest.java index 40de770e0c66..9d888d056453 100644 --- a/src/test/java/com/thealgorithms/bitmanipulation/BitSwapTest.java +++ b/src/test/java/com/thealgorithms/bitmanipulation/BitSwapTest.java @@ -1,13 +1,62 @@ package com.thealgorithms.bitmanipulation; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; -import org.junit.jupiter.api.Test; -public class BitSwapTest { - @Test - void testHighestSetBit() { - assertEquals(3, BitSwap.bitSwap(3, 0, 1)); - assertEquals(5, BitSwap.bitSwap(6, 0, 1)); - assertEquals(7, BitSwap.bitSwap(7, 1, 1)); +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class BitSwapTest { + + @ParameterizedTest(name = "Additional cases: data={0}, posA={1}, posB={2} -> expected={3}") + @MethodSource("provideAdditionalCases") + void testAdditionalCases(int data, int posA, int posB, int expected) { + assertEquals(expected, BitSwap.bitSwap(data, posA, posB)); + } + + @ParameterizedTest(name = "Swap different bits: data={0}, posA={1}, posB={2} -> expected={3}") + @MethodSource("provideDifferentBitsCases") + void swapDifferentBits(int data, int posA, int posB, int expected) { + assertEquals(expected, BitSwap.bitSwap(data, posA, posB)); + } + + @ParameterizedTest(name = "Swap same bits: data={0}, posA={1}, posB={2} should not change") + @MethodSource("provideSameBitsCases") + void swapSameBits(int data, int posA, int posB) { + assertEquals(data, BitSwap.bitSwap(data, posA, posB)); + } + + @ParameterizedTest(name = "Edge cases: data={0}, posA={1}, posB={2} -> expected={3}") + @MethodSource("provideEdgeCases") + void testEdgeCases(int data, int posA, int posB, int expected) { + assertEquals(expected, BitSwap.bitSwap(data, posA, posB)); + } + + @ParameterizedTest(name = "Invalid positions: data={0}, posA={1}, posB={2} should throw") + @MethodSource("provideInvalidPositions") + void invalidPositionThrowsException(int data, int posA, int posB) { + assertThrows(IllegalArgumentException.class, () -> BitSwap.bitSwap(data, posA, posB)); + } + + static Stream provideAdditionalCases() { + return Stream.of(Arguments.of(3, 0, 1, 3), Arguments.of(6, 0, 1, 5), Arguments.of(7, 1, 1, 7)); + } + + static Stream provideDifferentBitsCases() { + return Stream.of(Arguments.of(0b01, 0, 1, 0b10)); + } + + static Stream provideSameBitsCases() { + return Stream.of(Arguments.of(0b111, 0, 2), Arguments.of(0b0, 1, 3), Arguments.of(0b1010, 1, 3), Arguments.of(-1, 5, 5)); + } + + static Stream provideEdgeCases() { + return Stream.of(Arguments.of(Integer.MIN_VALUE, 31, 0, 1), Arguments.of(0, 0, 31, 0)); + } + + static Stream provideInvalidPositions() { + return Stream.of(Arguments.of(0, -1, 0), Arguments.of(0, 0, 32), Arguments.of(0, -5, 33), Arguments.of(0, Integer.MIN_VALUE, Integer.MAX_VALUE)); } } diff --git a/src/test/java/com/thealgorithms/bitmanipulation/OnesComplementTest.java b/src/test/java/com/thealgorithms/bitmanipulation/OnesComplementTest.java index 6be4eb595f79..0e90ed79f587 100644 --- a/src/test/java/com/thealgorithms/bitmanipulation/OnesComplementTest.java +++ b/src/test/java/com/thealgorithms/bitmanipulation/OnesComplementTest.java @@ -1,8 +1,12 @@ package com.thealgorithms.bitmanipulation; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; /** * Test case for Highest Set Bit @@ -39,9 +43,16 @@ public void testOnesComplementMixedBits() { assertEquals("1001", OnesComplement.onesComplement("0110")); } + @ParameterizedTest + @NullAndEmptySource + public void testOnesComplementNullOrEmptyInputThrowsException(String input) { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> OnesComplement.onesComplement(input)); + assertEquals("Input must be a non-empty binary string.", exception.getMessage()); + } + @Test - public void testOnesComplementEmptyString() { - // Test empty string scenario - assertEquals("", OnesComplement.onesComplement("")); + public void testOnesComplementInvalidCharactersThrowsException() { + Exception exception = assertThrows(IllegalArgumentException.class, () -> OnesComplement.onesComplement("10a1")); + assertTrue(exception.getMessage().startsWith("Input must contain only '0' and '1'")); } } diff --git a/src/test/java/com/thealgorithms/bitmanipulation/ParityCheckTest.java b/src/test/java/com/thealgorithms/bitmanipulation/ParityCheckTest.java index 90147a61207b..1654c8ddfc1e 100644 --- a/src/test/java/com/thealgorithms/bitmanipulation/ParityCheckTest.java +++ b/src/test/java/com/thealgorithms/bitmanipulation/ParityCheckTest.java @@ -6,10 +6,30 @@ import org.junit.jupiter.api.Test; public class ParityCheckTest { + @Test + public void testIsEvenParity() { + assertTrue(ParityCheck.checkParity(0)); // 0 -> 0 ones + assertTrue(ParityCheck.checkParity(3)); // 11 -> 2 ones + assertTrue(ParityCheck.checkParity(5)); // 101 -> 2 ones + assertTrue(ParityCheck.checkParity(10)); // 1010 -> 2 ones + assertTrue(ParityCheck.checkParity(15)); // 1111 -> 4 ones + assertTrue(ParityCheck.checkParity(1023)); // 10 ones + } + @Test public void testIsOddParity() { - assertTrue(ParityCheck.checkParity(5)); // 101 has 2 ones (even parity) - assertFalse(ParityCheck.checkParity(7)); // 111 has 3 ones (odd parity) - assertFalse(ParityCheck.checkParity(8)); // 1000 has 1 one (odd parity) + assertFalse(ParityCheck.checkParity(1)); // 1 -> 1 one + assertFalse(ParityCheck.checkParity(2)); // 10 -> 1 one + assertFalse(ParityCheck.checkParity(7)); // 111 -> 3 ones + assertFalse(ParityCheck.checkParity(8)); // 1000 -> 1 one + assertFalse(ParityCheck.checkParity(11)); // 1011 -> 3 ones + assertFalse(ParityCheck.checkParity(31)); // 11111 -> 5 ones + } + + @Test + public void testLargeNumbers() { + assertTrue(ParityCheck.checkParity(0b10101010)); // 4 ones + assertFalse(ParityCheck.checkParity(0b100000000)); // 1 one + assertTrue(ParityCheck.checkParity(0xAAAAAAAA)); // Alternating bits, 16 ones } } diff --git a/src/test/java/com/thealgorithms/conversions/NumberToWordsTest.java b/src/test/java/com/thealgorithms/conversions/NumberToWordsTest.java new file mode 100644 index 000000000000..7b264678daa4 --- /dev/null +++ b/src/test/java/com/thealgorithms/conversions/NumberToWordsTest.java @@ -0,0 +1,60 @@ +package com.thealgorithms.conversions; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.math.BigDecimal; +import org.junit.jupiter.api.Test; + +public class NumberToWordsTest { + + @Test + void testNullInput() { + assertEquals("Invalid Input", NumberToWords.convert(null), "Null input should return 'Invalid Input'"); + } + + @Test + void testZeroInput() { + assertEquals("Zero", NumberToWords.convert(BigDecimal.ZERO), "Zero input should return 'Zero'"); + } + + @Test + void testPositiveWholeNumbers() { + assertEquals("One", NumberToWords.convert(BigDecimal.ONE), "1 should convert to 'One'"); + assertEquals("One Thousand", NumberToWords.convert(new BigDecimal("1000")), "1000 should convert to 'One Thousand'"); + assertEquals("One Million", NumberToWords.convert(new BigDecimal("1000000")), "1000000 should convert to 'One Million'"); + } + + @Test + void testNegativeWholeNumbers() { + assertEquals("Negative One", NumberToWords.convert(new BigDecimal("-1")), "-1 should convert to 'Negative One'"); + assertEquals("Negative One Thousand", NumberToWords.convert(new BigDecimal("-1000")), "-1000 should convert to 'Negative One Thousand'"); + } + + @Test + void testFractionalNumbers() { + assertEquals("Zero Point One Two Three", NumberToWords.convert(new BigDecimal("0.123")), "0.123 should convert to 'Zero Point One Two Three'"); + assertEquals("Negative Zero Point Four Five Six", NumberToWords.convert(new BigDecimal("-0.456")), "-0.456 should convert to 'Negative Zero Point Four Five Six'"); + } + + @Test + void testLargeNumbers() { + assertEquals("Nine Hundred Ninety Nine Million Nine Hundred Ninety Nine Thousand Nine Hundred Ninety Nine", NumberToWords.convert(new BigDecimal("999999999")), "999999999 should convert correctly"); + assertEquals("One Trillion", NumberToWords.convert(new BigDecimal("1000000000000")), "1000000000000 should convert to 'One Trillion'"); + } + + @Test + void testNegativeLargeNumbers() { + assertEquals("Negative Nine Trillion Eight Hundred Seventy Six Billion Five Hundred Forty Three Million Two Hundred Ten Thousand Nine Hundred Eighty Seven", NumberToWords.convert(new BigDecimal("-9876543210987")), "-9876543210987 should convert correctly"); + } + + @Test + void testFloatingPointPrecision() { + assertEquals("One Million Point Zero Zero One", NumberToWords.convert(new BigDecimal("1000000.001")), "1000000.001 should convert to 'One Million Point Zero Zero One'"); + } + + @Test + void testEdgeCases() { + assertEquals("Zero", NumberToWords.convert(new BigDecimal("-0.0")), "-0.0 should convert to 'Zero'"); + assertEquals("Zero Point Zero Zero Zero Zero Zero Zero One", NumberToWords.convert(new BigDecimal("1E-7")), "1E-7 should convert to 'Zero Point Zero Zero Zero Zero Zero Zero One'"); + } +} diff --git a/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java b/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java new file mode 100644 index 000000000000..fbf63e37946b --- /dev/null +++ b/src/test/java/com/thealgorithms/conversions/WordsToNumberTest.java @@ -0,0 +1,114 @@ +package com.thealgorithms.conversions; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.math.BigDecimal; +import org.junit.jupiter.api.Test; + +public class WordsToNumberTest { + + @Test + void testNullInput() { + WordsToNumberException exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert(null)); + assertEquals(WordsToNumberException.ErrorType.NULL_INPUT, exception.getErrorType(), "Exception should be of type NULL_INPUT"); + } + + @Test + void testStandardCases() { + assertEquals("0", WordsToNumber.convert("zero"), "'zero' should convert to '0'"); + assertEquals("5", WordsToNumber.convert("five"), "'five' should convert to '5'"); + assertEquals("21", WordsToNumber.convert("twenty one"), "'twenty one' should convert to '21'"); + assertEquals("101", WordsToNumber.convert("one hundred one"), "'one hundred' should convert to '101'"); + assertEquals("342", WordsToNumber.convert("three hundred and forty two"), "'three hundred and forty two' should convert to '342'"); + } + + @Test + void testLargeNumbers() { + assertEquals("1000000", WordsToNumber.convert("one million"), "'one million' should convert to '1000000'"); + assertEquals("1000000000", WordsToNumber.convert("one billion"), "'one billion' should convert to '1000000000'"); + assertEquals("1000000000000", WordsToNumber.convert("one trillion"), "'one trillion' should convert to '1000000000000'"); + assertEquals("999000000900999", WordsToNumber.convert("nine hundred ninety nine trillion nine hundred thousand nine hundred and ninety nine"), "'nine hundred ninety nine trillion nine hundred thousand nine hundred and ninety nine' should convert to '999000000900999'"); + } + + @Test + void testNegativeNumbers() { + assertEquals("-5", WordsToNumber.convert("negative five"), "'negative five' should convert to '-5'"); + assertEquals("-120", WordsToNumber.convert("negative one hundred and twenty"), "'negative one hundred and twenty' should convert correctly"); + } + + @Test + void testNegativeLargeNumbers() { + assertEquals("-1000000000000", WordsToNumber.convert("negative one trillion"), "'negative one trillion' should convert to '-1000000000000'"); + assertEquals("-9876543210987", WordsToNumber.convert("Negative Nine Trillion Eight Hundred Seventy Six Billion Five Hundred Forty Three Million Two Hundred Ten Thousand Nine Hundred Eighty Seven"), ""); + } + + @Test + void testDecimalNumbers() { + assertEquals("3.1415", WordsToNumber.convert("three point one four one five"), "'three point one four one five' should convert to '3.1415'"); + assertEquals("-2.718", WordsToNumber.convert("negative two point seven one eight"), "'negative two point seven one eight' should convert to '-2.718'"); + assertEquals("-1E-7", WordsToNumber.convert("negative zero point zero zero zero zero zero zero one"), "'negative zero point zero zero zero zero zero zero one' should convert to '-1E-7'"); + } + + @Test + void testLargeDecimalNumbers() { + assertEquals("1000000000.0000000001", WordsToNumber.convert("one billion point zero zero zero zero zero zero zero zero zero one"), "Tests a large whole number with a tiny fractional part"); + assertEquals("999999999999999.9999999999999", + WordsToNumber.convert("nine hundred ninety nine trillion nine hundred ninety nine billion nine hundred ninety nine million nine hundred ninety nine thousand nine hundred ninety nine point nine nine nine nine nine nine nine nine nine nine nine nine nine"), + "Tests maximum scale handling for large decimal numbers"); + assertEquals("0.505", WordsToNumber.convert("zero point five zero five"), "Tests a decimal with an internal zero, ensuring correct parsing"); + assertEquals("42.00000000000001", WordsToNumber.convert("forty two point zero zero zero zero zero zero zero zero zero zero zero zero zero one"), "Tests a decimal with leading zeros before a significant figure"); + assertEquals("7.89E-7", WordsToNumber.convert("zero point zero zero zero zero zero zero seven eight nine"), "Tests scientific notation for a small decimal with multiple digits"); + assertEquals("0.999999", WordsToNumber.convert("zero point nine nine nine nine nine nine"), "Tests a decimal close to one with multiple repeated digits"); + } + + @Test + void testCaseInsensitivity() { + assertEquals("21", WordsToNumber.convert("TWENTY-ONE"), "Uppercase should still convert correctly"); + assertEquals("-100.0001", WordsToNumber.convert("negAtiVe OnE HuNdReD, point ZeRO Zero zERo ONE"), "Mixed case should still convert correctly"); + assertEquals("-225647.00019", WordsToNumber.convert("nEgative twO HundRed, and twenty-Five thOusaNd, six huNdred Forty-Seven, Point zero zero zero One nInE")); + } + + @Test + void testInvalidInputs() { + WordsToNumberException exception; + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("negative one hundred AlPha")); + assertEquals(WordsToNumberException.ErrorType.UNKNOWN_WORD, exception.getErrorType()); + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("twenty thirteen")); + assertEquals(WordsToNumberException.ErrorType.UNEXPECTED_WORD, exception.getErrorType()); + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("negative negative ten")); + assertEquals(WordsToNumberException.ErrorType.MULTIPLE_NEGATIVES, exception.getErrorType()); + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("one hundred hundred")); + assertEquals(WordsToNumberException.ErrorType.UNEXPECTED_WORD, exception.getErrorType()); + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("one thousand and hundred")); + assertEquals(WordsToNumberException.ErrorType.INVALID_CONJUNCTION, exception.getErrorType()); + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("one thousand hundred")); + assertEquals(WordsToNumberException.ErrorType.UNEXPECTED_WORD, exception.getErrorType()); + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("nine hundred and nine hundred")); + assertEquals(WordsToNumberException.ErrorType.INVALID_CONJUNCTION, exception.getErrorType()); + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("forty two point")); + assertEquals(WordsToNumberException.ErrorType.MISSING_DECIMAL_NUMBERS, exception.getErrorType()); + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("sixty seven point hello")); + assertEquals(WordsToNumberException.ErrorType.UNEXPECTED_WORD_AFTER_POINT, exception.getErrorType()); + + exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convert("one negative")); + assertEquals(WordsToNumberException.ErrorType.INVALID_NEGATIVE, exception.getErrorType()); + } + + @Test + void testConvertToBigDecimal() { + assertEquals(new BigDecimal("-100000000000000.056"), WordsToNumber.convertToBigDecimal("negative one hundred trillion point zero five six"), "should convert to appropriate BigDecimal value"); + + WordsToNumberException exception = assertThrows(WordsToNumberException.class, () -> WordsToNumber.convertToBigDecimal(null)); + assertEquals(WordsToNumberException.ErrorType.NULL_INPUT, exception.getErrorType(), "Exception should be of type NULL_INPUT"); + } +} diff --git a/src/test/java/com/thealgorithms/datastructures/bag/BagTest.java b/src/test/java/com/thealgorithms/datastructures/bag/BagTest.java index b7e64851383c..8212793dfb79 100644 --- a/src/test/java/com/thealgorithms/datastructures/bag/BagTest.java +++ b/src/test/java/com/thealgorithms/datastructures/bag/BagTest.java @@ -6,7 +6,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import com.thealgorithms.datastructures.bags.Bag; +import java.util.ArrayList; import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; import org.junit.jupiter.api.Test; class BagTest { @@ -156,4 +159,116 @@ void testIteratorWithDuplicates() { } assertEquals(3, count, "Iterator should traverse all 3 items including duplicates"); } + + @Test + void testCollectionElements() { + Bag> bag = new Bag<>(); + List list1 = new ArrayList<>(); + list1.add("a"); + list1.add("b"); + + List list2 = new ArrayList<>(); + list2.add("c"); + + List emptyList = new ArrayList<>(); + + bag.add(list1); + bag.add(list2); + bag.add(emptyList); + bag.add(list1); // Duplicate + + assertEquals(4, bag.size(), "Bag should contain 4 list elements"); + assertTrue(bag.contains(list1), "Bag should contain list1"); + assertTrue(bag.contains(list2), "Bag should contain list2"); + assertTrue(bag.contains(emptyList), "Bag should contain empty list"); + } + + @Test + void testIteratorConsistency() { + Bag bag = new Bag<>(); + bag.add("first"); + bag.add("second"); + bag.add("third"); + + // Multiple iterations should return same elements + List firstIteration = new ArrayList<>(); + for (String item : bag) { + firstIteration.add(item); + } + + List secondIteration = new ArrayList<>(); + for (String item : bag) { + secondIteration.add(item); + } + + assertEquals(firstIteration.size(), secondIteration.size(), "Both iterations should have same size"); + assertEquals(3, firstIteration.size(), "First iteration should have 3 elements"); + assertEquals(3, secondIteration.size(), "Second iteration should have 3 elements"); + } + + @Test + void testMultipleIterators() { + Bag bag = new Bag<>(); + bag.add("item1"); + bag.add("item2"); + + Iterator iter1 = bag.iterator(); + Iterator iter2 = bag.iterator(); + + assertTrue(iter1.hasNext(), "First iterator should have next element"); + assertTrue(iter2.hasNext(), "Second iterator should have next element"); + + String first1 = iter1.next(); + String first2 = iter2.next(); + + org.junit.jupiter.api.Assertions.assertNotNull(first1, "First iterator should return non-null element"); + org.junit.jupiter.api.Assertions.assertNotNull(first2, "Second iterator should return non-null element"); + } + + @Test + void testIteratorHasNextConsistency() { + Bag bag = new Bag<>(); + bag.add("single"); + + Iterator iter = bag.iterator(); + assertTrue(iter.hasNext(), "hasNext should return true"); + assertTrue(iter.hasNext(), "hasNext should still return true after multiple calls"); + + String item = iter.next(); + assertEquals("single", item, "Next should return the single item"); + + assertFalse(iter.hasNext(), "hasNext should return false after consuming element"); + assertFalse(iter.hasNext(), "hasNext should still return false"); + } + + @Test + void testIteratorNextOnEmptyBag() { + Bag bag = new Bag<>(); + Iterator iter = bag.iterator(); + + assertFalse(iter.hasNext(), "hasNext should return false for empty bag"); + assertThrows(NoSuchElementException.class, iter::next, "next() should throw NoSuchElementException on empty bag"); + } + + @Test + void testBagOrderIndependence() { + Bag bag1 = new Bag<>(); + Bag bag2 = new Bag<>(); + + // Add same elements in different order + bag1.add("first"); + bag1.add("second"); + bag1.add("third"); + + bag2.add("third"); + bag2.add("first"); + bag2.add("second"); + + assertEquals(bag1.size(), bag2.size(), "Bags should have same size"); + + // Both bags should contain all elements + assertTrue(bag1.contains("first") && bag2.contains("first")); + assertTrue(bag1.contains("second") && bag2.contains("second")); + assertTrue(bag1.contains("third") && bag2.contains("third")); + } } diff --git a/src/test/java/com/thealgorithms/datastructures/bloomfilter/BloomFilterTest.java b/src/test/java/com/thealgorithms/datastructures/bloomfilter/BloomFilterTest.java index 048eb7e481a7..9e1ba88adaee 100644 --- a/src/test/java/com/thealgorithms/datastructures/bloomfilter/BloomFilterTest.java +++ b/src/test/java/com/thealgorithms/datastructures/bloomfilter/BloomFilterTest.java @@ -1,5 +1,12 @@ package com.thealgorithms.datastructures.bloomfilter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -113,4 +120,140 @@ void testBoundaryConditions() { Assertions.assertTrue(filter.contains("d"), "Filter should contain 'd'"); Assertions.assertFalse(filter.contains("e"), "Filter should not contain 'e' which was not inserted"); } + + @Test + void testLongDataType() { + BloomFilter filter = new BloomFilter<>(5, 1000); + Long[] values = {Long.MIN_VALUE, Long.MAX_VALUE}; + + for (Long value : values) { + filter.insert(value); + } + + for (Long value : values) { + Assertions.assertTrue(filter.contains(value), "Filter should contain " + value); + } + } + + @Test + void testFloatDataType() { + BloomFilter filter = new BloomFilter<>(3, 200); + Float[] values = {1.5f, -3.7f, 0.0f, Float.MAX_VALUE, Float.MIN_VALUE}; + + for (Float value : values) { + filter.insert(value); + } + + for (Float value : values) { + Assertions.assertTrue(filter.contains(value), "Filter should contain " + value); + } + + Assertions.assertFalse(filter.contains(88.88f), "Filter should not contain uninserted value"); + } + + @Test + void testBooleanDataType() { + BloomFilter filter = new BloomFilter<>(2, 50); + filter.insert(Boolean.TRUE); + filter.insert(Boolean.FALSE); + + Assertions.assertTrue(filter.contains(Boolean.TRUE), "Filter should contain true"); + Assertions.assertTrue(filter.contains(Boolean.FALSE), "Filter should contain false"); + } + + @Test + void testListDataType() { + BloomFilter> filter = new BloomFilter<>(4, 200); + List list1 = Arrays.asList("apple", "banana"); + List list2 = Arrays.asList("cat", "dog"); + List emptyList = new ArrayList<>(); + + filter.insert(list1); + filter.insert(list2); + filter.insert(emptyList); + + Assertions.assertTrue(filter.contains(list1), "Filter should contain list1"); + Assertions.assertTrue(filter.contains(list2), "Filter should contain list2"); + Assertions.assertTrue(filter.contains(emptyList), "Filter should contain empty list"); + Assertions.assertFalse(filter.contains(Arrays.asList("elephant", "tiger")), "Filter should not contain uninserted list"); + } + + @Test + void testMapDataType() { + BloomFilter> filter = new BloomFilter<>(3, 150); + Map map1 = new HashMap<>(); + map1.put("key1", 1); + map1.put("key2", 2); + + Map map2 = new HashMap<>(); + map2.put("key3", 3); + + Map emptyMap = new HashMap<>(); + + filter.insert(map1); + filter.insert(map2); + filter.insert(emptyMap); + + Assertions.assertTrue(filter.contains(map1), "Filter should contain map1"); + Assertions.assertTrue(filter.contains(map2), "Filter should contain map2"); + Assertions.assertTrue(filter.contains(emptyMap), "Filter should contain empty map"); + } + + @Test + void testSetDataType() { + BloomFilter> filter = new BloomFilter<>(3, 100); + Set set1 = new HashSet<>(Arrays.asList(1, 2, 3)); + Set set2 = new HashSet<>(Arrays.asList(4, 5)); + Set emptySet = new HashSet<>(); + + filter.insert(set1); + filter.insert(set2); + filter.insert(emptySet); + + Assertions.assertTrue(filter.contains(set1), "Filter should contain set1"); + Assertions.assertTrue(filter.contains(set2), "Filter should contain set2"); + Assertions.assertTrue(filter.contains(emptySet), "Filter should contain empty set"); + Assertions.assertFalse(filter.contains(new HashSet<>(Arrays.asList(6, 7, 8))), "Filter should not contain uninserted set"); + } + + @Test + void testArrayDataType() { + BloomFilter filter = new BloomFilter<>(3, 100); + int[] array1 = {1, 2, 3}; + int[] array2 = {4, 5}; + int[] emptyArray = {}; + + filter.insert(array1); + filter.insert(array2); + filter.insert(emptyArray); + + Assertions.assertTrue(filter.contains(array1), "Filter should contain array1"); + Assertions.assertTrue(filter.contains(array2), "Filter should contain array2"); + Assertions.assertTrue(filter.contains(emptyArray), "Filter should contain empty array"); + Assertions.assertFalse(filter.contains(new int[] {6, 7, 8}), "Filter should not contain different array"); + } + + @Test + void testSpecialFloatingPointValues() { + BloomFilter filter = new BloomFilter<>(3, 100); + Double[] specialValues = {Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, -0.0, 0.0}; + + for (Double value : specialValues) { + filter.insert(value); + } + + for (Double value : specialValues) { + Assertions.assertTrue(filter.contains(value), "Filter should contain " + value); + } + } + + @Test + void testVerySmallBloomFilter() { + BloomFilter smallFilter = new BloomFilter<>(1, 5); + smallFilter.insert("test1"); + smallFilter.insert("test2"); + + Assertions.assertTrue(smallFilter.contains("test1")); + Assertions.assertTrue(smallFilter.contains("test2")); + } } diff --git a/src/test/java/com/thealgorithms/datastructures/buffers/CircularBufferTest.java b/src/test/java/com/thealgorithms/datastructures/buffers/CircularBufferTest.java index b115fc187b1a..69af422e7175 100644 --- a/src/test/java/com/thealgorithms/datastructures/buffers/CircularBufferTest.java +++ b/src/test/java/com/thealgorithms/datastructures/buffers/CircularBufferTest.java @@ -2,7 +2,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; @@ -68,11 +67,11 @@ void testFullBuffer() { @Test void testIllegalArguments() { - assertThrows(IllegalArgumentException.class, () -> new CircularBuffer<>(0)); - assertThrows(IllegalArgumentException.class, () -> new CircularBuffer<>(-1)); + org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, () -> new CircularBuffer<>(0)); + org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, () -> new CircularBuffer<>(-1)); CircularBuffer buffer = new CircularBuffer<>(1); - assertThrows(IllegalArgumentException.class, () -> buffer.put(null)); + org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, () -> buffer.put(null)); } @Test @@ -85,4 +84,149 @@ void testLargeBuffer() { buffer.put(1000); // This should overwrite 0 assertEquals(1, buffer.get()); } + + @Test + void testPutAfterGet() { + CircularBuffer buffer = new CircularBuffer<>(2); + buffer.put(10); + buffer.put(20); + assertEquals(10, buffer.get()); + buffer.put(30); + assertEquals(20, buffer.get()); + assertEquals(30, buffer.get()); + assertNull(buffer.get()); + } + + @Test + void testMultipleWrapArounds() { + CircularBuffer buffer = new CircularBuffer<>(3); + for (int i = 1; i <= 6; i++) { + buffer.put(i); + buffer.get(); // add and immediately remove + } + assertTrue(buffer.isEmpty()); + assertNull(buffer.get()); + } + + @Test + void testOverwriteMultipleTimes() { + CircularBuffer buffer = new CircularBuffer<>(2); + buffer.put("X"); + buffer.put("Y"); + buffer.put("Z"); // overwrites "X" + buffer.put("W"); // overwrites "Y" + assertEquals("Z", buffer.get()); + assertEquals("W", buffer.get()); + assertNull(buffer.get()); + } + + @Test + void testIsEmptyAndIsFullTransitions() { + CircularBuffer buffer = new CircularBuffer<>(2); + assertTrue(buffer.isEmpty()); + org.junit.jupiter.api.Assertions.assertFalse(buffer.isFull()); + + buffer.put(1); + org.junit.jupiter.api.Assertions.assertFalse(buffer.isEmpty()); + org.junit.jupiter.api.Assertions.assertFalse(buffer.isFull()); + + buffer.put(2); + assertTrue(buffer.isFull()); + + buffer.get(); + org.junit.jupiter.api.Assertions.assertFalse(buffer.isFull()); + + buffer.get(); + assertTrue(buffer.isEmpty()); + } + + @Test + void testInterleavedPutAndGet() { + CircularBuffer buffer = new CircularBuffer<>(3); + buffer.put("A"); + buffer.put("B"); + assertEquals("A", buffer.get()); + buffer.put("C"); + assertEquals("B", buffer.get()); + assertEquals("C", buffer.get()); + assertNull(buffer.get()); + } + + @Test + void testRepeatedNullInsertionThrows() { + CircularBuffer buffer = new CircularBuffer<>(5); + for (int i = 0; i < 3; i++) { + int finalI = i; + org.junit.jupiter.api.Assertions.assertThrows(IllegalArgumentException.class, () -> buffer.put(null), "Iteration: " + finalI); + } + } + @Test + void testFillThenEmptyThenReuseBuffer() { + CircularBuffer buffer = new CircularBuffer<>(3); + + buffer.put(1); + buffer.put(2); + buffer.put(3); + assertTrue(buffer.isFull()); + + assertEquals(1, buffer.get()); + assertEquals(2, buffer.get()); + assertEquals(3, buffer.get()); + + assertTrue(buffer.isEmpty()); + + buffer.put(4); + buffer.put(5); + assertEquals(4, buffer.get()); + assertEquals(5, buffer.get()); + assertTrue(buffer.isEmpty()); + } + + @Test + void testPutReturnsTrueOnlyIfPreviouslyEmpty() { + CircularBuffer buffer = new CircularBuffer<>(2); + + assertTrue(buffer.put("one")); // was empty + org.junit.jupiter.api.Assertions.assertFalse(buffer.put("two")); // not empty + org.junit.jupiter.api.Assertions.assertFalse(buffer.put("three")); // overwrite + } + + @Test + void testOverwriteAndGetAllElementsCorrectly() { + CircularBuffer buffer = new CircularBuffer<>(3); + + buffer.put(1); + buffer.put(2); + buffer.put(3); + buffer.put(4); // Overwrites 1 + buffer.put(5); // Overwrites 2 + + assertEquals(3, buffer.get()); + assertEquals(4, buffer.get()); + assertEquals(5, buffer.get()); + assertNull(buffer.get()); + } + + @Test + void testBufferWithOneElementCapacity() { + CircularBuffer buffer = new CircularBuffer<>(1); + + assertTrue(buffer.put("first")); + assertEquals("first", buffer.get()); + assertNull(buffer.get()); + + assertTrue(buffer.put("second")); + assertEquals("second", buffer.get()); + } + + @Test + void testPointerWraparoundWithExactMultipleOfCapacity() { + CircularBuffer buffer = new CircularBuffer<>(3); + for (int i = 0; i < 6; i++) { + buffer.put(i); + buffer.get(); // keep buffer size at 0 + } + assertTrue(buffer.isEmpty()); + assertNull(buffer.get()); + } } diff --git a/src/test/java/com/thealgorithms/datastructures/caches/FIFOCacheTest.java b/src/test/java/com/thealgorithms/datastructures/caches/FIFOCacheTest.java new file mode 100644 index 000000000000..5f250e6ca3fd --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/caches/FIFOCacheTest.java @@ -0,0 +1,330 @@ +package com.thealgorithms.datastructures.caches; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; + +class FIFOCacheTest { + private FIFOCache cache; + private Set evictedKeys; + private List evictedValues; + + @BeforeEach + void setUp() { + evictedKeys = new HashSet<>(); + evictedValues = new ArrayList<>(); + + cache = new FIFOCache.Builder(3) + .defaultTTL(1000) + .evictionListener((k, v) -> { + evictedKeys.add(k); + evictedValues.add(v); + }) + .build(); + } + + @Test + void testPutAndGet() { + cache.put("a", "apple"); + Assertions.assertEquals("apple", cache.get("a")); + } + + @Test + void testOverwriteValue() { + cache.put("a", "apple"); + cache.put("a", "avocado"); + Assertions.assertEquals("avocado", cache.get("a")); + } + + @Test + void testExpiration() throws InterruptedException { + cache.put("temp", "value", 100); + Thread.sleep(200); + Assertions.assertNull(cache.get("temp")); + Assertions.assertTrue(evictedKeys.contains("temp")); + } + + @Test + void testEvictionOnCapacity() { + cache.put("a", "alpha"); + cache.put("b", "bravo"); + cache.put("c", "charlie"); + cache.put("d", "delta"); + + int size = cache.size(); + Assertions.assertEquals(3, size); + Assertions.assertEquals(1, evictedKeys.size()); + Assertions.assertEquals(1, evictedValues.size()); + } + + @Test + void testEvictionListener() { + cache.put("x", "one"); + cache.put("y", "two"); + cache.put("z", "three"); + cache.put("w", "four"); + + Assertions.assertFalse(evictedKeys.isEmpty()); + Assertions.assertFalse(evictedValues.isEmpty()); + } + + @Test + void testHitsAndMisses() { + cache.put("a", "apple"); + Assertions.assertEquals("apple", cache.get("a")); + Assertions.assertNull(cache.get("b")); + Assertions.assertEquals(1, cache.getHits()); + Assertions.assertEquals(1, cache.getMisses()); + } + + @Test + void testSizeExcludesExpired() throws InterruptedException { + cache.put("a", "a", 100); + cache.put("b", "b", 100); + cache.put("c", "c", 100); + Thread.sleep(150); + Assertions.assertEquals(0, cache.size()); + } + + @Test + void testSizeIncludesFresh() { + cache.put("a", "a", 1000); + cache.put("b", "b", 1000); + cache.put("c", "c", 1000); + Assertions.assertEquals(3, cache.size()); + } + + @Test + void testToStringDoesNotExposeExpired() throws InterruptedException { + cache.put("live", "alive"); + cache.put("dead", "gone", 100); + Thread.sleep(150); + String result = cache.toString(); + Assertions.assertTrue(result.contains("live")); + Assertions.assertFalse(result.contains("dead")); + } + + @Test + void testNullKeyGetThrows() { + Assertions.assertThrows(IllegalArgumentException.class, () -> cache.get(null)); + } + + @Test + void testPutNullKeyThrows() { + Assertions.assertThrows(IllegalArgumentException.class, () -> cache.put(null, "v")); + } + + @Test + void testPutNullValueThrows() { + Assertions.assertThrows(IllegalArgumentException.class, () -> cache.put("k", null)); + } + + @Test + void testPutNegativeTTLThrows() { + Assertions.assertThrows(IllegalArgumentException.class, () -> cache.put("k", "v", -1)); + } + + @Test + void testBuilderNegativeCapacityThrows() { + Assertions.assertThrows(IllegalArgumentException.class, () -> new FIFOCache.Builder<>(0)); + } + + @Test + void testBuilderNullEvictionListenerThrows() { + FIFOCache.Builder builder = new FIFOCache.Builder<>(1); + Assertions.assertThrows(IllegalArgumentException.class, () -> builder.evictionListener(null)); + } + + @Test + void testEvictionListenerExceptionDoesNotCrash() { + FIFOCache listenerCache = new FIFOCache.Builder(1).evictionListener((k, v) -> { throw new RuntimeException("Exception"); }).build(); + + listenerCache.put("a", "a"); + listenerCache.put("b", "b"); + Assertions.assertDoesNotThrow(() -> listenerCache.get("a")); + } + + @Test + void testTtlZeroThrowsIllegalArgumentException() { + Executable exec = () -> new FIFOCache.Builder(3).defaultTTL(-1).build(); + Assertions.assertThrows(IllegalArgumentException.class, exec); + } + + @Test + void testPeriodicEvictionStrategyEvictsAtInterval() throws InterruptedException { + FIFOCache periodicCache = new FIFOCache.Builder(10).defaultTTL(50).evictionStrategy(new FIFOCache.PeriodicEvictionStrategy<>(3)).build(); + + periodicCache.put("x", "1"); + Thread.sleep(100); + int ev1 = periodicCache.getEvictionStrategy().onAccess(periodicCache); + int ev2 = periodicCache.getEvictionStrategy().onAccess(periodicCache); + int ev3 = periodicCache.getEvictionStrategy().onAccess(periodicCache); + + Assertions.assertEquals(0, ev1); + Assertions.assertEquals(0, ev2); + Assertions.assertEquals(1, ev3, "Eviction should happen on the 3rd access"); + Assertions.assertEquals(0, periodicCache.size()); + } + + @Test + void testPeriodicEvictionStrategyThrowsExceptionIfIntervalLessThanOrEqual0() { + Executable executable = () -> new FIFOCache.Builder(10).defaultTTL(50).evictionStrategy(new FIFOCache.PeriodicEvictionStrategy<>(0)).build(); + + Assertions.assertThrows(IllegalArgumentException.class, executable); + } + + @Test + void testImmediateEvictionStrategyStrategyEvictsOnEachCall() throws InterruptedException { + FIFOCache immediateEvictionStrategy = new FIFOCache.Builder(10).defaultTTL(50).evictionStrategy(new FIFOCache.ImmediateEvictionStrategy<>()).build(); + + immediateEvictionStrategy.put("x", "1"); + Thread.sleep(100); + int evicted = immediateEvictionStrategy.getEvictionStrategy().onAccess(immediateEvictionStrategy); + + Assertions.assertEquals(1, evicted); + } + + @Test + void testBuilderThrowsExceptionIfEvictionStrategyNull() { + Executable executable = () -> new FIFOCache.Builder(10).defaultTTL(50).evictionStrategy(null).build(); + + Assertions.assertThrows(IllegalArgumentException.class, executable); + } + + @Test + void testReturnsCorrectStrategyInstance() { + FIFOCache.EvictionStrategy strategy = new FIFOCache.ImmediateEvictionStrategy<>(); + + FIFOCache newCache = new FIFOCache.Builder(10).defaultTTL(1000).evictionStrategy(strategy).build(); + + Assertions.assertSame(strategy, newCache.getEvictionStrategy(), "Returned strategy should be the same instance"); + } + + @Test + void testDefaultStrategyIsImmediateEvictionStrategy() { + FIFOCache newCache = new FIFOCache.Builder(5).defaultTTL(1000).build(); + + Assertions.assertTrue(newCache.getEvictionStrategy() instanceof FIFOCache.ImmediateEvictionStrategy, "Default strategy should be ImmediateEvictionStrategyStrategy"); + } + + @Test + void testGetEvictionStrategyIsNotNull() { + FIFOCache newCache = new FIFOCache.Builder(5).build(); + + Assertions.assertNotNull(newCache.getEvictionStrategy(), "Eviction strategy should never be null"); + } + + @Test + void testRemoveKeyRemovesExistingKey() { + cache.put("A", "Alpha"); + cache.put("B", "Beta"); + + Assertions.assertEquals("Alpha", cache.get("A")); + Assertions.assertEquals("Beta", cache.get("B")); + + String removed = cache.removeKey("A"); + Assertions.assertEquals("Alpha", removed); + + Assertions.assertNull(cache.get("A")); + Assertions.assertEquals(1, cache.size()); + } + + @Test + void testRemoveKeyReturnsNullIfKeyNotPresent() { + cache.put("X", "X-ray"); + + Assertions.assertNull(cache.removeKey("NonExistent")); + Assertions.assertEquals(1, cache.size()); + } + + @Test + void testRemoveKeyHandlesExpiredEntry() throws InterruptedException { + FIFOCache expiringCache = new FIFOCache.Builder(2).defaultTTL(100).evictionStrategy(new FIFOCache.ImmediateEvictionStrategy<>()).build(); + + expiringCache.put("T", "Temporary"); + + Thread.sleep(200); + + String removed = expiringCache.removeKey("T"); + Assertions.assertEquals("Temporary", removed); + Assertions.assertNull(expiringCache.get("T")); + } + + @Test + void testRemoveKeyThrowsIfKeyIsNull() { + Assertions.assertThrows(IllegalArgumentException.class, () -> cache.removeKey(null)); + } + + @Test + void testRemoveKeyTriggersEvictionListener() { + AtomicInteger evictedCount = new AtomicInteger(); + + FIFOCache localCache = new FIFOCache.Builder(2).evictionListener((key, value) -> evictedCount.incrementAndGet()).build(); + + localCache.put("A", "Apple"); + localCache.put("B", "Banana"); + + localCache.removeKey("A"); + + Assertions.assertEquals(1, evictedCount.get(), "Eviction listener should have been called once"); + } + + @Test + void testRemoveKeyDoestNotAffectOtherKeys() { + cache.put("A", "Alpha"); + cache.put("B", "Beta"); + cache.put("C", "Gamma"); + + cache.removeKey("B"); + + Assertions.assertEquals("Alpha", cache.get("A")); + Assertions.assertNull(cache.get("B")); + Assertions.assertEquals("Gamma", cache.get("C")); + } + + @Test + void testEvictionListenerExceptionDoesNotPropagate() { + FIFOCache localCache = new FIFOCache.Builder(1).evictionListener((key, value) -> { throw new RuntimeException(); }).build(); + + localCache.put("A", "Apple"); + + Assertions.assertDoesNotThrow(() -> localCache.put("B", "Beta")); + } + + @Test + void testGetKeysReturnsAllFreshKeys() { + cache.put("A", "Alpha"); + cache.put("B", "Beta"); + cache.put("G", "Gamma"); + + Set expectedKeys = Set.of("A", "B", "G"); + Assertions.assertEquals(expectedKeys, cache.getAllKeys()); + } + + @Test + void testGetKeysIgnoresExpiredKeys() throws InterruptedException { + cache.put("A", "Alpha"); + cache.put("B", "Beta"); + cache.put("G", "Gamma", 100); + + Set expectedKeys = Set.of("A", "B"); + Thread.sleep(200); + Assertions.assertEquals(expectedKeys, cache.getAllKeys()); + } + + @Test + void testClearRemovesAllEntries() { + cache.put("A", "Alpha"); + cache.put("B", "Beta"); + cache.put("G", "Gamma"); + + cache.clear(); + Assertions.assertEquals(0, cache.size()); + } +} diff --git a/src/test/java/com/thealgorithms/datastructures/caches/LIFOCacheTest.java b/src/test/java/com/thealgorithms/datastructures/caches/LIFOCacheTest.java new file mode 100644 index 000000000000..df60a393b136 --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/caches/LIFOCacheTest.java @@ -0,0 +1,341 @@ +package com.thealgorithms.datastructures.caches; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; + +class LIFOCacheTest { + private LIFOCache cache; + private Set evictedKeys; + private List evictedValues; + + @BeforeEach + void setUp() { + evictedKeys = new HashSet<>(); + evictedValues = new ArrayList<>(); + + cache = new LIFOCache.Builder(3) + .defaultTTL(1000) + .evictionListener((k, v) -> { + evictedKeys.add(k); + evictedValues.add(v); + }) + .build(); + } + + @Test + void testPutAndGet() { + cache.put("a", "apple"); + Assertions.assertEquals("apple", cache.get("a")); + } + + @Test + void testOverwriteValue() { + cache.put("a", "apple"); + cache.put("a", "avocado"); + Assertions.assertEquals("avocado", cache.get("a")); + } + + @Test + void testExpiration() throws InterruptedException { + cache.put("temp", "value", 100); + Thread.sleep(200); + Assertions.assertNull(cache.get("temp")); + Assertions.assertTrue(evictedKeys.contains("temp")); + } + + @Test + void testEvictionOnCapacity() { + cache.put("a", "alpha"); + cache.put("b", "bravo"); + cache.put("c", "charlie"); + cache.put("d", "delta"); + + int size = cache.size(); + Assertions.assertEquals(3, size); + Assertions.assertEquals(1, evictedKeys.size()); + Assertions.assertEquals(1, evictedValues.size()); + Assertions.assertEquals("charlie", evictedValues.getFirst()); + } + + @Test + void testEvictionListener() { + cache.put("x", "one"); + cache.put("y", "two"); + cache.put("z", "three"); + cache.put("w", "four"); + + Assertions.assertFalse(evictedKeys.isEmpty()); + Assertions.assertFalse(evictedValues.isEmpty()); + } + + @Test + void testHitsAndMisses() { + cache.put("a", "apple"); + Assertions.assertEquals("apple", cache.get("a")); + Assertions.assertNull(cache.get("b")); + Assertions.assertEquals(1, cache.getHits()); + Assertions.assertEquals(1, cache.getMisses()); + } + + @Test + void testSizeExcludesExpired() throws InterruptedException { + cache.put("a", "a", 100); + cache.put("b", "b", 100); + cache.put("c", "c", 100); + Thread.sleep(150); + Assertions.assertEquals(0, cache.size()); + } + + @Test + void testSizeIncludesFresh() { + cache.put("a", "a", 1000); + cache.put("b", "b", 1000); + cache.put("c", "c", 1000); + Assertions.assertEquals(3, cache.size()); + } + + @Test + void testToStringDoesNotExposeExpired() throws InterruptedException { + cache.put("live", "alive"); + cache.put("dead", "gone", 100); + Thread.sleep(150); + String result = cache.toString(); + Assertions.assertTrue(result.contains("live")); + Assertions.assertFalse(result.contains("dead")); + } + + @Test + void testNullKeyGetThrows() { + Assertions.assertThrows(IllegalArgumentException.class, () -> cache.get(null)); + } + + @Test + void testPutNullKeyThrows() { + Assertions.assertThrows(IllegalArgumentException.class, () -> cache.put(null, "v")); + } + + @Test + void testPutNullValueThrows() { + Assertions.assertThrows(IllegalArgumentException.class, () -> cache.put("k", null)); + } + + @Test + void testPutNegativeTTLThrows() { + Assertions.assertThrows(IllegalArgumentException.class, () -> cache.put("k", "v", -1)); + } + + @Test + void testBuilderNegativeCapacityThrows() { + Assertions.assertThrows(IllegalArgumentException.class, () -> new LIFOCache.Builder<>(0)); + } + + @Test + void testBuilderNullEvictionListenerThrows() { + LIFOCache.Builder builder = new LIFOCache.Builder<>(1); + Assertions.assertThrows(IllegalArgumentException.class, () -> builder.evictionListener(null)); + } + + @Test + void testEvictionListenerExceptionDoesNotCrash() { + LIFOCache listenerCache = new LIFOCache.Builder(1).evictionListener((k, v) -> { throw new RuntimeException("Exception"); }).build(); + + listenerCache.put("a", "a"); + listenerCache.put("b", "b"); + Assertions.assertDoesNotThrow(() -> listenerCache.get("a")); + } + + @Test + void testTtlZeroThrowsIllegalArgumentException() { + Executable exec = () -> new LIFOCache.Builder(3).defaultTTL(-1).build(); + Assertions.assertThrows(IllegalArgumentException.class, exec); + } + + @Test + void testPeriodicEvictionStrategyEvictsAtInterval() throws InterruptedException { + LIFOCache periodicCache = new LIFOCache.Builder(10).defaultTTL(50).evictionStrategy(new LIFOCache.PeriodicEvictionStrategy<>(3)).build(); + + periodicCache.put("x", "1"); + Thread.sleep(100); + int ev1 = periodicCache.getEvictionStrategy().onAccess(periodicCache); + int ev2 = periodicCache.getEvictionStrategy().onAccess(periodicCache); + int ev3 = periodicCache.getEvictionStrategy().onAccess(periodicCache); + + Assertions.assertEquals(0, ev1); + Assertions.assertEquals(0, ev2); + Assertions.assertEquals(1, ev3, "Eviction should happen on the 3rd access"); + Assertions.assertEquals(0, periodicCache.size()); + } + + @Test + void testPeriodicEvictionStrategyThrowsExceptionIfIntervalLessThanOrEqual0() { + Executable executable = () -> new LIFOCache.Builder(10).defaultTTL(50).evictionStrategy(new LIFOCache.PeriodicEvictionStrategy<>(0)).build(); + + Assertions.assertThrows(IllegalArgumentException.class, executable); + } + + @Test + void testImmediateEvictionStrategyStrategyEvictsOnEachCall() throws InterruptedException { + LIFOCache immediateEvictionStrategy = new LIFOCache.Builder(10).defaultTTL(50).evictionStrategy(new LIFOCache.ImmediateEvictionStrategy<>()).build(); + + immediateEvictionStrategy.put("x", "1"); + Thread.sleep(100); + int evicted = immediateEvictionStrategy.getEvictionStrategy().onAccess(immediateEvictionStrategy); + + Assertions.assertEquals(1, evicted); + } + + @Test + void testBuilderThrowsExceptionIfEvictionStrategyNull() { + Executable executable = () -> new LIFOCache.Builder(10).defaultTTL(50).evictionStrategy(null).build(); + + Assertions.assertThrows(IllegalArgumentException.class, executable); + } + + @Test + void testReturnsCorrectStrategyInstance() { + LIFOCache.EvictionStrategy strategy = new LIFOCache.ImmediateEvictionStrategy<>(); + + LIFOCache newCache = new LIFOCache.Builder(10).defaultTTL(1000).evictionStrategy(strategy).build(); + + Assertions.assertSame(strategy, newCache.getEvictionStrategy(), "Returned strategy should be the same instance"); + } + + @Test + void testDefaultStrategyIsImmediateEvictionStrategy() { + LIFOCache newCache = new LIFOCache.Builder(5).defaultTTL(1000).build(); + + Assertions.assertInstanceOf(LIFOCache.ImmediateEvictionStrategy.class, newCache.getEvictionStrategy(), "Default strategy should be ImmediateEvictionStrategyStrategy"); + } + + @Test + void testGetEvictionStrategyIsNotNull() { + LIFOCache newCache = new LIFOCache.Builder(5).build(); + + Assertions.assertNotNull(newCache.getEvictionStrategy(), "Eviction strategy should never be null"); + } + + @Test + void testRemoveKeyRemovesExistingKey() { + cache.put("A", "Alpha"); + cache.put("B", "Beta"); + + Assertions.assertEquals("Alpha", cache.get("A")); + Assertions.assertEquals("Beta", cache.get("B")); + + String removed = cache.removeKey("A"); + Assertions.assertEquals("Alpha", removed); + + Assertions.assertNull(cache.get("A")); + Assertions.assertEquals(1, cache.size()); + } + + @Test + void testRemoveKeyReturnsNullIfKeyNotPresent() { + cache.put("X", "X-ray"); + + Assertions.assertNull(cache.removeKey("NonExistent")); + Assertions.assertEquals(1, cache.size()); + } + + @Test + void testRemoveKeyHandlesExpiredEntry() throws InterruptedException { + LIFOCache expiringCache = new LIFOCache.Builder(2).defaultTTL(100).evictionStrategy(new LIFOCache.ImmediateEvictionStrategy<>()).build(); + + expiringCache.put("T", "Temporary"); + + Thread.sleep(200); + + String removed = expiringCache.removeKey("T"); + Assertions.assertEquals("Temporary", removed); + Assertions.assertNull(expiringCache.get("T")); + } + + @Test + void testRemoveKeyThrowsIfKeyIsNull() { + Assertions.assertThrows(IllegalArgumentException.class, () -> cache.removeKey(null)); + } + + @Test + void testRemoveKeyTriggersEvictionListener() { + AtomicInteger evictedCount = new AtomicInteger(); + + LIFOCache localCache = new LIFOCache.Builder(2).evictionListener((key, value) -> evictedCount.incrementAndGet()).build(); + + localCache.put("A", "Apple"); + localCache.put("B", "Banana"); + + localCache.removeKey("A"); + + Assertions.assertEquals(1, evictedCount.get(), "Eviction listener should have been called once"); + } + + @Test + void testRemoveKeyDoestNotAffectOtherKeys() { + cache.put("A", "Alpha"); + cache.put("B", "Beta"); + cache.put("C", "Gamma"); + + cache.removeKey("B"); + + Assertions.assertEquals("Alpha", cache.get("A")); + Assertions.assertNull(cache.get("B")); + Assertions.assertEquals("Gamma", cache.get("C")); + } + + @Test + void testEvictionListenerExceptionDoesNotPropagate() { + LIFOCache localCache = new LIFOCache.Builder(1).evictionListener((key, value) -> { throw new RuntimeException(); }).build(); + + localCache.put("A", "Apple"); + + Assertions.assertDoesNotThrow(() -> localCache.put("B", "Beta")); + } + + @Test + void testGetKeysReturnsAllFreshKeys() { + cache.put("A", "Alpha"); + cache.put("B", "Beta"); + cache.put("G", "Gamma"); + + Set expectedKeys = Set.of("A", "B", "G"); + Assertions.assertEquals(expectedKeys, cache.getAllKeys()); + } + + @Test + void testGetKeysIgnoresExpiredKeys() throws InterruptedException { + cache.put("A", "Alpha"); + cache.put("B", "Beta"); + cache.put("G", "Gamma", 100); + + Set expectedKeys = Set.of("A", "B"); + Thread.sleep(200); + Assertions.assertEquals(expectedKeys, cache.getAllKeys()); + } + + @Test + void testClearRemovesAllEntries() { + cache.put("A", "Alpha"); + cache.put("B", "Beta"); + cache.put("G", "Gamma"); + + cache.clear(); + Assertions.assertEquals(0, cache.size()); + } + + @Test + void testGetExpiredKeyIncrementsMissesCount() throws InterruptedException { + LIFOCache localCache = new LIFOCache.Builder(3).evictionStrategy(cache -> 0).defaultTTL(10).build(); + localCache.put("A", "Alpha"); + Thread.sleep(100); + String value = localCache.get("A"); + Assertions.assertEquals(1, localCache.getMisses()); + Assertions.assertNull(value); + } +} diff --git a/src/test/java/com/thealgorithms/datastructures/caches/RRCacheTest.java b/src/test/java/com/thealgorithms/datastructures/caches/RRCacheTest.java new file mode 100644 index 000000000000..100c73ea2a5b --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/caches/RRCacheTest.java @@ -0,0 +1,222 @@ +package com.thealgorithms.datastructures.caches; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Random; +import java.util.Set; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; + +class RRCacheTest { + + private RRCache cache; + private Set evictedKeys; + private List evictedValues; + + @BeforeEach + void setUp() { + evictedKeys = new HashSet<>(); + evictedValues = new ArrayList<>(); + + cache = new RRCache.Builder(3) + .defaultTTL(1000) + .random(new Random(0)) + .evictionListener((k, v) -> { + evictedKeys.add(k); + evictedValues.add(v); + }) + .build(); + } + + @Test + void testPutAndGet() { + cache.put("a", "apple"); + Assertions.assertEquals("apple", cache.get("a")); + } + + @Test + void testOverwriteValue() { + cache.put("a", "apple"); + cache.put("a", "avocado"); + Assertions.assertEquals("avocado", cache.get("a")); + } + + @Test + void testExpiration() throws InterruptedException { + cache.put("temp", "value", 100); // short TTL + Thread.sleep(200); + Assertions.assertNull(cache.get("temp")); + Assertions.assertTrue(evictedKeys.contains("temp")); + } + + @Test + void testEvictionOnCapacity() { + cache.put("a", "alpha"); + cache.put("b", "bravo"); + cache.put("c", "charlie"); + cache.put("d", "delta"); // triggers eviction + + int size = cache.size(); + Assertions.assertEquals(3, size); + Assertions.assertEquals(1, evictedKeys.size()); + Assertions.assertEquals(1, evictedValues.size()); + } + + @Test + void testEvictionListener() { + cache.put("x", "one"); + cache.put("y", "two"); + cache.put("z", "three"); + cache.put("w", "four"); // one of x, y, z will be evicted + + Assertions.assertFalse(evictedKeys.isEmpty()); + Assertions.assertFalse(evictedValues.isEmpty()); + } + + @Test + void testHitsAndMisses() { + cache.put("a", "apple"); + Assertions.assertEquals("apple", cache.get("a")); + Assertions.assertNull(cache.get("b")); + Assertions.assertEquals(1, cache.getHits()); + Assertions.assertEquals(1, cache.getMisses()); + } + + @Test + void testSizeExcludesExpired() throws InterruptedException { + cache.put("a", "a", 100); + cache.put("b", "b", 100); + cache.put("c", "c", 100); + Thread.sleep(150); + Assertions.assertEquals(0, cache.size()); + } + + @Test + void testToStringDoesNotExposeExpired() throws InterruptedException { + cache.put("live", "alive"); + cache.put("dead", "gone", 100); + Thread.sleep(150); + String result = cache.toString(); + Assertions.assertTrue(result.contains("live")); + Assertions.assertFalse(result.contains("dead")); + } + + @Test + void testNullKeyGetThrows() { + Assertions.assertThrows(IllegalArgumentException.class, () -> cache.get(null)); + } + + @Test + void testPutNullKeyThrows() { + Assertions.assertThrows(IllegalArgumentException.class, () -> cache.put(null, "v")); + } + + @Test + void testPutNullValueThrows() { + Assertions.assertThrows(IllegalArgumentException.class, () -> cache.put("k", null)); + } + + @Test + void testPutNegativeTTLThrows() { + Assertions.assertThrows(IllegalArgumentException.class, () -> cache.put("k", "v", -1)); + } + + @Test + void testBuilderNegativeCapacityThrows() { + Assertions.assertThrows(IllegalArgumentException.class, () -> new RRCache.Builder<>(0)); + } + + @Test + void testBuilderNullRandomThrows() { + RRCache.Builder builder = new RRCache.Builder<>(1); + Assertions.assertThrows(IllegalArgumentException.class, () -> builder.random(null)); + } + + @Test + void testBuilderNullEvictionListenerThrows() { + RRCache.Builder builder = new RRCache.Builder<>(1); + Assertions.assertThrows(IllegalArgumentException.class, () -> builder.evictionListener(null)); + } + + @Test + void testEvictionListenerExceptionDoesNotCrash() { + RRCache listenerCache = new RRCache.Builder(1).evictionListener((k, v) -> { throw new RuntimeException("Exception"); }).build(); + + listenerCache.put("a", "a"); + listenerCache.put("b", "b"); // causes eviction but should not crash + Assertions.assertDoesNotThrow(() -> listenerCache.get("a")); + } + + @Test + void testTtlZeroThrowsIllegalArgumentException() { + Executable exec = () -> new RRCache.Builder(3).defaultTTL(-1).build(); + Assertions.assertThrows(IllegalArgumentException.class, exec); + } + + @Test + void testPeriodicEvictionStrategyEvictsAtInterval() throws InterruptedException { + RRCache periodicCache = new RRCache.Builder(10).defaultTTL(50).evictionStrategy(new RRCache.PeriodicEvictionStrategy<>(3)).build(); + + periodicCache.put("x", "1"); + Thread.sleep(100); + int ev1 = periodicCache.getEvictionStrategy().onAccess(periodicCache); + int ev2 = periodicCache.getEvictionStrategy().onAccess(periodicCache); + int ev3 = periodicCache.getEvictionStrategy().onAccess(periodicCache); + + Assertions.assertEquals(0, ev1); + Assertions.assertEquals(0, ev2); + Assertions.assertEquals(1, ev3, "Eviction should happen on the 3rd access"); + Assertions.assertEquals(0, periodicCache.size()); + } + + @Test + void testPeriodicEvictionStrategyThrowsExceptionIfIntervalLessThanOrEqual0() { + Executable executable = () -> new RRCache.Builder(10).defaultTTL(50).evictionStrategy(new RRCache.PeriodicEvictionStrategy<>(0)).build(); + + Assertions.assertThrows(IllegalArgumentException.class, executable); + } + + @Test + void testNoEvictionStrategyEvictsOnEachCall() throws InterruptedException { + RRCache noEvictionStrategyCache = new RRCache.Builder(10).defaultTTL(50).evictionStrategy(new RRCache.NoEvictionStrategy<>()).build(); + + noEvictionStrategyCache.put("x", "1"); + Thread.sleep(100); + int evicted = noEvictionStrategyCache.getEvictionStrategy().onAccess(noEvictionStrategyCache); + + Assertions.assertEquals(1, evicted); + } + + @Test + void testBuilderThrowsExceptionIfEvictionStrategyNull() { + Executable executable = () -> new RRCache.Builder(10).defaultTTL(50).evictionStrategy(null).build(); + + Assertions.assertThrows(IllegalArgumentException.class, executable); + } + + @Test + void testReturnsCorrectStrategyInstance() { + RRCache.EvictionStrategy strategy = new RRCache.NoEvictionStrategy<>(); + + RRCache newCache = new RRCache.Builder(10).defaultTTL(1000).evictionStrategy(strategy).build(); + + Assertions.assertSame(strategy, newCache.getEvictionStrategy(), "Returned strategy should be the same instance"); + } + + @Test + void testDefaultStrategyIsNoEviction() { + RRCache newCache = new RRCache.Builder(5).defaultTTL(1000).build(); + + Assertions.assertTrue(newCache.getEvictionStrategy() instanceof RRCache.PeriodicEvictionStrategy, "Default strategy should be NoEvictionStrategy"); + } + + @Test + void testGetEvictionStrategyIsNotNull() { + RRCache newCache = new RRCache.Builder(5).build(); + + Assertions.assertNotNull(newCache.getEvictionStrategy(), "Eviction strategy should never be null"); + } +} diff --git a/src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java b/src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java index 36593d6669f8..0356949a8f69 100644 --- a/src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java +++ b/src/test/java/com/thealgorithms/datastructures/crdt/LWWElementSetTest.java @@ -3,106 +3,96 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; -import org.junit.jupiter.api.BeforeEach; +import java.time.Instant; import org.junit.jupiter.api.Test; class LWWElementSetTest { - private LWWElementSet set; - private final Bias bias = Bias.ADDS; - - @BeforeEach - void setUp() { - set = new LWWElementSet(); - } - @Test - void testAdd() { - Element element = new Element("key1", 1, bias); - set.add(element); - - assertTrue(set.lookup(element)); + void testAddElement() { + LWWElementSet set = new LWWElementSet<>(); + set.add("A"); + assertTrue(set.lookup("A")); } @Test - void testRemove() { - Element element = new Element("key1", 1, bias); - set.add(element); - set.remove(element); - - assertFalse(set.lookup(element)); + void testRemoveElement() { + LWWElementSet set = new LWWElementSet<>(); + set.add("A"); + set.remove("A"); + assertFalse(set.lookup("A")); } @Test - void testRemoveNonexistentElement() { - Element element = new Element("key1", 1, bias); - set.remove(element); - - assertFalse(set.lookup(element)); + void testLookupWithoutAdding() { + LWWElementSet set = new LWWElementSet<>(); + assertFalse(set.lookup("A")); } @Test - void testLookupNonexistentElement() { - Element element = new Element("key1", 1, bias); + void testLookupLaterTimestampsFalse() { + LWWElementSet set = new LWWElementSet<>(); + + set.addSet.put("A", new Element<>("A", Instant.now())); + set.removeSet.put("A", new Element<>("A", Instant.now().plusSeconds(10))); - assertFalse(set.lookup(element)); + assertFalse(set.lookup("A")); } @Test - void testCompareEqualSets() { - LWWElementSet otherSet = new LWWElementSet(); + void testLookupEarlierTimestampsTrue() { + LWWElementSet set = new LWWElementSet<>(); - Element element = new Element("key1", 1, bias); - set.add(element); - otherSet.add(element); + set.addSet.put("A", new Element<>("A", Instant.now())); + set.removeSet.put("A", new Element<>("A", Instant.now().minusSeconds(10))); - assertTrue(set.compare(otherSet)); - - otherSet.add(new Element("key2", 2, bias)); - assertTrue(set.compare(otherSet)); + assertTrue(set.lookup("A")); } @Test - void testCompareDifferentSets() { - LWWElementSet otherSet = new LWWElementSet(); - - Element element1 = new Element("key1", 1, bias); - Element element2 = new Element("key2", 2, bias); - - set.add(element1); - otherSet.add(element2); - - assertFalse(set.compare(otherSet)); + void testLookupWithConcurrentTimestamps() { + LWWElementSet set = new LWWElementSet<>(); + Instant now = Instant.now(); + set.addSet.put("A", new Element<>("A", now)); + set.removeSet.put("A", new Element<>("A", now)); + assertFalse(set.lookup("A")); } @Test - void testMerge() { - LWWElementSet otherSet = new LWWElementSet(); + void testMergeTwoSets() { + LWWElementSet set1 = new LWWElementSet<>(); + LWWElementSet set2 = new LWWElementSet<>(); - Element element1 = new Element("key1", 1, bias); - Element element2 = new Element("key2", 2, bias); + set1.add("A"); + set2.add("B"); + set2.remove("A"); - set.add(element1); - otherSet.add(element2); + set1.merge(set2); - set.merge(otherSet); - - assertTrue(set.lookup(element1)); - assertTrue(set.lookup(element2)); + assertFalse(set1.lookup("A")); + assertTrue(set1.lookup("B")); } @Test - void testCompareTimestampsEqualTimestamps() { - LWWElementSet lwwElementSet = new LWWElementSet(); + void testMergeWithConflictingTimestamps() { + LWWElementSet set1 = new LWWElementSet<>(); + LWWElementSet set2 = new LWWElementSet<>(); - Element e1 = new Element("key1", 10, Bias.REMOVALS); - Element e2 = new Element("key1", 10, Bias.REMOVALS); + Instant now = Instant.now(); + set1.addSet.put("A", new Element<>("A", now.minusSeconds(10))); + set2.addSet.put("A", new Element<>("A", now)); - assertTrue(lwwElementSet.compareTimestamps(e1, e2)); + set1.merge(set2); - e1 = new Element("key1", 10, Bias.ADDS); - e2 = new Element("key1", 10, Bias.ADDS); + assertTrue(set1.lookup("A")); + } - assertFalse(lwwElementSet.compareTimestamps(e1, e2)); + @Test + void testRemoveOlderThanAdd() { + LWWElementSet set = new LWWElementSet<>(); + Instant now = Instant.now(); + set.addSet.put("A", new Element<>("A", now)); + set.removeSet.put("A", new Element<>("A", now.minusSeconds(10))); + assertTrue(set.lookup("A")); } } diff --git a/src/test/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionTest.java b/src/test/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionTest.java index a10a99d40496..581bac6151dd 100644 --- a/src/test/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionTest.java +++ b/src/test/java/com/thealgorithms/datastructures/disjointsetunion/DisjointSetUnionTest.java @@ -1,8 +1,9 @@ package com.thealgorithms.datastructures.disjointsetunion; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; public class DisjointSetUnionTest { @@ -12,7 +13,7 @@ public void testMakeSet() { DisjointSetUnion dsu = new DisjointSetUnion<>(); Node node = dsu.makeSet(1); assertNotNull(node); - Assertions.assertEquals(node, node.parent); + assertEquals(node, node.parent); } @Test @@ -33,19 +34,197 @@ public void testUnionFindSet() { Node root3 = dsu.findSet(node3); Node root4 = dsu.findSet(node4); - Assertions.assertEquals(node1, node1.parent); - Assertions.assertEquals(node1, node2.parent); - Assertions.assertEquals(node1, node3.parent); - Assertions.assertEquals(node1, node4.parent); + assertEquals(node1, node1.parent); + assertEquals(node1, node2.parent); + assertEquals(node1, node3.parent); + assertEquals(node1, node4.parent); - Assertions.assertEquals(node1, root1); - Assertions.assertEquals(node1, root2); - Assertions.assertEquals(node1, root3); - Assertions.assertEquals(node1, root4); + assertEquals(node1, root1); + assertEquals(node1, root2); + assertEquals(node1, root3); + assertEquals(node1, root4); - Assertions.assertEquals(1, node1.rank); - Assertions.assertEquals(0, node2.rank); - Assertions.assertEquals(0, node3.rank); - Assertions.assertEquals(0, node4.rank); + assertEquals(1, node1.rank); + assertEquals(0, node2.rank); + assertEquals(0, node3.rank); + assertEquals(0, node4.rank); + } + + @Test + public void testFindSetOnSingleNode() { + DisjointSetUnion dsu = new DisjointSetUnion<>(); + Node node = dsu.makeSet("A"); + assertEquals(node, dsu.findSet(node)); + } + + @Test + public void testUnionAlreadyConnectedNodes() { + DisjointSetUnion dsu = new DisjointSetUnion<>(); + Node node1 = dsu.makeSet(1); + Node node2 = dsu.makeSet(2); + Node node3 = dsu.makeSet(3); + + dsu.unionSets(node1, node2); + dsu.unionSets(node2, node3); + + // Union nodes that are already connected + dsu.unionSets(node1, node3); + + // All should have the same root + Node root = dsu.findSet(node1); + assertEquals(root, dsu.findSet(node2)); + assertEquals(root, dsu.findSet(node3)); + } + + @Test + public void testRankIncrease() { + DisjointSetUnion dsu = new DisjointSetUnion<>(); + Node node1 = dsu.makeSet(1); + Node node2 = dsu.makeSet(2); + Node node3 = dsu.makeSet(3); + Node node4 = dsu.makeSet(4); + + dsu.unionSets(node1, node2); // rank of node1 should increase + dsu.unionSets(node3, node4); // rank of node3 should increase + dsu.unionSets(node1, node3); // union two trees of same rank -> rank increases + + assertEquals(2, dsu.findSet(node1).rank); + } + + @Test + public void testMultipleMakeSets() { + DisjointSetUnion dsu = new DisjointSetUnion<>(); + Node node1 = dsu.makeSet(1); + Node node2 = dsu.makeSet(2); + Node node3 = dsu.makeSet(3); + + assertNotEquals(node1, node2); + assertNotEquals(node2, node3); + assertNotEquals(node1, node3); + + assertEquals(node1, node1.parent); + assertEquals(node2, node2.parent); + assertEquals(node3, node3.parent); + } + + @Test + public void testPathCompression() { + DisjointSetUnion dsu = new DisjointSetUnion<>(); + Node node1 = dsu.makeSet(1); + Node node2 = dsu.makeSet(2); + Node node3 = dsu.makeSet(3); + + dsu.unionSets(node1, node2); + dsu.unionSets(node2, node3); + + // After findSet, path compression should update parent to root directly + Node root = dsu.findSet(node3); + assertEquals(root, node1); + assertEquals(node1, node3.parent); + } + + @Test + public void testUnionByRankSmallerToLarger() { + DisjointSetUnion dsu = new DisjointSetUnion<>(); + Node node1 = dsu.makeSet(1); + Node node2 = dsu.makeSet(2); + Node node3 = dsu.makeSet(3); + + // Create tree with node1 as root and rank 1 + dsu.unionSets(node1, node2); + assertEquals(1, node1.rank); + assertEquals(0, node2.rank); + + // Union single node (rank 0) with tree (rank 1) + // Smaller rank tree should attach to larger rank tree + dsu.unionSets(node3, node1); + assertEquals(node1, dsu.findSet(node3)); + assertEquals(1, node1.rank); // Rank should not increase + } + + @Test + public void testUnionByRankEqualRanks() { + DisjointSetUnion dsu = new DisjointSetUnion<>(); + Node node1 = dsu.makeSet(1); + Node node2 = dsu.makeSet(2); + Node node3 = dsu.makeSet(3); + Node node4 = dsu.makeSet(4); + + // Create two trees of equal rank (1) + dsu.unionSets(node1, node2); + dsu.unionSets(node3, node4); + assertEquals(1, node1.rank); + assertEquals(1, node3.rank); + + // Union two trees of equal rank + dsu.unionSets(node1, node3); + Node root = dsu.findSet(node1); + assertEquals(2, root.rank); // Rank should increase by 1 + } + + @Test + public void testLargeChainPathCompression() { + DisjointSetUnion dsu = new DisjointSetUnion<>(); + Node node1 = dsu.makeSet(1); + Node node2 = dsu.makeSet(2); + Node node3 = dsu.makeSet(3); + Node node4 = dsu.makeSet(4); + Node node5 = dsu.makeSet(5); + + // Create a long chain: 1 -> 2 -> 3 -> 4 -> 5 + dsu.unionSets(node1, node2); + dsu.unionSets(node2, node3); + dsu.unionSets(node3, node4); + dsu.unionSets(node4, node5); + + // Find from the deepest node + Node root = dsu.findSet(node5); + + // Path compression should make all nodes point directly to root + assertEquals(root, node5.parent); + assertEquals(root, node4.parent); + assertEquals(root, node3.parent); + assertEquals(root, node2.parent); + assertEquals(root, node1.parent); + } + + @Test + public void testMultipleDisjointSets() { + DisjointSetUnion dsu = new DisjointSetUnion<>(); + Node node1 = dsu.makeSet(1); + Node node2 = dsu.makeSet(2); + Node node3 = dsu.makeSet(3); + Node node4 = dsu.makeSet(4); + Node node5 = dsu.makeSet(5); + Node node6 = dsu.makeSet(6); + + // Create two separate components + dsu.unionSets(node1, node2); + dsu.unionSets(node2, node3); + + dsu.unionSets(node4, node5); + dsu.unionSets(node5, node6); + + // Verify they are separate + assertEquals(dsu.findSet(node1), dsu.findSet(node2)); + assertEquals(dsu.findSet(node2), dsu.findSet(node3)); + assertEquals(dsu.findSet(node4), dsu.findSet(node5)); + assertEquals(dsu.findSet(node5), dsu.findSet(node6)); + + assertNotEquals(dsu.findSet(node1), dsu.findSet(node4)); + assertNotEquals(dsu.findSet(node3), dsu.findSet(node6)); + } + + @Test + public void testEmptyValues() { + DisjointSetUnion dsu = new DisjointSetUnion<>(); + Node emptyNode = dsu.makeSet(""); + Node nullNode = dsu.makeSet(null); + + assertEquals(emptyNode, dsu.findSet(emptyNode)); + assertEquals(nullNode, dsu.findSet(nullNode)); + + dsu.unionSets(emptyNode, nullNode); + assertEquals(dsu.findSet(emptyNode), dsu.findSet(nullNode)); } } diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/KruskalTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/KruskalTest.java index b18f161ef1a6..7291cd6c319c 100644 --- a/src/test/java/com/thealgorithms/datastructures/graphs/KruskalTest.java +++ b/src/test/java/com/thealgorithms/datastructures/graphs/KruskalTest.java @@ -10,6 +10,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +@SuppressWarnings({"rawtypes", "unchecked"}) public class KruskalTest { private Kruskal kruskal; diff --git a/src/test/java/com/thealgorithms/datastructures/lists/CountSinglyLinkedListRecursionTest.java b/src/test/java/com/thealgorithms/datastructures/lists/CountSinglyLinkedListRecursionTest.java index 1a3efe8a5572..3d3f62fc5132 100644 --- a/src/test/java/com/thealgorithms/datastructures/lists/CountSinglyLinkedListRecursionTest.java +++ b/src/test/java/com/thealgorithms/datastructures/lists/CountSinglyLinkedListRecursionTest.java @@ -1,8 +1,10 @@ package com.thealgorithms.datastructures.lists; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; public class CountSinglyLinkedListRecursionTest { @@ -15,35 +17,112 @@ public void setUp() { } @Test + @DisplayName("Count of an empty list should be 0") public void testCountEmptyList() { - // An empty list should have a count of 0 - assertEquals(0, list.count(), "Count of an empty list should be 0."); + assertEquals(0, list.count()); } @Test + @DisplayName("Count after inserting a single element should be 1") public void testCountSingleElementList() { - // Insert a single element and check the count list.insert(1); - assertEquals(1, list.count(), "Count of a single-element list should be 1."); + assertEquals(1, list.count()); } @Test + @DisplayName("Count after inserting multiple distinct elements") public void testCountMultipleElements() { - // Insert multiple elements and check the count for (int i = 1; i <= 5; i++) { list.insert(i); } - assertEquals(5, list.count(), "Count of a list with 5 elements should be 5."); + assertEquals(5, list.count()); } @Test + @DisplayName("Count should reflect total number of nodes with duplicate values") public void testCountWithDuplicateElements() { - // Insert duplicate elements and verify the count is correct - list.insert(1); list.insert(2); list.insert(2); list.insert(3); list.insert(3); - assertEquals(5, list.count(), "Count of a list with duplicate elements should match total node count."); + list.insert(1); + assertEquals(5, list.count()); + } + + @Test + @DisplayName("Count should return 0 after clearing the list") + public void testCountAfterClearingList() { + for (int i = 1; i <= 4; i++) { + list.insert(i); + } + list.clear(); // assumed to exist + assertEquals(0, list.count()); + } + + @Test + @DisplayName("Count on a very large list should be accurate") + public void testCountOnVeryLargeList() { + int n = 1000; + for (int i = 0; i < n; i++) { + list.insert(i); + } + assertEquals(n, list.count()); + } + + @Test + @DisplayName("Count should work correctly with negative values") + public void testCountOnListWithNegativeNumbers() { + list.insert(-1); + list.insert(-2); + list.insert(-3); + assertEquals(3, list.count()); + } + + @Test + @DisplayName("Calling count multiple times should return the same value if list is unchanged") + public void testCountIsConsistentWithoutModification() { + list.insert(1); + list.insert(2); + int count1 = list.count(); + int count2 = list.count(); + assertEquals(count1, count2); + } + + @Test + @DisplayName("Count should reflect total even if all values are the same") + public void testCountAllSameValues() { + for (int i = 0; i < 5; i++) { + list.insert(42); + } + assertEquals(5, list.count()); + } + + @Test + @DisplayName("Count should remain correct after multiple interleaved insert and count operations") + public void testCountAfterEachInsert() { + assertEquals(0, list.count()); + list.insert(1); + assertEquals(1, list.count()); + list.insert(2); + assertEquals(2, list.count()); + list.insert(3); + assertEquals(3, list.count()); + } + + @Test + @DisplayName("List should not throw on edge count (0 nodes)") + public void testEdgeCaseNoElements() { + assertDoesNotThrow(() -> list.count()); + } + + @Test + @DisplayName("Should count accurately after inserting then removing all elements") + public void testCountAfterInsertAndClear() { + for (int i = 0; i < 10; i++) { + list.insert(i); + } + assertEquals(10, list.count()); + list.clear(); + assertEquals(0, list.count()); } } diff --git a/src/test/java/com/thealgorithms/datastructures/lists/CursorLinkedListTest.java b/src/test/java/com/thealgorithms/datastructures/lists/CursorLinkedListTest.java index bf5501826994..20bf24d79159 100644 --- a/src/test/java/com/thealgorithms/datastructures/lists/CursorLinkedListTest.java +++ b/src/test/java/com/thealgorithms/datastructures/lists/CursorLinkedListTest.java @@ -109,4 +109,189 @@ void testMemoryLimitExceeded() { } }); } + + @Test + void testSingleElementOperations() { + // Test operations with just one element + list.append("Only"); + assertEquals("Only", list.get(0)); + assertEquals(0, list.indexOf("Only")); + + list.remove("Only"); + assertNull(list.get(0)); + assertEquals(-1, list.indexOf("Only")); + } + + @Test + void testDuplicateElements() { + // Test handling of duplicate elements + list.append("Duplicate"); + list.append("Other"); + list.append("Duplicate"); + + assertEquals(0, list.indexOf("Duplicate")); // Should return first occurrence + assertEquals("Duplicate", list.get(0)); + assertEquals("Duplicate", list.get(2)); + + list.remove("Duplicate"); // Should remove first occurrence + assertEquals("Other", list.get(0)); + assertEquals("Duplicate", list.get(1)); + } + + @Test + void testRemoveByIndexEdgeCases() { + list.append("First"); + list.append("Second"); + list.append("Third"); + + // Test removing invalid indices + list.removeByIndex(-1); // Should not crash + list.removeByIndex(10); // Should not crash + + // Verify list unchanged + assertEquals("First", list.get(0)); + assertEquals("Second", list.get(1)); + assertEquals("Third", list.get(2)); + + // Test removing first element by index + list.removeByIndex(0); + assertEquals("Second", list.get(0)); + assertEquals("Third", list.get(1)); + } + + @Test + void testRemoveByIndexLastElement() { + list.append("First"); + list.append("Second"); + list.append("Third"); + + // Remove last element by index + list.removeByIndex(2); + assertEquals("First", list.get(0)); + assertEquals("Second", list.get(1)); + assertNull(list.get(2)); + } + + @Test + void testConsecutiveOperations() { + // Test multiple consecutive operations + list.append("A"); + list.append("B"); + list.append("C"); + list.append("D"); + + list.remove("B"); + list.remove("D"); + + assertEquals("A", list.get(0)); + assertEquals("C", list.get(1)); + assertNull(list.get(2)); + + list.append("E"); + assertEquals("E", list.get(2)); + } + + @Test + void testMemoryReclamation() { + // Test that removed elements free up memory space + for (int i = 0; i < 50; i++) { + list.append("Element" + i); + } + + // Remove some elements + for (int i = 0; i < 25; i++) { + list.remove("Element" + i); + } + + // Should be able to add more elements (testing memory reclamation) + for (int i = 100; i < 150; i++) { + list.append("New" + i); + } + + // Verify some elements exist + assertEquals("Element25", list.get(0)); + assertEquals("New100", list.get(25)); + } + + @Test + void testSpecialCharacters() { + // Test with strings containing special characters + list.append("Hello World!"); + list.append("Test@123"); + list.append("Special#$%"); + list.append(""); // Empty string + + assertEquals("Hello World!", list.get(0)); + assertEquals("Test@123", list.get(1)); + assertEquals("Special#$%", list.get(2)); + assertEquals("", list.get(3)); + + assertEquals(3, list.indexOf("")); + } + + @Test + void testLargeIndices() { + list.append("Test"); + + // Test very large indices + assertNull(list.get(Integer.MAX_VALUE)); + assertNull(list.get(1000)); + } + + @Test + void testSequentialRemovalByIndex() { + list.append("A"); + list.append("B"); + list.append("C"); + list.append("D"); + + // Remove elements sequentially by index + list.removeByIndex(1); // Remove "B" + assertEquals("A", list.get(0)); + assertEquals("C", list.get(1)); + assertEquals("D", list.get(2)); + + list.removeByIndex(1); // Remove "C" + assertEquals("A", list.get(0)); + assertEquals("D", list.get(1)); + assertNull(list.get(2)); + } + + @Test + void testAppendAfterRemoval() { + list.append("First"); + list.append("Second"); + + list.remove("First"); + list.append("Third"); + + assertEquals("Second", list.get(0)); + assertEquals("Third", list.get(1)); + assertEquals(1, list.indexOf("Third")); + } + + @Test + void testPerformanceWithManyOperations() { + // Test with many mixed operations + for (int i = 0; i < 50; i++) { + list.append("Item" + i); + } + + // Remove every other element + for (int i = 0; i < 50; i += 2) { + list.remove("Item" + i); + } + + // Verify remaining elements + assertEquals("Item1", list.get(0)); + assertEquals("Item3", list.get(1)); + assertEquals("Item5", list.get(2)); + + // Add more elements + for (int i = 100; i < 110; i++) { + list.append("New" + i); + } + + assertEquals("New100", list.get(25)); + } } diff --git a/src/test/java/com/thealgorithms/datastructures/lists/MergeKSortedLinkedListTest.java b/src/test/java/com/thealgorithms/datastructures/lists/MergeKSortedLinkedListTest.java index 99a890112d31..8d3150d18ed0 100644 --- a/src/test/java/com/thealgorithms/datastructures/lists/MergeKSortedLinkedListTest.java +++ b/src/test/java/com/thealgorithms/datastructures/lists/MergeKSortedLinkedListTest.java @@ -90,4 +90,88 @@ private int[] getListValues(Node head) { } return Arrays.copyOf(values, i); // return only filled part } + + @Test + void testMergeWithNullListsInArray() { + Node list1 = new Node(1, new Node(3)); + Node list2 = null; + Node list3 = new Node(2, new Node(4)); + Node[] lists = {list1, list2, list3}; + + MergeKSortedLinkedList merger = new MergeKSortedLinkedList(); + Node mergedHead = merger.mergeKList(lists, lists.length); + + int[] expectedValues = {1, 2, 3, 4}; + int[] actualValues = getListValues(mergedHead); + assertArrayEquals(expectedValues, actualValues, "Should handle null lists mixed with valid lists"); + } + + @Test + void testMergeWithDuplicateValues() { + Node list1 = new Node(1, new Node(1, new Node(3))); + Node list2 = new Node(1, new Node(2, new Node(3))); + Node list3 = new Node(3, new Node(3)); + Node[] lists = {list1, list2, list3}; + + MergeKSortedLinkedList merger = new MergeKSortedLinkedList(); + Node mergedHead = merger.mergeKList(lists, lists.length); + + int[] expectedValues = {1, 1, 1, 2, 3, 3, 3, 3}; + int[] actualValues = getListValues(mergedHead); + assertArrayEquals(expectedValues, actualValues, "Should handle duplicate values correctly"); + } + + @Test + void testMergeWithZeroLength() { + Node[] lists = {}; + + MergeKSortedLinkedList merger = new MergeKSortedLinkedList(); + Node mergedHead = merger.mergeKList(lists, 0); + + assertNull(mergedHead, "Should return null for zero-length array"); + } + + @Test + void testMergeWithNegativeNumbers() { + Node list1 = new Node(-5, new Node(-1, new Node(3))); + Node list2 = new Node(-3, new Node(0, new Node(2))); + Node[] lists = {list1, list2}; + + MergeKSortedLinkedList merger = new MergeKSortedLinkedList(); + Node mergedHead = merger.mergeKList(lists, lists.length); + + int[] expectedValues = {-5, -3, -1, 0, 2, 3}; + int[] actualValues = getListValues(mergedHead); + assertArrayEquals(expectedValues, actualValues, "Should handle negative numbers correctly"); + } + + @Test + void testMergeIdenticalLists() { + Node list1 = new Node(1, new Node(2, new Node(3))); + Node list2 = new Node(1, new Node(2, new Node(3))); + Node list3 = new Node(1, new Node(2, new Node(3))); + Node[] lists = {list1, list2, list3}; + + MergeKSortedLinkedList merger = new MergeKSortedLinkedList(); + Node mergedHead = merger.mergeKList(lists, lists.length); + + int[] expectedValues = {1, 1, 1, 2, 2, 2, 3, 3, 3}; + int[] actualValues = getListValues(mergedHead); + assertArrayEquals(expectedValues, actualValues, "Should merge identical lists correctly"); + } + + @Test + void testMergeAlreadySortedSequence() { + Node list1 = new Node(1, new Node(2)); + Node list2 = new Node(3, new Node(4)); + Node list3 = new Node(5, new Node(6)); + Node[] lists = {list1, list2, list3}; + + MergeKSortedLinkedList merger = new MergeKSortedLinkedList(); + Node mergedHead = merger.mergeKList(lists, lists.length); + + int[] expectedValues = {1, 2, 3, 4, 5, 6}; + int[] actualValues = getListValues(mergedHead); + assertArrayEquals(expectedValues, actualValues, "Should handle already sorted sequence"); + } } diff --git a/src/test/java/com/thealgorithms/datastructures/lists/ReverseKGroupTest.java b/src/test/java/com/thealgorithms/datastructures/lists/ReverseKGroupTest.java index b2db478f692c..76b7ab063de4 100644 --- a/src/test/java/com/thealgorithms/datastructures/lists/ReverseKGroupTest.java +++ b/src/test/java/com/thealgorithms/datastructures/lists/ReverseKGroupTest.java @@ -20,8 +20,8 @@ public void testReverseKGroupWithEmptyList() { @Test public void testReverseKGroupWithSingleNodeList() { ReverseKGroup reverser = new ReverseKGroup(); - Node singleNode = new Node(5); - Node result = reverser.reverseKGroup(singleNode, 2); + SinglyLinkedListNode singleNode = new SinglyLinkedListNode(5); + SinglyLinkedListNode result = reverser.reverseKGroup(singleNode, 2); assertEquals(5, result.value); assertNull(result.next); } @@ -31,15 +31,15 @@ public void testReverseKGroupWithKEqualTo2() { ReverseKGroup reverser = new ReverseKGroup(); // Create a list with multiple elements (1 -> 2 -> 3 -> 4 -> 5) - Node head; - head = new Node(1); - head.next = new Node(2); - head.next.next = new Node(3); - head.next.next.next = new Node(4); - head.next.next.next.next = new Node(5); + SinglyLinkedListNode head; + head = new SinglyLinkedListNode(1); + head.next = new SinglyLinkedListNode(2); + head.next.next = new SinglyLinkedListNode(3); + head.next.next.next = new SinglyLinkedListNode(4); + head.next.next.next.next = new SinglyLinkedListNode(5); // Test reverse with k=2 - Node result1 = reverser.reverseKGroup(head, 2); + SinglyLinkedListNode result1 = reverser.reverseKGroup(head, 2); assertEquals(2, result1.value); assertEquals(1, result1.next.value); assertEquals(4, result1.next.next.value); @@ -53,15 +53,15 @@ public void testReverseKGroupWithKEqualTo3() { ReverseKGroup reverser = new ReverseKGroup(); // Create a list with multiple elements (1 -> 2 -> 3 -> 4 -> 5) - Node head; - head = new Node(1); - head.next = new Node(2); - head.next.next = new Node(3); - head.next.next.next = new Node(4); - head.next.next.next.next = new Node(5); + SinglyLinkedListNode head; + head = new SinglyLinkedListNode(1); + head.next = new SinglyLinkedListNode(2); + head.next.next = new SinglyLinkedListNode(3); + head.next.next.next = new SinglyLinkedListNode(4); + head.next.next.next.next = new SinglyLinkedListNode(5); // Test reverse with k=3 - Node result = reverser.reverseKGroup(head, 3); + SinglyLinkedListNode result = reverser.reverseKGroup(head, 3); assertEquals(3, result.value); assertEquals(2, result.next.value); assertEquals(1, result.next.next.value); diff --git a/src/test/java/com/thealgorithms/datastructures/lists/RotateSinglyLinkedListsTest.java b/src/test/java/com/thealgorithms/datastructures/lists/RotateSinglyLinkedListsTest.java index 70c0dfccafa4..c476ad1b0203 100644 --- a/src/test/java/com/thealgorithms/datastructures/lists/RotateSinglyLinkedListsTest.java +++ b/src/test/java/com/thealgorithms/datastructures/lists/RotateSinglyLinkedListsTest.java @@ -14,24 +14,24 @@ public class RotateSinglyLinkedListsTest { private final RotateSinglyLinkedLists rotator = new RotateSinglyLinkedLists(); // Helper method to create a linked list from an array of values - private Node createLinkedList(int[] values) { + private SinglyLinkedListNode createLinkedList(int[] values) { if (values.length == 0) { return null; } - Node head = new Node(values[0]); - Node current = head; + SinglyLinkedListNode head = new SinglyLinkedListNode(values[0]); + SinglyLinkedListNode current = head; for (int i = 1; i < values.length; i++) { - current.next = new Node(values[i]); + current.next = new SinglyLinkedListNode(values[i]); current = current.next; } return head; } // Helper method to convert a linked list to a string for easy comparison - private String linkedListToString(Node head) { + private String linkedListToString(SinglyLinkedListNode head) { StringBuilder sb = new StringBuilder(); - Node current = head; + SinglyLinkedListNode current = head; while (current != null) { sb.append(current.value); if (current.next != null) { @@ -51,55 +51,55 @@ public void testRotateRightEmptyList() { @Test public void testRotateRightSingleNodeList() { // Rotate a list with a single element - Node singleNode = new Node(5); - Node rotatedSingleNode = rotator.rotateRight(singleNode, 3); + SinglyLinkedListNode singleNode = new SinglyLinkedListNode(5); + SinglyLinkedListNode rotatedSingleNode = rotator.rotateRight(singleNode, 3); assertEquals("5", linkedListToString(rotatedSingleNode)); } @Test public void testRotateRightMultipleElementsList() { // Rotate a list with multiple elements (rotate by 2) - Node head = createLinkedList(new int[] {1, 2, 3, 4, 5}); - Node rotated = rotator.rotateRight(head, 2); + SinglyLinkedListNode head = createLinkedList(new int[] {1, 2, 3, 4, 5}); + SinglyLinkedListNode rotated = rotator.rotateRight(head, 2); assertEquals("4 -> 5 -> 1 -> 2 -> 3", linkedListToString(rotated)); } @Test public void testRotateRightFullRotation() { // Rotate by more than the length of the list - Node head = createLinkedList(new int[] {1, 2, 3, 4, 5}); - Node rotated = rotator.rotateRight(head, 7); + SinglyLinkedListNode head = createLinkedList(new int[] {1, 2, 3, 4, 5}); + SinglyLinkedListNode rotated = rotator.rotateRight(head, 7); assertEquals("4 -> 5 -> 1 -> 2 -> 3", linkedListToString(rotated)); } @Test public void testRotateRightZeroRotation() { // Rotate a list by k = 0 (no rotation) - Node head = createLinkedList(new int[] {1, 2, 3, 4, 5}); - Node rotated = rotator.rotateRight(head, 0); + SinglyLinkedListNode head = createLinkedList(new int[] {1, 2, 3, 4, 5}); + SinglyLinkedListNode rotated = rotator.rotateRight(head, 0); assertEquals("1 -> 2 -> 3 -> 4 -> 5", linkedListToString(rotated)); } @Test public void testRotateRightByListLength() { // Rotate a list by k equal to list length (no change) - Node head = createLinkedList(new int[] {1, 2, 3, 4, 5}); - Node rotated = rotator.rotateRight(head, 5); + SinglyLinkedListNode head = createLinkedList(new int[] {1, 2, 3, 4, 5}); + SinglyLinkedListNode rotated = rotator.rotateRight(head, 5); assertEquals("1 -> 2 -> 3 -> 4 -> 5", linkedListToString(rotated)); } @Test public void testRotateRightByMultipleOfListLength() { - Node head = createLinkedList(new int[] {1, 2, 3, 4, 5}); - Node rotated = rotator.rotateRight(head, 10); // k = 2 * list length + SinglyLinkedListNode head = createLinkedList(new int[] {1, 2, 3, 4, 5}); + SinglyLinkedListNode rotated = rotator.rotateRight(head, 10); // k = 2 * list length assertEquals("1 -> 2 -> 3 -> 4 -> 5", linkedListToString(rotated)); } @Test public void testRotateRightLongerList() { // Rotate a longer list by a smaller k - Node head = createLinkedList(new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9}); - Node rotated = rotator.rotateRight(head, 4); + SinglyLinkedListNode head = createLinkedList(new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9}); + SinglyLinkedListNode rotated = rotator.rotateRight(head, 4); assertEquals("6 -> 7 -> 8 -> 9 -> 1 -> 2 -> 3 -> 4 -> 5", linkedListToString(rotated)); } } diff --git a/src/test/java/com/thealgorithms/datastructures/lists/SinglyLinkedListTest.java b/src/test/java/com/thealgorithms/datastructures/lists/SinglyLinkedListTest.java index a47434083cdb..f80c6b5055f0 100644 --- a/src/test/java/com/thealgorithms/datastructures/lists/SinglyLinkedListTest.java +++ b/src/test/java/com/thealgorithms/datastructures/lists/SinglyLinkedListTest.java @@ -18,9 +18,9 @@ public class SinglyLinkedListTest { * @return linked list with pre-defined number of nodes */ private SinglyLinkedList createSampleList(int length) { - List nodeList = new ArrayList<>(); + List nodeList = new ArrayList<>(); for (int i = 1; i <= length; i++) { - Node node = new Node(i); + SinglyLinkedListNode node = new SinglyLinkedListNode(i); nodeList.add(node); } @@ -34,10 +34,10 @@ private SinglyLinkedList createSampleList(int length) { @Test void detectLoop() { // List has cycle - Node firstNode = new Node(1); - Node secondNode = new Node(2); - Node thirdNode = new Node(3); - Node fourthNode = new Node(4); + SinglyLinkedListNode firstNode = new SinglyLinkedListNode(1); + SinglyLinkedListNode secondNode = new SinglyLinkedListNode(2); + SinglyLinkedListNode thirdNode = new SinglyLinkedListNode(3); + SinglyLinkedListNode fourthNode = new SinglyLinkedListNode(4); firstNode.next = secondNode; secondNode.next = thirdNode; @@ -112,13 +112,13 @@ void reverseList() { // Reversing the LinkedList using reverseList() method and storing the head of the reversed // linkedlist in a head node The reversed linkedlist will be 4->3->2->1->null - Node head = list.reverseListIter(list.getHead()); + SinglyLinkedListNode head = list.reverseListIter(list.getHead()); // Recording the Nodes after reversing the LinkedList - Node firstNode = head; // 4 - Node secondNode = firstNode.next; // 3 - Node thirdNode = secondNode.next; // 2 - Node fourthNode = thirdNode.next; // 1 + SinglyLinkedListNode firstNode = head; // 4 + SinglyLinkedListNode secondNode = firstNode.next; // 3 + SinglyLinkedListNode thirdNode = secondNode.next; // 2 + SinglyLinkedListNode fourthNode = thirdNode.next; // 1 // Checking whether the LinkedList is reversed or not by comparing the original list and // reversed list nodes @@ -134,10 +134,10 @@ void reverseList() { void reverseListNullPointer() { // Creating a linkedlist with first node assigned to null SinglyLinkedList list = new SinglyLinkedList(); - Node first = list.getHead(); + SinglyLinkedListNode first = list.getHead(); // Reversing the linkedlist - Node head = list.reverseListIter(first); + SinglyLinkedListNode head = list.reverseListIter(first); // checking whether the method works fine if the input is null assertEquals(head, first); @@ -151,10 +151,10 @@ void reverseListTest() { // Reversing the LinkedList using reverseList() method and storing the head of the reversed // linkedlist in a head node - Node head = list.reverseListIter(list.getHead()); + SinglyLinkedListNode head = list.reverseListIter(list.getHead()); // Storing the head in a temp variable, so that we cannot loose the track of head - Node temp = head; + SinglyLinkedListNode temp = head; int i = 20; // This is for the comparison of values of nodes of the reversed linkedlist // Checking whether the reverseList() method performed its task @@ -171,7 +171,7 @@ void recursiveReverseList() { SinglyLinkedList list = createSampleList(5); // Reversing the linked list using reverseList() method - Node head = list.reverseListRec(list.getHead()); + SinglyLinkedListNode head = list.reverseListRec(list.getHead()); // Check if the reversed list is: 5 -> 4 -> 3 -> 2 -> 1 assertEquals(5, head.value); @@ -185,10 +185,10 @@ void recursiveReverseList() { void recursiveReverseListNullPointer() { // Create an empty linked list SinglyLinkedList list = new SinglyLinkedList(); - Node first = list.getHead(); + SinglyLinkedListNode first = list.getHead(); // Reversing the empty linked list - Node head = list.reverseListRec(first); + SinglyLinkedListNode head = list.reverseListRec(first); // Check if the head remains the same (null) assertNull(head); @@ -200,11 +200,11 @@ void recursiveReverseListTest() { SinglyLinkedList list = createSampleList(20); // Reversing the linked list using reverseList() method - Node head = list.reverseListRec(list.getHead()); + SinglyLinkedListNode head = list.reverseListRec(list.getHead()); // Check if the reversed list has the correct values int i = 20; - Node temp = head; + SinglyLinkedListNode temp = head; while (temp != null && i > 0) { assertEquals(i, temp.value); temp = temp.next; diff --git a/src/test/java/com/thealgorithms/datastructures/lists/SkipListTest.java b/src/test/java/com/thealgorithms/datastructures/lists/SkipListTest.java index c572739ffbbf..16d1a015a4d9 100644 --- a/src/test/java/com/thealgorithms/datastructures/lists/SkipListTest.java +++ b/src/test/java/com/thealgorithms/datastructures/lists/SkipListTest.java @@ -1,110 +1,115 @@ package com.thealgorithms.datastructures.lists; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Arrays; import java.util.stream.IntStream; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; class SkipListTest { + private SkipList skipList; + + @BeforeEach + void setUp() { + skipList = new SkipList<>(); + } + @Test - void add() { - SkipList skipList = new SkipList<>(); + @DisplayName("Add element and verify size and retrieval") + void testAdd() { assertEquals(0, skipList.size()); skipList.add("value"); - print(skipList); assertEquals(1, skipList.size()); + assertEquals("value", skipList.get(0)); } @Test - void get() { - SkipList skipList = new SkipList<>(); + @DisplayName("Get retrieves correct element by index") + void testGet() { skipList.add("value"); - - String actualValue = skipList.get(0); - - print(skipList); - assertEquals("value", actualValue); + assertEquals("value", skipList.get(0)); } @Test - void contains() { - SkipList skipList = createSkipList(); - print(skipList); - - boolean contains = skipList.contains("b"); - - assertTrue(contains); + @DisplayName("Contains returns true if element exists") + void testContains() { + skipList = createSkipList(); + assertTrue(skipList.contains("b")); + assertTrue(skipList.contains("a")); + assertFalse(skipList.contains("z")); // negative test } @Test - void removeFromHead() { - SkipList skipList = createSkipList(); - String mostLeftElement = skipList.get(0); + @DisplayName("Remove element from head and check size and order") + void testRemoveFromHead() { + skipList = createSkipList(); + String first = skipList.get(0); int initialSize = skipList.size(); - print(skipList); - skipList.remove(mostLeftElement); + skipList.remove(first); - print(skipList); assertEquals(initialSize - 1, skipList.size()); + assertFalse(skipList.contains(first)); } @Test - void removeFromTail() { - SkipList skipList = createSkipList(); - String mostRightValue = skipList.get(skipList.size() - 1); + @DisplayName("Remove element from tail and check size and order") + void testRemoveFromTail() { + skipList = createSkipList(); + String last = skipList.get(skipList.size() - 1); int initialSize = skipList.size(); - print(skipList); - skipList.remove(mostRightValue); + skipList.remove(last); - print(skipList); assertEquals(initialSize - 1, skipList.size()); + assertFalse(skipList.contains(last)); } @Test - void checkSortedOnLowestLayer() { - SkipList skipList = new SkipList<>(); + @DisplayName("Elements should be sorted at base level") + void testSortedOrderOnBaseLevel() { String[] values = {"d", "b", "a", "c"}; Arrays.stream(values).forEach(skipList::add); - print(skipList); String[] actualOrder = IntStream.range(0, values.length).mapToObj(skipList::get).toArray(String[] ::new); - assertArrayEquals(new String[] {"a", "b", "c", "d"}, actualOrder); + org.junit.jupiter.api.Assertions.assertArrayEquals(new String[] {"a", "b", "c", "d"}, actualOrder); } - private SkipList createSkipList() { - SkipList skipList = new SkipList<>(); - String[] values = { - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - }; + @Test + @DisplayName("Duplicate elements can be added and count correctly") + void testAddDuplicates() { + skipList.add("x"); + skipList.add("x"); + assertEquals(2, skipList.size()); + assertEquals("x", skipList.get(0)); + assertEquals("x", skipList.get(1)); + } + + @Test + @DisplayName("Add multiple and remove all") + void testClearViaRemovals() { + String[] values = {"a", "b", "c"}; Arrays.stream(values).forEach(skipList::add); - return skipList; + + for (String v : values) { + skipList.remove(v); + } + + assertEquals(0, skipList.size()); } - /** - * Print Skip List representation to console. - * Optional method not involved in testing process. Used only for visualisation purposes. - * @param skipList to print - */ - private void print(SkipList skipList) { - System.out.println(skipList); + private SkipList createSkipList() { + SkipList s = new SkipList<>(); + String[] values = {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"}; + Arrays.stream(values).forEach(s::add); + return s; } } diff --git a/src/test/java/com/thealgorithms/datastructures/lists/SortedLinkedListTest.java b/src/test/java/com/thealgorithms/datastructures/lists/SortedLinkedListTest.java index 82e0853da374..71f932465eef 100644 --- a/src/test/java/com/thealgorithms/datastructures/lists/SortedLinkedListTest.java +++ b/src/test/java/com/thealgorithms/datastructures/lists/SortedLinkedListTest.java @@ -128,4 +128,81 @@ public void testIsEmptyAfterDeletion() { list.delete(10); assertTrue(list.isEmpty()); } + + @Test + public void testInsertNegativeNumbers() { + list.insert(-10); + list.insert(-5); + list.insert(-20); + assertEquals("[-20, -10, -5]", list.toString()); + } + + @Test + public void testInsertMixedPositiveAndNegativeNumbers() { + list.insert(0); + list.insert(-1); + list.insert(1); + assertEquals("[-1, 0, 1]", list.toString()); + } + + @Test + public void testMultipleDeletesUntilEmpty() { + list.insert(2); + list.insert(4); + list.insert(6); + assertTrue(list.delete(4)); + assertTrue(list.delete(2)); + assertTrue(list.delete(6)); + assertTrue(list.isEmpty()); + assertEquals("[]", list.toString()); + } + + @Test + public void testDeleteDuplicateValuesOnlyDeletesOneInstance() { + list.insert(5); + list.insert(5); + list.insert(5); + assertTrue(list.delete(5)); + assertEquals("[5, 5]", list.toString()); + assertTrue(list.delete(5)); + assertEquals("[5]", list.toString()); + assertTrue(list.delete(5)); + assertEquals("[]", list.toString()); + } + + @Test + public void testSearchOnListWithDuplicates() { + list.insert(7); + list.insert(7); + list.insert(7); + assertTrue(list.search(7)); + assertFalse(list.search(10)); + } + + @Test + public void testToStringOnEmptyList() { + assertEquals("[]", list.toString()); + } + + @Test + public void testDeleteAllDuplicates() { + list.insert(4); + list.insert(4); + list.insert(4); + assertTrue(list.delete(4)); + assertTrue(list.delete(4)); + assertTrue(list.delete(4)); + assertFalse(list.delete(4)); // nothing left to delete + assertEquals("[]", list.toString()); + } + + @Test + public void testInsertAfterDeletion() { + list.insert(1); + list.insert(3); + list.insert(5); + assertTrue(list.delete(3)); + list.insert(2); + assertEquals("[1, 2, 5]", list.toString()); + } } diff --git a/src/test/java/com/thealgorithms/datastructures/queues/DequeTest.java b/src/test/java/com/thealgorithms/datastructures/queues/DequeTest.java index 1244a2e260d2..ada314383c74 100644 --- a/src/test/java/com/thealgorithms/datastructures/queues/DequeTest.java +++ b/src/test/java/com/thealgorithms/datastructures/queues/DequeTest.java @@ -87,4 +87,111 @@ void testToString() { deque.addFirst(5); assertEquals("Head -> 5 <-> 10 <-> 20 <- Tail", deque.toString()); } + + @Test + void testAlternatingAddRemove() { + Deque deque = new Deque<>(); + deque.addFirst(1); + deque.addLast(2); + deque.addFirst(0); + assertEquals(0, deque.pollFirst()); + assertEquals(2, deque.pollLast()); + assertEquals(1, deque.pollFirst()); + org.junit.jupiter.api.Assertions.assertTrue(deque.isEmpty()); + } + + @Test + void testSizeAfterOperations() { + Deque deque = new Deque<>(); + assertEquals(0, deque.size()); + deque.addFirst(1); + deque.addLast(2); + deque.addFirst(3); + assertEquals(3, deque.size()); + deque.pollFirst(); + deque.pollLast(); + assertEquals(1, deque.size()); + } + + @Test + void testNullValues() { + Deque deque = new Deque<>(); + deque.addFirst(null); + assertNull(deque.peekFirst()); + assertNull(deque.pollFirst()); + org.junit.jupiter.api.Assertions.assertTrue(deque.isEmpty()); + } + + @Test + void testMultipleAddFirst() { + Deque deque = new Deque<>(); + deque.addFirst(1); + deque.addFirst(2); + deque.addFirst(3); + + assertEquals(3, deque.peekFirst(), "First element should be the last added to front"); + assertEquals(1, deque.peekLast(), "Last element should be the first added to front"); + assertEquals(3, deque.size(), "Size should reflect all additions"); + } + + @Test + void testMultipleAddLast() { + Deque deque = new Deque<>(); + deque.addLast(1); + deque.addLast(2); + deque.addLast(3); + + assertEquals(1, deque.peekFirst(), "First element should be the first added to back"); + assertEquals(3, deque.peekLast(), "Last element should be the last added to back"); + assertEquals(3, deque.size(), "Size should reflect all additions"); + } + + @Test + void testSingleElementOperations() { + Deque deque = new Deque<>(); + deque.addFirst(1); + + assertEquals(1, deque.peekFirst(), "Single element should be both first and last"); + assertEquals(1, deque.peekLast(), "Single element should be both first and last"); + assertEquals(1, deque.size()); + + assertEquals(1, deque.pollFirst(), "Should be able to poll single element from front"); + org.junit.jupiter.api.Assertions.assertTrue(deque.isEmpty(), "Deque should be empty after polling single element"); + } + + @Test + void testSingleElementPollLast() { + Deque deque = new Deque<>(); + deque.addLast(1); + + assertEquals(1, deque.pollLast(), "Should be able to poll single element from back"); + org.junit.jupiter.api.Assertions.assertTrue(deque.isEmpty(), "Deque should be empty after polling single element"); + } + + @Test + void testMixedNullAndValues() { + Deque deque = new Deque<>(); + deque.addFirst("first"); + deque.addLast(null); + deque.addFirst(null); + deque.addLast("last"); + + assertEquals(4, deque.size(), "Should handle mixed null and non-null values"); + assertNull(deque.pollFirst(), "Should poll null from front"); + assertEquals("first", deque.pollFirst(), "Should poll non-null value"); + assertNull(deque.pollLast().equals("last") ? null : deque.peekLast(), "Should handle null correctly"); + } + + @Test + void testSymmetricOperations() { + Deque deque = new Deque<>(); + + // Test that addFirst/pollFirst and addLast/pollLast are symmetric + deque.addFirst(1); + deque.addLast(2); + + assertEquals(1, deque.pollFirst(), "addFirst/pollFirst should be symmetric"); + assertEquals(2, deque.pollLast(), "addLast/pollLast should be symmetric"); + org.junit.jupiter.api.Assertions.assertTrue(deque.isEmpty(), "Deque should be empty after symmetric operations"); + } } diff --git a/src/test/java/com/thealgorithms/datastructures/queues/PriorityQueuesTest.java b/src/test/java/com/thealgorithms/datastructures/queues/PriorityQueuesTest.java index 1a3b5aadebb2..e97fe091c556 100644 --- a/src/test/java/com/thealgorithms/datastructures/queues/PriorityQueuesTest.java +++ b/src/test/java/com/thealgorithms/datastructures/queues/PriorityQueuesTest.java @@ -55,4 +55,60 @@ void testPQExtra() { Assertions.assertEquals(myQueue.peek(), 2); Assertions.assertEquals(myQueue.getSize(), 1); } + + @Test + void testInsertUntilFull() { + PriorityQueue pq = new PriorityQueue(3); + pq.insert(1); + pq.insert(4); + pq.insert(2); + Assertions.assertTrue(pq.isFull()); + Assertions.assertEquals(4, pq.peek()); + } + + @Test + void testRemoveFromEmpty() { + PriorityQueue pq = new PriorityQueue(3); + Assertions.assertThrows(RuntimeException.class, pq::remove); + } + + @Test + void testInsertDuplicateValues() { + PriorityQueue pq = new PriorityQueue(5); + pq.insert(5); + pq.insert(5); + pq.insert(3); + Assertions.assertEquals(5, pq.peek()); + pq.remove(); + Assertions.assertEquals(5, pq.peek()); + pq.remove(); + Assertions.assertEquals(3, pq.peek()); + } + + @Test + void testSizeAfterInsertAndRemove() { + PriorityQueue pq = new PriorityQueue(4); + Assertions.assertEquals(0, pq.getSize()); + pq.insert(2); + Assertions.assertEquals(1, pq.getSize()); + pq.insert(10); + Assertions.assertEquals(2, pq.getSize()); + pq.remove(); + Assertions.assertEquals(1, pq.getSize()); + pq.remove(); + Assertions.assertEquals(0, pq.getSize()); + } + + @Test + void testInsertAndRemoveAll() { + PriorityQueue pq = new PriorityQueue(3); + pq.insert(8); + pq.insert(1); + pq.insert(6); + Assertions.assertTrue(pq.isFull()); + pq.remove(); + pq.remove(); + pq.remove(); + Assertions.assertTrue(pq.isEmpty()); + } } diff --git a/src/test/java/com/thealgorithms/datastructures/queues/QueueByTwoStacksTest.java b/src/test/java/com/thealgorithms/datastructures/queues/QueueByTwoStacksTest.java index 87f136a84631..491cb7634302 100644 --- a/src/test/java/com/thealgorithms/datastructures/queues/QueueByTwoStacksTest.java +++ b/src/test/java/com/thealgorithms/datastructures/queues/QueueByTwoStacksTest.java @@ -33,19 +33,19 @@ public void testDequeue() { queue.put(10); queue.put(20); queue.put(30); - assertEquals(10, queue.get()); // First item out - assertEquals(20, queue.get()); // Second item out - assertEquals(30, queue.get()); // Third item out + assertEquals(10, queue.get()); + assertEquals(20, queue.get()); + assertEquals(30, queue.get()); } @Test public void testInterleavedOperations() { queue.put(10); queue.put(20); - assertEquals(10, queue.get()); // Dequeue first item + assertEquals(10, queue.get()); queue.put(30); - assertEquals(20, queue.get()); // Dequeue second item - assertEquals(30, queue.get()); // Dequeue third item + assertEquals(20, queue.get()); + assertEquals(30, queue.get()); } @Test @@ -62,8 +62,76 @@ public void testQueueSize() { @Test public void testEmptyQueueException() { - assertThrows(NoSuchElementException.class, () -> { - queue.get(); // Attempting to dequeue from empty queue - }); + assertThrows(NoSuchElementException.class, () -> queue.get()); + } + + @Test + public void testDequeueAllElements() { + for (int i = 1; i <= 5; i++) { + queue.put(i); + } + for (int i = 1; i <= 5; i++) { + assertEquals(i, queue.get()); + } + assertEquals(0, queue.size()); + } + + @Test + public void testLargeNumberOfOperations() { + int n = 1000; + for (int i = 0; i < n; i++) { + queue.put(i); + } + for (int i = 0; i < n; i++) { + assertEquals(i, queue.get()); + } + assertEquals(0, queue.size()); + } + + @Test + public void testRefillDuringDequeue() { + queue.put(1); + queue.put(2); + assertEquals(1, queue.get()); + queue.put(3); + queue.put(4); + assertEquals(2, queue.get()); + assertEquals(3, queue.get()); + assertEquals(4, queue.get()); + } + + @Test + public void testAlternatingPutAndGet() { + queue.put(1); + assertEquals(1, queue.get()); + queue.put(2); + queue.put(3); + assertEquals(2, queue.get()); + queue.put(4); + assertEquals(3, queue.get()); + assertEquals(4, queue.get()); + } + + @Test + public void testSizeStability() { + queue.put(100); + int size1 = queue.size(); + int size2 = queue.size(); + assertEquals(size1, size2); + } + + @Test + public void testMultipleEmptyDequeues() { + assertThrows(NoSuchElementException.class, () -> queue.get()); + assertThrows(NoSuchElementException.class, () -> queue.get()); + } + + @Test + public void testQueueWithStrings() { + QueueByTwoStacks stringQueue = new QueueByTwoStacks<>(); + stringQueue.put("a"); + stringQueue.put("b"); + assertEquals("a", stringQueue.get()); + assertEquals("b", stringQueue.get()); } } diff --git a/src/test/java/com/thealgorithms/datastructures/queues/QueueTest.java b/src/test/java/com/thealgorithms/datastructures/queues/QueueTest.java index 9a4f50d5e216..86ef940beab6 100644 --- a/src/test/java/com/thealgorithms/datastructures/queues/QueueTest.java +++ b/src/test/java/com/thealgorithms/datastructures/queues/QueueTest.java @@ -124,4 +124,204 @@ void testQueueCapacityException() { Assertions.assertThrows(IllegalArgumentException.class, () -> new Queue<>(0)); Assertions.assertThrows(IllegalArgumentException.class, () -> new Queue<>(-5)); } + + @Test + void testCircularBehavior() { + // Test that queue behaves correctly after multiple insert/remove cycles + queue.insert(1); + queue.insert(2); + queue.insert(3); + + // Remove all elements + queue.remove(); // removes 1 + queue.remove(); // removes 2 + queue.remove(); // removes 3 + + // Add elements again to test circular behavior + queue.insert(4); + queue.insert(5); + queue.insert(6); + + Assertions.assertEquals(4, queue.peekFront()); + Assertions.assertEquals(6, queue.peekRear()); + Assertions.assertEquals(3, queue.getSize()); + Assertions.assertTrue(queue.isFull()); + } + + @Test + void testMixedInsertRemoveOperations() { + // Test interleaved insert and remove operations + queue.insert(1); + queue.insert(2); + + Assertions.assertEquals(1, queue.remove()); + queue.insert(3); + queue.insert(4); + + Assertions.assertEquals(2, queue.remove()); + Assertions.assertEquals(3, queue.remove()); + + queue.insert(5); + queue.insert(6); + + Assertions.assertEquals(4, queue.peekFront()); + Assertions.assertEquals(6, queue.peekRear()); + Assertions.assertEquals(3, queue.getSize()); + } + + @Test + void testSingleElementOperations() { + // Test operations with single element + queue.insert(42); + + Assertions.assertEquals(42, queue.peekFront()); + Assertions.assertEquals(42, queue.peekRear()); + Assertions.assertEquals(1, queue.getSize()); + Assertions.assertFalse(queue.isEmpty()); + Assertions.assertFalse(queue.isFull()); + + Assertions.assertEquals(42, queue.remove()); + Assertions.assertTrue(queue.isEmpty()); + Assertions.assertEquals(0, queue.getSize()); + } + + @Test + void testNullValueHandling() { + // Test queue with null values (if supported) + Queue stringQueue = new Queue<>(3); + + Assertions.assertTrue(stringQueue.insert(null)); + Assertions.assertTrue(stringQueue.insert("test")); + Assertions.assertTrue(stringQueue.insert(null)); + + Assertions.assertNull(stringQueue.peekFront()); + Assertions.assertNull(stringQueue.peekRear()); + Assertions.assertEquals(3, stringQueue.getSize()); + + Assertions.assertNull(stringQueue.remove()); + Assertions.assertEquals("test", stringQueue.peekFront()); + } + + @Test + void testStringDataType() { + // Test queue with String data type + Queue stringQueue = new Queue<>(2); + stringQueue.insert("first"); + stringQueue.insert("second"); + + Assertions.assertEquals("first", stringQueue.peekFront()); + Assertions.assertEquals("second", stringQueue.peekRear()); + } + + @Test + void testLargerCapacityQueue() { + // Test queue with larger capacity + Queue largeQueue = new Queue<>(10); + + // Fill the queue + for (int i = 1; i <= 10; i++) { + Assertions.assertTrue(largeQueue.insert(i)); + } + + Assertions.assertTrue(largeQueue.isFull()); + Assertions.assertFalse(largeQueue.insert(11)); + + // Remove half the elements + for (int i = 1; i <= 5; i++) { + Assertions.assertEquals(i, largeQueue.remove()); + } + + Assertions.assertEquals(6, largeQueue.peekFront()); + Assertions.assertEquals(10, largeQueue.peekRear()); + Assertions.assertEquals(5, largeQueue.getSize()); + } + + @Test + void testQueueCapacityOne() { + // Test queue with capacity of 1 + Queue singleQueue = new Queue<>(1); + + Assertions.assertTrue(singleQueue.isEmpty()); + Assertions.assertFalse(singleQueue.isFull()); + + Assertions.assertTrue(singleQueue.insert(100)); + Assertions.assertTrue(singleQueue.isFull()); + Assertions.assertFalse(singleQueue.isEmpty()); + Assertions.assertFalse(singleQueue.insert(200)); + + Assertions.assertEquals(100, singleQueue.peekFront()); + Assertions.assertEquals(100, singleQueue.peekRear()); + + Assertions.assertEquals(100, singleQueue.remove()); + Assertions.assertTrue(singleQueue.isEmpty()); + } + + @Test + void testQueueWraparoundIndexing() { + // Test that internal array indexing wraps around correctly + queue.insert(1); + queue.insert(2); + queue.insert(3); // Queue full + + // Remove one element + queue.remove(); // removes 1 + + // Add another element (should wrap around) + queue.insert(4); + + Assertions.assertEquals("[2, 3, 4]", queue.toString()); + Assertions.assertEquals(2, queue.peekFront()); + Assertions.assertEquals(4, queue.peekRear()); + + // Continue the pattern + queue.remove(); // removes 2 + queue.insert(5); + + Assertions.assertEquals(3, queue.peekFront()); + Assertions.assertEquals(5, queue.peekRear()); + } + + @Test + void testQueueStateAfterMultipleCycles() { + // Test queue state after multiple complete fill/empty cycles + for (int cycle = 0; cycle < 3; cycle++) { + // Fill the queue + for (int i = 1; i <= 3; i++) { + queue.insert(i + cycle * 10); + } + + // Verify state + Assertions.assertTrue(queue.isFull()); + Assertions.assertEquals(3, queue.getSize()); + + // Empty the queue + for (int i = 1; i <= 3; i++) { + queue.remove(); + } + + // Verify empty state + Assertions.assertTrue(queue.isEmpty()); + Assertions.assertEquals(0, queue.getSize()); + } + } + + @Test + void testQueueConsistencyAfterOperations() { + // Test that queue maintains consistency after various operations + queue.insert(10); + queue.insert(20); + + int firstRemoved = queue.remove(); + queue.insert(30); + queue.insert(40); + + int secondRemoved = queue.remove(); + queue.insert(50); + + // Verify the order is maintained + Assertions.assertEquals(10, firstRemoved); + Assertions.assertEquals(20, secondRemoved); + Assertions.assertEquals(30, queue.peekFront()); + Assertions.assertEquals(50, queue.peekRear()); + } } diff --git a/src/test/java/com/thealgorithms/datastructures/stacks/NodeStackTest.java b/src/test/java/com/thealgorithms/datastructures/stacks/NodeStackTest.java index 7ac0d8bc324b..8a89382211ba 100644 --- a/src/test/java/com/thealgorithms/datastructures/stacks/NodeStackTest.java +++ b/src/test/java/com/thealgorithms/datastructures/stacks/NodeStackTest.java @@ -1,15 +1,26 @@ package com.thealgorithms.datastructures.stacks; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; class NodeStackTest { + private NodeStack intStack; + private NodeStack stringStack; + + @BeforeEach + void setUp() { + intStack = new NodeStack<>(); + stringStack = new NodeStack<>(); + } + @Test + @DisplayName("Test push operation") void testPush() { NodeStack stack = new NodeStack<>(); stack.push(10); @@ -18,6 +29,7 @@ void testPush() { } @Test + @DisplayName("Test pop operation") void testPop() { NodeStack stack = new NodeStack<>(); stack.push("First"); @@ -27,12 +39,14 @@ void testPop() { } @Test + @DisplayName("Test pop on empty stack throws exception") void testPopOnEmptyStack() { NodeStack stack = new NodeStack<>(); assertThrows(IllegalStateException.class, stack::pop, "Popping an empty stack should throw IllegalStateException."); } @Test + @DisplayName("Test peek operation") void testPeek() { NodeStack stack = new NodeStack<>(); stack.push(5); @@ -43,22 +57,25 @@ void testPeek() { } @Test + @DisplayName("Test peek on empty stack throws exception") void testPeekOnEmptyStack() { NodeStack stack = new NodeStack<>(); assertThrows(IllegalStateException.class, stack::peek, "Peeking an empty stack should throw IllegalStateException."); } @Test + @DisplayName("Test isEmpty method") void testIsEmpty() { NodeStack stack = new NodeStack<>(); assertTrue(stack.isEmpty(), "Newly initialized stack should be empty."); stack.push('A'); - assertFalse(stack.isEmpty(), "Stack should not be empty after a push operation."); + org.junit.jupiter.api.Assertions.assertFalse(stack.isEmpty(), "Stack should not be empty after a push operation."); stack.pop(); assertTrue(stack.isEmpty(), "Stack should be empty after popping the only element."); } @Test + @DisplayName("Test size method") void testSize() { NodeStack stack = new NodeStack<>(); assertEquals(0, stack.size(), "Size of empty stack should be 0."); @@ -70,4 +87,164 @@ void testSize() { stack.pop(); assertEquals(0, stack.size(), "Size should be 0 after popping all elements."); } + + @Test + @DisplayName("Test push and pop with null values") + void testPushPopWithNull() { + stringStack.push(null); + stringStack.push("not null"); + stringStack.push(null); + + assertEquals(3, stringStack.size(), "Stack should contain 3 elements including nulls"); + org.junit.jupiter.api.Assertions.assertNull(stringStack.pop(), "Should pop null value"); + assertEquals("not null", stringStack.pop(), "Should pop 'not null' value"); + org.junit.jupiter.api.Assertions.assertNull(stringStack.pop(), "Should pop null value"); + assertTrue(stringStack.isEmpty(), "Stack should be empty after popping all elements"); + } + + @Test + @DisplayName("Test LIFO (Last In First Out) behavior") + void testLifoBehavior() { + int[] values = {1, 2, 3, 4, 5}; + + // Push values in order + for (int value : values) { + intStack.push(value); + } + + // Pop values should be in reverse order + for (int i = values.length - 1; i >= 0; i--) { + assertEquals(values[i], intStack.pop(), "Elements should be popped in LIFO order"); + } + } + + @Test + @DisplayName("Test peek doesn't modify stack") + void testPeekDoesNotModifyStack() { + intStack.push(1); + intStack.push(2); + intStack.push(3); + + int originalSize = intStack.size(); + int peekedValue = intStack.peek(); + + assertEquals(3, peekedValue, "Peek should return top element"); + assertEquals(originalSize, intStack.size(), "Peek should not change stack size"); + assertEquals(3, intStack.peek(), "Multiple peeks should return same value"); + org.junit.jupiter.api.Assertions.assertFalse(intStack.isEmpty(), "Peek should not make stack empty"); + } + + @Test + @DisplayName("Test mixed push and pop operations") + void testMixedOperations() { + // Test interleaved push/pop operations + intStack.push(1); + assertEquals(1, intStack.pop()); + assertTrue(intStack.isEmpty()); + + intStack.push(2); + intStack.push(3); + assertEquals(3, intStack.pop()); + intStack.push(4); + assertEquals(4, intStack.peek()); + assertEquals(2, intStack.size()); + + assertEquals(4, intStack.pop()); + assertEquals(2, intStack.pop()); + assertTrue(intStack.isEmpty()); + } + + @Test + @DisplayName("Test stack with duplicate values") + void testStackWithDuplicates() { + intStack.push(1); + intStack.push(1); + intStack.push(1); + + assertEquals(3, intStack.size(), "Stack should handle duplicate values"); + assertEquals(1, intStack.peek(), "Peek should return duplicate value"); + + assertEquals(1, intStack.pop(), "Should pop first duplicate"); + assertEquals(1, intStack.pop(), "Should pop second duplicate"); + assertEquals(1, intStack.pop(), "Should pop third duplicate"); + assertTrue(intStack.isEmpty(), "Stack should be empty after popping all duplicates"); + } + + @Test + @DisplayName("Test stack with different data types") + void testDifferentDataTypes() { + NodeStack charStack = new NodeStack<>(); + NodeStack booleanStack = new NodeStack<>(); + + // Test with Character + charStack.push('A'); + charStack.push('Z'); + assertEquals('Z', charStack.peek(), "Should handle Character values"); + + // Test with Boolean + booleanStack.push(Boolean.TRUE); + booleanStack.push(Boolean.FALSE); + assertEquals(Boolean.FALSE, booleanStack.peek(), "Should handle Boolean values"); + } + + @Test + @DisplayName("Test stack state consistency after exceptions") + void testStateConsistencyAfterExceptions() { + // Stack should remain consistent after exception-throwing operations + intStack.push(1); + intStack.push(2); + + // Try to peek and pop normally first + assertEquals(2, intStack.peek()); + assertEquals(2, intStack.pop()); + assertEquals(1, intStack.size()); + + // Pop remaining element + assertEquals(1, intStack.pop()); + assertTrue(intStack.isEmpty()); + + // Now stack is empty, operations should throw exceptions + assertThrows(IllegalStateException.class, intStack::peek); + assertThrows(IllegalStateException.class, intStack::pop); + + // Stack should still be in valid empty state + assertTrue(intStack.isEmpty()); + assertEquals(0, intStack.size()); + + // Should be able to push after exceptions + intStack.push(3); + org.junit.jupiter.api.Assertions.assertFalse(intStack.isEmpty()); + assertEquals(1, intStack.size()); + assertEquals(3, intStack.peek()); + } + + @Test + @DisplayName("Test single element stack operations") + void testSingleElementStack() { + intStack.push(2); + + org.junit.jupiter.api.Assertions.assertFalse(intStack.isEmpty(), "Stack with one element should not be empty"); + assertEquals(1, intStack.size(), "Size should be 1"); + assertEquals(2, intStack.peek(), "Peek should return the single element"); + assertEquals(1, intStack.size(), "Peek should not change size"); + + assertEquals(2, intStack.pop(), "Pop should return the single element"); + assertTrue(intStack.isEmpty(), "Stack should be empty after popping single element"); + assertEquals(0, intStack.size(), "Size should be 0 after popping single element"); + } + + @Test + @DisplayName("Test toString method if implemented") + void testToString() { + // This test assumes NodeStack has a toString method + // If not implemented, this test can be removed or NodeStack can be enhanced + intStack.push(1); + intStack.push(2); + intStack.push(3); + + String stackString = intStack.toString(); + // Basic check that toString doesn't throw exception and returns something + assertTrue(stackString != null, "toString should not return null"); + assertTrue(stackString.length() > 0, "toString should return non-empty string"); + } } diff --git a/src/test/java/com/thealgorithms/datastructures/stacks/StackArrayTest.java b/src/test/java/com/thealgorithms/datastructures/stacks/StackArrayTest.java index 74de7ad6435a..392cdf2329fc 100644 --- a/src/test/java/com/thealgorithms/datastructures/stacks/StackArrayTest.java +++ b/src/test/java/com/thealgorithms/datastructures/stacks/StackArrayTest.java @@ -126,4 +126,62 @@ void testToString() { stack.push(3); Assertions.assertEquals("StackArray [1, 2, 3]", stack.toString()); } + + @Test + void testSingleElementOperations() { + // Test operations with a single element + stack.push(2); + Assertions.assertEquals(1, stack.size()); + Assertions.assertFalse(stack.isEmpty()); + Assertions.assertEquals(2, stack.peek()); + Assertions.assertEquals(2, stack.pop()); + Assertions.assertTrue(stack.isEmpty()); + } + + @Test + void testAlternatingPushPop() { + // Test alternating push and pop operations + stack.push(1); + Assertions.assertEquals(1, stack.pop()); + + stack.push(2); + stack.push(3); + Assertions.assertEquals(3, stack.pop()); + + stack.push(4); + Assertions.assertEquals(4, stack.pop()); + Assertions.assertEquals(2, stack.pop()); + Assertions.assertTrue(stack.isEmpty()); + } + + @Test + void testPushNullElements() { + // Test pushing null values + stack.push(null); + Assertions.assertEquals(1, stack.size()); + Assertions.assertNull(stack.peek()); + Assertions.assertNull(stack.pop()); + + // Mix null and non-null values + stack.push(1); + stack.push(null); + stack.push(2); + + Assertions.assertEquals(2, stack.pop()); + Assertions.assertNull(stack.pop()); + Assertions.assertEquals(1, stack.pop()); + } + + @Test + void testWithDifferentDataTypes() { + // Test with String type + StackArray stringStack = new StackArray<>(3); + stringStack.push("first"); + stringStack.push("second"); + stringStack.push("third"); + + Assertions.assertEquals("third", stringStack.pop()); + Assertions.assertEquals("second", stringStack.peek()); + Assertions.assertEquals(2, stringStack.size()); + } } diff --git a/src/test/java/com/thealgorithms/datastructures/stacks/StackOfLinkedListTest.java b/src/test/java/com/thealgorithms/datastructures/stacks/StackOfLinkedListTest.java index 58af66bc38f4..2dfe4c242e1c 100644 --- a/src/test/java/com/thealgorithms/datastructures/stacks/StackOfLinkedListTest.java +++ b/src/test/java/com/thealgorithms/datastructures/stacks/StackOfLinkedListTest.java @@ -118,4 +118,104 @@ public void testSequentialPushAndPop() { } assertTrue(stack.isEmpty(), "Stack should be empty after popping all elements"); } + + @Test + public void testPushZeroAndNegativeValues() { + stack.push(0); + stack.push(-1); + stack.push(-1); + + assertEquals(-1, stack.pop(), "Should handle negative values correctly"); + assertEquals(-1, stack.pop(), "Should handle negative values correctly"); + assertEquals(0, stack.pop(), "Should handle zero value correctly"); + } + + @Test + public void testPushDuplicateValues() { + stack.push(1); + stack.push(1); + stack.push(1); + + assertEquals(3, stack.getSize(), "Should allow duplicate values"); + assertEquals(1, stack.pop()); + assertEquals(1, stack.pop()); + assertEquals(1, stack.pop()); + } + + @Test + public void testPushAfterEmptyingStack() { + stack.push(1); + stack.push(2); + stack.pop(); + stack.pop(); + + assertTrue(stack.isEmpty(), "Stack should be empty"); + + stack.push(10); + assertEquals(10, stack.peek(), "Should work correctly after emptying and refilling"); + assertEquals(1, stack.getSize(), "Size should be correct after refilling"); + } + + @Test + public void testPeekDoesNotModifyStack() { + stack.push(1); + + int firstPeek = stack.peek(); + int secondPeek = stack.peek(); + int thirdPeek = stack.peek(); + + assertEquals(firstPeek, secondPeek, "Multiple peeks should return same value"); + assertEquals(secondPeek, thirdPeek, "Multiple peeks should return same value"); + assertEquals(1, stack.getSize(), "Peek should not modify stack size"); + assertEquals(1, stack.pop(), "Element should still be poppable after peeking"); + } + + @Test + public void testAlternatingPushAndPop() { + stack.push(1); + assertEquals(1, stack.pop()); + + stack.push(2); + stack.push(3); + assertEquals(3, stack.pop()); + + stack.push(4); + assertEquals(4, stack.pop()); + assertEquals(2, stack.pop()); + + assertTrue(stack.isEmpty(), "Stack should be empty after alternating operations"); + } + + @Test + public void testToStringWithSingleElement() { + stack.push(42); + assertEquals("42", stack.toString(), "String representation with single element should not have arrows"); + } + + @Test + public void testStackIntegrity() { + // Test that internal state remains consistent + for (int i = 0; i < 10; i++) { + stack.push(i); + assertEquals(i + 1, stack.getSize(), "Size should be consistent during pushes"); + assertEquals(i, stack.peek(), "Peek should return last pushed value"); + } + + for (int i = 9; i >= 0; i--) { + assertEquals(i, stack.peek(), "Peek should return correct value before pop"); + assertEquals(i, stack.pop(), "Pop should return values in LIFO order"); + assertEquals(i, stack.getSize(), "Size should be consistent during pops"); + } + } + + @Test + public void testMixedDataTypes() { + // If your stack supports Object types, test with different data types + + stack.push(1); + stack.push(2); + + assertEquals(Integer.valueOf(2), stack.pop()); + assertEquals(Integer.valueOf(1), stack.pop()); + } } diff --git a/src/test/java/com/thealgorithms/datastructures/trees/BTreeTest.java b/src/test/java/com/thealgorithms/datastructures/trees/BTreeTest.java new file mode 100644 index 000000000000..da29e117f25d --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/trees/BTreeTest.java @@ -0,0 +1,94 @@ +package com.thealgorithms.datastructures.trees; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.ArrayList; +import java.util.Arrays; +import org.junit.jupiter.api.Test; + +public class BTreeTest { + + @Test + public void testInsertSearchDelete() { + BTree bTree = new BTree(3); // Minimum degree t = 3 + + int[] values = {10, 20, 5, 6, 12, 30, 7, 17}; + for (int val : values) { + bTree.insert(val); + } + + for (int val : values) { + assertTrue(bTree.search(val), "Should find inserted value: " + val); + } + + ArrayList traversal = new ArrayList<>(); + bTree.traverse(traversal); + assertEquals(Arrays.asList(5, 6, 7, 10, 12, 17, 20, 30), traversal); + + bTree.delete(6); + assertFalse(bTree.search(6)); + traversal.clear(); + bTree.traverse(traversal); + assertEquals(Arrays.asList(5, 7, 10, 12, 17, 20, 30), traversal); + } + + @Test + public void testEmptyTreeSearch() { + BTree bTree = new BTree(3); + assertFalse(bTree.search(42), "Search in empty tree should return false."); + } + + @Test + public void testDuplicateInsertions() { + BTree bTree = new BTree(3); + bTree.insert(15); + bTree.insert(15); // Attempt duplicate + bTree.insert(15); // Another duplicate + + ArrayList traversal = new ArrayList<>(); + bTree.traverse(traversal); + + // Should contain only one 15 + long count = traversal.stream().filter(x -> x == 15).count(); + assertEquals(1, count, "Duplicate keys should not be inserted."); + } + + @Test + public void testDeleteNonExistentKey() { + BTree bTree = new BTree(3); + bTree.insert(10); + bTree.insert(20); + bTree.delete(99); // Doesn't exist + assertTrue(bTree.search(10)); + assertTrue(bTree.search(20)); + } + + @Test + public void testComplexInsertDelete() { + BTree bTree = new BTree(2); // Smaller degree to trigger splits more easily + int[] values = {1, 3, 7, 10, 11, 13, 14, 15, 18, 16, 19, 24, 25, 26, 21, 4, 5, 20, 22, 2, 17, 12, 6}; + + for (int val : values) { + bTree.insert(val); + } + + for (int val : values) { + assertTrue(bTree.search(val)); + } + + int[] toDelete = {6, 13, 7, 4, 2, 16}; + for (int val : toDelete) { + bTree.delete(val); + assertFalse(bTree.search(val)); + } + + ArrayList remaining = new ArrayList<>(); + bTree.traverse(remaining); + + for (int val : toDelete) { + assertFalse(remaining.contains(val)); + } + } +} diff --git a/src/test/java/com/thealgorithms/divideandconquer/CountingInversionsTest.java b/src/test/java/com/thealgorithms/divideandconquer/CountingInversionsTest.java index d12614d6fd06..f8356a87eb31 100644 --- a/src/test/java/com/thealgorithms/divideandconquer/CountingInversionsTest.java +++ b/src/test/java/com/thealgorithms/divideandconquer/CountingInversionsTest.java @@ -29,4 +29,35 @@ public void testAllInversions() { int[] arr = {5, 4, 3, 2, 1}; assertEquals(10, CountingInversions.countInversions(arr)); } + + @Test + public void testEmptyArray() { + int[] arr = {}; + assertEquals(0, CountingInversions.countInversions(arr)); + } + + @Test + public void testArrayWithDuplicates() { + int[] arr = {1, 3, 2, 3, 1}; + // Inversions: (3,2), (3,1), (3,1), (2,1) + assertEquals(4, CountingInversions.countInversions(arr)); + } + + @Test + public void testLargeArray() { + int n = 1000; + int[] arr = new int[n]; + for (int i = 0; i < n; i++) { + arr[i] = n - i; // descending order -> max inversions = n*(n-1)/2 + } + int expected = n * (n - 1) / 2; + assertEquals(expected, CountingInversions.countInversions(arr)); + } + + @Test + public void testArrayWithAllSameElements() { + int[] arr = {7, 7, 7, 7}; + // No inversions since all elements are equal + assertEquals(0, CountingInversions.countInversions(arr)); + } } diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOneTabulationTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOneTabulationTest.java new file mode 100644 index 000000000000..6c61ad2130e3 --- /dev/null +++ b/src/test/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOneTabulationTest.java @@ -0,0 +1,78 @@ +package com.thealgorithms.dynamicprogramming; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +public class KnapsackZeroOneTabulationTest { + + @Test + public void basicCheck() { + int[] values = {60, 100, 120}; + int[] weights = {10, 20, 30}; + int capacity = 50; + int itemCount = values.length; + + int expected = 220; // Best choice: item 1 (100) and item 2 (120) + int result = KnapsackZeroOneTabulation.compute(values, weights, capacity, itemCount); + assertEquals(expected, result); + } + + @Test + public void emptyKnapsack() { + int[] values = {}; + int[] weights = {}; + int capacity = 50; + int itemCount = 0; + + assertEquals(0, KnapsackZeroOneTabulation.compute(values, weights, capacity, itemCount)); + } + + @Test + public void zeroCapacity() { + int[] values = {60, 100, 120}; + int[] weights = {10, 20, 30}; + int capacity = 0; + int itemCount = values.length; + + assertEquals(0, KnapsackZeroOneTabulation.compute(values, weights, capacity, itemCount)); + } + + @Test + public void negativeCapacity() { + int[] values = {10, 20, 30}; + int[] weights = {1, 1, 1}; + int capacity = -10; + int itemCount = values.length; + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> KnapsackZeroOneTabulation.compute(values, weights, capacity, itemCount)); + assertEquals("Capacity must not be negative.", exception.getMessage()); + } + + @Test + public void mismatchedLengths() { + int[] values = {60, 100}; // Only 2 values + int[] weights = {10, 20, 30}; // 3 weights + int capacity = 50; + int itemCount = 2; // Matches `values.length` + + // You could either expect 0 or throw an IllegalArgumentException in your compute function + assertThrows(IllegalArgumentException.class, () -> { KnapsackZeroOneTabulation.compute(values, weights, capacity, itemCount); }); + } + + @Test + public void nullInputs() { + int[] weights = {1, 2, 3}; + int capacity = 10; + int itemCount = 3; + + IllegalArgumentException exception1 = assertThrows(IllegalArgumentException.class, () -> KnapsackZeroOneTabulation.compute(null, weights, capacity, itemCount)); + assertEquals("Values and weights arrays must not be null.", exception1.getMessage()); + + int[] values = {1, 2, 3}; + + IllegalArgumentException exception2 = assertThrows(IllegalArgumentException.class, () -> KnapsackZeroOneTabulation.compute(values, null, capacity, itemCount)); + assertEquals("Values and weights arrays must not be null.", exception2.getMessage()); + } +} diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOneTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOneTest.java new file mode 100644 index 000000000000..0ca2b91fc273 --- /dev/null +++ b/src/test/java/com/thealgorithms/dynamicprogramming/KnapsackZeroOneTest.java @@ -0,0 +1,68 @@ +package com.thealgorithms.dynamicprogramming; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class KnapsackZeroOneTest { + + @Test + void basicCheck() { + int[] values = {60, 100, 120}; + int[] weights = {10, 20, 30}; + int capacity = 50; + int expected = 220; + + int result = KnapsackZeroOne.compute(values, weights, capacity, values.length); + assertEquals(expected, result); + } + + @Test + void zeroCapacity() { + int[] values = {10, 20, 30}; + int[] weights = {1, 1, 1}; + int capacity = 0; + + int result = KnapsackZeroOne.compute(values, weights, capacity, values.length); + assertEquals(0, result); + } + + @Test + void zeroItems() { + int[] values = {}; + int[] weights = {}; + int capacity = 10; + + int result = KnapsackZeroOne.compute(values, weights, capacity, 0); + assertEquals(0, result); + } + + @Test + void weightsExceedingCapacity() { + int[] values = {10, 20}; + int[] weights = {100, 200}; + int capacity = 50; + + int result = KnapsackZeroOne.compute(values, weights, capacity, values.length); + assertEquals(0, result); + } + + @Test + void throwsOnNullArrays() { + assertThrows(IllegalArgumentException.class, () -> KnapsackZeroOne.compute(null, new int[] {1}, 10, 1)); + assertThrows(IllegalArgumentException.class, () -> KnapsackZeroOne.compute(new int[] {1}, null, 10, 1)); + } + + @Test + void throwsOnMismatchedArrayLengths() { + assertThrows(IllegalArgumentException.class, () -> KnapsackZeroOne.compute(new int[] {10, 20}, new int[] {5}, 15, 2)); + } + + @Test + void throwsOnNegativeInputs() { + assertThrows(IllegalArgumentException.class, () -> KnapsackZeroOne.compute(new int[] {10}, new int[] {5}, -1, 1)); + + assertThrows(IllegalArgumentException.class, () -> KnapsackZeroOne.compute(new int[] {10}, new int[] {5}, 5, -1)); + } +} diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequenceNLogNTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequenceNLogNTest.java new file mode 100644 index 000000000000..dc87d6751460 --- /dev/null +++ b/src/test/java/com/thealgorithms/dynamicprogramming/LongestIncreasingSubsequenceNLogNTest.java @@ -0,0 +1,22 @@ +package com.thealgorithms.dynamicprogramming; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class LongestIncreasingSubsequenceNLogNTest { + + private static Stream provideTestCases() { + return Stream.of(Arguments.of(new int[] {10, 9, 2, 5, 3, 7, 101, 18}, 4), Arguments.of(new int[] {0, 1, 0, 3, 2, 3}, 4), Arguments.of(new int[] {7, 7, 7, 7, 7}, 1), Arguments.of(new int[] {1, 3, 5, 4, 7}, 4), Arguments.of(new int[] {}, 0), Arguments.of(new int[] {10}, 1), + Arguments.of(new int[] {3, 10, 2, 1, 20}, 3), Arguments.of(new int[] {50, 3, 10, 7, 40, 80}, 4)); + } + + @ParameterizedTest + @MethodSource("provideTestCases") + public void testLengthOfLIS(int[] input, int expected) { + assertEquals(expected, LongestIncreasingSubsequenceNLogN.lengthOfLIS(input)); + } +} diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/TreeMatchingTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/TreeMatchingTest.java new file mode 100644 index 000000000000..d5418770a5d1 --- /dev/null +++ b/src/test/java/com/thealgorithms/dynamicprogramming/TreeMatchingTest.java @@ -0,0 +1,120 @@ +package com.thealgorithms.dynamicprogramming; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.thealgorithms.datastructures.graphs.UndirectedAdjacencyListGraph; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class TreeMatchingTest { + UndirectedAdjacencyListGraph graph; + + @BeforeEach + void setUp() { + graph = new UndirectedAdjacencyListGraph(); + for (int i = 0; i < 14; i++) { + graph.addNode(); + } + } + + @Test + void testMaxMatchingForGeneralTree() { + graph.addEdge(0, 1, 20); + graph.addEdge(0, 2, 30); + graph.addEdge(1, 3, 40); + graph.addEdge(1, 4, 10); + graph.addEdge(2, 5, 20); + graph.addEdge(3, 6, 30); + graph.addEdge(3, 7, 30); + graph.addEdge(5, 8, 40); + graph.addEdge(5, 9, 10); + + TreeMatching treeMatching = new TreeMatching(graph); + assertEquals(110, treeMatching.getMaxMatching(0, -1)); + } + + @Test + void testMaxMatchingForBalancedTree() { + graph.addEdge(0, 1, 20); + graph.addEdge(0, 2, 30); + graph.addEdge(0, 3, 40); + graph.addEdge(1, 4, 10); + graph.addEdge(1, 5, 20); + graph.addEdge(2, 6, 20); + graph.addEdge(3, 7, 30); + graph.addEdge(5, 8, 10); + graph.addEdge(5, 9, 20); + graph.addEdge(7, 10, 10); + graph.addEdge(7, 11, 10); + graph.addEdge(7, 12, 5); + TreeMatching treeMatching = new TreeMatching(graph); + assertEquals(100, treeMatching.getMaxMatching(0, -1)); + } + + @Test + void testMaxMatchingForTreeWithVariedEdgeWeights() { + graph.addEdge(0, 1, 20); + graph.addEdge(0, 2, 30); + graph.addEdge(0, 3, 40); + graph.addEdge(0, 4, 50); + graph.addEdge(1, 5, 20); + graph.addEdge(2, 6, 20); + graph.addEdge(3, 7, 30); + graph.addEdge(5, 8, 10); + graph.addEdge(5, 9, 20); + graph.addEdge(7, 10, 10); + graph.addEdge(4, 11, 50); + graph.addEdge(4, 12, 20); + TreeMatching treeMatching = new TreeMatching(graph); + assertEquals(140, treeMatching.getMaxMatching(0, -1)); + } + + @Test + void emptyTree() { + TreeMatching treeMatching = new TreeMatching(graph); + assertEquals(0, treeMatching.getMaxMatching(0, -1)); + } + + @Test + void testSingleNodeTree() { + UndirectedAdjacencyListGraph singleNodeGraph = new UndirectedAdjacencyListGraph(); + singleNodeGraph.addNode(); + + TreeMatching treeMatching = new TreeMatching(singleNodeGraph); + assertEquals(0, treeMatching.getMaxMatching(0, -1)); + } + + @Test + void testLinearTree() { + graph.addEdge(0, 1, 10); + graph.addEdge(1, 2, 20); + graph.addEdge(2, 3, 30); + graph.addEdge(3, 4, 40); + + TreeMatching treeMatching = new TreeMatching(graph); + assertEquals(60, treeMatching.getMaxMatching(0, -1)); + } + + @Test + void testStarShapedTree() { + graph.addEdge(0, 1, 15); + graph.addEdge(0, 2, 25); + graph.addEdge(0, 3, 35); + graph.addEdge(0, 4, 45); + + TreeMatching treeMatching = new TreeMatching(graph); + assertEquals(45, treeMatching.getMaxMatching(0, -1)); + } + + @Test + void testUnbalancedTree() { + graph.addEdge(0, 1, 10); + graph.addEdge(0, 2, 20); + graph.addEdge(1, 3, 30); + graph.addEdge(2, 4, 40); + graph.addEdge(4, 5, 50); + + TreeMatching treeMatching = new TreeMatching(graph); + assertEquals(100, treeMatching.getMaxMatching(0, -1)); + } +} diff --git a/src/test/java/com/thealgorithms/geometry/PointTest.java b/src/test/java/com/thealgorithms/geometry/PointTest.java new file mode 100644 index 000000000000..12901364b458 --- /dev/null +++ b/src/test/java/com/thealgorithms/geometry/PointTest.java @@ -0,0 +1,117 @@ +package com.thealgorithms.geometry; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +public class PointTest { + + @Test + void testCompareTo() { + Point p1 = new Point(1, 2); + Point p2 = new Point(5, -1); + Point p3 = new Point(3, 9); + Point p4 = new Point(3, 9); + assertEquals(1, p1.compareTo(p2)); + assertEquals(-1, p2.compareTo(p3)); + assertEquals(0, p3.compareTo(p4)); + } + + @Test + void testToString() { + Point p = new Point(-3, 5); + assertEquals("(-3, 5)", p.toString()); + } + + @Test + void testPolarOrder() { + Point p = new Point(0, 0); + assertNotNull(p.polarOrder()); + } + + @Test + void testOrientation() { + // setup points + Point pA = new Point(0, 0); + Point pB = new Point(1, 0); + Point pC = new Point(1, 1); + + // test for left curve + assertEquals(1, Point.orientation(pA, pB, pC)); + + // test for right curve + pB = new Point(0, 1); + assertEquals(-1, Point.orientation(pA, pB, pC)); + + // test for left curve + pC = new Point(-1, 1); + assertEquals(1, Point.orientation(pA, pB, pC)); + + // test for right curve + pB = new Point(1, 0); + pC = new Point(1, -1); + assertEquals(-1, Point.orientation(pA, pB, pC)); + + // test for collinearity + pB = new Point(1, 1); + pC = new Point(2, 2); + assertEquals(0, Point.orientation(pA, pB, pC)); + } + + @Test + void testPolarOrderCompare() { + Point ref = new Point(0, 0); + + Point pA = new Point(1, 1); + Point pB = new Point(1, -1); + assertTrue(ref.polarOrder().compare(pA, pB) < 0); + + pA = new Point(3, 0); + pB = new Point(2, 0); + assertTrue(ref.polarOrder().compare(pA, pB) < 0); + + pA = new Point(0, 1); + pB = new Point(-1, 1); + assertTrue(ref.polarOrder().compare(pA, pB) < 0); + + pA = new Point(1, 1); + pB = new Point(2, 2); + assertEquals(0, ref.polarOrder().compare(pA, pB)); + + pA = new Point(1, 2); + pB = new Point(2, 1); + assertTrue(ref.polarOrder().compare(pA, pB) > 0); + + pA = new Point(2, 1); + pB = new Point(1, 2); + assertTrue(ref.polarOrder().compare(pA, pB) < 0); + + pA = new Point(-1, 0); + pB = new Point(-2, 0); + assertTrue(ref.polarOrder().compare(pA, pB) < 0); + + pA = new Point(2, 3); + pB = new Point(2, 3); + assertEquals(0, ref.polarOrder().compare(pA, pB)); + + pA = new Point(0, 1); + pB = new Point(0, -1); + assertTrue(ref.polarOrder().compare(pA, pB) < 0); + + ref = new Point(1, 1); + + pA = new Point(1, 2); + pB = new Point(2, 2); + assertTrue(ref.polarOrder().compare(pA, pB) > 0); + + pA = new Point(2, 1); + pB = new Point(2, 0); + assertTrue(ref.polarOrder().compare(pA, pB) < 0); + + pA = new Point(0, 1); + pB = new Point(1, 0); + assertTrue(ref.polarOrder().compare(pA, pB) < 0); + } +} diff --git a/src/test/java/com/thealgorithms/graph/ConstrainedShortestPathTest.java b/src/test/java/com/thealgorithms/graph/ConstrainedShortestPathTest.java new file mode 100644 index 000000000000..eccd359f2634 --- /dev/null +++ b/src/test/java/com/thealgorithms/graph/ConstrainedShortestPathTest.java @@ -0,0 +1,218 @@ +package com.thealgorithms.graph; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.thealgorithms.graph.ConstrainedShortestPath.Graph; +import org.junit.jupiter.api.Test; + +public class ConstrainedShortestPathTest { + + /** + * Tests a simple linear graph to verify if the solver calculates the shortest path correctly. + * Expected: The minimal path cost from node 0 to node 2 should be 5 while not exceeding the resource limit. + */ + @Test + public void testSimpleGraph() { + Graph graph = new Graph(3); + graph.addEdge(0, 1, 2, 3); + graph.addEdge(1, 2, 3, 2); + + int maxResource = 5; + ConstrainedShortestPath solver = new ConstrainedShortestPath(graph, maxResource); + + assertEquals(5, solver.solve(0, 2)); + } + + /** + * Tests a graph where no valid path exists due to resource constraints. + * Expected: The solver should return -1, indicating no path is feasible. + */ + @Test + public void testNoPath() { + Graph graph = new Graph(3); + graph.addEdge(0, 1, 2, 6); + graph.addEdge(1, 2, 3, 6); + + int maxResource = 5; + ConstrainedShortestPath solver = new ConstrainedShortestPath(graph, maxResource); + + assertEquals(-1, solver.solve(0, 2)); + } + + /** + * Tests a graph with multiple paths between source and destination. + * Expected: The solver should choose the path with the minimal cost of 5, considering the resource limit. + */ + @Test + public void testMultiplePaths() { + Graph graph = new Graph(4); + graph.addEdge(0, 1, 1, 1); + graph.addEdge(1, 3, 5, 2); + graph.addEdge(0, 2, 2, 1); + graph.addEdge(2, 3, 3, 2); + + int maxResource = 3; + ConstrainedShortestPath solver = new ConstrainedShortestPath(graph, maxResource); + + assertEquals(5, solver.solve(0, 3)); + } + + /** + * Verifies that the solver allows a path exactly matching the resource limit. + * Expected: The path is valid with a total cost of 5. + */ + @Test + public void testExactResourceLimit() { + Graph graph = new Graph(3); + graph.addEdge(0, 1, 2, 3); + graph.addEdge(1, 2, 3, 2); + + int maxResource = 5; + ConstrainedShortestPath solver = new ConstrainedShortestPath(graph, maxResource); + + assertEquals(5, solver.solve(0, 2)); + } + + /** + * Tests a disconnected graph where the destination node cannot be reached. + * Expected: The solver should return -1, as the destination is unreachable. + */ + @Test + public void testDisconnectedGraph() { + Graph graph = new Graph(4); + graph.addEdge(0, 1, 2, 2); + graph.addEdge(2, 3, 3, 2); + + int maxResource = 5; + ConstrainedShortestPath solver = new ConstrainedShortestPath(graph, maxResource); + + assertEquals(-1, solver.solve(0, 3)); + } + + /** + * Tests a graph with cycles to ensure the solver does not fall into infinite loops and correctly calculates costs. + * Expected: The solver should compute the minimal path cost of 6. + */ + @Test + public void testGraphWithCycles() { + Graph graph = new Graph(4); + graph.addEdge(0, 1, 2, 1); + graph.addEdge(1, 2, 3, 1); + graph.addEdge(2, 0, 1, 1); + graph.addEdge(1, 3, 4, 2); + + int maxResource = 3; + ConstrainedShortestPath solver = new ConstrainedShortestPath(graph, maxResource); + + assertEquals(6, solver.solve(0, 3)); + } + + /** + * Tests the solver's performance and correctness on a large linear graph with 1000 nodes. + * Expected: The solver should efficiently calculate the shortest path with a cost of 999. + */ + @Test + public void testLargeGraphPerformance() { + int nodeCount = 1000; + Graph graph = new Graph(nodeCount); + for (int i = 0; i < nodeCount - 1; i++) { + graph.addEdge(i, i + 1, 1, 1); + } + + int maxResource = 1000; + ConstrainedShortestPath solver = new ConstrainedShortestPath(graph, maxResource); + + assertEquals(999, solver.solve(0, nodeCount - 1)); + } + + /** + * Tests a graph with isolated nodes to ensure the solver recognizes unreachable destinations. + * Expected: The solver should return -1 for unreachable nodes. + */ + @Test + public void testIsolatedNodes() { + Graph graph = new Graph(5); + graph.addEdge(0, 1, 2, 1); + graph.addEdge(1, 2, 3, 1); + + int maxResource = 5; + ConstrainedShortestPath solver = new ConstrainedShortestPath(graph, maxResource); + + assertEquals(-1, solver.solve(0, 3)); + } + + /** + * Tests a cyclic large graph with multiple overlapping paths. + * Expected: The solver should calculate the shortest path cost of 5. + */ + @Test + public void testCyclicLargeGraph() { + Graph graph = new Graph(10); + for (int i = 0; i < 9; i++) { + graph.addEdge(i, (i + 1) % 10, 1, 1); + } + graph.addEdge(0, 5, 5, 3); + + int maxResource = 10; + ConstrainedShortestPath solver = new ConstrainedShortestPath(graph, maxResource); + + assertEquals(5, solver.solve(0, 5)); + } + + /** + * Tests a large complex graph with multiple paths and varying resource constraints. + * Expected: The solver should identify the optimal path with a cost of 19 within the resource limit. + */ + @Test + public void testLargeComplexGraph() { + Graph graph = new Graph(10); + graph.addEdge(0, 1, 4, 2); + graph.addEdge(0, 2, 3, 3); + graph.addEdge(1, 3, 2, 1); + graph.addEdge(2, 3, 5, 2); + graph.addEdge(2, 4, 8, 4); + graph.addEdge(3, 5, 7, 3); + graph.addEdge(3, 6, 6, 2); + graph.addEdge(4, 6, 3, 2); + graph.addEdge(5, 7, 1, 1); + graph.addEdge(6, 7, 2, 2); + graph.addEdge(7, 8, 3, 1); + graph.addEdge(8, 9, 2, 1); + + int maxResource = 10; + ConstrainedShortestPath solver = new ConstrainedShortestPath(graph, maxResource); + + assertEquals(19, solver.solve(0, 9)); + } + + /** + * Edge case test where the graph has only one node and no edges. + * Expected: The minimal path cost is 0, as the start and destination are the same. + */ + @Test + public void testSingleNodeGraph() { + Graph graph = new Graph(1); + + int maxResource = 0; + ConstrainedShortestPath solver = new ConstrainedShortestPath(graph, maxResource); + + assertEquals(0, solver.solve(0, 0)); + } + + /** + * Tests a graph with multiple paths but a tight resource constraint. + * Expected: The solver should return -1 if no path can be found within the resource limit. + */ + @Test + public void testTightResourceConstraint() { + Graph graph = new Graph(4); + graph.addEdge(0, 1, 3, 4); + graph.addEdge(1, 2, 1, 2); + graph.addEdge(0, 2, 2, 2); + + int maxResource = 3; + ConstrainedShortestPath solver = new ConstrainedShortestPath(graph, maxResource); + + assertEquals(2, solver.solve(0, 2)); + } +} diff --git a/src/test/java/com/thealgorithms/graph/TravelingSalesmanTest.java b/src/test/java/com/thealgorithms/graph/TravelingSalesmanTest.java new file mode 100644 index 000000000000..b93c9f89c944 --- /dev/null +++ b/src/test/java/com/thealgorithms/graph/TravelingSalesmanTest.java @@ -0,0 +1,127 @@ +package com.thealgorithms.graph; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class TravelingSalesmanTest { + + // Test Case 1: A simple distance matrix with 4 cities + @Test + public void testBruteForceSimple() { + int[][] distanceMatrix = {{0, 10, 15, 20}, {10, 0, 35, 25}, {15, 35, 0, 30}, {20, 25, 30, 0}}; + int expectedMinDistance = 80; + int result = TravelingSalesman.bruteForce(distanceMatrix); + assertEquals(expectedMinDistance, result); + } + + @Test + public void testDynamicProgrammingSimple() { + int[][] distanceMatrix = {{0, 10, 15, 20}, {10, 0, 35, 25}, {15, 35, 0, 30}, {20, 25, 30, 0}}; + int expectedMinDistance = 80; + int result = TravelingSalesman.dynamicProgramming(distanceMatrix); + assertEquals(expectedMinDistance, result); + } + + // Test Case 2: A distance matrix with 3 cities + @Test + public void testBruteForceThreeCities() { + int[][] distanceMatrix = {{0, 10, 15}, {10, 0, 35}, {15, 35, 0}}; + int expectedMinDistance = 60; + int result = TravelingSalesman.bruteForce(distanceMatrix); + assertEquals(expectedMinDistance, result); + } + + @Test + public void testDynamicProgrammingThreeCities() { + int[][] distanceMatrix = {{0, 10, 15}, {10, 0, 35}, {15, 35, 0}}; + int expectedMinDistance = 60; + int result = TravelingSalesman.dynamicProgramming(distanceMatrix); + assertEquals(expectedMinDistance, result); + } + + // Test Case 3: A distance matrix with 5 cities (larger input) + @Test + public void testBruteForceFiveCities() { + int[][] distanceMatrix = {{0, 2, 9, 10, 1}, {2, 0, 6, 5, 8}, {9, 6, 0, 4, 3}, {10, 5, 4, 0, 7}, {1, 8, 3, 7, 0}}; + int expectedMinDistance = 15; + int result = TravelingSalesman.bruteForce(distanceMatrix); + assertEquals(expectedMinDistance, result); + } + + @Test + public void testDynamicProgrammingFiveCities() { + int[][] distanceMatrix = {{0, 2, 9, 10, 1}, {2, 0, 6, 5, 8}, {9, 6, 0, 4, 3}, {10, 5, 4, 0, 7}, {1, 8, 3, 7, 0}}; + int expectedMinDistance = 15; + int result = TravelingSalesman.dynamicProgramming(distanceMatrix); + assertEquals(expectedMinDistance, result); + } + + // Test Case 4: A distance matrix with 2 cities (simple case) + @Test + public void testBruteForceTwoCities() { + int[][] distanceMatrix = {{0, 1}, {1, 0}}; + int expectedMinDistance = 2; + int result = TravelingSalesman.bruteForce(distanceMatrix); + assertEquals(expectedMinDistance, result); + } + + @Test + public void testDynamicProgrammingTwoCities() { + int[][] distanceMatrix = {{0, 1}, {1, 0}}; + int expectedMinDistance = 2; + int result = TravelingSalesman.dynamicProgramming(distanceMatrix); + assertEquals(expectedMinDistance, result); + } + + // Test Case 5: A distance matrix with identical distances + @Test + public void testBruteForceEqualDistances() { + int[][] distanceMatrix = {{0, 10, 10, 10}, {10, 0, 10, 10}, {10, 10, 0, 10}, {10, 10, 10, 0}}; + int expectedMinDistance = 40; + int result = TravelingSalesman.bruteForce(distanceMatrix); + assertEquals(expectedMinDistance, result); + } + + @Test + public void testDynamicProgrammingEqualDistances() { + int[][] distanceMatrix = {{0, 10, 10, 10}, {10, 0, 10, 10}, {10, 10, 0, 10}, {10, 10, 10, 0}}; + int expectedMinDistance = 40; + int result = TravelingSalesman.dynamicProgramming(distanceMatrix); + assertEquals(expectedMinDistance, result); + } + + // Test Case 6: A distance matrix with only one city + @Test + public void testBruteForceOneCity() { + int[][] distanceMatrix = {{0}}; + int expectedMinDistance = 0; + int result = TravelingSalesman.bruteForce(distanceMatrix); + assertEquals(expectedMinDistance, result); + } + + @Test + public void testDynamicProgrammingOneCity() { + int[][] distanceMatrix = {{0}}; + int expectedMinDistance = 0; + int result = TravelingSalesman.dynamicProgramming(distanceMatrix); + assertEquals(expectedMinDistance, result); + } + + // Test Case 7: Distance matrix with large numbers + @Test + public void testBruteForceLargeNumbers() { + int[][] distanceMatrix = {{0, 1000000, 2000000}, {1000000, 0, 1500000}, {2000000, 1500000, 0}}; + int expectedMinDistance = 4500000; + int result = TravelingSalesman.bruteForce(distanceMatrix); + assertEquals(expectedMinDistance, result); + } + + @Test + public void testDynamicProgrammingLargeNumbers() { + int[][] distanceMatrix = {{0, 1000000, 2000000}, {1000000, 0, 1500000}, {2000000, 1500000, 0}}; + int expectedMinDistance = 4500000; + int result = TravelingSalesman.dynamicProgramming(distanceMatrix); + assertEquals(expectedMinDistance, result); + } +} diff --git a/src/test/java/com/thealgorithms/maths/AbsoluteMaxTest.java b/src/test/java/com/thealgorithms/maths/AbsoluteMaxTest.java index 70d2f64bc541..33461fbbc088 100644 --- a/src/test/java/com/thealgorithms/maths/AbsoluteMaxTest.java +++ b/src/test/java/com/thealgorithms/maths/AbsoluteMaxTest.java @@ -19,4 +19,12 @@ void testGetMaxValue() { void testGetMaxValueWithNoArguments() { assertThrows(IllegalArgumentException.class, AbsoluteMax::getMaxValue); } + + @Test + void testGetMaxValueWithSameAbsoluteValues() { + assertEquals(5, AbsoluteMax.getMaxValue(-5, 5)); + assertEquals(5, AbsoluteMax.getMaxValue(5, -5)); + assertEquals(12, AbsoluteMax.getMaxValue(-12, 9, 3, 12, 1)); + assertEquals(12, AbsoluteMax.getMaxValue(12, 9, 3, -12, 1)); + } } diff --git a/src/test/java/com/thealgorithms/maths/AbsoluteMinTest.java b/src/test/java/com/thealgorithms/maths/AbsoluteMinTest.java index 4b676ca634f7..dfca757fd877 100644 --- a/src/test/java/com/thealgorithms/maths/AbsoluteMinTest.java +++ b/src/test/java/com/thealgorithms/maths/AbsoluteMinTest.java @@ -15,7 +15,13 @@ void testGetMinValue() { @Test void testGetMinValueWithNoArguments() { - Exception exception = assertThrows(IllegalArgumentException.class, () -> AbsoluteMin.getMinValue()); + Exception exception = assertThrows(IllegalArgumentException.class, AbsoluteMin::getMinValue); assertEquals("Numbers array cannot be empty", exception.getMessage()); } + + @Test + void testGetMinValueWithSameAbsoluteValues() { + assertEquals(-5, AbsoluteMin.getMinValue(-5, 5)); + assertEquals(-5, AbsoluteMin.getMinValue(5, -5)); + } } diff --git a/src/test/java/com/thealgorithms/maths/AbsoluteValueTest.java b/src/test/java/com/thealgorithms/maths/AbsoluteValueTest.java index f87652253641..907d5cb45ef9 100644 --- a/src/test/java/com/thealgorithms/maths/AbsoluteValueTest.java +++ b/src/test/java/com/thealgorithms/maths/AbsoluteValueTest.java @@ -12,4 +12,28 @@ public class AbsoluteValueTest { void testGetAbsValue() { Stream.generate(() -> ThreadLocalRandom.current().nextInt()).limit(1000).forEach(number -> assertEquals(Math.abs(number), AbsoluteValue.getAbsValue(number))); } + + @Test + void testZero() { + assertEquals(0, AbsoluteValue.getAbsValue(0)); + } + + @Test + void testPositiveNumbers() { + assertEquals(5, AbsoluteValue.getAbsValue(5)); + assertEquals(123456, AbsoluteValue.getAbsValue(123456)); + assertEquals(Integer.MAX_VALUE, AbsoluteValue.getAbsValue(Integer.MAX_VALUE)); + } + + @Test + void testNegativeNumbers() { + assertEquals(5, AbsoluteValue.getAbsValue(-5)); + assertEquals(123456, AbsoluteValue.getAbsValue(-123456)); + assertEquals(Integer.MAX_VALUE, AbsoluteValue.getAbsValue(-Integer.MAX_VALUE)); + } + + @Test + void testMinIntEdgeCase() { + assertEquals(Integer.MIN_VALUE, AbsoluteValue.getAbsValue(Integer.MIN_VALUE)); + } } diff --git a/src/test/java/com/thealgorithms/maths/AverageTest.java b/src/test/java/com/thealgorithms/maths/AverageTest.java index c5c751938f5d..638739bc4fda 100644 --- a/src/test/java/com/thealgorithms/maths/AverageTest.java +++ b/src/test/java/com/thealgorithms/maths/AverageTest.java @@ -1,33 +1,48 @@ package com.thealgorithms.maths; -import org.junit.jupiter.api.Assertions; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; public class AverageTest { private static final double SMALL_VALUE = 0.00001d; - @Test - public void testAverageDouble12() { - double[] numbers = {3d, 6d, 9d, 12d, 15d, 18d, 21d}; - Assertions.assertEquals(12d, Average.average(numbers), SMALL_VALUE); + @ParameterizedTest(name = "average({0}) should be approximately {1}") + @MethodSource("provideDoubleArrays") + void testAverageDouble(double[] numbers, double expected) { + assertEquals(expected, Average.average(numbers), SMALL_VALUE); } - @Test - public void testAverageDouble20() { - double[] numbers = {5d, 10d, 15d, 20d, 25d, 30d, 35d}; - Assertions.assertEquals(20d, Average.average(numbers), SMALL_VALUE); + @ParameterizedTest(name = "average({0}) should be {1}") + @MethodSource("provideIntArrays") + void testAverageInt(int[] numbers, long expected) { + assertEquals(expected, Average.average(numbers)); } @Test - public void testAverageDouble() { - double[] numbers = {1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d}; - Assertions.assertEquals(4.5d, Average.average(numbers), SMALL_VALUE); + void testAverageDoubleThrowsExceptionOnNullOrEmpty() { + assertThrows(IllegalArgumentException.class, () -> Average.average((double[]) null)); + assertThrows(IllegalArgumentException.class, () -> Average.average(new double[0])); } @Test - public void testAverageInt() { - int[] numbers = {2, 4, 10}; - Assertions.assertEquals(5, Average.average(numbers)); + void testAverageIntThrowsExceptionOnNullOrEmpty() { + assertThrows(IllegalArgumentException.class, () -> Average.average((int[]) null)); + assertThrows(IllegalArgumentException.class, () -> Average.average(new int[0])); + } + + private static Stream provideDoubleArrays() { + return Stream.of(Arguments.of(new double[] {3d, 6d, 9d, 12d, 15d, 18d, 21d}, 12d), Arguments.of(new double[] {5d, 10d, 15d, 20d, 25d, 30d, 35d}, 20d), Arguments.of(new double[] {1d, 2d, 3d, 4d, 5d, 6d, 7d, 8d}, 4.5d), Arguments.of(new double[] {0d, 0d, 0d}, 0d), + Arguments.of(new double[] {-1d, -2d, -3d}, -2d), Arguments.of(new double[] {1e-10, 1e-10, 1e-10}, 1e-10)); + } + + private static Stream provideIntArrays() { + return Stream.of(Arguments.of(new int[] {2, 4, 10}, 5L), Arguments.of(new int[] {0, 0, 0}, 0L), Arguments.of(new int[] {-1, -2, -3}, -2L), Arguments.of(new int[] {1, 1, 1, 1, 1}, 1L)); } } diff --git a/src/test/java/com/thealgorithms/maths/BinaryPowTest.java b/src/test/java/com/thealgorithms/maths/BinaryPowTest.java index f9b019e8fad4..632dfbd1d65e 100644 --- a/src/test/java/com/thealgorithms/maths/BinaryPowTest.java +++ b/src/test/java/com/thealgorithms/maths/BinaryPowTest.java @@ -13,4 +13,34 @@ void testBinPow() { assertEquals(729, BinaryPow.binPow(9, 3)); assertEquals(262144, BinaryPow.binPow(8, 6)); } + + @Test + void testZeroExponent() { + assertEquals(1, BinaryPow.binPow(2, 0)); + assertEquals(1, BinaryPow.binPow(100, 0)); + assertEquals(1, BinaryPow.binPow(-5, 0)); + } + + @Test + void testZeroBase() { + assertEquals(0, BinaryPow.binPow(0, 5)); + assertEquals(1, BinaryPow.binPow(0, 0)); + } + + @Test + void testOneBase() { + assertEquals(1, BinaryPow.binPow(1, 100)); + assertEquals(1, BinaryPow.binPow(1, 0)); + } + + @Test + void testNegativeBase() { + assertEquals(-8, BinaryPow.binPow(-2, 3)); + assertEquals(16, BinaryPow.binPow(-2, 4)); + } + + @Test + void testLargeExponent() { + assertEquals(1073741824, BinaryPow.binPow(2, 30)); + } } diff --git a/src/test/java/com/thealgorithms/maths/CeilTest.java b/src/test/java/com/thealgorithms/maths/CeilTest.java index 5596760a8c40..ddd0deed41d3 100644 --- a/src/test/java/com/thealgorithms/maths/CeilTest.java +++ b/src/test/java/com/thealgorithms/maths/CeilTest.java @@ -2,16 +2,30 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.jupiter.api.Test; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.MethodSource; public class CeilTest { - @Test - void testCeil() { - assertEquals(8, Ceil.ceil(7.057)); - assertEquals(8, Ceil.ceil(7.004)); - assertEquals(-13, Ceil.ceil(-13.004)); - assertEquals(1, Ceil.ceil(.98)); - assertEquals(-11, Ceil.ceil(-11.357)); + @ParameterizedTest + @CsvSource({"7.057, 8", "7.004, 8", "-13.004, -13", "0.98, 1", "-11.357, -11"}) + void testCeil(double input, int expected) { + assertEquals(expected, Ceil.ceil(input)); + } + + @ParameterizedTest + @MethodSource("edgeCaseProvider") + void testEdgeCases(TestData data) { + assertEquals(Ceil.ceil(data.input), data.expected); + } + + record TestData(double input, double expected) { + } + + static Stream edgeCaseProvider() { + return Stream.of(new TestData(Double.MAX_VALUE, Double.MAX_VALUE), new TestData(Double.MIN_VALUE, Math.ceil(Double.MIN_VALUE)), new TestData(0.0, Math.ceil(0.0)), new TestData(-0.0, Math.ceil(-0.0)), new TestData(Double.NaN, Math.ceil(Double.NaN)), + new TestData(Double.NEGATIVE_INFINITY, Math.ceil(Double.NEGATIVE_INFINITY)), new TestData(Double.POSITIVE_INFINITY, Math.ceil(Double.POSITIVE_INFINITY))); } } diff --git a/src/test/java/com/thealgorithms/maths/GoldbachConjectureTest.java b/src/test/java/com/thealgorithms/maths/GoldbachConjectureTest.java new file mode 100644 index 000000000000..84c5824d26ae --- /dev/null +++ b/src/test/java/com/thealgorithms/maths/GoldbachConjectureTest.java @@ -0,0 +1,29 @@ +package com.thealgorithms.maths; + +import static com.thealgorithms.maths.GoldbachConjecture.getPrimeSum; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +public class GoldbachConjectureTest { + @Test + void testValidEvenNumbers() { + assertEquals(new GoldbachConjecture.Result(3, 7), getPrimeSum(10)); // 10 = 3 + 7 + assertEquals(new GoldbachConjecture.Result(5, 7), getPrimeSum(12)); // 12 = 5 + 7 + assertEquals(new GoldbachConjecture.Result(3, 11), getPrimeSum(14)); // 14 = 3 + 11 + assertEquals(new GoldbachConjecture.Result(5, 13), getPrimeSum(18)); // 18 = 5 + 13 + } + @Test + void testInvalidOddNumbers() { + assertThrows(IllegalArgumentException.class, () -> getPrimeSum(7)); + assertThrows(IllegalArgumentException.class, () -> getPrimeSum(15)); + } + @Test + void testLesserThanTwo() { + assertThrows(IllegalArgumentException.class, () -> getPrimeSum(1)); + assertThrows(IllegalArgumentException.class, () -> getPrimeSum(2)); + assertThrows(IllegalArgumentException.class, () -> getPrimeSum(-5)); + assertThrows(IllegalArgumentException.class, () -> getPrimeSum(-26)); + } +} diff --git a/src/test/java/com/thealgorithms/maths/MathBuilderTest.java b/src/test/java/com/thealgorithms/maths/MathBuilderTest.java new file mode 100644 index 000000000000..dc381bfca5d3 --- /dev/null +++ b/src/test/java/com/thealgorithms/maths/MathBuilderTest.java @@ -0,0 +1,52 @@ +package com.thealgorithms.maths; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class MathBuilderTest { + + @Test + void simpleMath() { + double result = new MathBuilder.Builder(100).add(200).multiply(10).print().divideIf(20, (a, b) -> a % 2 == 0).sqrt().print().ceil().build().get(); + assertEquals(13, result); + } + + @Test + void memoryTest() { + long result = new MathBuilder.Builder().set(100).sqrt().remember().add(21).recallIf(a -> a < 50, true).mod(2).build().toLong(); + assertEquals(0, result); + } + + @Test + void freeFallDistance() { + long distance = new MathBuilder.Builder(9.81).multiply(0.5).multiply(5 * 5).round().build().toLong(); + assertEquals(123, distance); // Expected result: 0.5 * 9.81 * 25 = 122.625 ≈ 123 + } + + @Test + void batchSalaryProcessing() { + double[] salaries = {2000, 3000, 4000, 5000}; + long[] processedSalaries = new long[salaries.length]; + for (int i = 0; i < salaries.length; i++) { + processedSalaries[i] = new MathBuilder.Builder(salaries[i]).addIf(salaries[i] * 0.1, (sal, bonus) -> sal > 2500).multiply(0.92).round().build().toLong(); + } + long[] expectedSalaries = {1840, 3036, 4048, 5060}; + assertArrayEquals(expectedSalaries, processedSalaries); + } + + @Test + void parenthesis() { + // 10 + (20*5) - 40 + (100 / 10) = 80 + double result = new MathBuilder.Builder(10).openParenthesis(20).multiply(5).closeParenthesisAndPlus().minus(40).openParenthesis(100).divide(10).closeParenthesisAndPlus().build().get(); + assertEquals(80, result); + } + + @Test + void areaOfCircle() { + // Radius is 4 + double area = new MathBuilder.Builder().pi().openParenthesis(4).multiply(4).closeParenthesisAndMultiply().build().get(); + assertEquals(Math.PI * 4 * 4, area); + } +} diff --git a/src/test/java/com/thealgorithms/maths/MedianTest.java b/src/test/java/com/thealgorithms/maths/MedianTest.java index d2b637abd3cb..560feb695792 100644 --- a/src/test/java/com/thealgorithms/maths/MedianTest.java +++ b/src/test/java/com/thealgorithms/maths/MedianTest.java @@ -1,6 +1,7 @@ package com.thealgorithms.maths; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.Test; @@ -34,4 +35,10 @@ void medianNegativeValues() { int[] arr = {-27, -16, -7, -4, -2, -1}; assertEquals(-5.5, Median.median(arr)); } + + @Test + void medianEmptyArrayThrows() { + int[] arr = {}; + assertThrows(IllegalArgumentException.class, () -> Median.median(arr)); + } } diff --git a/src/test/java/com/thealgorithms/maths/NumberOfDigitsTest.java b/src/test/java/com/thealgorithms/maths/NumberOfDigitsTest.java index 799052b22d83..153ab3347f1e 100644 --- a/src/test/java/com/thealgorithms/maths/NumberOfDigitsTest.java +++ b/src/test/java/com/thealgorithms/maths/NumberOfDigitsTest.java @@ -8,6 +8,7 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +@SuppressWarnings({"rawtypes", "unchecked"}) public class NumberOfDigitsTest { @ParameterizedTest diff --git a/src/test/java/com/thealgorithms/maths/PythagoreanTripleTest.java b/src/test/java/com/thealgorithms/maths/PythagoreanTripleTest.java index 13ea58155dec..75219dc47b47 100644 --- a/src/test/java/com/thealgorithms/maths/PythagoreanTripleTest.java +++ b/src/test/java/com/thealgorithms/maths/PythagoreanTripleTest.java @@ -1,22 +1,24 @@ package com.thealgorithms.maths; -import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; public class PythagoreanTripleTest { + @ParameterizedTest + @CsvSource({"3, 4, 5, true", "6, 8, 10, true", "9, 12, 15, true", "12, 16, 20, true", "15, 20, 25, true", "18, 24, 30, true", "5, 20, 30, false", "6, 8, 100, false", "-2, -2, 2, false", "0, 0, 0, false", "5, 5, 5, false"}) + void testIsPythagoreanTriple(int a, int b, int c, boolean expected) { + assertEquals(expected, PythagoreanTriple.isPythagTriple(a, b, c)); + } + @Test - public void testPythagoreanTriple() { - assertTrue(PythagoreanTriple.isPythagTriple(3, 4, 5)); - assertTrue(PythagoreanTriple.isPythagTriple(6, 8, 10)); - assertTrue(PythagoreanTriple.isPythagTriple(9, 12, 15)); - assertTrue(PythagoreanTriple.isPythagTriple(12, 16, 20)); - assertTrue(PythagoreanTriple.isPythagTriple(15, 20, 25)); - assertTrue(PythagoreanTriple.isPythagTriple(18, 24, 30)); - assertFalse(PythagoreanTriple.isPythagTriple(5, 20, 30)); - assertFalse(PythagoreanTriple.isPythagTriple(6, 8, 100)); - assertFalse(PythagoreanTriple.isPythagTriple(-2, -2, 2)); + void testUnorderedInputStillValid() { + // Should still detect Pythagorean triples regardless of argument order + assertTrue(PythagoreanTriple.isPythagTriple(5, 3, 4)); + assertTrue(PythagoreanTriple.isPythagTriple(13, 12, 5)); } } diff --git a/src/test/java/com/thealgorithms/maths/SquareFreeIntegerTest.java b/src/test/java/com/thealgorithms/maths/SquareFreeIntegerTest.java index d7e16e02602b..5b35ee7bd9d0 100644 --- a/src/test/java/com/thealgorithms/maths/SquareFreeIntegerTest.java +++ b/src/test/java/com/thealgorithms/maths/SquareFreeIntegerTest.java @@ -3,6 +3,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import com.thealgorithms.maths.Prime.SquareFreeInteger; import java.util.List; import org.junit.jupiter.api.Test; diff --git a/src/test/java/com/thealgorithms/maths/LiouvilleLambdaFunctionTest.java b/src/test/java/com/thealgorithms/maths/prime/LiouvilleLambdaFunctionTest.java similarity index 94% rename from src/test/java/com/thealgorithms/maths/LiouvilleLambdaFunctionTest.java rename to src/test/java/com/thealgorithms/maths/prime/LiouvilleLambdaFunctionTest.java index a2763047acf0..d32815c0b8a9 100644 --- a/src/test/java/com/thealgorithms/maths/LiouvilleLambdaFunctionTest.java +++ b/src/test/java/com/thealgorithms/maths/prime/LiouvilleLambdaFunctionTest.java @@ -1,8 +1,9 @@ -package com.thealgorithms.maths; +package com.thealgorithms.maths.prime; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import com.thealgorithms.maths.Prime.LiouvilleLambdaFunction; import org.junit.jupiter.api.Test; class LiouvilleLambdaFunctionTest { diff --git a/src/test/java/com/thealgorithms/maths/MillerRabinPrimalityCheckTest.java b/src/test/java/com/thealgorithms/maths/prime/MillerRabinPrimalityCheckTest.java similarity index 92% rename from src/test/java/com/thealgorithms/maths/MillerRabinPrimalityCheckTest.java rename to src/test/java/com/thealgorithms/maths/prime/MillerRabinPrimalityCheckTest.java index d547cecf24cd..4defcd587758 100644 --- a/src/test/java/com/thealgorithms/maths/MillerRabinPrimalityCheckTest.java +++ b/src/test/java/com/thealgorithms/maths/prime/MillerRabinPrimalityCheckTest.java @@ -1,8 +1,9 @@ -package com.thealgorithms.maths; +package com.thealgorithms.maths.prime; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import com.thealgorithms.maths.Prime.MillerRabinPrimalityCheck; import org.junit.jupiter.api.Test; class MillerRabinPrimalityCheckTest { diff --git a/src/test/java/com/thealgorithms/maths/MobiusFunctionTest.java b/src/test/java/com/thealgorithms/maths/prime/MobiusFunctionTest.java similarity index 96% rename from src/test/java/com/thealgorithms/maths/MobiusFunctionTest.java rename to src/test/java/com/thealgorithms/maths/prime/MobiusFunctionTest.java index f3a6514ce633..734d02477ba2 100644 --- a/src/test/java/com/thealgorithms/maths/MobiusFunctionTest.java +++ b/src/test/java/com/thealgorithms/maths/prime/MobiusFunctionTest.java @@ -1,8 +1,9 @@ -package com.thealgorithms.maths; +package com.thealgorithms.maths.prime; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import com.thealgorithms.maths.Prime.MobiusFunction; import org.junit.jupiter.api.Test; class MobiusFunctionTest { diff --git a/src/test/java/com/thealgorithms/maths/PrimeCheckTest.java b/src/test/java/com/thealgorithms/maths/prime/PrimeCheckTest.java similarity index 89% rename from src/test/java/com/thealgorithms/maths/PrimeCheckTest.java rename to src/test/java/com/thealgorithms/maths/prime/PrimeCheckTest.java index c3e1634c51fe..2182bcd9cb16 100644 --- a/src/test/java/com/thealgorithms/maths/PrimeCheckTest.java +++ b/src/test/java/com/thealgorithms/maths/prime/PrimeCheckTest.java @@ -1,5 +1,6 @@ -package com.thealgorithms.maths; +package com.thealgorithms.maths.prime; +import com.thealgorithms.maths.Prime.PrimeCheck; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/src/test/java/com/thealgorithms/maths/PrimeFactorizationTest.java b/src/test/java/com/thealgorithms/maths/prime/PrimeFactorizationTest.java similarity index 93% rename from src/test/java/com/thealgorithms/maths/PrimeFactorizationTest.java rename to src/test/java/com/thealgorithms/maths/prime/PrimeFactorizationTest.java index 6994379d736a..79d685726261 100644 --- a/src/test/java/com/thealgorithms/maths/PrimeFactorizationTest.java +++ b/src/test/java/com/thealgorithms/maths/prime/PrimeFactorizationTest.java @@ -1,7 +1,8 @@ -package com.thealgorithms.maths; +package com.thealgorithms.maths.prime; import static org.junit.jupiter.api.Assertions.assertEquals; +import com.thealgorithms.maths.Prime.PrimeFactorization; import java.util.List; import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; diff --git a/src/test/java/com/thealgorithms/misc/InverseOfMatrixTest.java b/src/test/java/com/thealgorithms/matrix/InverseOfMatrixTest.java similarity index 96% rename from src/test/java/com/thealgorithms/misc/InverseOfMatrixTest.java rename to src/test/java/com/thealgorithms/matrix/InverseOfMatrixTest.java index 2f20de444315..930fb377cd32 100644 --- a/src/test/java/com/thealgorithms/misc/InverseOfMatrixTest.java +++ b/src/test/java/com/thealgorithms/matrix/InverseOfMatrixTest.java @@ -1,5 +1,4 @@ -package com.thealgorithms.misc; - +package com.thealgorithms.matrix; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import java.util.stream.Stream; diff --git a/src/test/java/com/thealgorithms/matrix/MatrixMultiplicationTest.java b/src/test/java/com/thealgorithms/matrix/MatrixMultiplicationTest.java new file mode 100644 index 000000000000..9463d33a18cb --- /dev/null +++ b/src/test/java/com/thealgorithms/matrix/MatrixMultiplicationTest.java @@ -0,0 +1,101 @@ +package com.thealgorithms.matrix; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +public class MatrixMultiplicationTest { + + private static final double EPSILON = 1e-9; // for floating point comparison + + @Test + void testMultiply1by1() { + double[][] matrixA = {{1.0}}; + double[][] matrixB = {{2.0}}; + double[][] expected = {{2.0}}; + + double[][] result = MatrixMultiplication.multiply(matrixA, matrixB); + assertMatrixEquals(expected, result); + } + + @Test + void testMultiply2by2() { + double[][] matrixA = {{1.0, 2.0}, {3.0, 4.0}}; + double[][] matrixB = {{5.0, 6.0}, {7.0, 8.0}}; + double[][] expected = {{19.0, 22.0}, {43.0, 50.0}}; + + double[][] result = MatrixMultiplication.multiply(matrixA, matrixB); + assertMatrixEquals(expected, result); // Use custom method due to floating point issues + } + + @Test + void testMultiply3by2and2by1() { + double[][] matrixA = {{1.0, 2.0}, {3.0, 4.0}, {5.0, 6.0}}; + double[][] matrixB = {{7.0}, {8.0}}; + double[][] expected = {{23.0}, {53.0}, {83.0}}; + + double[][] result = MatrixMultiplication.multiply(matrixA, matrixB); + assertMatrixEquals(expected, result); + } + + @Test + void testMultiplyNonRectangularMatrices() { + double[][] matrixA = {{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}}; + double[][] matrixB = {{7.0, 8.0}, {9.0, 10.0}, {11.0, 12.0}}; + double[][] expected = {{58.0, 64.0}, {139.0, 154.0}}; + + double[][] result = MatrixMultiplication.multiply(matrixA, matrixB); + assertMatrixEquals(expected, result); + } + + @Test + void testNullMatrixA() { + double[][] b = {{1, 2}, {3, 4}}; + assertThrows(IllegalArgumentException.class, () -> MatrixMultiplication.multiply(null, b)); + } + + @Test + void testNullMatrixB() { + double[][] a = {{1, 2}, {3, 4}}; + assertThrows(IllegalArgumentException.class, () -> MatrixMultiplication.multiply(a, null)); + } + + @Test + void testMultiplyNull() { + double[][] matrixA = {{1.0, 2.0}, {3.0, 4.0}}; + double[][] matrixB = null; + + Exception exception = assertThrows(IllegalArgumentException.class, () -> MatrixMultiplication.multiply(matrixA, matrixB)); + + String expectedMessage = "Input matrices cannot be null"; + String actualMessage = exception.getMessage(); + + assertTrue(actualMessage.contains(expectedMessage)); + } + + @Test + void testIncompatibleDimensions() { + double[][] a = {{1.0, 2.0}}; + double[][] b = {{1.0, 2.0}}; + assertThrows(IllegalArgumentException.class, () -> MatrixMultiplication.multiply(a, b)); + } + + @Test + void testEmptyMatrices() { + double[][] a = new double[0][0]; + double[][] b = new double[0][0]; + assertThrows(IllegalArgumentException.class, () -> MatrixMultiplication.multiply(a, b)); + } + + private void assertMatrixEquals(double[][] expected, double[][] actual) { + assertEquals(expected.length, actual.length, "Row count mismatch"); + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i].length, actual[i].length, "Column count mismatch at row " + i); + for (int j = 0; j < expected[i].length; j++) { + assertEquals(expected[i][j], actual[i][j], EPSILON, "Mismatch at (" + i + "," + j + ")"); + } + } + } +} diff --git a/src/test/java/com/thealgorithms/maths/MatrixRankTest.java b/src/test/java/com/thealgorithms/matrix/MatrixRankTest.java similarity index 98% rename from src/test/java/com/thealgorithms/maths/MatrixRankTest.java rename to src/test/java/com/thealgorithms/matrix/MatrixRankTest.java index 415b84ec43f8..33a0196b7bf7 100644 --- a/src/test/java/com/thealgorithms/maths/MatrixRankTest.java +++ b/src/test/java/com/thealgorithms/matrix/MatrixRankTest.java @@ -1,4 +1,4 @@ -package com.thealgorithms.maths; +package com.thealgorithms.matrix; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/com/thealgorithms/misc/MatrixTransposeTest.java b/src/test/java/com/thealgorithms/matrix/MatrixTransposeTest.java similarity index 98% rename from src/test/java/com/thealgorithms/misc/MatrixTransposeTest.java rename to src/test/java/com/thealgorithms/matrix/MatrixTransposeTest.java index cf668807b819..0457f31418cf 100644 --- a/src/test/java/com/thealgorithms/misc/MatrixTransposeTest.java +++ b/src/test/java/com/thealgorithms/matrix/MatrixTransposeTest.java @@ -1,4 +1,4 @@ -package com.thealgorithms.misc; +package com.thealgorithms.matrix; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/src/test/java/com/thealgorithms/maths/MatrixUtilTest.java b/src/test/java/com/thealgorithms/matrix/MatrixUtilTest.java similarity index 96% rename from src/test/java/com/thealgorithms/maths/MatrixUtilTest.java rename to src/test/java/com/thealgorithms/matrix/MatrixUtilTest.java index b954e6ff7511..78947b1e70cb 100644 --- a/src/test/java/com/thealgorithms/maths/MatrixUtilTest.java +++ b/src/test/java/com/thealgorithms/matrix/MatrixUtilTest.java @@ -1,7 +1,8 @@ -package com.thealgorithms.maths; +package com.thealgorithms.matrix; import static org.junit.jupiter.api.Assertions.assertTrue; +import com.thealgorithms.matrix.utils.MatrixUtil; import java.math.BigDecimal; import java.util.Objects; import org.junit.jupiter.api.Test; diff --git a/src/test/java/com/thealgorithms/misc/MedianOfMatrixTest.java b/src/test/java/com/thealgorithms/matrix/MedianOfMatrixTest.java similarity index 58% rename from src/test/java/com/thealgorithms/misc/MedianOfMatrixTest.java rename to src/test/java/com/thealgorithms/matrix/MedianOfMatrixTest.java index 19bc66857ae6..b9b97014f3fc 100644 --- a/src/test/java/com/thealgorithms/misc/MedianOfMatrixTest.java +++ b/src/test/java/com/thealgorithms/matrix/MedianOfMatrixTest.java @@ -1,9 +1,11 @@ -package com.thealgorithms.misc; +package com.thealgorithms.matrix; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.junit.jupiter.api.Test; @@ -31,4 +33,18 @@ public void testMedianWithEvenNumberOfElements() { assertEquals(2, result); } + + @Test + public void testMedianSingleElement() { + List> matrix = new ArrayList<>(); + matrix.add(List.of(1)); + + assertEquals(1, MedianOfMatrix.median(matrix)); + } + + @Test + void testEmptyMatrixThrowsException() { + Iterable> emptyMatrix = Collections.emptyList(); + assertThrows(IllegalArgumentException.class, () -> MedianOfMatrix.median(emptyMatrix), "Expected median() to throw, but it didn't"); + } } diff --git a/src/test/java/com/thealgorithms/matrix/MirrorOfMatrixTest.java b/src/test/java/com/thealgorithms/matrix/MirrorOfMatrixTest.java new file mode 100644 index 000000000000..2e4370922370 --- /dev/null +++ b/src/test/java/com/thealgorithms/matrix/MirrorOfMatrixTest.java @@ -0,0 +1,53 @@ +package com.thealgorithms.matrix; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +class MirrorOfMatrixTest { + + @Test + void testMirrorMatrixRegularMatrix() { + double[][] originalMatrix = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + double[][] expectedMirrorMatrix = {{3, 2, 1}, {6, 5, 4}, {9, 8, 7}}; + double[][] mirroredMatrix = MirrorOfMatrix.mirrorMatrix(originalMatrix); + assertArrayEquals(expectedMirrorMatrix, mirroredMatrix); + } + + @Test + void testMirrorMatrixEmptyMatrix() { + double[][] originalMatrix = {}; + Exception e = assertThrows(IllegalArgumentException.class, () -> MirrorOfMatrix.mirrorMatrix(originalMatrix)); + assertEquals("The input matrix cannot be empty", e.getMessage()); + } + + @Test + void testMirrorMatrixSingleElementMatrix() { + double[][] originalMatrix = {{42}}; + double[][] expectedMirrorMatrix = {{42}}; + double[][] mirroredMatrix = MirrorOfMatrix.mirrorMatrix(originalMatrix); + assertArrayEquals(expectedMirrorMatrix, mirroredMatrix); + } + + @Test + void testMirrorMatrixMultipleRowsOneColumnMatrix() { + double[][] originalMatrix = {{1}, {2}, {3}, {4}}; + double[][] expectedMirrorMatrix = {{1}, {2}, {3}, {4}}; + double[][] mirroredMatrix = MirrorOfMatrix.mirrorMatrix(originalMatrix); + assertArrayEquals(expectedMirrorMatrix, mirroredMatrix); + } + + @Test + void testMirrorMatrixNullInput() { + double[][] originalMatrix = null; + Exception e = assertThrows(IllegalArgumentException.class, () -> MirrorOfMatrix.mirrorMatrix(originalMatrix)); + assertEquals("The input matrix cannot be null", e.getMessage()); + } + + @Test + void testMirrorMatrixThrows() { + assertThrows(IllegalArgumentException.class, () -> MirrorOfMatrix.mirrorMatrix(new double[][] {{1}, {2, 3}})); + } +} diff --git a/src/test/java/com/thealgorithms/matrix/SolveSystemTest.java b/src/test/java/com/thealgorithms/matrix/SolveSystemTest.java new file mode 100644 index 000000000000..c8d289bd8339 --- /dev/null +++ b/src/test/java/com/thealgorithms/matrix/SolveSystemTest.java @@ -0,0 +1,21 @@ +package com.thealgorithms.matrix; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +class SolveSystemTest { + + @ParameterizedTest + @MethodSource({"matrixGenerator"}) + void solveSystem(double[][] matrix, double[] constants, double[] solution) { + double[] expected = SolveSystem.solveSystem(matrix, constants); + assertArrayEquals(expected, solution, 1.0E-10, "Solution does not match expected"); + } + private static Stream matrixGenerator() { + return Stream.of(Arguments.of(new double[][] {{-5, 8, -4}, {0, 6, 3}, {0, 0, -4}}, new double[] {38, -9, 20}, new double[] {-2, 1, -5}), Arguments.of(new double[][] {{-2, -1, -1}, {3, 4, 1}, {3, 6, 5}}, new double[] {-11, 19, 43}, new double[] {2, 2, 5})); + } +} diff --git a/src/test/java/com/thealgorithms/matrix/TestPrintMatrixInSpiralOrder.java b/src/test/java/com/thealgorithms/matrix/TestPrintMatrixInSpiralOrder.java new file mode 100644 index 000000000000..bb415a5861a8 --- /dev/null +++ b/src/test/java/com/thealgorithms/matrix/TestPrintMatrixInSpiralOrder.java @@ -0,0 +1,26 @@ +package com.thealgorithms.matrix; + +import static org.junit.jupiter.api.Assertions.assertIterableEquals; + +import java.util.List; +import org.junit.jupiter.api.Test; + +public class TestPrintMatrixInSpiralOrder { + @Test + public void testOne() { + int[][] matrix = {{3, 4, 5, 6, 7}, {8, 9, 10, 11, 12}, {14, 15, 16, 17, 18}, {23, 24, 25, 26, 27}, {30, 31, 32, 33, 34}}; + var printClass = new PrintAMatrixInSpiralOrder(); + List res = printClass.print(matrix, matrix.length, matrix[0].length); + List list = List.of(3, 4, 5, 6, 7, 12, 18, 27, 34, 33, 32, 31, 30, 23, 14, 8, 9, 10, 11, 17, 26, 25, 24, 15, 16); + assertIterableEquals(res, list); + } + + @Test + public void testTwo() { + int[][] matrix = {{2, 2}}; + var printClass = new PrintAMatrixInSpiralOrder(); + List res = printClass.print(matrix, matrix.length, matrix[0].length); + List list = List.of(2, 2); + assertIterableEquals(res, list); + } +} diff --git a/src/test/java/com/thealgorithms/misc/MapReduceTest.java b/src/test/java/com/thealgorithms/misc/MapReduceTest.java index c79c40701cc1..748dd0a563cf 100644 --- a/src/test/java/com/thealgorithms/misc/MapReduceTest.java +++ b/src/test/java/com/thealgorithms/misc/MapReduceTest.java @@ -2,22 +2,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; public class MapReduceTest { - @Test - public void testMapReduceWithSingleWordSentence() { - String oneWordSentence = "Hactober"; - String result = MapReduce.mapreduce(oneWordSentence); - - assertEquals("Hactober: 1", result); - } - - @Test - public void testMapReduceWithMultipleWordSentence() { - String multipleWordSentence = "I Love Love HactoberFest"; - String result = MapReduce.mapreduce(multipleWordSentence); - - assertEquals("I: 1,Love: 2,HactoberFest: 1", result); + @ParameterizedTest + @CsvSource({"'hello world', 'hello: 1,world: 1'", "'one one two', 'one: 2,two: 1'", "'a a a a', 'a: 4'", "' spaced out ', 'spaced: 1,out: 1'"}) + void testCountWordFrequencies(String input, String expected) { + String result = MapReduce.countWordFrequencies(input); + assertEquals(expected, result); } } diff --git a/src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java b/src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java index e64ae1b741b6..f41953035846 100644 --- a/src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java +++ b/src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java @@ -11,12 +11,12 @@ */ public class MedianOfRunningArrayTest { - private static final String EXCEPTION_MESSAGE = "Enter at least 1 element, Median of empty list is not defined!"; + private static final String EXCEPTION_MESSAGE = "Median is undefined for an empty data set."; @Test public void testWhenInvalidInoutProvidedShouldThrowException() { var stream = new MedianOfRunningArrayInteger(); - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> stream.median()); + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, stream::getMedian); assertEquals(exception.getMessage(), EXCEPTION_MESSAGE); } @@ -24,68 +24,68 @@ public void testWhenInvalidInoutProvidedShouldThrowException() { public void testWithNegativeValues() { var stream = new MedianOfRunningArrayInteger(); stream.insert(-1); - assertEquals(-1, stream.median()); + assertEquals(-1, stream.getMedian()); stream.insert(-2); - assertEquals(-1, stream.median()); + assertEquals(-1, stream.getMedian()); stream.insert(-3); - assertEquals(-2, stream.median()); + assertEquals(-2, stream.getMedian()); } @Test public void testWithSingleValues() { var stream = new MedianOfRunningArrayInteger(); stream.insert(-1); - assertEquals(-1, stream.median()); + assertEquals(-1, stream.getMedian()); } @Test public void testWithRandomValues() { var stream = new MedianOfRunningArrayInteger(); stream.insert(10); - assertEquals(10, stream.median()); + assertEquals(10, stream.getMedian()); stream.insert(5); - assertEquals(7, stream.median()); + assertEquals(7, stream.getMedian()); stream.insert(20); - assertEquals(10, stream.median()); + assertEquals(10, stream.getMedian()); stream.insert(15); - assertEquals(12, stream.median()); + assertEquals(12, stream.getMedian()); stream.insert(25); - assertEquals(15, stream.median()); + assertEquals(15, stream.getMedian()); stream.insert(30); - assertEquals(17, stream.median()); + assertEquals(17, stream.getMedian()); stream.insert(35); - assertEquals(20, stream.median()); + assertEquals(20, stream.getMedian()); stream.insert(1); - assertEquals(17, stream.median()); + assertEquals(17, stream.getMedian()); } @Test public void testWithNegativeAndPositiveValues() { var stream = new MedianOfRunningArrayInteger(); stream.insert(-1); - assertEquals(-1, stream.median()); + assertEquals(-1, stream.getMedian()); stream.insert(2); - assertEquals(0, stream.median()); + assertEquals(0, stream.getMedian()); stream.insert(-3); - assertEquals(-1, stream.median()); + assertEquals(-1, stream.getMedian()); } @Test public void testWithDuplicateValues() { var stream = new MedianOfRunningArrayInteger(); stream.insert(-1); - assertEquals(-1, stream.median()); + assertEquals(-1, stream.getMedian()); stream.insert(-1); - assertEquals(-1, stream.median()); + assertEquals(-1, stream.getMedian()); stream.insert(-1); - assertEquals(-1, stream.median()); + assertEquals(-1, stream.getMedian()); } @Test @@ -98,20 +98,20 @@ public void testWithDuplicateValuesB() { stream.insert(20); stream.insert(0); stream.insert(50); - assertEquals(10, stream.median()); + assertEquals(10, stream.getMedian()); } @Test public void testWithLargeValues() { var stream = new MedianOfRunningArrayInteger(); stream.insert(1000000); - assertEquals(1000000, stream.median()); + assertEquals(1000000, stream.getMedian()); stream.insert(12000); - assertEquals(506000, stream.median()); + assertEquals(506000, stream.getMedian()); stream.insert(15000000); - assertEquals(1000000, stream.median()); + assertEquals(1000000, stream.getMedian()); stream.insert(2300000); - assertEquals(1650000, stream.median()); + assertEquals(1650000, stream.getMedian()); } @Test @@ -120,7 +120,7 @@ public void testWithLargeCountOfValues() { for (int i = 1; i <= 1000; i++) { stream.insert(i); } - assertEquals(500, stream.median()); + assertEquals(500, stream.getMedian()); } @Test @@ -129,7 +129,7 @@ public void testWithThreeValuesInDescendingOrder() { stream.insert(30); stream.insert(20); stream.insert(10); - assertEquals(20, stream.median()); + assertEquals(20, stream.getMedian()); } @Test @@ -138,7 +138,7 @@ public void testWithThreeValuesInOrder() { stream.insert(10); stream.insert(20); stream.insert(30); - assertEquals(20, stream.median()); + assertEquals(20, stream.getMedian()); } @Test @@ -147,7 +147,7 @@ public void testWithThreeValuesNotInOrderA() { stream.insert(30); stream.insert(10); stream.insert(20); - assertEquals(20, stream.median()); + assertEquals(20, stream.getMedian()); } @Test @@ -156,46 +156,46 @@ public void testWithThreeValuesNotInOrderB() { stream.insert(20); stream.insert(10); stream.insert(30); - assertEquals(20, stream.median()); + assertEquals(20, stream.getMedian()); } @Test public void testWithFloatValues() { var stream = new MedianOfRunningArrayFloat(); stream.insert(20.0f); - assertEquals(20.0f, stream.median()); + assertEquals(20.0f, stream.getMedian()); stream.insert(10.5f); - assertEquals(15.25f, stream.median()); + assertEquals(15.25f, stream.getMedian()); stream.insert(30.0f); - assertEquals(20.0f, stream.median()); + assertEquals(20.0f, stream.getMedian()); } @Test public void testWithByteValues() { var stream = new MedianOfRunningArrayByte(); stream.insert((byte) 120); - assertEquals((byte) 120, stream.median()); + assertEquals((byte) 120, stream.getMedian()); stream.insert((byte) -120); - assertEquals((byte) 0, stream.median()); + assertEquals((byte) 0, stream.getMedian()); stream.insert((byte) 127); - assertEquals((byte) 120, stream.median()); + assertEquals((byte) 120, stream.getMedian()); } @Test public void testWithLongValues() { var stream = new MedianOfRunningArrayLong(); stream.insert(120000000L); - assertEquals(120000000L, stream.median()); + assertEquals(120000000L, stream.getMedian()); stream.insert(92233720368547757L); - assertEquals(46116860244273878L, stream.median()); + assertEquals(46116860244273878L, stream.getMedian()); } @Test public void testWithDoubleValues() { var stream = new MedianOfRunningArrayDouble(); stream.insert(12345.67891); - assertEquals(12345.67891, stream.median()); + assertEquals(12345.67891, stream.getMedian()); stream.insert(23456789.98); - assertEquals(11734567.83, stream.median(), .01); + assertEquals(11734567.83, stream.getMedian(), .01); } } diff --git a/src/test/java/com/thealgorithms/misc/MirrorOfMatrixTest.java b/src/test/java/com/thealgorithms/misc/MirrorOfMatrixTest.java deleted file mode 100644 index 0da0cf0f804a..000000000000 --- a/src/test/java/com/thealgorithms/misc/MirrorOfMatrixTest.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.thealgorithms.misc; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import org.junit.jupiter.api.Test; - -class MirrorOfMatrixTest { - - @Test - void testMirrorMatrixRegularMatrix() { - int[][] originalMatrix = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; - int[][] expectedMirrorMatrix = {{3, 2, 1}, {6, 5, 4}, {9, 8, 7}}; - int[][] mirroredMatrix = MirrorOfMatrix.mirrorMatrix(originalMatrix); - assertArrayEquals(expectedMirrorMatrix, mirroredMatrix); - } - - @Test - void testMirrorMatrixEmptyMatrix() { - int[][] originalMatrix = {}; - int[][] expectedMirrorMatrix = {}; - int[][] mirroredMatrix = MirrorOfMatrix.mirrorMatrix(originalMatrix); - assertArrayEquals(expectedMirrorMatrix, mirroredMatrix); - } - - @Test - void testMirrorMatrixSingleElementMatrix() { - int[][] originalMatrix = {{42}}; - int[][] expectedMirrorMatrix = {{42}}; - int[][] mirroredMatrix = MirrorOfMatrix.mirrorMatrix(originalMatrix); - assertArrayEquals(expectedMirrorMatrix, mirroredMatrix); - } - - @Test - void testMirrorMatrixMultipleRowsOneColumnMatrix() { - int[][] originalMatrix = {{1}, {2}, {3}, {4}}; - int[][] expectedMirrorMatrix = {{1}, {2}, {3}, {4}}; - int[][] mirroredMatrix = MirrorOfMatrix.mirrorMatrix(originalMatrix); - assertArrayEquals(expectedMirrorMatrix, mirroredMatrix); - } - - @Test - void testMirrorMatrixNullInput() { - int[][] originalMatrix = null; - assertNull(MirrorOfMatrix.mirrorMatrix(originalMatrix)); - } - - @Test - void testMirrotMarixThrows() { - assertThrows(IllegalArgumentException.class, () -> MirrorOfMatrix.mirrorMatrix(new int[][] {{1}, {2, 3}})); - } -} diff --git a/src/test/java/com/thealgorithms/misc/RangeInSortedArrayTest.java b/src/test/java/com/thealgorithms/misc/RangeInSortedArrayTest.java index 7630d3e78dc7..543c66130449 100644 --- a/src/test/java/com/thealgorithms/misc/RangeInSortedArrayTest.java +++ b/src/test/java/com/thealgorithms/misc/RangeInSortedArrayTest.java @@ -32,4 +32,26 @@ private static Stream provideGetCountLessThanTestCases() { return Stream.of(Arguments.of(new int[] {1, 2, 3, 3, 4, 5}, 3, 4, "Count of elements less than existing key"), Arguments.of(new int[] {1, 2, 3, 3, 4, 5}, 4, 5, "Count of elements less than non-existing key"), Arguments.of(new int[] {1, 2, 2, 3}, 5, 4, "Count with all smaller elements"), Arguments.of(new int[] {2, 3, 4, 5}, 1, 0, "Count with no smaller elements"), Arguments.of(new int[] {}, 1, 0, "Count in empty array")); } + + @ParameterizedTest(name = "Edge case {index}: {3}") + @MethodSource("provideEdgeCasesForSortedRange") + void testSortedRangeEdgeCases(int[] nums, int key, int[] expectedRange, String description) { + assertArrayEquals(expectedRange, RangeInSortedArray.sortedRange(nums, key), description); + } + + private static Stream provideEdgeCasesForSortedRange() { + return Stream.of(Arguments.of(new int[] {5, 5, 5, 5, 5}, 5, new int[] {0, 4}, "All elements same as key"), Arguments.of(new int[] {1, 2, 3, 4, 5}, 1, new int[] {0, 0}, "Key is first element"), Arguments.of(new int[] {1, 2, 3, 4, 5}, 5, new int[] {4, 4}, "Key is last element"), + Arguments.of(new int[] {1, 2, 3, 4, 5}, 0, new int[] {-1, -1}, "Key less than all elements"), Arguments.of(new int[] {1, 2, 3, 4, 5}, 6, new int[] {-1, -1}, "Key greater than all elements"), + Arguments.of(new int[] {1, 2, 2, 2, 3, 3, 3, 4}, 3, new int[] {4, 6}, "Multiple occurrences spread"), Arguments.of(new int[] {2}, 2, new int[] {0, 0}, "Single element array key exists"), Arguments.of(new int[] {2}, 3, new int[] {-1, -1}, "Single element array key missing")); + } + + @ParameterizedTest(name = "Edge case {index}: {3}") + @MethodSource("provideEdgeCasesForGetCountLessThan") + void testGetCountLessThanEdgeCases(int[] nums, int key, int expectedCount, String description) { + assertEquals(expectedCount, RangeInSortedArray.getCountLessThan(nums, key), description); + } + + private static Stream provideEdgeCasesForGetCountLessThan() { + return Stream.of(Arguments.of(new int[] {1, 2, 3, 4, 5}, 0, 0, "Key less than all elements"), Arguments.of(new int[] {1, 2, 3, 4, 5}, 6, 5, "Key greater than all elements"), Arguments.of(new int[] {1}, 0, 0, "Single element greater than key")); + } } diff --git a/src/test/java/com/thealgorithms/others/CRCAlgorithmTest.java b/src/test/java/com/thealgorithms/others/CRCAlgorithmTest.java index a581a35bf963..3dc61f2c6569 100644 --- a/src/test/java/com/thealgorithms/others/CRCAlgorithmTest.java +++ b/src/test/java/com/thealgorithms/others/CRCAlgorithmTest.java @@ -1,29 +1,163 @@ - package com.thealgorithms.others; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; public class CRCAlgorithmTest { @Test - void test1() { + void testNoErrorsWithZeroBER() { CRCAlgorithm c = new CRCAlgorithm("10010101010100101010010000001010010101010", 10, 0.0); + c.generateRandomMess(); + c.divideMessageWithP(false); + c.changeMess(); + c.divideMessageWithP(true); + assertEquals(0, c.getWrongMess(), "BER=0 should produce no wrong messages"); + assertEquals(0, c.getWrongMessCaught(), "No errors, so no caught wrong messages"); + assertEquals(0, c.getWrongMessNotCaught(), "No errors, so no uncaught wrong messages"); + assertTrue(c.getCorrectMess() > 0, "Should have some correct messages"); + } + + @Test + void testAllErrorsWithBEROne() { + CRCAlgorithm c = new CRCAlgorithm("10010101010100101010010000001010010101010", 10, 1.0); + c.generateRandomMess(); + c.divideMessageWithP(false); + c.changeMess(); + c.divideMessageWithP(true); + assertTrue(c.getWrongMess() > 0, "BER=1 should produce wrong messages"); + assertEquals(0, c.getCorrectMess(), "BER=1 should produce no correct messages"); + } + + @Test + void testIntermediateBER() { + CRCAlgorithm c = new CRCAlgorithm("1101", 4, 0.5); + c.generateRandomMess(); + for (int i = 0; i < 1000; i++) { + c.refactor(); + c.generateRandomMess(); + c.divideMessageWithP(false); + c.changeMess(); + c.divideMessageWithP(true); + } + assertTrue(c.getWrongMess() > 0, "Some wrong messages expected with BER=0.5"); + assertTrue(c.getWrongMessCaught() >= 0, "Wrong messages caught counter >= 0"); + assertTrue(c.getWrongMessNotCaught() >= 0, "Wrong messages not caught counter >= 0"); + assertTrue(c.getCorrectMess() >= 0, "Correct messages counter >= 0"); + assertEquals(c.getWrongMess(), c.getWrongMessCaught() + c.getWrongMessNotCaught(), "Sum of caught and not caught wrong messages should equal total wrong messages"); + } - // A bit-error rate of 0.0 should not provide any wrong messages + @Test + void testMessageChangedFlag() { + CRCAlgorithm c = new CRCAlgorithm("1010", 4, 1.0); + c.generateRandomMess(); + c.divideMessageWithP(false); c.changeMess(); + assertTrue(c.getWrongMess() > 0, "Message should be marked as changed with BER=1"); + } + + @Test + void testSmallMessageSize() { + CRCAlgorithm c = new CRCAlgorithm("11", 2, 0.0); + c.generateRandomMess(); c.divideMessageWithP(false); - assertEquals(c.getWrongMess(), 0); + c.changeMess(); + c.divideMessageWithP(true); + assertEquals(0, c.getWrongMess(), "No errors expected for BER=0 with small message"); } @Test - void test2() { - CRCAlgorithm c = new CRCAlgorithm("10010101010100101010010000001010010101010", 10, 1.0); + void testLargeMessageSize() { + CRCAlgorithm c = new CRCAlgorithm("1101", 1000, 0.01); + c.generateRandomMess(); + c.divideMessageWithP(false); + c.changeMess(); + c.divideMessageWithP(true); + // Just ensure counters are updated, no exceptions + assertTrue(c.getWrongMess() >= 0); + assertTrue(c.getCorrectMess() >= 0); + } + + @Test + void testSingleBitMessage() { + CRCAlgorithm c = new CRCAlgorithm("11", 1, 0.0); + c.generateRandomMess(); + c.divideMessageWithP(false); + c.changeMess(); + c.divideMessageWithP(true); + + assertTrue(c.getCorrectMess() >= 0, "Single bit message should be handled"); + } - // A bit error rate of 1.0 should not provide any correct messages + @Test + void testPolynomialLongerThanMessage() { + CRCAlgorithm c = new CRCAlgorithm("11010101", 3, 0.0); + c.generateRandomMess(); + c.divideMessageWithP(false); c.changeMess(); + c.divideMessageWithP(true); + + // Should not crash, counters should be valid + assertTrue(c.getCorrectMess() + c.getWrongMess() >= 0); + } + + @Test + void testPolynomialWithOnlyOnes() { + CRCAlgorithm c = new CRCAlgorithm("1111", 5, 0.1); + c.generateRandomMess(); c.divideMessageWithP(false); - assertEquals(c.getCorrectMess(), 0); + c.changeMess(); + c.divideMessageWithP(true); + + assertTrue(c.getCorrectMess() + c.getWrongMess() >= 0); + } + + @Test + void testMultipleRefactorCalls() { + CRCAlgorithm c = new CRCAlgorithm("1101", 5, 0.2); + + for (int i = 0; i < 5; i++) { + c.refactor(); + c.generateRandomMess(); + c.divideMessageWithP(false); + c.changeMess(); + c.divideMessageWithP(true); + } + + // Counters should accumulate across multiple runs + assertTrue(c.getCorrectMess() + c.getWrongMess() > 0); + } + + @Test + void testCounterConsistency() { + CRCAlgorithm c = new CRCAlgorithm("1101", 10, 0.3); + + for (int i = 0; i < 100; i++) { + c.refactor(); + c.generateRandomMess(); + c.divideMessageWithP(false); + c.changeMess(); + c.divideMessageWithP(true); + } + + // Total messages processed should equal correct + wrong + int totalProcessed = c.getCorrectMess() + c.getWrongMess(); + assertEquals(100, totalProcessed, "Total processed messages should equal iterations"); + + // Wrong messages should equal caught + not caught + assertEquals(c.getWrongMess(), c.getWrongMessCaught() + c.getWrongMessNotCaught(), "Wrong messages should equal sum of caught and not caught"); + } + + @Test + void testGetterMethodsInitialState() { + CRCAlgorithm c = new CRCAlgorithm("1101", 10, 0.1); + + // Check initial state + assertEquals(0, c.getCorrectMess(), "Initial correct messages should be 0"); + assertEquals(0, c.getWrongMess(), "Initial wrong messages should be 0"); + assertEquals(0, c.getWrongMessCaught(), "Initial caught wrong messages should be 0"); + assertEquals(0, c.getWrongMessNotCaught(), "Initial not caught wrong messages should be 0"); } } diff --git a/src/test/java/com/thealgorithms/others/TestPrintMatrixInSpiralOrder.java b/src/test/java/com/thealgorithms/others/TestPrintMatrixInSpiralOrder.java index 986e72ea45b5..d35d4bb60c73 100644 --- a/src/test/java/com/thealgorithms/others/TestPrintMatrixInSpiralOrder.java +++ b/src/test/java/com/thealgorithms/others/TestPrintMatrixInSpiralOrder.java @@ -1,26 +1,26 @@ -package com.thealgorithms.others; - -import static org.junit.jupiter.api.Assertions.assertIterableEquals; - -import java.util.List; -import org.junit.jupiter.api.Test; - -public class TestPrintMatrixInSpiralOrder { - @Test - public void testOne() { - int[][] matrix = {{3, 4, 5, 6, 7}, {8, 9, 10, 11, 12}, {14, 15, 16, 17, 18}, {23, 24, 25, 26, 27}, {30, 31, 32, 33, 34}}; - var printClass = new PrintAMatrixInSpiralOrder(); - List res = printClass.print(matrix, matrix.length, matrix[0].length); - List list = List.of(3, 4, 5, 6, 7, 12, 18, 27, 34, 33, 32, 31, 30, 23, 14, 8, 9, 10, 11, 17, 26, 25, 24, 15, 16); - assertIterableEquals(res, list); - } - - @Test - public void testTwo() { - int[][] matrix = {{2, 2}}; - var printClass = new PrintAMatrixInSpiralOrder(); - List res = printClass.print(matrix, matrix.length, matrix[0].length); - List list = List.of(2, 2); - assertIterableEquals(res, list); - } -} +package com.thealgorithms.others; + +import static org.junit.jupiter.api.Assertions.assertIterableEquals; + +import java.util.List; +import org.junit.jupiter.api.Test; + +public class TestPrintMatrixInSpiralOrder { + @Test + public void testOne() { + int[][] matrix = {{3, 4, 5, 6, 7}, {8, 9, 10, 11, 12}, {14, 15, 16, 17, 18}, {23, 24, 25, 26, 27}, {30, 31, 32, 33, 34}}; + var printClass = new PrintAMatrixInSpiralOrder(); + List res = printClass.print(matrix, matrix.length, matrix[0].length); + List list = List.of(3, 4, 5, 6, 7, 12, 18, 27, 34, 33, 32, 31, 30, 23, 14, 8, 9, 10, 11, 17, 26, 25, 24, 15, 16); + assertIterableEquals(res, list); + } + + @Test + public void testTwo() { + int[][] matrix = {{2, 2}}; + var printClass = new PrintAMatrixInSpiralOrder(); + List res = printClass.print(matrix, matrix.length, matrix[0].length); + List list = List.of(2, 2); + assertIterableEquals(res, list); + } +} diff --git a/src/test/java/com/thealgorithms/others/TwoPointersTest.java b/src/test/java/com/thealgorithms/others/TwoPointersTest.java index 3a174e0cd19e..6e0d2b22d280 100644 --- a/src/test/java/com/thealgorithms/others/TwoPointersTest.java +++ b/src/test/java/com/thealgorithms/others/TwoPointersTest.java @@ -1,6 +1,8 @@ package com.thealgorithms.others; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; @@ -69,4 +71,10 @@ void testPairExistsAtEdges() { int key = 9; assertTrue(TwoPointers.isPairedSum(arr, key)); } + + @Test + void isPairedSumShouldThrowExceptionWhenArrayIsNull() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> TwoPointers.isPairedSum(null, 10)); + assertEquals("Input array must not be null.", exception.getMessage()); + } } diff --git a/src/test/java/com/thealgorithms/others/SudokuTest.java b/src/test/java/com/thealgorithms/puzzlesandgames/SudokuTest.java similarity index 97% rename from src/test/java/com/thealgorithms/others/SudokuTest.java rename to src/test/java/com/thealgorithms/puzzlesandgames/SudokuTest.java index 5018b2768302..7fb96dcf805f 100644 --- a/src/test/java/com/thealgorithms/others/SudokuTest.java +++ b/src/test/java/com/thealgorithms/puzzlesandgames/SudokuTest.java @@ -1,4 +1,4 @@ -package com.thealgorithms.others; +package com.thealgorithms.puzzlesandgames; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; diff --git a/src/test/java/com/thealgorithms/others/TowerOfHanoiTest.java b/src/test/java/com/thealgorithms/puzzlesandgames/TowerOfHanoiTest.java similarity index 97% rename from src/test/java/com/thealgorithms/others/TowerOfHanoiTest.java rename to src/test/java/com/thealgorithms/puzzlesandgames/TowerOfHanoiTest.java index ca9376dd48eb..42669eb03bb4 100644 --- a/src/test/java/com/thealgorithms/others/TowerOfHanoiTest.java +++ b/src/test/java/com/thealgorithms/puzzlesandgames/TowerOfHanoiTest.java @@ -1,4 +1,4 @@ -package com.thealgorithms.others; +package com.thealgorithms.puzzlesandgames; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/src/test/java/com/thealgorithms/misc/WordBoggleTest.java b/src/test/java/com/thealgorithms/puzzlesandgames/WordBoggleTest.java similarity index 98% rename from src/test/java/com/thealgorithms/misc/WordBoggleTest.java rename to src/test/java/com/thealgorithms/puzzlesandgames/WordBoggleTest.java index 1d4ed7c5e737..ef5d3c92eb5e 100644 --- a/src/test/java/com/thealgorithms/misc/WordBoggleTest.java +++ b/src/test/java/com/thealgorithms/puzzlesandgames/WordBoggleTest.java @@ -1,4 +1,4 @@ -package com.thealgorithms.misc; +package com.thealgorithms.puzzlesandgames; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/src/test/java/com/thealgorithms/randomized/KargerMinCutTest.java b/src/test/java/com/thealgorithms/randomized/KargerMinCutTest.java new file mode 100644 index 000000000000..876b6bf45eaf --- /dev/null +++ b/src/test/java/com/thealgorithms/randomized/KargerMinCutTest.java @@ -0,0 +1,114 @@ +package com.thealgorithms.randomized; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class KargerMinCutTest { + + @Test + public void testSimpleGraph() { + // Graph: 0 -- 1 + Collection nodes = Arrays.asList(0, 1); + List edges = List.of(new int[] {0, 1}); + + KargerMinCut.KargerOutput result = KargerMinCut.findMinCut(nodes, edges); + + assertEquals(1, result.minCut()); + assertTrue(result.first().contains(0) || result.first().contains(1)); + assertTrue(result.second().contains(0) || result.second().contains(1)); + } + + @Test + public void testTriangleGraph() { + // Graph: 0 -- 1 -- 2 -- 0 + Collection nodes = Arrays.asList(0, 1, 2); + List edges = List.of(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 0}); + + KargerMinCut.KargerOutput result = KargerMinCut.findMinCut(nodes, edges); + + assertEquals(2, result.minCut()); + } + + @Test + public void testSquareGraph() { + // Graph: 0 -- 1 + // | | + // 3 -- 2 + Collection nodes = Arrays.asList(0, 1, 2, 3); + List edges = List.of(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 3}, new int[] {3, 0}); + + KargerMinCut.KargerOutput result = KargerMinCut.findMinCut(nodes, edges); + + assertEquals(2, result.minCut()); + } + + @Test + public void testDisconnectedGraph() { + // Graph: 0 -- 1 2 -- 3 + Collection nodes = Arrays.asList(0, 1, 2, 3); + List edges = List.of(new int[] {0, 1}, new int[] {2, 3}); + + KargerMinCut.KargerOutput result = KargerMinCut.findMinCut(nodes, edges); + + assertEquals(0, result.minCut()); + } + + @Test + public void testCompleteGraph() { + // Complete Graph: 0 -- 1 -- 2 -- 3 (all nodes connected to each other) + Collection nodes = Arrays.asList(0, 1, 2, 3); + List edges = List.of(new int[] {0, 1}, new int[] {0, 2}, new int[] {0, 3}, new int[] {1, 2}, new int[] {1, 3}, new int[] {2, 3}); + + KargerMinCut.KargerOutput result = KargerMinCut.findMinCut(nodes, edges); + + assertEquals(3, result.minCut()); + } + + @Test + public void testSingleNodeGraph() { + // Graph: Single node with no edges + Collection nodes = List.of(0); + List edges = List.of(); + + KargerMinCut.KargerOutput result = KargerMinCut.findMinCut(nodes, edges); + + assertEquals(0, result.minCut()); + assertTrue(result.first().contains(0)); + assertTrue(result.second().isEmpty()); + } + + @Test + public void testTwoNodesNoEdge() { + // Graph: 0 1 (no edges) + Collection nodes = Arrays.asList(0, 1); + List edges = List.of(); + + KargerMinCut.KargerOutput result = KargerMinCut.findMinCut(nodes, edges); + + assertEquals(0, result.minCut()); + assertTrue(result.first().contains(0) || result.first().contains(1)); + assertTrue(result.second().contains(0) || result.second().contains(1)); + } + + @Test + public void testComplexGraph() { + // Nodes: 0, 1, 2, 3, 4, 5, 6, 7, 8 + // Edges: Fully connected graph with additional edges for complexity + Collection nodes = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8); + List edges = List.of(new int[] {0, 1}, new int[] {0, 2}, new int[] {0, 3}, new int[] {0, 4}, new int[] {0, 5}, new int[] {1, 2}, new int[] {1, 3}, new int[] {1, 4}, new int[] {1, 5}, new int[] {1, 6}, new int[] {2, 3}, new int[] {2, 4}, new int[] {2, 5}, new int[] {2, 6}, + new int[] {2, 7}, new int[] {3, 4}, new int[] {3, 5}, new int[] {3, 6}, new int[] {3, 7}, new int[] {3, 8}, new int[] {4, 5}, new int[] {4, 6}, new int[] {4, 7}, new int[] {4, 8}, new int[] {5, 6}, new int[] {5, 7}, new int[] {5, 8}, new int[] {6, 7}, new int[] {6, 8}, new int[] {7, 8}, + new int[] {0, 6}, new int[] {1, 7}, new int[] {2, 8}); + + KargerMinCut.KargerOutput result = KargerMinCut.findMinCut(nodes, edges); + + // The exact minimum cut value depends on the randomization, but it should be consistent + // for this graph structure. For a fully connected graph, the minimum cut is typically + // determined by the smallest number of edges connecting two partitions. + assertTrue(result.minCut() > 0); + } +} diff --git a/src/test/java/com/thealgorithms/randomized/MonteCarloIntegrationTest.java b/src/test/java/com/thealgorithms/randomized/MonteCarloIntegrationTest.java new file mode 100644 index 000000000000..2a3a84b5ceea --- /dev/null +++ b/src/test/java/com/thealgorithms/randomized/MonteCarloIntegrationTest.java @@ -0,0 +1,91 @@ +package com.thealgorithms.randomized; + +import static com.thealgorithms.randomized.MonteCarloIntegration.approximate; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.function.Function; +import org.junit.jupiter.api.Test; + +class MonteCarloIntegrationTest { + + private static final double EPSILON = 0.03; // Allow 3% error margin + + @Test + void testConstantFunction() { + // Integral of f(x) = 2 from 0 to 1 is 2 + Function constant = x -> 2.0; + double result = approximate(constant, 0, 1, 10000); + assertEquals(2.0, result, EPSILON); + } + + @Test + void testLinearFunction() { + // Integral of f(x) = x from 0 to 1 is 0.5 + Function linear = Function.identity(); + double result = approximate(linear, 0, 1, 10000); + assertEquals(0.5, result, EPSILON); + } + + @Test + void testQuadraticFunction() { + // Integral of f(x) = x^2 from 0 to 1 is 1/3 + Function quadratic = x -> x * x; + double result = approximate(quadratic, 0, 1, 10000); + assertEquals(1.0 / 3.0, result, EPSILON); + } + + @Test + void testLargeSampleSize() { + // Integral of f(x) = x^2 from 0 to 1 is 1/3 + Function quadratic = x -> x * x; + double result = approximate(quadratic, 0, 1, 50000000); + assertEquals(1.0 / 3.0, result, EPSILON / 2); // Larger sample size, smaller error margin + } + + @Test + void testReproducibility() { + Function linear = Function.identity(); + double result1 = approximate(linear, 0, 1, 10000, 42L); + double result2 = approximate(linear, 0, 1, 10000, 42L); + assertEquals(result1, result2, 0.0); // Exactly equal + } + + @Test + void testNegativeInterval() { + // Integral of f(x) = x from -1 to 1 is 0 + Function linear = Function.identity(); + double result = approximate(linear, -1, 1, 10000); + assertEquals(0.0, result, EPSILON); + } + + @Test + void testNullFunction() { + Exception exception = assertThrows(IllegalArgumentException.class, () -> approximate(null, 0, 1, 1000)); + assertNotNull(exception); + } + + @Test + void testInvalidInterval() { + Function linear = Function.identity(); + Exception exception = assertThrows(IllegalArgumentException.class, () -> { + approximate(linear, 2, 1, 1000); // b <= a + }); + assertNotNull(exception); + } + + @Test + void testZeroSampleSize() { + Function linear = Function.identity(); + Exception exception = assertThrows(IllegalArgumentException.class, () -> approximate(linear, 0, 1, 0)); + assertNotNull(exception); + } + + @Test + void testNegativeSampleSize() { + Function linear = Function.identity(); + Exception exception = assertThrows(IllegalArgumentException.class, () -> approximate(linear, 0, 1, -100)); + assertNotNull(exception); + } +} diff --git a/src/test/java/com/thealgorithms/randomized/RandomizedClosestPairTest.java b/src/test/java/com/thealgorithms/randomized/RandomizedClosestPairTest.java new file mode 100644 index 000000000000..fd739b743989 --- /dev/null +++ b/src/test/java/com/thealgorithms/randomized/RandomizedClosestPairTest.java @@ -0,0 +1,30 @@ +package com.thealgorithms.randomized; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.thealgorithms.randomized.RandomizedClosestPair.Point; +import org.junit.jupiter.api.Test; + +public class RandomizedClosestPairTest { + + @Test + public void testFindClosestPairDistance() { + Point[] points = {new Point(1, 1), new Point(2, 2), new Point(3, 3), new Point(8, 8), new Point(13, 13)}; + double result = RandomizedClosestPair.findClosestPairDistance(points); + assertEquals(Math.sqrt(2), result, 0.00001); + } + + @Test + public void testWithIdenticalPoints() { + Point[] points = {new Point(0, 0), new Point(0, 0), new Point(1, 1)}; + double result = RandomizedClosestPair.findClosestPairDistance(points); + assertEquals(0.0, result, 0.00001); + } + + @Test + public void testWithDistantPoints() { + Point[] points = {new Point(0, 0), new Point(5, 0), new Point(10, 0)}; + double result = RandomizedClosestPair.findClosestPairDistance(points); + assertEquals(5.0, result, 0.00001); + } +} diff --git a/src/test/java/com/thealgorithms/randomized/RandomizedMatrixMultiplicationVerificationTest.java b/src/test/java/com/thealgorithms/randomized/RandomizedMatrixMultiplicationVerificationTest.java new file mode 100644 index 000000000000..330662ac2c52 --- /dev/null +++ b/src/test/java/com/thealgorithms/randomized/RandomizedMatrixMultiplicationVerificationTest.java @@ -0,0 +1,41 @@ +package com.thealgorithms.randomized; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Test; + +class RandomizedMatrixMultiplicationVerificationTest { + + @Test + void testCorrectMultiplication() { + int[][] a = {{1, 2}, {3, 4}}; + int[][] b = {{5, 6}, {7, 8}}; + int[][] c = {{19, 22}, {43, 50}}; + assertTrue(RandomizedMatrixMultiplicationVerification.verify(a, b, c, 10)); + } + + @Test + void testIncorrectMultiplication() { + int[][] a = {{1, 2}, {3, 4}}; + int[][] b = {{5, 6}, {7, 8}}; + int[][] wrongC = {{20, 22}, {43, 51}}; + assertFalse(RandomizedMatrixMultiplicationVerification.verify(a, b, wrongC, 10)); + } + + @Test + void testLargeMatrix() { + int size = 100; + int[][] a = new int[size][size]; + int[][] b = new int[size][size]; + int[][] c = new int[size][size]; + + for (int i = 0; i < size; i++) { + a[i][i] = 1; + b[i][i] = 1; + c[i][i] = 1; + } + + assertTrue(RandomizedMatrixMultiplicationVerification.verify(a, b, c, 15)); + } +} diff --git a/src/test/java/com/thealgorithms/randomized/RandomizedQuickSortTest.java b/src/test/java/com/thealgorithms/randomized/RandomizedQuickSortTest.java new file mode 100644 index 000000000000..ec3d5a0b3546 --- /dev/null +++ b/src/test/java/com/thealgorithms/randomized/RandomizedQuickSortTest.java @@ -0,0 +1,44 @@ +package com.thealgorithms.randomized; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import org.junit.jupiter.api.Test; + +/** + * Unit tests for the RandomizedQuickSort class. + */ +public class RandomizedQuickSortTest { + + /** + * Tests sorting of an array with multiple elements, including duplicates. + */ + @Test + public void testRandomizedQuickSortMultipleElements() { + int[] arr = {3, 6, 8, 10, 1, 2, 1}; + int[] expected = {1, 1, 2, 3, 6, 8, 10}; + RandomizedQuickSort.randomizedQuickSort(arr, 0, arr.length - 1); + assertArrayEquals(expected, arr); + } + + /** + * Tests sorting of an empty array. + */ + @Test + public void testRandomizedQuickSortEmptyArray() { + int[] arr = {}; + int[] expected = {}; + RandomizedQuickSort.randomizedQuickSort(arr, 0, arr.length - 1); + assertArrayEquals(expected, arr); + } + + /** + * Tests sorting of an array with a single element. + */ + @Test + public void testRandomizedQuickSortSingleElement() { + int[] arr = {5}; + int[] expected = {5}; + RandomizedQuickSort.randomizedQuickSort(arr, 0, arr.length - 1); + assertArrayEquals(expected, arr); + } +} diff --git a/src/test/java/com/thealgorithms/randomized/ReservoirSamplingTest.java b/src/test/java/com/thealgorithms/randomized/ReservoirSamplingTest.java new file mode 100644 index 000000000000..0c6061fcde2a --- /dev/null +++ b/src/test/java/com/thealgorithms/randomized/ReservoirSamplingTest.java @@ -0,0 +1,45 @@ +package com.thealgorithms.randomized; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.Test; + +public class ReservoirSamplingTest { + + @Test + public void testSampleSizeEqualsStreamLength() { + int[] stream = {1, 2, 3, 4, 5}; + int sampleSize = 5; + + List result = ReservoirSampling.sample(stream, sampleSize); + + assertEquals(sampleSize, result.size()); + assertTrue(Arrays.stream(stream).allMatch(result::contains)); + } + + @Test + public void testSampleSizeLessThanStreamLength() { + int[] stream = {10, 20, 30, 40, 50, 60}; + int sampleSize = 3; + + List result = ReservoirSampling.sample(stream, sampleSize); + + assertEquals(sampleSize, result.size()); + for (int value : result) { + assertTrue(Arrays.stream(stream).anyMatch(x -> x == value)); + } + } + + @Test + public void testSampleSizeGreaterThanStreamLengthThrowsException() { + int[] stream = {1, 2, 3}; + + Exception exception = assertThrows(IllegalArgumentException.class, () -> ReservoirSampling.sample(stream, 5)); + + assertEquals("Sample size cannot exceed stream size.", exception.getMessage()); + } +} diff --git a/src/test/java/com/thealgorithms/recursion/GenerateSubsetsTest.java b/src/test/java/com/thealgorithms/recursion/GenerateSubsetsTest.java index b92d1406b0a7..983552722781 100644 --- a/src/test/java/com/thealgorithms/recursion/GenerateSubsetsTest.java +++ b/src/test/java/com/thealgorithms/recursion/GenerateSubsetsTest.java @@ -1,36 +1,40 @@ package com.thealgorithms.recursion; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; +import java.util.Arrays; import java.util.List; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; public final class GenerateSubsetsTest { @Test - void subsetRecursionTestOne() { - String str = "abc"; - String[] expected = new String[] {"abc", "ab", "ac", "a", "bc", "b", "c", ""}; - - List ans = GenerateSubsets.subsetRecursion(str); - assertArrayEquals(ans.toArray(), expected); + @DisplayName("Subsets of 'abc'") + void testSubsetsOfABC() { + assertSubsets("abc", Arrays.asList("abc", "ab", "ac", "a", "bc", "b", "c", "")); } @Test - void subsetRecursionTestTwo() { - String str = "cbf"; - String[] expected = new String[] {"cbf", "cb", "cf", "c", "bf", "b", "f", ""}; + @DisplayName("Subsets of 'cbf'") + void testSubsetsOfCBF() { + assertSubsets("cbf", Arrays.asList("cbf", "cb", "cf", "c", "bf", "b", "f", "")); + } - List ans = GenerateSubsets.subsetRecursion(str); - assertArrayEquals(ans.toArray(), expected); + @Test + @DisplayName("Subsets of 'aba' with duplicates") + void testSubsetsWithDuplicateChars() { + assertSubsets("aba", Arrays.asList("aba", "ab", "aa", "a", "ba", "b", "a", "")); } @Test - void subsetRecursionTestThree() { - String str = "aba"; - String[] expected = new String[] {"aba", "ab", "aa", "a", "ba", "b", "a", ""}; + @DisplayName("Subsets of empty string") + void testEmptyInput() { + assertSubsets("", List.of("")); + } - List ans = GenerateSubsets.subsetRecursion(str); - assertArrayEquals(ans.toArray(), expected); + private void assertSubsets(String input, Iterable expected) { + List actual = GenerateSubsets.subsetRecursion(input); + assertIterableEquals(expected, actual, "Subsets do not match for input: " + input); } } diff --git a/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java b/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java index aab5c64c847f..660a53299ab0 100644 --- a/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java +++ b/src/test/java/com/thealgorithms/scheduling/SJFSchedulingTest.java @@ -4,107 +4,46 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import com.thealgorithms.devutils.entities.ProcessDetails; -import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Stream; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; class SJFSchedulingTest { - private ArrayList process; - void initialisation0() { - process = new ArrayList<>(); - process.add(new ProcessDetails("1", 0, 6)); - process.add(new ProcessDetails("2", 1, 2)); + private static Stream schedulingTestData() { + return Stream.of(Arguments.of(List.of(new ProcessDetails("1", 0, 6), new ProcessDetails("2", 1, 2)), List.of("1", "2")), + Arguments.of(List.of(new ProcessDetails("1", 0, 6), new ProcessDetails("2", 1, 2), new ProcessDetails("3", 4, 3), new ProcessDetails("4", 3, 1), new ProcessDetails("5", 6, 4), new ProcessDetails("6", 5, 5)), List.of("1", "4", "2", "3", "5", "6")), + Arguments.of(List.of(new ProcessDetails("1", 0, 3), new ProcessDetails("2", 1, 2), new ProcessDetails("3", 2, 1)), List.of("1", "3", "2")), Arguments.of(List.of(new ProcessDetails("1", 0, 3), new ProcessDetails("2", 5, 2), new ProcessDetails("3", 9, 1)), List.of("1", "2", "3")), + Arguments.of(Collections.emptyList(), List.of())); } - void initialisation1() { - process = new ArrayList<>(); - process.add(new ProcessDetails("1", 0, 6)); - process.add(new ProcessDetails("2", 1, 2)); - process.add(new ProcessDetails("3", 4, 3)); - process.add(new ProcessDetails("4", 3, 1)); - process.add(new ProcessDetails("5", 6, 4)); - process.add(new ProcessDetails("6", 5, 5)); - } - - void initialisation2() { - - process = new ArrayList<>(); - process.add(new ProcessDetails("1", 0, 3)); - process.add(new ProcessDetails("2", 1, 2)); - process.add(new ProcessDetails("3", 2, 1)); - } - void initialisation3() { - process = new ArrayList<>(); - process.add(new ProcessDetails("1", 0, 3)); - process.add(new ProcessDetails("2", 5, 2)); - process.add(new ProcessDetails("3", 9, 1)); - } - @Test - void constructor() { - initialisation0(); - SJFScheduling a = new SJFScheduling(process); - assertEquals(6, a.processes.get(0).getBurstTime()); - assertEquals(2, a.processes.get(1).getBurstTime()); + @ParameterizedTest(name = "Test SJF schedule: {index}") + @MethodSource("schedulingTestData") + void testSJFScheduling(List inputProcesses, List expectedSchedule) { + SJFScheduling scheduler = new SJFScheduling(inputProcesses); + scheduler.scheduleProcesses(); + assertEquals(expectedSchedule, scheduler.getSchedule()); } @Test - void sort() { - initialisation1(); - SJFScheduling a = new SJFScheduling(process); - a.sortByArrivalTime(); - assertEquals("1", a.processes.get(0).getProcessId()); - assertEquals("2", a.processes.get(1).getProcessId()); - assertEquals("3", a.processes.get(3).getProcessId()); - assertEquals("4", a.processes.get(2).getProcessId()); - assertEquals("5", a.processes.get(5).getProcessId()); - assertEquals("6", a.processes.get(4).getProcessId()); - } + @DisplayName("Test sorting by arrival order") + void testProcessArrivalOrderIsSorted() { + List processes = List.of(new ProcessDetails("1", 0, 6), new ProcessDetails("2", 1, 2), new ProcessDetails("4", 3, 1), new ProcessDetails("3", 4, 3), new ProcessDetails("6", 5, 5), new ProcessDetails("5", 6, 4)); + SJFScheduling scheduler = new SJFScheduling(processes); + List actualOrder = scheduler.getProcesses().stream().map(ProcessDetails::getProcessId).toList(); - @Test - void scheduling() { - initialisation1(); - SJFScheduling a = new SJFScheduling(process); - a.scheduleProcesses(); - assertEquals("1", a.schedule.get(0)); - assertEquals("4", a.schedule.get(1)); - assertEquals("2", a.schedule.get(2)); - assertEquals("3", a.schedule.get(3)); - assertEquals("5", a.schedule.get(4)); - assertEquals("6", a.schedule.get(5)); + assertEquals(List.of("1", "2", "4", "3", "6", "5"), actualOrder); } @Test - void schedulingOfTwoProcesses() { - initialisation0(); - SJFScheduling a = new SJFScheduling(process); - a.scheduleProcesses(); - assertEquals("1", a.schedule.get(0)); - assertEquals("2", a.schedule.get(1)); - } - - @Test - void schedulingOfAShortestJobArrivingLast() { - initialisation2(); - SJFScheduling a = new SJFScheduling(process); - a.scheduleProcesses(); - assertEquals("1", a.schedule.get(0)); - assertEquals("3", a.schedule.get(1)); - assertEquals("2", a.schedule.get(2)); - } - @Test - void schedulingWithProcessesNotComingBackToBack() { - initialisation3(); - SJFScheduling a = new SJFScheduling(process); - a.scheduleProcesses(); - assertEquals("1", a.schedule.get(0)); - assertEquals("2", a.schedule.get(1)); - assertEquals("3", a.schedule.get(2)); - } - @Test - void schedulingOfNothing() { - process = new ArrayList<>(); - SJFScheduling a = new SJFScheduling(process); - a.scheduleProcesses(); - assertTrue(a.schedule.isEmpty()); + void testSchedulingEmptyList() { + SJFScheduling scheduler = new SJFScheduling(Collections.emptyList()); + scheduler.scheduleProcesses(); + assertTrue(scheduler.getSchedule().isEmpty()); } } diff --git a/src/test/java/com/thealgorithms/searches/BoyerMooreTest.java b/src/test/java/com/thealgorithms/searches/BoyerMooreTest.java new file mode 100644 index 000000000000..9021eacbb8ee --- /dev/null +++ b/src/test/java/com/thealgorithms/searches/BoyerMooreTest.java @@ -0,0 +1,55 @@ +package com.thealgorithms.searches; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class BoyerMooreTest { + + @Test + public void testPatternFound() { + BoyerMoore bm = new BoyerMoore("ABCDABD"); + String text = "ABC ABCDAB ABCDABCDABDE"; + int index = bm.search(text); + assertEquals(15, index); + } + + @Test + public void testPatternNotFound() { + BoyerMoore bm = new BoyerMoore("XYZ"); + String text = "ABC ABCDAB ABCDABCDABDE"; + int index = bm.search(text); + assertEquals(-1, index); + } + + @Test + public void testPatternAtBeginning() { + BoyerMoore bm = new BoyerMoore("ABC"); + String text = "ABCDEF"; + int index = bm.search(text); + assertEquals(0, index); + } + + @Test + public void testPatternAtEnd() { + BoyerMoore bm = new BoyerMoore("CDE"); + String text = "ABCDEFGCDE"; + int index = bm.search(text); + assertEquals(2, index); // Primera ocurrencia de "CDE" + } + + @Test + public void testEmptyPattern() { + BoyerMoore bm = new BoyerMoore(""); + String text = "Hello world"; + int index = bm.search(text); + assertEquals(0, index); + } + + @Test + public void testStaticSearchMethod() { + String text = "ABCDEFGCDE"; + int index = BoyerMoore.staticSearch(text, "CDE"); + assertEquals(2, index); // Primera ocurrencia de "CDE" + } +} diff --git a/src/test/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearchTest.java b/src/test/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearchTest.java index 39ac5bf037ea..8d1423cbeeb0 100644 --- a/src/test/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearchTest.java +++ b/src/test/java/com/thealgorithms/searches/RowColumnWiseSorted2dArrayBinarySearchTest.java @@ -110,4 +110,131 @@ public void rowColumnSorted2dArrayBinarySearchTestNotFound() { assertEquals(expected[0], ans[0]); assertEquals(expected[1], ans[1]); } + + /** + * Tests for a WIDE rectangular matrix (3 rows, 4 columns) + */ + private static final Integer[][] WIDE_RECTANGULAR_MATRIX = { + {10, 20, 30, 40}, + {15, 25, 35, 45}, + {18, 28, 38, 48}, + }; + + @Test + public void rowColumnSorted2dArrayBinarySearchTestWideMatrixMiddle() { + Integer target = 25; // A value in the middle + int[] ans = RowColumnWiseSorted2dArrayBinarySearch.search(WIDE_RECTANGULAR_MATRIX, target); + int[] expected = {1, 1}; + assertEquals(expected[0], ans[0]); + assertEquals(expected[1], ans[1]); + } + + @Test + public void rowColumnSorted2dArrayBinarySearchTestWideMatrixTopRightCorner() { + Integer target = 40; // The top-right corner element + int[] ans = RowColumnWiseSorted2dArrayBinarySearch.search(WIDE_RECTANGULAR_MATRIX, target); + int[] expected = {0, 3}; + assertEquals(expected[0], ans[0]); + assertEquals(expected[1], ans[1]); + } + + @Test + public void rowColumnSorted2dArrayBinarySearchTestWideMatrixBottomLeftCorner() { + Integer target = 18; // The bottom-left corner element + int[] ans = RowColumnWiseSorted2dArrayBinarySearch.search(WIDE_RECTANGULAR_MATRIX, target); + int[] expected = {2, 0}; + assertEquals(expected[0], ans[0]); + assertEquals(expected[1], ans[1]); + } + + @Test + public void rowColumnSorted2dArrayBinarySearchTestWideMatrixTopLeftCorner() { + Integer target = 10; // The top-left corner element + int[] ans = RowColumnWiseSorted2dArrayBinarySearch.search(WIDE_RECTANGULAR_MATRIX, target); + int[] expected = {0, 0}; + assertEquals(expected[0], ans[0]); + assertEquals(expected[1], ans[1]); + } + + @Test + public void rowColumnSorted2dArrayBinarySearchTestWideMatrixBottomRightCorner() { + Integer target = 48; // The bottom-right corner element + int[] ans = RowColumnWiseSorted2dArrayBinarySearch.search(WIDE_RECTANGULAR_MATRIX, target); + int[] expected = {2, 3}; + assertEquals(expected[0], ans[0]); + assertEquals(expected[1], ans[1]); + } + + @Test + public void rowColumnSorted2dArrayBinarySearchTestWideMatrixNotFound() { + Integer target = 99; // A value that does not exist + int[] ans = RowColumnWiseSorted2dArrayBinarySearch.search(WIDE_RECTANGULAR_MATRIX, target); + int[] expected = {-1, -1}; + assertEquals(expected[0], ans[0]); + assertEquals(expected[1], ans[1]); + } + + /** + * Tests for a TALL rectangular matrix (4 rows, 3 columns) + */ + private static final Integer[][] TALL_RECTANGULAR_MATRIX = { + {10, 20, 30}, + {15, 25, 35}, + {18, 28, 38}, + {21, 31, 41}, + }; + + @Test + public void rowColumnSorted2dArrayBinarySearchTestTallMatrixMiddle() { + Integer target = 28; // A value in the middle + int[] ans = RowColumnWiseSorted2dArrayBinarySearch.search(TALL_RECTANGULAR_MATRIX, target); + int[] expected = {2, 1}; + assertEquals(expected[0], ans[0]); + assertEquals(expected[1], ans[1]); + } + + @Test + public void rowColumnSorted2dArrayBinarySearchTestTallMatrixTopRightCorner() { + Integer target = 30; // The top-right corner element + int[] ans = RowColumnWiseSorted2dArrayBinarySearch.search(TALL_RECTANGULAR_MATRIX, target); + int[] expected = {0, 2}; + assertEquals(expected[0], ans[0]); + assertEquals(expected[1], ans[1]); + } + + @Test + public void rowColumnSorted2dArrayBinarySearchTestTallMatrixBottomLeftCorner() { + Integer target = 21; // The bottom-left corner element + int[] ans = RowColumnWiseSorted2dArrayBinarySearch.search(TALL_RECTANGULAR_MATRIX, target); + int[] expected = {3, 0}; + assertEquals(expected[0], ans[0]); + assertEquals(expected[1], ans[1]); + } + + @Test + public void rowColumnSorted2dArrayBinarySearchTestTallMatrixTopLeftCorner() { + Integer target = 10; // The top-left corner element + int[] ans = RowColumnWiseSorted2dArrayBinarySearch.search(TALL_RECTANGULAR_MATRIX, target); + int[] expected = {0, 0}; + assertEquals(expected[0], ans[0]); + assertEquals(expected[1], ans[1]); + } + + @Test + public void rowColumnSorted2dArrayBinarySearchTestTallMatrixBottomRightCorner() { + Integer target = 41; // The bottom-right corner element + int[] ans = RowColumnWiseSorted2dArrayBinarySearch.search(TALL_RECTANGULAR_MATRIX, target); + int[] expected = {3, 2}; + assertEquals(expected[0], ans[0]); + assertEquals(expected[1], ans[1]); + } + + @Test + public void rowColumnSorted2dArrayBinarySearchTestTallMatrixNotFound() { + Integer target = 5; // A value that does not exist + int[] ans = RowColumnWiseSorted2dArrayBinarySearch.search(TALL_RECTANGULAR_MATRIX, target); + int[] expected = {-1, -1}; + assertEquals(expected[0], ans[0]); + assertEquals(expected[1], ans[1]); + } } diff --git a/src/test/java/com/thealgorithms/searches/TestSearchInARowAndColWiseSortedMatrix.java b/src/test/java/com/thealgorithms/searches/TestSearchInARowAndColWiseSortedMatrix.java index 014fb4bd24af..a56f79670cf3 100644 --- a/src/test/java/com/thealgorithms/searches/TestSearchInARowAndColWiseSortedMatrix.java +++ b/src/test/java/com/thealgorithms/searches/TestSearchInARowAndColWiseSortedMatrix.java @@ -1,27 +1,25 @@ -package com.thealgorithms.searches; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; - -import org.junit.jupiter.api.Test; - -public class TestSearchInARowAndColWiseSortedMatrix { - @Test - public void searchItem() { - int[][] matrix = {{3, 4, 5, 6, 7}, {8, 9, 10, 11, 12}, {14, 15, 16, 17, 18}, {23, 24, 25, 26, 27}, {30, 31, 32, 33, 34}}; - - var test = new SearchInARowAndColWiseSortedMatrix(); - int[] res = test.search(matrix, 16); - int[] expectedResult = {2, 2}; - assertArrayEquals(expectedResult, res); - } - - @Test - public void notFound() { - int[][] matrix = {{3, 4, 5, 6, 7}, {8, 9, 10, 11, 12}, {14, 15, 16, 17, 18}, {23, 24, 25, 26, 27}, {30, 31, 32, 33, 34}}; - - var test = new SearchInARowAndColWiseSortedMatrix(); - int[] res = test.search(matrix, 96); - int[] expectedResult = {-1, -1}; - assertArrayEquals(expectedResult, res); - } -} +package com.thealgorithms.searches; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import org.junit.jupiter.api.Test; + +public class TestSearchInARowAndColWiseSortedMatrix { + @Test + public void searchItem() { + int[][] matrix = {{3, 4, 5, 6, 7}, {8, 9, 10, 11, 12}, {14, 15, 16, 17, 18}, {23, 24, 25, 26, 27}, {30, 31, 32, 33, 34}}; + var test = new SearchInARowAndColWiseSortedMatrix(); + int[] res = test.search(matrix, 16); + int[] expectedResult = {2, 2}; + assertArrayEquals(expectedResult, res); + } + + @Test + public void notFound() { + int[][] matrix = {{3, 4, 5, 6, 7}, {8, 9, 10, 11, 12}, {14, 15, 16, 17, 18}, {23, 24, 25, 26, 27}, {30, 31, 32, 33, 34}}; + var test = new SearchInARowAndColWiseSortedMatrix(); + int[] res = test.search(matrix, 96); + int[] expectedResult = {-1, -1}; + assertArrayEquals(expectedResult, res); + } +} diff --git a/src/test/java/com/thealgorithms/slidingwindow/ShortestCoprimeSegmentTest.java b/src/test/java/com/thealgorithms/slidingwindow/ShortestCoprimeSegmentTest.java new file mode 100644 index 000000000000..acb9e1e30ac7 --- /dev/null +++ b/src/test/java/com/thealgorithms/slidingwindow/ShortestCoprimeSegmentTest.java @@ -0,0 +1,65 @@ +package com.thealgorithms.slidingwindow; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +import java.util.Arrays; +import org.junit.jupiter.api.Test; + +/** + * Unit tests for ShortestCoprimeSegment algorithm + * + * @author DomTr (...) + */ +public class ShortestCoprimeSegmentTest { + @Test + public void testShortestCoprimeSegment() { + assertArrayEquals(new long[] {4, 6, 9}, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {4, 6, 9, 3, 6})); + assertArrayEquals(new long[] {4, 5}, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {4, 5, 9, 3, 6})); + assertArrayEquals(new long[] {3, 2}, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {3, 2})); + assertArrayEquals(new long[] {9, 10}, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {3, 9, 9, 9, 10})); + + long[] test5 = new long[] {3 * 11, 11 * 7, 11 * 7 * 3, 11 * 7 * 3 * 5, 11 * 7 * 3 * 5 * 13, 7 * 13, 11 * 7 * 3 * 5 * 13}; + long[] answer5 = Arrays.copyOfRange(test5, 0, test5.length - 1); + assertArrayEquals(answer5, ShortestCoprimeSegment.shortestCoprimeSegment(test5)); + + // Test suite, when the entire array needs to be taken + long[] test6 = new long[] {3 * 7, 7 * 5, 5 * 7 * 3, 3 * 5}; + assertArrayEquals(test6, ShortestCoprimeSegment.shortestCoprimeSegment(test6)); + + long[] test7 = new long[] {3 * 11, 11 * 7, 11 * 7 * 3, 3 * 7}; + assertArrayEquals(test7, ShortestCoprimeSegment.shortestCoprimeSegment(test7)); + + long[] test8 = new long[] {3 * 11, 11 * 7, 11 * 7 * 3, 11 * 7 * 3 * 5, 5 * 7}; + assertArrayEquals(test8, ShortestCoprimeSegment.shortestCoprimeSegment(test8)); + + long[] test9 = new long[] {3 * 11, 11 * 7, 11 * 7 * 3, 11 * 7 * 3 * 5, 11 * 7 * 3 * 5 * 13, 7 * 13}; + assertArrayEquals(test9, ShortestCoprimeSegment.shortestCoprimeSegment(test9)); + + long[] test10 = new long[] {3 * 11, 7 * 11, 3 * 7 * 11, 3 * 5 * 7 * 11, 3 * 5 * 7 * 11 * 13, 2 * 3 * 5 * 7 * 11 * 13, 2 * 3 * 5 * 7 * 11 * 13 * 17, 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19, 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23, 7 * 13}; + assertArrayEquals(test10, ShortestCoprimeSegment.shortestCoprimeSegment(test10)); + + // Segment can consist of one element + long[] test11 = new long[] {1}; + assertArrayEquals(test11, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {4, 6, 1, 3, 6})); + long[] test12 = new long[] {1}; + assertArrayEquals(test12, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {1})); + } + @Test + public void testShortestCoprimeSegment2() { + assertArrayEquals(new long[] {2 * 3, 2 * 3 * 5, 2 * 3 * 5 * 7, 5 * 7}, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {2 * 3, 2 * 3 * 5, 2 * 3 * 5 * 7, 5 * 7, 2 * 3 * 5 * 7})); + assertArrayEquals(new long[] {5 * 7, 2}, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {2 * 3, 2 * 3 * 5, 2 * 3 * 5 * 7, 5 * 7, 2})); + assertArrayEquals(new long[] {5 * 7, 2 * 5 * 7, 2 * 11}, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {2 * 3, 2 * 3 * 5, 2 * 3 * 5 * 7, 5 * 7, 2 * 5 * 7, 2 * 11})); + assertArrayEquals(new long[] {3 * 5 * 7, 2 * 3, 2}, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {2, 2 * 3, 2 * 3 * 5, 3 * 5 * 7, 2 * 3, 2})); + } + @Test + public void testNoCoprimeSegment() { + // There may not be a coprime segment + long[] empty = new long[] {}; + assertArrayEquals(empty, ShortestCoprimeSegment.shortestCoprimeSegment(null)); + assertArrayEquals(empty, ShortestCoprimeSegment.shortestCoprimeSegment(empty)); + assertArrayEquals(empty, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {4, 6, 8, 12, 8})); + assertArrayEquals(empty, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {4, 4, 4, 4, 10, 4, 6, 8, 12, 8})); + assertArrayEquals(empty, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {100})); + assertArrayEquals(empty, ShortestCoprimeSegment.shortestCoprimeSegment(new long[] {2, 2, 2})); + } +} diff --git a/src/test/java/com/thealgorithms/sorts/AdaptiveMergeSortTest.java b/src/test/java/com/thealgorithms/sorts/AdaptiveMergeSortTest.java index 9d94b165d81b..8cb401802c4b 100644 --- a/src/test/java/com/thealgorithms/sorts/AdaptiveMergeSortTest.java +++ b/src/test/java/com/thealgorithms/sorts/AdaptiveMergeSortTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import java.util.Objects; import org.junit.jupiter.api.Test; public class AdaptiveMergeSortTest { @@ -50,4 +51,92 @@ public void testSortSingleElement() { Integer[] result = adaptiveMergeSort.sort(input); assertArrayEquals(expected, result); } + + @Test + public void testSortAlreadySortedArray() { + AdaptiveMergeSort adaptiveMergeSort = new AdaptiveMergeSort(); + Integer[] inputArray = {-12, -6, -3, 0, 2, 2, 13, 46}; + Integer[] outputArray = adaptiveMergeSort.sort(inputArray); + Integer[] expectedOutput = {-12, -6, -3, 0, 2, 2, 13, 46}; + assertArrayEquals(outputArray, expectedOutput); + } + + @Test + public void testSortReversedSortedArray() { + AdaptiveMergeSort adaptiveMergeSort = new AdaptiveMergeSort(); + Integer[] inputArray = {46, 13, 2, 2, 0, -3, -6, -12}; + Integer[] outputArray = adaptiveMergeSort.sort(inputArray); + Integer[] expectedOutput = {-12, -6, -3, 0, 2, 2, 13, 46}; + assertArrayEquals(outputArray, expectedOutput); + } + + @Test + public void testSortAllEqualArray() { + AdaptiveMergeSort adaptiveMergeSort = new AdaptiveMergeSort(); + Integer[] inputArray = {2, 2, 2, 2, 2}; + Integer[] outputArray = adaptiveMergeSort.sort(inputArray); + Integer[] expectedOutput = {2, 2, 2, 2, 2}; + assertArrayEquals(outputArray, expectedOutput); + } + + @Test + public void testSortMixedCaseStrings() { + AdaptiveMergeSort adaptiveMergeSort = new AdaptiveMergeSort(); + String[] inputArray = {"banana", "Apple", "apple", "Banana"}; + String[] expectedOutput = {"Apple", "Banana", "apple", "banana"}; + String[] outputArray = adaptiveMergeSort.sort(inputArray); + assertArrayEquals(expectedOutput, outputArray); + } + + /** + * Custom Comparable class for testing. + **/ + static class Person implements Comparable { + String name; + int age; + + Person(String name, int age) { + this.name = name; + this.age = age; + } + + @Override + public int compareTo(Person o) { + return Integer.compare(this.age, o.age); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Person person = (Person) o; + return age == person.age && Objects.equals(name, person.name); + } + + @Override + public int hashCode() { + return Objects.hash(name, age); + } + } + + @Test + public void testSortCustomObjects() { + AdaptiveMergeSort adaptiveMergeSort = new AdaptiveMergeSort(); + Person[] inputArray = { + new Person("Alice", 32), + new Person("Bob", 25), + new Person("Charlie", 28), + }; + Person[] expectedOutput = { + new Person("Bob", 25), + new Person("Charlie", 28), + new Person("Alice", 32), + }; + Person[] outputArray = adaptiveMergeSort.sort(inputArray); + assertArrayEquals(expectedOutput, outputArray); + } } diff --git a/src/test/java/com/thealgorithms/sorts/BogoSortTest.java b/src/test/java/com/thealgorithms/sorts/BogoSortTest.java index 3ebfb7a305b0..dc4f9e1c25bb 100644 --- a/src/test/java/com/thealgorithms/sorts/BogoSortTest.java +++ b/src/test/java/com/thealgorithms/sorts/BogoSortTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import java.util.Objects; import org.junit.jupiter.api.Test; public class BogoSortTest { @@ -63,4 +64,87 @@ public void bogoSortDuplicateStringArray() { String[] expectedOutput = {"a", "b", "b", "c", "d", "d", "h", "s"}; assertArrayEquals(outputArray, expectedOutput); } + + @Test + public void bogoSortAlreadySortedArray() { + Integer[] inputArray = {-12, -6, -3, 0, 2, 2, 13, 46}; + Integer[] outputArray = bogoSort.sort(inputArray); + Integer[] expectedOutput = {-12, -6, -3, 0, 2, 2, 13, 46}; + assertArrayEquals(outputArray, expectedOutput); + } + + @Test + public void bogoSortReversedSortedArray() { + Integer[] inputArray = {46, 13, 2, 2, 0, -3, -6, -12}; + Integer[] outputArray = bogoSort.sort(inputArray); + Integer[] expectedOutput = {-12, -6, -3, 0, 2, 2, 13, 46}; + assertArrayEquals(outputArray, expectedOutput); + } + + @Test + public void bogoSortAllEqualArray() { + Integer[] inputArray = {2, 2, 2, 2, 2}; + Integer[] outputArray = bogoSort.sort(inputArray); + Integer[] expectedOutput = {2, 2, 2, 2, 2}; + assertArrayEquals(outputArray, expectedOutput); + } + + @Test + public void bogoSortMixedCaseStrings() { + String[] inputArray = {"banana", "Apple", "apple", "Banana"}; + String[] expectedOutput = {"Apple", "Banana", "apple", "banana"}; + String[] outputArray = bogoSort.sort(inputArray); + assertArrayEquals(expectedOutput, outputArray); + } + + /** + * Custom Comparable class for testing. + **/ + static class Person implements Comparable { + String name; + int age; + + Person(String name, int age) { + this.name = name; + this.age = age; + } + + @Override + public int compareTo(Person o) { + return Integer.compare(this.age, o.age); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Person person = (Person) o; + return age == person.age && Objects.equals(name, person.name); + } + + @Override + public int hashCode() { + return Objects.hash(name, age); + } + } + + @Test + public void bogoSortCustomObjects() { + Person[] inputArray = { + new Person("Alice", 32), + new Person("Bob", 25), + new Person("Charlie", 28), + }; + Person[] expectedOutput = { + new Person("Bob", 25), + new Person("Charlie", 28), + new Person("Alice", 32), + }; + Person[] outputArray = bogoSort.sort(inputArray); + assertArrayEquals(expectedOutput, outputArray); + } } diff --git a/src/test/java/com/thealgorithms/sorts/BubbleSortTest.java b/src/test/java/com/thealgorithms/sorts/BubbleSortTest.java index 8690a3f5435c..3b99dca13b06 100644 --- a/src/test/java/com/thealgorithms/sorts/BubbleSortTest.java +++ b/src/test/java/com/thealgorithms/sorts/BubbleSortTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import java.util.Objects; import org.junit.jupiter.api.Test; /** @@ -91,4 +92,87 @@ public void bubbleSortStringArray() { }; assertArrayEquals(outputArray, expectedOutput); } + + @Test + public void bubbleSortAlreadySortedArray() { + Integer[] inputArray = {-12, -6, -3, 0, 2, 2, 13, 46}; + Integer[] outputArray = bubbleSort.sort(inputArray); + Integer[] expectedOutput = {-12, -6, -3, 0, 2, 2, 13, 46}; + assertArrayEquals(outputArray, expectedOutput); + } + + @Test + public void bubbleSortReversedSortedArray() { + Integer[] inputArray = {46, 13, 2, 2, 0, -3, -6, -12}; + Integer[] outputArray = bubbleSort.sort(inputArray); + Integer[] expectedOutput = {-12, -6, -3, 0, 2, 2, 13, 46}; + assertArrayEquals(outputArray, expectedOutput); + } + + @Test + public void bubbleSortAllEqualArray() { + Integer[] inputArray = {2, 2, 2, 2, 2}; + Integer[] outputArray = bubbleSort.sort(inputArray); + Integer[] expectedOutput = {2, 2, 2, 2, 2}; + assertArrayEquals(outputArray, expectedOutput); + } + + @Test + public void bubbleSortMixedCaseStrings() { + String[] inputArray = {"banana", "Apple", "apple", "Banana"}; + String[] expectedOutput = {"Apple", "Banana", "apple", "banana"}; + String[] outputArray = bubbleSort.sort(inputArray); + assertArrayEquals(expectedOutput, outputArray); + } + + /** + * Custom Comparable class for testing. + **/ + static class Person implements Comparable { + String name; + int age; + + Person(String name, int age) { + this.name = name; + this.age = age; + } + + @Override + public int compareTo(Person o) { + return Integer.compare(this.age, o.age); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Person person = (Person) o; + return age == person.age && Objects.equals(name, person.name); + } + + @Override + public int hashCode() { + return Objects.hash(name, age); + } + } + + @Test + public void bubbleSortCustomObjects() { + Person[] inputArray = { + new Person("Alice", 32), + new Person("Bob", 25), + new Person("Charlie", 28), + }; + Person[] expectedOutput = { + new Person("Bob", 25), + new Person("Charlie", 28), + new Person("Alice", 32), + }; + Person[] outputArray = bubbleSort.sort(inputArray); + assertArrayEquals(expectedOutput, outputArray); + } } diff --git a/src/test/java/com/thealgorithms/sorts/DarkSortTest.java b/src/test/java/com/thealgorithms/sorts/DarkSortTest.java new file mode 100644 index 000000000000..1df077e2ad74 --- /dev/null +++ b/src/test/java/com/thealgorithms/sorts/DarkSortTest.java @@ -0,0 +1,74 @@ +package com.thealgorithms.sorts; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.junit.jupiter.api.Test; + +class DarkSortTest { + + @Test + void testSortWithIntegers() { + Integer[] unsorted = {5, 3, 8, 6, 2, 7, 4, 1}; + Integer[] expected = {1, 2, 3, 4, 5, 6, 7, 8}; + + DarkSort darkSort = new DarkSort(); + Integer[] sorted = darkSort.sort(unsorted); + + assertArrayEquals(expected, sorted); + } + + @Test + void testEmptyArray() { + Integer[] unsorted = {}; + Integer[] expected = {}; + + DarkSort darkSort = new DarkSort(); + Integer[] sorted = darkSort.sort(unsorted); + + assertArrayEquals(expected, sorted); + } + + @Test + void testSingleElementArray() { + Integer[] unsorted = {42}; + Integer[] expected = {42}; + + DarkSort darkSort = new DarkSort(); + Integer[] sorted = darkSort.sort(unsorted); + + assertArrayEquals(expected, sorted); + } + + @Test + void testAlreadySortedArray() { + Integer[] unsorted = {1, 2, 3, 4, 5}; + Integer[] expected = {1, 2, 3, 4, 5}; + + DarkSort darkSort = new DarkSort(); + Integer[] sorted = darkSort.sort(unsorted); + + assertArrayEquals(expected, sorted); + } + + @Test + void testDuplicateElementsArray() { + Integer[] unsorted = {4, 2, 7, 2, 1, 4}; + Integer[] expected = {1, 2, 2, 4, 4, 7}; + + DarkSort darkSort = new DarkSort(); + Integer[] sorted = darkSort.sort(unsorted); + + assertArrayEquals(expected, sorted); + } + + @Test + void testNullArray() { + Integer[] unsorted = null; + + DarkSort darkSort = new DarkSort(); + Integer[] sorted = darkSort.sort(unsorted); + + assertNull(sorted, "Sorting a null array should return null"); + } +} diff --git a/src/test/java/com/thealgorithms/sorts/FlashSortTest.java b/src/test/java/com/thealgorithms/sorts/FlashSortTest.java index 6b1a74403a59..5b27975d3bea 100644 --- a/src/test/java/com/thealgorithms/sorts/FlashSortTest.java +++ b/src/test/java/com/thealgorithms/sorts/FlashSortTest.java @@ -5,7 +5,6 @@ import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.Test; @@ -47,7 +46,7 @@ public void testCustomConstructorInvalidRatio(double ratio) { } @TestFactory - public Collection dynamicTestsForSorting() { + public List dynamicTestsForSorting() { List dynamicTests = new ArrayList<>(); double[] ratios = {0.1, 0.2, 0.5, 0.9}; @@ -60,7 +59,7 @@ public Collection dynamicTestsForSorting() { return dynamicTests; } - private Collection createDynamicTestsForRatio(double ratio) { + private List createDynamicTestsForRatio(double ratio) { List dynamicTests = new ArrayList<>(); for (TestMethod testMethod : getTestMethodsFromSuperClass()) { dynamicTests.add(DynamicTest.dynamicTest("Ratio: " + ratio + " - Test: " + testMethod.name(), testMethod.executable())); diff --git a/src/test/java/com/thealgorithms/sorts/GnomeSortTest.java b/src/test/java/com/thealgorithms/sorts/GnomeSortTest.java index d86546472580..1d875d1fad0d 100644 --- a/src/test/java/com/thealgorithms/sorts/GnomeSortTest.java +++ b/src/test/java/com/thealgorithms/sorts/GnomeSortTest.java @@ -1,7 +1,9 @@ package com.thealgorithms.sorts; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import java.util.Objects; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -79,4 +81,92 @@ public void gnomeSortDuplicateStringArray() { gnomeSort.sort(inputArray); assertThat(inputArray).isEqualTo(expectedOutput); } + + @Test + @DisplayName("GnomeSort for sorted Array") + public void testSortAlreadySortedArray() { + Integer[] inputArray = {-12, -6, -3, 0, 2, 2, 13, 46}; + Integer[] outputArray = gnomeSort.sort(inputArray); + Integer[] expectedOutput = {-12, -6, -3, 0, 2, 2, 13, 46}; + assertArrayEquals(outputArray, expectedOutput); + } + + @Test + @DisplayName("GnomeSort for reversed sorted Array") + public void testSortReversedSortedArray() { + Integer[] inputArray = {46, 13, 2, 2, 0, -3, -6, -12}; + Integer[] outputArray = gnomeSort.sort(inputArray); + Integer[] expectedOutput = {-12, -6, -3, 0, 2, 2, 13, 46}; + assertArrayEquals(outputArray, expectedOutput); + } + + @Test + @DisplayName("GnomeSort for All equal Array") + public void testSortAllEqualArray() { + Integer[] inputArray = {2, 2, 2, 2, 2}; + Integer[] outputArray = gnomeSort.sort(inputArray); + Integer[] expectedOutput = {2, 2, 2, 2, 2}; + assertArrayEquals(outputArray, expectedOutput); + } + + @Test + @DisplayName("GnomeSort String Array with mixed cases") + public void testSortMixedCaseStrings() { + String[] inputArray = {"banana", "Apple", "apple", "Banana"}; + String[] expectedOutput = {"Apple", "Banana", "apple", "banana"}; + String[] outputArray = gnomeSort.sort(inputArray); + assertArrayEquals(expectedOutput, outputArray); + } + + /** + * Custom Comparable class for testing. + **/ + static class Person implements Comparable { + String name; + int age; + + Person(String name, int age) { + this.name = name; + this.age = age; + } + + @Override + public int compareTo(Person o) { + return Integer.compare(this.age, o.age); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Person person = (Person) o; + return age == person.age && Objects.equals(name, person.name); + } + + @Override + public int hashCode() { + return Objects.hash(name, age); + } + } + + @Test + @DisplayName("GnomeSort Custom Object Array") + public void testSortCustomObjects() { + Person[] inputArray = { + new Person("Alice", 32), + new Person("Bob", 25), + new Person("Charlie", 28), + }; + Person[] expectedOutput = { + new Person("Bob", 25), + new Person("Charlie", 28), + new Person("Alice", 32), + }; + Person[] outputArray = gnomeSort.sort(inputArray); + assertArrayEquals(expectedOutput, outputArray); + } } diff --git a/src/test/java/com/thealgorithms/sorts/InsertionSortTest.java b/src/test/java/com/thealgorithms/sorts/InsertionSortTest.java index 78744973355d..32a2a807295b 100644 --- a/src/test/java/com/thealgorithms/sorts/InsertionSortTest.java +++ b/src/test/java/com/thealgorithms/sorts/InsertionSortTest.java @@ -3,6 +3,7 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.Objects; import java.util.function.Function; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -111,4 +112,87 @@ private void testWithRandomArray(Function sortAlgorithm) { Double[] sorted = sortAlgorithm.apply(array); assertTrue(SortUtils.isSorted(sorted)); } + + @Test + public void testSortAlreadySortedArray() { + Integer[] inputArray = {-12, -6, -3, 0, 2, 2, 13, 46}; + Integer[] outputArray = insertionSort.sort(inputArray); + Integer[] expectedOutput = {-12, -6, -3, 0, 2, 2, 13, 46}; + assertArrayEquals(outputArray, expectedOutput); + } + + @Test + public void testSortReversedSortedArray() { + Integer[] inputArray = {46, 13, 2, 2, 0, -3, -6, -12}; + Integer[] outputArray = insertionSort.sort(inputArray); + Integer[] expectedOutput = {-12, -6, -3, 0, 2, 2, 13, 46}; + assertArrayEquals(outputArray, expectedOutput); + } + + @Test + public void testSortAllEqualArray() { + Integer[] inputArray = {2, 2, 2, 2, 2}; + Integer[] outputArray = insertionSort.sort(inputArray); + Integer[] expectedOutput = {2, 2, 2, 2, 2}; + assertArrayEquals(outputArray, expectedOutput); + } + + @Test + public void testSortMixedCaseStrings() { + String[] inputArray = {"banana", "Apple", "apple", "Banana"}; + String[] expectedOutput = {"Apple", "Banana", "apple", "banana"}; + String[] outputArray = insertionSort.sort(inputArray); + assertArrayEquals(expectedOutput, outputArray); + } + + /** + * Custom Comparable class for testing. + **/ + static class Person implements Comparable { + String name; + int age; + + Person(String name, int age) { + this.name = name; + this.age = age; + } + + @Override + public int compareTo(Person o) { + return Integer.compare(this.age, o.age); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Person person = (Person) o; + return age == person.age && Objects.equals(name, person.name); + } + + @Override + public int hashCode() { + return Objects.hash(name, age); + } + } + + @Test + public void testSortCustomObjects() { + Person[] inputArray = { + new Person("Alice", 32), + new Person("Bob", 25), + new Person("Charlie", 28), + }; + Person[] expectedOutput = { + new Person("Bob", 25), + new Person("Charlie", 28), + new Person("Alice", 32), + }; + Person[] outputArray = insertionSort.sort(inputArray); + assertArrayEquals(expectedOutput, outputArray); + } } diff --git a/src/test/java/com/thealgorithms/sorts/SimpleSortTest.java b/src/test/java/com/thealgorithms/sorts/SimpleSortTest.java deleted file mode 100644 index 887b314e46ff..000000000000 --- a/src/test/java/com/thealgorithms/sorts/SimpleSortTest.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.thealgorithms.sorts; - -public class SimpleSortTest extends SortingAlgorithmTest { - @Override - SortAlgorithm getSortAlgorithm() { - return new SimpleSort(); - } -} diff --git a/src/test/java/com/thealgorithms/sorts/SlowSortTest.java b/src/test/java/com/thealgorithms/sorts/SlowSortTest.java index d4d9eaa1c275..5fbdf8477092 100644 --- a/src/test/java/com/thealgorithms/sorts/SlowSortTest.java +++ b/src/test/java/com/thealgorithms/sorts/SlowSortTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import java.util.Objects; import org.junit.jupiter.api.Test; /** @@ -76,4 +77,87 @@ public void slowSortStringSymbolArray() { String[] expectedOutput = {"(a", "(b", ")", "a", "au", "auk", "auk", "bhy", "cba", "cba", "cbf", "á", "ó"}; assertArrayEquals(outputArray, expectedOutput); } + + @Test + public void testSortAlreadySortedArray() { + Integer[] inputArray = {-12, -6, -3, 0, 2, 2, 13, 46}; + Integer[] outputArray = slowSort.sort(inputArray); + Integer[] expectedOutput = {-12, -6, -3, 0, 2, 2, 13, 46}; + assertArrayEquals(outputArray, expectedOutput); + } + + @Test + public void testSortReversedSortedArray() { + Integer[] inputArray = {46, 13, 2, 2, 0, -3, -6, -12}; + Integer[] outputArray = slowSort.sort(inputArray); + Integer[] expectedOutput = {-12, -6, -3, 0, 2, 2, 13, 46}; + assertArrayEquals(outputArray, expectedOutput); + } + + @Test + public void testSortAllEqualArray() { + Integer[] inputArray = {2, 2, 2, 2, 2}; + Integer[] outputArray = slowSort.sort(inputArray); + Integer[] expectedOutput = {2, 2, 2, 2, 2}; + assertArrayEquals(outputArray, expectedOutput); + } + + @Test + public void testSortMixedCaseStrings() { + String[] inputArray = {"banana", "Apple", "apple", "Banana"}; + String[] expectedOutput = {"Apple", "Banana", "apple", "banana"}; + String[] outputArray = slowSort.sort(inputArray); + assertArrayEquals(expectedOutput, outputArray); + } + + /** + * Custom Comparable class for testing. + **/ + static class Person implements Comparable { + String name; + int age; + + Person(String name, int age) { + this.name = name; + this.age = age; + } + + @Override + public int compareTo(Person o) { + return Integer.compare(this.age, o.age); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Person person = (Person) o; + return age == person.age && Objects.equals(name, person.name); + } + + @Override + public int hashCode() { + return Objects.hash(name, age); + } + } + + @Test + public void testSortCustomObjects() { + Person[] inputArray = { + new Person("Alice", 32), + new Person("Bob", 25), + new Person("Charlie", 28), + }; + Person[] expectedOutput = { + new Person("Bob", 25), + new Person("Charlie", 28), + new Person("Alice", 32), + }; + Person[] outputArray = slowSort.sort(inputArray); + assertArrayEquals(expectedOutput, outputArray); + } } diff --git a/src/test/java/com/thealgorithms/sorts/SpreadSortTest.java b/src/test/java/com/thealgorithms/sorts/SpreadSortTest.java index a4992a02abfa..896aee8ba4ab 100644 --- a/src/test/java/com/thealgorithms/sorts/SpreadSortTest.java +++ b/src/test/java/com/thealgorithms/sorts/SpreadSortTest.java @@ -6,8 +6,7 @@ import org.junit.jupiter.api.function.Executable; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.ArgumentsProvider; -import org.junit.jupiter.params.provider.ArgumentsSource; +import org.junit.jupiter.params.provider.MethodSource; public class SpreadSortTest extends SortingAlgorithmTest { @@ -20,16 +19,13 @@ SortAlgorithm getSortAlgorithm() { return new SpreadSort(); } - static class ConstructorArgumentsProvider implements ArgumentsProvider { - @Override - public Stream provideArguments(org.junit.jupiter.api.extension.ExtensionContext context) { - return Stream.of(Arguments.of(0, 16, 2, IllegalArgumentException.class), Arguments.of(16, 0, 2, IllegalArgumentException.class), Arguments.of(16, 16, 0, IllegalArgumentException.class), Arguments.of(1001, 16, 2, IllegalArgumentException.class), - Arguments.of(16, 1001, 2, IllegalArgumentException.class), Arguments.of(16, 16, 101, IllegalArgumentException.class)); - } + private static Stream wrongConstructorInputs() { + return Stream.of(Arguments.of(0, 16, 2, IllegalArgumentException.class), Arguments.of(16, 0, 2, IllegalArgumentException.class), Arguments.of(16, 16, 0, IllegalArgumentException.class), Arguments.of(1001, 16, 2, IllegalArgumentException.class), + Arguments.of(16, 1001, 2, IllegalArgumentException.class), Arguments.of(16, 16, 101, IllegalArgumentException.class)); } @ParameterizedTest - @ArgumentsSource(ConstructorArgumentsProvider.class) + @MethodSource("wrongConstructorInputs") void testConstructor(int insertionSortThreshold, int initialBucketCapacity, int minBuckets, Class expectedException) { Executable executable = () -> new SpreadSort(insertionSortThreshold, initialBucketCapacity, minBuckets); assertThrows(expectedException, executable); diff --git a/src/test/java/com/thealgorithms/sorts/TopologicalSortTest.java b/src/test/java/com/thealgorithms/sorts/TopologicalSortTest.java index de115b458fe7..d5588b2b968e 100644 --- a/src/test/java/com/thealgorithms/sorts/TopologicalSortTest.java +++ b/src/test/java/com/thealgorithms/sorts/TopologicalSortTest.java @@ -3,6 +3,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertIterableEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import com.thealgorithms.sorts.TopologicalSort.Graph; import java.util.LinkedList; @@ -59,4 +60,18 @@ public void failureTest() { + "Back edge: 6 -> 2"; assertEquals(exception.getMessage(), expected); } + @Test + void testEmptyGraph() { + Graph graph = new Graph(); + LinkedList sorted = TopologicalSort.sort(graph); + assertTrue(sorted.isEmpty()); + } + @Test + void testSingleNode() { + Graph graph = new Graph(); + graph.addEdge("A", ""); + LinkedList sorted = TopologicalSort.sort(graph); + assertEquals(1, sorted.size()); + assertEquals("A", sorted.getFirst()); + } } diff --git a/src/test/java/com/thealgorithms/stacks/DuplicateBracketsTest.java b/src/test/java/com/thealgorithms/stacks/DuplicateBracketsTest.java index e2cc6acb8112..bc7b3266d98e 100644 --- a/src/test/java/com/thealgorithms/stacks/DuplicateBracketsTest.java +++ b/src/test/java/com/thealgorithms/stacks/DuplicateBracketsTest.java @@ -4,20 +4,23 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.MethodSource; class DuplicateBracketsTest { @ParameterizedTest - @CsvSource({"'((a + b) + (c + d))'", "'(a + b)'", "'a + b'", "'('", "''"}) + @CsvSource({"'((a + b) + (c + d))'", "'(a + b)'", "'a + b'", "'('", "''", "'a + (b * c) - d'", "'(x + y) * (z)'", "'(a + (b - c))'"}) void testInputReturnsFalse(String input) { assertFalse(DuplicateBrackets.check(input)); } @ParameterizedTest - @CsvSource({"'(a + b) + ((c + d))'", "'((a + b))'", "'((((a + b)))))'"}) + @CsvSource({"'(a + b) + ((c + d))'", "'((a + b))'", "'((((a + b)))))'", "'((x))'", "'((a + (b)))'", "'(a + ((b)))'", "'(((a)))'", "'(((())))'"}) void testInputReturnsTrue(String input) { assertTrue(DuplicateBrackets.check(input)); } @@ -26,4 +29,27 @@ void testInputReturnsTrue(String input) { void testInvalidInput() { assertThrows(IllegalArgumentException.class, () -> DuplicateBrackets.check(null)); } + + @ParameterizedTest(name = "Should be true: \"{0}\"") + @MethodSource("provideInputsThatShouldReturnTrue") + void testDuplicateBracketsTrueCases(String input) { + assertTrue(DuplicateBrackets.check(input)); + } + + static Stream provideInputsThatShouldReturnTrue() { + return Stream.of(Arguments.of("()"), Arguments.of("(( ))")); + } + + @ParameterizedTest(name = "Should be false: \"{0}\"") + @MethodSource("provideInputsThatShouldReturnFalse") + void testDuplicateBracketsFalseCases(String input) { + assertFalse(DuplicateBrackets.check(input)); + } + + static Stream provideInputsThatShouldReturnFalse() { + return Stream.of(Arguments.of("( )"), // whitespace inside brackets + Arguments.of("abc + def"), // no brackets + Arguments.of("(a + (b * c)) - (d / e)") // complex, but no duplicates + ); + } } diff --git a/src/test/java/com/thealgorithms/stacks/InfixToPostfixTest.java b/src/test/java/com/thealgorithms/stacks/InfixToPostfixTest.java index 02a08e393a00..bd63c1ac28f2 100644 --- a/src/test/java/com/thealgorithms/stacks/InfixToPostfixTest.java +++ b/src/test/java/com/thealgorithms/stacks/InfixToPostfixTest.java @@ -12,7 +12,7 @@ class InfixToPostfixTest { @ParameterizedTest @MethodSource("provideValidExpressions") - void testValidExpressions(String infix, String expectedPostfix) throws Exception { + void testValidExpressions(String infix, String expectedPostfix) { assertEquals(expectedPostfix, InfixToPostfix.infix2PostFix(infix)); } @@ -28,6 +28,6 @@ void testInvalidExpressions(String infix, String expectedMessage) { } private static Stream provideInvalidExpressions() { - return Stream.of(Arguments.of("((a+b)*c-d", "invalid expression")); + return Stream.of(Arguments.of("((a+b)*c-d", "Invalid expression: unbalanced brackets.")); } } diff --git a/src/test/java/com/thealgorithms/stacks/InfixToPrefixTest.java b/src/test/java/com/thealgorithms/stacks/InfixToPrefixTest.java index 91be8a63da62..0ea948307336 100644 --- a/src/test/java/com/thealgorithms/stacks/InfixToPrefixTest.java +++ b/src/test/java/com/thealgorithms/stacks/InfixToPrefixTest.java @@ -13,7 +13,7 @@ public class InfixToPrefixTest { @ParameterizedTest @MethodSource("provideValidExpressions") - void testValidExpressions(String infix, String expectedPrefix) throws Exception { + void testValidExpressions(String infix, String expectedPrefix) { assertEquals(expectedPrefix, InfixToPrefix.infix2Prefix(infix)); } diff --git a/src/test/java/com/thealgorithms/stacks/LargestRectangleTest.java b/src/test/java/com/thealgorithms/stacks/LargestRectangleTest.java index a54372adda0e..fec5d371c106 100644 --- a/src/test/java/com/thealgorithms/stacks/LargestRectangleTest.java +++ b/src/test/java/com/thealgorithms/stacks/LargestRectangleTest.java @@ -2,76 +2,27 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.jupiter.api.Test; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; public class LargestRectangleTest { - @Test - void testLargestRectangleHistogramWithTypicalCases() { - // Typical case with mixed heights - int[] heights = {2, 1, 5, 6, 2, 3}; - String expected = "10"; - String result = LargestRectangle.largestRectangleHistogram(heights); - assertEquals(expected, result); - - // Another typical case with increasing heights - heights = new int[] {2, 4}; - expected = "4"; - result = LargestRectangle.largestRectangleHistogram(heights); - assertEquals(expected, result); - - // Case with multiple bars of the same height - heights = new int[] {4, 4, 4, 4}; - expected = "16"; - result = LargestRectangle.largestRectangleHistogram(heights); - assertEquals(expected, result); + @ParameterizedTest(name = "Histogram: {0} → Expected area: {1}") + @MethodSource("histogramProvider") + void testLargestRectangleHistogram(int[] heights, String expected) { + assertEquals(expected, LargestRectangle.largestRectangleHistogram(heights)); } - @Test - void testLargestRectangleHistogramWithEdgeCases() { - // Edge case with an empty array - int[] heights = {}; - String expected = "0"; - String result = LargestRectangle.largestRectangleHistogram(heights); - assertEquals(expected, result); - - // Edge case with a single bar - heights = new int[] {5}; - expected = "5"; - result = LargestRectangle.largestRectangleHistogram(heights); - assertEquals(expected, result); - - // Edge case with all bars of height 0 - heights = new int[] {0, 0, 0}; - expected = "0"; - result = LargestRectangle.largestRectangleHistogram(heights); - assertEquals(expected, result); + static Stream histogramProvider() { + return Stream.of(Arguments.of(new int[] {2, 1, 5, 6, 2, 3}, "10"), Arguments.of(new int[] {2, 4}, "4"), Arguments.of(new int[] {4, 4, 4, 4}, "16"), Arguments.of(new int[] {}, "0"), Arguments.of(new int[] {5}, "5"), Arguments.of(new int[] {0, 0, 0}, "0"), + Arguments.of(new int[] {6, 2, 5, 4, 5, 1, 6}, "12"), Arguments.of(new int[] {2, 1, 5, 6, 2, 3, 1}, "10"), Arguments.of(createLargeArray(10000, 1), "10000")); } - @Test - void testLargestRectangleHistogramWithLargeInput() { - // Large input case - int[] heights = new int[10000]; - for (int i = 0; i < heights.length; i++) { - heights[i] = 1; - } - String expected = "10000"; - String result = LargestRectangle.largestRectangleHistogram(heights); - assertEquals(expected, result); - } - - @Test - void testLargestRectangleHistogramWithComplexCases() { - // Complex case with a mix of heights - int[] heights = {6, 2, 5, 4, 5, 1, 6}; - String expected = "12"; - String result = LargestRectangle.largestRectangleHistogram(heights); - assertEquals(expected, result); - - // Case with a peak in the middle - heights = new int[] {2, 1, 5, 6, 2, 3, 1}; - expected = "10"; - result = LargestRectangle.largestRectangleHistogram(heights); - assertEquals(expected, result); + private static int[] createLargeArray(int size, int value) { + int[] arr = new int[size]; + java.util.Arrays.fill(arr, value); + return arr; } } diff --git a/src/test/java/com/thealgorithms/stacks/MinStackUsingTwoStacksTest.java b/src/test/java/com/thealgorithms/stacks/MinStackUsingTwoStacksTest.java index e5deb17e9a8f..36bdde49b235 100644 --- a/src/test/java/com/thealgorithms/stacks/MinStackUsingTwoStacksTest.java +++ b/src/test/java/com/thealgorithms/stacks/MinStackUsingTwoStacksTest.java @@ -1,38 +1,112 @@ package com.thealgorithms.stacks; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import java.util.EmptyStackException; import org.junit.jupiter.api.Test; public class MinStackUsingTwoStacksTest { @Test - public void testMinStackOperations() { + public void testBasicOperations() { MinStackUsingTwoStacks minStack = new MinStackUsingTwoStacks(); minStack.push(3); minStack.push(5); - assertEquals(3, minStack.getMin()); + assertEquals(3, minStack.getMin(), "Min should be 3"); minStack.push(2); minStack.push(1); - assertEquals(1, minStack.getMin()); + assertEquals(1, minStack.getMin(), "Min should be 1"); minStack.pop(); - assertEquals(2, minStack.getMin()); + assertEquals(2, minStack.getMin(), "Min should be 2 after popping 1"); + + assertEquals(2, minStack.top(), "Top should be 2"); + } + + @Test + public void testPushDuplicateMins() { + MinStackUsingTwoStacks minStack = new MinStackUsingTwoStacks(); + minStack.push(2); + minStack.push(2); + minStack.push(1); + minStack.push(1); + assertEquals(1, minStack.getMin(), "Min should be 1"); + + minStack.pop(); + assertEquals(1, minStack.getMin(), "Min should still be 1 after popping one 1"); + + minStack.pop(); + assertEquals(2, minStack.getMin(), "Min should be 2 after popping both 1s"); + + minStack.pop(); + assertEquals(2, minStack.getMin(), "Min should still be 2 after popping one 2"); + + minStack.pop(); + // Now stack is empty, expect exception on getMin + assertThrows(EmptyStackException.class, minStack::getMin); } @Test - public void testMinStackOperations2() { + public void testPopOnEmptyStack() { MinStackUsingTwoStacks minStack = new MinStackUsingTwoStacks(); + assertThrows(EmptyStackException.class, minStack::pop); + } + + @Test + public void testTopOnEmptyStack() { + MinStackUsingTwoStacks minStack = new MinStackUsingTwoStacks(); + assertThrows(EmptyStackException.class, minStack::top); + } + + @Test + public void testGetMinOnEmptyStack() { + MinStackUsingTwoStacks minStack = new MinStackUsingTwoStacks(); + assertThrows(EmptyStackException.class, minStack::getMin); + } + + @Test + public void testSingleElementStack() { + MinStackUsingTwoStacks minStack = new MinStackUsingTwoStacks(); + minStack.push(10); + assertEquals(10, minStack.getMin()); + assertEquals(10, minStack.top()); + + minStack.pop(); + assertThrows(EmptyStackException.class, minStack::getMin); + } + + @Test + public void testIncreasingSequence() { + MinStackUsingTwoStacks minStack = new MinStackUsingTwoStacks(); + minStack.push(1); + minStack.push(2); minStack.push(3); - minStack.push(5); - assertEquals(3, minStack.getMin()); + minStack.push(4); + + assertEquals(1, minStack.getMin()); + assertEquals(4, minStack.top()); + + minStack.pop(); + minStack.pop(); + assertEquals(1, minStack.getMin()); + assertEquals(2, minStack.top()); + } + @Test + public void testDecreasingSequence() { + MinStackUsingTwoStacks minStack = new MinStackUsingTwoStacks(); + minStack.push(4); + minStack.push(3); minStack.push(2); minStack.push(1); + assertEquals(1, minStack.getMin()); + assertEquals(1, minStack.top()); minStack.pop(); assertEquals(2, minStack.getMin()); + assertEquals(2, minStack.top()); } } diff --git a/src/test/java/com/thealgorithms/stacks/PostfixEvaluatorTest.java b/src/test/java/com/thealgorithms/stacks/PostfixEvaluatorTest.java index 882fe644ccd5..682240acd752 100644 --- a/src/test/java/com/thealgorithms/stacks/PostfixEvaluatorTest.java +++ b/src/test/java/com/thealgorithms/stacks/PostfixEvaluatorTest.java @@ -4,24 +4,41 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.EmptyStackException; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; public class PostfixEvaluatorTest { - @Test - public void testValidExpressions() { - assertEquals(22, PostfixEvaluator.evaluatePostfix("5 6 + 2 *")); - assertEquals(27, PostfixEvaluator.evaluatePostfix("7 2 + 3 *")); - assertEquals(3, PostfixEvaluator.evaluatePostfix("10 5 / 1 +")); + @ParameterizedTest(name = "Expression: \"{0}\" → Result: {1}") + @CsvSource({"'5 6 + 2 *', 22", "'7 2 + 3 *', 27", "'10 5 / 1 +', 3", "'8', 8", "'3 4 +', 7"}) + @DisplayName("Valid postfix expressions") + void testValidExpressions(String expression, int expected) { + assertEquals(expected, PostfixEvaluator.evaluatePostfix(expression)); } @Test - public void testInvalidExpression() { + @DisplayName("Should throw EmptyStackException for incomplete expression") + void testInvalidExpression() { assertThrows(EmptyStackException.class, () -> PostfixEvaluator.evaluatePostfix("5 +")); } @Test - public void testMoreThanOneStackSizeAfterEvaluation() { + @DisplayName("Should throw IllegalArgumentException for extra operands") + void testExtraOperands() { assertThrows(IllegalArgumentException.class, () -> PostfixEvaluator.evaluatePostfix("5 6 + 2 * 3")); } + + @Test + @DisplayName("Should throw ArithmeticException for division by zero") + void testDivisionByZero() { + assertThrows(ArithmeticException.class, () -> PostfixEvaluator.evaluatePostfix("1 0 /")); + } + + @Test + @DisplayName("Should throw IllegalArgumentException for invalid characters") + void testInvalidToken() { + assertThrows(IllegalArgumentException.class, () -> PostfixEvaluator.evaluatePostfix("1 a +")); + } } diff --git a/src/test/java/com/thealgorithms/stacks/PrefixEvaluatorTest.java b/src/test/java/com/thealgorithms/stacks/PrefixEvaluatorTest.java index e2faa61955b3..ba67163fd49e 100644 --- a/src/test/java/com/thealgorithms/stacks/PrefixEvaluatorTest.java +++ b/src/test/java/com/thealgorithms/stacks/PrefixEvaluatorTest.java @@ -4,24 +4,28 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.EmptyStackException; +import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; public class PrefixEvaluatorTest { - @Test - public void testValidExpressions() { - assertEquals(10, PrefixEvaluator.evaluatePrefix("+ * 2 3 4")); - assertEquals(5, PrefixEvaluator.evaluatePrefix("- + 7 3 5")); - assertEquals(6, PrefixEvaluator.evaluatePrefix("/ * 3 2 1")); + @ParameterizedTest(name = "Expression: \"{0}\" → Result: {1}") + @CsvSource({"'+ * 2 3 4', 10", "'- + 7 3 5', 5", "'/ * 3 2 1', 6"}) + void testValidExpressions(String expression, int expected) { + assertEquals(expected, PrefixEvaluator.evaluatePrefix(expression)); } @Test - public void testInvalidExpression() { + @DisplayName("Should throw EmptyStackException for incomplete expression") + void testInvalidExpression() { assertThrows(EmptyStackException.class, () -> PrefixEvaluator.evaluatePrefix("+ 3")); } @Test - public void testMoreThanOneStackSizeAfterEvaluation() { + @DisplayName("Should throw IllegalArgumentException if stack not reduced to one result") + void testMoreThanOneStackSizeAfterEvaluation() { assertThrows(IllegalArgumentException.class, () -> PrefixEvaluator.evaluatePrefix("+ 3 4 5")); } } diff --git a/src/test/java/com/thealgorithms/stacks/SortStackTest.java b/src/test/java/com/thealgorithms/stacks/SortStackTest.java index b9f2f1b6f106..9747af5337e8 100644 --- a/src/test/java/com/thealgorithms/stacks/SortStackTest.java +++ b/src/test/java/com/thealgorithms/stacks/SortStackTest.java @@ -74,4 +74,187 @@ public void testSortWithDuplicateElements() { assertEquals(2, (int) stack.pop()); assertEquals(1, (int) stack.pop()); } + + @Test + public void testSortReverseSortedStack() { + // Test worst case scenario - completely reverse sorted + stack.push(5); + stack.push(4); + stack.push(3); + stack.push(2); + stack.push(1); + SortStack.sortStack(stack); + + assertEquals(5, stack.size()); + assertEquals(5, (int) stack.pop()); + assertEquals(4, (int) stack.pop()); + assertEquals(3, (int) stack.pop()); + assertEquals(2, (int) stack.pop()); + assertEquals(1, (int) stack.pop()); + } + + @Test + public void testSortWithAllSameElements() { + // Test stack with all identical elements + stack.push(7); + stack.push(7); + stack.push(7); + stack.push(7); + SortStack.sortStack(stack); + + assertEquals(4, stack.size()); + assertEquals(7, (int) stack.pop()); + assertEquals(7, (int) stack.pop()); + assertEquals(7, (int) stack.pop()); + assertEquals(7, (int) stack.pop()); + } + + @Test + public void testSortWithNegativeNumbers() { + // Test with negative numbers + stack.push(-3); + stack.push(1); + stack.push(-5); + stack.push(2); + stack.push(-1); + SortStack.sortStack(stack); + + assertEquals(5, stack.size()); + assertEquals(2, (int) stack.pop()); + assertEquals(1, (int) stack.pop()); + assertEquals(-1, (int) stack.pop()); + assertEquals(-3, (int) stack.pop()); + assertEquals(-5, (int) stack.pop()); + } + + @Test + public void testSortWithAllNegativeNumbers() { + // Test with only negative numbers + stack.push(-10); + stack.push(-5); + stack.push(-15); + stack.push(-1); + SortStack.sortStack(stack); + + assertEquals(4, stack.size()); + assertEquals(-1, (int) stack.pop()); + assertEquals(-5, (int) stack.pop()); + assertEquals(-10, (int) stack.pop()); + assertEquals(-15, (int) stack.pop()); + } + + @Test + public void testSortWithZero() { + // Test with zero included + stack.push(3); + stack.push(0); + stack.push(-2); + stack.push(1); + SortStack.sortStack(stack); + + assertEquals(4, stack.size()); + assertEquals(3, (int) stack.pop()); + assertEquals(1, (int) stack.pop()); + assertEquals(0, (int) stack.pop()); + assertEquals(-2, (int) stack.pop()); + } + + @Test + public void testSortLargerStack() { + // Test with a larger number of elements + int[] values = {15, 3, 9, 1, 12, 6, 18, 4, 11, 8}; + for (int value : values) { + stack.push(value); + } + + SortStack.sortStack(stack); + + assertEquals(10, stack.size()); + + // Verify sorted order (largest to smallest when popping) + int[] expectedOrder = {18, 15, 12, 11, 9, 8, 6, 4, 3, 1}; + for (int expected : expectedOrder) { + assertEquals(expected, (int) stack.pop()); + } + } + + @Test + public void testSortTwoElements() { + // Test edge case with exactly two elements + stack.push(5); + stack.push(2); + SortStack.sortStack(stack); + + assertEquals(2, stack.size()); + assertEquals(5, (int) stack.pop()); + assertEquals(2, (int) stack.pop()); + } + + @Test + public void testSortTwoElementsAlreadySorted() { + // Test two elements already in correct order + stack.push(2); + stack.push(5); + SortStack.sortStack(stack); + + assertEquals(2, stack.size()); + assertEquals(5, (int) stack.pop()); + assertEquals(2, (int) stack.pop()); + } + + @Test + public void testSortStackWithMinAndMaxValues() { + // Test with Integer.MAX_VALUE and Integer.MIN_VALUE + stack.push(0); + stack.push(Integer.MAX_VALUE); + stack.push(Integer.MIN_VALUE); + stack.push(100); + SortStack.sortStack(stack); + + assertEquals(4, stack.size()); + assertEquals(Integer.MAX_VALUE, (int) stack.pop()); + assertEquals(100, (int) stack.pop()); + assertEquals(0, (int) stack.pop()); + assertEquals(Integer.MIN_VALUE, (int) stack.pop()); + } + + @Test + public void testSortWithManyDuplicates() { + // Test with multiple sets of duplicates + stack.push(3); + stack.push(1); + stack.push(3); + stack.push(1); + stack.push(2); + stack.push(2); + stack.push(3); + SortStack.sortStack(stack); + + assertEquals(7, stack.size()); + assertEquals(3, (int) stack.pop()); + assertEquals(3, (int) stack.pop()); + assertEquals(3, (int) stack.pop()); + assertEquals(2, (int) stack.pop()); + assertEquals(2, (int) stack.pop()); + assertEquals(1, (int) stack.pop()); + assertEquals(1, (int) stack.pop()); + } + + @Test + public void testOriginalStackIsModified() { + // Verify that the original stack is modified, not a copy + Stack originalReference = stack; + stack.push(3); + stack.push(1); + stack.push(2); + + SortStack.sortStack(stack); + + // Verify it's the same object reference + assertTrue(stack == originalReference); + assertEquals(3, stack.size()); + assertEquals(3, (int) stack.pop()); + assertEquals(2, (int) stack.pop()); + assertEquals(1, (int) stack.pop()); + } } diff --git a/src/test/java/com/thealgorithms/strings/AlphabeticalTest.java b/src/test/java/com/thealgorithms/strings/AlphabeticalTest.java index 083239152ec2..7b41e11ef22f 100644 --- a/src/test/java/com/thealgorithms/strings/AlphabeticalTest.java +++ b/src/test/java/com/thealgorithms/strings/AlphabeticalTest.java @@ -1,30 +1,15 @@ package com.thealgorithms.strings; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; public class AlphabeticalTest { - @Test - public void isAlphabetical() { - // expected to be true - String input1 = "abcdefghijklmno"; - String input2 = "abcdxxxyzzzz"; - String input3 = "fpw"; - - // expected to be false - String input4 = "123a"; - String input5 = "abcABC"; - String input6 = "abcdefghikjlmno"; - - assertTrue(Alphabetical.isAlphabetical(input1)); - assertTrue(Alphabetical.isAlphabetical(input2)); - assertTrue(Alphabetical.isAlphabetical(input3)); - - assertFalse(Alphabetical.isAlphabetical(input4)); - assertFalse(Alphabetical.isAlphabetical(input5)); - assertFalse(Alphabetical.isAlphabetical(input6)); + @ParameterizedTest(name = "\"{0}\" → Expected: {1}") + @CsvSource({"'abcdefghijklmno', true", "'abcdxxxyzzzz', true", "'123a', false", "'abcABC', false", "'abcdefghikjlmno', false", "'aBC', true", "'abc', true", "'xyzabc', false", "'abcxyz', true", "'', false", "'1', false"}) + void testIsAlphabetical(String input, boolean expected) { + assertEquals(expected, Alphabetical.isAlphabetical(input)); } } diff --git a/src/test/java/com/thealgorithms/strings/AnagramsTest.java b/src/test/java/com/thealgorithms/strings/AnagramsTest.java index 88f6e0bb72ec..fa8ea72f2b8c 100644 --- a/src/test/java/com/thealgorithms/strings/AnagramsTest.java +++ b/src/test/java/com/thealgorithms/strings/AnagramsTest.java @@ -13,36 +13,37 @@ record AnagramTestCase(String input1, String input2, boolean expected) { private static Stream anagramTestData() { return Stream.of(new AnagramTestCase("late", "tale", true), new AnagramTestCase("late", "teal", true), new AnagramTestCase("listen", "silent", true), new AnagramTestCase("hello", "olelh", true), new AnagramTestCase("hello", "world", false), new AnagramTestCase("deal", "lead", true), - new AnagramTestCase("binary", "brainy", true), new AnagramTestCase("adobe", "abode", true), new AnagramTestCase("cat", "act", true), new AnagramTestCase("cat", "cut", false)); + new AnagramTestCase("binary", "brainy", true), new AnagramTestCase("adobe", "abode", true), new AnagramTestCase("cat", "act", true), new AnagramTestCase("cat", "cut", false), new AnagramTestCase("Listen", "Silent", true), new AnagramTestCase("Dormitory", "DirtyRoom", true), + new AnagramTestCase("Schoolmaster", "TheClassroom", true), new AnagramTestCase("Astronomer", "MoonStarer", true), new AnagramTestCase("Conversation", "VoicesRantOn", true)); } @ParameterizedTest @MethodSource("anagramTestData") void testApproach1(AnagramTestCase testCase) { - assertEquals(testCase.expected(), Anagrams.approach1(testCase.input1(), testCase.input2())); + assertEquals(testCase.expected(), Anagrams.areAnagramsBySorting(testCase.input1(), testCase.input2())); } @ParameterizedTest @MethodSource("anagramTestData") void testApproach2(AnagramTestCase testCase) { - assertEquals(testCase.expected(), Anagrams.approach2(testCase.input1(), testCase.input2())); + assertEquals(testCase.expected(), Anagrams.areAnagramsByCountingChars(testCase.input1(), testCase.input2())); } @ParameterizedTest @MethodSource("anagramTestData") void testApproach3(AnagramTestCase testCase) { - assertEquals(testCase.expected(), Anagrams.approach3(testCase.input1(), testCase.input2())); + assertEquals(testCase.expected(), Anagrams.areAnagramsByCountingCharsSingleArray(testCase.input1(), testCase.input2())); } @ParameterizedTest @MethodSource("anagramTestData") void testApproach4(AnagramTestCase testCase) { - assertEquals(testCase.expected(), Anagrams.approach4(testCase.input1(), testCase.input2())); + assertEquals(testCase.expected(), Anagrams.areAnagramsUsingHashMap(testCase.input1(), testCase.input2())); } @ParameterizedTest @MethodSource("anagramTestData") void testApproach5(AnagramTestCase testCase) { - assertEquals(testCase.expected(), Anagrams.approach5(testCase.input1(), testCase.input2())); + assertEquals(testCase.expected(), Anagrams.areAnagramsBySingleFreqArray(testCase.input1(), testCase.input2())); } } diff --git a/src/test/java/com/thealgorithms/strings/CharacterSameTest.java b/src/test/java/com/thealgorithms/strings/CharactersSameTest.java similarity index 100% rename from src/test/java/com/thealgorithms/strings/CharacterSameTest.java rename to src/test/java/com/thealgorithms/strings/CharactersSameTest.java diff --git a/src/test/java/com/thealgorithms/strings/CheckAnagramsTest.java b/src/test/java/com/thealgorithms/strings/CheckAnagramsTest.java deleted file mode 100644 index 82a75a130ef0..000000000000 --- a/src/test/java/com/thealgorithms/strings/CheckAnagramsTest.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.thealgorithms.strings; - -import static org.junit.jupiter.api.Assertions.assertThrows; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class CheckAnagramsTest { - private static final String MESSAGE = "Strings must contain only lowercase English letters!"; - - // CHECK METHOD isAnagrams() - @Test - public void testCheckAnagrams() { - String testString1 = "STUDY"; - String testString2 = "DUSTY"; - Assertions.assertTrue(CheckAnagrams.isAnagrams(testString1, testString2)); - } - - @Test - public void testCheckFalseAnagrams() { - String testString1 = "STUDY"; - String testString2 = "random"; - Assertions.assertFalse(CheckAnagrams.isAnagrams(testString1, testString2)); - } - - @Test - public void testCheckSameWordAnagrams() { - String testString1 = "STUDY"; - Assertions.assertTrue(CheckAnagrams.isAnagrams(testString1, testString1)); - } - - @Test - public void testCheckDifferentCasesAnagram() { - String testString1 = "STUDY"; - String testString2 = "dusty"; - Assertions.assertTrue(CheckAnagrams.isAnagrams(testString1, testString2)); - } - - // CHECK METHOD isAnagramsUnicode() - // Below tests work with strings which consist of Unicode symbols & the algorithm is case-sensitive. - @Test - public void testStringAreValidAnagramsCaseSensitive() { - Assertions.assertTrue(CheckAnagrams.isAnagramsUnicode("Silent", "liSten")); - Assertions.assertTrue(CheckAnagrams.isAnagramsUnicode("This is a string", "is This a string")); - } - - @Test - public void testStringAreNotAnagramsCaseSensitive() { - Assertions.assertFalse(CheckAnagrams.isAnagramsUnicode("Silent", "Listen")); - Assertions.assertFalse(CheckAnagrams.isAnagramsUnicode("This is a string", "Is this a string")); - } - - // CHECK METHOD isAnagramsOptimised() - // Below tests work with strings which consist of only lowercase English letters - @Test - public void testOptimisedAlgorithmStringsAreValidAnagrams() { - Assertions.assertTrue(CheckAnagrams.isAnagramsOptimised("silent", "listen")); - Assertions.assertTrue(CheckAnagrams.isAnagramsOptimised("mam", "amm")); - } - - @Test - public void testOptimisedAlgorithmShouldThrowExceptionWhenStringsContainUppercaseLetters() { - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> CheckAnagrams.isAnagramsOptimised("Silent", "Listen")); - Assertions.assertEquals(exception.getMessage(), MESSAGE); - - exception = assertThrows(IllegalArgumentException.class, () -> Assertions.assertFalse(CheckAnagrams.isAnagramsOptimised("This is a string", "Is this a string"))); - Assertions.assertEquals(exception.getMessage(), MESSAGE); - } -} diff --git a/src/test/java/com/thealgorithms/strings/IsomorphicTest.java b/src/test/java/com/thealgorithms/strings/IsomorphicTest.java index 0dac47551868..5c3ed89b65d3 100644 --- a/src/test/java/com/thealgorithms/strings/IsomorphicTest.java +++ b/src/test/java/com/thealgorithms/strings/IsomorphicTest.java @@ -1,31 +1,23 @@ package com.thealgorithms.strings; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.jupiter.api.Test; +import java.util.stream.Stream; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; public final class IsomorphicTest { - private IsomorphicTest() { - } - - @Test - public static void main(String[] args) { - String str1 = "abbbbaac"; - String str2 = "kffffkkd"; - - String str3 = "xyxyxy"; - String str4 = "bnbnbn"; - String str5 = "ghjknnmm"; - String str6 = "wertpopo"; - - String str7 = "aaammmnnn"; - String str8 = "ggghhhbbj"; + @ParameterizedTest + @MethodSource("inputs") + public void testCheckStrings(String str1, String str2, Boolean expected) { + assertEquals(expected, Isomorphic.areIsomorphic(str1, str2)); + assertEquals(expected, Isomorphic.areIsomorphic(str2, str1)); + } - assertTrue(Isomorphic.checkStrings(str1, str2)); - assertTrue(Isomorphic.checkStrings(str3, str4)); - assertFalse(Isomorphic.checkStrings(str5, str6)); - assertFalse(Isomorphic.checkStrings(str7, str8)); + private static Stream inputs() { + return Stream.of(Arguments.of("", "", Boolean.TRUE), Arguments.of("", "a", Boolean.FALSE), Arguments.of("aaa", "aa", Boolean.FALSE), Arguments.of("abbbbaac", "kffffkkd", Boolean.TRUE), Arguments.of("xyxyxy", "bnbnbn", Boolean.TRUE), Arguments.of("ghjknnmm", "wertpopo", Boolean.FALSE), + Arguments.of("aaammmnnn", "ggghhhbbj", Boolean.FALSE)); } } diff --git a/src/test/java/com/thealgorithms/strings/LongestCommonPrefixTest.java b/src/test/java/com/thealgorithms/strings/LongestCommonPrefixTest.java index 580a2726d285..84e54f75e8cb 100644 --- a/src/test/java/com/thealgorithms/strings/LongestCommonPrefixTest.java +++ b/src/test/java/com/thealgorithms/strings/LongestCommonPrefixTest.java @@ -2,72 +2,23 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import org.junit.jupiter.api.Test; +import java.util.stream.Stream; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; public class LongestCommonPrefixTest { - private final LongestCommonPrefix longestCommonPrefix = new LongestCommonPrefix(); - - @Test - public void testCommonPrefix() { - String[] input = {"flower", "flow", "flight"}; - String expected = "fl"; - assertEquals(expected, longestCommonPrefix.longestCommonPrefix(input)); - } - - @Test - public void testNoCommonPrefix() { - String[] input = {"dog", "racecar", "car"}; - String expected = ""; - assertEquals(expected, longestCommonPrefix.longestCommonPrefix(input)); - } - - @Test - public void testEmptyArray() { - String[] input = {}; - String expected = ""; - assertEquals(expected, longestCommonPrefix.longestCommonPrefix(input)); - } - - @Test - public void testNullArray() { - String[] input = null; - String expected = ""; - assertEquals(expected, longestCommonPrefix.longestCommonPrefix(input)); - } - - @Test - public void testSingleString() { - String[] input = {"single"}; - String expected = "single"; - assertEquals(expected, longestCommonPrefix.longestCommonPrefix(input)); - } - - @Test - public void testCommonPrefixWithDifferentLengths() { - String[] input = {"ab", "a"}; - String expected = "a"; - assertEquals(expected, longestCommonPrefix.longestCommonPrefix(input)); - } - - @Test - public void testAllSameStrings() { - String[] input = {"test", "test", "test"}; - String expected = "test"; - assertEquals(expected, longestCommonPrefix.longestCommonPrefix(input)); - } - - @Test - public void testPrefixAtEnd() { - String[] input = {"abcde", "abcfgh", "abcmnop"}; - String expected = "abc"; - assertEquals(expected, longestCommonPrefix.longestCommonPrefix(input)); + @ParameterizedTest(name = "{index} => input={0}, expected=\"{1}\"") + @MethodSource("provideTestCases") + @DisplayName("Test Longest Common Prefix") + void testLongestCommonPrefix(String[] input, String expected) { + assertEquals(expected, LongestCommonPrefix.longestCommonPrefix(input)); } - @Test - public void testMixedCase() { - String[] input = {"Flower", "flow", "flight"}; - String expected = ""; - assertEquals(expected, longestCommonPrefix.longestCommonPrefix(input)); + private static Stream provideTestCases() { + return Stream.of(Arguments.of(new String[] {"flower", "flow", "flight"}, "fl"), Arguments.of(new String[] {"dog", "racecar", "car"}, ""), Arguments.of(new String[] {}, ""), Arguments.of(null, ""), Arguments.of(new String[] {"single"}, "single"), Arguments.of(new String[] {"ab", "a"}, "a"), + Arguments.of(new String[] {"test", "test", "test"}, "test"), Arguments.of(new String[] {"abcde", "abcfgh", "abcmnop"}, "abc"), Arguments.of(new String[] {"Flower", "flow", "flight"}, "")); } } diff --git a/src/test/java/com/thealgorithms/strings/ReverseStringTest.java b/src/test/java/com/thealgorithms/strings/ReverseStringTest.java index 501f702976ec..476765b00dfc 100644 --- a/src/test/java/com/thealgorithms/strings/ReverseStringTest.java +++ b/src/test/java/com/thealgorithms/strings/ReverseStringTest.java @@ -1,8 +1,10 @@ package com.thealgorithms.strings; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import java.util.stream.Stream; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -25,4 +27,21 @@ public void testReverseString(String input, String expectedOutput) { public void testReverseString2(String input, String expectedOutput) { assertEquals(expectedOutput, ReverseString.reverse2(input)); } + + @ParameterizedTest + @MethodSource("testCases") + public void testReverseString3(String input, String expectedOutput) { + assertEquals(expectedOutput, ReverseString.reverse3(input)); + } + + @ParameterizedTest + @MethodSource("testCases") + public void testReverseStringUsingStack(String input, String expectedOutput) { + assertEquals(expectedOutput, ReverseString.reverseStringUsingStack(input)); + } + + @Test + public void testReverseStringUsingStackWithNullInput() { + assertThrows(IllegalArgumentException.class, () -> ReverseString.reverseStringUsingStack(null)); + } } diff --git a/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java b/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java index 2b6884c91c8f..411b11e743b8 100644 --- a/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java +++ b/src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java @@ -1,27 +1,33 @@ package com.thealgorithms.strings; -import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; public class ValidParenthesesTest { - @Test - void testOne() { - assertTrue(ValidParentheses.isValid("()")); - assertTrue(ValidParentheses.isValidParentheses("()")); + @ParameterizedTest(name = "Input: \"{0}\" → Expected: {1}") + @CsvSource({"'()', true", "'()[]{}', true", "'(]', false", "'{[]}', true", "'([{}])', true", "'([)]', false", "'', true", "'(', false", "')', false", "'{{{{}}}}', true", "'[({})]', true", "'[(])', false", "'[', false", "']', false", "'()()()()', true", "'(()', false", "'())', false", + "'{[()()]()}', true"}) + void + testIsValid(String input, boolean expected) { + assertEquals(expected, ValidParentheses.isValid(input)); } @Test - void testTwo() { - assertTrue(ValidParentheses.isValid("()[]{}")); - assertTrue(ValidParentheses.isValidParentheses("()[]{}")); + void testNullInputThrows() { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> ValidParentheses.isValid(null)); + assertEquals("Input string cannot be null", ex.getMessage()); } - @Test - void testThree() { - assertFalse(ValidParentheses.isValid("(]")); - assertFalse(ValidParentheses.isValidParentheses("(]")); + @ParameterizedTest(name = "Input: \"{0}\" → throws IllegalArgumentException") + @CsvSource({"'a'", "'()a'", "'[123]'", "'{hello}'", "'( )'", "'\t'", "'\n'", "'@#$%'"}) + void testInvalidCharactersThrow(String input) { + IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> ValidParentheses.isValid(input)); + assertTrue(ex.getMessage().startsWith("Unexpected character")); } } diff --git a/src/test/java/com/thealgorithms/strings/zigZagPattern/ZigZagPatternTest.java b/src/test/java/com/thealgorithms/strings/zigZagPattern/ZigZagPatternTest.java index 518bfab80f08..2cbbfe3d2dd8 100644 --- a/src/test/java/com/thealgorithms/strings/zigZagPattern/ZigZagPatternTest.java +++ b/src/test/java/com/thealgorithms/strings/zigZagPattern/ZigZagPatternTest.java @@ -6,10 +6,14 @@ public class ZigZagPatternTest { @Test - public void palindrome() { + public void testZigZagPattern() { String input1 = "HelloWorldFromJava"; String input2 = "javaIsAProgrammingLanguage"; Assertions.assertEquals(ZigZagPattern.encode(input1, 4), "HooeWrrmalolFJvlda"); Assertions.assertEquals(ZigZagPattern.encode(input2, 4), "jAaLgasPrmgaaevIrgmnnuaoig"); + // Edge cases + Assertions.assertEquals("ABC", ZigZagPattern.encode("ABC", 1)); // Single row + Assertions.assertEquals("A", ZigZagPattern.encode("A", 2)); // numRows > length of string + Assertions.assertEquals("", ZigZagPattern.encode("", 3)); // Empty string } } diff --git a/src/test/java/com/thealgorithms/tree/HeavyLightDecompositionTest.java b/src/test/java/com/thealgorithms/tree/HeavyLightDecompositionTest.java new file mode 100644 index 000000000000..29189290e1d4 --- /dev/null +++ b/src/test/java/com/thealgorithms/tree/HeavyLightDecompositionTest.java @@ -0,0 +1,69 @@ +package com.thealgorithms.tree; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class HeavyLightDecompositionTest { + + private HeavyLightDecomposition hld; + private final int[] values = {0, 10, 20, 30, 40, 50}; + + /** + * Initializes the test environment with a predefined tree structure and values. + */ + @BeforeEach + void setUp() { + hld = new HeavyLightDecomposition(5); + hld.addEdge(1, 2); + hld.addEdge(1, 3); + hld.addEdge(2, 4); + hld.addEdge(2, 5); + hld.initialize(1, values); + } + + /** + * Verifies that the tree initializes successfully without errors. + */ + @Test + void testBasicTreeInitialization() { + assertTrue(true, "Basic tree structure initialized successfully"); + } + + /** + * Tests the maximum value query in the path between nodes. + */ + @Test + void testQueryMaxInPath() { + assertEquals(50, hld.queryMaxInPath(4, 5), "Max value in path (4,5) should be 50"); + assertEquals(30, hld.queryMaxInPath(3, 2), "Max value in path (3,2) should be 30"); + } + + /** + * Tests updating a node's value and ensuring it is reflected in queries. + */ + @Test + void testUpdateNodeValue() { + hld.updateSegmentTree(1, 0, hld.getPositionIndex() - 1, hld.getPosition(4), 100); + assertEquals(100, hld.queryMaxInPath(4, 5), "Updated value should be reflected in query"); + } + + /** + * Tests the maximum value query in a skewed tree structure. + */ + @Test + void testSkewedTreeMaxQuery() { + assertEquals(40, hld.queryMaxInPath(1, 4), "Max value in skewed tree (1,4) should be 40"); + } + + /** + * Ensures query handles cases where u is a deeper node correctly. + */ + @Test + void testDepthSwapInPathQuery() { + assertEquals(50, hld.queryMaxInPath(5, 2), "Query should handle depth swap correctly"); + assertEquals(40, hld.queryMaxInPath(4, 1), "Query should handle swapped nodes correctly and return max value"); + } +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy