I have the following code:
#include <vector>
#include <memory>
struct Node{
int value;
Node *left = nullptr;
Node *right = nullptr;
};
std::vector<std::unique_ptr<Node>> createListNodes(int min, int max)
{
// odered vector with i.e. {0,1,2,3,4}
std::vector<std::unique_ptr<Node>> alternative;
if (min == max)
{
alternative.emplace_back(std::make_unique<Node>(min,nullptr,nullptr)); // it is a leaf node
return alternative;
}
for (int i=min; i<=max; i++)
{
std::vector<std::unique_ptr<Node>> left = createListNodes(min,i-1); // for the left side
std::vector<std::unique_ptr<Node>> right = createListNodes(i+1,max); // for the left side
if (left.size() == 0) // if node i has just one child and it is in the right
{
for (auto elem_right : right) // ERROR
{
alternative.emplace_back(std::make_unique<Node>(i,nullptr,elem_right));
}
}
else if (right.size() == 0) // if node i has just one child and it is in the left
{
for (auto elem_left : left) // ERROR
{
alternative.emplace_back(std::make_unique<Node>(i,elem_left,nullptr));
}
}
for (auto elem_left : left) // ERROR
{
for (auto elem_right : right) // ERROR
{
alternative.emplace_back(std::make_unique<Node>(i,elem_left,elem_right));
}
}
}
return alternative;
}
int main()
{
int N = 4;
std::vector<std::unique_ptr<Node>> combinations = createListNodes(0, N);
}
I am receiving an error when iterating over the vector of unique_ptr but I do not manage to understand the real problem. I have tried as well moving the unique_ptr to the vector alternative but the problem still persists.
error: call to implicitly-deleted copy constructor of 'std::__1::unique_ptr<Node,
std::__1::default_delete<Node> >'
for (auto elem_left : left)
You might do something like:
You have several issue, you iterate over copy, instead of reference.
lifetime of inner nodes stop at each loop iteration.
You can make nodes own its children:
struct Node{
int value;
std::unique_ptr<Node> left = nullptr;
std::unique_ptr<Node> right = nullptr;
Node(int v, std::unique_ptr<Node> left = nullptr, std::unique_ptr<Node>right = nullptr) :
value(v), left(std::move(left)), right(std::move(right))
{}
std::unique_ptr<Node> DeepCopy() const
{
return std::make_unique<Node>(value,
left ? left->DeepCopy() : nullptr,
right ? right->DeepCopy() : nullptr);
}
};
std::vector<std::unique_ptr<Node>> createListNodes(int min, int max)
{
// odered vector with i.e. {0,1,2,3,4}
std::vector<std::unique_ptr<Node>> alternative;
if (min == max)
{
alternative.emplace_back(std::make_unique<Node>(min, nullptr, nullptr)); // it is a leaf node
return alternative;
}
for (int i=min; i<=max; i++)
{
std::vector<std::unique_ptr<Node>> left = createListNodes(min, i-1); // for the left side
std::vector<std::unique_ptr<Node>> right = createListNodes(i+1, max); // for the left side
if (left.size() == 0) // if node i has just one child and it is in the right
{
for (auto& elem_right : right)
{
alternative.emplace_back(std::make_unique<Node>(i, nullptr, std::move(elem_right)));
}
}
else if (right.size() == 0) // if node i has just one child and it is in the left
{
for (auto& elem_left : left)
{
alternative.emplace_back(std::make_unique<Node>(i, std::move(elem_left), nullptr));
}
}
for (auto& elem_left : left)
{
for (auto& elem_right : right)
{
alternative.emplace_back(std::make_unique<Node>(i, elem_left->DeepCopy(), elem_right->DeepCopy()));
}
}
}
return alternative;
}
Demo (with std::unique_ptr)
Demo (with std::shared_ptr)
Related
I got an assignment but I'm stuck in the titled problem. It will be very glad that you will help me to solve this. The quick over review I have provided the classes and main file for which I have to implemented the function and run the code. There are two files named fheap.hpp and djstra.hpp and the main file.
int main(){
// Fibonacci Heap
FibonacciHeap<int> heap(3);
std::cout<<(heap.get_min()==std::nullopt)<<std::endl;
std::vector<int> inserted;
for(int i = 0 ; i < 15 ; ++i) {
int temp = rand() % 100+1;
heap.insert(temp);
cout << temp;
cout << "inserted & min :";
cout << heap.get_min().value() << endl;
}
std::cout<<heap.get_min().value()<<std::endl;
for (int j = 0; j < 15; ++j) {
int min_value = heap.extract_min().value();
cout << "min_value: ";
std::cout << min_value;
cout << " size: ";
cout << heap.size()<<endl;
}
// Dijkstra's Algorithm
edges_t edges1 = {{0, 1, 3.0f},
{0, 2, 1.0f},
{1, 2, 7.0f},
{1, 3, 5.0f},
{1, 4, 1.0f},
{2, 3, 2.0f},
{3, 4, 7.0f}};
Graph g1(5, edges1, GraphType::UNDIRECTED);
std::unordered_map<vertex_t, std::optional<std::tuple<vertex_t, edge_weight_t>>> result
= dijkstra_shortest_path(g1, 2);
// Previous vertex of src are not checked.
std::vector<vertex_t> previous = {2, 0, (vertex_t)-1, 2, 1};
std::vector<edge_weight_t> dist = {1.0f, 4.0f, 0.0f, 2.0f, 5.0f};
// The printed result should be same as above.
for(size_t i = 0 ; i < 5 && i!=2 ; ++i) {
std::cout<<"[vertex i] ";
std::cout<<"previous: "<<std::get<0>(result[i].value())<<", ";
std::cout<<"distance: "<<std::get<1>(result[i].value())<<std::endl;
}
return 0;
}
Suprisingly the djstra part is giving me the required output. second file loop in the main section throws memory error Edit: ( meaning it exits the program with some memory address and sometimes show what() std:: optional error). The fheap class is below that are responsible for it are below:
#ifndef __FHEAP_H_
#define __FHEAP_H_
#include <iostream>
#include <initializer_list>
#include <optional>
#include <vector>
#include <cmath>
#include <memory>
#include <queue>
#include <list>
template <typename T>
class PriorityQueue {
public:
virtual void insert(const T& item) = 0;
virtual std::optional<T> extract_min() = 0;
virtual bool is_empty() const = 0;
};
template <typename T>
class FibonacciNode {
public:
// Constructors
FibonacciNode()
:key(), degree(0), marked(false), child(nullptr), right(nullptr) {}
FibonacciNode(const T& item)
:key(item), degree(0), marked(false), child(nullptr), right(nullptr) {}
// Destructor
~FibonacciNode() = default;
T key;
size_t degree;
bool marked;
std::shared_ptr<FibonacciNode<T>> right;
std::shared_ptr<FibonacciNode<T>> child;
// NOTE: To prevent circular reference, left/parent pointer should be set to weak_ptr.
std::shared_ptr<FibonacciNode<T>> left;
std::shared_ptr<FibonacciNode<T>> parent;
};
template <typename T>
class FibonacciHeap : public PriorityQueue<T> {
public:
// Constructors
FibonacciHeap()
: min_node(nullptr), size_(0) {}
FibonacciHeap(const T& item)
: min_node(nullptr), size_(0) { insert(item); }
// Disable copy constructor.
FibonacciHeap(const FibonacciHeap<T> &);
// Destructor
//~FibonacciHeap();
void insert(const T& item) override;
void insert(std::shared_ptr<FibonacciNode<T>>& node);
// Return raw pointer of the min_node.
FibonacciNode<T>* get_min_node() { return min_node.get(); }
std::optional<T> get_min() const;
std::optional<T> extract_min() override;
std::optional<T> extract_min1();
void decrease_key(std::shared_ptr<FibonacciNode<T>>& x, T new_key);
void remove(std::shared_ptr<FibonacciNode<T>>& node);
bool is_empty() const override { return !size_; }
size_t size() const { return size_; }
private:
std::shared_ptr<FibonacciNode<T>> min_node;
std::shared_ptr<FibonacciNode<T>> min;
size_t size_;
void consolidate();
void merge(std::shared_ptr<FibonacciNode<T>>& x, std::shared_ptr<FibonacciNode<T>>& y);
void cut(std::shared_ptr<FibonacciNode<T>>& x);
void recursive_cut(std::shared_ptr<FibonacciNode<T>>& x);
};
template <typename T>
void FibonacciHeap<T>::insert(const T& item) {
std::shared_ptr<FibonacciNode<T>> node = std::make_shared<FibonacciNode<T>>(item);
insert(node);
}
template <typename T>
std::optional<T> FibonacciHeap<T>::get_min() const {
if (min_node) {
return min_node->key;
} else {
return std::nullopt;
}
}
template <typename T>
void FibonacciHeap<T>::insert(std::shared_ptr<FibonacciNode<T>>& node) {
// Make the new node the right sibling of the min_node, if it exists
if (min_node) {
node->right = min_node->right;
min_node->right = node;
node->left = min_node;
node->right->left = node;
}
// Otherwise, make the new node the min_node and its own right sibling
else {
min_node = node;
node->right = node;
node->left = node;
}
// If the new node has a smaller key than the current min_node, update min_node
if (node->key < min_node->key) {
min_node = node;
}
// Increase the size of the heap
++size_;
}
template <typename T>
std::optional<T> FibonacciHeap<T>::extract_min() {
// Return nullopt if the heap is empty
if (!min_node) {
return std::nullopt;
}
// Store the min_node in a temporary variable
std::shared_ptr<FibonacciNode<T>> z = min_node;
// If the min_node has children, add them to the root list
if (z->child) {
std::shared_ptr<FibonacciNode<T>> child = z->child;
do {
child->parent.reset();
child = child->right;
} while (child != z->child);
merge(min_node, z->child);
}
// Remove the min_node from the root list
std::shared_ptr<FibonacciNode<T>> left = z->left;
std::shared_ptr<FibonacciNode<T>> right = z->right;
left->right = right;
right->left = left;
// If the min_node was the only node in the heap, set min_node to nullptr
if (z == right) {
min_node.reset();
}
// Otherwise, set the new min_node to be the node that was previously to the right of z
else {
min_node = right;
consolidate();
}
// Decrease the size of the heap
--size_;
// Return the key of the extracted min_node
return z->key;
}
template <typename T>
void FibonacciHeap<T>::decrease_key(std::shared_ptr<FibonacciNode<T>>& x, T new_key) {
// If the new key is greater than the current key, throw an exception
if (new_key > x->key) {
throw std::invalid_argument("New key is greater than current key.");
}
// Update the key of the node
x->key = new_key;
// If the node has a parent and its new key is smaller than its parent's key, cut it from its parent and add it to the root list
auto parent = x->parent.lock();
if (parent && x->key < parent->key) {
cut(x);
}
// If the node's new key is smaller than the current min_node's key, update min_node
if (x->key < min_node->key) {
min_node = x;
}
}
template <typename T>
void FibonacciHeap<T>::remove(std::shared_ptr<FibonacciNode<T>>& x) {
// Set the key of the node to be removed to the minimum value
x->key = std::numeric_limits<T>::min();
// Perform a decrease key operation on the node to be removed
decrease_key(x, std::numeric_limits<T>::min());
// Extract the minimum value, which should be the node to be removed
extract_min();
}
template <typename T>
void FibonacciHeap<T>::consolidate() {
float phi = (1 + sqrt(5)) / 2.0;
int len = int(log(size_) / log(phi)) + 10;
std::vector<std::shared_ptr<FibonacciNode<T>>> A(len, nullptr);
std::shared_ptr<FibonacciNode<T>> w = min_node;
std::shared_ptr<FibonacciNode<T>> x = w;
do {
x = x->right;
std::shared_ptr<FibonacciNode<T>> y = x;
int d = y->degree;
while (A[d]) {
std::shared_ptr<FibonacciNode<T>> z = A[d];
if (y->key > z->key) {
std::swap(y, z);
}
merge(y, z);
A[d] = nullptr;
++d;
}
A[d] = y;
} while (w != x);
min_node.reset();
for (int i = 0; i < len; ++i) {
if (A[i]) {
if (min_node) {
A[i]->right = min_node->right;
min_node->right = A[i];
A[i]->left = min_node;
A[i]->right->left = A[i];
if (A[i]->key < min_node->key) {
min_node = A[i];
}
}
else {
min_node = A[i];
min_node->right = min_node;
min_node->left = min_node;
}
}
}
}
template <typename T>
void FibonacciHeap<T>::merge(std::shared_ptr<FibonacciNode<T>>& x, std::shared_ptr<FibonacciNode<T>>& y) {
// Make x the right sibling of y
x->right = y->right;
y->right->left = x;
y->right = x;
x->left = y;
// If x has a smaller key than y, make x the new min_node
if (x->key < y->key) {
min_node = x;
}
// Otherwise, make y the new min_node
else {
min_node = y;
}
// Increase the size of the heap
size_ += 2;
}
template <typename T>
void FibonacciHeap<T>::cut(std::shared_ptr<FibonacciNode<T>>& x) {
// Get a pointer to the parent of x
auto parent = x->parent;
// If x has no parent, we do not need to cut it
if (!parent) return;
// Remove x from the child list of parent
if (x->right == x) {
parent->child = nullptr;
}
else {
x->right->left = x->left;
x->left->right = x->right;
if (parent->child == x) {
parent->child = x->right;
}
}
// Decrease the degree of parent
--parent->degree;
// Add x to the root list of the heap
x->right = min_node->right;
min_node->right = x;
x->left = min_node;
x->right->left = x;
// Clear the parent and marked fields of x
x->parent.reset();
x->marked = false;
}
template <typename T>
void FibonacciHeap<T>::recursive_cut(std::shared_ptr<FibonacciNode<T>>& x) {
// Get the parent of the node
auto parent = x->parent.lock();
// If the node has a parent, cut it from the parent and perform a recursive cut on the parent
if (parent) {
if (x->marked) {
// Cut the node from the parent
cut(x);
// Perform a recursive cut on the parent
recursive_cut(parent);
}
// If the node is not marked, mark it
else {
x->marked = true;
}
}
}
#endif // __FHEAP_H_
I know, I'm asking a very long question. I've tried every approach but it's not solving.
I Tried debugging the code and introducing cout operations where I think is error after debugging is in the line
`
std::shared_ptr<FibonacciNode<T>> z = A[d];
I tried ArrayList but still no change.
Edit: Second for loop means the 2nd loop in int main ()
vector<int> *bstValuesToVector(BinaryTreeNode *root) {
if (root == nullptr) {
return nullptr;
}
vector<int> *v;
vector<int> *leftAns = bstValuesToVector(root->left);
vector<int> *rightAns = bstValuesToVector(root->right);
if (leftAns != nullptr) {
for (int i = 0; i < leftAns->size(); i++) {
v->push_back(leftAns->at(i));
}
}
v->push_back(root->data);
if (rightAns != nullptr) {
for (int i = 0; i < rightAns->size(); i++) {
v->push_back(rightAns->at(i));
}
}
return v;
}
It is not giving any error on compiling, but it is also not successfully returning something, what can be the problem ?
std::vector is a container, so just use it.
struct BinaryTreeNode {
BinaryTreeNode* left;
BinaryTreeNode* right;
int data;
};
std::vector<int> bstValuesToVector(BinaryTreeNode *root) {
if (root == nullptr) {
return {};
}
std::vector<int> v;
std::vector<int> leftAns = bstValuesToVector(root->left);
std::vector<int> rightAns = bstValuesToVector(root->right);
// for (int i = 0; i < leftAns.size(); i++) {
// v.push_back(leftAns[i]);
// }
for (auto data : leftAns) {
v.push_back(data);
}
v.push_back(root->data);
// for (int i = 0; i < rightAns.size(); i++) {
// v.push_back(rightAns[i]);
// }
for (auto data : rightAns) {
v.push_back(data);
}
return v;
}
Copying a std::vector is usually very expensive, you could take a lesson of Inorder Traversal at first.
The problem is you are trying to access the memory of a not allocated pointer that first occurs here : v->push_back(root->data);.
You need to actually create a vector and keep its address into your "v" pointer as follows :
vector<int> *v = new vector<int>();
If you do this, then you need to avoid the memory leak by releasing your partial result vectors :
if (leftAns != nullptr) {
for (int i = 0; i < leftAns->size(); i++) {
v->push_back(leftAns->at(i));
}
delete leftAns; // see this line
}
Analog for rightAns
Stop naming your variables as "v", "Ans", use the best naming you can! See why.
My suggestion as #zjyhjqs written:
struct BinaryTreeNode {
BinaryTreeNode* left;
BinaryTreeNode* right;
int data;
};
std::vector<int> bstValuesToVector(BinaryTreeNode *root) {
if (root == nullptr) {
return {};
}
std::vector<int> result;
std::vector<int> leftData = bstValuesToVector(root->left);
std::vector<int> rightData = bstValuesToVector(root->right);
for (auto data : leftData) {
result.push_back(data);
}
result.push_back(root->data);
for (auto data : rightData) {
result.push_back(data);
}
return result;
}
I have already some sort of solution for the problem:
Given an integer N, construct all possible binary search trees with N nodes.
except that I include trees with root the minimum and maximum value but this is not my main concern.
I want to put emphasis into correctly using the move semantics and memory management in C++ (as a learning exercice).
My solution is:
#include <vector>
struct Node{
int value;
Node *left = nullptr;
Node *right = nullptr;
};
std::vector<Node*> createListNodes(int min, int max)
{
// ordered vector with i.e. {0,1,2,3,4}
Node *node = new Node;
if (min == max)
{
node->value = min;
return std::vector<Node*> {node}; // it is a leaf node
}
std::vector<Node*> alterantive{};
for (int i=min; i<=max; i++)
{
auto left = createListNodes(min,i-1); // for the left side
auto right = createListNodes(i+1,max); // for the left side
if (left.size() == 0) // if node i has just one child and it is in the right
{
for (auto elem_right : right)
{
alterantive.emplace_back(new Node{i,nullptr,elem_right});
}
}
else if (right.size() == 0) // if node i has just one child and it is in the left
{
for (auto elem_left : left)
{
alterantive.emplace_back(new Node{i,elem_left,nullptr});
}
}
for (auto elem_left : left)
{
for (auto elem_right : right)
{
alterantive.emplace_back(new Node{i,elem_left,elem_right});
}
}
}
return alterantive;
}
int main()
{
int N = 4;
std::vector<Node*> combinations = createListNodes(0, N);
}
So would like to know:
Improvements I could made to my basic design, I would prefer not to use smart pointers yet but the raw ones, to make it more memory efficient (copying less values from one side to the other ...)
General improvements in the code, even though my main focus is on memory management, memory leaks ...
I have programmed in Java for a few years now, and I am attempting to learn C++.
I would like some tips about what is wrong with this piece of code specifically, but more importantly, I'd like to know whether I am approaching this question correctly or not.
The task is to return TreeNode *root to a BST, given vector<int>& preorder.
The general idea is clear to me: recursively find left and right bounds, and build the tree using this.
I have tried:
using a helper method that returns a TreeNode * - this caused AddressSanitizer: heap-buffer-overflow errors
converting the helper method to return type void, and passing a TreeNode *ptr as a parameter - this causes runtime error: member access within null pointer of type 'TreeNode' errors
My code:
class Solution {
public:
TreeNode* bstFromPreorder(vector<int>& preorder) {
TreeNode* root = new TreeNode();
constructSubtree(preorder, root, 0, preorder.size());
return root;
}
private:
void constructSubtree(vector<int>& preorder, TreeNode* ptr, int start, int end) {
if(start == -1 || start >= end) {
return;
}
ptr->val = preorder[start];
int split = -1; // first idx where preorder[idx] > preorder[start]
for(int i = start + 1; i < end; ++i) {
if(preorder[i] > preorder[start]) {
split = i;
break;
}
}
constructSubtree(preorder, ptr->left, start + 1, split);
constructSubtree(preorder, ptr->right, split, end);
}
};
some example input: [8,5,1,7,10,12]
Can someone explain what I'm doing wrong?
As I said, I am still learning C++, and I would also really like to hear general tips about working with pointers (and who is responsible for freeing their content).
ptr of constructSubtree() should be allocated before call, because it's not allocated in the function. so you should allocate ptr->left and ptr->right before call the function constructSubtree() recursively.
below is working code(though not so neat)
class TreeNode
{
public:
TreeNode() { val = 0; left = nullptr; right = nullptr; }
int val;
TreeNode *left;
TreeNode *right;
void print()
{
if(left != nullptr)
left->print();
std::cout << val << std::endl;
if(right != nullptr)
right->print();
}
void remove()
{
if(left != nullptr)
left->remove();
if(right != nullptr)
right->remove();
}
};
class Solution {
public:
TreeNode* bstFromPreorder(std::vector<int>& preorder) {
constructSubtree(preorder, &root, 0, preorder.size());
return root;
}
private:
TreeNode *root;
void constructSubtree(std::vector<int>& preorder, TreeNode** ptr, int start, int end) {
if(start == -1 || start >= end) {
return;
}
*ptr = new TreeNode();
(*ptr)->val = preorder[start];
int split = -1; // first idx where preorder[idx] > preorder[start]
for(int i = start + 1; i < end; ++i) {
if(preorder[i] > preorder[start]) {
split = i;
break;
}
}
if(split != -1)
{
constructSubtree(preorder, &((*ptr)->left), start + 1, split);
constructSubtree(preorder, &((*ptr)->right), split, end);
}
}
};
I have spent some time recently designing an iterator for the AVL Tree (right now it just has the inserting mechanics though; haven't implemented tree balancing).
I wanted to test out the iterator, so I checked how to make it online and settled on making it by having a stack holding the tree nodes (e.g. in normal iteration stack would contain all nodes left of this->top node).
This is how the iteration is supposed to work:
for (auto it = tree.iterator(); it.hasNext(); it.next())
{
// process
}
However, VS changes (disables) my Iterator(const Iterator& it) and Iterator(Iterator&& it) constructors and then the iteration fails because the stack is always empty.
After setting Iterator() = delete;, I run into the issue of stack having an unusually large size with invisible parameters.
If extra information is needed, feel free to ask. I think that it's best if I just paste the relevant code because I do not understand this behaviour and do not know what details I should say:
avlTree<Key, Info>::iterator:
class Iterator
{
private:
std::vector<Node*> stack;
bool reverse;
Node* ptr;
std::vector<Node*> makeStack(Node* start, long height)
{
std::vector<Node*> newStack;
newStack.reserve(height);
while (start != nullptr)
{
newStack.push_back(start);
if (reverse)
start = start->right;
else
start = start->left;
}
return newStack;
}
Iterator(Node* start, long height, bool reverse = false) : reverse(reverse), ptr(nullptr)
{
stack = makeStack(start, height);
}
friend class avlTree;
public:
Iterator(Iterator&& iterator)
{
stack = move(iterator.stack);
ptr = nullptr;
}
Iterator(const Iterator& iterator)
{
stack = iterator.stack;
ptr = nullptr;
}
//Iterator() = delete;
bool hasNext()
{
return stack.size() > 0;
}
void next()
{
if (!stack.size()) throw "Empty iterator stack";
if (ptr == stack[stack.size() - 1])
{
stack.pop_back();
if (reverse) // fill the stack with the subsequent nodes (reverse or normal direction)
{
Node* start = ptr->left;
while (start != nullptr)
{
stack.push_back(start);
start = start->right;
}
}
else
{
Node* start = ptr->right;
while (start != nullptr)
{
stack.push_back(start);
start = start->left;
}
}
}
if (stack.size() > 0)
ptr = stack[stack.size() - 1];
}
const Key& getKey()
{
if (!ptr) throw "ptr is nullptr";
else return ptr->key;
}
Info& getInfo()
{
if (!ptr) throw "ptr is nullptr";
else return ptr->info;
}
};
main:
avlTree<char, int> tester;
for (char i = 'g'; i <= 'z'; ++i)
tester.insert(i);
for (char i = 'a'; i < 'g'; ++i)
tester.insert(i);
for (auto it = tester.iterator(); it.hasNext(); it.next())
{
std::cout << it.getKey() << " ";
}
Screenshot of the code & message I get while debugging: http://prntscr.com/qi79zd
How do I fix the issue and make the iteration work?
EDIT:
Complete code:
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <fstream>
#include <chrono>
#include <iterator>
#include <functional>
//#include <ctime>
template<typename T>
void swap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
template<typename Key, typename Info>
class avlTree
{
private:
struct Node
{
const Key key;
Info info;
Node* left;
Node* right;
long leftHeight, rightHeight;
Node(const Key& key, Info&& info = Info(), Node* left = nullptr, Node* right = nullptr)
: key(key), info(info), left(left), right(right), leftHeight(1), rightHeight(1) {}
Node& operator()(Node* nleft, Node* nright)
{
left = nleft;
right = nright;
return *this;
}
Node& operator()(long left, long right)
{
leftHeight = left;
rightHeight = right;
}
};
Node* top;
long length;
public:
class Iterator
{
private:
std::vector<Node*> stack;
bool reverse;
Node* ptr;
std::vector<Node*> makeStack(Node* start, long height)
{
std::vector<Node*> newStack;
newStack.reserve(height);
while (start != nullptr)
{
newStack.push_back(start);
if (reverse)
start = start->right;
else
start = start->left;
}
return newStack;
}
Iterator(Node* start, long height, bool reverse = false) : reverse(reverse), ptr(nullptr)
{
stack = makeStack(start, height);
}
friend class avlTree;
public:
Iterator(Iterator&& iterator)
{
stack = move(iterator.stack);
ptr = nullptr;
}
Iterator(const Iterator& iterator)
{
stack = iterator.stack;
ptr = nullptr;
}
bool hasNext()
{
return stack.size() > 0;
}
void next()
{
if (!stack.size()) throw "Empty iterator stack";
//stack.insert(stack.end(), vector.begin(), vector.end());
if (ptr == stack[stack.size() - 1])
{
stack.pop_back();
if (reverse)
{
Node* start = ptr->left;
while (start != nullptr)
{
stack.push_back(start);
start = start->right;
}
}
else
{
Node* start = ptr->right;
while (start != nullptr)
{
stack.push_back(start);
start = start->left;
}
}
}
if (stack.size() > 0)
ptr = stack[stack.size() - 1];
}
const Key& getKey()
{
if (!ptr) throw "ptr is nullptr";
else return ptr->key;
}
Info& getInfo()
{
if (!ptr) throw "ptr is nullptr";
else return ptr->info;
}
};
avlTree()
{
this->top = nullptr;
this->length = 0;
}
~avlTree()
{
recursiveDelete(top);
length = 0;
}
void printAsc()
{
for (auto it = iterator(); it.hasNext(); it.next())
{
std::cout << it.getKey() << " " << it.getInfo() << "\n";
}
}
void printDesc()
{
recDesc(top);
}
void printTop()
{
if (top) // != nullptr
{
std::cout << ".." << top->key << std::endl;
if (top->left)
std::cout << "." << top->left->key << "..";
else std::cout << ".0..";
if (top->right)
std::cout << top->right->key << std::endl;
else std::cout << "0" << std::endl;
}
}
void insert(const Key& key);
long height()
{
return !top ? 0 : top->leftHeight > top->rightHeight ? top->leftHeight : top->rightHeight;
}
private:
void recDesc(Node* parent);
void recursiveDelete(Node* parent);
void insertRecursive(Node* parent, const Key& key, int& depth);
// void rightRotation(Node* top, Node* parent = nullptr);
public:
Iterator iterator()
{
return Iterator(top, height());
}
};
std::vector<std::string> readFile(bool toDarwin = true);
/****************************************************************************/
int main()
{
// auto start = std::chrono::system_clock::now();
avlTree<std::string, int> counter;
avlTree<char, int> tester;
for (char i = 'g'; i <= 'z'; ++i)
tester.insert(i);
for (char i = 'a'; i < 'g'; ++i)
tester.insert(i);
for (auto it = tester.iterator(); it.hasNext(); it.next())
{
std::cout << it.getKey() << " ";
}
return 0;
}
/****************************************************************************/
template<typename Key, typename Info>
void avlTree<Key, Info>::recDesc(Node* parent)
{
if (parent->left != nullptr)
recAsc(parent->left);
std::cout << parent->key;
if (parent->right != nullptr)
recAsc(parent->left);
}
template<typename Key, typename Info>
void avlTree<Key, Info>::recursiveDelete(Node* parent)
{
if (!parent) return;
if (parent->left != nullptr)
recursiveDelete(parent->left);
if (parent->right != nullptr)
recursiveDelete(parent->right);
delete parent;
}
template<typename Key, typename Info>
void avlTree<Key, Info>::insertRecursive(Node* parent, const Key& key, int& depth)
{
if (parent->key == key)
++(parent->info);
else if (parent->key > key)
{
if (parent->left == nullptr)
{
parent->left = new Node(key);
++(parent->left->info);
++length;
depth = 1;
// (* parent->left)(depth, depth)
}
else
{
insertRecursive(parent->left, key, depth);
++depth;
parent->leftHeight = depth;
}
}
else if (parent->key < key)
{
if (parent->right == nullptr)
{
parent->right = new Node(key);
++(parent->right->info);
++length;
depth = 1;
// (* parent->right)(depth, depth)
}
else
{
insertRecursive(parent->right, key, depth);
++depth;
parent->rightHeight = depth;
}
}
}
template<typename Key, typename Info>
void avlTree<Key, Info>::insert(const Key& key)
{
int depth = 0;
if (!top)
{
top = new Node(key);
// (*top)(1, 1)
++length;
++(top->info);
}
else
{
insertRecursive(top, key, depth);
++depth;
top->key > key ? ++(top->leftHeight) : top->key < key ? ++(top->rightHeight) : NULL;
}
}
/* Irrelevant to the problem
std::vector<std::string> readFile(bool toDarwin)
{
// shrink_to_fit()
std::ifstream file;
std::string word;
std::vector<std::string> words;
words.reserve(1000000);
if (toDarwin == 1)
file.open("OnTheOriginOfSpecies.txt");
else
file.open("The_bible.txt");
while (file >> word)
{
words.push_back(word);
}
words.shrink_to_fit();
return words;
}
*/
I believe the problem is that you are not aware of RVO - return value optimization. Most compilers do so and in fact it is mandatory in C++17. What's RVO?
class A;
A func()
{
A a_infunc = {};
return a_infunc;
}
//use
A a_outsidefunc = func();
In this simple example at no point A::A(const A&) or A::A(A&&) is called. a_infunc is exactly the same variable as a_outsidefunc.
So in the for-loop:
for (auto it = tree.iterator(); it.hasNext(); it.next())
{
// process
}
There will be no calls to Iterator(const Iterator& it) or Iterator(Iterator&& it) due to RVO.