I'm currently working through AVL trees and am curious why the output (pre order traversal) is only showing two levels of indentation, as if one of the second order nodes is pointing to three separate 3rd level node. I'm note sure if this is an issue with my print function, or the actual code.
#include <iostream>
#include <list>
#include <vector>
#include <iomanip>
using namespace std;
template <class T>
class BST;
template <class T>
class BSTNode{
T data;
BSTNode<T>* parent;
BSTNode<T>* left;
BSTNode<T>* right;
int height;
public:
BSTNode(T data = T(), BSTNode<T>* parent = nullptr, BSTNode<T>* left = nullptr,
BSTNode<T>* right = nullptr, int height = 0) : data(data), parent(parent), left(left), right(right), height(height){}
friend class BST<T>;
int getSize() const;
};
template <class T>
class BST{
public:
BSTNode<T>* root = nullptr;
BST() {}
~BST();
BST(const BST& rhs) {*this = rhs;};
BST& operator=(const BST& rhs);
void printPreOrder(BSTNode<T>* p, int indent);
void insert(T item, BSTNode<T> * & node);
void remove(BSTNode<T>*& temp); //pass pointer by reference because we will be changing the pointer
void clear(BSTNode<T>*& root); //clears the entire tree;
BST<T>* clone(BSTNode<T>* start);
void rotateRight(BSTNode<T> * & node); //rotate the left child (the left child becomes the parent and parent becomes the right child)
void rotateLeft(BSTNode<T> * & node); //rotate the right child (the right child becomes the parent and the parent becomes the left child)
void doubleRotateRight(BSTNode<T> *& node); //same result as rotate right
void doubleRotateLeft(BSTNode<T> *& node); //same result as rotate left
int height(BSTNode<T> * node); //return height
void balance(BSTNode<T> * &node);
};
template <class T>
int BSTNode<T>::getSize() const {
int count = 1;
if(left != nullptr){
count += left->getSize();
};
if(right != nullptr){
count += right->getSize();
};
return count;
}
template <class T>
void BST<T>::printPreOrder(BSTNode<T>* p, int indent){
if(p) {
if (indent) {
std::cout << std::setw(indent) << '\t';
}
cout<< p->data << "\n ";
if(p->left) printPreOrder(p->left, indent+2);
if(p->right) printPreOrder(p->right, indent+2);
}
}
template <class T>
void BST<T>::insert(T item, BSTNode<T> * & node){
if(!node){
node = new BSTNode<T>(item);
}
else if(item < node->data){
insert(item, node->left);
}
else{
insert(item, node->right);
}
balance(node);
}
template <class T>
void BST<T>::remove(BSTNode<T>*& temp){
if(temp->left == nullptr && temp->right == nullptr){
if(temp->parent == nullptr){
root = nullptr;
}
else if(temp->parent->left == temp){
temp->parent->left = nullptr;
}
else{
temp->parent->right = nullptr;
}
delete temp;
}
else if(temp->left == nullptr){ //promote right
BSTNode<T>* toDelete = temp->right;
temp->data = toDelete->data;
temp->left = toDelete->left;
temp->right = toDelete->right;
if(temp->left){
temp->left->parent = temp->left;
}
if(temp->right){
temp->right->parent = temp;
}
delete toDelete;
}
else if(temp->right == nullptr){ //promote left
BSTNode<T>* toDelete = temp->left;
temp->data = toDelete->data;
temp->left = toDelete->left;
temp->right = toDelete->right;
if(temp->left){
temp->left->parent = temp->left;
}
if(temp->right){
temp->right->parent = temp;
}
delete toDelete;
}
else{
BSTNode<T>* maxOfLeft = temp->left;
while(maxOfLeft){
maxOfLeft = maxOfLeft->right;
}
temp->data = maxOfLeft->data;
remove(maxOfLeft);
}
balance(temp);
}
template <class T>
void BST<T>::clear(BSTNode<T>*& root) {
if (root) {
if (root->left) {
clear(root->left);
}
if (root->right) {
clear(root->right);
}
delete root;
}
root = nullptr;
};
template <class T>
BST<T>::~BST(){
clear(root);
}
template <class T>
BST<T>* BST<T>::clone(BSTNode<T>* start){
if(!start){
return nullptr;
}
else{
return new BSTNode<T>(start->data, clone(start->left), clone(start->right));
}
}
template <class T>
BST<T>& BST<T>::operator=(const BST<T>& rhs){
if(this == &rhs){
return *this;
}
clear(root);
root = clone(rhs.root);
return *this;
}
template <class T>
void BST<T>::rotateRight(BSTNode<T> * & node){
BSTNode<T> * newParent = node->left;
node->left = newParent->right;
newParent->right = node;
node->height = max(height(node->right),height(node->left)) + 1;
newParent->height = max(height(newParent->left), node->height) + 1;
node = newParent; //set new root (we can't access newParent outside of this function!)
}
template <class T>
void BST<T>::rotateLeft(BSTNode<T> * & node){
BSTNode<T> * newParent = node->right;
node->right = newParent->left;
newParent->left = node;
node->height = max(height(node->right), height(node->left)) + 1;
newParent->height = max(height(newParent->right), node->height) + 1;
node = newParent; //set new root (we can't access newParent outside of this function!)
}
template <class T>
int BST<T>::height(BSTNode<T> *node){
if(node){
return node->height;
};
return -1;
}
template <class T>
void BST<T>::doubleRotateRight(BSTNode<T> * &node){
rotateLeft(node->left);
rotateRight(node);
}
template<class T>
void BST<T>::doubleRotateLeft(BSTNode<T> * &node){
rotateRight(node->right);
rotateLeft(node);
}
template<class T>
void BST<T>::balance(BSTNode<T> * &node){
if(!node){
return;
}
if(height(node->left) > height(node->right) + 1){
if(height(node->left->left) >= height(node->left->right)){
rotateRight(node);
}
else{
doubleRotateRight(node);
};
};
if(height(node->right) > height(node->left) + 1){
if(height(node->right->right) >= height(node->right->left)){
rotateLeft(node);
}
else{
doubleRotateLeft(node);
}
}
node->height = max(height(node->right), height(node->left)) + 1;
}
int main() {
vector<int>data = {5, 3, 4, 2, 1, 2, 6, 7};
BST<int> test;
for(int r : data){
test.insert(r, test.root);
}
test.printPreOrder(test.root,0);
cout << endl;
return 0;
}
Here is the output I am getting:
3
2
1
2
5
4
6
7
From my understanding, I should be getting the following output:
3
2
1
2
5
4
6
7
Don't use tabs.
Consider this example:
#include <iostream>
#include <iomanip>
int main() {
for (int indent=0;indent<5;++indent) {
if (indent) {
std::cout << std::setw(indent) << "\t" << "tabs" << "\n";
std::cout << std::setw(indent) << " " << "spaces" << "\n";
}
}
}
Possible output is:
tabs
spaces
tabs
spaces
tabs
spaces
tabs
spaces
Related
I'm trying to create a binary search tree by keeping the path: each node has a link to its parent. Below is the classic binary search. How do I change it to be able to solve my problem?
I tried adding the "father" pointer to the struct but I have no problems understanding how and when to save it. I am new to this language so be patient. thank you so much
#include <iostream>
template <class T>
class BinaryTree
{
struct node {
T value;
struct node* right;
struct node* left;
};
public:
BinaryTree();
~BinaryTree();
void add(T val);
void printPreOrder();
void printInOrder();
void printPostOrder();
int size();
bool lookup(T val);
private:
struct node* root;
int treeSize;
void add(struct node** node, T val);
bool lookup(struct node* node, T val);
void printPreOrder(struct node* node);
void printInOrder(struct node* node);
void printPostOrder(struct node* node);
void deleteTree(struct node* node);
};
template <class T>
BinaryTree<T>::BinaryTree() {
this->root = NULL;
this->treeSize = 0;
}
template <class T>
BinaryTree<T>::~BinaryTree() {
deleteTree(this->root);
}
template <class T>
int BinaryTree<T>::size() {
return this->treeSize;
}
template <class T>
void BinaryTree<T>::add(T val) {
add(&(this->root), val);
}
template <class T>
void BinaryTree<T>::add(struct node** node, T val) {
if (*node == NULL) {
struct node* tmp = new struct node;
tmp->value = val;
tmp->left = NULL;
tmp->right = NULL;
*node = tmp;
this->treeSize++;
}
else {
if (val > (*node)->value) {
add(&(*node)->right, val);
}
else {
add(&(*node)->left, val);
}
}
}
template <class T>
void BinaryTree<T>::printInOrder() {
printInOrder(this->root);
std::cout << std::endl;
}
template <class T>
void BinaryTree<T>::printInOrder(struct node* node) {
if (node != NULL) {
printInOrder(node->left);
std::cout << node->value << ", ";
printInOrder(node->right);
}
}
template <class T>
void BinaryTree<T>::printPreOrder() {
printPreOrder(this->root);
std::cout << std::endl;
}
template <class T>
void BinaryTree<T>::printPreOrder(struct node* node) {
if (node != NULL) {
std::cout << node->value << ", ";
printInOrder(node->left);
printInOrder(node->right);
}
}
template <class T>
void BinaryTree<T>::printPostOrder() {
printPostOrder(this->root);
std::cout << std::endl;
}
template <class T>
void BinaryTree<T>::printPostOrder(struct node* node) {
if (node != NULL) {
printInOrder(node->left);
printInOrder(node->right);
std::cout << node->value << ", ";
}
}
template <class T>
void BinaryTree<T>::deleteTree(struct node* node) {
if (node != NULL) {
deleteTree(node->left);
deleteTree(node->right);
delete node;
}
}
template <class T>
bool BinaryTree<T>::lookup(T val) {
return lookup(this->root, val);
}
template <class T>
bool BinaryTree<T>::lookup(struct node* node, T val) {
if (node == NULL) {
return false;
}
else {
if (val == node->value) {
return true;
}
if (val > node->value) {
return lookup(node->right, val);
}
else {
return lookup(node->left, val);
}
}
}
I will give you the recursive solution since it is the natural way to implement it:
First it would be a good idea to define a constructor in your struct like so:
node(T value, node* left = nullptr, node* right = nullptr){
this->value = value;
this->left = left;
this->right = right;
}
Take out the struct in the struct node* root.
void insert(T value){
Node* temp = root;
insert(value, root);
}
//helper function
void insert(T value, Node* root){
if(root->left == nullptr && root->right == nullptr){
if(root->value < value){
root->left = new Node(value);
}
else{
root->right = new Node(value);
}
return;
}
if(value < root->value)insert(value, root->left);
else{
insert(value, root->right);
}
}
Not sure where you got your code it does not look correct....
I don't understand the need for pointer to pointer to struct node in your code. Pointer to struct node would suffice. As far as your question goes, you can pass the parent of current node as a third parameter in the method add. Initially it will be null. Now incase you have to go down to the child of the current node, then the current node becomes it's parent. When you have to allocate memory for value val, set the it's parent there.
template <class T>
void BinaryTree<T>::add(struct node** node, T val, struct node* parent = nullptr) {
if (*node == NULL) {
struct node* tmp = new struct node;
tmp->value = val;
tmp->left = NULL;
tmp->right = NULL;
temp->parent = parent;
*node = tmp;
this->treeSize++;
}
else {
if (val > (*node)->value) {
add(&(*node)->right, val, *node);
}
else {
add(&(*node)->left, val, *node;
}
}
}
I am having trouble implementing this with the class I have. So far as a linkedlist of type int or string it works great, but I am not sure how to navigate the list if I initialize it like
linkedlist<linkedlist<int>> nums;
From my program it seems that the head of each secondary list would be an entry in the primary, but my question is how would I navigate it?. For example how would I print all the values of each linkedlist, I am sure I am making this more difficult than it it, but any help would be appreciated.
/* Node Class */
template <typename T>
class Node {
public:
T data;
Node* next;
Node* previous;
Node(T data);
Node();
T getData();
};
template <typename T>
Node<T>::Node() {
this->next = NULL;
this->previous = NULL;
}
template <typename T>
Node<T>::Node(T data) {
this->data = data;
}
template <typename T>
T Node<T>::getData() {
return this->data;
}
/* Linked List: */
template <typename T>
class linkedlist {
private:
Node<T>* head;
Node<T>* tail;
int list_size;
public:
linkedlist();
T getHead();
T getTail();
int size();
void addnodetail(T);
void addnodehead(T);
void push(T);
T pop();
//T* peek();
bool isEmpty() const {
return head == NULL;
}
//T* get(int index);
void printlist();
void printListBackwards();
~linkedlist();
};
template <typename T>
linkedlist<T>::linkedlist() {
this->head = NULL;
this->tail = NULL;
this->list_size = 0;
}
template <typename T>
T linkedlist<T>::getHead() {
return this->head->data;
}
template <typename T>
T linkedlist<T>::getTail() {
return this->tail->data;
}
template <class T>
int linkedlist<T>::size() {
return this->list_size;
}
template <typename T>
void linkedlist<T>::addnodetail(T input) {
Node<T>* newnode = new Node<T>(input);
newnode->next = NULL;
newnode->previous = NULL;
if (this->head == NULL) {
this->head = newnode;
this->tail = this->head;
this->list_size = this->list_size + 1;
} else {
this->tail->next = newnode;
newnode->previous = this->tail;
this->tail = newnode;
this->list_size = this->list_size + 1;
}
}
template <typename T>
void linkedlist<T>::addnodehead(T input) {
Node<T>* newnode = new Node<T>(input);
newnode->next = NULL;
newnode->previous = NULL;
if (this->head == NULL) {
this->head = newnode;
this->tail = this->head;
this->list_size = this->list_size + 1;
} else {
this->head->previous = newnode;
newnode->next = this->head;
this->head = newnode;
this->list_size = this->list_size + 1;
}
}
template <typename T>
void linkedlist<T>::push(T input) {
this->addnodehead(input);
}
template <typename T>
T linkedlist<T>::pop() {
Node<T>* temp = this->head;
// T* temp = this->head;
this->head = this->head->next;
this->head->previous = NULL;
this->list_size = this->list_size - 1;
return temp->data;
}
/*
template <class T>
T* MyList<T>::peek() {
return this->head;
}
template <class T>
T* MyList<T>::get(int index) {
if (index == 0) {
return this->head;
} else if (index == this->list_size - 1) {
return this->tail;
} else if (index < 0 || index >= this->list_size) {
return NULL;
}
if (index < this->list_size / 2) {
T* temp = this->head;
int i = 0;
while (temp) {
if (i == index) { return temp; }
i++;
temp = temp->next;
}
} else {
T* temp = this->tail;
int i = this->list_size - 1;
while (temp) {
if (i == index) { return temp; }
i--;
temp = temp->previous;
}
}
return NULL;
}*/
template <typename T>
void linkedlist<T>::printlist() {
cout << "HEAD: ";
Node<T>* temp = this->head;
while(temp) {
cout << temp->data << " -> ";
temp = temp->next;
}
cout << "\b\b\b\b :TAIL" << endl;
}
template <class T>
void linkedlist<T>::printListBackwards() {
cout << "TAIL: ";
Node<T>* temp = this->tail;
while(temp) {
cout << temp->data << " -> ";
temp = temp->previous;
}
cout << "\b\b\b\b :HEAD" << endl;
}
template <typename T>
linkedlist<T>::~linkedlist() {
for(Node<T>* p;!isEmpty();){
p = head->next;
delete head;
head = p;
}
}
EDIT with copy constructor
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include <iostream>
#include <ctype.h>
using namespace std;
using namespace std;
/*struct AdjListNode
{
int dest;
struct AdjListNode* next;
};
// A structure to represent an adjacency list
struct AdjList
{
struct AdjListNode *head; // pointer to head node of list
};
// A structure to represent a graph. A graph is an array of adjacency lists.
// Size of array will be V (number of vertices in graph)
struct Graph
{
int V;
struct AdjList* array;
};
// A utility function to create a new adjacency list node
struct AdjListNode* newAdjListNode(int dest)
{
struct AdjListNode* newNode =
(struct AdjListNode*) malloc(sizeof(struct AdjListNode));
newNode->dest = dest;
newNode->next = NULL;
return newNode;
}
// A utility function that creates a graph of V vertices
struct Graph* createGraph(int V)
{
struct Graph* graph = (struct Graph*) malloc(sizeof(struct Graph));
graph->V = V;
// Create an array of adjacency lists. Size of array will be V
graph->array = (struct AdjList*) malloc(V * sizeof(struct AdjList));
// Initialize each adjacency list as empty by making head as NULL
int i;
for (i = 0; i < V; ++i)
graph->array[i].head = NULL;
return graph;
}
// Adds an edge to an undirected graph
void addEdge(struct Graph* graph, int src, int dest)
{
// Add an edge from src to dest. A new node is added to the adjacency
// list of src. The node is added at the begining
struct AdjListNode* newNode = newAdjListNode(dest);
newNode->next = graph->array[src].head;
graph->array[src].head = newNode;
// Since graph is undirected, add an edge from dest to src also
newNode = newAdjListNode(src);
newNode->next = graph->array[dest].head;
graph->array[dest].head = newNode;
}
// A utility function to print the adjacenncy list representation of graph
void printGraph(struct Graph* graph)
{
int v;
for (v = 0; v < graph->V; ++v)
{
struct AdjListNode* pCrawl = graph->array[v].head;
printf("\n Adjacency list of vertex %d\n head ", v);
while (pCrawl)
{
printf("-> %d", pCrawl->dest);
pCrawl = pCrawl->next;
}
printf("\n");
}
}
*/
/* Node Class */
template <typename T>
class Node {
public:
T data;
Node* next;
Node* previous;
Node(T data);
Node();
T getData();
};
template <typename T>
Node<T>::Node() {
this->next = NULL;
this->previous = NULL;
}
template <typename T>
Node<T>::Node(T data) {
this->data = data;
this->next = NULL;
}
template <typename T>
T Node<T>::getData() {
return this->data;
}
/* Linked List: */
template <typename T>
class linkedlist {
private:
Node<T>* head;
Node<T>* tail;
int list_size;
public:
linkedlist();
linkedlist(linkedlist& object);
T getHead();
T getTail();
int size();
void addtail(const T& input);
void addhead(const T& input);
void push(T);
T pop();
//T* peek();
bool isEmpty() const {
return head == NULL;
}
//T* get(int index);
void printlist();
void printListBackwards();
~linkedlist();
};
template <typename T>
linkedlist<T>::linkedlist() {
this->head = NULL;
this->tail = NULL;
this->list_size = 0;
}
template <typename T>
linkedlist<T>::linkedlist(linkedlist &object){
if(object.head == NULL){
head == NULL;
}
else {
head = new Node<T>(object.head->data);
Node<T>* temp = head;
Node<T>* objecthead = object.head;
Node<T>* current = objecthead;
while(current->next != NULL){
temp->next = new Node<T>(current->next->data);
current = current->next;
temp = temp->next;
}
}
}
template <typename T>
T linkedlist<T>::getHead() {
return this->head->data;
}
template <typename T>
T linkedlist<T>::getTail() {
return this->tail->data;
}
template <class T>
int linkedlist<T>::size() {
return this->list_size;
}
template <typename T>
void linkedlist<T>::addtail(const T& input) {
Node<T>* newnode = new Node<T>(input);
newnode->next = NULL;
newnode->previous = NULL;
if (this->head == NULL) {
this->head = newnode;
this->tail = this->head;
this->list_size = this->list_size + 1;
} else {
this->tail->next = newnode;
newnode->previous = this->tail;
this->tail = newnode;
this->list_size = this->list_size + 1;
}
}
template <typename T>
void linkedlist<T>::addhead(const T& input) {
Node<T>* newnode = new Node<T>(input);
newnode->next = NULL;
newnode->previous = NULL;
if (this->head == NULL) {
this->head = newnode;
this->tail = this->head;
this->list_size = this->list_size + 1;
} else {
this->head->previous = newnode;
newnode->next = this->head;
this->head = newnode;
this->list_size = this->list_size + 1;
}
}
template <typename T>
void linkedlist<T>::push(T input) {
this->addhead(input);
}
template <typename T>
T linkedlist<T>::pop() {
Node<T>* temp = this->head;
if(temp != NULL){
this->head = this->head->next;
this->head->previous = NULL;
this->list_size = this->list_size - 1;
return temp->data;
}
else{
cout << "Error:Empty List!";
exit (EXIT_FAILURE);
}
}
/*
template <class T>
T* MyList<T>::peek() {
return this->head;
}
template <class T>
T* MyList<T>::get(int index) {
if (index == 0) {
return this->head;
} else if (index == this->list_size - 1) {
return this->tail;
} else if (index < 0 || index >= this->list_size) {
return NULL;
}
if (index < this->list_size / 2) {
T* temp = this->head;
int i = 0;
while (temp) {
if (i == index) { return temp; }
i++;
temp = temp->next;
}
} else {
T* temp = this->tail;
int i = this->list_size - 1;
while (temp) {
if (i == index) { return temp; }
i--;
temp = temp->previous;
}
}
return NULL;
}*/
template <typename T>
void linkedlist<T>::printlist() {
cout << "STACK" << endl;
cout << "-------------------" << endl;
Node<T>* temp = this->head;
while(temp) {
cout << "\t" << temp->data << endl;
temp = temp->next;
}
//cout << "\b\b\b\b :TAIL" << endl;
}
template <class T>
void linkedlist<T>::printListBackwards() {
cout << "TAIL: ";
Node<T>* temp = this->tail;
while(temp) {
cout << temp->data << " -> ";
temp = temp->previous;
}
cout << "\b\b\b\b :HEAD" << endl;
}
template <typename T>
linkedlist<T>::~linkedlist() {
for(Node<T>* p;!isEmpty();){
p = head->next;
delete head;
head = p;
}
}
#endif // LINKEDLIST_H
Can someone help me find/make/point me in the right direction of a disjoint set implementation using Doubly Linked Lists? I have some supplemental code and I've already started editing it, I was wondering if someone could help me fill the rest in or at least give me some pointers on how to do so.
DisjointSet.h
#pragma once
#include "TemplateDoublyLinkedList.h"
#include <cstddef>
#include <iostream>
#include <vector>
using namespace std;
// Disjoint Set
template <typename T>
class DisjointSet {
private:
vector<DListNode<T>*> nodeLocator;
public:
~DisjointSet();
DisjointSet(int n) { nodeLocator.resize(n); }
vector<DListNode<T>*> getNodeLocator() const { return nodeLocator; }
DListNode<T>* MakeSet(int key, T node);
DListNode<T>* Union(DListNode<T> nodeI, DListNode<T> nodeJ);
DListNode<T>* FindSet(DListNode<T> node);
DListNode<T>* FindSet(int nodeKey);
};
template <typename T>
DListNode<T>* DisjointSet<T>::MakeSet(int key, T node)
{
DListNode<T> *temp = new DListNode(key, node);
nodeLocator.insert(nodeLocator.begin() + key - 1, temp);
return temp;
}
template <typename T>
DListNode<T>* DisjointSet<T>::Union(DListNode<T> nodeI, DListNode<T> nodeJ){
if (nodeI.getListSize() >= nodeJ.getListSize())
{
nodeI.getTrailer()->setNext(nodeJ.getRepresentative());
nodeJ.getRepresentative()->setPrevious(nodeI.getTrailer());
nodeI.getRepresentative()->setTrailer(nodeJ.getTrailer());
nodeJ.getRepresentative()->setTrailer(NULL);
nodeJ.getRepresentative()->setRepresentative(nodeI.getRepresentative());
nodeI.setListSize(nodeI.getListSize()+nodeJ.getListSize());
return nodeI.getRepresentative();
}
else if (nodeI.getListSize() < nodeJ.getListSize())
{
nodeJ.getTrailer()->setNext(nodeI.getRepresentative());
nodeI.getRepresentative()->setPrevious(nodeJ.getTrailer());
nodeJ.getRepresentative()->setTrailer(nodeI.getTrailer());
nodeI.getRepresentative()->setTrailer(NULL);
nodeI.getRepresentative()->setRepresentative(nodeJ.getRepresentative());
nodeJ.setListSize(nodeI.getListSize() + nodeJ.getListSize());
return nodeJ.getRepresentative();
}
return NULL;
}
template <typename T>
DListNode<T>* DisjointSet<T>::FindSet(DListNode<T> node){
}
template <typename T>
DListNode<T>* DisjointSet<T>::FindSet(int nodeKey){
if (nodeLocator[nodeKey-1]) != NULL)
return nodeLocator[nodeKey-1];
else
return nullptr;
}
template <typename T>
ostream& DisjointSet<T>::operator<<(ostream& out, const DisjointSet<T>& ds){
}
TemplateDoublyLinkedList.h
#pragma once
#include <string>
#include <cstdlib>
#include <iostream>
#include <stdexcept>
using namespace std;
// list node
template <typename T>
class DListNode {
private:
friend class DisjointSet;
int key, listSize;
T obj;
DListNode *prev, *next, *representative;
DListNode *trailer; //just the representative node has this pointer assigned
public:
DListNode(int k, T e, DListNode *p = NULL, DListNode *n = NULL)
: key(k), obj(e), prev(p), next(n) { listSize = 1; }
T getElem() const { return obj; }
T& getElemt() { return obj; }
DListNode<T> * getNext() const { return next; }
DListNode<T> * getPrev() const { return prev; }
void setNext(DListNode* n) { this->next = n; }
void setPrevious(DListNode* p) { this->prev = p; }
DListNode<T>* insert_before(T d); // insert the int before this node
// return a pointer to the inserted node
DListNode<T>* insert_after(T d); // insert the int after this node
// return a pointer to the inserted node
void delete_before(); // delete the node before this node
void delete_after(); // delete the node after this node
int getKey() { return key; }
DListNode<T>* getRepresentative() const { return representative; }
DListNode<T>* getTrailer() const { return trailer; }
void setRepresentative(DListNode* rep);
void setTrailer(DListNode* trail);
int getListSize() { return this->getRepresentative()->listSize; }
void setListSize(int lSize)
{ this->listSize = lSize; if(this->next != NULL) this->next->setListSize(lSize); }
};
template <typename T>
void DListNode<T>::setRepresentative(DListNode* rep) {
this->representative = rep;
if (this->next != NULL)
{
this->next->setRepresentative(rep);
}
}
template <typename T>
void DListNode<T>::setTrailer(DListNode* trail) {
this->representative = trail;
}
template <typename T>
DListNode<T>* DListNode<T>::insert_before(T d) {
DListNode<T>* temp = new DListNode(d); //temp pointer // 1 OPERATION
if(prev!= NULL){ //if previous is not null // 2 OPERATION
temp -> next = this; //initialize next // 2 OPERATION
temp -> prev = prev; //initialize previous // 2 OPERATION
prev -> next = temp; // insert in the list // 2 OPERATION
prev = temp; // 1 OPERATION
}
else{ //if null than do a simple insert
temp -> next = this; // 2 OPERATION
prev = temp; // 1 OPERATION
}
return temp; // 1 OPERATION
}
template <typename T>
DListNode<T>* DListNode<T>::insert_after(T d) {
DListNode<T>* temp = new DListNode(d); // 2 OPERATION
if(next != NULL){ //if next is not null do this // 2 OPERATION
temp -> next = next; //initialize next and previous // 2 OPERATION
temp -> prev = this; // 2 OPERATION
next -> prev = temp; //make the connection to insert // 2 OPERATION
next = temp; // 1 OPERATION
}
else{ //if null than do a simple insert
temp -> prev = this; // 2 OPERATION
next = temp; // 1 OPERATION
}
return temp; // 1 OPERATION
}
template <typename T>
void DListNode<T>::delete_before() {
if(prev!= NULL){ //check if something is there // 2 OPERATION
DListNode<T>* temp = prev; // 1 OPERATION
temp -> prev-> next = temp-> next; //change the interconnections // 4 OPERATION
temp -> next -> prev = temp -> prev; // 4 OPERATION
delete temp; //delete the element // 1 OPERATION
}
else{
cout << ">Error: Nothing is there :(" << endl;
}
}
template <typename T>
void DListNode<T>::delete_after() {
if(next != NULL){ //check if something is there
DListNode<T>* temp = next; // 1 OPERATION
next -> prev = this; //change the interconnections // 2 OPERATION
next = next -> next; // 2 OPERATION
delete temp; //delete the element // 1 OPERATION
}
else{
cout << ">Error: Nothing is there :(" << endl;
}
}
I have a data structure that uses a template class such that it can store any data type - ints, floats, strings, etc.
Because the data will be organized, I need a way to compare two values. Usually I can use > or <, but in the case of strings that will not work because using the >/< operators on a string won't tell me which comes first alphabetically. For that, I need to use the compare() function.
However since the data structure is a template class, I can't tell it to use the compare() function because it won't recognize the compare() function for anything BUT a string.
As a work-around, I tried writing two compare functions:
template (class t)
int BinaryTree<T>::compareVals(T v1, T v2);
and
template (class t)
int BinaryTree<T>::compareVals(string v1, string v2);
So that in the case of the value being a string type, the program would use the method with the compare() function in it.
However trying to do that, I am getting a compiler error basically telling me I can't overload the function.
So I'm out of ideas. How can I make this template class correctly compare and sort strings as well as numbers?
Thank you very much for your input!
Here is the entire class, for reference:
#ifndef binarytree_class
#define binarytree_class
#include <iostream>
#include <string>
#include <vector>
using std::cout;
using std::string;
using std::vector;
template <class T>
class BinaryTree{
public:
struct TreeNode{
TreeNode * leftChild,
* rightChild;
T key;
vector<T> data;
int size;
};
BinaryTree();
~BinaryTree();
bool isEmpty();
int getSize();
void add(T key, T data);
void remove(T key);
int getHeight();
bool keyExists(T key);
int getKeyHeight(T key);
void displayAll();
private:
int size;
TreeNode * root;
TreeNode * findParent(TreeNode * start, TreeNode * child); //finds the parent node of child in subtree starting at root start
TreeNode * findNode(TreeNode * node, T input); //find node with data input in subtree at root node
TreeNode * findMin(TreeNode * node);
void removeNode(TreeNode * node); //Small part of algorithm (case: 2 children) borrowed from tech-faq.com/binary-tree-deleting-a-node.html
void displaySubTree(TreeNode * node); //displays subtree starting at node
void sortAdd(TreeNode * eNode, TreeNode * nNode); //adds a new node nNode to subtree starting at root eNode
void destroySubTree(TreeNode * node); //destroys subtree starting at node.
void display(TreeNode * node, string indent, bool last); //Algorithm borrowed from http://stackoverflow.com/questions/1649027/how-do-i-print-out-a-tree-structure
char leftOrRight(TreeNode * eNode, TreeNode * nNode); //compares keys in existing node vs new node and returns L or R
int calcHeight(TreeNode * node, int depth); //calculates the height from node. Algorithm borrowed from wiki.answers.com
int compareVals(T v1, T v2);
int compareVals(string v1, string v2);
};
template <class T>
BinaryTree<T>::BinaryTree<T>() : size(0){}
template <class T>
bool BinaryTree<T>::isEmpty(){
return (!size);
}
template <class T>
int BinaryTree<T>::compareVals(T v1, T v2){
int result;
v1 <= v2? result = -1 : result = 1;
return result;
}
template <class T>
int BinaryTree<T>::compareVals(string v1, string v2){
int result;
result = v1.compare(v2);
if(result >= 0)
result = -1;
else
result = 1;
return result;
}
template <class T>
int BinaryTree<T>::getSize(){
return size;
}
template <class T>
void BinaryTree<T>::add(T key, T data){
bool done = false;
TreeNode * temp;
if(keyExists(key)){
temp = findNode(root,key);
temp->size++;
temp->data.push_back(key);
}
else{
temp = new TreeNode;
temp->leftChild = 0;
temp->rightChild = 0;
temp->key = key;
temp->size = 0;
temp->data.push_back(data);
if(isEmpty())
root = temp;
else
sortAdd(root, temp);
size++;
}
}
template <class T>
void BinaryTree<T>::sortAdd(TreeNode * eNode, TreeNode * nNode){
if(leftOrRight(eNode, nNode) == 'L'){
if(eNode->leftChild == 0)
eNode->leftChild = nNode;
else
sortAdd(eNode->leftChild,nNode);
} else {
if(eNode->rightChild == 0)
eNode->rightChild = nNode;
else
sortAdd(eNode->rightChild,nNode);
}
}
template <class T>
char BinaryTree<T>::leftOrRight(TreeNode * eNode, TreeNode * nNode){
char result;
if(compareVals(nNode->key, eNode->key) == -1)
result = 'L';
else
result = 'R';
return result;
}
template <class T>
void BinaryTree<T>::displayAll(){
display(root,"",true);
}
template <class T>
void BinaryTree<T>::display(TreeNode * node, string indent, bool last){
if(!isEmpty()){
cout << indent;
if(last){
cout << "\\-";
indent += " ";
} else {
cout << "|-";
indent += "| ";
}
cout << node->key << "\n";
if(node->leftChild != 0)
display(node->leftChild, indent, false);
if(node->rightChild != 0)
display(node->rightChild, indent, true);
} else
cout << "TREE IS EMPTY" << "\n\n";
}
template <class T>
int BinaryTree<T>::getHeight(){
if(!root)
cout << "ERROR: getHeight() root is NULL!" << "\n";
int result;
if(isEmpty())
result = 0;
else
result = calcHeight(root, 1);
return result;
}
template <class T>
int BinaryTree<T>::getKeyHeight(T key){
int result = -1;
if(!keyExists(key))
cout << "ERROR: Trying to get height of nonexistant key " << key << "\n";
else{
TreeNode * temp = findNode(root, key);
result = getHeight() - calcHeight(temp,1);
}
return result;
}
template <class T>
int BinaryTree<T>::calcHeight(TreeNode * node, int depth){ //Algorithm borrowed from wiki.answers.com
int leftDepth,
rightDepth,
result;
if(node->leftChild)
leftDepth = calcHeight(node->leftChild, depth+1);
else
leftDepth = depth;
if(node->rightChild)
rightDepth = calcHeight(node->rightChild, depth+1);
else
rightDepth = depth;
if(leftDepth > rightDepth)
result = leftDepth;
else
result = rightDepth;
return result;
}
template <class T>
void BinaryTree<T>::remove(T input){
if(!keyExists(input))
cout << "ERR: trying to remove nonexistant key " << input << "\n";
else{
TreeNode * temp = findNode(root,input);
removeNode(temp);
}
}
template <class T>
bool BinaryTree<T>::keyExists(T key){
bool result;
if(isEmpty())
result = false;
else{
if(findNode(root,key) != 0)
result = true;
else
result = false;
}
return result;
}
template <class T>
typename BinaryTree<T>::TreeNode * BinaryTree<T>::findNode(TreeNode * node, T input){
TreeNode * result = 0; //Returns 0 if none found
if(node->key == input)
result = node;
else{
if(node->leftChild != 0)
result = findNode(node->leftChild, input);
if(result == 0 && node->rightChild != 0)
result = findNode(node->rightChild, input);
}
return result;
}
template <class T>
void BinaryTree<T>::removeNode(TreeNode * node){
TreeNode * parent = 0;
if(node != root)
parent = findParent(root,node);
if(node->leftChild && node->rightChild){ //Case: both children (algorithm borrowed from tech-faq.com)
TreeNode * temp = findMin(node->rightChild);
string tkey = temp->key;
removeNode(temp);
node->key = tkey;
} else {
if(parent){
if(!(node->leftChild) && !(node->rightChild)){ //case: no children & not root
if(parent->leftChild == node)
parent->leftChild = 0;
else
parent->rightChild = 0;
}
if(!(node->leftChild) && node->rightChild){ //case: right child only & not root
if(parent->leftChild == node)
parent->leftChild = node->rightChild;
else
parent->rightChild = node->rightChild;
}
if(node->leftChild && !(node->rightChild)){ //case: left child only & not root
if(parent->leftChild == node)
parent->leftChild = node->leftChild;
else
parent->rightChild = node->leftChild;
}
delete node;
size--;
}
else{
if(node->leftChild) //case: left child only & root
root = node->leftChild;
else //case: right child only & root
root = node->rightChild;
delete node; //case: no children & root intrinsically covered
size--;
}
}
}
template <class T>
typename BinaryTree<T>::TreeNode * BinaryTree<T>::findMin(TreeNode * node){
TreeNode * result;
if(node->leftChild == 0)
result = node;
else
result = findMin(node->leftChild);
return result;
}
template <class T>
typename BinaryTree<T>::TreeNode * BinaryTree<T>::findParent(TreeNode * start, TreeNode * child){
TreeNode * result = 0;
if(start->leftChild){
if(start->leftChild->key == child->key)
result = start;
else
result = findParent(start->leftChild, child);
}
if(start->rightChild && result == 0){
if(start->rightChild->key == child->key)
result = start;
else
result = findParent(start->rightChild, child);
}
return result;
}
template <class T>
void BinaryTree<T>::destroySubTree(TreeNode * node){
TreeNode * parent = 0;
if(node != root)
parent = findParent(root,node);
if(node->leftChild)
destroySubTree(node->leftChild);
if(node->rightChild)
destroySubTree(node->rightChild);
if(parent){
if(parent->leftChild == node)
parent->leftChild = 0;
else
parent->rightChild = 0;
}
size--;
delete node;
}
template <class T>
BinaryTree<T>::~BinaryTree<T>(){
if(!isEmpty())
destroySubTree(root);
}
#endif
When T is std::string, you will end up having to functions with identical signature, that's why your compiler is complaining. To overcome this, just make compareVals a template of its own. I would also suggest you make them static, so that you can call them without an object.
static int compareVals(std::string const& v1, std::string const& v2)
{
//compare std::string
}
template<typename U>
static int compareVals(U v1, U v2)
{
//compare everything else
}
In fact, std::string does have built in relational operators, so for your specific use case it might not be necessary to define a compare function like the above. At any rate, this approach might still be useful to avoid making the assumption operators are defined for every data type your BinaryTree might end up supporting in the future.
I am trying to create a custom Binary Search Tree, and I have everything done except for the rotate function, which seems to be not moving a node over. The rotate function only gets called when a node is searched and found, and if the node has a right child. For simplicity I will only add the functions that are used in this, to make it shorter:
#include <iostream>
using namespace std;
template <typename T>
class MRBST {
public:
MRBST();
~MRBST();
void push(const T &);
bool search(const T &);
void PrintPreorder();
private:
struct Node {
T data;
Node *left;
Node *right;
Node (const T & theData, Node *lt, Node *rt)
: data(theData), left(lt), right(rt) {}
};
Node *root;
void push(const T &, Node * &) const;
void remove(const T &, Node * &) const;
Node* findMin(Node *t) const {
if (t == NULL) {
return NULL;
}
if (t->left == NULL) {
return t;
}
return findMin(t->left);
}
void preorder(Node * &);
bool search(const T &, Node *);
Node* findNode(const T & x, Node * t) {
if (t == NULL) {
return NULL;
}
if (x < t->data) {
return findNode(x, t->left);
} else if (x > t->data) {
return findNode(x, t->right);
} else if (x == t->data) {
return t;
}
return NULL;
}
void rotate(Node *);
};
template <typename T>
void MRBST<T>::PrintPreorder() {
preorder(root);
cout << endl;
}
template <typename T>
void MRBST<T>::preorder(Node * & t) {
if (t != NULL) {
cout << t->data << endl;
preorder(t->left);
preorder(t->right);
}
}
template <typename T>
bool MRBST<T>::search(const T & x) {
if (search(x, root)) {
Node *temp = findNode(x, root);
rotate(temp);
return true;
} else {
return false;
}
}
template <typename T>
void MRBST<T>::rotate(Node * k1) {
if (k1->right == NULL) {
return;
} else {
Node *temp = k1->right;
k1->right = temp->left;
temp->left = k1;
}
}
template <typename T>
bool MRBST<T>::search(const T & x, Node *t) {
if (t == NULL) {
return false;
} else if (x < t->data) {
return search(x, t->left);
} else if (x > t->data) {
return search(x, t->right);
} else {
return true;
}
}
I have a simple testing file that just adds some numbers to the tree, and then searches, followed by a print out in Preordering.
#include <iostream>
#include "MRBST.h"
using namespace std;
int main() {
MRBST<int> binaryTree;
binaryTree.push(5);
binaryTree.push(20);
binaryTree.push(3);
binaryTree.push(3);
binaryTree.push(4);
binaryTree.push(22);
binaryTree.push(17);
binaryTree.push(18);
binaryTree.push(8);
binaryTree.push(9);
binaryTree.push(1);
binaryTree.PrintPreorder();
cout << endl;
binaryTree.search(17);
binaryTree.PrintPreorder();
cout << endl;
}
With the output looking a something like this:
5
3
1
4
20
17
8
9
18
22
5
3
1
4
20
17
8
9
22
If anyone could give some insight into what is going wrong with my rotate function, that would be a great help.
Why are you doing rotate on search? It should be read-only.
You're losing the node because of that.
Look at your rotate:
Node *temp = k1->right;
k1->right = temp->left;
temp->left = k1;
Assume k1=x has right=y and left=z, look step by step:
Node *temp = k1->right;
temp =k1->right = y, k1 = x, k1->left = z
k1->right = temp->left;
k1->right = ?, k1->left = z, temp = y
temp->left = k1;
k1->right = ?, k1->left = z, temp->left = x.
Now - where did Y go? You lost it.
Look closely at your rotate() function, step by step, to see whether it does what you want it to do or not.