mirror of
https://github.com/TheAlgorithms/Ruby
synced 2024-12-26 21:58:56 +01:00
minor changes
This commit is contained in:
commit
1fe4dead1b
72 changed files with 1887 additions and 489 deletions
10
.github/CODEOWNERS
vendored
Normal file
10
.github/CODEOWNERS
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
# This is a comment.
|
||||
# Each line is a file pattern followed by one or more owners.
|
||||
|
||||
# More details are here: https://help.github.com/articles/about-codeowners/
|
||||
|
||||
# The '*' pattern is global owners.
|
||||
|
||||
# Order is important. The last matching pattern has the most precedence.
|
||||
|
||||
/.* @vbrazo @vzvu3k6k
|
60
.github/stale.yml
vendored
Normal file
60
.github/stale.yml
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
# Configuration for probot-stale - https://github.com/probot/stale
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request becomes stale
|
||||
daysUntilStale: 30
|
||||
|
||||
# Number of days of inactivity before an Issue or Pull Request with the stale label is closed.
|
||||
# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale.
|
||||
daysUntilClose: 7
|
||||
|
||||
# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled)
|
||||
onlyLabels: []
|
||||
|
||||
# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable
|
||||
exemptLabels:
|
||||
- "Status: on hold"
|
||||
|
||||
# Set to true to ignore issues in a project (defaults to false)
|
||||
exemptProjects: false
|
||||
|
||||
# Set to true to ignore issues in a milestone (defaults to false)
|
||||
exemptMilestones: false
|
||||
|
||||
# Set to true to ignore issues with an assignee (defaults to false)
|
||||
exemptAssignees: false
|
||||
|
||||
# Label to use when marking as stale
|
||||
staleLabel: stale
|
||||
|
||||
# Comment to post when removing the stale label.
|
||||
# unmarkComment: >
|
||||
# Your comment here.
|
||||
|
||||
# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls':
|
||||
pulls:
|
||||
# Comment to post when marking as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This pull request has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
|
||||
# Comment to post when closing a stale Pull Request.
|
||||
closeComment: >
|
||||
Please reopen this pull request once you commit the changes requested
|
||||
or make improvements on the code. If this is not the case and you need
|
||||
some help, feel free to seek help from our [Gitter](https://gitter.im/TheAlgorithms)
|
||||
or ping one of the reviewers. Thank you for your contributions!
|
||||
|
||||
issues:
|
||||
# Comment to post when marking as stale. Set to `false` to disable
|
||||
markComment: >
|
||||
This issue has been automatically marked as stale because it has not had
|
||||
recent activity. It will be closed if no further activity occurs. Thank you
|
||||
for your contributions.
|
||||
|
||||
# Comment to post when closing a stale Issue.
|
||||
closeComment: >
|
||||
Please reopen this issue once you add more information and updates here.
|
||||
If this is not the case and you need some help, feel free to seek help
|
||||
from our [Gitter](https://gitter.im/TheAlgorithms) or ping one of the
|
||||
reviewers. Thank you for your contributions!
|
12
.github/workflows/test.yml
vendored
Normal file
12
.github/workflows/test.yml
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
name: test
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- uses: ruby/setup-ruby@master
|
||||
with:
|
||||
ruby-version: '3.0'
|
||||
- name: Run tests
|
||||
run: rake test
|
59
.github/workflows/update_directory_md.yml
vendored
Normal file
59
.github/workflows/update_directory_md.yml
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
name: update_directory_md
|
||||
on: [push]
|
||||
jobs:
|
||||
update_directory_md:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- uses: actions/setup-python@master
|
||||
- name: update_directory_md
|
||||
shell: python
|
||||
run: |
|
||||
import os
|
||||
from typing import Iterator
|
||||
URL_BASE = "https://github.com/TheAlgorithms/Ruby/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() == ".rb":
|
||||
yield os.path.join(dirpath, filename).lstrip("./")
|
||||
|
||||
def md_prefix(i):
|
||||
return f"{i * ' '}*" if i else "\n##"
|
||||
|
||||
def print_path(old_path: str, new_path: str) -> str:
|
||||
global g_output
|
||||
old_parts = old_path.split(os.sep)
|
||||
for i, new_part in enumerate(new_path.split(os.sep)):
|
||||
if i + 1 > len(old_parts) or old_parts[i] != new_part:
|
||||
if new_part:
|
||||
g_output.append(f"{md_prefix(i)} {new_part.replace('_', ' ').title()}")
|
||||
return new_path
|
||||
|
||||
def build_directory_md(top_dir: str = ".") -> str:
|
||||
global g_output
|
||||
old_path = ""
|
||||
for filepath in sorted(good_filepaths(), key=str.lower):
|
||||
filepath, filename = os.path.split(filepath)
|
||||
if filepath != old_path:
|
||||
old_path = print_path(old_path, filepath)
|
||||
indent = (filepath.count(os.sep) + 1) if filepath else 0
|
||||
url = "/".join((URL_BASE, filepath, filename)).replace(" ", "%20")
|
||||
filename = os.path.splitext(filename.replace("_", " ").title())[0]
|
||||
g_output.append(f"{md_prefix(indent)} [{filename}]({url})")
|
||||
return "\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-actions
|
||||
git config --global user.email '${GITHUB_ACTOR}@users.noreply.github.com'
|
||||
git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY
|
||||
git add DIRECTORY.md
|
||||
git commit -am "updating DIRECTORY.md" || true
|
||||
git push --force origin HEAD:$GITHUB_REF || true
|
67
CONTRIBUTING.md
Normal file
67
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,67 @@
|
|||
# Contributing guidelines
|
||||
|
||||
## Before contributing
|
||||
|
||||
Welcome to [TheAlgorithms/Ruby](https://github.com/TheAlgorithms/Ruby)! Before sending your pull requests, make sure that you **read the whole guidelines**. If you have any doubt on the contributing guide, please feel free to [state it clearly in an issue](https://github.com/TheAlgorithms/Ruby/issues/new) or ask the community in [Gitter](https://gitter.im/TheAlgorithms).
|
||||
|
||||
## Contributing
|
||||
|
||||
### Contributor
|
||||
|
||||
We are very happy that you consider implementing algorithms and data structure for others! This repository is referenced and used by learners from all over the globe. Being one of our contributors, you agree and confirm that:
|
||||
|
||||
- You did your work - no plagiarism allowed
|
||||
- Any plagiarized work will not be merged.
|
||||
- Your work will be distributed under [MIT License](LICENSE.md) once your pull request is merged
|
||||
- You submitted work fulfils or mostly fulfils our styles and standards
|
||||
|
||||
**New implementation** is welcome! For example, new solutions for a problem, different representations for a graph data structure or algorithm designs with different complexity but **identical implementation** of an existing implementation is not allowed. Please check whether the solution is already implemented or not before submitting your pull request.
|
||||
|
||||
**Improving comments** and **writing proper tests** are also highly welcome.
|
||||
|
||||
### Contribution
|
||||
|
||||
We appreciate any contribution, from fixing a grammar mistake in a comment to implementing complex algorithms. Please read this section if you are contributing your work.
|
||||
|
||||
Your contribution will be tested by our [automated testing on Travis CI](https://travis-ci.org/TheAlgorithms/Ruby/pull_requests) to save time and mental energy. After you have submitted your pull request, you should see the Travis tests start to run at the bottom of your submission page. If those tests fail, then click on the ___details___ button try to read through the Travis output to understand the failure. If you do not understand, please leave a comment on your submission page and a community member will try to help.
|
||||
|
||||
Please help us keep our issue list small by adding fixes: #{$ISSUE_NO} to the commit message of pull requests that resolve open issues. GitHub will use this tag to auto close the issue when the PR is merged.
|
||||
|
||||
#### What is an Algorithm?
|
||||
|
||||
An Algorithm is one or more functions (or classes) that:
|
||||
* take one or more inputs,
|
||||
* perform some internal calculations or data manipulations,
|
||||
* return one or more outputs,
|
||||
* have minimal side effects.
|
||||
|
||||
Algorithms should be packaged in a way that would make it easy for readers to put them into larger programs.
|
||||
|
||||
Algorithms should:
|
||||
|
||||
* have intuitive class and function names that make their purpose clear to readers
|
||||
* use Ruby naming conventions and intuitive variable names to ease comprehension
|
||||
* be flexible to take different input values
|
||||
* have Ruby type hints for their input parameters and return values
|
||||
* raise Ruby exceptions on erroneous input values
|
||||
* return all calculation results instead of printing or plotting them
|
||||
|
||||
Algorithms in this repo should not be how-to examples for existing Ruby packages. Instead, they should perform internal calculations or manipulations to convert input values into different output values. Those calculations or manipulations can use data types, classes, or functions of existing Ruby packages but each algorithm in this repo should add unique value.
|
||||
|
||||
#### Other Requirements for Submissions
|
||||
|
||||
- If you are submitting code in the `project_euler/` directory, please also read [the dedicated Guideline](https://github.com/TheAlgorithms/Ruby/blob/master/project_euler/README.md) before contributing to our Project Euler library.
|
||||
- Strictly use snake_case (underscore_separated) in your file_name, as it will be easy to parse in future using scripts.
|
||||
- Please avoid creating new directories if at all possible. Try to fit your work into the existing directory structure.
|
||||
- If possible, follow the standard *within* the folder you are submitting to.
|
||||
- If you have modified/added code work, make sure the code compiles before submitting.
|
||||
- If you have modified/added documentation work, ensure your language is concise and contains no grammar errors.
|
||||
- Do not update the `README.md` or `DIRECTORY.md` file which will be periodically autogenerated by our Travis CI processes.
|
||||
- Add a corresponding explanation to [Algorithms-Explanation](https://github.com/TheAlgorithms/Algorithms-Explanation) (Optional but recommended).
|
||||
|
||||
- Most importantly,
|
||||
- **Be consistent in the use of these guidelines when submitting.**
|
||||
- **Join** [Gitter](https://gitter.im/TheAlgorithms) **now!**
|
||||
- Happy coding!
|
||||
|
||||
Writer [@vbrazo](https://github.com/vbrazo), Dec 2020.
|
89
DIRECTORY.md
Normal file
89
DIRECTORY.md
Normal file
|
@ -0,0 +1,89 @@
|
|||
|
||||
## Ciphers
|
||||
* [Merkle Hellman Cryptosystem](https://github.com/TheAlgorithms/Ruby/blob/master/ciphers/merkle_hellman_cryptosystem.rb)
|
||||
|
||||
## Data Structures
|
||||
* Arrays
|
||||
* [Get Products Of All Other Elements](https://github.com/TheAlgorithms/Ruby/blob/master/data_structures/arrays/get_products_of_all_other_elements.rb)
|
||||
* Binary Trees
|
||||
* [Inorder Traversal](https://github.com/TheAlgorithms/Ruby/blob/master/data_structures/binary_trees/inorder_traversal.rb)
|
||||
* [Invert](https://github.com/TheAlgorithms/Ruby/blob/master/data_structures/binary_trees/invert.rb)
|
||||
* [Postorder Traversal](https://github.com/TheAlgorithms/Ruby/blob/master/data_structures/binary_trees/postorder_traversal.rb)
|
||||
* [Preorder Traversal](https://github.com/TheAlgorithms/Ruby/blob/master/data_structures/binary_trees/preorder_traversal.rb)
|
||||
* Linked Lists
|
||||
* [Double List](https://github.com/TheAlgorithms/Ruby/blob/master/data_structures/linked_lists/double_list.rb)
|
||||
* [Single List](https://github.com/TheAlgorithms/Ruby/blob/master/data_structures/linked_lists/single_list.rb)
|
||||
* Queues
|
||||
* [Queue](https://github.com/TheAlgorithms/Ruby/blob/master/data_structures/queues/queue.rb)
|
||||
* Stacks
|
||||
* [Stack](https://github.com/TheAlgorithms/Ruby/blob/master/data_structures/stacks/stack.rb)
|
||||
* Tries
|
||||
* [Trie](https://github.com/TheAlgorithms/Ruby/blob/master/data_structures/tries/trie.rb)
|
||||
|
||||
## Discrete Mathematics
|
||||
* [Euclidean Gcd](https://github.com/TheAlgorithms/Ruby/blob/master/discrete_mathematics/euclidean_gcd.rb)
|
||||
* [Exteded Euclidean Algorithm](https://github.com/TheAlgorithms/Ruby/blob/master/discrete_mathematics/exteded_euclidean_algorithm.rb)
|
||||
* [Lcm](https://github.com/TheAlgorithms/Ruby/blob/master/discrete_mathematics/lcm.rb)
|
||||
|
||||
## Maths
|
||||
* [Abs](https://github.com/TheAlgorithms/Ruby/blob/master/maths/abs.rb)
|
||||
* [Abs Test](https://github.com/TheAlgorithms/Ruby/blob/master/maths/abs_test.rb)
|
||||
* [Aliquot Sum](https://github.com/TheAlgorithms/Ruby/blob/master/maths/aliquot_sum.rb)
|
||||
* [Aliquot Sum Test](https://github.com/TheAlgorithms/Ruby/blob/master/maths/aliquot_sum_test.rb)
|
||||
* [Binary To Decimal](https://github.com/TheAlgorithms/Ruby/blob/master/maths/binary_to_decimal.rb)
|
||||
* [Ceil](https://github.com/TheAlgorithms/Ruby/blob/master/maths/ceil.rb)
|
||||
* [Ceil Test](https://github.com/TheAlgorithms/Ruby/blob/master/maths/ceil_test.rb)
|
||||
* [Number Of Digits](https://github.com/TheAlgorithms/Ruby/blob/master/maths/number_of_digits.rb)
|
||||
* [Square Root](https://github.com/TheAlgorithms/Ruby/blob/master/maths/square_root.rb)
|
||||
* [Square Root Test](https://github.com/TheAlgorithms/Ruby/blob/master/maths/square_root_test.rb)
|
||||
* [Sum Of Digits](https://github.com/TheAlgorithms/Ruby/blob/master/maths/sum_of_digits.rb)
|
||||
|
||||
## Other
|
||||
* [Fisher Yates](https://github.com/TheAlgorithms/Ruby/blob/master/other/fisher_yates.rb)
|
||||
|
||||
## Project Euler
|
||||
* Problem 1
|
||||
* [Sol1](https://github.com/TheAlgorithms/Ruby/blob/master/project_euler/problem_1/sol1.rb)
|
||||
* Problem 2
|
||||
* [Sol1](https://github.com/TheAlgorithms/Ruby/blob/master/project_euler/problem_2/sol1.rb)
|
||||
* Problem 20
|
||||
* [Sol1](https://github.com/TheAlgorithms/Ruby/blob/master/project_euler/problem_20/sol1.rb)
|
||||
* Problem 21
|
||||
* [Sol1](https://github.com/TheAlgorithms/Ruby/blob/master/project_euler/problem_21/sol1.rb)
|
||||
* Problem 22
|
||||
* [Sol1](https://github.com/TheAlgorithms/Ruby/blob/master/project_euler/problem_22/sol1.rb)
|
||||
* Problem 3
|
||||
* [Sol1](https://github.com/TheAlgorithms/Ruby/blob/master/project_euler/problem_3/sol1.rb)
|
||||
* [Sol2](https://github.com/TheAlgorithms/Ruby/blob/master/project_euler/problem_3/sol2.rb)
|
||||
* Problem 4
|
||||
* [Sol1](https://github.com/TheAlgorithms/Ruby/blob/master/project_euler/problem_4/sol1.rb)
|
||||
* [Sol2](https://github.com/TheAlgorithms/Ruby/blob/master/project_euler/problem_4/sol2.rb)
|
||||
* Problem 5
|
||||
* [Sol1](https://github.com/TheAlgorithms/Ruby/blob/master/project_euler/problem_5/sol1.rb)
|
||||
|
||||
## Searches
|
||||
* [Binary Search](https://github.com/TheAlgorithms/Ruby/blob/master/searches/binary_search.rb)
|
||||
* [Depth First Search](https://github.com/TheAlgorithms/Ruby/blob/master/searches/depth_first_search.rb)
|
||||
* [Double Linear Search](https://github.com/TheAlgorithms/Ruby/blob/master/searches/double_linear_search.rb)
|
||||
|
||||
## Searches
|
||||
* [Jump Search](https://github.com/TheAlgorithms/Ruby/blob/master/Searches/jump_search.rb)
|
||||
|
||||
## Searches
|
||||
* [Linear Search](https://github.com/TheAlgorithms/Ruby/blob/master/searches/linear_search.rb)
|
||||
* [Recursive Double Linear Search](https://github.com/TheAlgorithms/Ruby/blob/master/searches/recursive_double_linear_search.rb)
|
||||
* [Recursive Linear Search](https://github.com/TheAlgorithms/Ruby/blob/master/searches/recursive_linear_search.rb)
|
||||
* [Ternary Search](https://github.com/TheAlgorithms/Ruby/blob/master/searches/ternary_search.rb)
|
||||
|
||||
## Sorting
|
||||
* [Bogo Sort](https://github.com/TheAlgorithms/Ruby/blob/master/sorting/bogo_sort.rb)
|
||||
* [Bogo Sort Test](https://github.com/TheAlgorithms/Ruby/blob/master/sorting/bogo_sort_test.rb)
|
||||
* [Bubble Sort](https://github.com/TheAlgorithms/Ruby/blob/master/sorting/bubble_sort.rb)
|
||||
* [Bucket Sort](https://github.com/TheAlgorithms/Ruby/blob/master/sorting/bucket_sort.rb)
|
||||
* [Heap Sort](https://github.com/TheAlgorithms/Ruby/blob/master/sorting/heap_sort.rb)
|
||||
* [Insertion Sort](https://github.com/TheAlgorithms/Ruby/blob/master/sorting/insertion_sort.rb)
|
||||
* [Merge Sort](https://github.com/TheAlgorithms/Ruby/blob/master/sorting/merge_sort.rb)
|
||||
* [Quicksort](https://github.com/TheAlgorithms/Ruby/blob/master/sorting/quicksort.rb)
|
||||
* [Radix Sort](https://github.com/TheAlgorithms/Ruby/blob/master/sorting/radix_sort.rb)
|
||||
* [Selection Sort](https://github.com/TheAlgorithms/Ruby/blob/master/sorting/selection_sort.rb)
|
||||
* [Shell Sort](https://github.com/TheAlgorithms/Ruby/blob/master/sorting/shell_sort.rb)
|
21
LICENSE.md
Normal file
21
LICENSE.md
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2021 The Algorithms
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
91
README.md
91
README.md
|
@ -1,87 +1,20 @@
|
|||
# The Algorithms - Ruby
|
||||
# The Algorithms - Ruby
|
||||
|
||||
[![Gitter chat](https://img.shields.io/badge/Chat-Gitter-ff69b4.svg?label=Chat&logo=gitter&style=flat-square)](https://gitter.im/TheAlgorithms)
|
||||
[![contributions welcome](https://img.shields.io/static/v1.svg?label=Contributions&message=Welcome&color=0059b3&style=flat-square)](https://github.com/TheAlgorithms/Ruby/blob/master/CONTRIBUTING.md)
|
||||
![](https://img.shields.io/github/repo-size/TheAlgorithms/Ruby.svg?label=Repo%20size&style=flat-square)
|
||||
### All algorithms implemented in Ruby (for education)
|
||||
|
||||
These are for demonstration purposes only.
|
||||
## Sorting Algorithms
|
||||
These implementations are for learning purposes only. Therefore they may be less efficient than the implementations in the Ruby standard library.
|
||||
|
||||
### Bogo Sort
|
||||
![alt text][bogo-image]
|
||||
## Contribution Guidelines
|
||||
|
||||
From [Wikipedia][bogo-wiki]: Bogo sort is a highly ineffective sorting function based on the generate and test paradigm. The function successively generates permutations of its input until it finds one that is sorted. It is not useful for sorting, but may be used for educational purposes, to contrast it with more efficient algorithms.
|
||||
Read our [Contribution Guidelines](CONTRIBUTING.md) before you contribute.
|
||||
|
||||
__Properties__
|
||||
* Unbounded (randomized version), O((n+1)!) (deterministic version)
|
||||
* Best case performance O(n)
|
||||
* Average case performance O((n+1)!)
|
||||
## Community Channel
|
||||
|
||||
### Bubble Sort
|
||||
![alt text][bubble-image]
|
||||
We're on [Gitter](https://gitter.im/TheAlgorithms)! Please join us.
|
||||
|
||||
From [Wikipedia][bubble-wiki]: Bubble sort, sometimes referred to as sinking sort, is a simple sorting algorithm that repeatedly steps through the list to be sorted, compares each pair of adjacent items and swaps them if they are in the wrong order. The pass through the list is repeated until no swaps are needed, which indicates that the list is sorted.
|
||||
## List of Algorithms
|
||||
|
||||
__Properties__
|
||||
* Worst case performance O(n^2)
|
||||
* Best case performance O(n)
|
||||
* Average case performance O(n^2)
|
||||
|
||||
###### View the algorithm in [action][bubble-toptal]
|
||||
|
||||
|
||||
|
||||
### Insertion Sort
|
||||
![alt text][insertion-image]
|
||||
|
||||
From [Wikipedia][insertion-wiki]: Insertion sort is a simple sorting algorithm that builds the final sorted array (or list) one item at a time. It is much less efficient on large lists than more advanced algorithms such as quicksort, heapsort, or merge sort.
|
||||
|
||||
__Properties__
|
||||
* Worst case performance O(n^2)
|
||||
* Best case performance O(n)
|
||||
* Average case performance O(n^2)
|
||||
|
||||
###### View the algorithm in [action][insertion-toptal]
|
||||
|
||||
|
||||
### Selection Sort
|
||||
![alt text][selection-image]
|
||||
|
||||
From [Wikipedia][selection-wiki]: The algorithm divides the input list into two parts: the sublist of items already sorted, which is built up from left to right at the front (left) of the list, and the sublist of items remaining to be sorted that occupy the rest of the list. Initially, the sorted sublist is empty and the unsorted sublist is the entire input list. The algorithm proceeds by finding the smallest (or largest, depending on sorting order) element in the unsorted sublist, exchanging (swapping) it with the leftmost unsorted element (putting it in sorted order), and moving the sublist boundaries one element to the right.
|
||||
|
||||
__Properties__
|
||||
* Worst case performance O(n^2)
|
||||
* Best case performance O(n^2)
|
||||
* Average case performance O(n^2)
|
||||
|
||||
###### View the algorithm in [action][selection-toptal]
|
||||
|
||||
|
||||
### Shell Sort
|
||||
![alt text][shell-image]
|
||||
|
||||
From [Wikipedia][shell-wiki]: Shellsort, also known as Shell sort or Shell's method, is an in-place comparison sort. It can be seen as either a generalization of sorting by exchange (bubble sort) or sorting by insertion (insertion sort).[3] The method starts by sorting pairs of elements far apart from each other, then progressively reducing the gap between elements to be compared. Starting with far apart elements, it can move some out-of-place elements into position faster than a simple nearest neighbor exchange. Donald Shell published the first version of this sort in 1959.[4][5] The running time of Shellsort is heavily dependent on the gap sequence it uses. For many practical variants, determining their time complexity remains an open problem.
|
||||
|
||||
__Properties__
|
||||
* Worst case performance O(n^2)
|
||||
* Best case performance O(n log n)
|
||||
* Average case performance depends on gap sequence
|
||||
|
||||
###### View the algorithm in [action][shell-toptal]
|
||||
|
||||
[selection-toptal]: https://www.toptal.com/developers/sorting-algorithms/selection-sort
|
||||
[selection-wiki]: https://en.wikipedia.org/wiki/Selection_sort
|
||||
[selection-image]: https://upload.wikimedia.org/wikipedia/commons/thumb/b/b0/Selection_sort_animation.gif/250px-Selection_sort_animation.gif "Selection Sort Sort"
|
||||
|
||||
|
||||
[bubble-toptal]: https://www.toptal.com/developers/sorting-algorithms/bubble-sort
|
||||
[bubble-wiki]: https://en.wikipedia.org/wiki/Bubble_sort
|
||||
[bubble-image]: https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/Bubblesort-edited-color.svg/220px-Bubblesort-edited-color.svg.png "Bubble Sort"
|
||||
|
||||
[insertion-toptal]: https://www.toptal.com/developers/sorting-algorithms/insertion-sort
|
||||
[insertion-wiki]: https://en.wikipedia.org/wiki/Insertion_sort
|
||||
[insertion-image]: https://upload.wikimedia.org/wikipedia/commons/7/7e/Insertionsort-edited.png "Insertion Sort"
|
||||
|
||||
[shell-toptal]: https://www.toptal.com/developers/sorting-algorithms/shell-sort
|
||||
[shell-wiki]: https://en.wikipedia.org/wiki/Shellsort
|
||||
[shell-image]: https://upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Shell_sorting_algorithm_color_bars.svg/267px-Shell_sorting_algorithm_color_bars.svg.png "Shell Sort"
|
||||
|
||||
[bogo-wiki]: https://en.wikipedia.org/wiki/Bogosort
|
||||
[bogo-image]: http://www.siafoo.net/graph/d174e8328044fa36d07b25a4c0ad6631
|
||||
See our [directory](DIRECTORY.md).
|
||||
|
|
7
Rakefile
Normal file
7
Rakefile
Normal file
|
@ -0,0 +1,7 @@
|
|||
require 'rake/testtask'
|
||||
|
||||
Rake::TestTask.new(:test) do |t|
|
||||
t.test_files = FileList['**/*_test.rb']
|
||||
end
|
||||
|
||||
task default: :test
|
42
Searches/jump_search.rb
Normal file
42
Searches/jump_search.rb
Normal file
|
@ -0,0 +1,42 @@
|
|||
# Works only on sorted arrays.
|
||||
# Finding element by creating step in array and jump ahead by fixed steps and finding element using linear search inside that steped array.
|
||||
# Time Complexity: O(√n)
|
||||
|
||||
def jump_search(arr, x)
|
||||
n = arr.length
|
||||
|
||||
# Finding block size to be jumped
|
||||
step = Math.sqrt(n)
|
||||
prev = 0
|
||||
|
||||
# Finding the block where element is
|
||||
# present (if it is present)
|
||||
while arr[[step, n].min - 1] < x
|
||||
prev = step
|
||||
step += Math.sqrt(n)
|
||||
return -1 if prev >= n
|
||||
end
|
||||
|
||||
# Doing a linear search for x in block
|
||||
# beginning with prev.
|
||||
while arr[prev] < x
|
||||
prev += 1
|
||||
# If we reached next block or end of
|
||||
# array, element is not present.
|
||||
return -1 if prev == [step, n].min
|
||||
end
|
||||
|
||||
# If element is found
|
||||
return prev if arr[prev] == x
|
||||
|
||||
-1
|
||||
end
|
||||
|
||||
puts 'Enter a sorted space-separated list:'
|
||||
arr = gets.chomp.split(' ').map(&:to_i)
|
||||
puts 'Enter the value to be searched:'
|
||||
value = gets.chomp.to_i
|
||||
|
||||
index = jump_search(arr, value)
|
||||
|
||||
puts index == -1 ? 'Element not found' : "Number #{value} is at #{index}"
|
|
@ -1,18 +0,0 @@
|
|||
class Array
|
||||
def sorted?
|
||||
### goes thru array and checks if all elements are in order
|
||||
for i in 1...self.length
|
||||
return false if self[i-1] > self[i]
|
||||
end
|
||||
return true
|
||||
end
|
||||
def bogosort
|
||||
### randomly shuffles until sorted
|
||||
self.shuffle! until self.sorted?
|
||||
return self #return sorted array
|
||||
end
|
||||
end
|
||||
|
||||
puts "Enter a list of numbers seprated by space"
|
||||
str = gets.chomp.split('')
|
||||
puts str.bogosort.join('')
|
|
@ -1,22 +0,0 @@
|
|||
def bubble_sort(array)
|
||||
n = array.length
|
||||
loop do
|
||||
swapped = false
|
||||
|
||||
(n-1).times do |i|
|
||||
if array[i] > array[i+1]
|
||||
array[i], array[i+1] = array[i+1], array[i]
|
||||
swapped = true
|
||||
end
|
||||
end
|
||||
|
||||
break if not swapped
|
||||
end
|
||||
|
||||
array
|
||||
end
|
||||
puts "Enter a list of numbers seprated by space"
|
||||
|
||||
list = gets
|
||||
bubble_sort(list)
|
||||
print list
|
|
@ -1,34 +0,0 @@
|
|||
"""
|
||||
Algorithm: Heap-Sort
|
||||
Time-Complexity: O(nlogn)
|
||||
"""
|
||||
def heap_sort(array)
|
||||
array_size = array.size
|
||||
adjusted_array = [nil] + array
|
||||
(array_size / 2).downto(1) do |i|
|
||||
adjusted_down(adjusted_array, i, array_size)
|
||||
end
|
||||
while array_size > 1
|
||||
adjusted_array[1], adjusted_array[array_size] = adjusted_array[array_size], adjusted_array[1]
|
||||
array_size -= 1
|
||||
adjusted_down(adjusted_array, 1, array_size)
|
||||
end
|
||||
adjusted_array.drop(1)
|
||||
end
|
||||
|
||||
#Method to adjust heap in downward manner
|
||||
def adjusted_down(adjusted_array, parent, limit)
|
||||
top = adjusted_array[parent]
|
||||
while (child = 2 * parent) <= limit
|
||||
child += 1 if child < limit and adjusted_array[child] < adjusted_array[child + 1]
|
||||
break if top >= adjusted_array[child]
|
||||
adjusted_array[parent] = adjusted_array[child]
|
||||
parent = child
|
||||
end
|
||||
adjusted_array[parent] = top
|
||||
end
|
||||
|
||||
|
||||
#Code for testing heapsort
|
||||
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15].shuffle
|
||||
print heap_sort(array)
|
|
@ -1,27 +0,0 @@
|
|||
def shell_sort(a)
|
||||
n=a.length
|
||||
h=1
|
||||
|
||||
while (h<n/3) #for computing increment factor "h"
|
||||
h= (3*h)+1
|
||||
end
|
||||
|
||||
while h>=1
|
||||
# Logic of insertion sort with inrement steps of "h"
|
||||
for i in h...n
|
||||
j=i
|
||||
while j>=h
|
||||
if a[j-h]>a[j]
|
||||
temp=a[j]
|
||||
a[j]=a[j-h]
|
||||
a[j-h]=temp
|
||||
end
|
||||
j-=h
|
||||
end
|
||||
end
|
||||
h/=3
|
||||
end
|
||||
|
||||
return a
|
||||
|
||||
end
|
71
ciphers/merkle_hellman_cryptosystem.rb
Executable file
71
ciphers/merkle_hellman_cryptosystem.rb
Executable file
|
@ -0,0 +1,71 @@
|
|||
require 'openssl'
|
||||
|
||||
class MerkleHellman
|
||||
SMALLEST_KNAPSACK_ITEM = 2**32
|
||||
STEP = 2**32
|
||||
|
||||
def initialize(size)
|
||||
@size = size
|
||||
sum = SMALLEST_KNAPSACK_ITEM
|
||||
@easy_knapsack = size.times.map do |_k|
|
||||
x = sum + rand(STEP)
|
||||
sum += x
|
||||
x
|
||||
end
|
||||
@n = sum + rand(STEP)
|
||||
|
||||
loop do
|
||||
@a = rand(0..@n)
|
||||
break if @a.gcd(@n) == 1
|
||||
end
|
||||
|
||||
@hard_knapsack = @easy_knapsack.map do |x|
|
||||
(@a * x) % @n
|
||||
end
|
||||
end
|
||||
|
||||
def encrypt(msg)
|
||||
raise ArgumentError, "max length is #{@size / 8} characters" if msg.length * 8 > @size
|
||||
|
||||
c = 0
|
||||
msg.each_codepoint.reverse_each.with_index do |ch, i|
|
||||
7.downto(0) do |j|
|
||||
wj = ch.>>(j).& 1
|
||||
c += wj * @hard_knapsack[i * 8 + 7 - j]
|
||||
end
|
||||
end
|
||||
c
|
||||
end
|
||||
|
||||
def decrypt(c)
|
||||
p = @a.to_bn.mod_inverse(@n).mod_mul(c, @n).to_i
|
||||
byte = 0
|
||||
msg = []
|
||||
@easy_knapsack.reverse_each.with_index do |x, i|
|
||||
bit = 0
|
||||
if p >= x
|
||||
p -= x
|
||||
bit = 1
|
||||
end
|
||||
byte |= (bit << (i % 8))
|
||||
if i % 8 == 7
|
||||
msg << byte.chr
|
||||
byte = 0
|
||||
end
|
||||
end
|
||||
msg.join
|
||||
end
|
||||
attr_accessor :hard_knapsack
|
||||
end
|
||||
|
||||
str = 'Hello there, this is my plaintext'
|
||||
mh = MerkleHellman.new(str.length * 8)
|
||||
puts "[*] Encrypting \"#{str}\""
|
||||
|
||||
c = mh.encrypt(str)
|
||||
|
||||
puts "[*] Ciphertext : #{c}"
|
||||
|
||||
decrypted = mh.decrypt(c)
|
||||
|
||||
puts "[*] after decryption : \"#{decrypted}\""
|
|
@ -1,93 +0,0 @@
|
|||
#Define a node for the list
|
||||
class Node
|
||||
attr_accessor :value, :next
|
||||
def initialize(value)
|
||||
@value = value
|
||||
@next = nil
|
||||
end
|
||||
end
|
||||
|
||||
# Class for circular linked list (last node points to the head node)
|
||||
class CircularList
|
||||
attr_accessor :head
|
||||
|
||||
def initialize()
|
||||
@head = nil
|
||||
end
|
||||
|
||||
def insert_end(value)
|
||||
newNode = Node.new(value)
|
||||
if (@head == nil)
|
||||
@head = newNode
|
||||
@head.next = @head
|
||||
else
|
||||
tempNode = @head
|
||||
while (tempNode.next != @head)
|
||||
tempNode = tempNode.next
|
||||
end
|
||||
newNode.next = @head
|
||||
tempNode.next = newNode
|
||||
end
|
||||
end
|
||||
|
||||
def insert_head(value)
|
||||
newNode = Node.new(value)
|
||||
if (@head == nil)
|
||||
@head = newNode
|
||||
@head.next = head
|
||||
else
|
||||
tempNode = @head
|
||||
while (tempNode.next != @head)
|
||||
tempNode = tempNode.next
|
||||
end
|
||||
newNode.next = @head
|
||||
tempNode.next = newNode
|
||||
@head = newNode
|
||||
end
|
||||
end
|
||||
|
||||
def print_list
|
||||
print "["
|
||||
if (@head != nil)
|
||||
printNode = @head
|
||||
while (printNode.next != @head)
|
||||
print "#{printNode.value}"
|
||||
print ", "
|
||||
printNode = printNode.next
|
||||
end
|
||||
print printNode.value
|
||||
end
|
||||
print "]"
|
||||
STDOUT.flush
|
||||
end
|
||||
|
||||
def delete_head
|
||||
if (@head != nil) && (@head.next != @head)
|
||||
newHead = @head.next
|
||||
tempNode = newHead
|
||||
while(tempNode.next != @head)
|
||||
tempNode = tempNode.next
|
||||
end
|
||||
tempNode.next = newHead
|
||||
@head = newHead
|
||||
elsif (@head != nil) && (@head.next == @head)
|
||||
@head = nil
|
||||
end
|
||||
end
|
||||
|
||||
def delete_end
|
||||
if (@head != nil) && (@head.next != @head)
|
||||
tempNode = @head
|
||||
while (tempNode.next.next != @head)
|
||||
tempNode = tempNode.next
|
||||
end
|
||||
tempNode.next = @head
|
||||
elsif (@head != nil) && (@head.next == @head)
|
||||
@head = nil
|
||||
end
|
||||
end
|
||||
|
||||
def isEmpty()
|
||||
return (@head==nil)
|
||||
end
|
||||
end
|
87
data_structures/arrays/get_products_of_all_other_elements.rb
Normal file
87
data_structures/arrays/get_products_of_all_other_elements.rb
Normal file
|
@ -0,0 +1,87 @@
|
|||
# Arrays - Get Products of all other elements in Ruby
|
||||
|
||||
# Algorithm challenge description:
|
||||
# Given an array of integers, return a new array such that
|
||||
# each element at index `i` of the new array is the product of
|
||||
# all the numbers in the original array except the one at `i`.
|
||||
|
||||
#
|
||||
# 1. Brute force solution
|
||||
#
|
||||
def calculate_products_of_all_other_elements(nums)
|
||||
product_of_other_elements = Array.new(nums.length, 1)
|
||||
|
||||
nums.each_with_index do |_num1, i|
|
||||
nums.each_with_index do |num2, j|
|
||||
product_of_other_elements[i] = product_of_other_elements[i] * num2 if i != j
|
||||
end
|
||||
end
|
||||
|
||||
product_of_other_elements
|
||||
end
|
||||
|
||||
puts(calculate_products_of_all_other_elements([1, 2, 3]))
|
||||
|
||||
#
|
||||
# 2. O(n) time and space
|
||||
# Arrays - Get Products of all other elements in Ruby
|
||||
#
|
||||
|
||||
# Generates prefix products
|
||||
def build_prefix_products(nums)
|
||||
prefix_products = []
|
||||
|
||||
nums.each do |num|
|
||||
prefix_products << if prefix_products.count > 0
|
||||
(prefix_products.last * num)
|
||||
else
|
||||
num
|
||||
end
|
||||
end
|
||||
|
||||
prefix_products
|
||||
end
|
||||
|
||||
# Generates suffix products
|
||||
def build_suffix_products(nums)
|
||||
suffix_products = []
|
||||
|
||||
nums.reverse.each do |num|
|
||||
suffix_products << if suffix_products.count > 0
|
||||
(suffix_products.last * num)
|
||||
else
|
||||
num
|
||||
end
|
||||
end
|
||||
|
||||
suffix_products
|
||||
end
|
||||
|
||||
# Builds output
|
||||
def output(prefix_products, suffix_products, nums)
|
||||
result = []
|
||||
|
||||
nums.reverse.each_with_index do |_num, index|
|
||||
result << if index == 0
|
||||
suffix_products[index + 1]
|
||||
elsif index == nums.length - 1
|
||||
prefix_products[index - 1]
|
||||
else
|
||||
(prefix_products[index - 1] * suffix_products[index + 1])
|
||||
end
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
# Generate result from the product of prefixes and suffixes
|
||||
def products(nums)
|
||||
prefix_products = build_prefix_products(nums)
|
||||
suffix_products = build_suffix_products(nums)
|
||||
suffix_products = suffix_products.reverse
|
||||
|
||||
output(prefix_products, suffix_products, nums)
|
||||
end
|
||||
|
||||
puts(products([1, 2, 3]))
|
||||
# => [6, 3, 2]
|
|
@ -1,23 +1,23 @@
|
|||
# Definition for a binary tree node.
|
||||
# class TreeNode
|
||||
# attr_accessor :val, :left, :right
|
||||
# def initialize(val)
|
||||
# @val = val
|
||||
# @left, @right = nil, nil
|
||||
# end
|
||||
# attr_accessor :val, :left, :right
|
||||
# def initialize(val)
|
||||
# @val = val
|
||||
# @left, @right = nil, nil
|
||||
# end
|
||||
# end
|
||||
|
||||
# @param {TreeNode} root
|
||||
# @return {Integer[]}
|
||||
def inorder_traversal(root)
|
||||
ans = []
|
||||
def traverse(node, ans)
|
||||
if node != nil
|
||||
traverse(node.left, ans)
|
||||
ans.push(node.val)
|
||||
traverse(node.right,ans)
|
||||
end
|
||||
ans = []
|
||||
def traverse(node, ans)
|
||||
unless node.nil?
|
||||
traverse(node.left, ans)
|
||||
ans.push(node.val)
|
||||
traverse(node.right, ans)
|
||||
end
|
||||
traverse(root,ans)
|
||||
return ans
|
||||
end
|
||||
end
|
||||
traverse(root, ans)
|
||||
ans
|
||||
end
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
# Definition for a binary tree node.
|
||||
# class TreeNode
|
||||
# attr_accessor :val, :left, :right
|
||||
# def initialize(val)
|
||||
# @val = val
|
||||
# @left, @right = nil, nil
|
||||
# end
|
||||
# attr_accessor :val, :left, :right
|
||||
# def initialize(val)
|
||||
# @val = val
|
||||
# @left, @right = nil, nil
|
||||
# end
|
||||
# end
|
||||
|
||||
# @param {TreeNode} root
|
||||
# @return {TreeNode}
|
||||
def invert_tree(root)
|
||||
if root == nil
|
||||
return nil
|
||||
end
|
||||
temp = root.left
|
||||
root.left = invert_tree(root.right)
|
||||
root.right = invert_tree(temp)
|
||||
return root
|
||||
end
|
||||
return nil if root.nil?
|
||||
|
||||
temp = root.left
|
||||
root.left = invert_tree(root.right)
|
||||
root.right = invert_tree(temp)
|
||||
root
|
||||
end
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
# Definition for a binary tree node.
|
||||
# class TreeNode
|
||||
# attr_accessor :val, :left, :right
|
||||
# def initialize(val)
|
||||
# @val = val
|
||||
# @left, @right = nil, nil
|
||||
# end
|
||||
# attr_accessor :val, :left, :right
|
||||
# def initialize(val)
|
||||
# @val = val
|
||||
# @left, @right = nil, nil
|
||||
# end
|
||||
# end
|
||||
|
||||
# @param {TreeNode} root
|
||||
# @return {Integer[]}
|
||||
def postorder_traversal(root)
|
||||
ans = []
|
||||
def traverse(node, ans)
|
||||
if node != nil
|
||||
traverse(node.left, ans)
|
||||
traverse(node.right,ans)
|
||||
ans.push(node.val)
|
||||
end
|
||||
ans = []
|
||||
def traverse(node, ans)
|
||||
unless node.nil?
|
||||
traverse(node.left, ans)
|
||||
traverse(node.right, ans)
|
||||
ans.push(node.val)
|
||||
end
|
||||
traverse(root,ans)
|
||||
return ans
|
||||
end
|
||||
end
|
||||
traverse(root, ans)
|
||||
ans
|
||||
end
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
# Definition for a binary tree node.
|
||||
# class TreeNode
|
||||
# attr_accessor :val, :left, :right
|
||||
# def initialize(val)
|
||||
# @val = val
|
||||
# @left, @right = nil, nil
|
||||
# end
|
||||
# attr_accessor :val, :left, :right
|
||||
# def initialize(val)
|
||||
# @val = val
|
||||
# @left, @right = nil, nil
|
||||
# end
|
||||
# end
|
||||
|
||||
# @param {TreeNode} root
|
||||
# @return {Integer[]}
|
||||
def preorder_traversal(root)
|
||||
ans = []
|
||||
def traverse(node, ans)
|
||||
if node != nil
|
||||
ans.push(node.val)
|
||||
traverse(node.left, ans)
|
||||
traverse(node.right,ans)
|
||||
end
|
||||
ans = []
|
||||
def traverse(node, ans)
|
||||
unless node.nil?
|
||||
ans.push(node.val)
|
||||
traverse(node.left, ans)
|
||||
traverse(node.right, ans)
|
||||
end
|
||||
traverse(root,ans)
|
||||
return ans
|
||||
end
|
||||
end
|
||||
traverse(root, ans)
|
||||
ans
|
||||
end
|
||||
|
|
86
data_structures/linked_lists/circular_list.rb
Normal file
86
data_structures/linked_lists/circular_list.rb
Normal file
|
@ -0,0 +1,86 @@
|
|||
# Define a node for the list
|
||||
class Node
|
||||
attr_accessor :value, :next
|
||||
|
||||
def initialize(value)
|
||||
@value = value
|
||||
@next = nil
|
||||
end
|
||||
end
|
||||
|
||||
# Class for circular linked list (last node points to the head node)
|
||||
class CircularList
|
||||
attr_accessor :head
|
||||
|
||||
def initialize
|
||||
@head = nil
|
||||
end
|
||||
|
||||
def insert_end(value)
|
||||
newNode = Node.new(value)
|
||||
if @head.nil?
|
||||
@head = newNode
|
||||
@head.next = @head
|
||||
else
|
||||
tempNode = @head
|
||||
tempNode = tempNode.next while tempNode.next != @head
|
||||
newNode.next = @head
|
||||
tempNode.next = newNode
|
||||
end
|
||||
end
|
||||
|
||||
def insert_head(value)
|
||||
newNode = Node.new(value)
|
||||
if @head.nil?
|
||||
@head = newNode
|
||||
@head.next = head
|
||||
else
|
||||
tempNode = @head
|
||||
tempNode = tempNode.next while tempNode.next != @head
|
||||
newNode.next = @head
|
||||
tempNode.next = newNode
|
||||
@head = newNode
|
||||
end
|
||||
end
|
||||
|
||||
def print_list
|
||||
print '['
|
||||
unless @head.nil?
|
||||
printNode = @head
|
||||
while printNode.next != @head
|
||||
print printNode.value.to_s
|
||||
print ', '
|
||||
printNode = printNode.next
|
||||
end
|
||||
print printNode.value
|
||||
end
|
||||
print ']'
|
||||
STDOUT.flush
|
||||
end
|
||||
|
||||
def delete_head
|
||||
if !@head.nil? && (@head.next != @head)
|
||||
newHead = @head.next
|
||||
tempNode = newHead
|
||||
tempNode = tempNode.next while tempNode.next != @head
|
||||
tempNode.next = newHead
|
||||
@head = newHead
|
||||
elsif !@head.nil? && (@head.next == @head)
|
||||
@head = nil
|
||||
end
|
||||
end
|
||||
|
||||
def delete_end
|
||||
if !@head.nil? && (@head.next != @head)
|
||||
tempNode = @head
|
||||
tempNode = tempNode.next while tempNode.next.next != @head
|
||||
tempNode.next = @head
|
||||
elsif !@head.nil? && (@head.next == @head)
|
||||
@head = nil
|
||||
end
|
||||
end
|
||||
|
||||
def isEmpty
|
||||
@head.nil?
|
||||
end
|
||||
end
|
|
@ -1,6 +1,7 @@
|
|||
# Define a node in the list
|
||||
class Node
|
||||
attr_accessor :value, :next, :prev
|
||||
|
||||
def initialize(value)
|
||||
@value = value
|
||||
@next = nil
|
||||
|
@ -10,15 +11,17 @@ end
|
|||
|
||||
# A Class for double linked lists (each element links to the next one, and to the previous one)
|
||||
class DoubleList
|
||||
include Enumerable
|
||||
attr_accessor :head, :tail
|
||||
def initialize()
|
||||
|
||||
def initialize
|
||||
@head = nil
|
||||
@tail = nil
|
||||
end
|
||||
|
||||
def insert_tail(value)
|
||||
new_node = Node.new(value)
|
||||
if (@head == nil)
|
||||
if @head.nil?
|
||||
@head = new_node
|
||||
@tail = new_node
|
||||
else
|
||||
|
@ -30,7 +33,7 @@ class DoubleList
|
|||
|
||||
def insert_head(value)
|
||||
new_node = Node.new(value)
|
||||
if (@head == nil)
|
||||
if @head.nil?
|
||||
@head = new_node
|
||||
@tail = new_node
|
||||
else
|
||||
|
@ -40,41 +43,36 @@ class DoubleList
|
|||
end
|
||||
end
|
||||
|
||||
def delete_tail()
|
||||
if (@tail != nil)
|
||||
def delete_tail
|
||||
until @tail.nil?
|
||||
@tail = @tail.prev
|
||||
if (@tail != nil)
|
||||
@tail.next = nil
|
||||
end
|
||||
@tail.next = nil unless @tail.nil?
|
||||
end
|
||||
end
|
||||
|
||||
def delete_head()
|
||||
if (@head != nil)
|
||||
def delete_head
|
||||
until @head.nil?
|
||||
@head = @head.next
|
||||
if (@head != nil)
|
||||
@head.prev = nil
|
||||
end
|
||||
@head.prev = nil unless @head.nil?
|
||||
end
|
||||
end
|
||||
|
||||
def print_list()
|
||||
print "["
|
||||
if (@head != nil)
|
||||
printNode = @head
|
||||
while (printNode != nil)
|
||||
print "#{printNode.value}"
|
||||
if (printNode != @tail)
|
||||
print ", "
|
||||
end
|
||||
printNode = printNode.next
|
||||
end
|
||||
def each
|
||||
return if @head.nil?
|
||||
|
||||
current = @head
|
||||
until current.nil?
|
||||
yield current.value
|
||||
current = current.next
|
||||
end
|
||||
print "]"
|
||||
STDOUT.flush
|
||||
end
|
||||
|
||||
def is_empty()
|
||||
return (@head==nil)
|
||||
def print_list
|
||||
# the to_a method is from Enumerable, will call each to get the values, and return an array
|
||||
puts '[' + to_a.join(', ') + ']'
|
||||
end
|
||||
end
|
||||
|
||||
def empty?
|
||||
@head.nil?
|
||||
end
|
||||
end
|
|
@ -1,6 +1,7 @@
|
|||
# Define a node in the list
|
||||
class Node
|
||||
attr_accessor :value, :next
|
||||
|
||||
def initialize(value)
|
||||
@value = value
|
||||
@next = nil
|
||||
|
@ -10,27 +11,27 @@ end
|
|||
# A Class for single linked lists (each element links to the next one, but not to the previous one)
|
||||
|
||||
class SingleList
|
||||
include Enumerable
|
||||
attr_accessor :head
|
||||
def initialize()
|
||||
|
||||
def initialize
|
||||
@head = nil
|
||||
end
|
||||
|
||||
def insert_tail(value)
|
||||
newNode = Node.new(value)
|
||||
if (@head == nil)
|
||||
if @head.nil?
|
||||
@head = newNode
|
||||
else
|
||||
tempNode = @head
|
||||
while (tempNode.next != nil)
|
||||
tempNode = tempNode.next
|
||||
end
|
||||
tempNode = tempNode.next until tempNode.next.nil?
|
||||
tempNode.next = newNode
|
||||
end
|
||||
end
|
||||
|
||||
def insert_head(value)
|
||||
newNode = Node.new(value)
|
||||
if (@head == nil)
|
||||
if @head.nil?
|
||||
@head = newNode
|
||||
else
|
||||
newNode.next = @head
|
||||
|
@ -38,43 +39,38 @@ class SingleList
|
|||
end
|
||||
end
|
||||
|
||||
def print_list()
|
||||
print "["
|
||||
if (@head != nil)
|
||||
printNode = @head
|
||||
while (printNode != nil)
|
||||
print "#{printNode.value}"
|
||||
if (printNode.next != nil)
|
||||
print ", "
|
||||
end
|
||||
printNode = printNode.next
|
||||
end
|
||||
def each
|
||||
return if @head.nil?
|
||||
|
||||
current = @head
|
||||
until current.nil?
|
||||
yield current.value
|
||||
current = current.next
|
||||
end
|
||||
print "]"
|
||||
STDOUT.flush
|
||||
end
|
||||
|
||||
def print_list
|
||||
puts '[' + to_a.join(', ') + ']'
|
||||
end
|
||||
|
||||
def delete_head
|
||||
if (@head != nil) && (@head.next != nil)
|
||||
if !@head.nil? && !@head.next.nil?
|
||||
newHead = @head.next
|
||||
@head = newHead
|
||||
elsif (@head != nil) && (@head.next == nil)
|
||||
elsif !@head.nil? && @head.next.nil?
|
||||
@head = nil
|
||||
end
|
||||
end
|
||||
|
||||
def delete_tail
|
||||
if (@head != nil)
|
||||
tempNode = @head
|
||||
while (tempNode.next.next != nil)
|
||||
tempNode = tempNode.next
|
||||
end
|
||||
tempNode.next = nil
|
||||
end
|
||||
return if @head.nil?
|
||||
|
||||
tempNode = @head
|
||||
tempNode = tempNode.next until tempNode.next.next.nil?
|
||||
tempNode.next = nil
|
||||
end
|
||||
|
||||
def isEmpty()
|
||||
return (@head==nil)
|
||||
def empty?
|
||||
@head.nil?
|
||||
end
|
||||
|
||||
end
|
||||
end
|
106
data_structures/queues/queue.rb
Normal file
106
data_structures/queues/queue.rb
Normal file
|
@ -0,0 +1,106 @@
|
|||
# A queue is like a waiting list.
|
||||
# Imagine you are waiting in line to buy the latest Android product
|
||||
# or getting a parking ticket. These are queues!
|
||||
|
||||
#
|
||||
#
|
||||
# 1. An array can behave like a Queue if you use the right methods.
|
||||
#
|
||||
# These methods are:
|
||||
# - unshift: when you unshift, you are adding one item to the queue
|
||||
# - pop
|
||||
#
|
||||
|
||||
class ArrayQueue
|
||||
def initialize(queue = [])
|
||||
@queue = queue
|
||||
end
|
||||
|
||||
attr_accessor :queue
|
||||
|
||||
def add(item)
|
||||
queue.unshift(item)
|
||||
end
|
||||
|
||||
def pop
|
||||
queue.pop
|
||||
end
|
||||
|
||||
def peek
|
||||
queue[-1]
|
||||
end
|
||||
end
|
||||
|
||||
queue = ArrayQueue.new
|
||||
queue.add(3)
|
||||
queue.add(4)
|
||||
queue.add(5)
|
||||
|
||||
puts queue.inspect
|
||||
# => #<ArrayQueue:0x00007fc78200f5e0 @queue=[5, 4, 3]>
|
||||
|
||||
queue.pop
|
||||
|
||||
puts queue.inspect
|
||||
# => #<ArrayQueue:0x00007fc78200f5e0 @queue=[5, 4]>
|
||||
|
||||
puts(queue.peek)
|
||||
# => 4
|
||||
|
||||
#
|
||||
#
|
||||
# 2. Ruby Concurrent Queue
|
||||
# Ruby has a proper thread-safe, blocking, Queue class.
|
||||
# You can use this queue for coordinating work in a multi-threaded program.
|
||||
#
|
||||
# Reference: https://ruby-doc.org/core-2.5.0/Queue.html
|
||||
#
|
||||
|
||||
queue = Queue.new
|
||||
|
||||
queue << 1
|
||||
queue << 2
|
||||
queue << 3
|
||||
|
||||
queue.pop
|
||||
# 1
|
||||
|
||||
queue.pop
|
||||
# 2
|
||||
|
||||
# If the queue is empty, calling pop will put your current
|
||||
# thread to sleep & wait until something is added to the queue.
|
||||
|
||||
#
|
||||
#
|
||||
# 3. How to Use a Ruby SizedQueue
|
||||
# A sized queue is the same as a regular queue but with a size limit.
|
||||
#
|
||||
# Reference: https://ruby-doc.org/core-2.5.0/SizedQueue.html
|
||||
#
|
||||
|
||||
queue = SizedQueue.new(5)
|
||||
|
||||
# When the queue is full, the push (same as <<) operation
|
||||
# will suspend the current thread until an item is taken off the queue.
|
||||
|
||||
queue.push(:oranges)
|
||||
queue.push(:apples)
|
||||
queue.push(:blue)
|
||||
queue.push(:orange)
|
||||
queue.push(:green)
|
||||
# At this point, the SizedQueue is full
|
||||
|
||||
queue.push(:throw_expection)
|
||||
# data_structures/queues/queue.rb:81:in `push': No live threads left. Deadlock? (fatal)
|
||||
# 1 threads, 1 sleeps current:0x00007ff54f407130 main thread:0x00007ff54f407130
|
||||
# * #<Thread:0x00007ff54f86ef38 sleep_forever>
|
||||
# rb_thread_t:0x00007ff54f407130 native:0x000000010dd24dc0 int:0
|
||||
# data_structures/queues/queue.rb:81:in `push'
|
||||
# data_structures/queues/queue.rb:81:in `<main>'
|
||||
# from data_structures/queues/queue.rb:81:in `<main>'
|
||||
|
||||
# You can choose to raise an exception, passing true as an argument as follows:
|
||||
queue.push(:throw_expection, true)
|
||||
# data_structures/queues/queue.rb:83:in `push': queue full (ThreadError)
|
||||
# from data_structures/queues/queue.rb:83:in `<main>'
|
87
data_structures/stacks/stack.rb
Normal file
87
data_structures/stacks/stack.rb
Normal file
|
@ -0,0 +1,87 @@
|
|||
# A stack is an abstract data type that serves as a collection of
|
||||
# elements with two principal operations: push() and pop(). push() adds an
|
||||
# element to the top of the stack, and pop() removes an element from the top
|
||||
# of a stack. The order in which elements come off of a stack are
|
||||
# Last In, First Out (LIFO)
|
||||
|
||||
class StackOverflowError < StandardError; end
|
||||
|
||||
class Stack
|
||||
def initialize(limit, stack = [])
|
||||
@stack = stack
|
||||
@limit = limit
|
||||
end
|
||||
|
||||
attr_accessor :stack, :limit
|
||||
|
||||
def push(item)
|
||||
raise StackOverflowError unless stack.count < limit
|
||||
|
||||
stack << item
|
||||
end
|
||||
|
||||
def pop
|
||||
stack.pop
|
||||
end
|
||||
|
||||
def peek
|
||||
stack.last
|
||||
end
|
||||
|
||||
def empty?
|
||||
stack.count.zero?
|
||||
end
|
||||
|
||||
def full?
|
||||
stack.count == limit
|
||||
end
|
||||
|
||||
def size
|
||||
stack.count
|
||||
end
|
||||
|
||||
def contains?(item)
|
||||
stack.include?(item)
|
||||
end
|
||||
end
|
||||
|
||||
stack = Stack.new(10, [])
|
||||
|
||||
puts stack.empty?
|
||||
# => true
|
||||
|
||||
stack.push(3)
|
||||
stack.push(5)
|
||||
stack.push(7)
|
||||
stack.push(9)
|
||||
|
||||
puts stack.full?
|
||||
# => false
|
||||
|
||||
puts stack.contains?(5)
|
||||
# => true
|
||||
|
||||
puts stack.pop
|
||||
# => 9
|
||||
|
||||
puts stack.peek
|
||||
# => 7
|
||||
|
||||
puts stack.size
|
||||
# => 3
|
||||
|
||||
puts stack.inspect
|
||||
# => #<Stack:0x00007fceed83eb40 @stack=[3, 5, 7], @limit=10>
|
||||
|
||||
stack.push(13)
|
||||
stack.push(15)
|
||||
stack.push(17)
|
||||
stack.push(19)
|
||||
stack.push(23)
|
||||
stack.push(25)
|
||||
stack.push(27)
|
||||
# At this point, the stack is full
|
||||
|
||||
stack.push(29)
|
||||
# => data_structures/stacks/stack.rb:18:in `push': StackOverflowError (StackOverflowError)
|
||||
# from data_structures/stacks/stack.rb:83:in `<main>'
|
75
data_structures/tries/trie.rb
Normal file
75
data_structures/tries/trie.rb
Normal file
|
@ -0,0 +1,75 @@
|
|||
# A Trie (prefix tree) is a kind of search tree used to provide quick lookup
|
||||
# of words/patterns in a set of words. A basic Trie however has O(n^2)
|
||||
# space complexity making it impractical in practice.
|
||||
# It however provides O(max(search_string, length of longest word))
|
||||
# lookup time making it an optimal approach when space is not an issue.
|
||||
|
||||
class Node
|
||||
attr_reader :value, :next
|
||||
attr_accessor :word
|
||||
|
||||
def initialize(value)
|
||||
@value = value
|
||||
@word = false
|
||||
@next = []
|
||||
end
|
||||
end
|
||||
|
||||
class Trie
|
||||
def initialize
|
||||
@root = Node.new('*')
|
||||
end
|
||||
|
||||
def insert_many(word)
|
||||
letters = word.chars
|
||||
base = @root
|
||||
|
||||
letters.each do |letter|
|
||||
base = insert(letter, base.next)
|
||||
end
|
||||
end
|
||||
|
||||
def include?(word)
|
||||
letters = word.chars
|
||||
base = @root
|
||||
|
||||
letters.all? do |letter|
|
||||
base = find(letter, base.next)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# check if it already exists
|
||||
# if not add character to node
|
||||
def insert(character, trie)
|
||||
found = trie.find do |n|
|
||||
n.value == character
|
||||
end
|
||||
|
||||
add_node(character, trie) unless found
|
||||
end
|
||||
|
||||
def add_node(character, trie)
|
||||
Node.new(character).tap do |new_node|
|
||||
trie << new_node
|
||||
end
|
||||
end
|
||||
|
||||
def find(character, trie)
|
||||
trie.find do |n|
|
||||
n.value == character
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
trie = Trie.new
|
||||
trie.insert_many('Dogs')
|
||||
trie.insert_many('South')
|
||||
trie.insert_many('Cape Town')
|
||||
|
||||
puts trie.include?('Cape Town')
|
||||
# => true
|
||||
|
||||
puts trie.include?('not presented')
|
||||
# => false
|
|
@ -1,16 +1,14 @@
|
|||
#https://en.wikipedia.org/wiki/Euclidean_algorithm
|
||||
# https://en.wikipedia.org/wiki/Euclidean_algorithm
|
||||
|
||||
def euclidean_gcd(a, b)
|
||||
while b != 0
|
||||
t = b
|
||||
b = a % b
|
||||
a = t
|
||||
end
|
||||
return a
|
||||
while b != 0
|
||||
t = b
|
||||
b = a % b
|
||||
a = t
|
||||
end
|
||||
a
|
||||
end
|
||||
|
||||
puts "GCD(3, 5) = " + euclidean_gcd(3, 5).to_s
|
||||
puts "GCD(3, 6) = " + euclidean_gcd(3, 6).to_s
|
||||
puts "GCD(6, 3) = " + euclidean_gcd(6, 3).to_s
|
||||
|
||||
|
||||
puts 'GCD(3, 5) = ' + euclidean_gcd(3, 5).to_s
|
||||
puts 'GCD(3, 6) = ' + euclidean_gcd(3, 6).to_s
|
||||
puts 'GCD(6, 3) = ' + euclidean_gcd(6, 3).to_s
|
||||
|
|
30
discrete_mathematics/exteded_euclidean_algorithm.rb
Normal file
30
discrete_mathematics/exteded_euclidean_algorithm.rb
Normal file
|
@ -0,0 +1,30 @@
|
|||
# https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm
|
||||
|
||||
def extended_euclidean_gcd(a, b)
|
||||
x0 = a
|
||||
x1 = b
|
||||
s = 1
|
||||
t = 0
|
||||
until x1.zero?
|
||||
q, x2 = x0.divmod(x1)
|
||||
x0 = x1
|
||||
x1 = x2
|
||||
s, t = t, s - q * t
|
||||
end
|
||||
x0
|
||||
end
|
||||
|
||||
puts 'GCD(3, 5) = ' + extended_euclidean_gcd(3, 5).to_s
|
||||
# GCD(3, 5) = 1
|
||||
puts 'GCD(3, 6) = ' + extended_euclidean_gcd(3, 6).to_s
|
||||
# GCD(3, 6) = 3
|
||||
puts 'GCD(6, 3) = ' + extended_euclidean_gcd(6, 3).to_s
|
||||
# GCD(6, 3) = 3
|
||||
|
||||
#
|
||||
# Dynamic driver code:
|
||||
#
|
||||
# a = gets.to_i
|
||||
# b = gets.to_i
|
||||
# puts "GCD (#{a}, #{b} ) = #{extended_euclidean_gcd(a, b)}"
|
||||
#
|
|
@ -1,23 +1,23 @@
|
|||
# LCM (Least Common Multiple) of two numbers is the smallest number which can be divided by both numbers.
|
||||
|
||||
p "Least Common Multiple"
|
||||
p 'Least Common Multiple'
|
||||
|
||||
p "Enter first number"
|
||||
p 'Enter first number'
|
||||
value_one = gets.chomp.to_i
|
||||
|
||||
p "Enter second number"
|
||||
p 'Enter second number'
|
||||
value_two = gets.chomp.to_i
|
||||
|
||||
def gcd(first, second)
|
||||
if second != 0
|
||||
gcd(second, first%second)
|
||||
gcd(second, first % second)
|
||||
else
|
||||
first
|
||||
end
|
||||
end
|
||||
|
||||
def lcm(first, second)
|
||||
(first * second)/gcd(first, second)
|
||||
(first * second) / gcd(first, second)
|
||||
end
|
||||
|
||||
p "Least Common Multiple is: #{lcm(value_one, value_two)}"
|
||||
p "Least Common Multiple is: #{lcm(value_one, value_two)}"
|
||||
|
|
10
maths/abs.rb
Normal file
10
maths/abs.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Calculates the absolute value of a number
|
||||
class Abs
|
||||
def self.call(number)
|
||||
return -number if number.negative?
|
||||
|
||||
number
|
||||
end
|
||||
end
|
18
maths/abs_test.rb
Normal file
18
maths/abs_test.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'minitest/autorun'
|
||||
require_relative './abs'
|
||||
|
||||
class AbsTest < Minitest::Test
|
||||
def test_positive_number
|
||||
assert_equal Abs.call(4), 4
|
||||
end
|
||||
|
||||
def test_zero
|
||||
assert_equal Abs.call(0), 0
|
||||
end
|
||||
|
||||
def test_negative_number
|
||||
assert_equal Abs.call(-9), 9
|
||||
end
|
||||
end
|
21
maths/aliquot_sum.rb
Normal file
21
maths/aliquot_sum.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative './square_root'
|
||||
require_relative './ceil'
|
||||
|
||||
# Calculates the aliquot sum of a number (the sum of all proper divisors of a number)
|
||||
class AliquotSum
|
||||
class << self
|
||||
def call(number)
|
||||
divisors(number).sum
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def divisors(number)
|
||||
low_divisors = (1..Ceil.call(SquareRoot.call(number))).select { |num| (number % num).zero? }
|
||||
high_divisors = low_divisors.map { |div| number / div }
|
||||
(low_divisors + high_divisors).uniq - [number]
|
||||
end
|
||||
end
|
||||
end
|
21
maths/aliquot_sum_test.rb
Normal file
21
maths/aliquot_sum_test.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'minitest/autorun'
|
||||
require_relative './aliquot_sum'
|
||||
|
||||
class AliquotSumTest < Minitest::Test
|
||||
def test_zero
|
||||
assert_equal AliquotSum.call(0), 0
|
||||
end
|
||||
|
||||
def test_one
|
||||
assert_equal Abs.call(1), 1
|
||||
end
|
||||
|
||||
def test_many
|
||||
(2..100).each do |number|
|
||||
expected_aliquot_sum = (1...number).select { |num| (number % num).zero? }.sum
|
||||
assert_equal AliquotSum.call(number), expected_aliquot_sum
|
||||
end
|
||||
end
|
||||
end
|
24
maths/binary_to_decimal.rb
Normal file
24
maths/binary_to_decimal.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
#
|
||||
# For any binary number of n digits i.e dn-1 ... d3 d2 d1 d0
|
||||
# The equivalent decimal number is equal to the sum of binary digits (dn) times their power of 2 (2n):
|
||||
# decimal = d0×2^0 + d1×2^1 + d2×2^2 + ...
|
||||
#
|
||||
|
||||
def binary_to_decimal(n)
|
||||
decimal = 0
|
||||
base = 1
|
||||
until n.zero?
|
||||
x = n % 10
|
||||
n /= 10
|
||||
decimal += x * base
|
||||
base *= 2
|
||||
end
|
||||
decimal
|
||||
end
|
||||
|
||||
puts 'Decimal value of 110011 is ' + binary_to_decimal(110_011).to_s
|
||||
# Decimal value of 110011 is 51
|
||||
puts 'Decimal value of 11110 is ' + binary_to_decimal(11_110).to_s
|
||||
# Decimal value of 11110 is 30
|
||||
puts 'Decimal value of 101 is ' + binary_to_decimal(101).to_s
|
||||
# Decimal value of 101 is 5
|
11
maths/ceil.rb
Normal file
11
maths/ceil.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Ceil
|
||||
class << self
|
||||
def call(number)
|
||||
return number if number.is_a?(Integer) || number == number.to_i
|
||||
|
||||
number.to_i + 1
|
||||
end
|
||||
end
|
||||
end
|
18
maths/ceil_test.rb
Normal file
18
maths/ceil_test.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'minitest/autorun'
|
||||
require_relative './ceil'
|
||||
|
||||
class CeilTest < Minitest::Test
|
||||
def test_integer
|
||||
assert_equal Ceil.call(4), 4
|
||||
end
|
||||
|
||||
def test_float_at_integer
|
||||
assert_equal Ceil.call(4.0), 4
|
||||
end
|
||||
|
||||
def test_float_not_at_integer
|
||||
assert_equal Ceil.call(4.01), 5
|
||||
end
|
||||
end
|
22
maths/number_of_digits.rb
Normal file
22
maths/number_of_digits.rb
Normal file
|
@ -0,0 +1,22 @@
|
|||
# Given a number, find number of digits in it.
|
||||
|
||||
def count_digits(n)
|
||||
count = 0
|
||||
temp = n
|
||||
|
||||
return 1 if n == 0
|
||||
|
||||
until temp.zero?
|
||||
count += 1
|
||||
temp /= 10
|
||||
end
|
||||
|
||||
count
|
||||
end
|
||||
|
||||
puts 'Number of digits in 8732 is ' + count_digits(8732).to_s
|
||||
# Number of digits in 8732 is 4
|
||||
puts 'Number of digits in 112233 is ' + count_digits(112_233).to_s
|
||||
# Number of digits in 112233 is 6
|
||||
puts 'Number of digits in 0 is ' + count_digits(0).to_s
|
||||
# Number of digits in 0 is 1
|
26
maths/square_root.rb
Normal file
26
maths/square_root.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Calculates the square root of a number
|
||||
class SquareRoot
|
||||
class << self
|
||||
EPSILON = 1E-10
|
||||
|
||||
def call(number)
|
||||
raise DomainError, 'Cannot find square root of negative number' if number.negative?
|
||||
return 0 if number.zero?
|
||||
|
||||
find_root(number)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_root(x0, xn = x0)
|
||||
xn1 = xn - ((xn * xn - x0) / (2.0 * xn))
|
||||
return xn1 if (xn1 - xn).abs <= EPSILON
|
||||
|
||||
find_root(x0, xn1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class DomainError < StandardError; end
|
22
maths/square_root_test.rb
Normal file
22
maths/square_root_test.rb
Normal file
|
@ -0,0 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'minitest/autorun'
|
||||
require_relative './square_root'
|
||||
|
||||
class SquareRootTest < Minitest::Test
|
||||
def test_negative_number
|
||||
assert_raises DomainError do
|
||||
SquareRoot.call(-1)
|
||||
end
|
||||
end
|
||||
|
||||
def test_zero
|
||||
assert_equal 0, SquareRoot.call(0)
|
||||
end
|
||||
|
||||
def test_all_numbers_below_1024
|
||||
(1...1024).each do |num|
|
||||
assert_in_delta SquareRoot.call(num), Math.sqrt(num), 1E-12
|
||||
end
|
||||
end
|
||||
end
|
19
maths/sum_of_digits.rb
Normal file
19
maths/sum_of_digits.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
# Given a number, find sum of its digits.
|
||||
|
||||
def digits_sum(n)
|
||||
a = 0
|
||||
sum = 0
|
||||
until n.zero?
|
||||
a = n % 10
|
||||
sum += a
|
||||
n /= 10
|
||||
end
|
||||
sum
|
||||
end
|
||||
|
||||
puts 'Sum of digits of 3456 is ' + digits_sum(3456).to_s
|
||||
# Sum of digits of 3456 is 18
|
||||
puts 'Sum of digits of 1234 is ' + digits_sum(1234).to_s
|
||||
# Sum of digits of 1234 is 10
|
||||
puts 'Sum of digits of 9251321 is ' + digits_sum(9_251_321).to_s
|
||||
# Sum of digits of 9251321 is 23
|
|
@ -1,12 +1,12 @@
|
|||
# Fisher and Yates Shuffle is one of the simplest and most popular shuffling algorithm
|
||||
def fisher_yates_shuffle(array)
|
||||
n = array.length
|
||||
while n > 0
|
||||
i = rand(n-=1)
|
||||
array[i], array[n] = array[n], array[i]
|
||||
end
|
||||
return array
|
||||
n = array.length
|
||||
while n > 0
|
||||
i = rand(n -= 1)
|
||||
array[i], array[n] = array[n], array[i]
|
||||
end
|
||||
array
|
||||
end
|
||||
|
||||
arr = [1, 2, 40, 30, 20, 15, 323, 12, 3, 4]
|
||||
puts fisher_yates_shuffle(arr)
|
||||
puts fisher_yates_shuffle(arr)
|
||||
|
|
20
project_euler/README.md
Normal file
20
project_euler/README.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Project Euler
|
||||
|
||||
Problems are taken from https://projecteuler.net/, the Project Euler. [Problems are licensed under CC BY-NC-SA 4.0](https://projecteuler.net/copyright).
|
||||
|
||||
Project Euler is a series of challenging mathematical/computer programming problems that require more than just mathematical
|
||||
insights to solve. Project Euler is ideal for mathematicians who are learning to code.
|
||||
|
||||
## Solution Guidelines
|
||||
|
||||
Welcome to [TheAlgorithms/Ruby](https://github.com/TheAlgorithms/Ruby)! Before reading the solution guidelines, make sure you read the whole [Contributing Guidelines](https://github.com/TheAlgorithms/Ruby/blob/master/CONTRIBUTING.md) as it won't be repeated in here. If you have any doubt on the guidelines, please feel free to [state it clearly in an issue](https://github.com/TheAlgorithms/Ruby/issues/new) or ask the community in [Gitter](https://gitter.im/TheAlgorithms). Be sure to read the [Coding Style](https://github.com/TheAlgorithms/Ruby/blob/master/project_euler/README.md#coding-style) before starting solution.
|
||||
|
||||
### Coding Style
|
||||
|
||||
* Please maintain consistency in project directory and solution file names. Keep the following points in mind:
|
||||
* Create a new directory only for the problems which do not exist yet.
|
||||
* Please name the project **directory** as `problem_<problem_number>` where `problem_number` should be filled with 0s so as to occupy 3 digits. Example: `problem_001`, `problem_002`, `problem_067`, `problem_145`, and so on.
|
||||
|
||||
* You can have as many helper functions as you want but there should be one main function called `solution` which should satisfy the conditions as stated below:
|
||||
* It should contain positional argument(s) whose default value is the question input. Example: Please take a look at [Problem 1](https://projecteuler.net/problem=1) where the question is to *Find the sum of all the multiples of 3 or 5 below 1000.* In this case the main solution function will be `solution(limit = 1000)`.
|
||||
* When the `solution` function is called without any arguments like so: `solution()`, it should return the answer to the problem.
|
|
@ -8,7 +8,7 @@ even_fib_sum = 0
|
|||
fib_first = 1
|
||||
fib_second = 2
|
||||
|
||||
while fib_second < 4000000
|
||||
while fib_second < 4_000_000
|
||||
even_fib_sum += fib_second if fib_second.even?
|
||||
fib_second += fib_first
|
||||
fib_first = fib_second - fib_first
|
18
project_euler/problem_20/sol1.rb
Normal file
18
project_euler/problem_20/sol1.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# n! means n x (n - 1) x ... x 3 x 2 x 1
|
||||
|
||||
# For example, 10! = 10 x 9 x ... x 3 x 2 x 1 = 3628800,
|
||||
# and the sum of the digits in the number 10! is 3 + 6 + 2 + 8 + 8 + 0 + 0 = 27.
|
||||
#
|
||||
# Find the sum of the digits in the number 100!
|
||||
|
||||
# method to calculate factorial of a number
|
||||
def factorial(number)
|
||||
number.downto(1).reduce(:*)
|
||||
end
|
||||
|
||||
# fetch digits of factorial of `number` and find
|
||||
# sum of all those digits, and prints the result on the console
|
||||
number = 100
|
||||
puts factorial(number).digits.sum
|
57
project_euler/problem_21/sol1.rb
Normal file
57
project_euler/problem_21/sol1.rb
Normal file
|
@ -0,0 +1,57 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Let d(n) be defined as the sum of proper divisors of n
|
||||
# (numbers less than n which divide evenly into n).
|
||||
# If d(a) = b and d(b) = a, where a & b, then a and b are an amicable pair.
|
||||
# and each of a and b are called amicable numbers.
|
||||
#
|
||||
# For example,
|
||||
#
|
||||
# The proper divisors of 220 are 1, 2, 4, 5, 10, 11, 20, 22, 44, 55 and 110;
|
||||
# therefore d(220) = 284.
|
||||
#
|
||||
# The proper divisors of 284 are 1, 2, 4, 71 and 142; so d(284) = 220.
|
||||
#
|
||||
# Evaluate the sum of all the amicable numbers under 10000.
|
||||
|
||||
# get list of all divisors of `number`
|
||||
def get_divisors(number)
|
||||
divisors = []
|
||||
(1..(Math.sqrt(number).to_i)).each do |num|
|
||||
if (number % num).zero?
|
||||
divisors << num
|
||||
divisors << number / num
|
||||
end
|
||||
end
|
||||
divisors
|
||||
end
|
||||
|
||||
# get list of all proper divisors of `number` i.e. removing `number` from
|
||||
# the list of divisors
|
||||
def get_proper_divisors(number)
|
||||
divisors = get_divisors(number)
|
||||
divisors.delete(number)
|
||||
divisors
|
||||
end
|
||||
|
||||
# implementation of a method `d` as mentioned in the question
|
||||
# i.e. finding sum of all proper divisors of `number`
|
||||
def d(number)
|
||||
get_proper_divisors(number).sum
|
||||
end
|
||||
|
||||
# given an upper `limit`, this method finds all amicable numbers
|
||||
# under this `limit`
|
||||
def find_amicable_numbers(limit)
|
||||
result = []
|
||||
(1...limit).each do |a|
|
||||
b = d(a)
|
||||
res = d(b)
|
||||
result.push(a) if (a == res) && (a != b)
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
# calling `find_amicable_numbers` method and finding sum of all such numbers
|
||||
# below 10000, and printing the result on the console
|
||||
puts find_amicable_numbers(10_000).sum
|
1
project_euler/problem_22/p022_names.txt
Normal file
1
project_euler/problem_22/p022_names.txt
Normal file
File diff suppressed because one or more lines are too long
40
project_euler/problem_22/sol1.rb
Normal file
40
project_euler/problem_22/sol1.rb
Normal file
|
@ -0,0 +1,40 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Problem 22
|
||||
# Using names.txt (right click and 'Save Link/Target As...'),
|
||||
# a 46K text file containing over five-thousand first names,
|
||||
# begin by sorting it into alphabetical order.
|
||||
# Then working out the alphabetical value for each name,
|
||||
# multiply this value by its alphabetical position in the list to obtain a name score.
|
||||
|
||||
# For example, when the list is sorted into alphabetical order,
|
||||
# COLIN, which is worth 3 + 15 + 12 + 9 + 14 = 53,
|
||||
# is the 938th name in the list. So, COLIN would obtain a score of 938 * 53 = 49714.
|
||||
|
||||
# What is the total of all the name scores in the file?
|
||||
|
||||
# reading the contents of the file
|
||||
file_contents = File.read('p022_names.txt')
|
||||
|
||||
# replacing the occuerance of \" to '' and spliting the result by ','
|
||||
# to get an array of sorted words
|
||||
words = file_contents.tr('\"', '').split(',').sort
|
||||
|
||||
# this method calculates the worth of a word based on the ASCII
|
||||
# values of the characters
|
||||
def word_worth(word)
|
||||
word.chars.sum { |char| char.ord - 'A'.ord + 1 }
|
||||
end
|
||||
|
||||
# this method takes the words as an input
|
||||
# calls `word_worth` method on each word
|
||||
# to that value multiply that with the index of the word in the array
|
||||
# add the same to the result
|
||||
def total_rank(words)
|
||||
result = 0
|
||||
words.each_with_index { |word, index| result += word_worth(word) * (index + 1) }
|
||||
result
|
||||
end
|
||||
|
||||
# outputs total rank on the console
|
||||
puts total_rank(words)
|
29
project_euler/problem_3/sol1.rb
Normal file
29
project_euler/problem_3/sol1.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# The prime factors of 13195 are 5, 7, 13 and 29.
|
||||
# What is the largest prime factor of the number 600851475143
|
||||
|
||||
# find all factors of the given number
|
||||
def get_factors(number)
|
||||
factors = []
|
||||
(1..Math.sqrt(number).to_i).each do |num|
|
||||
if (number % num).zero?
|
||||
factors << num
|
||||
factors << number / num
|
||||
end
|
||||
end
|
||||
factors
|
||||
end
|
||||
|
||||
# determine if a given number is a prime number
|
||||
def prime?(number)
|
||||
get_factors(number).length == 2
|
||||
end
|
||||
|
||||
# find the largest prime
|
||||
def largest_prime_factor(number)
|
||||
prime_factors = get_factors(number).select { |factor| prime?(factor) }
|
||||
prime_factors.max
|
||||
end
|
||||
|
||||
puts largest_prime_factor(600_851_475_143)
|
18
project_euler/problem_3/sol2.rb
Normal file
18
project_euler/problem_3/sol2.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
# The prime factors of 13195 are 5, 7, 13 and 29.
|
||||
# What is the largest prime factor of the number 600851475143 ?
|
||||
|
||||
def solution(n)
|
||||
prime = 1
|
||||
i = 2
|
||||
while i * i <= n
|
||||
while (n % i).zero?
|
||||
prime = i
|
||||
n = n.fdiv i
|
||||
end
|
||||
i += 1
|
||||
end
|
||||
prime = n if n > 1
|
||||
prime.to_i
|
||||
end
|
||||
|
||||
puts solution(600_851_475_143)
|
11
project_euler/problem_4/sol1.rb
Normal file
11
project_euler/problem_4/sol1.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
# A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.
|
||||
# Find the largest palindrome made from the product of two 3-digit numbers.
|
||||
|
||||
answer = 0
|
||||
999.downto(99) do |i|
|
||||
999.downto(99) do |j|
|
||||
t = (i * j)
|
||||
answer = i * j if (t.to_s == t.to_s.reverse) && (t > answer) && (t > answer)
|
||||
end
|
||||
end
|
||||
puts answer
|
26
project_euler/problem_4/sol2.rb
Normal file
26
project_euler/problem_4/sol2.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.
|
||||
# Find the largest palindrome made from the product of two 3-digit numbers.
|
||||
|
||||
class Integer
|
||||
def parindrome?
|
||||
self == reverse
|
||||
end
|
||||
|
||||
# 123.reverse == 321
|
||||
# 100.reverse == 1
|
||||
def reverse
|
||||
result = 0
|
||||
n = self
|
||||
loop do
|
||||
result = result * 10 + n % 10
|
||||
break if (n /= 10).zero?
|
||||
end
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
factors = (100..999).to_a
|
||||
products = factors.product(factors).map { _1 * _2 }
|
||||
puts products.select(&:parindrome?).max
|
|
@ -3,7 +3,6 @@
|
|||
# What is the smallest positive number that is evenly
|
||||
# divisible by all of the numbers from 1 to 20?
|
||||
|
||||
|
||||
# Euclid's algorithm for the greatest common divisor
|
||||
def gcd(a, b)
|
||||
b.zero? ? a : gcd(b, a % b)
|
||||
|
@ -20,4 +19,4 @@ result = 1
|
|||
result = lcm(result, i + 1)
|
||||
end
|
||||
|
||||
p result
|
||||
p result
|
|
@ -1,15 +1,17 @@
|
|||
=begin
|
||||
Searches through a list for a value in O(log(n)) time.
|
||||
The list must be sorted.
|
||||
=end
|
||||
# Searches through a list for a value in O(log(n)) time.
|
||||
# The list must be sorted.
|
||||
def binary_search(array, key)
|
||||
front = 0
|
||||
back = array.length - 1
|
||||
while front <= back
|
||||
middle = (front + back) / 2
|
||||
return middle if array[middle] == key
|
||||
key < array[middle] ?
|
||||
back = middle - 1 : front = middle + 1
|
||||
|
||||
if key < array[middle]
|
||||
back = middle - 1
|
||||
else
|
||||
front = middle + 1
|
||||
end
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
@ -18,6 +20,8 @@ puts "Enter a sorted space-separated list:"
|
|||
arr = gets.chomp.split(' ').map(&:to_i)
|
||||
puts "Enter the value to be searched:"
|
||||
value = gets.chomp.to_i
|
||||
puts binary_search(arr, value) != nil ?
|
||||
"Found at index #{binary_search(arr, value)}" :
|
||||
puts if binary_search(arr, value) != nil
|
||||
"Found at index #{binary_search(arr, value)}"
|
||||
else
|
||||
"Not found"
|
||||
end
|
53
searches/depth_first_search.rb
Normal file
53
searches/depth_first_search.rb
Normal file
|
@ -0,0 +1,53 @@
|
|||
# @param [Integer] start
|
||||
# @param [Integer] target
|
||||
# @param [Array] adjacency_list
|
||||
# @return [Array] routes
|
||||
def dfs(start, target, adjacency_list)
|
||||
is_visited = Hash.new(false)
|
||||
parent = {}
|
||||
stack = [start]
|
||||
loop do
|
||||
break if stack.empty?
|
||||
|
||||
current_node = stack.pop
|
||||
is_visited[current_node] = true
|
||||
|
||||
return get_path(parent, target) if current_node == target
|
||||
|
||||
adjacency_list[current_node].each do |neighbor|
|
||||
next if is_visited[neighbor]
|
||||
|
||||
stack << neighbor
|
||||
is_visited[neighbor] = true
|
||||
parent[neighbor] = current_node
|
||||
end
|
||||
end
|
||||
[]
|
||||
end
|
||||
|
||||
# @param [Hash] parent
|
||||
# @param [Integer] dest
|
||||
# @return [Array] path
|
||||
def get_path(parent, dest)
|
||||
iterator = dest
|
||||
path = [dest]
|
||||
while parent.has_key?(iterator)
|
||||
path << parent[iterator]
|
||||
iterator = parent[iterator]
|
||||
end
|
||||
path.reverse
|
||||
end
|
||||
|
||||
def main
|
||||
adjacency_list = [
|
||||
[1, 2], # 0
|
||||
[0, 3], # 1
|
||||
[0, 3], # 2
|
||||
[1, 2, 4], # 3
|
||||
[3, 5], # 4
|
||||
[4] # 5
|
||||
]
|
||||
p dfs(0, 5, adjacency_list)
|
||||
end
|
||||
|
||||
main
|
29
searches/double_linear_search.rb
Normal file
29
searches/double_linear_search.rb
Normal file
|
@ -0,0 +1,29 @@
|
|||
# Iterate through the array from both sides to find the index of search_item.
|
||||
|
||||
def double_linear_search(array, search_item)
|
||||
start_ind = 0
|
||||
end_ind = array.length - 1
|
||||
|
||||
while start_ind <= end_ind
|
||||
return start_ind if array[start_ind] == search_item
|
||||
return end_ind if array[end_ind] == search_item
|
||||
|
||||
start_ind += 1
|
||||
end_ind -= 1
|
||||
end
|
||||
|
||||
# returns -1 if search_item is not found in array
|
||||
-1
|
||||
end
|
||||
|
||||
puts(double_linear_search([1, 5, 5, 10], 1))
|
||||
# => 0
|
||||
|
||||
puts(double_linear_search([1, 5, 5, 10], 5))
|
||||
# => 1
|
||||
|
||||
puts(double_linear_search([1, 5, 5, 10], 100))
|
||||
# => -1
|
||||
|
||||
puts(double_linear_search([1, 5, 5, 10], 10))
|
||||
# => 3
|
|
@ -1,18 +1,18 @@
|
|||
=begin
|
||||
Looks through array for a value in O(n) time.
|
||||
Array does not need to be sorted.
|
||||
=end
|
||||
# Looks through array for a value in O(n) time.
|
||||
# Array does not need to be sorted.
|
||||
def linear_search(array, key)
|
||||
array.each_with_index do |current, index|
|
||||
return index if current == key
|
||||
end
|
||||
return nil
|
||||
nil
|
||||
end
|
||||
|
||||
puts "Enter a space-separated list:"
|
||||
arr = gets.chomp.split(' ').map(&:to_i)
|
||||
puts "Enter a value to be searched:"
|
||||
key = gets.chomp.to_i
|
||||
puts linear_search(arr, key) != nil ?
|
||||
"Found at index #{linear_search(arr, key)}" :
|
||||
puts if linear_search(arr, key) != nil
|
||||
"Found at index #{linear_search(arr, key)}"
|
||||
else
|
||||
"Not found"
|
||||
end
|
27
searches/recursive_double_linear_search.rb
Normal file
27
searches/recursive_double_linear_search.rb
Normal file
|
@ -0,0 +1,27 @@
|
|||
# Iterate through the array to find the index of key using recursion.
|
||||
|
||||
def recursive_double_linear_search(data, key, left = 0, right = 0)
|
||||
right &&= data.length - 1
|
||||
|
||||
return -1 if left > right
|
||||
|
||||
return left if data[left] == key
|
||||
return right if data[right] == key
|
||||
|
||||
recursive_double_linear_search(data, key, left + 1, right - 1)
|
||||
end
|
||||
|
||||
puts(recursive_double_linear_search([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], 5))
|
||||
# => 5
|
||||
|
||||
puts(recursive_double_linear_search([1, 2, 4, 5, 3], 4))
|
||||
# => 2
|
||||
|
||||
puts(recursive_double_linear_search([1, 2, 4, 5, 3], 6))
|
||||
# => -1
|
||||
|
||||
puts(recursive_double_linear_search([5], 5))
|
||||
# => 0
|
||||
|
||||
puts(recursive_double_linear_search([], 1))
|
||||
# => -1
|
25
searches/recursive_linear_search.rb
Normal file
25
searches/recursive_linear_search.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
# A pure Ruby implementation of a recursive linear search algorithm
|
||||
|
||||
def rec_linear_search(sequence, low, high, target)
|
||||
raise Exception('Invalid upper or lower bound!') unless high < sequence.length && low < sequence.length
|
||||
|
||||
return -1 if high < low
|
||||
|
||||
return low if sequence[low] == target
|
||||
|
||||
return high if sequence[high] == target
|
||||
|
||||
rec_linear_search(sequence, low + 1, high - 1, target)
|
||||
end
|
||||
|
||||
puts(rec_linear_search([0, 30, 500, 100, 700], 0, 4, 0))
|
||||
# => 0
|
||||
|
||||
puts(rec_linear_search([0, 30, 500, 100, 700], 0, 4, 700))
|
||||
# => 4
|
||||
|
||||
puts(rec_linear_search([0, 30, 500, 100, 700], 0, 4, 30))
|
||||
# => 1
|
||||
|
||||
puts(rec_linear_search([0, 30, 500, 100, 700], 0, 4, -6))
|
||||
# => -1
|
43
searches/ternary_search.rb
Normal file
43
searches/ternary_search.rb
Normal file
|
@ -0,0 +1,43 @@
|
|||
# Ternary Search
|
||||
# -------------------------------
|
||||
# Ternary search is a searching technique that is used to search the position of a specific value in an array.
|
||||
# Ternary search is a divide-and-conquer algorithm.
|
||||
# It is mandatory for the array to be sorted (in which you will search for an element).
|
||||
# The array is divided into three parts and then we determine in which part the element exists.
|
||||
# In this search, after each iteration it neglects 1/3 part of the array and repeats the same operations on the remaining ⅔.
|
||||
# Time Complexity: O(log3 n)
|
||||
# Space Complexity: O(1)
|
||||
|
||||
def ternary_search(l, r, key, arr)
|
||||
# l is the starting index and r is the ending index of the array/sub-array.
|
||||
if r >= l
|
||||
# find mid1 and mid2
|
||||
mid1 = l + (r - l) / 3
|
||||
mid2 = r - (r - l) / 3
|
||||
# check if key is equal to mid1
|
||||
if arr[mid1] == key
|
||||
mid1
|
||||
# check if key is equal to mid2
|
||||
elsif arr[mid2] == key
|
||||
mid2
|
||||
# Since key is not present at mid, check in which region it is present
|
||||
# then repeat the Search operation in that region
|
||||
elsif key < arr[mid1]
|
||||
ternary_search(l, mid1 - 1, key, arr)
|
||||
elsif key > arr[mid2]
|
||||
ternary_search(mid2 + 1, r, key, arr)
|
||||
else
|
||||
ternary_search(mid1 + 1, mid2 - 1, key, arr)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
puts "Enter a space-separated list:"
|
||||
arr = gets.chomp.split(' ').map(&:to_i)
|
||||
puts "Enter a value to be searched:"
|
||||
key = gets.chomp.to_i
|
||||
puts if ternary_search(0, arr.length - 1, key, arr) != nil
|
||||
"Found at index #{ternary_search(0, arr.length - 1, key, arr)}"
|
||||
else
|
||||
"Not found"
|
||||
end
|
21
sorting/bogo_sort.rb
Normal file
21
sorting/bogo_sort.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
class Array
|
||||
def sorted?
|
||||
### goes thru array and checks if all elements are in order
|
||||
(1...length).each do |i|
|
||||
return false if self[i - 1] > self[i]
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def bogosort
|
||||
### randomly shuffles until sorted
|
||||
shuffle! until sorted?
|
||||
self # return sorted array
|
||||
end
|
||||
end
|
||||
|
||||
if $0 == __FILE__
|
||||
puts 'Enter a list of numbers separated by space'
|
||||
str = gets.chomp.split('')
|
||||
puts str.bogosort.join('')
|
||||
end
|
16
sorting/bogo_sort_test.rb
Normal file
16
sorting/bogo_sort_test.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
require 'minitest/autorun'
|
||||
require_relative './bogo_sort'
|
||||
|
||||
class TestBogoSort < Minitest::Test
|
||||
def test_sorted_array
|
||||
input = [1, 2, 3, 4, 5]
|
||||
expected = input.dup
|
||||
assert_equal expected, input.bogosort
|
||||
end
|
||||
|
||||
def test_reversed_array
|
||||
input = [5, 4, 3, 2, 1]
|
||||
expected = [1, 2, 3, 4, 5]
|
||||
assert_equal expected, input.bogosort
|
||||
end
|
||||
end
|
22
sorting/bubble_sort.rb
Normal file
22
sorting/bubble_sort.rb
Normal file
|
@ -0,0 +1,22 @@
|
|||
def bubble_sort(array)
|
||||
n = array.length
|
||||
loop do
|
||||
swapped = false
|
||||
|
||||
(n - 1).times do |i|
|
||||
if array[i] > array[i + 1]
|
||||
array[i], array[i + 1] = array[i + 1], array[i]
|
||||
swapped = true
|
||||
end
|
||||
end
|
||||
|
||||
break unless swapped
|
||||
end
|
||||
|
||||
array
|
||||
end
|
||||
puts 'Enter a list of numbers separated by space'
|
||||
|
||||
list = gets
|
||||
bubble_sort(list)
|
||||
print list
|
|
@ -1,30 +1,29 @@
|
|||
|
||||
DEFAULT_BUCKET_SIZE = 5
|
||||
|
||||
def bucket_sort(input, bucket_size = DEFAULT_BUCKET_SIZE)
|
||||
print 'Array is empty' if input.empty?
|
||||
|
||||
array = input.split(' ').map(&:to_i)
|
||||
|
||||
bucket_count = ((array.max - array.min) / bucket_size).floor + 1
|
||||
|
||||
# create buckets
|
||||
buckets = []
|
||||
bucket_count.times { buckets.push [] }
|
||||
|
||||
# fill buckets
|
||||
array.each do |item|
|
||||
buckets[((item - array.min) / bucket_size).floor].push(item)
|
||||
end
|
||||
|
||||
# sort buckets
|
||||
buckets.each do |bucket|
|
||||
bucket.sort!
|
||||
end
|
||||
|
||||
buckets.flatten.join(' ')
|
||||
end
|
||||
puts "Enter a list of numbers seprated by space"
|
||||
|
||||
list = gets
|
||||
print bucket_sort(list)
|
||||
DEFAULT_BUCKET_SIZE = 5
|
||||
|
||||
def bucket_sort(input, bucket_size = DEFAULT_BUCKET_SIZE)
|
||||
print 'Array is empty' if input.empty?
|
||||
|
||||
array = input.split(' ').map(&:to_i)
|
||||
|
||||
bucket_count = ((array.max - array.min) / bucket_size).floor + 1
|
||||
|
||||
# create buckets
|
||||
buckets = []
|
||||
bucket_count.times { buckets.push [] }
|
||||
|
||||
# fill buckets
|
||||
array.each do |item|
|
||||
buckets[((item - array.min) / bucket_size).floor].push(item)
|
||||
end
|
||||
|
||||
# sort buckets
|
||||
buckets.each do |bucket|
|
||||
bucket.sort!
|
||||
end
|
||||
|
||||
buckets.flatten.join(' ')
|
||||
end
|
||||
puts 'Enter a list of numbers separated by space'
|
||||
|
||||
list = gets
|
||||
print bucket_sort(list)
|
32
sorting/heap_sort.rb
Normal file
32
sorting/heap_sort.rb
Normal file
|
@ -0,0 +1,32 @@
|
|||
# Algorithm: Heap-Sort
|
||||
# Time-Complexity: O(nlogn)
|
||||
def heap_sort(array)
|
||||
array_size = array.size
|
||||
adjusted_array = [nil] + array
|
||||
(array_size / 2).downto(1) do |i|
|
||||
adjusted_down(adjusted_array, i, array_size)
|
||||
end
|
||||
while array_size > 1
|
||||
adjusted_array[1], adjusted_array[array_size] = adjusted_array[array_size], adjusted_array[1]
|
||||
array_size -= 1
|
||||
adjusted_down(adjusted_array, 1, array_size)
|
||||
end
|
||||
adjusted_array.drop(1)
|
||||
end
|
||||
|
||||
# Method to adjust heap in downward manner
|
||||
def adjusted_down(adjusted_array, parent, limit)
|
||||
top = adjusted_array[parent]
|
||||
while (child = 2 * parent) <= limit
|
||||
child += 1 if (child < limit) && (adjusted_array[child] < adjusted_array[child + 1])
|
||||
break if top >= adjusted_array[child]
|
||||
|
||||
adjusted_array[parent] = adjusted_array[child]
|
||||
parent = child
|
||||
end
|
||||
adjusted_array[parent] = top
|
||||
end
|
||||
|
||||
# Code for testing heapsort
|
||||
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15].shuffle
|
||||
print heap_sort(array)
|
|
@ -1,17 +1,17 @@
|
|||
def insertion_sort(array)
|
||||
0.upto(array.length - 1).each do |index|
|
||||
element = array[index]
|
||||
position = index
|
||||
while element < array[position - 1] && position > 0
|
||||
array[position] = array[position - 1]
|
||||
array[position - 1] = element
|
||||
position -= 1
|
||||
end
|
||||
end
|
||||
array
|
||||
end
|
||||
puts "Enter a list of numbers seprated by space"
|
||||
|
||||
list = gets
|
||||
insertion_sort(list)
|
||||
print list
|
||||
def insertion_sort(array)
|
||||
0.upto(array.length - 1).each do |index|
|
||||
element = array[index]
|
||||
position = index
|
||||
while element < array[position - 1] && position > 0
|
||||
array[position] = array[position - 1]
|
||||
array[position - 1] = element
|
||||
position -= 1
|
||||
end
|
||||
end
|
||||
array
|
||||
end
|
||||
puts 'Enter a list of numbers separated by space'
|
||||
|
||||
list = gets
|
||||
insertion_sort(list)
|
||||
print list
|
33
sorting/merge_sort.rb
Normal file
33
sorting/merge_sort.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
def merge_sort(array)
|
||||
return array if array.length <= 1
|
||||
|
||||
mid = array.length / 2
|
||||
first_array = array.slice(0..mid - 1)
|
||||
second_array = array.slice(mid..-1)
|
||||
|
||||
first_array = merge_sort first_array
|
||||
second_array = merge_sort second_array
|
||||
|
||||
# merge
|
||||
result = []
|
||||
until first_array.empty? && second_array.empty?
|
||||
if first_array.empty?
|
||||
result.concat(second_array)
|
||||
second_array.clear
|
||||
elsif second_array.empty?
|
||||
result.concat(first_array)
|
||||
first_array.clear
|
||||
else
|
||||
result << if first_array.first < second_array.first
|
||||
first_array.shift
|
||||
else
|
||||
second_array.shift
|
||||
end
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
puts 'Enter a list of numbers separated by space'
|
||||
list = gets
|
||||
print merge_sort list.split(' ').map(&:to_i)
|
|
@ -1,15 +1,15 @@
|
|||
def quicksort
|
||||
return [] if empty?
|
||||
def quicksort(arr)
|
||||
return [] if arr.empty?
|
||||
|
||||
# chose a random pivot value
|
||||
pivot = delete_at(rand(size))
|
||||
pivot = arr.delete_at(rand(arr.size))
|
||||
# partition array into 2 arrays and comparing them to each other and eventually returning
|
||||
# array with the pivot value sorted
|
||||
left, right = partition(&pivot.method(:>))
|
||||
left, right = arr.partition(&pivot.method(:>))
|
||||
|
||||
# recursively calling the quicksort method on itself
|
||||
return *left.quicksort, pivot, *right.quicksort
|
||||
[*quicksort(left), pivot, *quicksort(right)]
|
||||
end
|
||||
|
||||
arr = [34, 2, 1, 5, 3]
|
||||
p arr.quicksort
|
||||
p quicksort(arr)
|
|
@ -13,6 +13,6 @@ def selection_sort(array)
|
|||
end
|
||||
end
|
||||
|
||||
arr = ([9,8,3,1,2,55,68,48].shuffle) #We have taken a rondom example and also shuffling it
|
||||
arr = [9, 8, 3, 1, 2, 55, 68, 48].shuffle # We have taken a rondom example and also shuffling it
|
||||
selection_sort(arr)
|
||||
puts "Sorted array is: #{arr.inspect}"
|
24
sorting/shell_sort.rb
Normal file
24
sorting/shell_sort.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
def shell_sort(a)
|
||||
n = a.length
|
||||
h = 1
|
||||
|
||||
h = (3 * h) + 1 while h < n / 3
|
||||
|
||||
while h >= 1
|
||||
# Logic of insertion sort with inrement steps of "h"
|
||||
(h...n).each do |i|
|
||||
j = i
|
||||
while j >= h
|
||||
if a[j - h] > a[j]
|
||||
temp = a[j]
|
||||
a[j] = a[j - h]
|
||||
a[j - h] = temp
|
||||
end
|
||||
j -= h
|
||||
end
|
||||
end
|
||||
h /= 3
|
||||
end
|
||||
|
||||
a
|
||||
end
|
Loading…
Reference in a new issue