C++ How to find the longest possible combination of decreasing numbers in an array - c++

I am working on a problem in which I'm given a list of numbers representing the diameter of cake layers (for example: 9 12 10 7 4 6 11 5). With this list, I have to find the length of the longest combination of numbers that are equal to or decreasing (stacking cake layers from greatest diameter at the bottom to smallest at the top). You are allowed to skip over numbers, but you can't come back to them. I.e. with the previous list, the length of the longest combination would be 5 with the combination being (12,10,7,6,5).
I believe that the best way to solve this would be feeding the array into a tree and returning the height of the tree. This is currently the code I have, with a working tree implementation above the main
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
string sizeInput, transfer; //Strings to hold input and transfer to array
int maxLayers = 0, numOfInputs = 0, numNodes = 0; //ints for holding the max height and the number of inputs by the user
int cakeSizes [30]; //Array holding sizes of the cakes input, no more than 30
cout << "Cake sizes: ";
getline(cin,sizeInput); //Gets input from user and puts into a stringstream
stringstream readInput(sizeInput);
while(readInput >> transfer)
{
cakeSizes[numOfInputs] = stoi(transfer); //Puts the numbers into the array and counts how many were placed
numOfInputs++;
}
for(int i=0; i<numOfInputs; i++) //Puts the array into a tree
{
Tree<int> cakeStack; //Creates tree to hold combination
initialize(cakeStack);
for(int j=i; j<numOfInputs; j++)
{
if(cakeSizes[j]<=cakeSizes[j-1])
{
insert(cakeStack, cakeSizes[j]);
}
}
if(height(cakeStack) > maxLayers) //Checks if the new combination tree's height is greater than the last
{
maxLayers = height(cakeStack);
}
destroy(cakeStack); //Destroys the tree from the previous combination in preparation for new one
}
cout << endl << "You can build a cake with " << maxLayers << " layers.";
}
This actually works for combinations that are always decreasing (like 5,4,2,1 and 8,3,2,1), but it fails when interrupting numbers are thrown in (like with 5,4,2,8,1). I'm almost certain that the problem lies here:
for(int j=i; j<numOfInputs; j++)
{
if(cakeSizes[j]<=cakeSizes[j-1])
{
insert(cakeStack, cakeSizes[j]);
}
}
But I'm unsure of how to implement it an a way that checks all combinations of the array (like skipping numbers that wouldn't give the longest combination), rather than running straight down the list unable to skip numbers.

The tree is definitely the way to go. You build the tree by inserting each value under the smallest node larger than it. Then when the tree is finished you iterate through it looking for the longest path.
What I did in the code below is I made a head node to store the sub trees and it needed a really large value so that all the inputs would fit under it. But then when I print the tree or look for a path I need to ignore that head node, so I have to keep track of the depth.
#include <iostream>
#include <vector>
#include <climits>
struct Tree {
Tree(int value) : value(value) {}
int value;
std::vector<Tree> children;
};
// Recursively check this level of the tree
void insert_node(Tree& node, int value)
{
// if the new value is bigger than where
// we are then stop descending
if (value > node.value)
return;
// if the new value fits under this
// parent then check all the children
bool inserted = false;
for (Tree& child : node.children)
// if we find a child large enough
// then insert ourselves inside
if (value < child.value)
{
insert_node(child, value);
inserted = true;
}
// if the new value fits under this parent but
// not under any of the children then put it here
if (!inserted)
node.children.push_back(value);
}
void print_tree(Tree node,
std::vector<bool> flags = std::vector<bool>(100, true),
bool last = false,
int depth = 0)
{
for (int i = 1; i < depth; ++i)
{
if (flags[i])
std::cout << "| ";
else
std::cout << " ";
}
// Don't print our fake head
if (depth > 0)
{
std::cout << "+- " << node.value << '\n';
if (last) flags[depth] = false;
}
int n = 0;
for (Tree child : node.children)
{
last = (n++ == node.children.size() - 1);
print_tree(child, flags, last, depth + 1);
}
flags[depth] = true;
}
void print_path(std::vector<int> path)
{
std::cout << "Path:";
for (int value : path)
std::cout << " " << value;
std::cout << "\n";
}
void print_paths(Tree node,
std::vector<int>& max_path,
std::vector<int> path = std::vector<int>(),
int depth = 0)
{
// Don't add our fake head
if (depth > 0)
path.push_back(node.value);
if (node.children.size() == 0)
{
print_path(path);
// check if this path is the longest one yet
if (max_path.size() < path.size())
max_path = path;
}
for (Tree child : node.children)
print_paths(child, max_path, path, depth + 1);
}
int main()
{
Tree head(INT_MAX);
std::vector<int> input = {9, 12, 10, 7, 4, 6, 11, 5};
// Build the tree
for (int value : input)
insert_node(head, value);
// Print the tree
std::cout << "Tree:\n";
print_tree(head);
std::cout << "\n";
// Print the paths and
// find the longest one
// and then print it too
std::vector<int> max_path;
print_paths(head, max_path);
std::cout << "\nLongest ";
print_path(max_path);
return 0;
}

Related

if user enter 5 then display the last 5 elements of linked list vise versa

i am stuck in my uni assignment....
i have an linked list of 20 elements, i have to take the value from user and if user enter 5 then print the last 5 elements of linked list
void traverse(List list) {
Node *savedCurrentNode = list.currentNode;
list.currentNode = list.headNode;
for(int i = 1; list.next() == true; i++)
{
std::cout << "Element " << i << " " << list.get() << endl;
}
list.currentNode = savedCurrentNode;
}
im trying this but this method prints all the elements of my linked list
For what little code you have, a review:
// Why are you passing the list by value? That is wasteful.
void traverse(List list) {
// I don't see you taking a value anywhere; surely you know how to do that
// What is happening here? Can't you just assign the head to something
// directly?
Node *savedCurrentNode = list.currentNode;
list.currentNode = list.headNode;
// Like you said, this traverses the entire list, it's also poorly
// formed. You literally don't need i.
// for (; list.next(); /* However your list increments here */)
for(int i = 1; list.next() == true; i++)
{
std::cout << "Element " << i << " " << list.get() << endl;
}
// What is the purpose of this?
list.currentNode = savedCurrentNode;
}
For someone who is writing a linked list, this code seems to be fundamentally flawed. My expectation of someone tackling a linked list is that they are about to stop being a beginner, but I'm not seeing that here in the code and what structure of the list class is implied. The list class is weird to say the least.
And just to be clear, my expectation stems from where I place the linked list assignment in my curriculum. It's also more idiomatic than this list.
With that out of the way, this task is trivial if you took the time to think the project through. Most students skip the planning step and create unnecessary headaches for themselves.
Knowing that you would need the total size of the list, why not just make it member data? Any function that adds to the list will increment the value accordingly. And any function that subtracts from the list will decrement accordingly. That way you always know the size of the list at all times.
Knowing the size of the list is most of the battle. You then need to do the arithmetic necessary to advance in the list to satisfy your requirement. And now you can print.
#include <iostream>
class SList {
public:
SList() = default;
//
// Rule of 5 intentionally left out
//
void push_front(int val) {
m_head = new Node{val, m_head};
++m_size; // The magic happens here
}
std::size_t size() const { return m_size; }
void traverse_last(int numElements, std::ostream& sout = std::cout) const {
int placement = m_size;
Node* walker = m_head;
// Move our walker node the appropriate amount of steps
while (walker && placement > numElements) {
walker = walker->next;
--placement;
}
// Now that we're in position, we can print
while (walker) {
sout << walker->data << ' ';
walker = walker->next;
}
sout << '\n';
}
private:
struct Node {
int data;
Node* next = nullptr;
};
Node* m_head = nullptr;
std::size_t m_size = 0ULL;
};
int main() {
SList test;
for (int i = 5; i > 0; --i) {
test.push_front(i);
}
std::cout << "Size: " << test.size() << '\n';
for (int i = 1; i <= 5; ++i) {
test.traverse_last(i);
}
test.traverse_last(10);
}
Output:
❯ ./a.out
Size: 5
5
4 5
3 4 5
2 3 4 5
1 2 3 4 5
1 2 3 4 5
void traverse(List list, int printFrom)
{
Node *savedCurrentNode = list.currentNode;
list.currentNode = list.headNode;
for(int i=1; list.next(); i++)
{
if(i > printFrom)
{
cout << "Element " << (i - printFrom) << " " << list.get() << endl;
}
}
list.currentNode = savedCurrentNode;
}
solved my prblem by this there printFrom is a variable whose value is number of elemenets that skipped like if my linked list have size of 20 and user want to see last 5 then printFrom stores 15 and skipped 15 values and print last 5

How can you check if a sequence of nodes exists in an undirected graph, where each node is adjacent to the next?

I have an undirected graph of letters in a rectangular format, where each node has an edge to the adjacent neighboring node.
For example:
d x f p
o y a a
z t i b
l z t z
In this graph node "d" is adjacent to [x, y, o].
I want to check if the sequence of nodes "dot" exists in the graph, where each subsequent node is adjacent to the next. The main application is a word search game, where only words with adjacent letters count. For example, the sequence "zap" does NOT count, since the nodes are not adjacent. I do not need to check if the sequence is a real word, only that it is adjacent in the graph.
My graph.h is as follows:
// graph.h
#include <queue>
#include "SLList.h"
#include "DynArray.h"
template<typename Type>
class Graph {
public:
struct Edge {
unsigned int toVertex; // index to vertex the edge connects to
};
struct Vertex {
// the data that this vertex is storing
Type element;
// the list of edges that connect this vertex to another vertex
SLList<Edge> edges;
///////////////////////////////////////////////////////////////////////////
// Function : addEdge
// Parameters : toVertex - the index of the vertex we are adjacent to
///////////////////////////////////////////////////////////////////////////
void addEdge(const unsigned int& toVertex) {
Edge e;
e.toVertex = toVertex;
edges.addHead(e);
}
};
private:
// dynarray of vertices
DynArray<Vertex> vertices;
// helper function to check if a vertex is a in a queue
bool IsInQueue(DynArray<Edge> arrayOfEdges, unsigned int _toVertex) {
for (unsigned int i = 0; i < arrayOfEdges.size(); ++i) {
if (arrayOfEdges[i].toVertex == _toVertex)
return true;
}
return false;
}
public:
/////////////////////////////////////////////////////////////////////////////
// Function : addVertex
// Parameters : value - the data to store in this vertex
// Return : unsigned int - the index this vertex was added at
/////////////////////////////////////////////////////////////////////////////
unsigned int addVertex(const Type& value) {
Vertex v;
v.element = value;
vertices.append(v);
return vertices.size();
}
/////////////////////////////////////////////////////////////////////////////
// Function : operator[]
// Parameters : index - the index in the graph to access
// Return : Vertex& - the vertex stored at the specified index
/////////////////////////////////////////////////////////////////////////////
Vertex& operator[](const unsigned int& index) {
return vertices[index];
}
/////////////////////////////////////////////////////////////////////////////
// Function : size
// Return : unsiged int - the number of vertices in the graph
/////////////////////////////////////////////////////////////////////////////
unsigned int size() const {
return vertices.size();
}
/////////////////////////////////////////////////////////////////////////////
// Function : clear
// Notes : clears the graph and readies it for re-use
/////////////////////////////////////////////////////////////////////////////
void clear() {
// for each node, remove all its edges
// then remove the node from the array
for (unsigned int i = 0; i < vertices.size(); ++i) {
vertices[i].edges.clear();
}
vertices.clear();
}
};
So far I tried:
my algorithm:
finding the starting node
setting a current node to this start node
searching all edges of the current node for the next node in sequence without visiting nodes that have been visited
if next node in sequence is found then current is set to next and next is incremented
if current == end and next == null then return true
else false
However, this does not work every time. For example, it works for "dot", but not "pay" in the above graph. This is because once it visits the second "a" it marks as visited and cannot find "y" anymore. I believe there are other problems with this algorithm.
I have searched other answers on here, but they only explain how to find a path from a start node to an end node, where the path doesn't matter. In this case, the path is what matters.
Solution in c++ using my graph.h preferred.
Here is a simple Depth-First Search-based procedure that attempts to find a path that creates a specified string in a grid of characters. This DFS is an example of a basic brute-force algorithm, as it simply tries all possible paths that could be right. In the below program, I use my own Graph class (sorry), but it should be simple enough to understand. Here is my code in C++:
#include <iostream>
#include <fstream>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
struct Graph{
int rows, cols;
vector <vector<char>> grid;
// DFS: Recursively tries all possible paths - SEE THE BELOW FUNCTION FIRST
void dfs(int r, int c, size_t len, string &str, bool &done, auto &vis, auto &path){
// if (len == str.size()), that means that we've found a path that
// corresponds to the whole string, meaning that we are done.
if(len == str.size()){
done = true;
return;
}
// Check all nodes surrounding the node at row r and column c
for(int next_r = r-1; next_r <= r+1; ++next_r){
for(int next_c = c-1; next_c <= c+1; ++next_c){
// Bounds check on next_r and next_c
if(next_r < 0 || next_r >= rows){continue;}
else if(next_c < 0 || next_c >= cols){continue;}
// KEY: We don't visit nodes that we have visited before!
if(vis[next_r][next_c]){
continue;
}
// ONLY if grid[next_r][next_c] happens to be the next character in str
// that we are looking for, recurse.
if(grid[next_r][next_c] == str[len]){
vis[next_r][next_c] = true;
path.push_back({next_r, next_c});
dfs(next_r, next_c, len + 1, str, done, vis, path);
// If done is true, that means we must've set it to true in
// the previous function call, which means we have found
// a valid path. This means we should keep return-ing.
if(done){return;}
vis[next_r][next_c] = false;
path.pop_back();
}
}
if(done){return;} // see the above comment
}
}
// Returns a vector <pair<int, int>> detailing the path, if any, in the grid
// that would produce str.
vector <pair<int, int>> get_path_of(string &str){
bool done = false;
vector <pair<int, int>> path;
// Try starting a DFS from every possible starting point until we find a valid
// path
for(int r = 0; r < rows; ++r){
for(int c = 0; c < cols; ++c){
vector <vector<bool>> vis(rows, vector <bool> (cols, false));
dfs(r, c, 0, str, done, vis, path);
// Found a path during the above function call! We can return now
if(done){
return path;
}
}
}
return {};
}
Graph(int r, int c){
rows = r;
cols = c;
grid = vector <vector<char>> (r, vector <char> (c));
}
};
int main()
{
// Input in the number of rows and columns in the grid
int R, C;
cin >> R >> C;
Graph G(R, C);
// Input the letters of the grid to G
for(int i = 0; i < R; ++i){
for(int j = 0; j < C; ++j){
cin >> G.grid[i][j];
}
}
// Input the strings to find in G
string str;
while(cin >> str){
vector <pair<int, int>> path = G.get_path_of(str);
cout << "PATH OF " << str << ": ";
for(const pair <int, int> &item : path){
cout << "{" << item.first << ", " << item.second << "} ";
}
cout << "\n";
}
return 0;
}
If you have any questions, please don't hesitate to ask!

Getting a floating point exception error while doing text frequency analysis?

So for a school project, we are being asked to do a word frequency analysis of a text file using dictionaries and bucket hashing. The output should be something like this:
$ ./stats < jabberwocky.txt
READING text from STDIN. Hit ctrl-d when done entering text.
DONE.
HERE are the word statistics of that text:
There are 94 distinct words used in that text.
The top 10 ranked words (with their frequencies) are:
1. the:19, 2. and:14, 3. !:11, 4. he:7, 5. in:6, 6. .:5, 7.
through:3, 8. my:3, 9. jabberwock:3, 10. went:2
Among its 94 words, 57 of them appear exactly once.
Most of the code has been written for us, but there are four functions we need to complete to get this working:
increment(dict D, std::str w) which will increment the count of a word or add a new entry in the dictionary if it isn't there,
getCount(dict D, std::str w) which fetches the count of a word or returns 0,
dumpAndDestroy(dict D) which dumps the words and counts of those words into a new array by decreasing order of count and deletes D's buckets off the heap, and returns the pointer to that array,
rehash(dict D, std::str w) which rehashes the function when needed.
The structs used are here for reference:
// entry
//
// A linked list node for word/count entries in the dictionary.
//
struct entry {
std::string word; // The word that serves as the key for this entry.
int count; // The integer count associated with that word.
struct entry* next;
};
// bucket
//
// A bucket serving as the collection of entries that map to a
// certain location within a bucket hash table.
//
struct bucket {
entry* first; // It's just a pointer to the first entry in the
// bucket list.
};
// dict
//
// The unordered dictionary of word/count entries, organized as a
// bucket hash table.
//
struct dict {
bucket* buckets; // An array of buckets, indexed by the hash function.
int numIncrements; // Total count over all entries. Number of `increment` calls.
int numBuckets; // The array is indexed from 0 to numBuckets.
int numEntries; // The total number of entries in the whole
// dictionary, distributed amongst its buckets.
int loadFactor; // The threshold maximum average size of the
// buckets. When numEntries/numBuckets exceeds
// this loadFactor, the table gets rehashed.
};
I've written these functions, but when I try to run it with a text file, I get a Floating point exception error. I've emailed my professor for help, but he hasn't replied. This project is due very soon, so help would be much appreciated! My written functions for these are as below:
int getCount(dict* D, std::string w) {
int stringCount;
int countHash = hashValue(w, numKeys(D));
bucket correctList = D->buckets[countHash];
entry* current = correctList.first;
while (current != nullptr && current->word < w) {
if (current->word == w) {
stringCount = current->count;
}
current = current->next;
}
std::cout << "getCount working" << std::endl;
return stringCount;
}
void rehash(dict* D) {
// UNIMPLEMENTED
int newSize = (D->numBuckets * 2) + 1;
bucket** newArray = new bucket*[newSize];
for (int i = 0; i < D->numBuckets; i++) {
entry *n = D->buckets->first;
while (n != nullptr) {
entry *tmp = n;
n = n->next;
int newHashValue = hashValue(tmp->word, newSize);
newArray[newHashValue]->first = tmp;
}
}
delete [] D->buckets;
D->buckets = *newArray;
std::cout << "rehash working" << std::endl;
return;
void increment(dict* D, std::string w) {
// UNIMPLEMENTED
int incrementHash = hashValue(w, numKeys(D));
entry* current = D->buckets[incrementHash].first;
if (current == nullptr) {
int originalLF = D->loadFactor;
if ((D->numEntries + 1)/(D->numBuckets) > originalLF) {
rehash(D);
int incrementHash = hashValue(w, numKeys(D));
}
D->buckets[incrementHash].first->word = w;
D->buckets[incrementHash].first->count++;
}
while (current != nullptr && current->word < w) {
entry* follow = current;
current = current->next;
if (current->word == w) {
current->count++;
}
}
std::cout << "increment working" << std::endl;
D->numIncrements++;
}
entry* dumpAndDestroy(dict* D) {
// UNIMPLEMENTED
entry* es = new entry[D->numEntries];
for (int i = 0; i < D->numEntries; i++) {
es[i].word = "foo";
es[i].count = 0;
}
for (int j = 0; j < D->numBuckets; j++) {
entry* current = D->buckets[j].first;
while (current != nullptr) {
es[j].word = current->word;
es[j].count = current->count;
current = current->next;
}
}
delete [] D->buckets;
std::cout << "dumpAndDestroy working" << std::endl;
return es;
A floating-point exception is usually caused by the code attempting to divide-by-zero (or attempting to modulo-by-zero, which implicitly causes a divide-by-zero). With that in mind, I suspect this line is the locus of your problem:
if ((D->numEntries + 1)/(D->numBuckets) > originalLF) {
Note that if D->numBuckets is equal to zero, this line will do a divide-by-zero. I suggest temporarily inserting a line like like
std::cout << "about to divide by " << D->numBuckets << std::endl;
just before that line, and then re-running your program; that will make the problem apparent, assuming it is the problem. The solution, of course, is to make sure your code doesn't divide-by-zero (i.e. by setting D->numBuckets to the appropriate value, or alternatively by checking to see if it is zero before trying to use it is a divisor)

Incorrect count output / Having difficulty trying to create a HashTable/Set using open addressing

I'm trying to create a program that opens a .txt file containing a speech and assigns each word to a space in the array/set based on the hash value. Collisions are accounted for using open addressing method. The program should be able to perform the following functions: add(), remove(), find(), count() which keeps count of the elements IN the array/set, and loadfactor(). A template header.h file was provided that required some filling in, but my unfamiliarity with that style of coding was making it difficult for me to understand it. Below I have provided the code I have so far, and everything seems to be working except the mCount. The speech contains about 300 words but when I run the code, the count output shows 17. I'm assuming the error is in my resizing function but I am unsure.
//hashset.h file
#pragma once
#include <cmath>
#include <functional>
#include <vector>
template <typename TValue, typename TFunc>
class HashSet
{
private:
// Unlike Java, the C++ hashtable array won't be full of null references.
// It will be full of "Entry" objects, each of which tracks its current state
// as EMPTY, FULL (with a value), or NIL (value was once here, but was removed).
class Entry
{
public:
enum EntryState { EMPTY, FULL, NIL };
TValue value;
EntryState state;
Entry() : value(), state(EMPTY) {}
Entry(const TValue& v) : value(v), state(EMPTY) {}
};
TFunc mHash;
std::vector<Entry> mTable;
std::size_t mCount;
public:
// Constructs a hashtable with the given size, using the given function for
// computing h(k).
// hash must be a callable object (function, functor, etc.) that takes a parameter
// of type TValue and returns std::size_t (an integer).
HashSet(int size, TFunc hash) : mHash(hash)
{
// initialize count
mCount = 0;
// hashtable array cannot be same data type as that of what is being stored (cannot be string)
// requirement #4 - if user inputs array size that is not a power of 2, constructor must round to nearest power of 2 value
size = pow(2, (int(log(size - 1) / log(2)) | 1));
mTable.resize(size); // resizes the vector to have given size.
// Each element will be default-constructed to have state EMPTY.
}
void resize(int new_size) {
HashSet aux{ new_size, mHash }; //double the size, same hash function
for (const auto& entry : mTable)
if (entry.state == Entry::FULL && entry.state == Entry::EMPTY && entry.state == Entry::NIL) //there is an element
aux.add(entry.value); //insert it on the new set
*this = aux;
}
// Inserts the given value into the set.
void add(const TValue& value)
{
// Use the type std::size_t for working with hash table indices.
// Invoke the mHash function, passing the key to calculate h(k), as in
// size_t hashCode = mHash(value);
// Mod down to size.
// Go to the table at that index and do the insertion routine.
// Note, if table is full when trying to add an element, it should double in size
// to keep table size a power of 2
if (double(mCount) / mTable.size() > 0.8) // load factor comparison
this->resize(2 * mTable.size()); // call resize function if array is too small to accommodate addition
size_t hashCode = mHash(value) % mTable.size(); // mod value by table size to get starting index
if (mTable[hashCode].state == Entry::EMPTY || mTable[hashCode].state == Entry::NIL) { // NIL space CAN be replaced with value
mTable[hashCode].value = value; // store value in vector index specified by hashCode
mCount++; // increment counter when word is added
}
else {
for (std::size_t i = 1; i < mTable.size(); i++) {
// use open addressing to find next open space
if (mTable[hashCode].state != Entry::EMPTY) {
hashCode = ((mHash(value) % mTable.size()) + ((int)(pow(i, 2) + i) >> 1)) % mTable.size(); // h(k) + f(i) or h(k) + ((i^2 + i)) / 2
}
else if (mTable[hashCode].value == value) { // account for duplicates
break; // exit for-loop
}
else if (mTable[hashCode].state == Entry::EMPTY || mTable[hashCode].state == Entry::NIL) { // NIL space CAN be replaced with value
mTable[hashCode].value = value; // store value in vector index specified by new hashCode
mCount++; // increment counter when word is added
break; // exit for-loop
}
else
break; // exit for-loop
}
}
}
// Returns true if the given value is present in the set.
bool find(const TValue& key)
{
size_t hashCode = mHash(key) % mTable.size(); // mod value by table size to get starting index to do retrace
if (mTable[hashCode].value == key)
return true;
else if (mTable[hashCode].state != Entry::EMPTY || mTable[hashCode].state == Entry::NIL) { // check that set is not empty or has a NIL state
for (std::size_t i = 1; i < mTable.size(); i++) {
// use open addressing again to find key
if (mTable[hashCode].value != key)
hashCode = ((mHash(key) % mTable.size()) + ((int)(pow(i, 2) + i) >> 1)) % mTable.size();
else if (mTable[hashCode].value == key) {
return true; // value found at speecified location
break; // exit for-loop as first instance of value has been found
}
//else if (i == mTable.size()) // end of table reached, element not in set
//return false;
}
}
else // end of table reached, element was not in set
return false;
}
// Removes the given value from the set.
void remove(const TValue& key)
{
size_t hashCode = mHash(key) % mTable.size(); // mod value by table size to get starting index to do retrace
if (mTable[hashCode].value == key) {
mTable[hashCode].value = Entry::NIL; // replace value with NIL so find() op does not return a false when searching for element
mCount--; // decrement element counter
}
else if (mTable[hashCode].state != Entry::EMPTY || mTable[hashCode].state != Entry::NIL) { // check that there is a value to be removed
for (std::size_t i = 1; i < mTable.size(); i++) {
// use open addressing again to find key
if (mTable[hashCode].value != key) {
hashCode = ((mHash(key) % mTable.size()) + ((int)(pow(i, 2) + i) >> 1)) % mTable.size();
}
else {
mTable[hashCode].value = Entry::NIL; // if found after open addressing, replace with NIL
mCount--; // decrement element counter
}
}
}
}
int count() {
return mCount;
}
double loadFactor() {
double a = double(mCount) / mTable.size();
return a;
}
};
// main function
#include "hashset.h"
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
string testline;
vector<string> word;
HashSet<std::string, std::hash<std::string> > obj1{ 50, std::hash<std::string>{} };
ifstream Test("speech.txt");
if (!Test)
{
cout << "There was an error opening the file.\n";
return 0;
}
//store words in vector
while (Test >> testline) {
word.push_back(testline);
//obj1.add(testline);
}
//output whole vector with position numbers for each entry
cout << "Array contents:\n";
for (int i = 0; i < word.size(); i++) {
obj1.add(word[i]);
cout << word[i] << "(" << i << ")" << endl;
}
cout << "current count: " << obj1.count() << endl;
obj1.add("abcd"); // should hash to 4
if (obj1.find("abcd"))
cout << "abcd is in the set " << endl;
else
cout << "abcd is not in set " << endl;
obj1.add("adcb"); // should hash to 4 then 5 after probing
if (obj1.find("adcb"))
cout << "adcb is in the set " << endl;
else
cout << "adcb is not in set " << endl;
obj1.add("acde"); // should hash to 4 then 7 after probing
if (obj1.find("acde"))
cout << "acde is in the set " << endl;
else
cout << "acde is not in set " << endl;
obj1.remove("adcb"); // 5 should have NIL
if (obj1.find("adcb"))
cout << "adcb is in the set " << endl;
else
cout << "adcb is not in set " << endl;
if (obj1.find("acde"))
cout << "acde is still in the set " << endl;
else
cout << "acde is not in set " << endl;
cout << "final count: " << obj1.count() << endl;
system("pause");
exit(0);
}
}
The errors around NIL are because the enum defining NIL is part of the Entry class. You need to prefix NIL with the class name so the compile knows where the keyword comes from.
else if (mTable[hashCode] != NULL || mTable == Entry::NIL) { // getting error NIL identifier not found
The HashSet variable declaration is complaining because you are passing the wrong types. HashSet constructor takes a size and and a hash function. You are passing it a size and a string. Note the comment above the HashSet constructor
// hash must be a callable object (function, functor, etc.) that takes a parameter
// of type TValue and returns std::size_t (an integer).
This is your clue how to construct a HashSet object.

How to go about making a "Sorted Array to Balanced BST" recursion algorithm to an iterative one?

I've searched around but can't really understand or find help, since this iterative algorithm will require two stacks (to contain a left_Index and right_Index).
The main recursive way involves having it one side until the left_Index >= right_Index, and recursively doing so for both sides and per subsection (if that makes sense), which I don't understand how to do so exactly since I'm maintaining two stacks and need to see how exactly they relate to one another.
This problem is mostly due to me not understanding the way the normal recursive method words, although when looking at them side by side to see how to approach it, I always get stuck on what to do.
The backstory as to why I'm doing this:
Trying to solve the word ladder problem to go from A to B and decided to make a BST where the connections are connected by singular character differences and lengths. I'm getting the words from a text file containing a lot of the dictionary, and since I'm using a BST as the master list with all vertices the fact that this is a dictionary means every insert will be in order so the tree is right-leaning (so the speeds are slow for inserting O(n^2) which is a big hinderance). I was planning on storing data in an array then making a balanced BST from that since I believe speeds should go faster since insertion will be O(n*logn) which seems great. The problem with that is that I can't use a recursive approach since there's a lot of data leading to stack overflows, so I need to make it iteratively with stacks and loops, but am finding it too difficult.
My bad attempt at a start:
while (lindx.the_front() < rindx.the_back())
{
mid =(lindx.the_front() + rindx.the_back()) / 2;
dictionary.addVertex(vector[mid]);
std::cout << "Pushed " << vector[mid] << '\n';
rindx.push(mid - 1);
}
That basically gets the 1/2's from the left half of the program from a linked stack I made. "the_front()" is the first insertion, "the_back()" is the final/latest insert into the list. The main problem I have is understanding how to make it repeat per half to get all the values.
I need to find my past homework where I've done this but the code is something along the lines of...
void array2balanced(int array[], int lIndex, int rIndex)
{
//base case
if(lIndex > rIndex)
{
return;
}
//recursive cals
else
{
mid = (lIndex+rIndex)/2;
tree.insert(array[mid]);
array2balanced(array, lIndex, mid-1);
array2balanced(array, mid+1, rIndex);
}
}
UPDATE:
Progress so far
void balancedTree(std::vector<std::string> vector, dictionaryGraph &dictionary) // divide and conquer into tree?
{
linkedStack<int> lindx, rindx, midX;
unsigned int l_Index{ 0 }, r_Index{ vector.size() - 1 }, mid{ (l_Index + r_Index) / 2 };;
lindx.push(l_Index);
rindx.push(r_Index);
midX.push(mid);
int testCount{ 0 };
std::cout << "There are " << vector.size() << " words.\n";
while (!midX.empty())
{
mid = midX.pop();
l_Index = lindx.pop();
r_Index = rindx.pop();
std::cout << "inputted " << vector[mid] << '\n';
dictionary.addVertex(vector[mid]);
testCount++;
if (r_Index > l_Index)
{
midX.push((l_Index + mid) / 2);
lindx.push(l_Index);
rindx.push(mid - 1);
}
if (l_Index < r_Index)
{
midX.push((mid + r_Index) / 2);
lindx.push(mid + 1);
rindx.push(r_Index);
}
}
std::cout << testCount << " words were inputted...\n"; // To see how many were inserted
system("pause");
}
Problem I have is some inputs get repeated and some missed.
I don't think you need two stacks. You just need either a one stack or one queue.
Below codes can be tested on Leetcode
Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
One Stack Method
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
if not nums:
return None
l = len(nums)
node = TreeNode(0)
head = node
s = collections.deque([(node, 0, l)])
while s:
node, left, right = s.pop()
mid = (right + left) // 2
node.val = nums[mid]
if mid < right-1:
node.right = TreeNode(0)
s.append((node.right, mid+1, right))
if left < mid:
node.left = TreeNode(0)
s.append((node.left, left, mid))
return head
One Queue Method
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
if not nums:
return None
l = len(nums)
node = TreeNode(0)
head = node
q = collections.deque([(node, 0, l)])
while q:
node, left, right = q.popleft()
mid = (right + left) // 2
node.val = nums[mid]
if left < mid:
node.left = TreeNode(0)
q.append((node.left, left, mid))
if mid < right-1:
node.right = TreeNode(0)
q.append((node.right, mid+1, right))
return head
They are implemented using deque. Notice popleft() returns the first element(like stack) and pop() returns the last element(like queue).
This problem is mostly due to me not understanding the way the normal
recursive method words, although when looking at them side by side to
see how to approach it, I always get stuck on what to do.
It takes practice ... and maybe reviewing other peoples work.
require two stacks (to contain a left_Index and right_Index).
My apologies, I do not understand why the OP thinks this. My demo below has only 1 stack called 'todo', perhaps you will find the idea useful.
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
#include <cassert>
#include "./BTree.hh" // code not provided, used in this MCVE to
// conveniently provide "showTallTreeView()"
typedef std::vector<int> IVec_t;
class T607_t
{
IVec_t m_sortedIVec; // sorted - created with for loop
IVec_t m_recursiveIVec; // extract from sorted by recursion
IVec_t m_iterativeIVec; // extract from sorted by iteration
public:
T607_t() = default;
~T607_t() = default;
int exec(int , char** )
{
fillShowSortedIVec();
fillShowRecursiveIVec();
fillShowIterativeIVec();
showResults();
return 0;
}
private: // methods
The vectors are in class T607_t, so that each is available to any member function.
For this MCVE, I simply create "IVec_t m_sortedIVec;" and fill with a simple for loop:
void fillShowSortedIVec()
{
for (int i=0; i<15; ++i)
m_sortedIVec.push_back (i*100); // create in sorted order
showIVec(m_sortedIVec, "\n m_sortedIVec :");
}
Next (in this MCVE) is the recursive fill and show, and my adaptation of the OP's recursive method to produce the recursive insert sequence:
// ///////////////////////////////////////////////////////////////
void fillShowRecursiveIVec()
{
assert(m_sortedIVec.size() > 0);
int max = static_cast<int>(m_sortedIVec.size()) - 1;
// use OP's recursive insert
array2balancedR (m_sortedIVec, 0, max);
// NOTE - 'sequence' is inserted to 'm_recursiveIVec'
// instead of into tree the op did not share
showIVec(m_recursiveIVec, "\n m_recursiveIVec:");
}
// recursive extract from: m_sortedIVec to: m_recursiveIVec
// my adaptation of OP's recursive method
void array2balancedR(IVec_t& array, int lIndex, int rIndex)
{
//base case
if(lIndex > rIndex)
{
return;
}
else //recursive calls
{
int mid = (lIndex+rIndex)/2;
m_recursiveIVec.push_back(array[mid]); // does this
// tree.insert(array[mid]); // instead of this
array2balancedR(array, lIndex, mid-1); // recurse left
array2balancedR(array, mid+1, rIndex); // recurse right
}
}
Note: I left the "IVec_t& array" as a parameter to this function, because the OP's code has it. Within this 'class' wrapper, the function need not pass the array 'through the recursion', because each method has access to the instance data.
Next (in this MCVE) is a fill and show action using one possible iterative approach. I styled this iterative approach carefully to match the OP's recursive effort.
First, I added a 'tool' (IndxRng_t) to simplify the 'stack' capture of iterations for later processing. (i.e. "todo").
// //////////////////////////////////////////////////////////////
// iterative extract from m_sortedIVec to: m_iterativeIVec
class IndxRng_t // tool to simplify iteration
{
public:
IndxRng_t() = delete; // no default
IndxRng_t(int li, int ri)
: lIndx (li)
, rIndx (ri)
{}
~IndxRng_t() = default;
// get'er and set'er free. also glutton free. gmo free.
bool done() { return (lIndx > rIndx); } // range used up
int mid() { return ((lIndx + rIndx) / 2); } // compute
IndxRng_t left(int m) { return {lIndx, m-1}; } // ctor
IndxRng_t right(int m) { return {m+1, rIndx}; } // ctor
private:
int lIndx;
int rIndx;
};
void fillShowIterativeIVec()
{
assert(m_sortedIVec.size() > 0);
int max = static_cast<int>(m_sortedIVec.size()) - 1;
array2balancedI(m_sortedIVec, 0, max);
// 'sequence' inserted to 'm_iterativeIVec'
showIVec(m_iterativeIVec, "\n m_iterativeIVec:");
}
void array2balancedI(IVec_t& array, int lIndex, int rIndex)
{
std::vector<IndxRng_t> todo;
todo.push_back({lIndex, rIndex}); // load the first range
// iterative loop (No recursion)
do
{
if (0 == todo.size()) break; // exit constraint
// no more ranges to extract mid from
// fetch something to do
IndxRng_t todoRng = todo.back();
todo.pop_back(); // and remove from the todo list
if(todoRng.done()) continue; // lIndex > rIndex
int mid = todoRng.mid();
m_iterativeIVec.push_back(array[mid]); // do this
// tree.insert(array[mid]); // instead of this
todo.push_back(todoRng.right(mid) ); // iterate on right
todo.push_back(todoRng.left(mid) ); // iterate on left
}while(1);
}
And this mcve generates a result display:
void showResults()
{
assert(m_recursiveIVec.size() == m_sortedIVec.size());
assert(m_iterativeIVec.size() == m_sortedIVec.size());
std::cout << std::endl;
std::stringstream ss; // for btree use only
std::cout << "\n demo:\n create a BTree, "
<< std::flush;
std::cout << "\n Insert IVec_t " << std::endl;
BBT::BTree_t btree(ss);
std::cout << std::flush;
for (size_t i=0; i<m_iterativeIVec.size(); ++i)
btree.insertPL(m_iterativeIVec[i]);
std::cout << "\n iterative result:\n\n"
<< btree.showTallTreeView();
}
void showIVec(IVec_t& ivec, std::string lbl)
{
std::cout << lbl << std::endl;
for (auto it : ivec)
std::cout << std::setw(5) << it << std::flush;
std::cout << std::endl;
}
}; // class T607_t
int main(int argc, char* argv[])
{
T607_t t607;
return t607.exec(argc, argv);
}
My output (on Ubuntu 17.10, g++ 7.2.0),
m_sortedIVec :
0 100 200 300 400 500 600 700 800 900 1000 1100 1200 1300 1400
m_recursiveIVec:
700 300 100 0 200 500 400 600 1100 900 800 1000 1300 1200 1400
m_iterativeIVec:
700 300 100 0 200 500 400 600 1100 900 800 1000 1300 1200 1400
demo:
create a BTree,
Insert IVec_t
iterative result:
BTree_t::showTallTreeView(): (balance: 0 sz: 15)
0
100
200
300
400
500
600
700
800
900
1000
1100
1200
1300
1400
-----------------
Iterative JavaScript implementation of converting sorted array to Binary Search Tree (BST):
function sortedArrayToBstIteratively(nums) {
// use stack to iteratively split nums into node tuples and reuse values
const stack = []
// add root node to tree
const tree = { first: 0, last: nums.length - 1 }
stack.push(tree)
// split array in the middle and continue with the two halfs
while (stack.length > 0) {
const node = stack.pop()
if (node.last >= node.first) {
if (node.last === node.first) {
// node reaches a single leaf value (last == first)
node.value = nums[node.first]
} else {
// node has still valid indices to further split the array (last > first)
const middle = Math.ceil((node.first + node.last) / 2)
node.value = nums[middle]
node.left = { first: node.first, last: middle - 1 }
node.right = { first: middle + 1, last: node.last }
stack.push(node.left)
stack.push(node.right)
}
} else {
// node has no more valid indices (last < first), create empty leaf
node.value = null
}
delete node.first
delete node.last
}
// console.log(JSON.stringify(tree))
return tree
}