sort array by first item in subarray c++ [closed] - c++

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I have an array of arrays, for example: [[4, 204], [10, 39], [1, 500]]).
I want to sort them by the first element of the subarray so that it becomes: [[1, 500], [4, 204], [10, 39]].
I couldn't find any answers to this question for C++.
How would I do this in C++?
code:
int n;
int time;
int timeTable[100][2];
if (inputFile.is_open()) {
for (int i = 0; i < 100; i++) {
inputFile >> n;
timeTable[i][0] = n;
inputFile >> time;
timeTable[i][1] = time;
}
}

One way to sort the array is to not sort the array itself.
Instead, sort an array of indices that point inside of the array, and then use the sorted index to access the elements. It is much easier to do that than to manipulate a 2d array in a sorting function.
In general, if you have the memory for the array of indices (we will need additional storage for the index array), sorting objects that have
a large payload per item, or
the original order of the array needs to be kept around, or
sorting is just clumsy1 or impossible to manipulate easily in a sorting algorithm,
can use this technique that will be described here.
Here is an example:
#include <algorithm>
#include <iostream>
int main()
{
int index[3] = {0,1,2};
int timeTable[3][2] = {{4, 204}, {10, 39}, {1, 500}};
std::sort(index, index + 3, [&](int n1, int n2){ return timeTable[n1][0] < timeTable[n2][0]; });
for (int i = 0; i < 3; ++i)
std::cout << "The index is " << index[i] << ". The data at this index is [" <<
timeTable[index[i]][0] << " " << timeTable[index[i]][1] << "]\n";
}
Live Example
So basically we create an initial index array numbered from 0 to n-1 where n are the number of items to sort. Then we call std::sort on the index, and in the sorting criteria, we compare the items in the actual array using the indices passed to the sorting predicate. The result will be the index array having its elements swapped around during the sort instead of the original array's elements being swapped.
Note that the sorting predicate is very simple -- we state exactly what we want the indices to represent in the sort by using the indices being passed on the timeTable array. There is no tricky, error-prone, or code that does not scale well if one of the items is out of order (for example, the parallel array scenario -- imagine 20 arrays and having to swap 20 items just because one item is out of order).
After sorting the indices, when it comes time to use the timeTable array, we use the index array to point to the items (note how we specify the index by using timeTable[index[i]][0] instead of timeTable[i][0]).
1 Included in the "clumsy" category are those "parallel
array sort" questions that show up on StackOverflow, where the poster is asked to sort multiple arrays "in parallel" based on data in one of those arrays.

Related

Find uncommon elements using hashing

I think this is a fairly common question but I didn't find any answer for this using hashing in C++.
I have two arrays, both of the same lengths, which contain some elements, for example:
A={5,3,5,4,2}
B={3,4,1,2,1}
Here, the uncommon elements are: {5,5,1,1}
I have tried this approach- iterating a while loop on both the arrays after sorting:
while(i<n && j<n) {
if(a[i]<b[j])
uncommon[k++]=a[i++];
else if (a[i] > b[j])
uncommon[k++]=b[j++];
else {
i++;
j++;
}
}
while(i<n && a[i]!=b[j-1])
uncommon[k++]=a[i++];
while(j < n && b[j]!=a[i-1])
uncommon[k++]=b[j++];
and I am getting the correct answer with this. However, I want a better approach in terms of time complexity since sorting both arrays every time might be computationally expensive.
I tried to do hashing but couldn't figure it out entirely.
To insert elements from arr1[]:
set<int> uncommon;
for (int i=0;i<n1;i++)
uncommon.insert(arr1[i]);
To compare arr2[] elements:
for (int i = 0; i < n2; i++)
if (uncommon.find(arr2[i]) != uncommon.end())
Now, what I am unable to do is to send only those elements to the uncommon array[] which are uncommon to both of them.
Thank you!
First of all, std::set does not have anything to do with hashing. Sets and maps are ordered containers. Implementations may differ, but most likely it is a binary search tree. Whatever you do, you wont get faster that nlogn with them - the same complexity as sorting.
If you're fine with nlogn and sorting, I'd strongly advice just using set_symmetric_difference algorithm https://en.cppreference.com/w/cpp/algorithm/set_symmetric_difference , it requires two sorted containers.
But if you insist on an implementation relying on hashing, you should use std::unordered_set or std::unordered_map. This way you can be faster than nlogn. You can get your answer in nm time, where n = a.size() and m = b.size(). You should create two unordered_set`s: hashed_a, hashed_b and in two loops check what elements from hashed_a are not in hashed_b, and what elements in hashed_b are not in hashed_a. Here a pseudocode:
create hashed_a and hashed_b
create set_result // for the result
for (a_v : hashed_a)
if (a_v not in hashed_b)
set_result.insert(a_v)
for (b_v : hashed_b)
if (b_v not in hashed_a)
set_result.insert(b_v)
return set_result // it holds the symmetric diference, which you need
UPDATE: as noted in the comments, my answer doesn't count for duplicates. The easiest way to modify it for duplicates would be to use unordered_map<int, int> with the keys for elements in the set and values for number of encounters.
First, you need to find a way to distinguish between the same values contained in the same array (for ex. 5 and 5 in the first array, and 1 and 1 in the second array). This is the key to reducing the overall complexity, otherwise you can't do better than O(nlogn). A good possible algorithm for this task is to create a wrapper object to hold your actual values, and put in your arrays pointers to those wrapper objects with actual data, so your pointer addresses will serve as a unique identifier for objects. This wrapping will cost you just O(n1+n2) operations, but also an additional O(n1+n2) space.
Now your problem is that you have in both arrays only elements unique to each of those arrays, and you want to find the uncommon elements. This means the (Union of both array elements) - (Intersection of both array elements). Therefore, all you need to do is to push all the elements of the first array into a hash-map (complexity O(n1)), and then start pushing all the elements of the second array into the same hash-map (complexity O(n2)), by detecting the collisions (equality of an element from first array with an element from the second array). This comparison step will require O(n2) comparisons in the worst case. So for the maximum performance optimization you could have checked the size of the arrays before starting pushing the elements into the hash-map, and swap the arrays so that the first push will take place with the longest array. Your overall algorithm complexity would be O(n1+n2) pushes (hashings) and O(n2) comparisons.
The implementation is the most boring stuff, so I let it to you ;)
A solution without sorting (and without hashing but you seem to care more about complexity then the hashing itself) is to notice the following : an uncommon element e is an element that is in exactly one multiset.
This means that the multiset of all uncommon elements is the union between 2 multisets:
S1 = The element in A that are not in B
S2 = The element in B that are not in A
Using the std::set_difference, you get:
#include <set>
#include <vector>
#include <iostream>
#include <algorithm>
int main() {
std::multiset<int> ms1{5,3,5,4,2};
std::multiset<int> ms2{3,4,1,2,1};
std::vector<int> v;
std::set_difference( ms1.begin(), ms1.end(), ms2.begin(), ms2.end(), std::back_inserter(v));
std::set_difference( ms2.begin(), ms2.end(), ms1.begin(), ms1.end(), std::back_inserter(v));
for(int e : v)
std::cout << e << ' ';
return 0;
}
Output:
5 5 1 1
The complexity of this code is 4.(N1+N2 -1) where N1 and N2 are the size of the multisets.
Links:
set_difference: https://en.cppreference.com/w/cpp/algorithm/set_difference
compiler explorer: https://godbolt.org/z/o3KGbf
The Question can Be solved in O(nlogn) time-complexity.
ALGORITHM
Sort both array with merge sort in O(nlogn) complexity. You can also use sort-function. For example sort(array1.begin(),array1.end()).
Now use two pointer method to remove all common elements on both arrays.
Program of above Method
int i = 0, j = 0;
while (i < array1.size() && j < array2.size()) {
// If not common, print smaller
if (array1[i] < array2[j]) {
cout << array1[i] << " ";
i++;
}
else if (array2[j] < array1[i]) {
cout << array2[j] << " ";
j++;
}
// Skip common element
else {
i++;
j++;
}
}
Complexity of above program is O(array1.size() + array2.size()). In worst case say O(2n)
The above program gives the uncommon elements as output. If you want to store them , just create a vector and push them into vector.
Original Problem LINK

How to iterate over unique elements in an array in c++ [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
Suppose I have the following array:
int arr[7] = {18,16,5,5,18,16,4}
How can I iterate over unique elements(18, 16, 5 and 4) in a loop in the same order in which they occur?
I could use a set but then the order of the iteration would change(set stores elements in ascending order).
What is the fastest solution to this problem?
Iterate over the array and store the numbers you have already seen in a set. For each iteration you check whether the number is already in the set or not. If yes, skip the current element. If not, process it and insert it into the set.
Also note that you want an std::unordered_set and not a std::set which is ordered. Order doesn't matter for your filtering set.
If the values are in a known limited range, you can use a lookup table. Create an array with bool elements, sized to maximum value + 1. Use the values of the first array as index into the bool array.
#include <iostream>
int main() {
int arr[7] = {18,16,5,5,18,16,4};
constexpr int maxValue = 18;
bool lookup[maxValue + 1]{};
for( auto i : arr )
{
if( ! lookup[ i ] )
{
std::cout << i << ' ';
lookup[ i ] = true;
}
}
}
Live Demo
A std::bitset would be more space efficient but also slower, because individual bits cannot be directly addressed by the CPU.
Simply replace the bool array like so:
std::bitset<maxValue + 1> lookup;
The remaining code stays the same.
Live Demo

how do i go about using a bubble sort for sorting 4 arrays from least to greatest? c++

i have 4 arrays which are parallel to each other. one of the arrays holds an integer value. I'm supposed to make the array that holds the integer value sorted from smallest integer value to greatest integer value. The part I'm confused about is after i use the bubble sort technique is that my other 3 arrays that were parallel to the integer array are no longer parallel because the subscript value changed. How do I go about making my other 3 arrays parallel to the new integer array values. Say that I have IntegerArray[0]=2 IntegerArray[1]=1 and I then sort it in order IntegerArray[0]=1 IntegerArray[1]=2 how would I make sure that my other arrays are parallel? say that IntegerArray[0]=2 (the original before sorting) was parallel with say NameArray[0]=Greg NameArray[1]=George if I ran a for loop to print my array values how would I make it so that names array would be parallel with my sorted integer array? Also besides the name array, I have two other arrays that need to be parallel as well.
Sorting 4 parallel arrays can be implemented in exactly the same way as a sorting a single array, except in the part where you would swap two values of the single array, you instead swap the corresponding indices in all 4 of the arrays.
Another approach is to "zip" the arrays into a single array of class objects and sort that. This allows you to use a regular sorting algorithm with no changes to swapping, but of course requires zipping and unzipping of the parallel arrays.
One way to sort parallel arrays is to not sort the arrays themselves, but sort an array of index values that point to the first, second, third, etc. item into the arrays.
Here is an example:
#include <iostream>
#include <algorithm>
#include <string>
int main()
{
std::string names[5] = { "Jack", "Joe", "Alice", "Bob", "Carol" };
int grades[5] = { 80, 75, 90, 95, 68 };
//...
int index[5] = { 0,1,2,3,4 };
//...
// perform bubble sort on the grades in ascending order
for (int i = 0; i < 5; ++i)
{
for (int j = 0; j < 4; ++j)
if (grades[index[j]] > grades[index[j+1]])
std::swap(index[j], index[j+1]);
}
// print out the sorted values, sorted by grade in ascending order
for (int i = 0; i < 5; ++i)
std::cout << names[index[i]] << " " << grades[index[i]] << "\n";
}
Live Example
Note that the only thing actually swapped are values in the array of indices. The arrays with the actual data are never changed.

I am trying my sorting method, which works well with data with no repeates entries, but am getting random numbers in place of repeated numbers?

I have been trying a sorting method in which I subtract each number stored in an array by other elements in the same array. Then, I saw a pattern that the number of differences which come to be negative, is the rank or position of element in the Sorted one. But, things go wrong when I am using repeated entries.
My basic method is :
Take every element of the SampleArray.
subtract it from every element of the SampleArray
check if the difference comes to be negative.
if it is then, increase a variable called counter.
And use this counter as the position of element in sorted array.
For example: lets take (5,2,6,4)
first take 5, subtract it from each of the numbers which will give results (0,-3,1,-1), so counter will become 2, which will be the index of 5 in the sorted Array. And repeat it for each of the elements.
for 5, counter will be 2.
for 2, counter will be 0.
for 6, counter will be 3.
for 4, counter will be 1.
And hence the sorted Array will be {2,4,5,6}.
First, see the code :
#include <iostream>
using namespace std;
void sorting(int myArray[], int sizeofArray);
int main()
{
int checkArray[] = {5,4,2,20,12,13,8,6,10,15,0}; //my sample Arry
int sized;
sized=sizeof checkArray/sizeof(int);//to know the size
cout << sized << endl;
sorting(checkArray, sized);
}
void sorting(int myArray[], int sizeofArray)
{
int tempArray[sizeofArray];
for (int i=0; i<sizeofArray; i++)
{
int counter=0;
for (int j=0;j<sizeofArray; j++ )
{
int checkNum = myArray[j]-myArray[i];
if (checkNum<0)
counter++; //to know the numbers of negatives
else
counter+=0;
}
tempArray[counter]=myArray[i];
}
for (int x=0;x<sizeofArray; x++)
{
cout << tempArray[x] << " " ;
}
}
Now, if we run this program with entries with no repetitions then, it sorts out the array, But if we use repeated entries like
int checkArray[] = {8,2,4,4,6}
the tempArray gets its first element as 2 as counter will be zero.
the tempArray gets its second element as 4 as counter will be 1.
but, the tempArray can't get its third one as counter will be still 1, and thus prints some randomNo in place of this. (here the things go wrong).
Can you please suggest a method to solve this?
This is an odd way of writing insertion sort, https://en.wikipedia.org/wiki/Insertion_sort
I would assume you can change your condition to:
if (checkNum<0 || (checkNum==0 && j<i))
But I would suggest using a proper sorting routine instead
The idea is to separate duplicates by saying that if the values are the same we sort according to their order in the sequence; as if the sequence was a pair of the value and the sequence number (0, 1, 2, 3, 4, 5, ...).
The issue here is that for any 2 equally sized numbers the nested loop will return the same counter value. Thus for such a counter value tempArray[counter + 1] will never be initialized.
The way to solve this would be to maintain a vector<bool> denoting what each position had been written and write to the next valid position if that is the case.
But supporting a second vector is just going to make your O(n2) code slower. Consider using sort instead:
sort(begin(checkArray), end(checkArray))

C++ Sorting Array. Why need other sort method? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
--------Adding 4/27/2015
I think I get some idea from #Ulrich Eckhardt. And thanks all for replying.
Question: for sorting array, why not directly use sort(), what algorithm in sort()?
Remember when I was studying at school, professor gave us C++ homework about sorting an array. We use lots of time, and we thought something crazy that could do "A[]=B[]" or "A.size()"[just clarify we could not do those things in array]. Then our professor taught us sorting algorithm. Sorting array became something like this:(quickSort for example)
void quickSort(int arr[], int left, int right) {
int i = left, j = right;
int tmp;
int pivot = arr[(left + right) / 2];
/* partition */
while (i <= j) {
while (arr[i] < pivot)
i++;
while (arr[j] > pivot)
j--;
if (i <= j) {
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
i++;
j--;
}
};
/* recursion */
if (left < j)
quickSort(arr, left, j);
if (i < right)
quickSort(arr, i, right);
}
When I saw the sort() I was sharked. Actually life could be so simple.
Question: for sorting array, why not directly use sort(). What is sort()? and what algorithm in sort()? how to implement sort()?
-----------------------Adding 4/27/2015
Just wondering, for sorting array. We have "sort" method already in algorithm library, and why we still need all kinds of other sorting method (like quick sort, merge sort, bubble sort...) to sort array? Does that cost less time? The code for sorting array is like below.
#include <iostream>
#include <algorithm>
int main()
{int array[]={23, 5, -10, 0, 0, 321, 1, 2, 99, 30};
int elements =sizeof(array)/sizeof(array[0]);
std::sort(array, array + elements);
for(int i =0; i < elements;++i)
std::cout<< array[i]<<' ';
}
Also could sort strings:
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
int main()
{ string array[] = { "s", "a", "b", "c", "d", "e", "f", "f", "b", "sg" };
int elements = sizeof(array) / sizeof(array[0]);
std::sort(array, array + elements);
for (int i = 0; i < elements; ++i)
std::cout << array[i] << ' ';
}
Thanks all for taking time answering.
std::sort also uses some comparison sort algorithm. And different algorithms have different usages. Best example: Bead sort. This algorithm has a pretty good runtime complexity. But it can only be used for unsigned integers. Every algorithm has its own flaws and strengthes.
No doubt quick sort sort()and merge sort stable_sort() are the fastest but there are factors such as whether given order of the elements in container is random,nearly sorted, reversed or it contains duplicate values.
Combine these factors with one more factor that is number of elements to be sorted gives you the idea why we might need different sorting algos.
Sorting algos are invented one after the other and every newly discovered sorting algo was required to be faster than previous one to get accepted.
To get the mist clear on algos' runtime you can refer to:
http://www.sorting-algorithms.com/
I hope that helped. Comment for further clarification.
The built in algorithm library isn't enough to sort data. It needs a backbone, which is the algorithm(Merge/Bubble/Heap) and code.