Algorithm “a”的正确术语是什么;“凝聚”;事件队列?
假设我有一个“事件”对象队列,其中每个对象都有一个“事件类型”和某种数据字段。在C++中,可以是这样的:Algorithm “a”的正确术语是什么;“凝聚”;事件队列?,algorithm,data-structures,Algorithm,Data Structures,假设我有一个“事件”对象队列,其中每个对象都有一个“事件类型”和某种数据字段。在C++中,可以是这样的: enum class EventType { A, B, C }; struct Event { EventType type; std::string message; }; 比方说,我想要一个这些事件的队列,并且我希望该队列具有以下属性: 将事件推送到队列时,将删除所有具有相同EventType的现有事件。因此,当从队列中弹出事件时,它始
enum class EventType
{
A,
B,
C
};
struct Event
{
EventType type;
std::string message;
};
比方说,我想要一个这些事件的队列,并且我希望该队列具有以下属性:
- 将事件推送到队列时,将删除所有具有相同
的现有事件。因此,当从队列中弹出事件时,它始终是其EventType
EventType
- 不同
的事件按推送顺序弹出。(EventType
不需要任何参数)李>pop()
事件
为先进先出,对于事件类型
为后进先出
示例:
将以下事件推送到队列(字母为事件类型,数字为实例号)
如果pop()然后被调用3次,则按顺序返回的项将是
C3 B2 A3
这种类型的数据结构有名字吗?有实现的例子吗?免责声明:设计非常高效的数据结构这是与域(架构)和数据上下文严格相关的事情。以下解决方案旨在对一般情况具有理论上的有效性。有关更多详细信息,请参见最终注意事项
结构设计 这个想法很简单 保留表示队列的基础数据结构 每次插入新事件时,请检查类型是否已存在。在这种情况下,我们可以删除该元素。通过这种方式,我们维护第一个属性(每个类型只有一个实例,这意味着我们总是为该类型弹出最新的实例) 最后,我们在队列的末尾插入新实例。因此,我们保留第二个属性
一个简单实现的示例
#包括
考虑和分析
- 在我的示例中,我使用了
std::list
作为底层数据结构。事实上,一个std::list
在频繁删除“中间”时非常方便。此外,删除后,迭代器不会失效。这是一个很好的属性,以防我们想要改进队列
QueueWithAGoodName::push
具有运行时复杂性:O(N)
(因为我们应用线性扫描来查找类型)。其中N
是队列的大小
QueueWithAGoodName::pop
和QueueWithAGoodName::front
是O(1)
进一步考虑
- 对于这种类型的数据结构,有一个重要的特性。我们每种类型有一个实例。这意味着
N
(队列大小)的上限是EventType
s的数量
- 如果事件类型的数量有限,则可以考虑几个因素,因为(对于常见体系结构)运行时复杂性
O(N)
可以近似为O(1)
。在这种情况下,std::vector
作为底层数据结构可能由于缓存而更加有效
- 在我报告的简单示例中,
push
是O(N)
。如果您有几种类型的EventType
s,则可以使数据结构在推送操作中更有效。简而言之,您可以使用辅助std::无序_映射(即哈希映射)来避免线性搜索。删除后,std::list
不会使迭代器无效,因此哈希表保持一致
免责声明:设计非常高效的数据结构这是与域(架构)和数据上下文严格相关的事情。以下解决方案旨在对一般情况具有理论上的有效性。有关更多详细信息,请参见最终注意事项
结构设计
这个想法很简单
保留表示队列的基础数据结构
每次插入新事件时,请检查类型是否已存在。在这种情况下,我们可以删除该元素。通过这种方式,我们维护第一个属性(每个类型只有一个实例,这意味着我们总是为该类型弹出最新的实例)
最后,我们在队列的末尾插入新实例。因此,我们保留第二个属性
一个简单实现的示例
#包括
考虑和分析
- 在我的示例中,我使用了
std::list
作为底层数据结构。事实上,一个std::list
在频繁删除“中间”时非常方便。此外,删除后,迭代器不会失效。这是一个很好的属性,以防我们想要改进队列
QueueWithAGoodName::push
具有运行时复杂性:O(N)
(因为我们应用线性扫描来查找类型)。其中N
是队列的大小
QueueWithAGoodName::pop
和QueueWithAGoodName::front
是O(1)
进一步考虑
- 对于这种类型的数据结构,有一个重要的特性。我们每种类型有一个实例。这意味着
N
(队列大小)的上限是EventType
s的数量
- 如果事件类型的数量有限,则可以考虑几个因素,因为(对于常见体系结构)运行时复杂性
O(N)
可以近似为O(1)
。在这种情况下,std::vector
作为底层数据结构可能由于缓存而更加有效
- 在我报告的简单示例中,
push
是O(N)
。如果您有几种类型的EventType
s,则可以使数据结构在推送操作中更有效。简而言之,您可以使用一个辅助std::unordered\u映射
C3 B2 A3
#include <algorithm>
#include <list>
#include <utility>
class QueueWithAGoodName {
public:
using reference = Event&;
void push(Event event) {
if (const auto finder =
std::find_if(queue_.begin(),
queue_.end(),
[eventType = event.type](const Event& event) {
return event.type == eventType;
});
finder != queue_.end()) {
queue_.erase(finder);
}
queue_.push_back(std::move(event));
}
reference front() { return queue_.front(); }
void pop() { queue_.pop_front(); }
private:
std::list<Event> queue_;
};