Klonowalne listy

0

Potrzebuję operacji na listach w C++. Z pozoru zadanie może wydawać się trywialne, ale po pierwsze, nie dołączam pojedynczego obiektu, tylko na boku tworzę grupę na przykład drzewo z 5 elementów a potem podłączam po d któryś węzeł. Po drugie, musi być klonowanie - nie chcę aby zmiana w jednym miejscu zmieniała w innym gdy dwa razy podczepię element w dwóch różnych miejscach. Poza tym dziedziczenie z polimorfizmem oraz operacja, która powoduje trudności - zastąpienie poddrzewka innym. Na początku, zastępowanie drzewka określonego typu - tu były trudności bo nie mogę dla węzła a wykonać zmiany tego węzła, mogę zmieniać jego dane ale nie jego adres. Powinno to byc drzewko , lista dzieci i parent, oraz głębokość, czyli jak dodaję, to również dzieci aktualizują głębokość i parenta do nowych sklonowanych elementów.

1

Zadasz jakieś pytanie, czy mamy tylko poklepać Cię po ramieniu?

0

Jak zrobić coś takiego: chcę wymienić w drzewku element na poddrzewko, ale nie mogę ponieważ gdy dla elementu a wołam a.replace(subtree), wtedy w a mogę zmienić dane, ale nie mogę zmienić samego wskazania na a.

0

Co to znaczy element na poddrzewko? Chcesz zmienić węzeł na poddrzewo, a reszta nie zmieniona, tylko wskazuje na nowy element?

0

Tak, aby zgadzały się linki ojciec - dzieci.

Piszę od początku,

class Node
{
	vector<Node*> childs;
	Node* parent = nullptr;
	int level = 0;

najprościej jak można

	void Add(Node* node)
	{
		childs.push_back(node);
		node->parent = this;
		node->level = level+1;
	}

Teraz chcę zamienić to na shared_ptr<Node>, niby nic trudnego ale jak zamienić node->parent = this ? W C++ this to goły wskaźnik, robiłem coś takiego dając do procedury shared_ptr<Node> th:

void Add(Node* node, shared_ptr<Node> th)

Następna sprawa: jak uniknąć cykli? Jest:

int main()
{
	Node *root;
	root = new Node("1");
	Node *node = new Node("2");
	root->Add(node);
	node->Add(root); //<---to spowoduje cykl
	root->print();
    return 0;
}

Można patrzeć na level ,ale jak dokładnie
Następnie - klonowanie.

Co do shared: to nie wiedziałem że jest shared_from_this(), które można wołać gdy przedziedziczy się własną klasę z std::enable_shared_from_this<NazwaMojejKlasy>

Tylko że shared from this będzie niepotrzebny z powodu wycieków pamięci dla cyklicznych zależności. Lepsze weak albo po prostu wskaźnik.(były problemy z ustawieniem weak na nullptr)
Wersja która dodaje drzewo, i robi erase zerując dzieci ale jak usunąć ten węzeł?

#include <memory>
#include <string>
#include <vector>
#include <assert.h>

using namespace std;

class Node
{
	vector<shared_ptr<Node>> childs;
	Node* parent = nullptr;//not shared_ptr! because of memory leaks of circular dependency
	int level = 0;
public:
	string name;
	Node(string name)
	{
		this->name = name;
	}
	~Node()
	{
		printf("delete %s\n",name.c_str());
	}
	shared_ptr<Node> clone()
	{
		shared_ptr<Node> result = make_shared<Node>(name+"a");
		return result;
	}
	void erase()
	{
		printf("erase from %s\n", name.c_str());
		childs.clear();
	}
	void Add(shared_ptr<Node> node)
	{
		shared_ptr<Node> clone = node->clone();
		childs.push_back(clone);
		clone->parent = this;
		clone->level = level+1;
		for (size_t i = 0; i<node->childs.size(); i++)
			clone->Add(node->childs[i]);
	}
	shared_ptr<Node>& at(int index)
	{
		return childs[index];
	}
	void print()
	{
		for (int i = 0; i<level; i++)
			printf("  ");
		printf("%s->",name.c_str());
		if (parent) printf("%s", parent->name.c_str());
		printf("\n");
		for (size_t i=0; i<childs.size(); i++)
			childs[i]->print();
	}
};

int main()
{
	shared_ptr<Node>root,rootB;
	root = make_shared<Node>("1");
	root->Add(make_shared<Node>("2"));
	root->Add(make_shared<Node>("3"));
	root->at(0)->Add(make_shared<Node>("4"));
	root->at(0)->Add(make_shared<Node>("5"));
	root->at(1)->Add(make_shared<Node>("6"));
	root->at(1)->Add(make_shared<Node>("7"));

	rootB = make_shared<Node>("1b");
	rootB->Add(make_shared<Node>("2b"));
	rootB->Add(make_shared<Node>("3b"));
	rootB->at(0)->Add(make_shared<Node>("4b"));
	rootB->at(0)->Add(make_shared<Node>("5b"));
	rootB->at(1)->Add(make_shared<Node>("6b"));
	rootB->at(1)->Add(make_shared<Node>("7b"));
//	node->Add(root);
	//root->print();printf("\n");
	//rootB->print(); printf("\n");
	root->at(0)->Add(rootB);
	rootB = nullptr;
	//rootB->at(0)->Add(rootB);//tu cykl?
	root->print();
	root->at(0)->erase();
	root->print();
    return 0;
}
0

Okazuje się, że nie tak jak powinno być zrobiłem klonowanie - teraz gdy podczepiam poddrzewo, wchodzi w głąb i klonuje w razie potrzeby po jednym obiekcie. A co gdy chcę podczepić w pewnym miejscu właśnie to drzewo, czyli roota? Więc powinien całe drzewo sklonować a potem podczepić. Jak to zrobić?

1 użytkowników online, w tym zalogowanych: 0, gości: 1