Я должен признать, что я еще никогда не слышал о (термин) левые дети-правые родные деревья (или я уже забыл об этом). Однако я уже видел нечто подобное в действии, когда использовал libXml2 . (Взгляните на struct _xmlNode
, чтобы понять, что я имею в виду.)
Итак, я объясняю, как бы я сделал сравнение CTree::operator==()
:
bool operator==(const CTree &cTree) const
{
- Я бы сначала сравнил
data
. Нет необходимости проходить через любого потомка или брата, если узлы root имеют разные данные.
if (data != cTree.data) return false; // unequal data -> equality failed
Следующим шагом будет сравнение парных указателей
kids
. Если у одного из узлов есть дочерние элементы, а у другого нет, сравнение на равенство может выручить. Для этого я просто конвертирую указатели в
bool
с.
if (!kids != !cTree.kids) return false; // only one has kids -> equality failed
То же самое сделано для указателей родного брата.
if (!sibs != !cTree.sibs) return false; // only one has sibs -> equality failed
Теперь оба или ни один из узлов не имеют дочерних элементов. Итак, для первого случая первая рекурсия в детей сделана. (В последнем случае этот шаг можно пропустить.)
// recursion into kids (if there are kids)
if (kids && *kids != *cTree.kids) return false; // kids exist but are unequal
На последнем этапе рекурсия должна выполняться для братьев и сестер, если есть братья и сестры. В противном случае узлы (поддеревья) в этой точке уже считаются равными. Я использую логическое или короткое замыкание. Следовательно, если
sibs
имеет
nullptr
, правая часть пропускается и возвращается
!nullptr
(
== true
). В противном случае возвращаемое значение приводит к сравнению братьев и сестер.
// recursion into sibs (if there are sibs)
return !sibs || *sibs == *cTree.sibs; // no sibs or result of sibs equality check
Вот и все.
}
Для симметрии (а также потому, что она уже использовалась) должна быть определена и противоположная часть
operator!=()
. Он просто основан на
operator==()
и AFAIK, это очень обычно.
bool operator!=(const CTree &cTree) const { return !(*this == cTree); }
Я сделал MCVE, чтобы проверить и продемонстрировать это. Таким образом, я изменил тип data
с char
на std::string
, чтобы сделать его более наглядным:
#include <iostream>
#include <string>
class CTree {
private:
std::string data;
CTree *kids;
CTree *sibs;
CTree *prev;
public:
CTree(const std::string data = ""):
data(data), kids(nullptr), sibs(nullptr), prev(nullptr)
{ }
// adds a child.
void add(CTree *kid)
{
if (kids) {
kids->prev = kid; kid->sibs = kids;
}
kids = kid; kid->prev = this;
}
bool operator==(const CTree &cTree) const
{
if (data != cTree.data) return false; // unequal data -> equality failed
if (!kids != !cTree.kids) return false; // only one has kids -> equality failed
// recursion into kids (if there are kids)
if (kids && *kids != *cTree.kids) return false; // kids exist but are unequal
if (!sibs != !cTree.sibs) return false; // only one has sibs -> equality failed
// recursion into sibs (if there are sibs)
return !sibs || *sibs == *cTree.sibs; // no sibs or result of sibs equality check
}
bool operator!=(const CTree &cTree) const { return !(*this == cTree); }
};
CTree* install(bool complete)
{
CTree *pRoot = new CTree("/");
CTree *pBin = new CTree("bin/"); pRoot->add(pBin);
CTree *pUsr = new CTree("usr/"); pRoot->add(pUsr);
CTree *pBash = new CTree("bash"); pBin->add(pBash);
CTree *pCsh = new CTree("csh"); pBin->add(pCsh);
if (complete) {
CTree *pEtc = new CTree("etc/"); pRoot->add(pEtc);
CTree *pInitD = new CTree("init.d"); pEtc->add(pInitD);
}
return pRoot;
}
int main()
{
CTree *drv1 = install(false);
CTree *drv2 = install(false);
CTree *drv3 = install(true);
std::cout << "drv1 == drv2? " << (*drv1 == *drv2 ? "yes" : "no") << '\n';
std::cout << "drv1 == drv3? " << (*drv1 == *drv3 ? "yes" : "no") << '\n';
std::cout << "drv2 == drv3? " << (*drv2 == *drv3 ? "yes" : "no") << '\n';
}
Вывод:
drv1 == drv2? yes
drv1 == drv3? no
drv2 == drv3? no
Live Demo on coliru
Подумав дважды, я понял, что равенство operator==()
можно записать еще более компактно, хотя я не думаю, что оно улучшает читабельность, и я не ожидаю какой-либо производительности победа:
bool operator==(const CTree &cTree) const
{
return data == cTree.data // unequal data -> equality failed
&& !kids == !cTree.kids // only one has kids -> equality failed
&& !sibs == !cTree.sibs // only one has sibs -> equality failed
&& (!kids || *kids == *cTree.kids) // no kids or result of kids equality check
&& (!sibs || *sibs == *cTree.sibs); // no sibs or result of sibs equality check
}
Демонстрация в реальном времени на coliru