在 C++ 中实现二叉搜索

Jinku Hu 2023年10月12日 C++ C++ Algorithm
  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,
Enjoying our tutorials? Subscribe to DelftStack on YouTube to support us in creating more high-quality video guides. Subscribe
作者: Jinku Hu
Jinku Hu avatar Jinku Hu avatar

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

LinkedIn Facebook

相关文章 - C++ Algorithm