2020-07-07 21:27:45 +08:00
|
|
|
/**
|
2020-07-08 02:53:12 +08:00
|
|
|
* @author sprintyaf
|
2020-07-08 00:38:40 +08:00
|
|
|
* @file fibonacci_search.cpp
|
2020-07-07 21:27:45 +08:00
|
|
|
* @brief [Fibonacci search
|
|
|
|
* algorithm](https://en.wikipedia.org/wiki/Fibonacci_search_technique)
|
|
|
|
*/
|
|
|
|
|
2020-07-07 18:38:58 +08:00
|
|
|
#include <iostream>
|
2020-07-07 21:27:45 +08:00
|
|
|
#include <vector> // for std::vector class
|
|
|
|
#include <cassert> // for assert
|
2020-07-08 00:38:40 +08:00
|
|
|
#include <cstdlib> // for random numbers
|
|
|
|
#include <algorithm> // for sorting
|
2020-07-07 21:27:45 +08:00
|
|
|
|
2020-07-07 18:38:58 +08:00
|
|
|
|
|
|
|
|
2020-07-07 21:27:45 +08:00
|
|
|
/**
|
2020-07-08 00:38:40 +08:00
|
|
|
* @brief using fibonacci search algorithm finds an index of a given element in a sorted array
|
|
|
|
*
|
|
|
|
* @param arr sorted array
|
|
|
|
* @param value value that we're looking for
|
|
|
|
* @returns if the array contains the value, returns an index of the element. otherwise -1.
|
2020-07-07 21:27:45 +08:00
|
|
|
*/
|
2020-07-08 00:38:40 +08:00
|
|
|
int fibonacci_search(const std::vector<int> &arr, int value){
|
2020-07-10 23:13:16 +08:00
|
|
|
// initialize last and current members of Fibonacci sequence
|
|
|
|
int last = 0, current = 1;
|
|
|
|
int length = arr.size(); // array size
|
|
|
|
// next member of Fibonacci sequence which is "last" + "current"
|
|
|
|
int next = last + current;
|
2020-07-07 18:38:58 +08:00
|
|
|
|
2020-07-10 23:13:16 +08:00
|
|
|
// "next" will store the smallest Fibonacci number greater or equal to "length"
|
2020-07-07 18:38:58 +08:00
|
|
|
while(next < length){
|
|
|
|
last = current;
|
|
|
|
current = next;
|
|
|
|
next = last + current;
|
|
|
|
}
|
|
|
|
|
2020-07-10 23:13:16 +08:00
|
|
|
// "offset" is the end of eliminated range from front
|
|
|
|
int offset = -1, index;
|
|
|
|
// while loop until there are elements left to consider.
|
|
|
|
// when "next" becomes 1, last is equal to 0, so search is done,
|
|
|
|
// because arr[offset] will already be eliminated
|
2020-07-07 18:38:58 +08:00
|
|
|
while(next > 1){
|
2020-07-10 23:13:16 +08:00
|
|
|
// check if "last" is valid location
|
2020-07-08 00:38:40 +08:00
|
|
|
index = std::min(offset + last, length-1);
|
2020-07-10 23:13:16 +08:00
|
|
|
// if value is greater than the value at "index", eliminate the subarray from offset to index
|
2020-07-07 18:38:58 +08:00
|
|
|
if(arr[index] < value){
|
|
|
|
next = current;
|
|
|
|
current = last;
|
|
|
|
last = next - current;
|
|
|
|
offset = index;
|
2020-07-10 23:13:16 +08:00
|
|
|
// if value is less than the value at "index", eliminate the subarray after index+1
|
2020-07-07 18:38:58 +08:00
|
|
|
} else if(arr[index] > value){
|
|
|
|
next = last;
|
|
|
|
current = current - last;
|
|
|
|
last = next - current;
|
2020-07-10 23:13:16 +08:00
|
|
|
// element is found
|
2020-07-07 18:38:58 +08:00
|
|
|
} else {
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
}
|
2020-07-10 23:13:16 +08:00
|
|
|
// comparing the last element
|
2020-07-08 00:38:40 +08:00
|
|
|
if(current && !arr.empty() && arr[offset+1] == value){
|
2020-07-07 18:38:58 +08:00
|
|
|
return offset+1;
|
|
|
|
}
|
2020-07-10 23:13:16 +08:00
|
|
|
// value was not found, return -1
|
2020-07-07 18:38:58 +08:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2020-07-07 21:27:45 +08:00
|
|
|
/**
|
2020-07-08 00:38:40 +08:00
|
|
|
* @brief random tests for checking performance when an array doesn't contain an element
|
|
|
|
*/
|
|
|
|
bool no_occurence_tests(){
|
2020-07-07 21:27:45 +08:00
|
|
|
bool passed = true;
|
2020-07-08 00:38:40 +08:00
|
|
|
int rand_num, rand_value, index, num_tests = 1000;
|
|
|
|
std::vector<int> arr;
|
|
|
|
while(num_tests--){
|
|
|
|
arr.clear();
|
|
|
|
for(int i = 0; i < 100; i++){
|
2020-07-08 00:45:03 +08:00
|
|
|
rand_num = std::rand() % 1000;
|
2020-07-08 00:38:40 +08:00
|
|
|
arr.push_back(rand_num);
|
|
|
|
}
|
2020-07-08 00:45:03 +08:00
|
|
|
rand_value = std::rand() % 1000;
|
2020-07-08 00:38:40 +08:00
|
|
|
while(std::find(arr.begin(), arr.end(), rand_value) != arr.end()){
|
|
|
|
std::remove(arr.begin(), arr.end(), rand_value);
|
|
|
|
}
|
|
|
|
sort(arr.begin(), arr.end());
|
|
|
|
index = fibonacci_search(arr, rand_value);
|
|
|
|
passed = passed && (index == -1);
|
|
|
|
}
|
2020-07-07 21:27:45 +08:00
|
|
|
return passed;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2020-07-08 00:38:40 +08:00
|
|
|
* @brief random tests which cover cases when we have one, multiple or zero occurences of the value we're looking for
|
|
|
|
*/
|
|
|
|
bool random_tests(){
|
2020-07-07 21:27:45 +08:00
|
|
|
bool passed = true;
|
2020-07-08 00:38:40 +08:00
|
|
|
int rand_num, rand_value, index, real_value, num_tests = 10000;
|
|
|
|
std::vector<int> arr;
|
|
|
|
while(num_tests--){
|
|
|
|
arr.clear();
|
|
|
|
for(int i = 0; i < 100; i++){
|
2020-07-08 00:45:03 +08:00
|
|
|
rand_num = std::rand() % 1000;
|
2020-07-08 00:38:40 +08:00
|
|
|
arr.push_back(rand_num);
|
|
|
|
}
|
2020-07-08 00:45:03 +08:00
|
|
|
rand_value = std::rand() % 1000;
|
|
|
|
std::sort(arr.begin(), arr.end());
|
2020-07-08 00:38:40 +08:00
|
|
|
index = fibonacci_search(arr, rand_value);
|
|
|
|
if(index != -1){
|
|
|
|
real_value = arr[index];
|
|
|
|
passed = passed && (real_value == rand_value);
|
|
|
|
} else {
|
|
|
|
passed = passed && (std::find(arr.begin(), arr.end(), rand_value) == arr.end());
|
|
|
|
}
|
|
|
|
}
|
2020-07-07 21:27:45 +08:00
|
|
|
return passed;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Main Function
|
|
|
|
* testing the algorithm
|
|
|
|
*/
|
|
|
|
int main() {
|
2020-07-08 00:38:40 +08:00
|
|
|
assert(no_occurence_tests());
|
|
|
|
assert(random_tests());
|
2020-07-07 18:38:58 +08:00
|
|
|
return 0;
|
|
|
|
}
|