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 ()
Related
Hey I have this template of BinarySearchTreeNode in which i have to implement the following methods
Constructors
Destructor
Empty
leaf
Height
insert
i am done with the constructors and the insert part but i am facing issues with the destructor and the height functions please help me implement these methods
Special care is required for the implementation of method height(). The empty tree has no
height, hence height() must throw a domain_error exception in this case. For interior
nodes, however, if a subtree of a given BinaryTreeNode is empty, then this subtree
contributes a height of zero to the interior node. In other words, the smallest height of any
non-empty BinaryTreeNode is zero. Remember, interior nodes add one to the maximum
height of their subtrees.
Help me with these methods i am super new to DSA and c++ any help is greatly appreciated
#pragma once
#include <stdexcept>
#include <algorithm>
template <typename T>
struct BinaryTreeNode
{
using BNode = BinaryTreeNode<T>;
using BTreeNode = BNode *;
T key;
BTreeNode left;
BTreeNode right;
static BinaryTreeNode<T> NIL;
const T &findMax() const
{
if (empty())
{
throw std::domain_error("Empty tree encountered.");
}
return right->empty() ? key : right->findMax();
}
const T &findMin() const
{
if (empty())
{
throw std::domain_error("Empty tree encountered.");
}
return left->empty() ? key : left->findMin();
}
bool remove(const T &aKey, BTreeNode aParent)
{
BTreeNode x = this;
BTreeNode y = aParent;
while (!x->empty())
{
if (aKey == x->key)
{
break;
}
y = x; // new parent
x = aKey < x->key ? x->left : x->right;
}
if (x->empty())
{
return false; // delete failed
}
if (!x->left->empty())
{
const T &lKey = x->left->findMax(); // find max to left
x->key = lKey;
x->left->remove(lKey, x);
}
else
{
if (!x->right->empty())
{
const T &lKey = x->right->findMin(); // find min to right
x->key = lKey;
x->right->remove(lKey, x);
}
else
{
if (y != &NIL) // y can be NIL
{
if (y->left == x)
{
y->left = &NIL;
}
else
{
y->right = &NIL;
}
}
delete x; // free deleted node
}
}
return true;
}
// Implement theses
BinaryTreeNode() : key(T()), left(&NIL), right(&NIL)
{
}
BinaryTreeNode(const T &aKey) : key(aKey), left(&NIL), right(&NIL)
{
}
BinaryTreeNode(T &&aKey) : key(std::move(aKey)), left(&NIL), right(&NIL)
{
}
~BinaryTreeNode()
{
}
bool empty() const
{
return this == &NIL;
}
bool leaf() const
{
return left == &NIL && right == &NIL;
}
size_t height() const
{
}
bool insert(const T &aKey)
{
if (aKey == key || empty())
return false;
if (aKey < key)
{
if (!left->empty())
return left->insert(aKey);
left = new BinaryTreeNode(aKey);
}
else
{
if (!right->empty())
return right->insert(aKey);
right = new BinaryTreeNode(aKey);
}
return true;
}
};
template <typename T>
BinaryTreeNode<T> BinaryTreeNode<T>::NIL;
I am writing some code on Splay Tree nodes. Without being too technical, I want to implement one base tree and one derived tree that supports reversion of the left and right sub-trees. The current excerpt looks like this:
struct node {
node *f, *c[2];
int size;
void push_down() {}
};
struct reversable_node : node {
int r;
void push_down() {
if (r) {
std::swap(c[0], c[1]);
c[0]->r ^= 1, c[1]->r ^= 1, r = 0;
}
}
};
This obviously does not work, because c[0] are of type node and does not have member r. Still, I know that c[0] of node only points to node and c[0] of reversable_node only points to reversable_node. So I can do some cast:
((reversable_node *)c[0])->r ^= 1, ((reversable_node *)c[1])->r ^= 1, r = 0;
But this looks super clumsy. Is there a better way to do a self-reference pointer in the base class that also works in derived classes?
P.S. The whole code looks like this:
struct node {
node *f, *c[2];
int size;
node() {
f = c[0] = c[1] = nullptr;
size = 1;
}
void push_down() {}
void update() {
size = 1;
for (int t = 0; t < 2; ++t)
if (c[t]) size += c[t]->size;
}
};
struct reversable_node : node {
int r;
reversable_node() : node() { r = 0; }
void push_down() {
if (r) {
std::swap(c[0], c[1]);
((reversable_node *)c[0])->r ^= 1, ((reversable_node *)c[1])->r ^= 1, r = 0;
}
}
};
template <typename T = node, int MAXSIZE = 500000>
struct tree {
T pool[MAXSIZE + 2];
node *root;
int size;
tree() {
size = 2;
root = pool[0], root->c[1] = pool[1], root->size = 2;
pool[1]->f = root;
}
void rotate(T *n) {
int v = n->f->c[0] == n;
node *p = n->f, *m = n->c[v];
p->push_down(), n->push_down();
n->c[v] = p, p->f = n, p->c[v ^ 1] = m;
if (m) m->f = p;
p->update(), n->update();
}
void splay(T *n, T *s = nullptr) {
while (n->f != s) {
T *m = n->f, *l = m->f;
if (l == s)
rotate(n);
else if ((l->c[0] == m) == (m->c[0] == n))
rotate(m), rotate(n);
else
rotate(n), rotate(n);
}
if (!s) root = n;
}
node *new_node() { return pool[size++]; }
void walk(node *n, int &v, int &pos) {
n->push_down();
int s = n->c[0] ? n->c[0]->size : 0;
(v = s > pos) && (pos -= s + 1);
}
void add_node(node *n, int pos) {
node *c = root;
int v;
++pos;
do {
walk(c, v, pos);
} while (c->c[v] && (c = c->c[v]));
c->c[v] = n, n->f = cur, splay(n);
}
node *find(int pos, int splay = true) {
node *c = root;
int v;
++pos;
do {
walk(c, v, pos);
} while (pos && (c = c->c[v]));
if (splay) splay(c);
return c;
}
node *find_range(int posl, int posr) {
node *l = find(posl - 1), *r = find(posr, false);
splay(r, l);
if (r->c[0]) r->c[0]->push_down();
return r->c[0];
}
};
So basically we have a flag of whether a node is reversed, and when we try to rotate the tree, we push down the flag from the node to its children. This may require some understanding of the Splay Tree.
P.S.2 It is supposed to be a library, but some use cases would be like this:
#include "../template.h"
splay::tree<splay::reversable_node> s;
void dfs(splay::reversable_node *n) {
if (n) {
// Push down the flag.
n->push_down();
dfs(n->c[0]);
// Do something about n...
dfs(n->c[1]);
}
}
int main() {
// Insert 5 nodes to the Splay Tree.
for (int i = 0; i < 5; ++i) s.add_node(s.new_node(), 0);
// Find a range of the tree.
splay::reversable_node *n = s.find_range(0, 3);
// Reverse it.
n->r = 1;
std::swap(n->c[0], n->c[1]);
// Traverse it in inorder.
dfs(s.root);
}
Anyway thanks to CRTP I got it to work.
namespace splay {
/**
* Abstract node struct.
*/
template <typename T>
struct node {
T *f, *c[2];
int size;
node() {
f = c[0] = c[1] = nullptr;
size = 1;
}
void push_down() {}
void update() {
size = 1;
for (int t = 0; t < 2; ++t)
if (c[t]) size += c[t]->size;
}
};
/**
* Abstract reversible node struct.
*/
template <typename T>
struct reversible_node : node<T> {
int r;
reversible_node() : node<T>() { r = 0; }
void push_down() {
node<T>::push_down();
if (r) {
for (int t = 0; t < 2; ++t)
if (node<T>::c[t]) node<T>::c[t]->reverse();
r = 0;
}
}
void update() { node<T>::update(); }
/**
* Reverse the range of this node.
*/
void reverse() {
std::swap(node<T>::c[0], node<T>::c[1]);
r = r ^ 1;
}
};
template <typename T, int MAXSIZE = 500000>
struct tree {
T pool[MAXSIZE + 2];
T *root;
int size;
tree() {
size = 2;
root = pool, root->c[1] = pool + 1, root->size = 2;
pool[1].f = root;
}
/**
* Helper function to rotate node.
*/
void rotate(T *n) {
int v = n->f->c[0] == n;
T *p = n->f, *m = n->c[v];
if (p->f) p->f->c[p->f->c[1] == p] = n;
n->f = p->f, n->c[v] = p;
p->f = n, p->c[v ^ 1] = m;
if (m) m->f = p;
p->update(), n->update();
}
/**
* Splay n so that it is under s (or to root if s is null).
*/
void splay(T *n, T *s = nullptr) {
while (n->f != s) {
T *m = n->f, *l = m->f;
if (l == s)
rotate(n);
else if ((l->c[0] == m) == (m->c[0] == n))
rotate(m), rotate(n);
else
rotate(n), rotate(n);
}
if (!s) root = n;
}
/**
* Get a new node from the pool.
*/
T *new_node() { return pool + size++; }
/**
* Helper function to walk down the tree.
*/
int walk(T *n, int &v, int &pos) {
n->push_down();
int s = n->c[0] ? n->c[0]->size : 0;
(v = s < pos) && (pos -= s + 1);
return s;
}
/**
* Insert node n to position pos.
*/
void insert(T *n, int pos) {
T *c = root;
int v;
++pos;
while (walk(c, v, pos), c->c[v] && (c = c->c[v]))
;
c->c[v] = n, n->f = c, splay(n);
}
/**
* Find the node at position pos. If sp is true, splay it.
*/
T *find(int pos, int sp = true) {
T *c = root;
int v;
++pos;
while ((pos < walk(c, v, pos) || v) && (c = c->c[v]))
;
if (sp) splay(c);
return c;
}
/**
* Find the range [posl, posr) on the splay tree.
*/
T *find_range(int posl, int posr) {
T *l = find(posl - 1), *r = find(posr, false);
splay(r, l);
if (r->c[0]) r->c[0]->push_down();
return r->c[0];
}
};
} // namespace splay
Some use case:
struct node : splay::reversible_node<node> {
int val;
void push_down() { splay::reversible_node<node>::push_down(); }
void update() { splay::reversible_node<node>::update(); }
};
splay::tree<node> t;
int N, M;
void inorder(node *n) {
static int f = 0;
if (!n) return;
n->push_down();
inorder(n->c[0]);
if (n->val) {
if (f) printf(" ");
f = 1;
printf("%d", n->val);
}
inorder(n->c[1]);
}
int main() {
scanf("%d%d", &N, &M);
for (int i = 0; i < N; ++i) {
node *n = t.new_node();
n->val = i + 1;
t.insert(n, i);
}
for (int i = 0, u, v; i < M; ++i) {
scanf("%d%d", &u, &v);
node *n = t.find_range(u - 1, v);
n->reverse();
}
inorder(t.root);
}
Hopefully this allows me to write Splay faster in CP.
I am currently writing a program to mimic the functions of a linked list. I think the the code is crashing due to memory leaks, but I cannot figure out where they might be. I have tried deleting after every new, but when I delete it causes the functions to not operate correctly. I also think I my push_back() function may not be operating correctly, because my output does not match the output of std::list. Any help would be greatly appreciated. Thanks!
When I run the program this is the output I receive:
4000
33
100
3
33
100
423
423
100
33
200
100
4000
double free or corruption (fasttop)
Aborted (core dumped)
This is the output I am expecting:
4000
33
100
3
33
100
423
423
100
423
33
200
100
Header File:
#ifndef MYLIST_H
#define MYLIST_H
#include <iostream>
using std::cout;
using std::endl;
using std::cin;
using std::cerr;
using std::string;
template <typename T>
class Node
{
public:
T m_element;
Node<T> *m_prev;
Node<T> *m_next;
// Helps you make a dummy/sentinel/junk node
Node(Node<T> *in_prev, Node<T> *in_next):
m_prev(in_prev), m_next(in_next){}
Node(const T &x, Node<T> *in_prev, Node<T> *in_next):
m_element(x), m_prev(in_prev), m_next(in_next){}
};
template <typename T>
class MyList
{
private:
Node<T> *m_sentinel = nullptr;
int m_size;
public:
// A list size of 0 will have 1 sentinel node.
MyList();
~MyList();
MyList<T> & operator=(const MyList<T> &source);
MyList(const MyList<T> &source);
T & front();
T & back();
void assign(int count, const T &value);
// Default list size of 0, with one sentinel node, as above in constructor
void clear();
void push_front(const T &x);
void push_back(const T &x);
void pop_back();
void pop_front();
// Simplified version that only takes one int position.
// Inserts before element at position i.
// Not exactly like std::
// You do NOT need a special case for 0-big lists (i.e., no if size == 0)
// You should be able to insert in 0 big list.
void insert(int i, const T &x);
// Removes all elements in list that are equal to value.
// You do NOT need a special case for 0-big lists (i.e., no if size == 0).
void remove(T value);
// Removes element at position i.
void erase(int i);
void reverse();
bool empty();
int size();
// Mimicking C++ iterator trickery from here down.
// You don't need to edit these two.
int begin()
{
return 0;
}
int end()
{
return size();
}
};
#include "MyList.hpp"
#endif
HPP File:
template <typename T>
MyList<T>::MyList()
{
m_sentinel = new Node<T>(nullptr, nullptr);
m_sentinel->m_next = m_sentinel;
m_sentinel->m_prev = m_sentinel;
m_size = 0;
}
template <typename T>
MyList<T>::~MyList()
{
Node<T> *temp;
for(int i = 0; i < m_size; i++)
{
temp = m_sentinel->m_prev;
delete m_sentinel->m_prev;
m_sentinel->m_prev = temp->m_prev;
}
delete m_sentinel;
m_sentinel = nullptr;
}
template <typename T>
MyList<T> & MyList<T>::operator=(const MyList<T> &source)
{
this->~MyList();
Node<T>* tempNode = new Node<T>(nullptr, nullptr);
tempNode = source.m_sentinel->m_next;
m_sentinel = new Node<T>(nullptr, nullptr);
m_sentinel->m_next = m_sentinel;
m_sentinel->m_prev = m_sentinel;
for(int i = 0; i < source.m_size; i++)
{
this->push_back(tempNode->m_element);
tempNode = tempNode->m_next;
}
}
template <typename T>
MyList<T>::MyList(const MyList<T> &source)
{
*this = source;
}
template <typename T>
T & MyList<T>::front()
{
return m_sentinel->m_next->m_element;
}
template <typename T>
T & MyList<T>::back()
{
return m_sentinel->m_prev->m_element;
}
template <typename T>
void MyList<T>::assign(int count, const T &value)
{
while(m_size)
{
this->pop_back();
}
for(int i = 0; i < count; i++)
{
this->push_back(value);
}
m_size = count;
}
// Default list size of 0, with one sentinel node, as above in constructor
template <typename T>
void MyList<T>::clear()
{
while(m_size)
{
this->pop_back();
}
}
template <typename T>
void MyList<T>::push_front(const T &x)
{
Node<T> *tempNode = new Node<T>(x, m_sentinel, m_sentinel->m_next);
m_sentinel->m_next->m_prev = tempNode;
m_sentinel->m_next = tempNode;
m_size++;
}
template <typename T>
void MyList<T>::push_back(const T &x)
{
Node<T> *tempNode = new Node<T>(x, m_sentinel->m_prev, m_sentinel);
m_sentinel->m_prev = tempNode;
tempNode->m_prev->m_next = tempNode;
m_size++;
}
template <typename T>
void MyList<T>::pop_back()
{
//edit
if(m_size != 0)
{
//check if temp node is needed
//Node<T> *tempNode = m_sentinel->m_prev;
m_sentinel->m_prev = m_sentinel->m_prev->m_prev;
delete m_sentinel->m_prev->m_next;
m_sentinel->m_prev->m_next = nullptr;
m_sentinel->m_prev->m_next = m_sentinel;
//delete tempNode;
m_size--;
}
}
template <typename T>
void MyList<T>::pop_front()
{
if(m_size != 0)
{
m_size--;
m_sentinel->m_next = m_sentinel->m_next->m_next;
delete m_sentinel->m_next->m_prev;
m_sentinel->m_next->m_prev = nullptr;
m_sentinel->m_next->m_prev = m_sentinel;
}
}
// Simplified version that only takes one int position.
// Inserts before element at position i.
// Not exactly like std::
// You do NOT need a special case for 0-big lists (i.e., no if size == 0)
// You should be able to insert in 0 big list.
template <typename T>
void MyList<T>::insert(int i, const T &x)
{
if(i >= 0 && i < m_size)
{
Node<T> *tempNode = m_sentinel;
for(int j = 0; j < i; j++)
{
tempNode = tempNode->m_next;
}
Node<T> *insertNode = new Node<T>(x, tempNode, tempNode->m_next);
tempNode->m_prev->m_next = insertNode;
tempNode->m_next->m_prev = insertNode;
m_size++;
}
}
// Removes all elements in list that are equal to value.
// You do NOT need a special case for 0-big lists (i.e., no if size == 0).
template <typename T>
void MyList<T>::remove(T value)
{
Node<T> *currentNode = m_sentinel->m_next;
Node<T> *tempNode = currentNode->m_next;
int counter = m_size;
for(int i = 0; i < counter; i++)
{
if(currentNode->m_element == value)
{
currentNode->m_prev->m_next = currentNode->m_next;
currentNode->m_next->m_prev = currentNode->m_prev;
tempNode = currentNode->m_next;
m_size--;
delete currentNode;
currentNode = nullptr;
currentNode = tempNode;
}
else
{
currentNode = currentNode->m_next;
}
}
}
// Removes element at position i.
template <typename T>
void MyList<T>::erase(int i)
{
if(i >= 0 && i < m_size)
{
Node<T> *currentNode = m_sentinel->m_next;
for(int j = 0; j < i; j++)
{
currentNode = currentNode->m_next;
}
currentNode->m_prev->m_next = currentNode->m_next;
currentNode->m_next->m_prev = currentNode ->m_prev;
delete currentNode;
currentNode = nullptr;
m_size--;
}
}
template <typename T>
void MyList<T>::reverse()
{
Node<T> *nextNode = m_sentinel->m_next;
Node<T> *prevNode = m_sentinel->m_prev;
for(int i = 0; i < (m_size/2); i++)
{
std::swap(nextNode->m_element, prevNode->m_element);
nextNode = nextNode->m_next;
prevNode = prevNode->m_prev;
}
}
template <typename T>
bool MyList<T>::empty()
{
if(m_size==0)
{
return true;
}
else
{
return false;
}
}
template <typename T>
int MyList<T>::size()
{
return m_size;
}
Driver to test if MyList function works like std::list:
#include <list>
#include "MyList.h"
int main()
{
MyList<int> l;
//std::list<int> l;
l.push_back(4000);
l.push_back(200);
l.push_back(100);
cout << l.front() << endl;
l.front() = 33;
cout << l.front() << endl;
cout << l.back() << endl;
cout << l.size() << endl;
l.push_back(4000);
l.push_back(200);
l.push_back(100);
cout << l.front() << endl;
cout << l.back() << endl;
l.push_front(423);
cout << l.front() << endl;
MyList<int> sink;
sink = l;
cout << sink.front() << endl;
cout << sink.back() << endl;
l.insert(l.begin(), 3);
l.insert(l.end(), 20);
l.pop_front();
l.reverse();
int j = 0;
for(auto i = 0; i < l.size(); i++)
{
cout << l.back() << endl;
l.pop_back();
j++;
}
return 0;
}
Thanks!
UPDATED COPY CONSTRUCTOR AND ASSIGNMENT OPERATOR
template <typename T>
MyList<T> & MyList<T>::operator=(const MyList<T> &source)
{
MyList<T> temp(source);
std::swap(temp.m_sentinel, m_sentinel);
return *this;
}
template <typename T>
MyList<T>::MyList(const MyList<T> &source)
{
Node<T> *temp = source.m_sentinel;
m_sentinel = nullptr;
while(temp != nullptr)
{
push_back(temp->m_element);
}
}
Now it gives me a segfault and crashes when calling the push_back() function. I'm lost. I've tried implementing this several different ways but every time I either get a double free or a segfault.
this is my current avltree implementation, avltree.h:
#pragma once
#include <math.h>
#include <algorithm>
#include <iostream>
namespace avltree {
template <class T>
struct node {
static node * null_node;
node *left = null_node;
node *right = null_node;
node *parent = null_node;
int height = 0;
T value;
node(T value) :value(value) {}
node(T value, int height) :height(height), value(value) {}
};
template <class T>
node<T>* node<T>::null_node = new node(0, -1);
template <class T>
struct avltree {
public:
node<T> *root;
avltree(T value);
node<T> *insert(T value);
void print(void);
void print_with_height(void);
private:
node<T> *insert(T value, node<T> *x);
node<T> *left_rotate(node<T> *x);
node<T> *right_rotate(node<T> *x);
void retrace(node<T> *n);
void update_root();
void print(node<T> *n);
void print(node<T> *n, int depth);
void update_height(node<T> *n);
};
template <class T>
avltree<T>::avltree(T value) :root(new node<T>(value)) { }
template <class T>
node<T> *avltree<T>::insert(T value) {
auto n = insert(value, root);
update_root();
return n;
}
template <class T>
void avltree<T>::retrace(node<T> *n) {
while (n != node<T>::null_node) {
update_height(n);
if (n->left->height - n->right->height > 1) {
if (n->left->left->height >= n->left->right->height) {
right_rotate(n);
}
else {
left_rotate(n);
right_rotate(n);
}
}
else
if (n->right->height - n->left->height > 1) {
if (n->right->right->height >= n->right->left->height) {
left_rotate(n);
}
else {
right_rotate(n);
left_rotate(n);
}
}
n = n->parent;
}
}
template <class T>
node<T> *avltree<T>::insert(T value, node<T> *n) {
if (n->value > value) {
if (n->left != node<T>::null_node) {
n->left->height++;
insert(value, n->left);
}
else {
auto new_node = new node<T>(value);
n->left = new_node;
new_node->parent = n;
retrace(n);
return new_node;
}
}
if (n->value < value) {
if (n->right != node<T>::null_node) {
n->right->height++;
insert(value, n->right);
}
else {
auto new_node = new node<T>(value);
n->right = new_node;
new_node->parent = n;
retrace(n);
return new_node;
}
}
update_height(n);
return n;
}
template <class T>
node<T> *avltree<T>::left_rotate(node<T> *x) {
node<T> *y = x->right;
if (y == node<T>::null_node) {
return node<T>::null_node;
}
y->parent = x->parent;
if (x->parent->right == x) {
x->parent->right = y;
}
else {
x->parent->left = y;
}
y->left = x;
x->parent = y;
x->right = y->left;
x->right->parent = x;
update_height(x);
update_height(y);
return x;
}
template <class T>
node<T> *avltree<T>::right_rotate(node<T> *x) {
node<T> *y = x->left;
if (y == node<T>::null_node) {
return node<T>::null_node;
}
y->parent = x->parent;
if (x->parent->right == x) {
x->parent->right = y;
}
else {
x->parent->left = y;
}
y->right = x;
x->parent = y;
x->left = y->right;
x->left->parent = x;
update_height(x);
update_height(y);
return x;
}
template <class T>
void avltree<T>::update_root() {
auto n = root, last = root;
while (n != node<T>::null_node) {
last = n;
n = n->parent;
}
root = last;
}
template <class T>
void avltree<T>::print(void) {
print(root);
cout << endl;
}
template <class T>
void avltree<T>::print(node<T> *n) {
if (n->left != node<T>::null_node) {
print(n->left);
}
cout << n->value << " ";
if (n->right != node<T>::null_node) {
print(n->right);
}
}
template <class T>
void avltree<T>::print(node<T> *n, int height) {
if (n->left != node<T>::null_node) {
print(n->left, height);
}
if (n->height == height) {
std::cout << n->value << ", ";
}
if (n->right != node<T>::null_node) {
print(n->right, height);
}
}
template <class T>
void avltree<T>::print_with_height(void) {
int height = root->height;
for (int height = root->height; height >= 0; height--) {
std::cout << "height = " << height << "\t:";
print(root, height);
std::cout << std::endl;
}
std::cout << std::endl;
}
template <class T>
void avltree<T>::update_height(node<T> *n) {
n->height = std::max(n->left->height, n->right->height) + 1;
}
}
And the following is main file:
#include "stdafx.h"
#include "avltree.h"
int main()
{
avltree::avltree<int> tree(1);
for (int i = 2; i < 128; i++) {
tree.insert(i);
}
tree.print_with_height();
return 0;
}
The problem with above code is that at iteration 124 it will generate an infinite loop inside retrace call in insert. Basically, the nodes will keep being rotated in such a way that root node cannot be reached (resulting in an infinite loop). I have checked the trivial examples (for a few nodes) and they work. Everything for a run is provided, I would appreciate if someone with experience in avltrees could take their time and run this program, perhaps finding out what goes wrong inside retrace/rotations.
Getting an infinite loop like that indicates a likely problem with your rotate functions. A quick look at left_rotate shows
y->left = x;
x->parent = y;
x->right = y->left;
What is y->left in that last assignment? x, so what you're really is x->right = x. This is clearly a problem that needs to be fixed.
A similar problem exists in right_rotate.
I wrote a Class called cube which holds a double linked list which should hold objects of a abstract class called Animation and has a method to add animations . It looks liket his:
class CubeLib
{
protected:
//some more variables
LinkedList<Animation*> animations; //a list of animations
public:
inline void addAnimation(Animation* a){
animations.add(a);
};
}
The interface:
class Animation
{
public:
virtual void update(short delta) = 0;
};
Inside of the ino of the arduino project i init the CubeLib and the Animation in global and inside of the setup i add them to the list:
CubeLib cube;
Sinus* sinus_ani =new Sinus(&cube); // if not like this it stucks at setup?!
void setup()
{
cube.addAnimation(sinus_ani);
}
Inside of a method called render i call the current Animations update function.
inline void CubeLib::update(short delta)
{
if (animations.size() != -1){ //if its not empty
animations[current_Animation]->update(delta);
}
}
But in this case it does happen nothing. The update of the Sinus does not get called.
Last but not least here is my double linked list. (I tested it but maybe there is some issue with it?)
template <typename T>
class LinkedList
{
protected:
private:
struct Node
{
Node* prev;
Node* next;
T value;
};
Node* last;
Node* first;
byte count;
public:
LinkedList()
{
count = -1; //empty
};
~LinkedList()
{
if (count > -1){
clear();
}
};
/** adds to list*/
inline void add(T t);
/**removes the thing at index*/
inline T remove(int index);
/** Returns NULL(ptr) if index is out of range or item not found somehow*/
inline T get(int index);
inline void clear();
/**Returns the first obj*/
inline T getFirst();
/**Returns the last obj*/
inline T getLast();
/**Returns the current size. If -1 its empty!*/
inline int size(){
return count;
};
T operator[](const int i)
{
return get(i);
};
};
template <typename T>
inline void LinkedList<T>::add(T t){
Node* n = new Node();
n->value = t;
if (count > -1)
{
n->next = first;
n->prev = last;
last->next = n;
last = n;
count++;
}
else if (count == -1)//first element
{
first = n;
first->next = n;
first->prev = n;
last = n;
last->next = n;
last->prev = n;
count++;
}
}
template <typename T>
inline T LinkedList<T>::remove(int index){
if (index <= count)
{
Node* n = last;
for (int i = 0; i <= index; i++)
{
n = n->next;
}
n->prev->next = n->next;
n->next->prev = n->prev;
count--;
return n->value; //return the value of that node
}
}
template <typename T>
inline T LinkedList<T>::get(int index){
if (index <= count && index > -1)
{
Node* n = first;
int i = 0;
while (i < index)
{
n = n->next;
i++;
}
return n->value;
}
return NULL;
}
template <typename T>
inline void LinkedList<T>::clear()
{
Node* n = first;
while (count > 0)
{
Node* toBeDeleted = n;
n = n->next;
delete toBeDeleted;
count--;
}
}
/**Returns the first obj*/
template <typename T>
inline T LinkedList<T>::getFirst()
{
return first->value;
};
/**Returns the last obj*/
template <typename T>
inline T LinkedList<T>::getLast()
{
return last->value;
};
I am sorry for alot of code here. And I hope its not a obvious failer.
Edit:
Sinus is declared liket his:
class Sinus : public Animation
{
private:
RGB color;
CubeLib* cube;
byte colorcounter;
float time;
public:
Sinus(CubeLib* c) : time(0.0), colorcounter(0), cube(c){
color.r = MAX_COLOR;
color.g = MAX_COLOR;
color.b = MAX_COLOR;
};
~Sinus(){};
void update(short delta);
};
void Sinus::update(short delta)
{
//do this 1000 times
time += (((float)delta)/1000.0);
for (int x = 0; x < 5; x++)
{
float value = (2.0*sin((float)(x + 1)*time*12.0)) + 2.0;
for (int y = 0; y < 5; y++)
{
for (int z = 0; z < 5; z++)
{
if (abs(((float)z) - value) < 0.5)
{
//cube.setLED(x, y, z, depth - 30/5*(int)abs(z-value), 0, 0);
cube->setLED(x, y, z, color);
}
else
{
cube->setLED(x, y, z, 0, 0, 0);
}
}
}
}
colorcounter++;
if (colorcounter > 25)
{
color.r = random(MAX_COLOR);
color.g = random(MAX_COLOR);
color.b = random(MAX_COLOR);
colorcounter = 0;
}
}
The error is really really really small and i noticed it just by luck.
I changed the counter of the list to byte to reduce the steps. But if my list is empty it is -1 so this would not work. Thats all! changed the count to short type and it works!
template <typename T>
class LinkedList
{
private:
struct Node
{
Node* prev;
Node* next;
T value;
};
Node* last;
Node* first;
short count; // HERE
/...
};