Sorting a two-dimensional array of characters? C++ - c++

I'm trying to sort a 10X15 array of characters, where each row is a word. My goal is to sort it in a descending order, from the largest value word at the top, at array[row 0][column 0 through 14] position, and the smallest value word at the bottom array[row 9][column 0 through 14]. Each row is a word (yeah, they don't look as words, but it's to test the sorting capability of the program).
To clarify: What I need to do is this... considering that EACH row is a whole word, I need to sort the rows from the highest value word being at the top, and the lowest value word being at the bottom.
Edit:
Everything works now. For anyone who has a similar question, look to the comments below, there are several fantastic solutions, I just went with the one where I create my own sort function to learn more about sorting. And thanks to all of you for helping me! :)

You are using c++ so quit using arrays and begin with stl types:
Convert each row into a string:
string tempString
for (int i = 0; i < rowSize; ++i) {
tempString.pushBack(array[foreachrow][i])
}
add them to a vector
std::vector<std::string> sorter;
sorter.push_back(tempString);
Do that for each row.
std::vector<std::string> sorter;
for each row {
for each coloumn {
the string thing
}
push back the string
}
Then sort the vector with std::sort and write the vector back into the array (if you have to but don't because arrays suck)

As usual, you need qsort:
void qsort( const void *ptr, size_t count, size_t size,
int (*comp)(const void *, const void *) );
That takes a void pointer to your starting address, the number of elements to sort, the size of each element, and a comparison function.
You would call it like this:
qsort( array, ROWS, COLS, compare_word );
Where you define compare_word to sort in reverse:
int compare_word( const void* a, const void* b )
{
return strncmp( b, a, COLS );
}
Now, given that each word is 15 characters long, there may be padding to deal with. I don't have absolute knowledge that the array will be packed as 10 by 15 instead of 10 by 16. But if you suspect so, you could pass (&array[1][0] - &array[0][0]) as the element size instead of COLS.
If you are not allowed to use qsort and instead must write your own sorting algorithm, do something simple like selection sort. You can use strncmp to test the strings. Look up the function (google makes it easy, or if you use Linux, man 3 strncmp). To swap the characters, you could use a temporary char array of length COLS and then 3 calls to memcpy to swap the words.

The problem with your new code using string and vector is a simple typo:
sorter[count] = array[count+1]; should be sorter[count] = sorter[count+1];

Related

Iterating over a column of a multidimensional array with std::count_if()?

I have a multidimensional array of type double (double someArray[10][20]). I'd like to:
a) use std::count_if() to iterate over a single column of that array, returning the number of values greater than some number
b) also require that the row index of that number is within a certain range.
I know the basics of using std::count_if (i.e. I know how to iterate over, say, some vector and return values greater than/less than/equal to some value, for example), but I'm not sure how to do this over a column of a multidimensional array, or how to check that the index of the element also satisfies some condition.
If you are willing to use boost::range, you can use the count_if with a stride count.
The reason why this will work is that an array, regardless of the number of dimensions, will store its data in contiguous memory, thus random-access iteration will work exactly as it would a one-dimensional array.
Thus the goal is to figure out the starting column (easy), and instead of iterating one element at a time forward as you would with the "normal" std::count_if, you want to iterate (in your case) 20 elements, since iterating that many will take you to the next row of the column you're interested in.
For a 2D array of M x N size, the starting and ending addresses you would use for the STL algorithm functions would be:
start: &array2D[0][0]
end (one item passed the end): &array[M-1][N]
Given this information, here is an example using boost:
#include <boost/range/adaptor/strided.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/assign.hpp>
#include <boost/range/algorithm.hpp>
#include <algorithm>
#include <iostream>
#include <numeric>
int main()
{
using namespace boost::adaptors;
using namespace boost::assign;
// declare and fill in the array with numbers starting from 0
double someArray[10][20];
std::iota(&someArray[0][0], &someArray[9][20], 0.0);
// let's get the address of the start of the third column
const double* startAddr = &someArray[0][2];
// here is the address of the end of the 2-dimensional array
const double* endAddr = &someArray[9][20]; // add up the third column
// create a SinglePass range consisting of the starting and ending address
// plus the stride count
auto str = std::make_pair(startAddr, endAddr) | strided(20);
// count how many items in the third column are less than 60
auto result = boost::range::count_if(str, [&](double val) { return val < 60; });
std::cout << result;
}
Output:
3
Divide and conquer.
Use count_if to iterate over a single column of a multidimensional array, checking that the index of the row is within a certain range.
Break the problem into smaller pieces, until they are small enough to solve.
Use count_if
iterate over a single column of a multidimensional array
checking that the index of the row is within a certain range
Hmm... that first task looks doable. Maybe the last. Back to division.
Use std::count_if
iterate:
over an array
but it's multidimensional
only one column matters
checking that the index of the row is within a certain range
Iterating over an array is not hard, given std::begin and std::end. The multidimensional aspect looks scary, so let's wait on that and see how far we can get. For now, just plug "iterate over an array" into "use count_if".
std::count_if(std::begin(someArray), std::end(someArray), [](auto & element)
{ return ???; });
Hmm... the name element is not accurate is it? When std::begin is applied to double [][20], only one dimension is consumed. The result of de-referencing is not double but double [20], so row would be a more accurate name.
std::count_if(std::begin(someArray), std::end(someArray), [](auto & row)
{ return ???; });
The multidimensional aspect might have just taken care of itself. Can we focus on just one column? Let's assume a variable named column is the desired column index, and target can be the "some number" from the problem description.
std::count_if(std::begin(someArray), std::end(someArray), [column, target](auto & row)
{ return row[column] > target; });
So that leaves restricting the row index to a certain range. That is, iterate over the restricted range instead of over the entire array. Looks like a job for std::next and std::prev. We'll just need two more variables to give us the range; let's use from and to.
// Check only the desired rows
auto start = std::next(std::begin(someArray), from);
auto stop = std::prev(std::end(someArray), 9 - to);
return std::count_if(start, stop, [column, target](auto & row)
{ return row[column] > target; });
(I don't like that magic number 9. Better would be ROWS-1, assuming suitable constants have been declared so that the array's declaration can become double someArray[ROWS][COLS].)

c++ indexed container with o(1) lookup

I am going to store char's in some container, then take char's from a string and look up index for char from string in said container.
I also need to do the opposite, take an index and find out what char is there.
So it be more like:
container<char> c;
int index = c.indexOf('a');
char letter = c[12];
I don't care about insert or remove operations.
I suppose the best solution would be to just use a string or char table.
Then do:
int index = 'a'-myString[0]; //for lookup
char c = myString[index]; //for index
The generic data structure that has the ability to look up in two directions is the bidirectional map. If implemented with hash tables, it should have constant complexity for lookup.
Now, if we can make the assumption that char is 8 bits wide, and that your indices are contiguous, then we can use a greatly simpler data structure: Simply store the characters in an array. Use another array of size 1 << CHAR_BIT to store the index of each character.

Sort merged array consisting of sorted arrays

I got two sorted arrays e.g. (3,4,5) and (1,3,7,8) and I got the combined sorted array (3,4,5,1,3,7,8).
Now I would like to sort the already combined array, without splitting it, but by overwriting it, by making use of the fact that it consists of 2 arrays which had already been sorted. Is there any way of doing this efficiently? I know there are a lot of threads about how to do this, by iterating through the sorted arrays and then putting the values into the new array accordingly, but I haven't seen this type of question anywhere yet. I would like to do this in c, but any help / pseudocode would be very kindly appreciated. Thanks!
Edit: The function which would do the sorting, would only be given the combined array and (maybe ) the length of the other two arrays if needed.
If you already have the original sorted arrays, the combined array (note it is not sorted) doesn't really help, except in that your destination storage is already allocated.
There's a well-known and very simple algorithm for merging two sorted ranges, but you can just use std::merge instead of coding it yourself.
Note that only works for non-overlapping input & output ranges: for your amended question, use std::inplace_merge, with the middle iterator set to the first element from your second sequence:
void sort_combined(int *array, size_t total, size_t first) {
std::inplace_merge(array, array + first, array + total);
}
// and use it like
int combined[] = {3, 4, 5, 1, 3, 7, 8};
const size_t first = 3;
const size_t second = 4;
const size_t total = 7; // == sizeof(combined)/sizeof(*combined)
sort_combined(combined, total, first);

Sorting dates (string) stored in vector

I have a vector that contains dates in this format, DDMMMYY, e.g 12Jan14
vector<string> tempDate
When I use the STL sort, basically it will work when all of the dates are in the same year/month. 01Jan14, 05Jan14, 11Jan14, etc. But when I enter 02Feb14, it will all be messed up.
sort (tempDate.begin(), tempDate.end())
Can anyone tell me what went wrong with it?
Edit: I tried to use templates, but it doesn't work as all the string got 'split' up.
I did some troubleshooting inside the sortDayMonthYear
template <class T>
bool sortDayMonthYear(T a, T b)
{
for (int i =0; i < a.size(); i++)
cout << a.at(i)<< endl;
}
What i get is something like this
0
1
J
A
N
1
4
0
2
J
A
N
1
4
Actually what I intend to do is to pass the two strings into the template function, using substr to get the day, month, year, compare and return true or false.
Your predicate should take two constant string references as argument, and then use those to decide which one is "lesser" than the other.
So:
bool sortDayMonthYear(const std::string& first, const std::string& second)
{
// Algorithm to find out which string is "lesser" than the other
}
Then you use that comparator function when sorting:
std::sort(std::begin(tempDate), std::end(tempDate), sortDayMonthYear);
The standard way of sorting strings is lexicographical (by alphabet, for each letter, just like in a dictionary).
Therefore, what you need is your own comparator. There is a version of sort which takes one as third parameter. See e.g. this question for starting ideas: Sorting a vector of custom objects

Fastest way to take 2D input and sort it simultaneously Row wise

I need a way in Which I can take the Input in a 2d array and sort it row wise in one of the fastest way . I tried taking Input and Sort it simultaneously using Insertion Sort. The Second thing I used is i took a multimap individually for a row and inserted with key value as the value i want and mapped value relates to that key as some Dummy value . Since map sorts key while Inserting It could be the one way I thought .
The below code is for making sure that 1 row in my 2D has its element sorted in
multimap. Basically you can say that I dont want to use a 2D structure at all as I
will use these rows individually one by one and hence can be considered as 1D array.
I also want they they gets rearranged While reading the Input , so i dont have to
extra opeartions for doing them.
for(long int j=1;j<=number_in_group;j++)
{
cin >> arrival_time;
arrival_map.insert(pair<long int, long int>(arrival_time,1));
}
Try an STL std::priority_queue? The output is guaranteed to be sorted, and if you polarize the inputs to be 2-D objects (that contain a row number for example) you're queue will build literally perfectly. At that point simply slurp the number off the queue in batches of 'n' where 'n' is your row size and each one will be sorted correctly. You will need a element type that encodes both the value AND the row in your priority queue, and sorts biased to the row # first, then then value. Your example uses long int as the data type for your values. Assuming your rows are no larger than the size of a system unsigned int:
class Element
{
public:
Element(unsigned int row, long int val)
: myrow(row), myval(val)
{};
bool operator <(const Element& elem)
{
return (myrow < elem.myrow ||
(myrow == elem.myrow && myval < elem.myvel);
}
unsigned int myrow;
long int myval;
};
typedef std::priority_queue<Element> MyQueue;
Note: this takes advantage of the priority queue's default comparison operator invoking std::less<>, which simply compares the items using the item-defined operator <(). Once you have this simply push your matrix into the queue, incrementing the row index as you switch to the next row.
MyQueue mq;
mq.push_back(Element(1,100));
mq.push_back(Element(1,99));
mq.push_back(Element(2,100));
mq.push_back(Element(2,101));
Popping the queue when finished will result in the following sequence:
99
100
100
101
Which I hope is what you want. Finally, please forgive the syntax errors and/or missing junk, as I just blasted this on the fly and have no compiler to check it against. Gotta love web cafes.