Merge pull request #111 from Liam0205/16_bsearch

[cpp][16_bsearch] all varients' impl.
This commit is contained in:
wangzheng0822 2018-11-02 10:46:02 +08:00 committed by GitHub
commit bdce324f77
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 137 additions and 45 deletions

View File

@ -8,19 +8,16 @@
#include <iterator>
#include <functional>
enum class BsearchPolicy { FIRST, LAST, UNSPECIFIED };
// Liam Huang: The algorithm works right with iterators that meet the ForwardIterator requirement,
// but with a bad time complexity. For better performance, iterators should meet
// the RandomAccessIterator requirement.
template <typename IterT,
typename ValueT = typename std::iterator_traits<IterT>::value_type,
typename Compare>
typename Compare = std::less<ValueT>>
IterT bsearch(IterT first,
IterT last,
ValueT target,
Compare comp,
BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) {
Compare comp = Compare()) {
IterT result = last;
while (std::distance(first, last) > 0) {
IterT mid = first + std::distance(first, last) / 2;
@ -29,38 +26,12 @@ IterT bsearch(IterT first,
} else if (comp(target, *mid)) {
last = mid;
} else { // equal
if (policy == BsearchPolicy::FIRST) {
if (mid == first or comp(*(mid - 1), *mid)) {
result = mid;
break;
} else {
last = mid;
}
} else if (policy == BsearchPolicy::LAST) {
if (std::distance(mid, last) == 1 or comp(*mid, *(mid + 1))) {
result = mid;
break;
} else {
first = mid + 1;
}
} else {
result = mid;
break;
}
}
}
return result;
}
template <typename IterT,
typename ValueT = typename std::iterator_traits<IterT>::value_type,
typename Compare = std::less<ValueT>>
IterT bsearch(IterT first,
IterT last,
ValueT target,
BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) {
return bsearch(first, last, target, Compare(), policy);
}
#endif // BSEARCH_BSEARCH_HPP_

View File

@ -8,10 +8,8 @@
#include "bsearch.hpp"
template <typename VecT, typename T = typename VecT::value_type>
void test_bsearch(const VecT& test,
T target,
BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) {
auto it = bsearch(test.begin(), test.end(), target, policy);
void test_bsearch(const VecT& test, T target) {
auto it = bsearch(test.begin(), test.end(), target);
std::cout << std::distance(test.begin(), it) << std::endl;
}
@ -21,17 +19,9 @@ int main() {
test_bsearch(test, 8); // 14
test_bsearch(test, -1); // 14
test_bsearch(test, 0); // 0, 1
test_bsearch(test, 0, BsearchPolicy::FIRST); // 0
test_bsearch(test, 0, BsearchPolicy::LAST); // 1
test_bsearch(test, 4); // 5, 6
test_bsearch(test, 4, BsearchPolicy::FIRST); // 5
test_bsearch(test, 4, BsearchPolicy::LAST); // 6
test_bsearch(test, 5); // 7, 8, 9, 10, 11
test_bsearch(test, 5, BsearchPolicy::FIRST); // 7
test_bsearch(test, 5, BsearchPolicy::LAST); // 11
test_bsearch(test, 7); // 13
test_bsearch(test, 7, BsearchPolicy::FIRST); // 13
test_bsearch(test, 7, BsearchPolicy::LAST); // 13
return 0;
}

View File

View File

@ -0,0 +1,90 @@
/**
* Created by Liam Huang (Liam0205) on 2018/10/26.
*/
#ifndef BSEARCH_BSEARCH_VARIENTS_HPP_
#define BSEARCH_BSEARCH_VARIENTS_HPP_
#include <iterator>
#include <functional>
enum class BsearchPolicy { UNSPECIFIED, FIRST, LAST, FIRST_NOT_LESS, LAST_NOT_GREATER };
// Liam Huang: The algorithm works right with iterators that meet the ForwardIterator requirement,
// but with a bad time complexity. For better performance, iterators should meet
// the RandomAccessIterator requirement.
template <typename IterT,
typename ValueT = typename std::iterator_traits<IterT>::value_type,
typename Compare>
IterT bsearch(IterT first,
IterT last,
ValueT target,
Compare comp,
BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) {
IterT result = last;
while (std::distance(first, last) > 0) {
IterT mid = first + std::distance(first, last) / 2;
if (policy == BsearchPolicy::FIRST_NOT_LESS) {
if (!comp(*mid, target)) {
if (mid == first or comp(*(mid - 1), target)) {
result = mid;
break;
} else {
last = mid;
}
} else {
first = mid + 1;
}
} else if (policy == BsearchPolicy::LAST_NOT_GREATER) {
if (comp(target, *mid)) {
last = mid;
} else {
if (std::distance(mid, last) == 1 or comp(target, *(mid + 1))) {
result = mid;
break;
} else {
first = mid + 1;
}
}
} else { // policy == UNSPECIFIED or FIRST or LAST
if (comp(*mid, target)) {
first = mid + 1;
} else if (comp(target, *mid)) {
last = mid;
} else { // equal
if (policy == BsearchPolicy::FIRST) {
if (mid == first or comp(*(mid - 1), *mid)) {
result = mid;
break;
} else {
last = mid;
}
} else if (policy == BsearchPolicy::LAST) {
if (std::distance(mid, last) == 1 or comp(*mid, *(mid + 1))) {
result = mid;
break;
} else {
first = mid + 1;
}
} else {
result = mid;
break;
}
}
}
}
return result;
}
template <typename IterT,
typename ValueT = typename std::iterator_traits<IterT>::value_type,
typename Compare = std::less<ValueT>>
IterT bsearch(IterT first,
IterT last,
ValueT target,
BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) {
return bsearch(first, last, target, Compare(), policy);
}
#endif // BSEARCH_BSEARCH_VARIENTS_HPP_

View File

@ -0,0 +1,41 @@
/**
* Created by Liam Huang (Liam0205) on 2018/10/26.
*/
#include <iostream>
#include <vector>
#include "bsearch_varients.hpp"
template <typename VecT, typename T = typename VecT::value_type>
void test_bsearch(const VecT& test,
T target,
BsearchPolicy policy = BsearchPolicy::UNSPECIFIED) {
auto it = bsearch(test.begin(), test.end(), target, policy);
std::cout << std::distance(test.begin(), it) << std::endl;
}
int main() {
std::vector<int> test{0, 0, 1, 2, 3, 4, 4, 5, 5, 5, 5, 5, 6, 8}; // std::less<int>()
test_bsearch(test, 8); // 14
test_bsearch(test, -1); // 14
test_bsearch(test, 0); // 0, 1
test_bsearch(test, 0, BsearchPolicy::FIRST); // 0
test_bsearch(test, 0, BsearchPolicy::LAST); // 1
test_bsearch(test, 4); // 5, 6
test_bsearch(test, 4, BsearchPolicy::FIRST); // 5
test_bsearch(test, 4, BsearchPolicy::LAST); // 6
test_bsearch(test, 5); // 7, 8, 9, 10, 11
test_bsearch(test, 5, BsearchPolicy::FIRST); // 7
test_bsearch(test, 5, BsearchPolicy::LAST); // 11
test_bsearch(test, 7, BsearchPolicy::FIRST_NOT_LESS); // 13
test_bsearch(test, 7, BsearchPolicy::LAST_NOT_GREATER); // 12
test_bsearch(test, 7, BsearchPolicy::FIRST); // 14
test_bsearch(test, 8); // 13
test_bsearch(test, 8, BsearchPolicy::FIRST); // 13
test_bsearch(test, 8, BsearchPolicy::LAST); // 13
return 0;
}