Find 2nd Key in BST - c++

I posted something yesterday and got some help to get started, and I feel like I am almost there now. I have created a BST, with the primary key as a name, and the secondary key as that persons weight. I have managed to finish everything I need except for searching for the lowest weight (secondary key). My method to search the minimum weight is a preorder traversal, and it outputs all of the weights correctly to the screen. What is the technique to go about for determining which is the lowest now? I've tried a few different if statements, and creating a minwt int, but am having no luck getting to work (I think it has something to do with the recursion). Anyways, here is the code. Any help, like always, is greatly appreciated. Thanks.
#include <iostream>
using namespace std;
class tNode
{
public:
string name;
int wt;
tNode *left, *right;
tNode()
{
left = right = 0;
}
tNode(string name, int wt, tNode *l = 0, tNode *r = 0)
{
this->name = name;
this->wt = wt;
left = l;
right = r;
}
};
class bSTree
{
public:
tNode *root;
bSTree()
{
root = 0;
}
bool add(string name, int wt)
{
tNode *temp = root, *prev = 0;
while (temp != 0)
{
prev = temp;
if (name < temp->name)
{
temp = temp->left;
}
else
{
temp = temp->right;
}
}
if (root == 0)
{
root = new tNode(name, wt);
}
else if (name < prev->name)
{
prev->left = new tNode(name, wt);
}
else if (name > prev->name)
{
prev->right = new tNode(name, wt);
}
else
{
return false;
}
return true;
}
void searchWeight(tNode* temp)
{
// DETERMINE LOWEST WEIGHT CONTAINED IN TREE
if (temp != 0)
{
cout << temp->wt << endl;
searchWeight(temp->left);
searchWeight(temp->right);
}
}
};

You need some temporary variables to hold the lowest weight and associated key. They need to be accessible outside of the scope of your searchWeight() function. For example:
#include <iostream>
using namespace std;
int lowest_weight = 999999; // Something sufficiently high
string lowest_weight_key;
class tNode
{
/*...*/
void searchWeight(tNode* temp)
{
// DETERMINE LOWEST WEIGHT CONTAINED IN TREE
if (temp != 0)
{
// if temp->wt is lower than lowest weight
// set lowest_weight equal to temp->wt
// and set lowest_weight_key equal to temp->name
cout << temp->wt << endl;
searchWeight(temp->left);
searchWeight(temp->right);
}
}
};
Now, just print out the values of lowest_weight and lowest_weight_key after calling searchWeight().

Related

basic insertion sort in linked list with logic problem (maybe it is because pointer)

I write a code for insertion sort for integer data in linked list in c++, I referred to the algorithms on the Internet, and finally took the following code using array as a basic concept for my version.
however, the sorting always ignore my first element,(but all the other element is ordered well).
I have tried checking my loop statement, checking the pointer address while looping (because my key pointer loop at first time didn't go into the judge pointer loop), checking the shifting mechanism while comparing, but I cannot find my logic problem.
(I know someone would said I doesn't provide enough data for you to help me, but I have been checking these things for two days, including asking friends and searching the solutions existed on website. So I really hope someone can answer me without blame, thank you.)
array version(on the internet)
#include <iostream>
void InsertionSort(int *arr, int size){
for (int i = 1; i < size; i++) {
int key = arr[i];
int j = i - 1;
while (key < arr[j] && j >= 0) {
arr[j+1] = arr[j];
j--;
}
arr[j+1] = key;
}
}
linked list version(by my own)
Node class used in my version
class Node
{
public:
Node()
{
next = NULL;
pre = NULL;
}
Node(int n)
{
data = n;
next = NULL;
pre = NULL;
}
int getData() { return data; }
Node *getNext() { return next; }
Node *getPre() { return pre; }
void setData(int d) { data = d; }
void setNext(Node *n) { next = n; }
void setPre(Node *p) { pre = p; }
private:
int data;
Node *next, *pre;
};
class List
{
public:
List() { list = NULL; }
List(int n) { generate(n); }
void generate(int n)
{
int j;
list = NULL;
for(j = 0;j < n;j ++)
generate();
}
void generate()
{
Node *buf = new Node(rand());
buf->setNext(list); //list->NODE2.next->NODE1.next->NULL
if(list != NULL)
list->setPre(buf);
list = buf;
}
void insertionSort()
{
bool breakByCompare;
Node* keyptr;
Node* judgeptr;// judge is the value that is going to compare with key
int key;
for(keyptr = list->getNext(); keyptr != NULL;
keyptr = keyptr->getNext()){
//if we set list as 5,7,6 ; 6 is key
key = keyptr->getData();//store the key value for the setting after shifting
breakByCompare = 0;
for(judgeptr = keyptr->getPre() ; judgeptr->getPre()!= NULL;
judgeptr= judgeptr->getPre()){
//list: 5,7,6 ; 7 is judge
if(judgeptr->getData() > key){
// 7>6, so we shift 7 to the position which was for 6
judgeptr->getNext()->setData(judgeptr->getData());// list: 5,7,7 ;
cout << judgeptr->getData() << " , " << keyptr->getData() << endl;
}
else{
break;
}
}
judgeptr->getNext()->setData(key);// list: 5,6,7
}
}
void print()
{
Node *cur = list;
while(cur != NULL)
{
cout<<cur->getData()<<" ";
cur = cur->getNext();
}
cout<<endl;
}
private:
Node *list;
};
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <ctime>
#define SIZE 100
int main()
{
srand(time(NULL));
List *l = new List(10);
l->print();
l->insertionSort();
l->print();
}
One of the most important difference between a linked list and an array is that it is sometimes required to handle the first element as a special case.
Here is a fixed version of your sorting method :
void insertionSort()
{
bool breakByCompare;
Node* keyptr;
Node* judgeptr;
int key;
for(keyptr = list->getNext(); keyptr != NULL; keyptr = keyptr->getNext()){
key = keyptr->getData();
breakByCompare = 0;
// I replaced judgeptr->getPre() by judgeptr in the condition
// to allow the backward loop to go until the root
for(judgeptr = keyptr->getPre() ; judgeptr != NULL; judgeptr= judgeptr->getPre()){
if(judgeptr->getData() > key){
judgeptr->getNext()->setData(judgeptr->getData());
cout << judgeptr->getData() << " , " << key << endl;
}
else break;
}
// Here is the special case : we must support a null judgeptr
// and replace its next element by the list
if (judgeptr) judgeptr->getNext()->setData(key);
else list->setData(key);
}
}

Implementing a recursive Void function (Finding height of Binary Search Tree)

I need to implement a void function that computes the height of each node in a binary tree and stores it in each node. I've found a few solutions online that are recursive in nature but they return int. Examples include (https://www.geeksforgeeks.org/write-a-c-program-to-find-the-maximum-depth-or-height-of-a-tree/). The difference between the model answer, besides that it is not a void function, is that it also does not store the height in each node.
This is my attempt at the solution, but I can't seem to get the code to work, nor refit the model answer to recursively apply in a void function. When I run my code in the helper code to test, it doesn't even show any output.
void computeHeight(Node *n) {
Node* ltraverser = n;
Node* rtraverser = n;
int lheight = 0;
int rheight =0;
if (n == NULL) {
n->height = 0;
}
while (ltraverser->left != NULL) {
ltraverser = ltraverser->left;
lheight += 1;
}
while (rtraverser->right != NULL) {
rtraverser = rtraverser->right;
lheight += 1;
}
if (lheight > rheight) {
n->height = lheight;
}
else {
n->height = rheight;
}
computeHeight(n->left);
computeHeight(n->right);
}
For reference:
The starter code below defines a class called "Node" that has two child pointers ("left" , "right") and an integer "height" member variable. There is also a constructor Node() that initializes the children to nullptr and the height to -1.
/*
The height of a node is the number of edges in
its longest chain of descendants.
Implement computeHeight to compute the height
of the subtree rooted at the node n. Note that
this function does not return a value. You should
store the calculated height in that node's own
height member variable. Your function should also
do the same for EVERY node in the subtree rooted
at the current node. (This naturally lends itself
to a recursive solution!)
Assume that the following includes have already been
provided. You should not need any other includes
than these.
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
You have also the following class Node already defined.
You cannot change this class definition, so it is
shown here in a comment for your reference only:
class Node {
public:
int height; // to be set by computeHeight()
Node *left, *right;
Node() { height = -1; left = right = nullptr; }
~Node() {
delete left;
left = nullptr;
delete right;
right = nullptr;
}
};
*/
For testing the code
// This function prints the tree in a nested linear format.
void printTree(const Node *n) {
if (!n) return;
std::cout << n->height << "(";
printTree(n->left);
std::cout << ")(";
printTree(n->right);
std::cout << ")";
}
Node *n = new Node();
n->left = new Node();
n->right = new Node();
n->right->left = new Node();
n->right->right = new Node();
n->right->right->right = new Node();
computeHeight(n);
printTree(n);
std::cout << std::endl << std::endl;
printTreeVertical(n);
delete n;
n = nullptr;
return 0;
}
Instead of returning node height just recurisvely call computeHeight on left and right nodes, then store maximum height in node structure.
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
#include <algorithm>
class Node {
public:
int height;
Node *left, *right;
Node() { height = -1; left = right = nullptr; }
~Node() {
delete left;
left = nullptr;
delete right;
right = nullptr;
}
};
void computeHeight(Node *node) {
if (node == nullptr) {
return;
}
computeHeight(node->left);
computeHeight(node->right);
int leftHeight = -1;
int rightHeight = -1;
if (node->left != nullptr) {
leftHeight = node->left->height;
}
if (node->right != nullptr) {
rightHeight = node->right->height;
}
node->height = std::max(leftHeight, rightHeight) + 1;
}
void printNode(Node *n, int level = 0) {
if (n == nullptr) {
return;
}
std::cout << std::string(level * 2, ' ') << "Height = " << n->height << "\n";
printNode(n->left, level + 1);
printNode(n->right, level + 1);
}
int main() {
Node *n = new Node();
n->left = new Node();
n->right = new Node();
n->right->left = new Node();
n->right->right = new Node();
n->right->right->right = new Node();
computeHeight(n);
printNode(n);
}
Your mistake is on the following part and because of this you program exits without showing the error
if (n == NULL) {
n->height = 0;
}
When n is NULL; you should not try to access n->height. Replace it as follows and your code will work:
if (n == NULL) {
return;
}
Also, as the other answer mentioned, when you want to compute height recursively, you don't need a while loop just use the following recursive formula:
Height(n) = 1 + max(Height(n->left), Height(n->right))
Also, for consistency reasons usually the height of NULL subtree is defined to be -1. This allows the recursive formula to work properly.
Word of advice: In order to debug any program, an easy way is to just print messages before and after function calls and/or certain lines. This way by checking which messages are not printed, you can quickly pinpoint which functions/lines are causing a problem and then investigate them.

Alphabetically sorted links in doubly linked list

I've been having some trouble getting my program to insert given names along with their weights in a linked list which has a respective link for names and weights, which are both to be sorted in ascending / alphabetical order. The weight links work fine but I can't seem to identify what I'm getting wrong in my name linker. Any help would be greatly appreciated. The problem most likely lies in the insertName() private function.
#include <iostream>
#include <string>
using namespace std;
class DoublyLinkedList
{
public:
void insert(string name, double weight);
void printNameAsc();
void printWeightAsc();
private:
struct Node
{
string name;
double weight;
Node* nextName;
Node* nextWeight;
};
Node* nameHead = NULL;
Node* weightHead = NULL;
Node* newP = NULL;
void insertName();
void insertWeight();
};
void DoublyLinkedList::insert(string name, double weight)
{
// variable declaration
newP = new Node;
newP->name = name;
newP->weight = weight;
newP->nextName = NULL;
newP->nextWeight = NULL;
// empty first element check
if (nameHead == NULL && weightHead == NULL)
{
nameHead = newP;
weightHead = newP;
return;
}
// name and weight insertion
insertName();
insertWeight();
return;
}
void DoublyLinkedList::insertName()
{
Node* activeP = nameHead;
Node* prevP = NULL;
// traversing through name links
while (true)
{
if (activeP == NULL)
{
break;
}
if ((activeP->name).compare(newP->name))
{
break;
}
prevP = activeP;
activeP = activeP->nextName;
}
//insertion
newP->nextName = activeP;
if (activeP == nameHead)
{
nameHead = newP;
}
else
{
prevP->nextName = newP;
}
return;
}
void DoublyLinkedList::insertWeight()
{
Node* activeP = weightHead;
Node* prevP = NULL;
// traversing through weight links
while (true)
{
if (activeP == NULL)
{
break;
}
if (newP->weight < activeP->weight)
{
break;
}
prevP = activeP;
activeP = activeP->nextWeight;
}
//insertion
newP->nextWeight = activeP;
if (activeP == weightHead)
{
weightHead = newP;
}
else
{
prevP->nextWeight = newP;
}
return;
}
void DoublyLinkedList::printNameAsc()
{
Node* activeP = nameHead;
while (activeP != NULL)
{
cout << activeP->name << " " << activeP->weight << endl;
activeP = activeP->nextName;
}
return;
}
void DoublyLinkedList::printWeightAsc()
{
Node* activeP = weightHead;
while (activeP != NULL)
{
cout << activeP->name << " " << activeP->weight << endl;
activeP = activeP->nextWeight;
}
return;
}
int main()
{
DoublyLinkedList nameList;
nameList.insert("Michael", 275);
nameList.insert("Tom", 150);
nameList.insert("Abe", 200);
nameList.printNameAsc();
system("pause");
nameList.printWeightAsc();
system("pause");
return 0;
}
Pretty sure your problem is here:
if ((activeP->name).compare(newP->name) > 0)
{
break;
}
Looks like you're finding the insertion point with activeP. When activeP->name > newP->name, you want to stop searching.
if ((activeP->name).compare(newP->name))
Is invalid, this will evaluate true if activeP < newP (compare statement is -1) or activeP > newP (compare statement is 1), effectively only skipping people with the same names.
Remember, carried over from C, truth is defined as not falseness, which is defined as (!0)
Also, why not just pass a reference of newP to insertName() and insertWeight()? It's good practice to not leave (possibly dangling) pointers stored as member variables.

Using an array of struct counting the number of occurrence of a word in a text file C++

Hi everyone this is my first time in Stackoverflow. I have a question regarding counting the occurrence of words in text file using C++. This is my code so far. I have to create an array struct of index of the word and the counter of each word then store all of them in an AVL tree. After opening the file and read a word, I look for it in the avl tree or trie. If it is there, use the node's index to increment the word's Cnt. If it is not there, add it to the word array and put its position in the next struct and put the structs position in the avl tree. Also I set the struct Cnt to 1. The problem I am having now is it seems like my program doesn't process the counting properly therefore it only prints out 0. Please give me recommendation on how I can fix the bug. Please find my code below:
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
#include <cstring>
#include <ctype.h>
#include <stdio.h>
#include <string>
#include <cctype>
#include <stdlib.h>
#include <stdbool.h>
using namespace std;
struct Node* insert(struct Node* node, int key) ;
void preOrder(struct Node *root) ;
void removePunct(char str[]);
int compareWord(char word1[], char word2[] );
struct Stats {
int wordPos, wordCnt;
};
Stats record[50000];
int indexRec = 0;
char word[50000*10] ;
int indexWord = 0;
int main() {
ifstream fin;
string fname;
char line[200], wordArray[500000];
cout << "Enter the text file name:" << endl;
cin >> fname;
fin.open(fname.c_str());
if (!fin) {
cerr << "Unable to open file" << endl;
exit(1);
}
struct Node *root = NULL;
while (!fin.eof() && fin >> line) { //use getline
for(int n=0,m=0; m!=strlen(line); m+=n) {
sscanf(&line[m],"%s%n",word,&n);
removePunct(word);
//strcpy(&wordArray[indexWord],word);
int flag = compareWord(wordArray, word);
if(flag==-1) {
strcpy(&wordArray[indexWord],word);
record[indexRec].wordPos = indexWord;
record[indexRec].wordCnt = 1;
root = insert(root, record[indexRec].wordPos);
indexWord+=strlen(word)+1;
// indexes of the word array
indexRec++;
cout << wordArray[indexWord] << " ";
} else
record[flag].wordCnt++;
cout << record[indexRec].wordCnt;
cout << endl;
}
/*for(int x = 0; x <= i; x++)
{
cout << record[x].wordPos << record[x].wordCnt << endl;
}*/
}
fin.close();
return 0;
}
void removePunct(char str[]) {
char *p;
int bad = 0;
int cur = 0;
while (str[cur] != '\0') {
if (bad < cur && !ispunct(str[cur]) && !isspace(str[cur])) {
str[bad] = str[cur];
}
if (ispunct(str[cur]) || isspace(str[cur])) {
cur++;
} else {
cur++;
bad++;
}
}
str[bad] = '\0';
for (p= str; *p!= '\0'; ++p) {
*p= tolower(*p);
}
return;
}
int compareWord(char word1[], char word2[] ) {
int x = strcmp(word1, word2);
if (x == 0 ) return x++;
if (x != 0) return -1;
}
struct Node {
int key;
struct Node *left;
struct Node *right;
int height;
};
// A utility function to get maximum of two integers
int max(int a, int b);
// A utility function to get height of the tree
int height(struct Node *N) {
if (N == NULL)
return 0;
return N->height;
}
// A utility function to get maximum of two integers
int max(int a, int b) {
return (a > b)? a : b;
}
/* Helper function that allocates a new node with the given key and
NULL left and right pointers. */
struct Node* newNode(int key) {
struct Node* node = (struct Node*)
malloc(sizeof(struct Node));
node->key = key;
node->left = NULL;
node->right = NULL;
node->height = 1; // new node is initially added at leaf
return(node);
}
// A utility function to right rotate subtree rooted with y
// See the diagram given above.
struct Node *rightRotate(struct Node *y) {
struct Node *x = y->left;
struct Node *T2 = x->right;
// Perform rotation
x->right = y;
y->left = T2;
// Update heights
y->height = max(height(y->left), height(y->right))+1;
x->height = max(height(x->left), height(x->right))+1;
// Return new root
return x;
}
// A utility function to left rotate subtree rooted with x
// See the diagram given above.
struct Node *leftRotate(struct Node *x) {
struct Node *y = x->right;
struct Node *T2 = y->left;
// Perform rotation
y->left = x;
x->right = T2;
// Update heights
x->height = max(height(x->left), height(x->right))+1;
y->height = max(height(y->left), height(y->right))+1;
// Return new root
return y;
}
// Get Balance factor of node N
int getBalance(struct Node *N) {
if (N == NULL)
return 0;
return height(N->left) - height(N->right);
}
// Recursive function to insert key in subtree rooted
// with node and returns new root of subtree.
struct Node* insert(struct Node* node, int key) {
/* 1. Perform the normal BST insertion */
if (node == NULL)
return(newNode(key));
if (key < node->key)
node->left = insert(node->left, key);
else if (key > node->key)
node->right = insert(node->right, key);
else // Equal keys are not allowed in BST
return node;
/* 2. Update height of this ancestor node */
node->height = 1 + max(height(node->left),
height(node->right));
/* 3. Get the balance factor of this ancestor
node to check whether this node became
unbalanced */
int balance = getBalance(node);
// If this node becomes unbalanced, then
// there are 4 cases
// Left Left Case
if (balance > 1 && key < node->left->key)
return rightRotate(node);
// Right Right Case
if (balance < -1 && key > node->right->key)
return leftRotate(node);
// Left Right Case
if (balance > 1 && key > node->left->key) {
node->left = leftRotate(node->left);
return rightRotate(node);
}
// Right Left Case
if (balance < -1 && key < node->right->key) {
node->right = rightRotate(node->right);
return leftRotate(node);
}
/* return the (unchanged) node pointer */
return node;
}
void preOrder(struct Node *root) {
if(root != NULL) {
printf("%d ", root->key);
preOrder(root->left);
preOrder(root->right);
}
}
One problem (I cannot see if this is the only problem) is that you have code like this, deleting all the intermediate lines:
record[indexRec].wordCnt = 1;
if find word fails
indexRec++;
cout << record[indexRec].wordCnt;
So when you have a new word (if I understand the code correctly!) you are printing out the next record. One fix would be:
if (flag==-1)
cout << record[indexRec-1].wordCnt;
else
cout << record[indexRec].wordCnt;
There's a lot of other issues, like compareWord() is very wrong, you should decide if you really want to use C++ or just C with std::cout, the file reading code is odd, you're including both C and C++ versions of standard headers, etc, but these are issues for another question!

Single Link List delete function in the middle issue

I look around for some help for single link list around the web but couldn't find the information I needed. What im trying to do is Design and Implement a single linked list with the following operations
a- Create "n" nodes
b- Delete from the middle (where im not deleting the middle, but anything else but the start and end node)
c- Insert in the middle
I did my "insert" part with a ADD function
but when I get to the delete function, im stuck in how to use a single link list & not a double, because Im trying to break that habit. Anyway here my code, it my delete function that im trying to fix. thanks
PS: tell me if my add function is also correct, :)
#include <iostream>
#include <vector>
using namespace std;
class node
{
public:
node(int user_input);
int info;
node * next_node;
};
node::node(int user_input)
{
info = user_input;
next_node = NULL;
}
class link_list
{
public:
node * start;
node * end;
int size;//seperated the attritibute from the method
link_list(); //default constuctor
link_list(int value); //value constuctor
link_list(int value, int num_of_Nodes); //n-ary
void Add(int store_node);
void Print(); //non midify
void insert_at_begining(int value); //while these guys are modify
void insert_at_end(int value); //
void insert_at_middle(int delete_node);
void delete_at_begining();
void delete_at_end(); //
void delete_at_middle(int Nodes_store);
private:
int Number_of_nodeV2;
};
link_list::link_list(int value, int num_of_Nodes) //this
{
//if val = 0 & num = 5 we get 5 new nodes
Number_of_nodeV2 = 0;
if (num_of_Nodes < 1)
{
cout << "error, please enter correct numbers" << endl;
}
else
{
start = new node(value); //this is pointing to node that has value in it.
//start == NULL;
node* tracker = start;
for (int i = 0; i < num_of_Nodes - 1; i++)
{
tracker->next_node = new node(value); //this track each node //-> de-renecen
tracker = tracker->next_node;
}
}
}
void link_list::Add(int store_node)
{
node* tracker = start;
node* newVal = new node(store_node);
while (tracker->next_node != NULL)
{
tracker = tracker->next_node;
}
tracker->next_node = newVal;
}
void link_list::Print()
{
node* tracker = start;
while (tracker != NULL)
{
cout << tracker->info << endl;
tracker = tracker->next_node;
cout << size;
}
}
void link_list::delete_at_middle(int delete_node)
{
//int center = 0;
node* tracker = start;
node* tracker2 = end;
node* temp;
node* temp1;
temp1 = temp = start;
if (start == NULL)
{
cout << "the list is empy" << endl;
}
else //this is where I cant seem to answer, thanks
{
while (temp != end)
{
temp = temp1->next_node;
if (temp->info = delete_node)
{
delete temp;
temp1->next_node = NULL; //ffffffffffff
}
}
tracker = tracker->next_node;
for (size_t i = 0; i < length; i++)
{
pre = start;
pre
}
//iltertae with tracker until the tracker has hit the center
}
}
int main() {
int Nodes_store = 0;
int delete_node = 0;
cout << "please enter the number of nodes" << endl;
cin >> Nodes_store;
cout << "please enter the number of to delete nodes" << endl;
cin >> delete_node;
link_list list = link_list(0, Nodes_store);
list.Print();
//list.delete_at_middle();
//list.Print();
//
//list.insert_at_middle(7);
//list.Print();
}AS'
;'