i'm trying to compare all leafs to return the lowest value of a tree, I don't have main function just a script to insert values so unfortunately I can't debug it.
tpNoArvore * findLowest(tpNoArvore * pNo){
tpNoArvore * left;
tpNoArvore * right;
tpNoArvore * res;
if (!pNo) return NULL; /* if */
left = findLowest(pNo->pNoL);
right = findLowest(pNo->pNoR);
if(isLeaf(pNo))
return pNo;
} /* if */
if(!left){
return right;
} /* if */
if(!right){
return left;
} /* if */
return (left->Valor < right->Valor) ? left : right ;
}
So, basically what i'm trying to achieve here is to compare the two sides of each node to find the lowest.
It seems strange that your code returns a pointer. I would expect something like:
// Assume valor is int
int findLowest(tpNoArvore * pNo){
if (!pNo) exit(1); /* fatal error */
// If this is a leaf just return its value
if(isLeaf(pNo)) return pNo->Valor;
// Not a leaf
// Find the lowest value in left part of tree
int leftValor = findLowest(pNo->pNoL);
// Find the lowest value in right part of tree
int rightValor = findLowest(pNo->pNoR);
// Return the lowest of leftValue ans rightValue
return (leftValor < rightValor) ? leftValor : rightValor ;
}
But maybe I have misundetstood your question.
Related
I came across this leetcode problem Insert Delete GetRandom where it is asked to implement a Data Structure to support Insert, Delete and getRandom in average O(1) time, and solved it as using map and a vector.
My solution passes all the test cases except for the last one and I'm not able to figure out why? The last test case is really very large to debug.
I changed my code a little bit and then it passes but still didn't got why the previous one didn't pass.
Non-Accepted Solution:
class RandomizedSet {
map<int, int> mp;
vector<int> v;
public:
/** Initialize your data structure here. */
RandomizedSet() {
}
/** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
bool insert(int val) {
if(mp.find(val) == mp.end()){
v.push_back(val);
mp[val] = v.size()-1;
return true;
}
else return false;
}
/** Removes a value from the set. Returns true if the set contained the specified element. */
bool remove(int val) {
if(mp.find(val) == mp.end()){
return false;
}
else{
int idx = mp[val];
mp.erase(val);
swap(v[idx], v[v.size()-1]);
v.pop_back();
if(mp.size()!=0) mp[v[idx]] = idx;
return true;
}
}
/** Get a random element from the set. */
int getRandom() {
if(v.size() == 0) return 0;
int rndm = rand()%v.size();
return v[rndm];
}
};
/**
* Your RandomizedSet object will be instantiated and called as such:
* RandomizedSet* obj = new RandomizedSet();
* bool param_1 = obj->insert(val);
* bool param_2 = obj->remove(val);
* int param_3 = obj->getRandom();
*/
Accpeted Solution:
The problem is in remove function, when i change the remove function by below code, it passes.
if(mp.find(val) == mp.end()){
return false;
}
else{
int idx = mp[val];
swap(v[idx], v[v.size()-1]);
v.pop_back();
mp[v[idx]] = idx;
mp.erase(val);
return true;
}
I don't understand why is this happening. I placed the mp.erase(val) in the last and replaced the if(mp.size()!=0) mp[v[idx]] = idx to mp[v[idx]] = idx only.
Both versions of remove function are able to handle corner case - when there is only single element left in the map and we want to remove it.
LeetCode 380
This is because of undefined behavior when the element removed is the last element.
e.g, say the operations are
insert(1) // v = [1], mp = [1->0]
insert(2) // v = [1,2], mp = [1->0, 2->1]
remove(2):
int idx = mp[val]; // val = 2, idx = 1
mp.erase(val); // mp = [1->0]
swap(v[idx], v[v.size()-1]); // idx = v.size()-1 = 1, so this does nothing.
v.pop_back(); // v = [1]
if(mp.size()!=0) mp[v[idx]] = idx; // mp[v[1]] = 1.
// But v[1] is undefined after pop_back(), since v's size is 1 at this point.
I am guessing that it doesn't clear the memory location accessed by v[1], so v[1] still points to 2, and it ends up putting 2 back into mp.
Was wondering if you guys could provide/assist me with concise solutions to determine whether a BTree underflows, and whether or not you could complete a right rotation on it. Bit confused as to the process of arriving at it. Don think it's as easy as just comparing the two unsigned values (particularly for underflow).
BTreeNode.h:
#ifndef BTREENODE_H
#define BTREENODE_H
#include <string>
#include <vector>
struct BTreeNode {
bool is_leaf_ = true;
std::vector<int> elements_;
std::vector<BTreeNode*> children_;
BTreeNode() {}
BTreeNode(std::vector<int> v) {
this->elements_ = v;
}
/**
* Fix the underflow child node at idx by rotating right
* (borrowing a node from left sibling).
* #param idx The underflow child to be fixed is at children_[idx].
* #return If the rotation can be done.
*/
bool rotateRight(unsigned idx, unsigned order);
};
/**
* Check if the given number of elements in a BTree node underflows.
* #param numElem Number of elements in this node.
* #param order The order of the BTree.
* #return True if it underflows, False otherwise.
*/
bool underflows(unsigned numElem, unsigned order);
/**
* A special case for removing an element from BTree. Assume elem
exists in leaf.
* #param item The element to be removed.
* #param parent The parent node that contains the leaf node as a
child.
* #param leaf_idx The leaf BTreeNode idx that contains the element to
be removed.
* #return If the removal is successful.
*/
bool removeFromLeaf(int item, BTreeNode* parent, unsigned leaf_idx,
unsigned order);
#endif
BTreeNode.cpp:
#include "BTreeNode.h"
#include <assert.h>
#include <algorithm>
#include <iostream>
/**
* Check if the given number of elements in a BTree node underflows.
* #param numElem Number of elements in this node.
* #param order The order of the BTree.
* #return True if it underflows, False otherwise.
*/
bool underflows(unsigned numElem, unsigned order) {
return false;
}
/**
* Fix the underflow child node at idx by rotating right
* (borrowing a node from left sibling).
* #param idx The underflow child to be fixed is at children_[idx].
* #return If the rotation can be done.
*/
bool BTreeNode::rotateRight(unsigned idx, unsigned order) {
/**
* First check if there is a left sibling.
* If there is not, simply return false because rotateRight cannot
be done.
*/
if (idx <= 0) return false;
/**
* Then check if the left sibling leaf contains enough elements
after one being borrowed.
*/
BTreeNode* prev = children_[idx - 1];
if (underflows(prev->elements_.size() - 1, order)) {
/**
* If it's not enough, this case cannot be handled by
rotateRight.
* Simply return false.
*/
return false;
}
/**
* Do the right rotation by stealing one element from left sibling
* and fixing the parent key.
*
* Example: Assume we are doing rotateRight around (40) to fix
right child
* (we are in BTreeNode(40), idx = 1 (the second child)),
* | 40 |
* / \
* | 10 | 20 | 30 | | 60 |
*
* after rotation, the tree should look like
* | 30 |
* / \
* | 10 | 20 | | 40 | 50 |
*
*/
// TODO: do the right rotation here
return true;
}
bool removeFromLeaf(int item, BTreeNode* parent, unsigned leaf_idx,
unsigned order) {
// sanity checks
assert(!parent->is_leaf_);
assert(leaf_idx < parent->children_.size());
BTreeNode* leaf = parent->children_[leaf_idx];
assert(leaf->is_leaf_);
std::vector<int>& elems = leaf->elements_;
std::vector<int>::iterator pos = std::find(elems.begin(),
elems.end(), item);
assert(pos != elems.end());
std::cout << "removing " << item << "..." << std::endl;
// delete item, shift other items, shrink the size
elems.erase(pos);
std::cout << "Does the node underflow? ";
// call rotateRight if current leaf node underflows
if (underflows(elems.size(), order)) {
std::cout << "Yes!" << std::endl;
return parent->rotateRight(leaf_idx, order);
}
std::cout << "No!" << std::endl;
return true;
}
I am working on a compression/decompression assignment. I'm trying to write a C++ method to build a tree using the following preorder traversal from the header of my compressed file:
001c1b01a01e1d
0 represents an internal node while 1 represents a leaf. Every time I create a node, I set the code of that node to either 0 or 1, because I will be using another method to decode the tree and it must know how to traverse down different sides by using these codes. Whenever I reach a 1 in the preorder traversal string, I set the node's "symbol" field to the following character in the preorder string. I can't get it to work though. Can anyone help? Here is my code ("bitsToRead" just represents the length of the preorder string so the method knows when to stop) Thanks!
void HCTree::buildFromHeader(ifstream& in, HCNode* n, int codeToUse) {
if( bitsToRead > 0) {
char c = in.get();
bitsToRead--;
if(c == '0') {
n = new HCNode(0, 0, 0, 0, 0, codeToUse);
if(rootSet == 0) {
root = n;
rootSet = true;
}
HCNode* left;
n->c0 = left;
HCNode* right;
n->c1 = right;
buildFromHeader(in, left, 0);
buildFromHeader(in, right, 1);
}
else {
byte symbol = in.get();
n = new HCNode(0, symbol, 0, 0, 0, codeToUse);
bitsToRead--;
n->c0 = n->c1 = NULL;
}
}
}
It seems changing
void HCTree::buildFromHeader(ifstream& in, HCNode* n, int codeToUse) {
to
void HCTree::buildFromHeader(ifstream& in, HCNode* &n, int codeToUse) {
will do the work.
Plus the rootSet logic can be omitted. You just call
buildFromHeader(in, root, codeToUse)
from the caller.
EDIT:
I misread your code in the first place. n = new HCNode(0, symbol, 0, 0, 0, codeToUse); is the code made me suggests to use a reference. Because what you want to do here is the changing the pointer passed from the leaf's ancestor (the n->c0 = left and n->c1 = right stuff). To make the whold thing work, in addition to the change above, change
HCNode* left;
n->c0 = left;
HCNode* right;
n->c1 = right;
buildFromHeader(in, left, 0);
buildFromHeader(in, right, 1);
to
buildFromHeader(in, n->c0, 0);
buildFromHeader(in, n->c1, 0);
This will let the callee to assign values transparently to pointers inside struct using references.
Many thanks in advance!
So, I've made attempts to make this function work. There are mistakes in the function but cannot catch them.
It seems to me, that I've missed the logic of sorting.
Could you point me 'where to go'?
/* node*/
typedef struct client {
int number; /* */
int balance;/* */
char lastName[20]; /* */
char firstName [20];/* */
char phone[11]; /* */
char email[20];
struct client *prev;/* */
struct client *next;
struct client *tmp; /* */
} Client;
Client *firstc,*currentc,*newc, *a, *b,*tmp; /*pointers*/
/* *"firstc' firstc element in list
*'currentc' current node
*'newc' new node
*'a' temporary pointer to Sort function
*'b' temporary pointer to Sort function
*'tmp' temporary pointer to Sort function
*/
int counter = 0;
int cnum = 0; /*cnum gives unique account numbers avoiding misentering*/
/*---Sort function------*/
void Sort()
{
/* */
int a = 0;/*variables to store balance*/
int b = 0;/*variables to store balance*/
if(firstc==NULL)
printf("Database is empty"); /*message*/
else
currentc = firstc;
currentc->prev = NULL;
tmp = NULL;
while((currentc=currentc->next)!= NULL)
{ /* 1) compare two nodes;
2) IF balance >*/
int a = currentc->balance;
int b = currentc->next->balance;/* debugger stopped here... */
if (a>b)
//if(currentc->balance >currentc->next->balance)
{ /*swap nodes*/
/*code using three pointers*/
tmp = currentc->next;
currentc->next->next = currentc->next;
currentc->next->next = tmp;
}
/*3)move along the list*/
else
currentc = currentc->next;
/*4) repeat to the end of list*/
}
currentc = firstc;
listAll();
return;
}
int b = currentc->next->balance;/* debugger stopped here... */
When currentc is pointing to the last item in the list currentc->next will be null. So currentc->next->balance is an access through a null pointer.
Also, practices like making assignments in conditions like while((currentc=currentc->next)!= NULL) will eventually come back to hurt you. In this case it seems you are skipping the first item in the list.
You probably meant:
if(firstc == NULL)
printf("Database is empty"); /*message*/
else
{ /* missing braces spotted by others */
currentc = firstc;
currentc->prev = NULL;
tmp = NULL;
for( ; currentc != NULL; currentc = currentc->next)
{
if(currentc->next == NUL)
/* nothing to compare */
break;
...
}
}
Furthermore the swapping code is swapping the wrong nodes:
tmp = currentc->next;
currentc->next->next = currentc->next;
currentc->next->next = tmp;
will almost (but not quite) swap the next node (b), with the one after it instead of with (a). You need to use the prev pointer (However since this looks like homework I had better not tell you exactly how to do it). Also, you are initialising prev but you need to keep it up to date in the loop. Actually, your 3 lines above are equivalent to:
tmp = currentc->next;
currentc->next->next = tmp;
so I think you meant something else.
the problem is when currentc is the last node, currectc->next is null, thus currentc->next->balance make it crash.
add some validation like
if (currentc->next == null)
and set b to a default/predefined value or put some logic whether you swap the nodes or not.
I'm literally ripping my hair out on this one fellas. Here's the problem. I've hard coded a 2-3 Tree and verified that it works with the use of an inorder traversal function that outputs the values of the node it's currently in. So I know the tree is built correctly.
Node *r;
Node zero,one,two,three,four,five,six,seven,eight,nine,ten;
r = &zero;
//Root
zero.small = 50;
zero.large = 90;
zero.left = &one; //Child node to the left
zero.middle = &four; //Child node in the middle
zero.right = &seven; //Child node to the right
//Left Tree
one.small = 20;
one.large = NULL;
one.left = &two;
one.middle = NULL;
one.right = &three;
two.small = 10;
two.large = NULL;
two.left = NULL;
two.middle = NULL;
two.right = NULL;
three.small = 30;
three.large = 40;
three.left = NULL;
three.middle = NULL;
three.right = NULL;
//Middle Tree
four.small = 70;
four.large = NULL;
four.left = &five;
four.middle = NULL;
four.right = &six;
five.small = 60;
five.large = NULL;
five.left = NULL;
five.middle = NULL;
five.right = NULL;
six.small = 80;
six.large = NULL;
six.left = NULL;
six.middle = NULL;
six.right = NULL;
//Right Tree
seven.small = 120;
seven.large = 150;
seven.left = &eight;
seven.middle = &nine;
seven.right = &ten;
eight.small = 100;
eight.large = 110;
eight.left = NULL;
eight.middle = NULL;
eight.right = NULL;
nine.small = 130;
nine.large = 140;
nine.left = NULL;
nine.middle = NULL;
nine.right = NULL;
ten.small = 160;
ten.large = NULL;
ten.left = NULL;
ten.middle = NULL;
ten.right = NULL;
cout<<"inorder traversal for debug"<<endl;
inOrder(*r);
Output would be: 10 20 30 40 50 60 70 80 90 100 110 120 130 140 150 160
So that proves the tree is built correctly. I've been asked to modify the code to search for a value in the tree. so I wrote this function below, that's essentially the inorder traversal function minus the outputs and a simple if statement that returns TRUE if the search key is found in the tree.
bool retrieve(Node r, int key)
{
if (r.left)
retrieve(*r.left, key);
if (r.small)
{
if (r.small == key)
{
cout<<"The node: "<<r.small<<" is equal to search key: "<<key<<endl; //for debug purposes
return true;
}
}
if (r.middle)
retrieve(*r.middle, key);
if (r.large)
if (r.right)
retrieve(*r.right, key);
}
The user is prompted for a number to search for (int key), and upon entry enters an if statement
if (retrieve(*r, key))
{
cout<<key<<" is found!"<<endl;
}
else
cout<<key<<" is not found!"<<endl;
Now the problem is that this seems logically sound to me, and yet when I enter the value "85" (which is not located on the tree AT ALL), the program outputs "85 is found!". Notice how it didn't output the COUT statement I have in the function.cout<<"The node: "<<r.small<<" is equal to search key: "<<key<<endl; I've debugged and stepped through the program and no matter what the bool function (retrieve) always returns true... What? So I switched the if statement in the bool function to return false (just for debugging purposes) upon entering "60" (which IS located on the tree), the boolean function STILL returns true. I've tried several combinations of slightly different code but to no avail.. What the heck is going on??
Thanks in advance,
Tyler
You never return a value, except in the if (r.small == key) branch.
From 2–3 tree - Wikipedia, I would say your code should compare the key with the small and large key first and depending on the comparison return the result from retrieve(*r.left/middle/right, key).
Something along these lines (untested)
if (key < r.small)
return retrieve(*r.small, key);
if (key == r.small)
return TRUE;
if (r.right == NULL)
return retrieve(*r.middle, key);
if (key < r.large)
return retrieve(*r.middle, key);
if (key == r.large)
return TRUE;
return retrieve(*r.right, key);
You need to first check if the key is found in the current node in either small or large, and if it is, return true. if it is not you need to recursively call retrieve on each of the contained nodes, and if any of them return true, return true. If your function has not returned yet you need to return false.
You need an initial test to see if the recursion should stop because you are at a least node.
// precondition: current is not 0
// returns: true or false. If true, location is set to the node
// where it was found.
bool DoSearch(Node *current, int key, Node *location)
{
/*
* Is key in current?
*/
if (current->smallValue == key || (current->isThreeNode()
&& current->largeValue == key)) {
location = current;
return true;
} else if ((current->isLeafNode())) {
location = current;
return false;
/*
* Does current have two keys?
*/
} else if (current->isThreeNode()){
if (key < current->smallValue) {
DoSearch(key, current->leftChild, location);
} else if (key < current->largeValue) {
DoSearch(key, current->middleChild, location);
} else {
DoSearch(key, current->rightChild, location);
}
} else { // ...or only one?
if (key < current->smallValue) {
DoSearch(key, current->leftChild, location);
} else {
DoSearch(key, current->rightChild, location);
}
}
}