diff --git a/src/algorithms/search/fibonacci-search/README.md b/src/algorithms/search/fibonacci-search/README.md new file mode 100644 index 00000000..54c43f78 --- /dev/null +++ b/src/algorithms/search/fibonacci-search/README.md @@ -0,0 +1,27 @@ +# Fibonacci Search Algorithm +Let k be defined as an element in F, the array of Fibonacci numbers. n = Fm is the array size. If n is not a Fibonacci number, let Fm be the smallest number in F that is greater than n. + +The array of Fibonacci numbers is defined where Fk+2 = Fk+1 + Fk, when k ≥ 0, F1 = 1, and F0 = 0. + +To test whether an item is in the list of ordered numbers, follow these steps: +```sh +Set k = m. +If k = 0, stop. There is no match; the item is not in the array. +Compare the item against element in Fk−1. +If the item matches, stop. +If the item is less than entry Fk−1, discard the elements from positions Fk−1 + 1 to n. Set k = k − 1 and return to step 2. +If the item is greater than entry Fk−1, discard the elements from positions 1 to Fk−1. Renumber the remaining elements from 1 to Fk−2, set k = k − 2, and return to step 2. +Alternative implementation (from "Sorting and Searching" by Knuth[4]): + +Given a table of records R1, R2, ..., RN whose keys are in increasing order K1 < K2 < ... < KN, the algorithm searches for a given argument K. Assume N+1 = Fk+1 + +Step 1. [Initialize] i ← Fk, p ← Fk-1, q ← Fk-2 (throughout the algorithm, p and q will be consecutive Fibonacci numbers) + +Step 2. [Compare] If K < Ki, go to Step 3; if K > Ki go to Step 4; and if K = Ki, the algorithm terminates successfully. + +Step 3. [Decrease i] If q=0, the algorithm terminates unsuccessfully. Otherwise set (i, p, q) ← (p, q, p - q) (which moves p and q one position back in the Fibonacci sequence); then return to Step 2 + +Step 4. [Increase i] If p=1, the algorithm terminates unsuccessfully. Otherwise set (i,p,q) ← (i + q, p - q, 2q - p) (which moves p and q two positions back in the Fibonacci sequence); and return to Step 2 +``` +The two variants of the algorithm presented above always divide the current interval into a larger and a smaller subinterval. The original algorithm,[1] however, would divide the new interval into a smaller and a larger subinterval in Step 4. This has the advantage that the new i is closer to the old i and is more suitable for accelerating searching on magnetic tape. + diff --git a/src/algorithms/search/fibonacci-search/__test__/fibonacciSearch.test.js b/src/algorithms/search/fibonacci-search/__test__/fibonacciSearch.test.js new file mode 100644 index 00000000..3ed81108 --- /dev/null +++ b/src/algorithms/search/fibonacci-search/__test__/fibonacciSearch.test.js @@ -0,0 +1,15 @@ +import fibonacciSearch from '../fibonacciSearch'; + +describe('fibonacciSearch', () => { + it('should search number in sorted array', () => { + expect(fibonacciSearch([], 1)).toBe(-1); + expect(fibonacciSearch([1], 1)).toBe(0); + expect(fibonacciSearch([1, 2], 1)).toBe(0); + expect(fibonacciSearch([1, 2], 2)).toBe(1); + expect(fibonacciSearch([1, 5, 10, 12], 1)).toBe(0); + expect(fibonacciSearch([1, 5, 10, 12, 14, 17, 22, 100], 17)).toBe(5); + expect(fibonacciSearch([1, 5, 10, 12, 14, 17, 22, 100], 1)).toBe(0); + expect(fibonacciSearch([1, 5, 10, 12, 14, 17, 22, 100], 100)).toBe(7); + expect(fibonacciSearch([1, 5, 10, 12, 14, 17, 22, 100], 0)).toBe(-1); + }); +}); diff --git a/src/algorithms/search/fibonacci-search/fibonacciSearch.js b/src/algorithms/search/fibonacci-search/fibonacciSearch.js new file mode 100644 index 00000000..9f2ee6f7 --- /dev/null +++ b/src/algorithms/search/fibonacci-search/fibonacciSearch.js @@ -0,0 +1,51 @@ +/** Author Slim Gharbi + * Fibonacci search implementation. + * + * @param {*[]} integers + * @param {*} elementToSearch + * @return {number} + */ +export default function fibonacciSearch(integers, elementToSearch) { + let i; + + /* Initialize fibonacci numbers */ + let fibonacciMinus2 = 0;// (m-2)'th Fibonacci No. + let fibonacciMinus1 = 1;// (m-1)'th Fibonacci No. + let fibonacciNumber = fibonacciMinus2 + fibonacciMinus1; // m'th Fibonacci + /* fibonacciNumber is going to store the smallest + Fibonacci Number greater than or equal to the length of the array */ + while (fibonacciNumber < integers.length) { + fibonacciMinus2 = fibonacciMinus1; + fibonacciMinus1 = fibonacciNumber; + fibonacciNumber = fibonacciMinus2 + fibonacciMinus1; + } + // Marks the eliminated range from front + let offset = -1; + /* while there are elements to be inspected. + Note that we compare integers[fibonacciMinus2] with elementToSearch. + When fibonacciNumber becomes 1, fibonacciMinus2 becomes 0 */ + while (fibonacciNumber > 1) { + // Check if fibonacciMinus2 is a valid location + i = Math.min((offset + fibonacciMinus2), (integers.length - 1)); + /* If elementToSearch is greater than the value at + index fibonacciMinus2, cut the subarray array + from offset to i */ + if (integers[i] < elementToSearch) { + fibonacciNumber = fibonacciMinus1; + fibonacciMinus1 = fibonacciMinus2; + fibonacciMinus2 = fibonacciNumber - fibonacciMinus1; + offset = i; + } else if (integers[i] > elementToSearch) { + fibonacciNumber = fibonacciMinus2; + fibonacciMinus1 -= fibonacciMinus2; + fibonacciMinus2 = fibonacciNumber - fibonacciMinus1; + /* If elementToSearch is greater than the value at index + fibonacciMinus2, cut the subarray after i+1 */ + } else return i; + // element found. return index + } + // comparing the last element with elementToSearch + if (fibonacciMinus1 === 1 && integers[offset + 1] === elementToSearch) return offset + 1; + // element not found. return -1 + return -1; +}