【问题标题】:Usage of binary search二分查找的使用
【发布时间】:2015-04-29 21:14:16
【问题描述】:

我目前正在做我的家庭作业,我几乎完成了,但我似乎不太了解我任务的最后一部分。这是任务描述,粗体字是我不明白的:

编写一个保存约会簿的程序。创建一个类 Appointment,其中存储约会的描述、约会日期、开始时间和结束时间。您的程序应该将约会保存在排序的向量中。用户可以添加约会并打印给定日期的所有约会。 添加新约会时,使用二分搜索查找应在向量中插入的位置。如果与其他约会冲突,请勿添加。

我上周刚刚了解了线性/二进制搜索算法,现在我无法看到我应该在这里做什么。通过二分搜索,我可以在例如向量中找到一个值(就像我的情况一样),对吧?那么如何确定应该在向量中插入新添加的约会的位置?什么应该告诉我它应该插入到哪里?我也有点困惑,即使向量可能还没有元素,我也必须使用二进制搜索来查找必须插入约会的位置。它首先说“添加约会时”,然后还说“..找到应该插入的位置”,这与我的解决方案有点冲突,因为我将新添加的约会推回向量,但描述问我首先找到应该添加然后插入的位置。听起来令人困惑,但我现在无法更好地表述它。

我不是要求直接代码,这就是为什么我到目前为止还没有发布我的解决方案。我只是想澄清一下我应该用那个二进制搜索做什么。谢谢

【问题讨论】:

  • 您不仅可以使用二分搜索在向量中定位特定值,还可以定位值所在的位置如果它已经在其中。 (放弃你的“解决方案”——你不应该使用push_back,所以它根本不是一个解决方案。)
  • @molbdnilo 好的,谢谢。我也不确定push_back,所以我可能不得不改用std::vector::insert 成员函数?
  • 是的,你应该这样做。有关此任务的可能逻辑,请参阅我的答案。

标签: c++ vector task binary-search


【解决方案1】:

Binary search 用于搜索平均复杂度为O(log n) 的排序数据。在std::vector 中,您可以使用insert() 方法在所需位置(只要它有效)显式插入值。

现在,关于你的任务:

添加新约会时,使用二分搜索查找应在向量中插入的位置。如果它与另一个约会冲突,请不要添加它。

一般方法是:

struct Appointment
{
    Date date;
    Time begin;
    Time end;
    //other required members
};

现在,书本身:

class AppointmentsBook
{
private:
    typedef std::vector<Appointment> ApVec;

    ApVec _appointments;

public:
    //constructors, finding methods etc.
    bool add(const Appointment& ap);
};

bool AppointmentsBook::add(const Appointment& ap)
{
    ApVec::iterator pos = this->find_insert_position(ap); //find_insert_position implements searching using binary search algo

    if((pos != this->_appointments.end()) && (ap->date == pos->date) && intersects(ap.begin, ap.end, pos->begin, pos->end))
    {
        return false;
    }
    else
    {
        this->_appointments.insert(pos, ap);
        return true;
    }
}

当然,这是伪代码。 intersects() 函数应该检查两个时间范围是否相互冲突。

注意,如果您被允许使用std 库中的某些功能,您可以使用std::lower_bound,它使用二分搜索并且要求元素是部分排序的:

范围 [first, last) 必须至少部分排序,即根据表达式 element &lt; valuecomp(element, value) 进行分区。


哦,还有一件事:如果您想知道,为什么 add() 内部的条件会检查:

`if(pos != this->_appointments.end())`

对于空书(因此,空的_appointments 向量),find_insert_position() 应该返回this-&gt;_appointments.end(),表示还没有约会。然后,可以(并且应该!)省略其他检查,并在向量的末尾插入新的约会。


使用std::lower_bound,您的find_insert_position() 函数可能如下所示:

AppointmentsBook::ApVec::iterator AppointmentsBook::find_insert_position(const Appointment& ap)
{
    if(this->_appointments.empty())
        return this->_appointments.end();

    return std::lower_bound(this->_appointments.begin(), this->_appointments.end(), ap);
}

【讨论】:

  • 感谢您的帮助。我目前正在阅读有关std::lower_bound 的信息。我被允许使用标准库
  • @nenko182 我使用std::lower_bound 更新了我的可能实施答案。
  • 感谢您的帮助。我使用std::lower::bound 函数实现了find_insert_position(),但我收到一条错误消息,提示“vect(在您的情况下为 ApVec)没有命名类型”。我在类私有部分做了typedef 声明。这里有什么问题?
  • 你有没有在课堂上声明find_insert_position()?请参阅我的答案的底部,
  • 是的,我当然做到了。我已经宣布了。它只会在我开始实现该功能时给出错误 - 它不会在类内给出错误。
【解决方案2】:

如果您被允许使用标准库算法,std::lower_bound 将执行二分搜索并返回向量内的一个位置,以便插入新元素。 在插入之前,您可以检查该位置(如果它不指向 end())以查看是否同时已经有约会。

请咨询this link,了解有关 lower_bound 及其作用的更多信息。

【讨论】:

    【解决方案3】:

    您必须对每个新约会重新排序条目向量,因此向量索引表示约会顺序。如果新约会的开始时间介于其他约会的开始时间和结束时间之间,您必须保留旧约会。

    算法:

    1. 在新约会之前对约会进行二分搜索
    2. 检查碰撞
    3. 在向量中推送新的空元素
    4. 在 2 中的索引 caluclatet 转移其他约会
    5. 在 2 中计算的索引处插入新约会

    【讨论】:

    • 1. Check for collision, 2. binary search vor appointments before the new appiointment -> 你确定吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多