在 C++ 中实现二叉搜索

Jinku Hu 2023年10月12日
  1. 在 C++ 中为 std::vector 容器实现二叉搜索算法
  2. 二叉搜索算法的复杂度分析
在 C++ 中实现二叉搜索

本文将解释如何在 C++ 中实现二叉搜索算法。

在 C++ 中为 std::vector 容器实现二叉搜索算法

搜索算法是在大多数常见问题中使用的基本子程序,以最有效的方式执行它们很重要。有多种类型的搜索算法;有些是为特殊数据结构量身定制的,有些可以更普遍地应用。

二叉搜索是一种分而治之的算法,应该用于排序的键数组。由于其最坏情况的性能,它通常被称为对数搜索,我们将在本文后面进行概述。

你可以将二叉搜索描述为:一旦我们拥有需要找到 k 键的对象的排序数组,我们应该将给定的键与数组中的中间元素进行比较。如果键小于元素,它应该位于数组的左半部分,或者如果它更大 - 我们应该在右半部分寻找它。

在我们对每个较小的半数组递归重复这个查找过程后,我们最终会找到键的位置或指示键不在数组中。尽管我们将算法描述为自然递归,但它可以使用迭代方法实现,但我们将重点介绍递归算法。

以下示例代码生成 [1-1000] 范围内的一千个随机整数,并将它们存储在 std::vector 容器中。然后使用 std::sort 算法对向量进行排序,然后我们声明另一个包含九个整数的向量进行搜索。请注意,searchVector 包装函数用于调用递归函数 binarySearch

后者检查两个位置的第一个索引是否比另一个多;如果是,函数返回。返回值 -1 用于指示给定键的未找到状态。接下来,计算中间位置并与键进行比较,如果为真则返回索引值。最后,我们选择需要搜索数组的哪一部分,并使用相应的索引调用相同的函数。

#include <iostream>
#include <random>
#include <vector>

using std::cout;
using std::endl;
using std::vector;

constexpr int MIN = 1;
constexpr int MAX = 1000;
constexpr int NUMS_TO_GEN = 1000;

template <typename T>
int binarySearch(const vector<T> &vec, T &item, int s1, int s2) {
  if (s1 > s2) return -1;

  auto middle = (s1 + s2) / 2;

  if (item == vec.at(middle)) return middle;

  if (item > vec.at(middle))
    return binarySearch(vec, item, middle + 1, s2);
  else
    return binarySearch(vec, item, s1, middle - 1);
}

template <typename T>
int searchVector(const vector<T> &vec, T &item) {
  return binarySearch(vec, item, 0, vec.size() - 1);
}

int main() {
  std::random_device rd;
  std::default_random_engine eng(rd());
  std::uniform_int_distribution<int> distr(MIN, MAX);

  std::vector<int> vec;
  vec.reserve(NUMS_TO_GEN);
  for (int n = 0; n < NUMS_TO_GEN; ++n) {
    vec.push_back(distr(eng));
  }
  std::sort(vec.begin(), vec.end());

  std::vector<int> vec2{2, 111, 222, 5, 333, 7, 8, 444, 100};
  for (auto &item : vec2) {
    searchVector(vec, item) != -1 ? cout << "found, " : cout << "did not, ";
  }
  cout << endl;

  return EXIT_SUCCESS;
}

输出:

did not, found, found, did not, found, did not, found, did not, found,

二叉搜索算法的复杂度分析

二叉搜索具有 O(log n) 复杂度,因此别名为 - 对数搜索。我们可以通过分析递归成本来粗略估计递归算法实现的运行时间。注意查找中间元素是一个常数时间的操作,我们需要遍历数组的一半。

在下面的程序中,我们演示了使用 STL std::sort 算法对我们的二叉搜索函数的验证测试。但是请记住,此检查不是形式验证,只是在算法实现过程中提供快速测试用例来调试和分析代码行为。

#include <iostream>
#include <random>
#include <vector>

using std::cout;
using std::endl;
using std::vector;

constexpr int MIN = 1;
constexpr int MAX = 1000;
constexpr int NUMS_TO_GEN = 1000;

template <typename T>
int binarySearch(const vector<T> &vec, T &item, int s1, int s2) {
  if (s1 > s2) return -1;

  auto middle = (s1 + s2) / 2;

  if (item == vec.at(middle)) return middle;

  if (item > vec.at(middle))
    return binarySearch(vec, item, middle + 1, s2);
  else
    return binarySearch(vec, item, s1, middle - 1);
}

template <typename T>
int searchVector(const vector<T> &vec, T &item) {
  return binarySearch(vec, item, 0, vec.size() - 1);
}

int main() {
  std::random_device rd;
  std::mt19937 eng(rd());
  std::uniform_int_distribution<int> distr(MIN, MAX);

  std::vector<int> vec;
  vec.reserve(NUMS_TO_GEN);
  for (int n = 0; n < NUMS_TO_GEN; ++n) {
    vec.push_back(distr(eng));
  }
  std::sort(vec.begin(), vec.end());

  std::vector<int> vec2{2, 111, 222, 5, 333, 7, 8, 444, 100};
  for (auto &item : vec2) {
    searchVector(vec, item) != -1 ? cout << "found, " : cout << "did not, ";
  }
  cout << endl;

  for (auto &item : vec2) {
    std::find(vec.begin(), vec.end(), item) != vec.end() ? cout << "found, "
                                                         : cout << "did not, ";
  }

  return EXIT_SUCCESS;
}

输出:

found, found, found, found, did not, did not, found, found, found,
found, found, found, found, did not, did not, found, found, found,
作者: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

DelftStack.com 创始人。Jinku 在机器人和汽车行业工作了8多年。他在自动测试、远程测试及从耐久性测试中创建报告时磨练了自己的编程技能。他拥有电气/电子工程背景,但他也扩展了自己的兴趣到嵌入式电子、嵌入式编程以及前端和后端编程。

LinkedIn Facebook

相关文章 - C++ Algorithm