Im just starting to learn C++ programming and for exercise i found this task. I have to write a PriorityQueue using dynamic, array based, integer stack. This is what i have got so far.
#include <iostream>
using namespace std;
class PrioQueue
{
private:
int *bottom_;
int *top_;
int size_;
public:
PrioQueue(int n = 20){
bottom_ = new int[n];
top_ = bottom_;
size_ = n;
}
int getSize(){ return size_; }
void push(int c){
if (!full()){
*top_ = c;
top_++;
}
else{
resize(size_ * 2);
*top_ = c;
top_++;
}
SortPrioQueue();
}
void resize(int newSize){
//Allocate new array and copy in data
int *newArray = new int[newSize];
memcpy(newArray, bottom_, size_ * sizeof(int));
// Set the top to the new array
top_ = newArray + (top_ - bottom_);
// Delete old array
delete[] bottom_;
// Update pointers and size
bottom_ = newArray;
size_ = newSize;
cout << "array has been resized" << endl;
}
void SortPrioQueue(){
int swap = 0; //holding variable
for (int i = 0; i < (size_ - 1); i++)
{
for (int j = (i + 1); j < size_; j++)
{
if (bottom_[i] > bottom_[j])
{
swap = bottom_[i];
bottom_[i] = bottom_[j];
bottom_[j] = swap;
}
}
}
}
int num_items() {
return (top_ - bottom_);
}
int pop(){
top_--;
return *top_;
}
int full() {
return (num_items() >= size_);
}
int empty() {
return (num_items() <= 0);
}
void print(){
cout << "Stack currently holds " << num_items() << " items: ";
for (int *element = bottom_; element<top_; element++) {
cout << " " << *element;
}
cout << "\n";
}
~PrioQueue(){ // stacks when exiting functions
delete[] bottom_;
}
};
int main(){
PrioQueue s(5);
s.print(); cout << "\n";
s.push(10); s.push(24); s.push(53); s.push(74); s.push(5);
s.print(); cout << "\n";
//s.SortPrioQueue();//if i call it here
s.print(); cout << "\n";
while (!s.empty()) s.pop();
if (s.num_items() != 0) {
cout << "Error: Stack is corrupt!\n";
}
s.print(); cout << "\n";
// destructor for s automatically called
system("pause"); // execute M$-DOS' pause command
return 0;
}
There seems to be a problem with SortPrioQueue() method. If i call it from main() method it works fine.
But if i call it from push() method then i get this.
Thanks in advance for your help.
SortPrioQueue() should use top_ - _bottom (or num_items()) as limit and not size.
Related
I am using a stack to reverse a given string. Each character of the string is pushed onto the stack, then they are popped back into a new string which is returned to main. But for some reason, the value of stack[top] in the stack class code never seems to change.
#include <iostream>
#include <string>
using namespace std;
const int size = 4;
class Stack{
private:
//char stack[size];
char* stack;
int top;
public:
Stack()
{
top = -1;
}
void Init_Size(int size)
{
stack = new char[size];
}
bool isFull()
{
if (top == (size - 1))
return true;
return false;
}
bool isEmpty()
{
if (top == -1)
return true;
return false;
}
void push(char c)
{
if (isFull())
{
cout << "STACK IS FULL" << endl;
return;
}
top++;
stack[top] == c;
cout << "PUSHED" << stack[top] << " ONTO STACK" << endl;
}
char pop()
{
if (isEmpty())
{
cout << "STACK IS EMPTY" << endl;
return '/'; //error
}
char temp = stack[top];
cout << stack[top] << endl;
top--;
cout << "POPPED" << temp << " OFF STACK" << endl;
return temp;
}
};
string ReverseString(string str)
{
Stack stack;
string result;
stack.Init_Size(str.length());
for (int i=0; i < str.length(); i++)
{
stack.push(str[i]);
}
for (int i=0; i < str.length(); i++)
{
result[i] = stack.pop();
}
return result;
}
int main()
{
string str;
cin >> str;
cout << ReverseString(str);
}
I tried using a normal array for the stack instead of a dynamic one, but no change, however, I did notice that the value of the stack array can be changed but only in the void Init_Size(int size) function and I'm not sure why.
I see a number of errors in your program:
size: You have a global constant size set to 4 which is used in your isFull function, independent of the local size parameter used in Init_Size. Make this a class variable instead.
Your push function has the line stack[top] == c with two = instead of one - thus comparing the value against stack instead of setting stack. Turn on warnings and you should have found this yourself
ReverseString assigns directly to result[i] without ever setting the size of result. You could have used the str variable instead, since that is just a copy.
Those three are the major errors that need fixing for your program to work, but there are several minor issues as well, like using namespace std; thereby making size ambigious, making unnecessary copies of strings, using new and c-style arrays etc.
You have a problem with creation and deletion of your arrays here in your program as well as a few small misshaps on the way.
Fix:
#include <iostream>
#include <string>
using namespace std;
class Stack{
private:
//char stack[size];
int size;
char* stack;
public:
Stack() : size(0), stack(NULL) {}
~Stack() {if (stack != NULL) delete stack;} //THIS IS NEEDED HERE
void Init_Size(int newSize)
{
if (stack != NULL) delete stack;
size = newSize;
stack = new char[newSize]; //CREATES DYNAMIC ARRAY WHICH YOU NEED TO REMEMBER TO REMOVE OTHERWISE MEMORY LEAK
}
void push(char c) //adds
{
//adding here should work in a way:
//a) create new dynamic array with different size
//b) copy all elements into new array
//c) delete array
if (stack == NULL) Init_Size(1);
char* newArray = new char[size+1];
for(int i = 0; i < size; i++)
{
newArray[i] = stack[i];
}
newArray[size] = c;
delete stack;
stack = newArray;
size++;
cout << "PUSHED " << stack[size-1] << " ONTO STACK" << endl;
}
char pop()
{
//removing here should work in a way:
//a) create new dynamic array with different size
//b) copy all elements into new array
//c) delete array
if (stack == NULL)
{
cout << "Stack empty" << endl;
return '\0';
}
char* newArray = new char[size-1];
for(int i = 0; i < size-1; i++)
{
newArray[i] = stack[i];
}
char temp = stack[size-1];
delete stack;
stack = newArray;
size--;
cout << "POPPED " << temp << " OFF STACK" << endl;
return temp;
}
};
string ReverseString(string str)
{
Stack stack;
string result;
stack.Init_Size(str.length());
for (int i=0; i < str.length(); i++)
{
stack.push(str[i]);
}
for (int i=0; i < str.length(); i++)
{
result[i] = stack.pop();
}
return result;
}
int main()
{
string str;
cin >> str;
cout << ReverseString(str);
}
I'd like to be able to consume parts of a buffer until it's empty. I designed my own below, but I'd like to know if there is such thing in the std library already, so I remove the possibilities of implementing my own wrong.
Note that I use std::vector<T> only for automatic storage. I don't do push_back to insert and pop_back to consume because I want the consumption of data to be as fast as possible.
#include <iostream>
#include <vector>
using namespace std;
template <class T>
class Buffer
{
public:
void write(T* buffer, size_t amountToWrite) {
if (amountToWrite <= this->_buffer.capacity()) {
std::copy(buffer, buffer + amountToWrite, this->_buffer.data());
_size += amountToWrite;
} else {
//In fact I wanted to increase capacity, not size. However we don't use the vector functions, so does it mater?
this->_buffer.resize(amountToWrite);
std::copy(buffer, buffer + amountToWrite, this->_buffer.data());
_size += amountToWrite;
}
}
size_t consume(T* bufferToWrite, size_t amountToConsume) {
if (_current==_size) {
//this means we've already read everything. Maybe we should throw or just return 0?
return 0;
}
if (amountToConsume <= this->_size) {
std::copy(this->_buffer.data() + _current, this->_buffer.data() + _current + amountToConsume, bufferToWrite);
_current += amountToConsume;
return amountToConsume;
} else {
size_t remaining = this->_size - amountToConsume;
std::copy(this->_buffer.data() + _current, this->_buffer.data() + _current + remaining, bufferToWrite);
_current += remaining;
return remaining;
}
}
private:
size_t _size = 0;
std::vector<T> _buffer;
size_t _current = 0;
};
int main()
{
Buffer<uint8_t> b;
uint8_t u[] = {1,2,3,4,5,6};
b.write(u, 6);
uint8_t r[3];
size_t consumedBytes = b.consume(r, 3);
std::cout << "consumed " << consumedBytes << std::endl;
for(int i=0; i<3; i++) {
std::cout << (int) r[i];
}
std::cout << std::endl;
size_t consumedBytes2 = b.consume(r, 3);
std::cout << "consumed " << consumedBytes2 << std::endl;
for(int i=0; i<3; i++) {
std::cout << (int) r[i];
}
std::cout << std::endl;
size_t consumedBytes3 = b.consume(r, 3);
std::cout << "consumed " << consumedBytes3 << std::endl;
return 0;
}
Do you see anything wrong in my implementation?
I'm trying to do the safest possible thing while making it fast.
I think you can take advantage of using dequeue from STL.
It implements a doubly linkedlist in which you can read from one side and write from the other side of it. Check this link for more detail explanations.
Also the other best implementation for a buffer is a circular buffer implementation.
I leave a C++ implementation code for a circular buffer.
class MyCircularQueue {
vector<int> mem;
int front;
int rear;
int len;
int cnt;
public:
MyCircularQueue(int k) {
len = k;
mem = vector<int> (k);
front = 0;
rear = -1;
cnt=0;
}
bool enQueue(int value) {
if(isFull())
return false;
rear = (rear+1) %len;
mem[rear]= value;
cnt++;
return true;
}
bool deQueue() {
if (isEmpty())
return false;
front = (front+1) % len;
cnt--;
return true;
}
int Front() {
if (isEmpty())
return -1;
return mem[front];
}
int Rear() {
if (isEmpty())
return -1;
return mem[rear];
}
bool isEmpty() {
return (cnt ==0);
}
bool isFull() {
return ( cnt == len);
}
};
I made a dynamic array with template. The problem is that when I don't keep there pointers (for example: Tab<string> da;) my destructor doesn't have to clear it and throws error caused by delete arr[i];. My question is if I can put some if condition(in which I would put clear() method) which would tell me if my array keeps pointers. In the simplest way I can use clear() in main when I keeps there pointers, but my teacher wants me to make it like I wrote above.
I tried using is_pointer, but it doesn't work or I use it wrong.
Any suggestions?
#ifndef TABLICA_H
#define TABLICA_H
#include <iostream>
#include <type_traits>
using namespace std;
template<class T>
class Tab
{
public:
int size = 0;
int max_size = 1;
T* arr;
bool isDynamic = false;
Tab()
{
arr = new T[max_size];
}
~Tab()
{
clear();
delete[] arr;
}
void check_size()
{
if (size == max_size)
{
max_size = max_size * 2;
T* arr2 = new T[max_size];
for (int i = 0; i < size; i++)
{
arr2[i] = arr[i];
}
delete[] arr;
arr = arr2;
}
}
void push_back(const T& value)
{
check_size();
arr[size] = value;
size++;
}
T return_by_index(int index)
{
if (index<0 || index > size)
{
return NULL;
}
return arr[index];
}
bool replace(int index, const T& value)
{
if (index<0 || index > size)
{
return false;
}
arr[index] = value;
return true;
}
void print(int number)
{
cout << "Rozmiar obecny: " << size << endl;
cout << "Rozmiar maksymalny: " << max_size << endl;
cout << "Adres tablicy: " << arr << endl;
cout << "Kilka poczatkowych elementow tablicy " << "(" << number << ")" << endl;
for (int i = 0; i < number; i++)
{
cout << *arr[i] << endl;
}
}
void clear()
{
for (int i = 0; i < size; i++)
{
delete arr[i];
}
}
};
#endif
//Source:
#include <iostream>
struct object
{
int field1;
char field2;
object()
{
field1 = rand() % 10001;
field2 = rand() % 26 + 'A';
}
};
ostream& operator<<(ostream& out, const object& o)
{
return out << o.field1 << " " << o.field2;
}
int main()
{
Tab < object* >* da = new Tab < object* >();
delete da;
system("PAUSE");
return 0;
Why am I getting these errors?
invalid conversion from 'Queue*' to 'int'
conversion from 'Stack*' to non-scalar type 'Stack' requested
I've tried modifying Queue & Stack, but to no avail. I am doing an assignment that implements Stack using Queues & implements Queue using Stacks.
Stack.h
#ifndef STACK_H_
#define STACK_H_
#include <iostream>
using namespace std;
class Stack {
int size;
int capacity; // for dynamic allocated array
int stackTop;
int *arr;
public:
Stack();
void push(int val);
int pop();
bool isFull();
bool empty();
int top();
int peek(int pos);
int resize();
};
bool Stack::empty(){
return size == 0;
}
bool Stack::isFull(){
return size == capacity;
}
void Stack::push(int val){
if(isFull())
resize();
arr[++stackTop] = val;
size++;
}
int Stack::pop(){
if(empty())
return true;
return arr[stackTop--];
}
int Stack::peek(int pos){
if(pos > stackTop || pos < 0){
cout << "Empty Stack";
return 0;
}
else{
return arr[size - pos - 1];
}
}
int Stack::top(){
if(empty()){
return true;
}
return *arr;
}
int Stack::resize(){
return size;
}
Queue.h
#ifndef QUEUE_H_
#define QUEUE_H_
#include <iostream>
using namespace std;
class Queue{
int f, r, *arr, size, capacity;
public:
Queue(): f(-1), r(-1), arr(nullptr), size(0), capacity(0){}
Queue(int cap): f(-1), r(-1), arr(new int[cap]), size(0), capacity(cap){}
~Queue(){delete []arr;}
Queue(const Queue ©){
f = copy.f;
r = copy.r;
arr = copy.arr;
size = copy.size;
capacity = copy.capacity;
}
Queue(Queue&& move){
f = move.f;
r = move.r;
arr = move.arr;
size = move.size;
capacity = move.capacity;
move.f = -1;
move.r = -1;
move.arr = nullptr;
move.size = 0;
move.capacity = 0;
}
Queue& operator=(const Queue& copyA){
if(this == ©A){
return *this;
}
f = copyA.f;
r = copyA.r;
arr = copyA.arr;
size = copyA.size;
capacity = copyA.capacity;
}
Queue& operator=(const Queue&& moveA){
if(this == &moveA){
return *this;
}
f = moveA.f;
r = moveA.r;
arr = moveA.arr;
size = moveA.size;
capacity = moveA.capacity;
// moveA.f = -1;
// moveA.r = -1;
// moveA.arr = nullptr;
// moveA.size = 0;
// moveA.capacity = 0;
return *this;
}
void enqueue(int x){
if(!full())
resize();
arr[f + r] = x;
size++;
}
int dequeue(){
if(!empty()){
return arr[++f];
} return -99999;
}
bool empty(){
return size == 0;
}
bool full(){
return size == capacity;
}
int peek(int pos){
if(pos > capacity || pos < 0){
cout << "Empty Queue";
return 0;
}else{
return arr[size - pos - 1];
}
}
void resize(){
int newSize = this->size * 2;
Queue *temp = new Queue[newSize];
int count = 0;
for(int i = 0; i < count; ++i){
int index = (f + 1) % size;
temp[i] = arr[index];
}
}
};
main.cpp
#include <iostream>
#include "Queue.h"
#include "Stack.h"
using namespace std;
int main(){
Queue q = new Queue(); //invalid conversion from 'Queue*' to 'int' [-fpermissive]
q.enqueue(1);
q.enqueue(2);
q.enqueue(3);
cout << q.dequeue() << '\n';
cout << q.dequeue() << '\n';
cout << q.dequeue() << '\n';
cout << endl;
Stack s = new Stack(); //conversion from 'Stack*' to non-scalar type 'Stack' requested
s.push(1);
s.push(2);
s.push(3);
cout << "current size: " << s.resize() << endl;
cout << s.top() << endl;
s.pop();
cout << s.top() << endl;
s.pop();
cout << s.top() << endl;
cout << "current size: " << s.resize() << endl;
return 0;
}
main.cpp:8:12: error: invalid conversion from 'Queue*' to 'int' [-fpermissive]
Queue q = new Queue();
^~~~~~~~~~~
20:12: error: conversion from 'Stack*' to non-scalar type 'Stack' requested
Stack s = new Stack();
^~~~~~~~~~~
The error would come from the line in main.cpp:
Queue q = new Queue();
The new keyword creates a pointer to the class object, so the correct syntax would be:
Queue *q = new Queue();
This is also shown in the C++ tutorial documentation here: http://www.cplusplus.com/doc/tutorial/classes/#pointers_to_classes
Same thing for the Stack pointer variable.
Note that this also means the syntax for using the objects must also change.
Instead of:
s.pop();
You will need to modify this to either:
(*s).pop();
or
s->pop();
Hope this helps!
When you instantiate with the new keyword, you create a pointer to the object. Thus, the correct instantiation would be the following:
Queue * q = new Queue();
Stack * s = new Stack();
When x is a pointer, then the value of x is the address of an object and *x is the actual object.
I don't agree with the answers advising getting it to work with new. It's unnecessary.
Instead of using new just leave them as normal stack variables. Then you're not burdened with having to later delete and you don't have to replace all instances of . to ->.
Simply
Queue q;
Stack s;
And your program remains otherwise unchanged.
(Do you perhaps come from a c# background? new is necessary there, but most often not necessary with C++)
Here is a program with my Stack class and some another functions.
ReadTheFile() - reads numbers, which are stored in num_file.txt, and returns a vector with those numbers.
IntervalCheck() - adds the numbers of the specific range from input vector and returns a vector with those numbers only.
VecToMyStack() - adds numbers from a vector to a stack.
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#define STACK_EMPTY -1
#define OUT_OF_STACK -2
using namespace std;
template <class T>
class Stack {
private:
struct Node{
T element;
Node *prevElement;
};
size_t NumberOfElements;
Node *tempAdr;
Node *topElement;
Node *newElement;
Node *erasedElement;
public:
Stack(){
topElement = new Node;
topElement->prevElement = nullptr;
NumberOfElements = 0;
}
~Stack(){
cout << endl << "I'm a destructor";
while(NumberOfElements !=0 ){
tempAdr = topElement->prevElement;
delete topElement;
topElement = tempAdr;
NumberOfElements--;
}
delete topElement;
}
void push(T input_element){
tempAdr = topElement;
topElement = new Node;
topElement->element = input_element;
topElement->prevElement = tempAdr;
NumberOfElements++;
}
void pop(){
if (NumberOfElements == 0) throw STACK_EMPTY;
else {
tempAdr = topElement->prevElement;
delete topElement;
topElement = tempAdr;
NumberOfElements--;
}
}
T top(){
return NumberOfElements != 0 ? topElement->element : throw STACK_EMPTY;
}
void insert(size_t position, T input_element){
if (position >= NumberOfElements) throw OUT_OF_STACK;
else {
tempAdr = topElement;
for (size_t i = 0; i < position; i++){
tempAdr = tempAdr->prevElement;
}
newElement = new Node;
newElement->element = input_element;
newElement->prevElement = tempAdr->prevElement;
tempAdr->prevElement = newElement;
NumberOfElements++;
}
}
void erase(size_t position){
if (position >= (NumberOfElements-1)) throw OUT_OF_STACK;
else{
tempAdr = topElement;
for (size_t i = 0; i < position; i++){
tempAdr = tempAdr->prevElement;
}
erasedElement = tempAdr->prevElement;
tempAdr->prevElement = tempAdr->prevElement->prevElement;
delete erasedElement;
NumberOfElements--;
}
}
void print(){
if (NumberOfElements != 0){
tempAdr = topElement;
for (size_t i = 0; i < NumberOfElements; i++){
cout << tempAdr->element << " ";
tempAdr = tempAdr->prevElement;
}
}
}
size_t size() { return NumberOfElements; }
};
vector<int> ReadTheFile() {
vector<int> vec_from_file;
int buffer;
ifstream basefile;
basefile.open("num_file.txt", ios::in);
if (basefile.is_open()) {
do {
if (basefile >> buffer)
vec_from_file.push_back(buffer);
else {
basefile.clear();
basefile.ignore(1, ' ');
}
} while (!basefile.eof());
basefile.close();
}
else cout << "Unable to open file" << endl;
return vec_from_file;
}
vector<int> IntervalCheck(vector<int> vec_for_check){
vector<int> out_vec;
if (vec_for_check.empty()) cout << "There is nothing to check";
else {
int begin_int, end_int;
do {
cin.clear();
cin.sync();
cout << "Input the first and the last value of the interval: ";
cin >> begin_int >> end_int;
} while (cin.fail());
for (auto &k : vec_for_check)
if (k > begin_int && k < end_int)
out_vec.push_back(k);
}
return out_vec;
}
Stack<int> VecToMyStack(vector<int> input_vec){
Stack<int> output_st;
if (input_vec.empty()) {
cout << "the end";
}
else {
for (auto &k : input_vec){
output_st.push(k);
}
}
return output_st;
}
int main(){
int choice = 0;
do {
cin.clear();
cin.sync();
VecToMyStack(IntervalCheck(ReadTheFile())).print();
cout << "Would you like to measure another interval? 1-yes 2-no";
cin >> choice;
} while (choice == 1);
system("pause");
return 0;
}
The whole program should push numbers from the file to a stack, and print this stack, using the print() method of the class. For example, if there is a num_file.txt with
0 1 2 3 4 5 6 7 8 9 10
inside, the program is expected to work in that way:
Input the first and the last value of the interval: 0 10 /* zero and
ten are inputed by the user*/
1 2 3 4 5 6 7 8 9
Would you like to measure another interval? 1-yes 2-no
But when the VecToMyStack(IntervalCheck(ReadTheFile())).print(); line is executed, I'm getting
Access violation reading location 0xFEEEFEEE.
exception. It seemes like the destructor of my Stack class is running before the print()function. Why does that happen? Is there something special what I should add to my Stack class or to VecToMyStack() function?
Finally, after a couple of hours of research, I've got that missing peace of code:
Stack(const Stack &object){
tempAdr = object.topElement;
T * tempMas=new T[object.NumberOfElements];
for (size_t i = 0; i < object.NumberOfElements; i++){
tempMas[i] = tempAdr->element;
tempAdr = tempAdr->prevElement;
}
topElement = new Node;
topElement->prevElement = nullptr;
NumberOfElements = 0;
for (int i = object.NumberOfElements - 1; i >= 0; i--){
push(tempMas[i]);
}
delete[] tempMas;
}
I know that my Stack class is still uncomplete without the overloaded assignment operator, but at least my code runs fine.