I'm trying to efficiently construct a binary suffix code for a given set of characters with their probabilities (i.e. a set of words none of which is a suffix of any other).
My basic idea is to construct a prefix-code using an implementation of the Huffman algorithm. By reversing the code words I get a suffix-free code. While this solution is working, it might not seem optimal, because I have to reverse variable-length code words (thus I need a lookup table combined with bit-shifts).
Is there any way to modify the Huffman algorithm in order to create a suffix-code more efficiently?
I would implement the HuffmanNode as
class HuffmanNode implements Comparable<HuffmanNode>
{
// data
private String text;
private double frequency;
// linkage
private HuffmanNode left;
private HuffmanNode right;
private HuffmanNode parent;
public HuffmanNode(String text, double frequency)
{
this.text = text;
this.frequency = frequency;
}
public HuffmanNode(HuffmanNode n0, HuffmanNode n1)
{
if(n0.frequency < n1.frequency)
{
left = n0;
right = n1;
}else if(n0.frequency > n1.frequency)
{
left = n1;
right = n0;
}else
{
if(n0.text.compareTo(n1.text) < 0)
{
left = n0;
right = n1;
}else
{
left = n1;
right = n0;
}
}
left.parent = this;
right.parent = this;
text = left.text + right.text;
frequency = left.frequency + right.frequency;
}
public HuffmanNode getParent() {
return parent;
}
public HuffmanNode getLeft() {
return left;
}
public HuffmanNode getRight() {
return right;
}
public String getText()
{
return text;
}
#Override
public int compareTo(HuffmanNode o) {
if(frequency < o.frequency)
return -1;
else if(frequency > o.frequency)
return 1;
else
return text.compareTo(o.text);
}
public Collection<HuffmanNode> leaves()
{
if(left == null && right == null)
{
Set<HuffmanNode> retval = new HashSet<>();
retval.add(this);
return retval;
}
else if(left == null || right == null)
{
Set<HuffmanNode> retval = new HashSet<>();
if(left != null)
retval.addAll(left.leaves());
if(right != null)
retval.addAll(right.leaves());
retval.add(this);
return retval;
}
else
{
Set<HuffmanNode> retval = new HashSet<>();
retval.addAll(left.leaves());
retval.addAll(right.leaves());
return retval;
}
}
public String toString()
{
return "{" + text + " -> " + frequency + "}";
}
}
This class represents a single node in a Huffman tree.
It has convenience methods for getting all the leaves from a (sub)tree.
You can then easily build the tree:
private Map<String,String> buildTree(String text)
{
List<HuffmanNode> nodes = new ArrayList<>();
for(Map.Entry<String,Double> en : frequency(text).entrySet())
{
nodes.add(new HuffmanNode(en.getKey(), en.getValue()));
}
java.util.Collections.sort(nodes);
while(nodes.size() != 1)
{
HuffmanNode n0 = nodes.get(0);
HuffmanNode n1 = nodes.get(1);
// build merged node
HuffmanNode newNode = new HuffmanNode(nodes.get(0), nodes.get(1));
nodes.remove(n0);
nodes.remove(n1);
// calculate insertion point
int insertionPoint = - java.util.Collections.binarySearch(nodes, newNode) - 1;
// insert
nodes.add(insertionPoint, newNode);
}
// build lookup table
Map<String, String> lookupTable = new HashMap<>();
for(HuffmanNode leaf : nodes.iterator().next().leaves())
{
String code = "";
HuffmanNode tmp = leaf;
while(tmp.getParent() != null)
{
if(tmp.getParent().getLeft() == tmp)
code = "0" + code;
else
code = "1" + code;
tmp = tmp.getParent();
}
lookupTable.put(leaf.getText(), code);
}
return lookupTable;
}
By changing the method that builds the code (for instance pre-pending the next digit rather than appending it) you can change the codes being produced.
I made my Huffman coding tree deploying C++ shown as below:
I created three class for this purpose - HuffmanTree, BinTree and BinNode.
You can see more details on my GitHub:https://github.com/MouChiaHung/DataStructures
Check these three files: bin_node.h, bin_tree.h and huffman_tree.h. They read source file "source", encode to file "encode" in the Huffman way, then decode the file "encode" and store results to output file "decode". Besides, Huffman table is recorded in file "table".
One of core functions is HuffmanTree::encode() which read characters from source file.
template<typename T> void amo::HuffmanTree<T>::grow(std::list<Model*>& list) { //ascendantly sorted list
Model* l;
Model* r;
Model* m;
BinNode<T>* lchild;
BinNode<T>* rchild;
BinNode<T>* vertex;
std::list<Model*>::iterator it = list.begin();
std::vector<BinNode<T>*> subs; //roots of sub-trees
typename std::vector<BinNode<T>*>::iterator it_subs = subs.begin();
int i = 0;
while (it!=list.end()) {
lchild = NULL;
rchild = NULL;
vertex = NULL;
cout << YELLOW << "while-loop:" << ++i << WHITE << endl;
if (std::next(it,1) == list.end()) { //met the last and single leaf or sub-tree
if (subs.size() > 1) {
cout << RED << "size of sub-tree is more than 1:" << subs.size() << WHITE << endl;
this->_root = subs.back();
subs.pop_back();
break;
}
else if (subs.size() == 1){
if (**it == subs.back()->data) { //met the last sub-tree
cout << GREEN << "going to attach the last sub-tree" << WHITE << endl;
vertex = subs.back();
subs.pop_back();
}
else { //met the last leaf
cout << GREEN << "going to attach the last leaf" << WHITE << endl;
r = *it;
lchild = subs.back();
subs.pop_back();
cout << CYAN << "lchild points to the root of the last sub-tree:" << *lchild;
rchild = new BinNode<T>(*r);
cout << CYAN << "rchild points to a new node:" << *rchild;
m = new Model(CHAR_VERTEX, (lchild->data.prob)+(r->prob));
vertex = new BinNode<T>(*m);
lchild->parent = vertex;
rchild->parent = vertex;
vertex->lchild = lchild;
vertex->rchild = rchild;
}
this->_root = vertex;
cout << CYAN << "root:" << *this->_root << WHITE << endl;
break;
}
else {
cout << RED << "size of sub-tree is less than 1:" << subs.size() << WHITE << endl;
this->_root = subs.back();
subs.pop_back();
break;
}
}
else {
l = *it;
it++;
r = *it;
m = new Model(CHAR_VERTEX, l->prob+r->prob);
for (it_subs=subs.begin(); it_subs!=subs.end(); it_subs++) { //set lchild if any sub-tree corresponds with this l model iterated currently
if (*l == (*it_subs)->data) {
cout << CYAN << "lchild points to the root of sub-tree:" << **it_subs;
lchild = *it_subs;
--(it_subs = subs.erase(it_subs));
}
if (lchild != NULL) break; //tricky but important
}
for (it_subs=subs.begin(); it_subs!=subs.end(); it_subs++) { //set rchild if any sub-tree corresponds with this r model iterated currently
if (*r == (*it_subs)->data) {
cout << CYAN << "rchild points to the root of sub-tree:" << **it_subs;
rchild = *it_subs;
--(it_subs = subs.erase(it_subs));
}
if (rchild != NULL) break; //tricky but important
}
if (lchild == NULL) { //set lchild with a new node if no any sub-tree corresponds with this l model iterated currently, which means meeting a row leaf
lchild = new BinNode<T>(*l);
cout << CYAN << "lchild points to a new node:" << *lchild;
}
if (rchild == NULL) { //set rchild with a new node if no any sub-tree corresponds with this r model iterated currently, which means meeting a row leaf
rchild = new BinNode<T>(*r);
cout << CYAN << "rchild points to a new node:" << *rchild;
}
vertex = new BinNode<T>(*m);
std::cout << GREEN << "growing..." << WHITE << endl;
std::cout << CYAN << "lchild" << *lchild << WHITE;
std::cout << CYAN << "rchild" << *rchild << WHITE;
std::cout << CYAN << "vertex" << *vertex << WHITE;
lchild->parent = vertex;
rchild->parent = vertex;
vertex->lchild = lchild;
vertex->rchild = rchild;
subs.push_back(vertex);
for (std::list<Model*>::iterator itt=it;itt!=list.end();itt++) {
if ((*m < **itt) || (*m == **itt)) {
list.insert(itt, m);
break;
}
else if (std::next(itt,1) == list.end()) {
list.push_back(m);
break;
}
}
it++;
}
}
this->updateHeightAll();
cout << GREEN << "-*-*-*-*-*-*-*-* Huffman tree top -*-*-*-*-*-*-*-*" << WHITE << endl;
this->traverseLevel();
cout << GREEN << "-*-*-*-*-*-*-*-* Huffman tree bottom -*-*-*-*-*-*-*-*" << WHITE << endl;
subs.clear();}
Another core function is Huffman::grow() which makes a binary tree for PFC coding.
template<typename T> void amo::HuffmanTree<T>::grow(std::list<Model*>& list) { //ascendantly sorted list
Model* l;
Model* r;
Model* m;
BinNode<T>* lchild;
BinNode<T>* rchild;
BinNode<T>* vertex;
std::list<Model*>::iterator it = list.begin();
std::vector<BinNode<T>*> subs; //roots of sub-trees
typename std::vector<BinNode<T>*>::iterator it_subs = subs.begin();
int i = 0;
while (it!=list.end()) {
lchild = NULL;
rchild = NULL;
vertex = NULL;
cout << YELLOW << "while-loop:" << ++i << WHITE << endl;
if (std::next(it,1) == list.end()) { //met the last and single leaf or sub-tree
if (subs.size() > 1) {
cout << RED << "size of sub-tree is more than 1:" << subs.size() << WHITE << endl;
this->_root = subs.back();
subs.pop_back();
break;
}
else if (subs.size() == 1){
if (**it == subs.back()->data) { //met the last sub-tree
cout << GREEN << "going to attach the last sub-tree" << WHITE << endl;
vertex = subs.back();
subs.pop_back();
}
else { //met the last leaf
cout << GREEN << "going to attach the last leaf" << WHITE << endl;
r = *it;
lchild = subs.back();
subs.pop_back();
cout << CYAN << "lchild points to the root of the last sub-tree:" << *lchild;
rchild = new BinNode<T>(*r);
cout << CYAN << "rchild points to a new node:" << *rchild;
m = new Model(CHAR_VERTEX, (lchild->data.prob)+(r->prob));
vertex = new BinNode<T>(*m);
lchild->parent = vertex;
rchild->parent = vertex;
vertex->lchild = lchild;
vertex->rchild = rchild;
}
this->_root = vertex;
cout << CYAN << "root:" << *this->_root << WHITE << endl;
break;
}
else {
cout << RED << "size of sub-tree is less than 1:" << subs.size() << WHITE << endl;
this->_root = subs.back();
subs.pop_back();
break;
}
}
else {
l = *it;
it++;
r = *it;
m = new Model(CHAR_VERTEX, l->prob+r->prob);
for (it_subs=subs.begin(); it_subs!=subs.end(); it_subs++) { //set lchild if any sub-tree corresponds with this l model iterated currently
if (*l == (*it_subs)->data) {
cout << CYAN << "lchild points to the root of sub-tree:" << **it_subs;
lchild = *it_subs;
--(it_subs = subs.erase(it_subs));
}
if (lchild != NULL) break; //tricky but important
}
for (it_subs=subs.begin(); it_subs!=subs.end(); it_subs++) { //set rchild if any sub-tree corresponds with this r model iterated currently
if (*r == (*it_subs)->data) {
cout << CYAN << "rchild points to the root of sub-tree:" << **it_subs;
rchild = *it_subs;
--(it_subs = subs.erase(it_subs));
}
if (rchild != NULL) break; //tricky but important
}
if (lchild == NULL) { //set lchild with a new node if no any sub-tree corresponds with this l model iterated currently, which means meeting a row leaf
lchild = new BinNode<T>(*l);
cout << CYAN << "lchild points to a new node:" << *lchild;
}
if (rchild == NULL) { //set rchild with a new node if no any sub-tree corresponds with this r model iterated currently, which means meeting a row leaf
rchild = new BinNode<T>(*r);
cout << CYAN << "rchild points to a new node:" << *rchild;
}
vertex = new BinNode<T>(*m);
std::cout << GREEN << "growing..." << WHITE << endl;
std::cout << CYAN << "lchild" << *lchild << WHITE;
std::cout << CYAN << "rchild" << *rchild << WHITE;
std::cout << CYAN << "vertex" << *vertex << WHITE;
lchild->parent = vertex;
rchild->parent = vertex;
vertex->lchild = lchild;
vertex->rchild = rchild;
subs.push_back(vertex);
for (std::list<Model*>::iterator itt=it;itt!=list.end();itt++) {
if ((*m < **itt) || (*m == **itt)) {
list.insert(itt, m);
break;
}
else if (std::next(itt,1) == list.end()) {
list.push_back(m);
break;
}
}
it++;
}
}
this->updateHeightAll();
cout << GREEN << "-*-*-*-*-*-*-*-* Huffman tree top -*-*-*-*-*-*-*-*" << WHITE << endl;
this->traverseLevel();
cout << GREEN << "-*-*-*-*-*-*-*-* Huffman tree bottom -*-*-*-*-*-*-*-*" << WHITE << endl;
subs.clear();}
And Huffman::generate() creates table for coding content.
template<typename T> void amo::HuffmanTree<T>::generate() {
std::string code = "";
std::queue<BinNode<T>*> queue;
BinNode<T>* node = this->_root;
BinNode<T>* tmp;
queue.push(node);
int i = 0;
while (true) {
if (queue.empty()) break;
node = queue.front();
queue.pop();
cout << YELLOW << "while-loop:" << ++i << ", node:" << *node << WHITE << endl;
if (node->data.c == CHAR_VERTEX) {
//do nothing
}
else {
if (node->isLeaf()) code = "";
tmp = node;
while (tmp!=NULL) {
if (tmp->isLeftChild()) code.insert(0, "0");
else if (tmp->isRightChild()) code.insert(0, "1");
tmp = tmp->parent;
}
if (node->data.c != CHAR_VERTEX) codes[node->data.c] = code;
}
if (node->hasLeftChild()) queue.push(node->lchild);
if (node->hasRightChild()) queue.push(node->rchild);
}
for (std::map<char,string>::iterator it=codes.begin();it!=codes.end();it++) {
cout << YELLOW << "codes[" << distance(codes.begin(),it) << "]:" << " key:" << it->first << " => value:" << it->second << WHITE << endl;
}}
Thanks, any suggestion is welcome.
Related
I'm implementing a Red Black Tree in C++ and I'm stuck on fixing color violations after insertion.
My left and right rotations seem to work fine but the colors in right branches of the tree are never getting fixed correctly. I think I covered all the cases in my fixViolation(Node*n) method but maybe I'm wrong.
I will also appreciate all other advice and tips on my code. pastebin link to my code
My code:
#include "pch.h"
#include <iostream>
#include <random>
#include <string>
#include <functional>
using namespace std;
enum Color { Black, Red };
template<typename T>
class RBTree;
template <typename T>
class Node
{
friend class RBTree<T>;
T data;
Color color;
Node* parent;
Node* leftChild;
Node* rightChild;
public:
Node()
{
this->parent = nullptr;
this->leftChild = nullptr;
this->rightChild = nullptr;
color = Red;
}
void gibColor(Node<T>*x)
{
if (x->color == Black)
cout << "black";
else
cout << "red";
}
};
template <typename T>
class RBTree
{
Node<T>* root;
int size;
public:
RBTree()
{
root = nullptr;
size = 1;
}
void leftRotate(Node<T>*child, Node<T>*parent)
{
child = parent->rightChild;
parent->rightChild = child->leftChild;
if (child->leftChild != nullptr)
{
child->leftChild->parent = parent;
}
child->parent = parent->parent;
if (parent->parent == nullptr)
{
root = child;
}
else if (parent == parent->parent->leftChild)
{
parent->parent->leftChild = child;
}
else {
parent->parent->rightChild = child;
}
child->leftChild = parent;
parent->parent = child;
}
void rightRotate(Node<T>*child, Node<T>*parent)
{
child = parent->leftChild;
parent->leftChild = child->rightChild;
if (child->rightChild != nullptr)
{
child->rightChild->parent = parent;
}
child->parent = parent->parent;
if (parent->parent == nullptr)
{
root = child;
}
else if (parent == parent->parent->rightChild)
{
parent->parent->rightChild = child;
}
else
{
parent->parent->leftChild = child;
}
child->rightChild = parent;
parent->parent = child;
}
void fixViolation(Node<T>*n)
{
Node<T>*grandparent;
Node<T>*parent;
//Node<T>*uncle;
parent = n->parent;
while (parent != nullptr&& parent->color == Red)
{
Node<T>*uncle;
grandparent = n->parent->parent;
if (grandparent->leftChild == parent)
{
uncle = grandparent->rightChild;
if (uncle != nullptr&&uncle->color == Red)
{
parent->color = Black;
uncle->color = Black;
grandparent->color = Red;
n = grandparent;
parent = n->parent;
}
else
{
if (parent->rightChild == n)
{
n = parent;
leftRotate(n->parent, n);
}
parent->color = Black;
grandparent->color = Red;
rightRotate(parent, grandparent);
}
}
else
{
uncle = grandparent->leftChild;
if (uncle != nullptr&&uncle->color == Red)
{
uncle->color = Black;
parent->color = Black;
grandparent->color = Red;
n = grandparent;
parent = n->parent;
}
else
{
if (parent->leftChild == n)
{
n = parent;
rightRotate(n->parent, n);
}
parent->color = Black;
grandparent->color = Red;
leftRotate(parent, grandparent);
}
}
}
root->color = Black;
}
void addElement(T el)
{
Node<T>*n = new Node<T>();
n->data = el;
n->leftChild = nullptr;
n->rightChild = nullptr;
n->color = Red;
Node<T>*temp = this->root;
Node<T>*y = nullptr;
if (root == nullptr)
{
n->color = Black;
root = n;
}
else
{
while (temp != nullptr)
{
y = temp;
if (temp->data < n->data)
{
temp = temp->rightChild;
}
else
{
temp = temp->leftChild;
}
}
n->parent = y;
if (y->data == n->data)
{
cout << "Duplikaty won!" << endl;
return;
}
if (y->data < n->data)
{
y->rightChild = n;
size = size + 1;
}
else
{
y->leftChild = n;
size = size + 1;
}
//InsertFixUp(n);
fixViolation(n);
}
}
void print(Node<T>*x)
{
//cout << "size: " << size << endl;
if (x == nullptr)
{
return;
}
if (x->parent == nullptr)
{
cout << "(" << x->data << ")";
cout << "[" << "kolor:";
x->gibColor(x);
cout << ", parent: NULL," << " l.child: ";
if (x->leftChild == nullptr)
{
cout << "NIL";
}
else
cout << x->leftChild->data;
cout << ", r.child: ";
if (x->rightChild == nullptr)
{
cout << "NIL";
}
else
cout << x->rightChild->data;
cout << "]";
cout << "-root " << endl;
//rodzic, l.dziecko, p.dziecko
}
else if (x->parent->leftChild == x)
{
//int c = x->gibColor(x);
cout << "(" << x->data << ")";
cout << "[" << "kolor:";
x->gibColor(x);
cout << ", parent: " << x->parent->data << ", l.child: ";
if (x->leftChild == nullptr)
{
cout << "NIL";
}
else
cout << x->leftChild->data;
cout << ", r.child: ";
if (x->rightChild == nullptr)
{
cout << "NIL" << "]" << endl;
}
else
cout << x->rightChild->data << "]" << endl;
}
else
{
cout << "(" << x->data << ")";
cout << "[" << "kolor:";
x->gibColor(x);
cout << ", parent: " << x->parent->data << ", l.child: ";
if (x->leftChild == nullptr)
{
cout << "NIL";
}
else
cout << x->leftChild->data;
cout << ", r.child: ";
if (x->rightChild == nullptr)
{
cout << "NIL" << "]" << endl;;
}
else
cout << x->rightChild->data << "]" << endl;
}
print(x->leftChild);
print(x->rightChild);
}
void printTree()
{
if (root == nullptr)
{
cout << "Empty tree!" << endl;
}
else
print(root);
}
};
int randomInt()
{
uniform_int_distribution<int> rozklad{ 0, 11000000 };
default_random_engine generator{ 11 };
function<int()> los{ bind(rozklad, generator) };
int l = los();
return l;
}
int main()
{
RBTree<int>* d1 = new RBTree<int>();
d1->addElement(55);
d1->addElement(69);
d1->addElement(62);
d1->addElement(71);
d1->addElement(70);
d1->addElement(14);
d1->printTree();
}
below is my current in-progress code converting a singly linked to a doubly linked list. I haven't touched the delete function yet. I've gotten insert in empty list, end of list, and beginning of list apparently working.
However nodes inserting in the middle seemingly fail to create a link to the previous node. My debugging lines I inserted seem to show both the n->next and n-> prev with the correct memory address, but when I go to reverseprint, any nodes inserted in the middle are missed and the links are gone. Where am I going wrong in regards to this?
Code below:
#include <iostream>
#include <string>
using namespace std;
// define a node for storage and linking
class node {
public:
string name;
node *next;
node *prev;
};
class linkedList {
public:
linkedList() :top(NULL) {}
bool empty() { return top == NULL; }
node *getTop() { return top; }
node *getEnd() { return end; }
void setTop(node *n) { top = n; }
void setEnd(node *p) { end = p; }
void add(string);
int menu();
void remove(string);
~linkedList();
void reversePrint();
friend ostream& operator << (ostream&, const linkedList&); // default output is in-order print.
private:
node *top;
node *end;
};
void main() {
linkedList l;
cout << l.empty() << endl;
int option = 0;
string s;
bool go = true;
while (go) {
option = l.menu();
switch (option) {
case 1: cout << "enter a name: "; cin >> s; l.add(s); break;
case 2: cout << "enter name to be deleted: "; cin >> s; l.remove(s); break;
case 3: cout << l; break;
//case 4: cout << "can not be done with a singly linked list" << endl;
case 4: l.reversePrint(); break;
case 5: cout << "exiting" << endl; go = false; break;
}
}
system("pause");
}
void linkedList::remove(string s) {
bool found = false;
node *curr = getTop(), *prev = NULL;
while (curr != NULL) {
// match found, delete
if (curr->name == s) {
found = true;
// found at top
if (prev == NULL) {
node *temp = getTop();
setTop(curr->next);
delete(temp);
// found in list - not top
}
else {
prev->next = curr->next;
delete(curr);
}
}
// not found, advance pointers
if (!found) {
prev = curr;
curr = curr->next;
}
// found, exit loop
else curr = NULL;
}
if (found)cout << "Deleted " << s << endl;
else cout << s << " Not Found " << endl;
}
void linkedList::add(string s) {
node *n = new node();
n->name = s;
n->next = NULL;
n->prev = NULL;
// take care of empty list case
if (empty()) {
top = n;
end = n;
// take care of node belongs at beginning case
}
else if (getTop()->name > s) {
n->next = getTop();
n->prev = NULL;
setTop(n);
node *temp;
temp = n->next;
temp->prev = n;
// take care of inorder and end insert
}
else {
// insert in order case
node *curr = getTop(), *prev = curr;
while (curr != NULL) {
if (curr->name > s)break;
prev = curr;
curr = curr->next;
}
if (curr != NULL) { // search found insert point
n->next = curr;
cout << n->name << " " << n << " prev " << prev << " " << prev->name << endl;
n->prev = prev;
prev->next = n;
cout << "n->prev is: " << n->prev << " " << n->prev->name << endl;
cout << "n->next is: " << n->next << " " << n->next->name << endl;
}
// take care of end of list insertion
else if (curr == NULL) {// search did not find insert point
prev->next = n;
n->prev = prev;
cout << "n->prev is: " << n->prev << " " << n->prev->name << endl;
setEnd(n);
}
}
}
ostream& operator << (ostream& os, const linkedList& ll) {
//linkedList x = ll; // put this in and the code blows up - why?
node *n = ll.top;
if (n == NULL)cout << "List is empty." << endl;
else
while (n != NULL) {
os << n->name << endl;
os << n << endl;
if (n->next != NULL) {
os << "next is " << n->next << endl;
}
n = n->next;
}
return os;
}
void linkedList::reversePrint() {
node *n = end;
if (n == NULL)cout << "List is empty." << endl;
else
while (n != NULL) {
//cout << n->name << endl;
cout << "memory address of " << n->name << " is " << n << endl;
if (n->prev != NULL) {
cout << "prev is " << n->prev << endl;
}
n = n->prev;
}
return;
}
// return memory to heap
linkedList::~linkedList() {
cout << "~linkedList called." << endl;
node *curr = getTop(), *del;
while (curr != NULL) {
del = curr;
curr = curr->next;
delete(del);
}
}
int linkedList::menu() {
int choice = 0;
while (choice < 1 || choice > 5) {
cout << "\nEnter your choice" << endl;
cout << " 1. Add a name." << endl;
cout << " 2. Delete a name." << endl;
cout << " 3. Show list." << endl;
cout << " 4. Show reverse list. " << endl;
cout << " 5. EXIT " << endl;
cin >> choice;
}
return choice;
}
You are not setting the prev of the current in insertion into middle, just do:
n->next = curr;
curr->prev = n; // <-- this
I am really trying to figure out the bug in my code I wrote for AVL tree but there seems to be a bug in it.
It calls the rotation functions but when it finishes rotation there are several problem:
root doesn't change
only root value is displayed when in-order traversal is done, other values seem to disappear
I have been trying to fix this bug since 2-3 days but cant seem to solve it.
Would love some help from you guys. I will be attaching the code with this.
/*
insertion
rotations all DONE
level order DONE
deletion
*/
#include <iostream>
#include <queue>
using namespace std;
struct node
{
int data;
int height;
node *left;
node *right;
node()
{
height = 0;
left = right = NULL;
}
};
class AVL
{
public:
node *root;
AVL()
{
root = NULL;
}
// search function
bool search(int num)
{
node *nodePtr = root;
if (root->data == num)
{
cout << "FOUND " << endl;
return true;
}
else
{
while (nodePtr != NULL)
{
if (nodePtr->data < num)
{
nodePtr = nodePtr->right;
}
else if (nodePtr->data > num)
{
nodePtr = nodePtr->left;
}
else
{
cout << "FOUND " << endl;
return true;
}
}
cout << "NOT FOUND " << endl;
return false;
}
}
// inorder
void inorder()
{
inorder(root);
}
// postorder
void postorder()
{
postorder(root);
}
// preorder
void preorder()
{
preorder(root);
}
// inorder utility function
void inorder(node *&nodePtr)
{
if (nodePtr)
{
inorder(nodePtr->left);
cout << nodePtr->data << ", ";
inorder(nodePtr->right);
}
}
// preorder utility function
void preorder(node *&nodePtr)
{
if (nodePtr)
{
cout << nodePtr->data << ", ";
preorder(nodePtr->left);
preorder(nodePtr->right);
}
}
// postorder utility function
void postorder(node *&nodePtr)
{
if (nodePtr)
{
postorder(nodePtr->left);
postorder(nodePtr->right);
cout << nodePtr->data << ", ";
}
}
// returns the number of nodes in the tree
int size(node *&nodePtr)
{
if (!nodePtr)
{
return 0;
}
else
{
return (size(nodePtr->left) + size(nodePtr->right)) + 1;
}
}
// function to check if tree is empty or not
bool isempty()
{
if (root == NULL)
{
return true;
}
else
{
return false;
}
}
// max function to calculate height and also the balance factor
int maximum(int x, int y)
{
if (x>y)
{
return x;
}
else
{
return y;
}
}
// returns the level of the tree
int returnHeight(node *&nodePtr)
{
if (nodePtr == NULL)
{
return 0;
}
else
{
return nodePtr->height;
}
}
// assigning the height to the node
void assignHeightToNode(node *&nodePtr)
{
int left = returnHeight(nodePtr->left);
int right = returnHeight(nodePtr->right);
nodePtr->height = maximum(left, right) + 1;
}
// single left rotate
node *singleLeftRotate(node *&nodePtr)
{
// if (nodePtr==NULL)
// {
// return;
// }
node * b = nodePtr->right;
nodePtr->right = b->left;
b->left = nodePtr;
return b;
}
// single right rotate
node *singleRightRotate(node *&nodePtr)
{
// if (nodePtr==NULL)
// {
// return ;
// }
node * b = nodePtr->left;
nodePtr->left = b->right;
b->right = nodePtr;
assignHeightToNode(nodePtr);
assignHeightToNode(b);
return b;
}
// double left rotate
node *doubleLeft(node *&nodePtr)
{
nodePtr->right = singleRightRotate(nodePtr->right);
return singleLeftRotate(nodePtr);
}
// double right rotate
node *doubleRight(node *&nodePtr)
{
nodePtr->left = singleLeftRotate(nodePtr->left);
return singleRightRotate(nodePtr);
}
// insert function
void insert1(int x)
{
cout << "NOW INSERTING " << x << endl;
insert2(x, root);
}
// insert utility function
void insert2(int &x, node *&nodePtr)
{
if (nodePtr == NULL)
{
node *newNode = new node;
newNode->data = x;
newNode->height = 0;
nodePtr = newNode;
checkRotations(nodePtr, x);
return;
}
else
{
if (x < nodePtr->data)
{
cout << endl << "GOING LEFT " << endl;
insert2(x, nodePtr->left);
}
else if (x > nodePtr->data)
{
cout << endl << "GOING RIGHT " << endl;
insert2(x, nodePtr->right);
}
else if (nodePtr->data == x)
{
cout << "DUPLICATE VALUES NOT ALLOWED " << endl;
return;
}
}
checkRotations(nodePtr, x);
}
// checking if rotations needed
void checkRotations(node *&nodePtr, int &x)
{
assignHeightToNode(nodePtr);
cout << endl << endl << "HEIGHT OF " << nodePtr->data << " IS " << nodePtr->height << endl;
int bf = returnHeight(nodePtr->left) - returnHeight(nodePtr->right);
cout << endl << endl << "BALANCE FACTOR AT NODE " << nodePtr->data << " IS " << bf << endl;
if (bf < -1 || bf > 1)
{
cout << endl << endl << "ROTATION IS HAPPEENING " << endl << endl;
if (x > nodePtr->data)
{
singleLeftRotate(nodePtr);
cout << endl << "ROTATION DONE SINGLE LEFT " << endl;
return;
}
else if (x < nodePtr->data)
{
singleRightRotate(nodePtr);
cout << endl << "ROTATION DONE SINGLE RIGHT " << endl;
return;
}
else if (x < root->data && x > root->left->data)
{
doubleRight(nodePtr);
cout << endl << "ROTATION DONE DOUBLE LEFT " << endl;
return;
}
else if (x > root->data && x < root->right->data)
{
doubleLeft(nodePtr);
cout << endl << "ROTATION DONE DOUBLE LEFT " << endl;
return;
}
}
}
// level order display code
void levelOrderDisplay()
{
levelOrderDisplay2(root);
}
// level order display utility function
void levelOrderDisplay2(node *&nodePtr)
{
if (nodePtr == NULL)
{
cout << "THE TREE IS EMPTY" << endl;
return;
}
queue <node *> displayer;
displayer.push(nodePtr);
while (!displayer.empty())
{
node *currentNode = displayer.front();
cout << currentNode->data << ", ";
if (currentNode->left != NULL)
{
displayer.push(currentNode->left);
}
else if (currentNode->right != NULL)
{
displayer.push(currentNode->right);
}
displayer.pop();
}
}
void rootD()
{
cout << "root is " << root->data << endl;
}
};
int main()
{
AVL tree;
tree.insert1(3);
tree.insert1(2);
tree.insert1(1);
tree.insert1(4);
tree.insert1(5);
tree.insert1(6);
tree.insert1(7);
tree.inorder();
// tree.rootD();
// tree.levelOrderDisplay();
// tree.rootD();
return 0;
}
I suggest you that do not pass node pointer by reference where your code does not change pointer value such as print. Try this... I completed my avl tree code just 2 3 day before and i have similar problem, when i debug my program i came to know that somehow in print function my pointer value is changed because i passed it by reference..... So.. Try this and see if work or not.... Hope this might help you.
Really late answer, but this is what you had to do. You should set the node passed in the function equal to the temporary node made in the function. In coding language, nodePtr=b should have been the last line of the single rotate functions.
Hope this helps :)
In the reverse function, I'm trying to swap the first 2 nodes only in a doubly linked list without swapping the data. It runs but it's not swapping the first 2 nodes in the list. Can someone point me in the right direction as to what I'm doing wrong?
struct node {
int data;
node * p; // FORWARD LINK
node * rp; // REVERSE LINK
};
ostream & operator<<(ostream &, const node *);
void addFront(node * & start, int);
void cleanUp(node *);
void reverse(node * &);
void main()
{
node * a = NULL;
cout << "EMPTY LIST CASE:\n";
cout << "BEFORE a is\n" << a << endl;
reverse(a);
cout << "AFTER a is\n" << a << endl;
cleanUp(a);
a = NULL;
addFront(a, 10);
cout << "\nONE ELEMENT LIST CASE:\n";
cout << "BEFORE a is\n" << a << endl;
reverse(a);
cout << "AFTER a is\n" << a << endl;
cleanUp(a);
a = NULL;
addFront(a, 30);
addFront(a, 20);
cout << "\nTWO ELEMENT LIST CASE:\n";
cout << "BEFORE a is\n" << a << endl;
reverse(a);
cout << "AFTER a is\n" << a << endl;
cleanUp(a);
a = NULL;
addFront(a, 60);
addFront(a, 50);
addFront(a, 40);
cout << "\nTHREE ELEMENT LIST CASE:\n";
cout << "BEFORE a is\n" << a << endl;
reverse(a);
cout << "AFTER a is\n" << a << endl;
cleanUp(a);
a = NULL;
addFront(a, 400);
addFront(a, 300);
addFront(a, 200);
addFront(a, 100);
cout << "\nFOUR ELEMENT LIST CASE:\n";
cout << "BEFORE a is\n" << a << endl;
reverse(a);
cout << "AFTER a is\n" << a << endl;
cleanUp(a);
}
void reverse(node * & s)
{
node * n1 = s;
node * n2 = s;
if (n1 == NULL) return;
node * temp = new node;
temp->rp = n1->rp;
temp->p = n1->p;
n1->rp = n2->rp;
n1->p = n2->p;
n2->rp = temp->rp;
n2->p = temp->p;
if (n1->p != NULL)
n1->p->rp = n1;
if (n1->rp != NULL)
n1->rp->p = n1;
if (n2->p != NULL)
n2->p->rp = n2;
if (n2->rp != NULL)
n2->rp->p = n2;
delete temp;
}
void addFront(node * & start, int x)
{
node * t = new node;
t->data = x;
if (start != NULL)
{
t->p = start;
t->rp = NULL;
start->rp = t;
}
else
{
t->p = NULL;
t->rp = NULL;
}
start = t;
}
void cleanUp(node * s)
{
node * walker, *prev;
walker = s;
while (walker != NULL)
{
prev = walker;
walker = walker->p;
delete prev;
}
}
ostream & operator<<(ostream & w, const node * s)
{
const node * walker = s;
const node * trailer = walker;
w << "Forward Print " << endl;
if (s == NULL)
{
w << "EMPTY LIST";
}
else
{
while (walker != NULL)
{
w << walker->data << ' ';
trailer = walker;
walker = walker->p;
}
}
w << endl << "Reverse Print " << endl;
if (trailer == NULL)
{
w << "EMPTY LIST";
return w;
}
while (trailer != NULL)
{
w << trailer->data << ' ';
trailer = trailer->rp;
}
return w;
}
Updated with complete program.
Here's an updated reverse:
void reverse(node * & s)
{
node * n1 = s;
if (n1 == NULL) return;
node * n2 = n1->p;
if (n2 == NULL) return;
node *temp;
node *n3;
n3 = n2->p;
temp = n1->rp;
n1->p = n3;
n1->rp = n2;
n2->rp = temp;
n2->p = n1;
if (n3 != NULL)
n3->rp = n1;
s = n2;
}
NOTE: even if temp had to remain as you defined it, there was no need to allocate and delete it. I would have used node temp and replaced temp->blah with temp.blah
I am trying to figure out how to create a tree in C++. I have tried debugging this for hours and I thought it was time I got another set of eyes on it. My question is if my treeNodeClass looks correct. Right now I am getting a stack explosion because I'm double removing items from my node. The tree itself will be parsing a simple xml file. Here is my code.
#include "treeNodeClass.h"
TreeNodeClass::TreeNodeClass()
{
cout << "TREENODECLASS::TREENODECLASS()" << endl;
attributes.clear();
children.clear();
data = "";
height = 0;
parent = NULL;
tag = "";
cout << "EXIT TREENODECLASS::TREENODECLASS()" << endl;
}
TreeNodeClass::TreeNodeClass(const TreeNodeClass& other)
{
cout << "TREENODECLASS::TREENODECLASS(const other)" << endl;
parent = NULL;
CopyIntoMe(other);
cout << "EXIT TREENODECLASS::TREENODECLASS(const other)" << endl;
}
TreeNodeClass::~TreeNodeClass()
{
cout << "TREENODECLASS::~TREENODECLASS()" << endl;
if(parent)
delete parent;
parent = NULL;
children.clear();
attributes.clear();
cout << "EXIT TREENODECLASS::~TREENODECLASS()" << endl;
}
void TreeNodeClass::CreateAttrib(string root, string val)
{
string attrib = root + "=" + val;
attributes.push_back(attrib);
}
void TreeNodeClass::CreateTag(string data, string name)
{
tag = name;
this->data = data;
}
list<string> TreeNodeClass::ReturnAttrib()
{
return this->attributes;
}
string TreeNodeClass::ReturnTag(string tag)
{
string retTag = "";
if(this->tag == tag)
retTag = this->tag;
return retTag;
}
void TreeNodeClass::AddChildren(TreeNodeClass* c)
{
if(c != NULL)
children.push_back(c);
}
TreeNodeClass& TreeNodeClass::operator=(const TreeNodeClass& other)
{
cout << "TREENODECLASS& TREENODECLASS OPERATOR = " << endl;
if(&other != this)
{
if(parent)
delete parent;
parent = NULL;
attributes.clear();
children.clear();
CopyIntoMe(other);
}
return *this;
}
void TreeNodeClass::CopyIntoMe(const TreeNodeClass& other)
{
cout << "Copy into me" << endl;
tag = other.tag;
data = other.data;
attributes = other.attributes;
children = other.children;
parent = new TreeNodeClass;
parent = other.parent;
height = other.height;
}
void TreeNodeClass::AddParent(TreeNodeClass* p)
{
if(p)
{
parent = new TreeNodeClass;
parent = p;
}
}
std::vector< TreeNodeClass* > TreeNodeClass::ReturnChildren()
{
return children;
}
ostream& operator<<(ostream& out, const TreeNodeClass& treeNode)
{
out << "NODE: " << treeNode.tag << " " << treeNode.data << endl;
out << "CHILDREN: " << treeNode.children.size() << endl;
out << "HEIGHT: " << treeNode.height << endl;
out << "Attributes: ";
for(list<string>::const_iterator iter = treeNode.attributes.begin(); iter != treeNode.attributes.end(); iter++)
{
out << *iter << " ";
}
out << endl;
}
void TreeNodeClass::SetHeight(int h)
{
height = h;
}
/*void function(TreeNodeClass* node)
{
cout << node << " " << *node << endl;
}
TreeNodeClass* function2(TreeNodeClass* node)
{
return node;
}
int main()
{
cout << "STARTING PROGRAM" << endl;
cout << "CREATING A TREE NODE CLASS " << endl;
TreeNodeClass* newNode;
TreeNodeClass* tempNode;
list<string> attribs;
newNode = new TreeNodeClass;
tempNode = new TreeNodeClass;
newNode->SetHeight(10);
cout << *tempNode << " " << *newNode << endl;
tempNode->SetHeight(20);
cout << *tempNode << "\n " << *newNode << endl;
cout << "Setting equal " << endl;
*tempNode = *newNode;
cout << *tempNode << " " << *newNode << endl;
tempNode->SetHeight(40);
cout << *tempNode << " " << *newNode << endl;
tempNode->AddChildren(newNode);
newNode->AddParent(tempNode);
cout << *tempNode << "\n " << *newNode << endl;
return 0;
}
*/
And I'm trying to use this code on a simple state machine. I basically set up a vector of lists to return the states. This is what I believe is giving me a majority of my errors. I've been staring at this as well for a while, but I'm kind of lost.The machine will create the tree (supposedly). When the state machine finishes (state 10) it returns and the calling function will just make another call to yylex(). Thanks for the help so far!
TreeNodeClass* ProcessTree(TokenT token, vector <list <stateAssoc> >& vecTree, int depth)
{
int state = 1; //Assume this is a new record.
bool noState = false;
bool update = true;
int dex = 0;
string root, value, data, tag;
TreeNodeClass* treeNode;
treeNode = new TreeNodeClass; //Assume a new node per state machine visit.
while(state != 10)
{
switch(state)
{
case 1: dex = 1;
break;
case 2: state = 3;
noState = true;
root = yylval;
break;
case 3: state = 4;
noState = true;
break;
case 4: dex = 3;
value = yylval;
//cout << value << endl;
treeNode->CreateAttrib(root, value);
break;
case 5: dex = 2;
data = yylval;
//cout << 5 << " " << yylval << " " << token << endl;
//If its data store as data; if tag its a start tag.
break;
case 6: dex = 4;
//cout << token << " " << yylval << endl;
break;
case 7: state = 9;
noState = true;
tag = yylval;
//cout << tag << token << endl;
if(data != "" and data != "authors")
treeNode->CreateTag(data, tag);
break;
case 8: {
TreeNodeClass* childNode = new TreeNodeClass;
childNode = ProcessTree(token, vecTree, depth+1);
cout << "BEFORE PARENT" << endl;
childNode->AddParent(treeNode);
childNode->SetHeight(depth);
treeNode->AddChildren(childNode);
delete childNode;
childNode = NULL;
}
token = TokenT(yylex()); //Get a new token to process.
dex = 5;
break;
case 9: state = 10;
noState = true;
update = false;
break;
case 10: noState = true;
update = false;
break;
default: cout << "Error " << endl;
cout << state << endl;
cin.get();
break;
}
if(!noState)
state = FindMatch(vecTree[dex], token);
else
noState = false;
if(update)
token = TokenT(yylex());
else
update = true;
}
return treeNode;
}
1.A children shouldn`t delete a parent:
TreeNodeClass::~TreeNodeClass()
{
cout << "TREENODECLASS::~TREENODECLASS()" << endl;
/* Delete next 2 lines
if(parent)
delete parent;
*/
parent = NULL;
children.clear();
attributes.clear();
cout << "EXIT TREENODECLASS::~TREENODECLASS()" << endl;
}
2.Containers will not delete a pointer -- you should take it in mind always. Easy way to delete, for example:
for (vector<TreeNodeClass*>::iterator child = children.begin(); child != children.end(); ++child)
delete *child;
But best way -- not use native pointers and use some smart pointers or shared pointers.
3.Main function do not delete pointers tempNode and newNode.
4.If you'll use native pointers, you should recursively create and copy each children. In other way you'll catch memory leak.
5.Example of method CopyIntoMe:
void TreeNodeClass::CopyIntoMe(const TreeNodeClass& other)
{
cout << "Copy into me" << endl;
tag = other.tag;
data = other.data;
attributes = other.attributes;
// delete each pointer to Nodes
foreach (vector<TreeNodeClass*>::iterator child = children.begin(); child != children.end(); ++child)
delete *child;
children.clear();
// Copy recursively each child
foreach (vector<TreeNodeClass*>::iterator child = other.children.begin(); child != other.children.end(); ++child) {
TreeNodeClass* new_child = new TreeNodeClass;
new_child->CopyIntoMe(*child);
children.push_back(new_child);
}
parent = other.parent;
height = other.height;
}
This is bad:
parent = new TreeNodeClass;
parent = p;
This is a memory leak. Since you are allocating memory and pointing parent to it, then immediately pointing parent to something else, you can never delete that allocated memory. The memory will be allocated and lost every time AddParent() is called.