How do I count nodes in a B-tree? - c++

I am struggling to count nodes in a B-tree. Here keys refer to an array of values and num_keys refers to the valid number of keys currently. How do I approach this to make it work?
int BTree::count_nodes(shared_ptr<btree> root){
int count = 0;
int i =0;
if (root == NULL) {
return 0;
}
for (i = 0; i < root->num_keys; i++) {
count +=root->keys[i];
}
return count;
}

Here, you can iterate over all nodes in the tree, incrementing the counter each time.
int BTree::count_nodes(shared_ptr<btree> root) {
int count = 0;
std::stack<shared_ptr<btree> > traversal_stack;
traversal_stack.push(root);
while (!traversal_stack.empty()) {
shared_ptr<btree> top = traversal_stack.top();
traversal_stack.pop();
++count;
for (shared_ptr<btree> child : top->children) {
traversal_stack.push(child);
}
}
return count;
}
This uses depth-first search. To do breadth-first search, change the std::stack into an std::queue and use .peek() instead of .top().
Note that it may be more efficient to have each node keep track of its subtree's number of nodes, and for the counts to be updated whenever nodes move around, instead of having a function like this.

Related

C++ permutation tree

I have tasks and I want to calculate the most profitable order to arrange them.
Instead of checking every permutation and doing n*n! calculations, I want to build a tree of permutations, that is, the number of children at each level decreases by 1, and at each node the sub-permutation that has already been calculated will be saved and not recalculated.
For example, if I have 4 tasks, the tree will look like this:
My attached code is missing. I don't know how to build the tree and the give nodes the indexes as in the figure. I know how to deal with a binary tree, but not with a tree where the number of children is different at each lavel.
(The value of each task depends on its location.
I know how to do that, so I didn't include it in the question).
int n = 4;
struct node
{
int task_index = -1;
double value;
struct node **next;
};
void build_tree(node *current_node, int current_level = 0)
{
if (current_level < 1 || current_level >= n)
return;
// current_node->task_index = ? ;
current_node->next = new node *[n - current_level];
for (int i = 0; i < n - current_level; i++)
{
build_tree(current_node->next[i], current_level + 1);
}
}
void print_tree(node *current_node, int current_level = 0)
{
// print indexes
}
void delete_tree(node *current_node, int current_level = 0)
{
// delete nodes
}
int main()
{
struct node *root = new node;
build_tree(root);
print_tree(root);
delete_tree(root);
delete root;
return 0;
}
void build_tree(node *current_node, int current_level = 0)
{
if (current_level < 1 || current_level >= n)
return;
// current_node->task_index = ? ;
current_node->next = new node *[n - current_level];
for (int i = 0; i < n - current_level; i++)
{
build_tree(current_node->next[i], current_level + 1);
}
}
When called with the default parameter of current_level = 0, as you illustrate in your code below, this function exits on the first line without doing anything. You need to decide whether you are indexing starting from 0 or from 1.
Other than that, the general outline of the algorithm looks okay, although I did not explicitly check for correctness.
Now, more broadly: is this an exercise to see if you can write a tree structure, or are you trying to get the job done? In the latter case you probably want to use a prebuilt data structure like that in the boost graph library.
If it's an exercise in building a tree structure, is it specifically an exercise to see if you can write code dealing with raw pointers-to-pointers? If not, you should work with the correct C++ containers for the job. For instance you probably want to store the list of child nodes in a std::vector rather than have a pointer-to-pointer with the only way to tell how many child nodes exist being the depth of the node in the tree. (There may be some use case for such an extremely specialized structure if you are hyper-optimizing something for a very specific reason, but it doesn't look like that's what's going on here.)
From your explanation what you are trying to build is a data structure that reuses sub-trees for common permutations:
012 -> X
210 -> X
such that X is only instantiated once. This, of course, is recursive, seeing as
01 -> Y
10 -> Y
Y2 -> X
If you look at it closely, there are 2^n such subtrees, because any prefix can have any one of the n input tasks used or not. This means you can represent the subtree as an index into an array of size 2^n, with a total footprint O(n*2^n), which improves on the vastly larger >n! tree:
struct Edge {
std::size_t task;
std::size_t sub;
};
struct Node {
std::vector<Edge> successor; // size in [0,n]
};
std::vector<Node> permutations; // size exactly 2^n
This will have this structure:
permutations: 0 1 2 3 4 ...
|-^
|---^
|-------^
|---^
|-^
Where the node at, e.g., location 3 has both task 0 and 1 already used and "points" to all (n-2) subtrees.
Of course, building this is not entirely trivial, but it compressed the search space and allows you re-use results for specific sub-trees.
You can build the table like this:
permutations.resize(1<<n);
for (std::size_t i = 0; i < size(permutations); ++i) {
permutations[i].successor.reserve(n); // maybe better heuristic?
for (std::size_t j = 0; j < n; ++j) {
if (((1<<j) & i) == 0) {
permutations[i].successor.push_back({j,(1<<j)|i});
}
}
}
Here is a live demo for n=4.
The recursive way to generate permutations is if you have n items then all of the permutations of the items are each of the n items concatenated with the permutations of the n-1 remaining items. In code this is easier to do if you pass around the collection of items.
Below I do it with an std::vector<int>. Once using a vector it makes more sense to just follow the "rule of zero" pattern and let the nodes have vectors of children and then not need to dynamically allocate anything manually:
#include <vector>
#include <algorithm>
#include <iostream>
struct node
{
int task_index = -1;
double value;
std::vector<node> next;
};
std::vector<int> remove_item(int item, const std::vector<int>& items) {
std::vector<int> output(items.size() - 1);
std::copy_if(items.begin(), items.end(), output.begin(),
[item](auto v) {return v != item; }
);
return output;
}
void build_tree(node& current_node, const std::vector<int>& tasks)
{
auto n = static_cast<int>(tasks.size());
for (auto curr_task : tasks) {
node child{ curr_task, 0.0, {} };
if (n > 1) {
build_tree(child, remove_item(curr_task, tasks));
}
current_node.next.emplace_back(std::move(child));
}
}
void print_tree(const node& current_node)
{
std::cout << "( " << current_node.task_index << " ";
for (const auto& child : current_node.next) {
print_tree(child);
}
std::cout << " )";
}
int main()
{
node root{ -1, 0.0, {} };
build_tree(root, { 1, 2, 3 });
print_tree(root);
return 0;
}

Delete Zero in ArrayList in C++

Inside the ArrayList I'm trying to delete all possible 0's that are appended as input, but for now it only deletes just one 0, no matter where it is located. But seems like I can't delete more than one zero at the time. How can I fix this?
void AList::elimZeros(){
int i;
int curr = 0;
for(i=0; i < listSize; i++) {
if ( (listArray[i] != 0 ) && (curr<listSize) ){
listArray[curr] = listArray[i];
curr++;
}
else if (listArray[i] == 0 )
{
listArray[curr] = listArray[i+1];
listSize--;
curr++;
}
}
}
This is the class for the ADT
class AList : public List {
private:
ListItemType* listArray; // Array holding list elements
static const int DEFAULT_SIZE = 10; // Default size
int maxSize; // Maximum size of list
int listSize; // Current # of list items
int curr; // Position of current element
// Duplicates the size of the array pointed to by listArray
// and update the value of maxSize.
void resize();
public:
// Constructors
// Create a new list object with maximum size "size"
AList(int size = DEFAULT_SIZE) : listSize(0), curr(0) {
maxSize = size;
listArray = new ListItemType[size]; // Create listArray
}
~AList(); // destructor to remove array
This is the input I'm testing with:
int main() {
AList L(10);
AList L2(20);
L.append(10);
expect(L.to_string()=="<|10>");
L.append(20);
expect(L.to_string()=="<|10,20>");
L.append(30);
L.append(0);
L.append(40);
L.append(0);
L.append(0);
expect(L.to_string()=="<|10,20,30,0,40>");
L.elimZeros();
expect(L.to_string()=="<|10,20,30,40>");
assertionReport();
}
It'd be helpful if you posted the class code for AList. Think you confused Java's ArrayList type, but assuming you're using vectors you can always just do:
for (int i = 0; i < listSize; i++) {
if(listArray[i] == 0) listArray.erase(i);
}
EDIT: Assuming this is the template of for the AList class, then there is simply a remove() function. In terms of your code, there are two issues.
You reference listSize in the for loop, then decrement it inside of the loop. Each iteration evaluates the value separately so you're reducing the number of total loop iterations and stopping early.
The other thing is if the entry is zero you shouldn't increment curr and set listArray[curr] = listArray[i+1]. This is basically assuming the next entry will not be a zero. So if it is, then you're copying the element and moving to the next. Your if statement can be cleaned up with:
if (listArray[i] == 0) {
listSize--;
} else {
listArray[curr] = listArray[i];
curr++;
}

Trying to find two random nodes and swap them in a doubly linked list

This program is basically just suppose to shuffle a deck of cards. The cards are stored in a doubly linked list, so 52 nodes. I'm getting a read access error in the getNode function, but I'm pretty sure my loop is correct, so I think the error is stemming from somewhere else. Maybe the swap function. My first step is getting pointers to the nodes that I'm trying to swap.
So I made a function, and I'm pretty sure it's right, except I'm wondering if I should be returning *traverseP instead of just traverseP. I don't think so, because I want to return a pointer to the node, not the value inside the node.
template<class T>
typename ReorderableList<T>::Node *ReorderableList<T>::getNode(int i) const
{
int count = 0;
for (Node *traverseP = firstP; traverseP != NULL; traverseP = traverseP->nextP) {
if (count == i)
return traverseP;
count++;
}
return NULL;
}
Next I made a swap function that take two ints, they represent the values I'm passing into the getNode function
template<class T>
void ReorderableList<T>::swap(int i, int j)
{
// Get pointers to ith and jth nodes.
Node *iPtr = getNode(i);
Node *jPtr = getNode(j);
//create temp Node and store the pointers
Node *temp = new Node;
temp = iPtr->prevP;
temp = iPtr->nextP;
//adjust the iPtr next/prev pointers
iPtr->prevP = jPtr->prevP;
iPtr->nextP = jPtr->nextP;
//adjust the jPtr next/prev pointers
jPtr->prevP = temp->prevP;
jPtr->nextP = temp->prevP;
//I'm a little unclear on these lines. I think they're checking if
//iPtr and jPtr have null pointers. I've tried making them equal jPtr and
//iPtr and that strangly didn't make any difference.
if (iPtr->prevP)
iPtr->prevP->nextP = jPtr;
if (iPtr->nextP)
iPtr->nextP->prevP = jPtr;
if (jPtr->prevP)
jPtr->prevP->nextP = iPtr;
if (jPtr->nextP)
jPtr->nextP->prevP = iPtr;
delete temp;
}
This is the shuffle function where this whole shabang kicks off
template<class T>
void randomShuffle(ReorderableList<T> &list, int n)
{
int randNum = 0;
for (int i = n-1; i > 0; i--)
{
randNum = (rand() & (i + 1));
if (randNum > i)
std::swap(randNum, i);
list.swap(randNum, i);
}
}
I've checked a couple different resources for the swap function and found two that both claimed they were correct, but they looked different to me.
Resource 1
Resource 2

How to add elements to a vector and traverse it simultaneously?

I want to perform BFS on a tree, to find out a certain leaf, but the graph is dynamic in nature, when I land on a leaf and that leaf isn't the one I am looking for, then its children are computed from the leaf (The leaf is no longer a leaf it is a node).
I tried two implementations , and both produced erronous results. I think the pointers are getting invalidated or this is an incorrect implementation. My code is as follows
int y=0;
while(graph.end() - graph.begin() < 262145 and graph.end() - graph.begin() < y){
if(found(graph[y])){
clock2 = graph[y];
break;
}
else{
if(graph[y].b[0] < 4) graph.push_back(move1(graph[y]));
if(graph[y].b[1] < 4) graph.push_back(move2(graph[y]));
}
y++;
}
and the next implementation was something like this
for(vector<foo> :: iterator i = graph.begin();i!=graph.end();i++){
if(found(*i)){
clock2 = *i;
break;
}
else{
if(i->b[0] < 4) graph.push_back(move1(*i));//move1 and move2 are
if(i->b[1] < 4) graph.push_back(move2(*i));//functions of return type foo
}
}
Both of these are causing the programme to crash. What is wrong with them, how to implement these? Please comment with additional queries.
I am a little confused as too what exactly is going on and what exactly you are asking. But if you are asking how to preform a simple BFS on a graph here is some sample code that I find pretty easy to read.
Comment further and I will change it to try and match the exact criteria of the question (once I have some more clarity that is)
struct node{
std::vector children<node*>;
int data;
}
void bfs(node* root, int value){ // THIS IS CHECK FOR INTS so change for whatever value
if(!root) return;
std::queue myq;
myq.push(root);
node* toCheck;
while(!myq.Empty()){
toCheck = myq.top();
myq.pop();
if(toCheck->data == value){
//do whatever you want with that information
}else{
/*
//forloop/whileloop as many times as necessary to set all the new children
//Example:
node* newNode = new node();
newNode->data = someValue; // just some information that you want to add
toCheck->children.push_back(newNode);
*/
}
for(int i = 0; i < toCheck->children.size(); i++){
myq.push(toCheck->children[i]);
}
}
}

Implementing min function

Good day, I found this priority queue implementation and I am trying to get a min version of it (instead of max). I have no idea where to start. I tried mixing the signs of the functions (naive attempt) but it didn't get me far. Any help of how to implement it and a few words explaining it are very wellcome. The source is below:
Note I have left it's comments
#include <iostream>
#include <vector>
#include <assert.h>
using namespace std;
class PriorityQueue
{
vector<int> pq_keys;
void shiftRight(int low, int high);
void shiftLeft(int low, int high);
void buildHeap();
public:
PriorityQueue(){}
PriorityQueue(vector<int>& items)
{
pq_keys = items;
buildHeap();
}
/*Insert a new item into the priority queue*/
void enqueue(int item);
/*Get the maximum element from the priority queue*/
int dequeue();
/*Just for testing*/
void print();
};
void PriorityQueue::enqueue(int item)
{
pq_keys.push_back(item);
shiftLeft(0, pq_keys.size() - 1);
return;
}
int PriorityQueue::dequeue()
{
assert(pq_keys.size() != 0);
int last = pq_keys.size() - 1;
int tmp = pq_keys[0];
pq_keys[0] = pq_keys[last];
pq_keys[last] = tmp;
pq_keys.pop_back();
shiftRight(0, last-1);
return tmp;
}
void PriorityQueue::print()
{
int size = pq_keys.size();
for (int i = 0; i < size; ++i)
cout << pq_keys[i] << " ";
cout << endl;
}
void PriorityQueue::shiftLeft(int low, int high)
{
int childIdx = high;
while (childIdx > low)
{
int parentIdx = (childIdx-1)/2;
/*if child is bigger than parent we need to swap*/
if (pq_keys[childIdx] > pq_keys[parentIdx])
{
int tmp = pq_keys[childIdx];
pq_keys[childIdx] = pq_keys[parentIdx];
pq_keys[parentIdx] = tmp;
/*Make parent index the child and shift towards left*/
childIdx = parentIdx;
}
else
{
break;
}
}
return;
}
void PriorityQueue::shiftRight(int low, int high)
{
int root = low;
while ((root*2)+1 <= high)
{
int leftChild = (root * 2) + 1;
int rightChild = leftChild + 1;
int swapIdx = root;
/*Check if root is less than left child*/
if (pq_keys[swapIdx] < pq_keys[leftChild])
{
swapIdx = leftChild;
}
/*If right child exists check if it is less than current root*/
if ((rightChild <= high) && (pq_keys[swapIdx] < pq_keys[rightChild]))
{
swapIdx = rightChild;
}
/*Make the biggest element of root, left and right child the root*/
if (swapIdx != root)
{
int tmp = pq_keys[root];
pq_keys[root] = pq_keys[swapIdx];
pq_keys[swapIdx] = tmp;
/*Keep shifting right and ensure that swapIdx satisfies
heap property aka left and right child of it is smaller than
itself*/
root = swapIdx;
}
else
{
break;
}
}
return;
}
void PriorityQueue::buildHeap()
{
/*Start with middle element. Middle element is chosen in
such a way that the last element of array is either its
left child or right child*/
int size = pq_keys.size();
int midIdx = (size -2)/2;
while (midIdx >= 0)
{
shiftRight(midIdx, size-1);
--midIdx;
}
return;
}
int main()
{
//example usage
PriorityQueue asd;
asd.enqueue(2);
asd.enqueue(3);
asd.enqueue(4);
asd.enqueue(7);
asd.enqueue(5);
asd.print();
cout<< asd.dequeue() << endl;
asd.print();
return 0;
}
Well generally in such problems, i.e. algorithms based on comparison of elements, you can redefine what does (a < b) mean. (That is how things in standard library work by the way. You can define your own comparator.)
So if you change it's meaning to the opposite. You will reverse the ordering.
You need to identify every comparison of elements, and switch it. So for every piece of code like this
/*if child is bigger than parent we need to swap*/
if (pq_keys[childIdx] > pq_keys[parentIdx])
invert it's meaning/logic.
Simple negation should do the trick:
/*if child is NOT bigger than parent we need to swap*/
if !(pq_keys[childIdx] > pq_keys[parentIdx])
You do not even need to understand algorithm. Just inverse meaning of what lesser element is.
Edit:
Additional note. You could actually refactor it into some kind of bool compare(T a, T b). And use this function where comparison is used. So whenever you want to change the behaviour you just need to change one place and it will be consistent. But that is mostly to avoid work to look for every such occurrence, and stupid bugs and when you miss one.
Easier:
std::prioroty_queue<int, std::vector<int>, std::greater<int>> my_queue;
If this is part of an exercise, then I suggest following the standard library's design principles: split the problem up:
data storage (e.g. std::vector)
sorting or "heapifying" algorithm (c.f. std::make_heap etc.)
ordering criteria (to be used by 2. above)
Your class should give you some leeway to change any of these independently. With that in place, you can trivially change the "less-than" ordering for a "greater than" one.