Issue with sorting algorithm and object pointers - c++

I have an object containing some data such as:
class Employee{
private:
int employee_number;
// +more objects and data
public:
int get_number() {
return employee_number;
}
};
The objects are stored in a pointer array:
Employee* employees[MAX + 1];
The first element in Employee is not used, so the algorithm skips employees[0]
The sorting algorithm is called each time a new employee has been added, here is what the sorting algorithm looks like:
int to = employees.length - 1;
for (int from = 1; from < to; from++) {
if (employees[from]->get_number() > employees[from + 1]->get_number()) {
Employee *tmp = employees[from + 1];
int i = from;
while (i >= 1 && employees[i]->get_number() > tmp->get_number()) {
employees[i + 1] = employees[i];
i--;
}
employees[i + 1] = tmp;
}
}
I'm not sure why this doesn't sort the employees array, as this algorithm works well with regular int arrays. Also keep in mind my entire code is written in my own language, so I had to translate into English here.

Assuming that you want to sort the Employee pointers in ascending order by the data member employee_number (i.e., employee_number is the key) of the objects they are pointing to, you could define the following predicate using a lambda expression:
auto cmp = [](auto a, auto b) {
return a->get_number() < b->get_number();
};
Then, use the std::sort() algorithm with the predicate above:
auto begin = &employees[1]; // skip 1st element
std::sort(begin, employees + num, cmp);
where num above is 1 (since you said that the 1st entry is not used) plus the number of Employee pointers inserted so far.
I'm not really sure what you want to achieve, but if you have the intention of calling std::sort() on the array every time a new Employee is added to the array, you might want to consider using another container like std::set instead of an array.

Related

Problem in merging two sorted arrays using pointers

I am trying to merge two sorted arrays using pointers. The third loop is working food upto first arr[5] but then show garbage values afterwards. is the sorting techniqure wrong or am I using pointers incorrectly?
#include<iostream>
using namespace std;
int main() {
int arr1[] = { 1,3,4,6 };
int arr2[] = { 2,3,4,5 };
int n1 = 4;
int n2 = 4;
int arr3[10];
int* endptr = &arr1[0];
int* endptr2 = &arr2[0];
int* endptr3 = arr3;
int k = 0;
while (endptr < &arr1[n1-1] &&endptr2 < &arr2[n2-1]) {
if (endptr[0] < endptr2[0]) {
endptr3[k++] = endptr[0];
endptr++;
}
else {
endptr3[k++] = endptr2[0];
endptr2++;
}
}
while (endptr < &arr1[n1 - 1]) {
endptr3[k++] = endptr[0];
endptr++;
}
while (endptr2 < &arr2[n2 - 1]) {
endptr3[k++] = endptr[0];
endptr2++;
}
cout << arr3[5];
}
I got the results up to first 6 elements and then get garbage values.
The way you are using the pointers is negatively affecting your thought process.
Let’s abstract it to a function to help make it cleaner:
void merge(
int * first1, int * last1, // elements of array1
int * first2, int * last2, // elements of array2
int * dest ) // where to put sorted data
This is the “iterator” idiom used by C++ algorithms. first points to the first element. last points to one-past the last element. (And we assume that dest points to enough space to contain the results.) So:
int array1[] = { 1,3,4,6 };
int array2[] = { 2,3,4,5,7 };
int array3[9]; // enough room for array1+array2
merge(
array1, array1+4, // first array has 4 elements
array2, array2+5, // second array has 5 elements
array3 ); // destination array has 4+5=9 elements
C++ actually gives us a couple of functions to get the first and last pointers to whatever underlying sequence container you’ve got:
merge(
std::begin(array1), std::end(array1),
std::begin(array2), std::end(array2),
std::begin(array3) );
Now we can reconsider our merge algorithm.
void merge(...)
{
// while both array1 and array2 have elements:
while ((first1 != last1) and (first2 != last2))
{
if (*first2 < *first1)
*dest++ = *first2++;
else
*dest++ = *first1++;
}
// if array1 has any leftover elements:
while (first1 != last1)
*dest++ = *first1++;
// if array2 has any leftover elements:
while (first2 != last2)
*dest++ = *first2++;
}
In particular, notice:
We can easily check whether an array has elements by comparing the first and last pointers directly. When first == last, there are no elements, since last is one-past the end of the source array.
Comparison is simple enough. We could have written that as if (first2[0] < first1[0]) but that is less idiomatic than just using the * operator.
Copying a value is as simple as a dereference and increment on both sides of the assignment.
The three loops of the merge all work on a simple “are there elements left?” check.
Note also how we kept the test condition to a strict less-than comparison. That has ramifications for generic programming (for example, merge sorting in non-increasing order), but I’ll leave it at that for today...

How to use insertion sorting on an array of objects?

I have a Movie class set up and I am trying to create a function to sort an array of movies by release date and then by rating. I have 7 movies in a text document getting stored into my array and getter functions at the ready but I am having trouble converting what little I know about sorting an array of ints into an array where I need to sort strings and then doubles.
Here is my code:
string Movie::getReleaseDate() {
return releaseDate;
}
double Movie::getRating() {
return rating;
}
void sortByDateRating(Movie movies[], int SIZE) {
int i;
int j;
int temp;
for (i = 1; i < SIZE; ++i) {
j = i;
while (j > 0 && movies[j] < movies[j - 1]) {
temp = movies[j];
movies[j] = movies[j - 1];
movies[j - 1] = temp;
--j;
}
}
}
I plan to call this function from a switch case I have in main. Thanks ahead of time.
Unless you really want to implement the sorting yourself, you can use the STL container std::map or the equivalent container from Boost.

Sorting an array by reference

I made a simple routine to sort an array witch accepts as a parameter an array of ints the problem is that when i compare the values array[i] shows the correct value in the debugger but array[i + 1] shows a bogus value ... i guess is a pointer issue but i can't figure it out what i am doing wrong.
Here is the code :
typedef int vector[10];
void task1(vector * param)
{
bool ordered = false;
while (!(ordered))
{
int tmp = 0;
ordered = true;
for (int i = 0; i < 9 ; i++)
{
if (*param[i] > *param[i+1])
{
tmp = *param[i];
*param[i] = *param[i + 1];
*param[i + 1] = tmp;
ordered = false;
}
}
}
}
int _tmain(int argc, _TCHAR* argv[])
{
vector tavi = {10,88,77,192,7,27,82,1,882,13};
task1(&tavi);
for (int i = 0 ; i < 10 ; i ++)
printf("%d ",tavi[i]);
_getch();
return 0;
}
The subscript-operator ([]) has a higher precedence than the derefence-operator (*), so *param[i] is actually *(param[i]). This means, you first go to the i-th element of param, and then dereference it - that is not what you want (param is not a pointer into an array). You want to dereference param and then go to the i-th element - this would be (*param)[i].
First of all: Why would you write the sorting yourself (not to mention that bubblesort is not exactly fast).
So why not simply use
std::sort(tavi, tavi + 10, std::less<int>());
Of course if you have C++11 or boost its also a good idea to forget about c style arrays and use std::array or boost::array instead:
std::array<int, 10> tavi = {10,88,77,192,7,27,82,1,882,13};
std::sort(tavi.begin(), tavi.end(), std::less<int>());
for (int i = 0 ; i < tavi.size(); i ++)
std::cout<<tavi[i]<<" ";
If however you really want to do it like that, *param[i] is the same as *(param[i]), while you want to use (*param)[i].
vector is type int[10]. Therefore, vector* is type int(*)[10]. That is, a pointer to an array of 10 ints. So the distance between param[i] and param[i+1] is sizeof(int) * 10
When you do this:
if (*param[i] > *param[i+1])
You are comparing one array of 10 ints to the next array of 10 ints. I wish this would simply not compile, unfortunately, what happens is that the arrays are implicitly converted to pointers to their first element. Since i < i+1, the above comparison will never be true.

c++ sorting names alphabetically

I have a program that is trying to sort some names alphabetically. I run it and it does not have any errors, but the names are not sorted. I compare 2 names and see which one is supposed to be shifted in the array.
Here is the code:
void sort_names(char array[])
{
const int arraysize = 5;
// Step through each element of the array
for (int startindex = 0; startindex < arraysize; startindex++)
{
int smallestnum = startindex;
for (int currentindex = startindex + 1; currentindex < arraysize; currentindex++)
{
// If the current element is smaller than our previously found smallest
if ((student_list[currentindex].lname) < (student_list[smallestnum].lname))
// Store the index
smallestnum = currentindex;
}
// Swap our start element with our smallest element
swap(student_list[startindex], student_list[smallestnum]);
}
}
My struct looks like this:
struct student {
char fname[30];
char lname[30];
};
Do I have to convert these to strings somewhere because they are characters arrays? I am kind of lost and trying to figure out how to make it sort properly.
The Problem is that in this line:
if ((student_list[currentindex].lname) < (student_list[smallestnum].lname))
it doesn't compare string characters, but rather compares memory adresses.
If you still want to use char arrays, you have to use the strcmp function. However, I recommed that you use string instead.
The problem is this line:
if ((student_list[currentindex].lname) < (student_list[smallestnum].lname))
The line compares the pointers, it does not compare the contents.
It should be:
if ( strcmp( student_list[currentindex].lname, student_list[smallestnum].lname ) < 0 )
Another alternative is to use std::string instead, which has built-in comparisons. For example:
struct student {
std::string fname;
std::string lname;
};

quicksort (n arrays should be treated as 1 and values remapped as needed)

I have a linked list of arrays (struct at bottom of post)
Each array may have values like the below example
Array1[] = {6,36,8,23};
Array2[] = {8,23,5,73};
Array3[] = {2,5,1,9};
I need to sort these so that all 3 arrays are treated as 1 large array...
I need to use quicksort so that it uses in-place processing... I am working with very large arrays and cannot afford to use additional memory..
The result should be something like this
Array1[] = {1,2,5,5};
Array2[] = {6,8,8,9};
Array3[] = {23,23,36,73};
Currently i am only able to sort each array individually... but thats not exactly what i need :(
struct iSection {
unsigned long Section_Count; // Total # of points in this block of memory
int *Section_Arr; // Point cloud for current block of memory
struct iSection *Next; // Pointer to next section
} iSection;
struct iDatabase {
struct iSection *First_Section;
struct iSection *Last_Section;
} iDatabase;
It's not that hard, more an interfacing issue then an algorithmics issue.
Write a wrapper container that provides an interface for accessing members and writing (say operator[] in C++) and internally it maps the size_t index argument to the right array. This wrapper class does need the size of every array though to be able to correctly map the index.
An example pseudocode operator[] would be:
int& JointDatabase::operator[](size_t index) {
// database is an iDatabase
iSection *cur = database.First_Section;
while (cur != database.Last_Section && index >= cur->Section_Count) {
index -= cur->Section_Count;
cur = cur->Next;
}
return cur->Section_Arr[index];
}
Then use this wrapper class as you would use a normal container in your Quicksort algorith.
If you can make sure that Array1, Array2, and Array3 are declared one after another and in continuous memory layout, then you can give the Array1 (the first one) in the sort() and give the combined size of all the arrays.
To check the continuous alignment you can use following trick.
template<size_t SIZE1, size_t SIZE2, size_t SIZE3>
bool Check(int (&a1)[SIZE1], int (&a2)[SIZE2], int (&a3)[SIZE3])
{
return (&a3[SIZE3 - 1] - &a1[0]) == (SIZE1 + SIZE2 + SIZE3);
}
Usage,
bool aligned = Check(Array1, Array2, Array3);
This is an example for 3 arrays, you can make it according to your need. And you can pass Array1,2,3 or Array3,2,1 depending on your machine.
Tested only in my brain:
struct ArrayWrapper {
int** arrays;
int* running_sums;
ArrayWrapper(int **arrays, int *arrays_length, int N) {
running_sums = new int*[N+1];
int sum = 0;
for (int i = 0; i < N; i++) {
running_sums[i+1] = sum;
sum += arrays_length[i];
}
}
int& operator[] (int index) {
int array_start = binary search `running_sum` for the closest number to `index` (round down)
return arrays[array_start][index - running_sums[array_start]]
}
}
so if you have something like:
array1 = {...}
array2 = {...}
...
arrayN = {...}
arrays = {array1, array2, ..., arrayN}
arrays_length = {array1_length, array2_length, ..., arrayN_length}
ArrayWrapper wrapper = new ArrayWrapper(arrays, arrays_length, N);
// wrapper then can be treated like normal array:
wrapper[10] = x;
x = wrapper[10];