Sorted list: must have class/struct/union - c++

so i have been working on a code for over two weeks and its not going too well. here are the instructions and the code is below it, as well as errors:
Task 1: Create one instance of this class. (the sorted list; he also had other instructions on HOW to start the code, but its already been done by me below in the code such as typedef...) You also need to read in data from one data file: float.dat, which contains the following numbers:
5.5
6.2
7.1
8.0
9.0
10.0
1.0
2.0
3.3
4.4
Data in float.dat contains floating numbers, which should be inserted into the object of SortedList. Note that you do not have any prior knowledge about data values in float.dat, but we assume that there are 10 elements in the data file.
Task 2: Use GetNextItem( ) to print out all the elements in the list in sorted sequence on computer screen.
Task 3: Use GetNextItem( ) to output all the elements in the list in sorted sequence onto a data file, output.dat.
Task 4: Design your test cases to demonstrate InsertItem( ), DeleteItem( ) and RetrieveItem( ) are working as expected.
here is the code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
#define MAX_ITEMS 10
typedef float ItemType;
class SortedList
{
private:
int length;
ItemType values[MAX_ITEMS];
int currentPos;
enum RelationType { LESS, GREATER, EQUAL };
public:
SortedList() {length = 0; currentPos = -1;}
int getLength() {return length;}
RelationType ComparedTo(ItemType x)
{
if (length > x.getLength())
return LESS;
else if (length == x.getLength())
return GREATER;
else
return EQUAL;
}
void MakeEmpty() {length = 0;}
void InsertItem(ItemType x)
{
int first = 0, last = length --;
bool moreToSearch = (first <= last);
int location = 0;
int midpoint= (first + last) / 2;
while (moreToSearch)
{
switch (x.ComparedTo(values[location]))
{
case LESS: //search in 1st half
moreToSearch = (first <= last);
break;
case GREATER:
location++;
moreToSearch = (location < length);
break;
}
}
for (int index = length; length > location; index--)
{
values[index] = values[index - 1];
}
values[location] = x;
length++;
}
void DeleteItem(ItemType x)
{
int location = 0;
while (x.ComparedTo(values[location]) != EQUAL)
location++;
for (int index = location ++; index < length; index++)
values[index --] = values[index];
length--;
}
void RetrieveItem(ItemType &x, bool & found)
{
int midpoint;
int first = 0, last = length - 1;
bool moreToSearch = (first <= last);
found = false;
int index = 0;
while (moreToSearch && !found)
{
midpoint = (first + last) / 2;
switch (x.ComparedTo(values[index++]))
{
case LESS: //search in 1st half
moreToSearch = (first <= last);
last = midpoint - 1;
break;
case GREATER: //Search in 2nd half
first = midpoint + 1;
moreToSearch = (first <= last);
break;
case EQUAL: //x has been found
found = true;
break;
}
}
}
int LengthIs() {return length;}
void ResetList() {currentPos = -1;}
bool IsFull()
{
if (length < 9)
return false;
else
return true;
}
void GetNextItem(ItemType &x)
{
currentPos++;
x = values[currentPos];
cout << x;
}
};
int main()
{
SortedList x;
ifstream inFile; ofstream output;
string line;
bool allAboutLists;
int i = 0;
int size = 0;
inFile.open("float.txt");
float values[10];
while (!inFile.eof()) // write or read data from inFile into values
{
inFile >> values[i];
i++;
size++; // this will count how many values there are in the array
x.InsertItem(values[i]);
++i;
}
x.ResetList();
cout << "The following is the list that's been made:" << endl << endl;
x.InsertItem(64);
//x.printlist();
cout << endl;
x.DeleteItem(64);
//x.printlist();
x.RetrieveItem(7.1, allAboutLists);
cout << endl;
cout << endl << "The length is: "; x.LengthIs(); cout << endl;
cout << "Is the list full?: " << boolalpha << x.IsFull() << endl;
cout << "The next item is: ";
for (int i = 0; i < 10; i++)
{
cout << x.GetNextItem << endl;
}
x.ResetList();
inFile.close();
output.open("output.txt");
for (int f = 0; f < 10; f++)
{
output << x.GetNextItem << endl;
}
system("pause");
return 0;
}
and the compiler keeps saying this:
(25) error C2228: left of '.getLength' must have class/struct/union [they mean the x. its red lined under, same for the rest of those left of etc..]
(27) error C2228: left of '.getLength' must have class/struct/union
(44) error C2228: left of '.ComparedTo' must have class/struct/union
(66): error C2228: left of '.ComparedTo' must have class/struct/union
-and also, 7.1 in main has something about refernce type mistake.
I am in extereme hurry as i have been working on it for 2 weeks now and its driving me crazy ! I have the code done as seen and more than wnough and just need to know what to change exactly because I am following everything I have been searching and researching yet its no good. so precise details or code specifically taken from mine and fixed would be appreciated.
Thanks!

You are passing x as ItemType which is a float.
float doesn't have those methods... looks like you wanted to pass it as a SortedList

The compare function needs two parameters in order to do a compare. Instead of ComparedTo, you may want to call it CompareToLocation.
RelationType CompareToLocation(ItemType x, size_t location){
if(x < values[location]) return LESS;
if(x == values[location]) return EQUAL;
return GREATER;}
An example usage would be:
result = CompareToLocation(x, location);
// ...

You defined ComparedTo as a method for SortedList, yet everytime you call that function, you call it on ItemType objects, which are actually floats.
As you can see in the definition of the method, you are trying to use, once again, SortedList methods on float Objects:
RelationType ComparedTo(ItemType x)
{
if (length > x.getLength())
return LESS;
else if (length == x.getLength())
return GREATER;
else
return EQUAL;
}
Your problem is not really a compiling one, but a conceptual one, since you don't seem to grasp what your are actually coding.
I'd recommend have your declarations and implementations separate, so you can see at a glance how does your class work.
Your class declaration should look something like this:
class SortedList
{
private:
int length;
ItemType values[MAX_ITEMS];
int currentPos;
enum RelationType { LESS, GREATER, EQUAL };
public:
SortedList();
int getLength();
RelationType ComparedTo(ItemType x) ;
void MakeEmpty();
void InsertItem(ItemType x) ;
void DeleteItem(ItemType x);
void RetrieveItem(ItemType &x, bool & found);
int LengthIs();
void ResetList();
bool IsFull();
void GetNextItem(ItemType &x);
};
You should focus on each method, making clear what each one of them is trying to achieve, and what does it need to achieve it (parameters).
For example:
RelationType ComparedTo(ItemType x) ;
Your SortedList class has this function, which receives an ItemType (float) as a parameter.
What is this trying to achieve? How do you compare a whole ordered list to a single element?
How can a single number be greater, less or EQUAL to a set of numbers?
Maybe what you really want to do is compate parameter X with an element inside the list?
If this is the case, how do you know which element in the list must be compared to parameter X? You should add another parameter telling you which element inside your ordered list to compare X to.
I quess this doesn't really solve your problem, but at least I hope this helps you understand better what your problem is.

Related

Delete and insert an element from/to array bag. Why boolean array instead of int?

I am implementing bag using array in C++. I can not figure out how to let the deleteElement function work. It is suppose to delete given element from the array.
I also don't understand why the array is initialized with bool and how the insert function works.
So, I got three questions:\
How to make the deleteElement function work?
Why is the array initialized with bool?
How does the insert function work? It looks like it only adds true value to the array, but when this program prints the array, you will see that the x value is printed out, I can not figure this out.
#include <iostream>
#include <math.h>
#include <algorithm>
using namespace std;
// cin -> add 0 qry 0 del 0 qry 0 quit
// cout -> TF
// add x -> Adds the number x to the bag
// qry x -> Checks if x belongs to the bag then output T, otherwise output F
// del x -> If there is an element x in the bag, remove it, otherwise do nothing.
// quit -> Stops the program
// Exercise: Fun with bags 1 (Here the bag is a set of int values).
/*
Example:
input: add 1 add 2 add 1 del 1 qry 1 qry 2 quit
output: FT
*/
// enumeration type for actions on the bag
enum action {add, qry, del, quit, none};
// translation of strings into actions
action str2action(string s) {
if (s=="add") return add;
if (s=="qry") return qry;
if (s=="del") return del;
if (s=="quit") return quit;
return none;
}
#define BAG_AS_ARRAY_SIZE 10
struct bag {
bool as_array[BAG_AS_ARRAY_SIZE]; // using arrays
};
// Simple function to initialise the bag
void initialise(bag &b){
// Array
for(int i=0; i<BAG_AS_ARRAY_SIZE; i++){
b.as_array[i] = false;
}
}
// function to display the content of the bag
void display_bag(bag b) {
cout << "The bag is : " << endl;
// Array
cout << " - (A) - : " ;
for(int i=0; i<BAG_AS_ARRAY_SIZE; i++){
if(b.as_array[i])
cout << i << " " ;
}
cout << endl;
return;
}
void insert(bag &b,unsigned int x){ //add
// Array
b.as_array[x] = true;
}
void check(bag &b,unsigned int x) //qry
{
bool q = false;
for(int i = 0; i < BAG_AS_ARRAY_SIZE; i++)
{
if(b.as_array[x])
{
q = true;
}
}
if(q == true)
{
cout << "T";
}
if(q == false)
{
cout << "F";
}
cout << endl;
}
void DeleteElement(bag &b, unsigned int x) //del
{
int i;
for (i=0; i<BAG_AS_ARRAY_SIZE; i++)
if (b.as_array[i] == x)
break;
if (i < BAG_AS_ARRAY_SIZE)
{
for (int j=i; j<BAG_AS_ARRAY_SIZE; j++)
b.as_array[j] = b.as_array[j+1];
}
}
// this function deals with actions on a bag
void update(bag &b, action a, unsigned int x){
switch(a){
case add:
insert(b,x);
break;
case qry:
check(b,x);
break;
case del:
DeleteElement(b,x);
break;
case quit:
break;
case none:
break;
default:
break;
}
return;
}
int main()
{
bag my_bag; //We create an array of boolean type.
string my_act_str;
unsigned int x;
initialise(my_bag); //The array is initialised with False, which is 0
bool go_on = true;
while(go_on)
{
display_bag(my_bag);
cout << "What's next? (actions = add x ,qry x ,del x ,quit)" << endl;
cin >> my_act_str;
action act = str2action(my_act_str);
if(act == quit)
{
go_on = false;
}
if(act == add)
{
cin >> x;
update(my_bag,act,x);
}
if(act == qry)
{
cin >> x;
update(my_bag,act,x);
}
if(act == del)
{
cin >> x;
update(my_bag,act,x);
}
}
return 0;
}
Edit:
I found out solution for the delete function. It is very easy one:
void delete_element(bag &b, unsigned int x)
{
b.as_array[x] = false;
}
Your three questions actually come from the fact that this is not really a bag. What you have here is more like a "Boolean mask" that indicates if numbers from zero to BAG_AS_ARRAY_SIZE - 1 are true or false. That is why you have a Boolean array as the storage and all elements in it are initialized with false. That is, the mask is not set for any of the numbers from zero to BAG_AS_ARRAY_SIZE - 1.
Your deleteElement function then only needs to set the corresponding array position of the mask to false to "delete" that number and "inserting" a number corresponds to setting that specific position in the mask to true.
In the display_bag function, notice that you are not print the content of the array (which obviously can only be either true or false), but the index of the positions in the array that have a true value.

Returning name of lowest node

First of all, this is part of a university course, so whilst a copy-paste solution would do, I'm looking for a bit more depth. I'll be seeing my supervisor tomorrow anyways though.
Now onto the problem. I am implementing Dijkstra's algorithm for 5 linked nodes, A-E, which have their associated costs and links stored in a vector;
struct Node
{
char nodeLink; //adjacent link
int cost; //cost of a link
}; //to use in Dijkstra algorithm
class HeadNode
{
public:
char Name;
bool Visited;
vector<Node> nodes;
HeadNode(char x) { Name = x; Visited = false; }
};
class Graph
{
char Start = 'A';
char StartNode;
char CurrentNode;
char Destination = 'E';
int TotalCost = 0;
vector<HeadNode> hnode;
vector<char> path;
vector<int> weight;
public:
Graph();
void createHeadNode(char X);
void createAdjMatrix();
char LeastDistance(char node);
void printAdjMatrix();
void Dijkstra(char StartNode);
char GetStartNode();
};
int main()
{
Graph graph;
graph.createHeadNode('A');
graph.createHeadNode('B');
graph.createHeadNode('C');
graph.createHeadNode('D');
graph.createHeadNode('E');
graph.createAdjMatrix();
//graph.printAdjMatrix();
graph.Dijkstra(graph.GetStartNode());
system("pause");
return 0;
}
Graph::Graph()
{
}
void Graph::createHeadNode(char x)
{
hnode.push_back(x);
}
In order to properly implement the algorithm, I have created a precursor function, LeastDistance(), within the class graph. I also have a function to get the start node, but that isn't particularly important here;
char Graph::LeastDistance(char node)
{
int smallest = 9999;
char smallestNode;
for (int i = 0; i < hnode.size(); i++)
{
for (int j = 0; j < hnode[i].nodes.size(); ++j)
{
if ((node == hnode[i].Name) && (hnode[i].nodes[j].cost <= smallest) && (hnode[i].Visited == false))
{
smallest = hnode[i].nodes[j].cost;
smallestNode = hnode[i].nodes[j].nodeLink;
}
else
{
hnode[i].Visited = true;
break;
}
}
}
TotalCost = TotalCost + smallest;
return(smallestNode);
}
void Graph::Dijkstra(char StartNode)
{
CurrentNode = StartNode;
if (CurrentNode == Destination)
{
cout << "the start is the destination, therefore the cost will be 0." << endl;
}
else
{
while(true)
{
if (CurrentNode != Destination)
{
CurrentNode = LeastDistance(StartNode);
cout << CurrentNode << "<-";
}
else if (CurrentNode == Destination)
{
cout << endl;
cout << "The total cost of this path is:" << TotalCost;
TotalCost = 0;//reset cost
break;
}
}
}
}
My problem is that the LeastDistance fucntion appears always to return node C, leading to it being printed over and over, so it fills the console. So far, I have tried to debug using visual studio 2017, but I cant make much sense out of the watches. I have also tweaked the order of the breaks around, and tried to make sure the visited flag is being set to true. whether any precedence of operations is affecting this I am not sure.
Thanks in advance.
I would contend that there are multiple problems with the way you implement this... but I think the one that's causing you the problem you describe is the statement right here:
if (CurrentNode != Destination)
{
CurrentNode = LeastDistance(StartNode);
cout << CurrentNode << "<-";
}
Think about what this does. Let's say your first node isn't the one you're looking for, then you call least distance and find the next smallest node. Then you print it. Then you iterate on the while loop again only to find that CurrentNode isn't the one you're looking for, so you call LeastDistance(StartNode) again, which will return the exactly same value. Thus, you'll keep printing the same result which apparently is c.
Assuming everything else is correct, I think you want:
CurrentNode = LeastDistance(CurrentNode);

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.

Wrong output C++ ArrayList

When i make ArrayList with size 5 it gives wrong result but when it becomes bigger than 5 it becomes correct!
#include <iostream>
#include <string>
using namespace std;
class list
{
typedef int ListElemtype;
private:
ListElemtype listArray[6];
public:
bool insert(ListElemtype e)
{
if (numberOfElements == 5) //It turns wrong result when ListArray equal 5??
{
cout << "Can't do the insertion" << endl;
return false;
} //Why it return false? I know why i but = instead of == :D
else
{
listArray[numberOfElements + 1] = e;
numberOfElements++;
cout << "Done perfectly!" << numberOfElements << endl;
return true;
}
};
bool first(ListElemtype &e);
bool next(ListElemtype &e);
int numberOfElements;
int CurrentPosition;
void LIST ()
{
CurrentPosition=-1;
numberOfElements=0;
return;
}
};
int main()
{
list A;
A.LIST();
A.insert(10);
A.insert(20);
A.insert(30);
A.insert(40);
A.insert(50);
A.insert(60);
system("pause");
return 0;
}
Arrays are indexed from zero, not from one. So listArray[numberOfElements+1]=e; should be listArray[numberOfElements]=e;. The first inserted element goes into listArray[0].
Your listArray size is 6 therefore array index would start from 0 till 5. When you have numberOfElements==5 with listArray[numberOfElements + 1] you are trying to store at index 6 which you don't have.
As you may know, C bases its arrays at 0 and not 1. Thus,
else { listArray[numberOfElements+1]=e;
writes to the end of the array contained within list A, when numberOfElements is equal to 5 or higher.

Priority Queue Wrong Order

I am programming the huffman encoding. This is the beginning of my program:
using namespace std;
//Counting methods
int *CountCharOccurence(string text)
{
int *charOccurrence = new int[127];
for(int i = 0; i < text.length(); i++)
{
charOccurrence[text[i]]++;
}
return charOccurrence;
}
void DisplayCharOccurence(int *charOccurrence)
{
for(int i = 0; i < 127; i++)
{
if(charOccurrence[i] > 0)
{
cout << (char)i << ": " << charOccurrence[i] << endl;
}
}
}
//Node struct
struct Node
{
public:
char character;
int occurrence;
Node(char c, int occ) {
character = c;
occurrence = occ;
}
bool operator < (const Node* node)
{
return (occurrence < node->occurrence);
}
};
void CreateHuffmanTree(int *charOccurrence)
{
priority_queue<Node*, vector<Node*> > pq;
for(int i = 0; i < 127; i++)
{
if(charOccurrence[i])
{
Node* node = new Node((char)i, charOccurrence[i]);
pq.push(node);
}
}
//Test
while(!pq.empty())
{
cout << "peek: " << pq.top()->character << pq.top()->occurrence << endl;
pq.pop();
}
}
int main(int argc, char** argv) {
int *occurrenceArray;
occurrenceArray = CountCharOccurence("SUSIE SAYS IT IS EASY");
DisplayCharOccurence(occurrenceArray);
CreateHuffmanTree(occurrenceArray);
return (EXIT_SUCCESS);
}
The program first outputs the characters with their occurence number. This looks fine:
: 4
A: 2
E: 2
I: 3
S: 6
T: 1
U: 1
Y: 2
but the test loop which has to display the node contents in priority order outputs this:
peek: Y2
peek: U1
peek: S6
peek: T1
peek: I3
peek: E2
peek: 4
peek: A2
This is not the expected order. Why?
Elements in your priority queue are pointers. Since you don't provide a function that takes 2 pointers to Node objects , default compare function compares 2 pointers.
bool compareNodes(Node* val1, Node* val2)
{
return val1->occurence < val2->occurence;
}
priority_queue<Node*, vector<Node*>,compareNodes > pq;
Your operator < is used when Node compares with Node*
You should tell your priority queue what it should sort by. In your case, you have to tell it to sort by Node::occurence.
You are storing pointers to nodes in the queue, but haven't provided a suitable comparison function, so they are sorted by comparing the pointers. The operator< you've provided will compare a node with a pointer, which isn't what you want.
There are two options:
Provide a function for comparing two node pointers according to their values, and give this function to the queue, or
Store node objects in the queue, and provide an operator< to compare two nodes.
The second option will also fix the memory leak in your code, and remove a whole pile of unnecessary memory allocations, so I would suggest that.