C++ C++';s std::set类是否能够为任何类型的数据结构实现二叉树?
我了解如何为大多数本机元素(如C++ C++';s std::set类是否能够为任何类型的数据结构实现二叉树?,c++,algorithm,C++,Algorithm,我了解如何为大多数本机元素(如ints或strings)实现二叉树。因此,我可以理解std::set的一个实现,它将有一个类似 switch(typeof(T)) // T being the typename/class in the implementation { case int: { /* create a binary tree structure that uses the bitshift operator to add element
int
s或string
s)实现二叉树。因此,我可以理解std::set
的一个实现,它将有一个类似
switch(typeof(T)) // T being the typename/class in the implementation
{
case int:
{
/* create a binary tree structure that uses the bitshift operator to
add elements, e.g. 13=1101 is created as
/
/
/
/
1
/
/
/
1
\
\
0
/
1
*/
}
case string:
{
/* Do something where the string is added to a tree by going letter-by-letter
and looking whether the letter is in the second half of the alphabet (?)
*/
}
// etcetera for every imaginable type
}
但显然这不是std::set实际实现的方式,因为即使我使用像
struct myStruct
{
char c;
bool b;
};
std::set<myStruct> mySet;
因为“!”的ASCII值代码>为21,整数为1时,abool=true
。同样,一般来说,这样做可能效率低下,因为一个非常大的数据结构将对应于一个巨大的树,它可能需要更多的时间来遍历,而不仅仅是对元素进行基本的线性搜索
这有意义吗?我真的很困惑,如果这里有人能纠正我,我会很高兴的。
简而言之,std::set
类只定义了一个类的原型,然后使用提供的参数(一些键类型Key
,一些值类型T
,如果没有给出,则推导出std::less
和std::allocator
,或者其他任何参数)在编译类型实例化该类
灵活性的很大一部分来自于能够创建部分专业化和使用其他模板和默认参数
现在,std::less
是为许多标准库类型和所有基本类型定义的,但不是为自定义类型定义的
有3种方法可以提供比较std::map
需求:
- 重写默认模板参数并将其提供给模板(如果重写具有状态,则向构造函数提供对象可能有意义)
- 专业
std::less
- 添加一个比较运算符(
operator您始终可以通过比较它们的字节数组来比较同一类型的两个,无论是什么
因此,如果集合表示为排序二叉树,则结果为-1的memcmp表示insert left,结果为+1的memcmp表示insert right
以后
<>我很想表明,不需要根据一个集合元素的位来进行分支,我没有考虑到一个限制,它需要一个STD::set元素来实现运算符。让我们试试你的例子:
#include <set>
struct myStruct {
char c;
bool b;
};
int main() {
std::set<myStruct> mySet;
mySet.insert(myStruct());
}
现在代码可以编译了
所有这些都是有效的,因为std::set
希望能够通过std::less
来比较两个T
对象,它尝试执行(T)lhs,这是高度特定于实现的:实际实现可能会有所不同。我希望能让您了解它的工作原理
一棵二叉树通常会在树的每个点保持实际值:你的图让我认为值只存在于叶节点(你在想一个吗?)。考虑一个字符串二叉树,MeMeBeS代码> CAT/CODE >,代码>鸭子< /代码>,<代码> GOOS,和<代码>狗< /代码>:
dog
/ \
cat duck
\
goose
这里请注意,每个节点都是集合中存在的一个值。(在这里,我们的集合有4个元素。)虽然您可能会执行某种0/1前缀,但您需要能够将对象转换为位字符串(查看原始的底层字节不一定有效),并且实际上并不需要
您需要理解C++中的模板;记住<代码>设置是“代码”,在<代码> t>代码>,即“代码> t>代码>是您使用集合时指定的任何内容。(在代码< >代码>代码中实现的字符串(<代码>设置<代码> >自定义代码>(代码>设置/代码>)),您可以想象一个帮助类:
template<typename T>
struct node {
T value;
node<T> *left, *right;
}
模板
结构节点{
T值;
节点*左,*右;
}
这个结构保存一个值,以及哪个节点在它的左边和右边。set
,因为它有T
要在它的实现中使用,可以使用它来将这个节点
结构模板化为相同的T
。在我的示例中,标记为“dog”的位将是一个节点
,值
是一个标准::字符串
,值为“dog”
,左
指向持有“cat”
的节点,右指向持有“duck”
的节点
在集合中查找值时,它会从根开始在树中查找该值。集合可以通过将要查找/插入/删除的值与其查看的节点进行比较来“知道”要走哪条路(左或右)。(对集合的一个要求是,无论你用什么模板,它都可以与相媲美。你是否尝试过你的myStruct
示例。如果成功了,你使用了哪种编译器。我认为你不明白平衡二叉树是如何工作的。在std::set
中只添加13
永远不会给出你描述的路径!听起来像是在描述(前缀树)任何C++编译器都会编译<代码> MyStult SabpPosits——但是一旦你尝试将一个对象插入到该集合中,它将失败,因为没有办法为两个<代码> MyStult对象排序。是的,你可以逐字节比较两个对象,但是这几乎不给你想要的,这就是为什么C++。+不会默认为该行为。如果尚未定义运算符suppose,则尝试为长度为50的字符数组创建二叉树。这是查找字符数组是否在树中的3200个“步骤”。这些步骤中的每一步都涉及检查是“右”还是“左”的两个操作.所以它更像是10000步。当然,你必须从一个记忆位置跳到另一个。它可能不会像制作一个巨大的数组来容纳所有长度为50个字符的数组那样快。这就是为什么我不会痴迷于在Amazon/Google/等网站编程采访。测试二叉树之类的知识@Markransem这仍然是一种决定的方式
bool operator<(myStruct const & lhs, myStruct const & rhs) {
if (lhs.c < rhs.c)
return true;
if (lhs.c > rhs.c)
return false;
return lhs.b < rhs.b;
}
dog
/ \
cat duck
\
goose
template<typename T>
struct node {
T value;
node<T> *left, *right;
}