I wrote a bubble sorting algorithm which sorts a dynamically allocated array using string comparison.
Here is my code:
void AddressBook::bubble_sort_address_book(){
bool swapped = true;
while(swapped){
swapped = false;
for(int i = 0; i < noOfEmployees; i++){
if(employees[i].combined_name() > employees[i+1].combined_name()){
Employee temp_employee = employees[i+1];
employees[i+1] = employees[i];
employees[i] = temp_employee;
}
}
}
}
My problem is pretty obvious, yet I can not seem to figure out how to solve it: The code sometimes fails on the line (in an undefined manner) :
Employee temp_employee = employees[i+1]
Its pretty obvious because if i is equal to the end of the array, accessing memory with i+1 results in undefined behaviour. However, if I stop the for loop with noOfEmployees-1, this does not happen but the first element is never sorted (obviously).
How can I implement bubble sort properly? It seems as such a trivial task. Am I missing something?
The following simplified version in pure C works fine:
int employees[10]= {3,1,7,6,9,7,1,0,2,6};
int noOfEmployees= 10;
void bubble_sort_address_book(void){
bool swapped = true;
int i;
while(swapped){
swapped = false;
for(i = 0; i < noOfEmployees-1; i++){
if(employees[i] > employees[i+1]){
int temp_employee = employees[i+1];
employees[i+1] = employees[i];
employees[i] = temp_employee;
swapped= true;
}
}
}
}
int main()
{
int i;
bubble_sort_address_book();
for (i=0; i<noOfEmployees; i++) {
printf("emp %d= %d\n", i, employees[i]);
}
return 0;
}
As you request, the function of variable swapped is to indicate that following a complete pass through the array no swap occurred and so it indicates the array is now sorted.
You can use an explicit bound on the outer loop.
You should also split things out into smaller functions.
bool operator <(Employee const & lhs, Employee const & rhs) {
return lhs.combined_name() < rhs.combined_name();
}
// a.k.a. std::swap
void swap(Employee & lhs, Employee & rhs) {
Employee temp(static_cast<Employee&&>(lhs)); // a.k.a. std::move
lhs = static_cast<Employee&&>(rhs);
rhs = static_cast<Employee&&>(temp);
}
void bubble_sort_impl(Employee * begin, Employee * end) {
for (; end != begin; --end) {
for (Employee * it = begin; it+1 != end; ++it) {
if (*(it+1) < *it) {
swap(*it, *(it+1));
}
}
}
}
// do we really need "bubble_" or "_address_book" in this name?
void AddressBook::bubble_sort_address_book() {
bubble_sort_impl(employees, employees + noOfEmployees);
}
another solution:
#include <iostream>
#include <vector>
using namespace std;
int employees[10] = { 3,1,7,6,9,7,1,0,2,6 };
void bubble_sort_address_book(void) {
bool swapped = true;
int i;
int noOfEmployees = 10;
while (swapped) {
swapped = false;
for (i = 1; i <= noOfEmployees ; i++) {
if (employees[i] > employees[i - 1]) {
int temp_employee = employees[i - 1];
employees[i - 1] = employees[i];
employees[i] = temp_employee;
swapped = true;
}
}
}
}
int main()
{
int i;
int noOfEmployees = 10;
bubble_sort_address_book();
for (i = 0; i<noOfEmployees; i++) {
printf("emp %d= %d\n", i, employees[i]);
}
return 0;
}
Related
Can anyone solve this for me? I couldn't find why is it giving error on these specific lines. I guess the syntax is right. I have commented the error lines. It is giving error on open.push_back(p) in DFID function and mylist.push_back(p); in GenerateChildren function Please help me on this. Much Thanks
#include <iostream>
#include <algorithm>
#include <list>
#include <string>
using namespace std;
const int n = 3;
int goal[n][n] = { { 1, 2, 3 },{ 8, 0, 4 },{ 7, 6, 5 } };
static int max_depth = 0;
list <int[3][3]> open;
list <string> closed;
bool DFID(int[3][3]);
list<int[3][3]> generateChildren(int[3][3]);
bool isGoal(int [3][3]);
string convertToString(int[3][3]);
bool inClosed(string);
void main()
{
int puzzle[n][n] = { { 1, 2, 3 }, { 8, 6, 4 }, { 7, 0, 5 } };
DFID(puzzle);
}
bool DFID(int p[3][3])
{
open.push_back(p); // Error on this line
open.pop_front();
list<int[3][3]> mylist = generateChildren(p);
list<int[3][3]>::iterator it;
for (it = mylist.begin(); it != mylist.end(); ++it)
{
if (isGoal(*it))
return true;
else
{
string s =convertToString(*it);
if (inClosed(s))
{
continue;
}
else
{
//
}
}
}
}
list<int[3][3]> generateChildren(int p[3][3])
{
//finding zero element
int a = 0, b = 0;
for (int i = 0; i < n; i++)
{
for (int j = 0; i < n; j++)
{
if (p[i][j] == 0)
{
a = i;
b = j;
break;
}
}
}
list <int[3][3]> mylist;
if (p[-a][b] != -1)
{
swap(p[a][b], p[--a][b]);
mylist.push_back(p); //Error on this line
}
if (p[a][--b] != -1)
{
swap(p[a][b], p[a][--b]);
mylist.push_back(p); //Error
}
if (p[++a][b] != 3)
{
swap(p[a][b], p[++a][b]);
mylist.push_back(p); //Error
}
if (p[a][++b] != 3)
{
swap(p[a][b], p[a][++b]);
mylist.push_back(p); //Error
}
return mylist;
}
bool isGoal(int p[3][3])
{
for (int i = 0; i < n; i++)
{
for (int j = 0; i < n; j++)
{
if (p[i][j] != goal[i][j]);
return false;
}
}
return true;
}
string convertToString(int p[3][3])
{
string puzz;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < n; j++)
{
puzz = puzz + to_string(p[i][j]);
}
}
return puzz;
}
bool inClosed(string s)
{
list<string>::iterator it;
for (it = closed.begin(); it != closed.end(); ++it)
{
if (*it == s);
return true;
}
return false;
}
There are multiple problems with the code as you show it.
One issue is that putting data into a container means it either needs to be move or copied. And arrays can't be neither moved nor copied.
Another issue is that e.g.
bool DFID(int[3][3]);
is equal to
bool DFID(int(*)[3]);
That is, the argument is a pointer and not an array. Pointers and arrays are different.
One possible way to solve your problems (both of them) is to use another standard container, such as std::array:
std::array<std::array<int, n>, n> goal;
std::list<std::array<std::array<int, n>, n>> open;
You can simplify the type with a type-alias:
using matrix_type = std::array<std::array<int, n>, n>;
matrix_type goal;
std::list<matrix_type> open;
The code below a solution to the following requirement:
"Change the representation of Link and List from ยง27.9 without changing the user interface provided by the functions. Allocate Links in an array of Links and have the members: first, last, prev, and next be ints (indices into the array). " - Exercise 6 Chapter 27 - Programming: Principles and Practice Using C++ B. Stroustrup
The interface is inherited from an ordinary implementation of an Intrusive doubly linked list. I've added the bool array (and the associated functions) to keep track of memory:
#include <iostream>
struct Link
{
int next;
int prev;
};
//------------------------------------------------------------------------------------
struct List
{
Link** head;
int first; // points to the current first node
int last;
bool* available;
int list_size;
int get_index()
{
for (int i = 0; i < list_size; ++i)
{
if (available[i] == true)
{
available[i] = false;
return i;
}
}
throw std::bad_alloc("bla bla!\n");
}
List()
{
list_size = 30;
head = new Link*[list_size];
available = new bool[list_size];
first = -1;
last = -1;
for (int i = 0; i < list_size; ++i)
{
available[i] = true;
}
}
void List::push_back(Link* l)
{
if (l == nullptr)
{
throw std::invalid_argument("bla bla!\n");
}
int index = get_index();
head[index] = l;
if (last != -1)
{
head[last]->next = index;
head[index]->prev = last;
}
else
{
first = index;
head[index]->prev = -1;
}
last = index;
head[index]->next = -1;
}
void push_front(Link* l)
{
if (l == nullptr)
{
throw std::invalid_argument("bla bla\n");
}
int index = get_index();
head[index] = l;
if (first != -1)
{
head[first]->prev = index;
head[index]->next = first;
}
else
{
last = index;
head[index]->next = -1;
}
first = index;
head[index]->prev = -1;
}
// index = ptr - base
std::ptrdiff_t index_from_address(Link* l) { return l - head[0]; }
Link* front() const { return head[first]; }
};
//------------------------------------------------------------------------------------
int main()
{
List l;
for (int i = 0; i < 10; ++i)
{
l.push_back(new Link());
}
for (int i = 0; i < 10; ++i)
{
l.push_front(new Link());
}
std::cout <<"first = "<< l.first <<", index = " << l.index_from_address(l.front());
getchar();
}
Expected result:
first = 19, index = 19
Actual result:
first = 19, index = 194
Why?
l - head[0]
Here you compare the values of the two pointers. You let all pointers in the array be default initialized, so their values are indeterminate, and therefore the behaviour of accessing the values is undefined.
You probably intended index_from_address to find the index where a particular pointer object is stored - rather than the object that is pointed to, since the pointed to object is not in the array pointed by head. To do that, you must add a whole bunch of &:
Link*& front() const // return a reference to the pointer object, not a copy
// take a reference to the pointer as an argument, add const for good measure
std::ptrdiff_t index_from_address(Link*& l) const
// compare the addresses of the pointers, rather than values
{ return &l - &head[0]; }
I am trying sort edges in Prim's Algorithm using STL and overloading operator () , But I am getting runtime error Invalid operator and Invalid Heap.
When I compile my code in CodeBlocks everything's working but Visual Studio 2015 displayed runtime errors. What should I do?
struct edge {
int cost;
int start;
int end;
};
struct sorting {
bool operator() (const edge &a, const edge &b)
{
if (a.cost<b.cost) return false;
else return true;
}
};
priority_queue < edge , vector <edge> , sorting> queue;
edge tree[1005];
int T[1000][1000];
int G[1005][1005];
bool ISIT[1005];
string STRINGS[1005];
int ID[40005];
int howmany = 0;
int howmanyneigh[1005];
void PRIM() {
int w = 1;
ISIT[w] = 1;
edge K;
howmany++;
for (int i = 0; i<howmanyneigh[w]; i++) {
K.start = w;
K.end = G[w][i];
K.cost = T[w][G[w][i]];
queue.push(K);
}
while (howmany<N)
edge b;
b = queue.top();
queue.pop();
while (ISIT[b.end]) {
b = queue.top();
queue.pop();
}
ISIT[b.end] = 1;
tree[howmany - 1] = b;
for (int i = 0; i<howmanyneigh[b.end]; i++) {
K.start = b.end;
K.end = G[b.end][i];
K.cost = T[b.end][G[b.end][i]];
queue.push(K);
}
howmany++;
}
}
It seems that you have a problem in your sorting comparator. This comparator should provide strict weak ordering. One of the requirements for strict weak ordering is that comp(a, a) == false. Change your sorting::operator() from
if (a.cost<b.cost) return false;
else return true;
to:
if (a.cost>b.cost) return true;
else return false;
or simply:
return a.cost > b.cost;
I have problem only with the push_back function, the compiler said:
CRT detected that the application wrote to memory after end of heap buffer
I want to make a push_back function, that adds a new element to the vector's end.
#pragma once
#include <cstdio>
#include <cmath>
#include <iostream>
#include <cstdlib>
class tomb {
private:
double *adat;
int szam;
public:
tomb(){
adat = NULL;
szam = 0;
}
int meret()const {
return szam;
}
~tomb() {
delete[] adat;
}
double & operator[](int n) {
return adat[n];
}
const double & operator[](int n)const {
return adat[n];
}
void push_back(const double &a) {
double *tmp;
int pos = szam + 1;
tmp = new double[szam+1];
for (int i = 0; i < szam; i++)
{
tmp[i] = adat[i];
}
tmp[pos] = a;
delete[] adat;
adat = tmp;
++szam;
}
void Kiir()const {
for (int i = 0; i < szam; i++)
{
std::cout << adat[i] << "\n";
}
}
};
pos should be szam not szam+1. You are willing to insert at the last position, which in 0-based indexing is n-1.
The problem is in this line:
tmp[pos] = a;
Since pos is initialized to szam + 1, that is equivalent to:
tmp[szam + 1] = a;
which is one out of the array limit.
The solution is to get rid of pos altogether and just do:
tmp[szam] = a;
BTW, your class is using the default copy constructor and assignment operator, and those will not work properly. You should really do something about that.
Alright, so without going into detail on why I'm writing this class, here it is.
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
aType * Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
aType * Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
aType * Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
It is supposed to be a std::Vector type object, without all the bells and whistles.
Problem is, it doesn't seem to work.
I basically start by going
nArray<string> ca = nArray<string>(5);
ca.Push_Back("asdf");
ca.Push_Back("asdf2");
int intret = 0;
cout << ca.GetAt(1,intret);
I get an Access Violation Reading Location error and it hits on the line
Array[_Count] = Item
in the Push_back function.
The problem seems to be that it's not treating the Array object as an array in memory.
I've spent time going through the code step by step, and I don't know what else to say, it's not operating right. I don't know how to word it right. I'm just hoping someone will read my code and point out a stupid mistake I've made, because I'm sure that's all it amounts to.
Update
So now I changed 3 initializations of Array in nArray(), nArray(int Count), and Resize(int newSize)
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
This is how my code was before. Anyway, the original problem was the fact that when I try to access a specific element in the array, it just accesses the first element, and it doesn't seem to add elements eather. It doesn't seem to be treating Array as an array.
int Resize(int newSize)
{
.
.
aType * Array = new aType[newSize*2];
At this point, instead of updating the member variable as you intended, you've actually created a local variable called Array whose value is discarded when you exit from Resize(). Change the line to
Array = new aType[newSize*2];
The same thing is happening in your constructors, they also need changing accordingly. Moreover, since the default constructor allocates an array, you should set the size members accordingly. You have too many of these: an array needs to keep track of current element count and maximum capacity, however you appear to have three members. What is the purpose of the third? Redundant information is bad, it makes code difficult to read and without a single point of truth it is easier to make mistakes.
With the code in Resize(), you can do better: the second copy is completely redundant.
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
Also, in
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
you need curly braces around body of the if(), just indentation on its own won't do the trick:
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
{
ret = 1;
return aType();
}
ret = 0;
return Array[Index];
}
You have a number of problems. At a guess, the one causing problems so far is that your default ctor (nArray::nArray()) defines a local variable named Array that it initializes, which leaves nArray::Array uninitialized.
Though you probably haven't seen any symptoms from it (yet), you do have at least one more problem. Names starting with an underscore followed by a capital letter (such as your _Size, _MaxSize, and _Count) are reserved for the implementation -- i.e., you're not allowed to use them.
The logic in your Resize also looks needlessly inefficient (if not outright broken), though given the time maybe it's just my brain not working quite right at this hour of the morning.
Your array is not initialized by the constructors and resize function (working on local vars instead).
And is there a reason you want to store instances of string and not pointers to string (string *) ?
I think the answer after the changes is in moonshadow's reply:
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1)
ret = 1;
return aType();
ret = 0;
return Array[Index];
}
This code will always return aType(), the last two lines will never be reached.
You might also want to check what happens if you start out with a default-constructed nArray. (Hint: you call Resize(_MaxSize); but what is the value of _MaxSize in this case?
Edit:
This outputs "asdf2" for me as it should be (with the initialization and the braces fixed):
template<class aType>
class nArray
{
public:
aType& operator[](int i)
{
return Array[i];
}
nArray()
{
Array = new aType[0];
_Size = 0;
_MaxSize = 0;
_Count = 0;
}
nArray(int Count)
{
Array = new aType[Count*2]();
_Size = Count;
_MaxSize = Count * 2;
_Count = 0;
}
int Resize(int newSize)
{
aType *temp = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
temp[i] = Array[i];
}
delete[] Array;
Array = new aType[newSize*2];
for(int i=0;i<_Count;i++)
{
Array[i] = temp[i];
}
delete [] temp;
_Size = newSize;
_MaxSize = newSize*2;
return 0;
}
int Push_Back(aType Item)
{
if(_Count+1 >= _Size)
{
Resize(_MaxSize);
}
Array[_Count] = Item;
_Count++;
return _Count - 1;
}
aType GetAt(int Index, int &ret)
{
if(Index > _Size-1) {
ret = 1;
return aType();
}
ret = 0;
return Array[Index];
}
private:
int _Size;
int _Count;
int _MaxSize;
aType * Array;
};
#include <string>
#include <iostream>
using namespace std;
int main()
{
nArray<string> ca = nArray<string>(5);
ca.Push_Back("asdf");
ca.Push_Back("asdf2");
int intret = 0;
cout << ca.GetAt(1,intret);
}