C++: Sort functions - c++

I am a C++ beginner. I want to understand how is this function operating on a string to sort it?
int SA_cmp(const void *a, const void *b) { return strcmp(S + *(int*)a, S + *(int*)b); }
any pointer will help?

That's a C comparison function, not a (C++) sorting function. A sort function (probably qsort, given the const void* arguments) would call it a number of times (passing it pointers to what are apparently indices into a buffer containing a number of null-terminated strings) in order to sort those indices (and, indirectly, the substrings they indicate).

This will not sort a string.
This is a method that helps comparing strings and is used by sorthing methods as a helper method.
It will return a negative number if string a is lexicographically smaller than string b, 0 if they are equal, or a positive number if b is greater than a.

Related

How can I compare if a char is higher or lower in alphabetical order than another?

Pretty much as the title. I'm writing a linked list and I need a function to sort the list alphabetically, and I'm pretty stumped. Not sure how this has never come up before, but I have no idea how to do it other than to create my own function listing the entire alphabet and comparing positions of letters from scratch.
Is there any easy way to do this?
Edit for clarity:
I've got a linear linked list of class objects, each class object has a char name, and I'm writing a function to compare the name of each object in the list, to find the highest object alphabetically, and then find the next object down alphabetically, etc, linking them together as I go. I already have a function that does this for an int field, so I just need to rewrite it to compare inequalities between alphabetical characters where a is largest and z is smallest.
In hindsight that was probably a lot more relevant than I thought.
I think a couple of the answers I've gotten already should work so I'll pop back and select a best answer once I've gotten it working.
I'm also working with g++ and unity.
I think that in general case the best approach will be to use std::char_traits:
char a, b;
std::cin >> a >> b;
std::locale loc;
a = std::tolower(a, loc);
b = std::tolower(b, loc);
std::cout << std::char_traits::compare(&a, &b, 1u);
But in many common situations you can simply compare chars as you do it with other integer types.
My guess is that your list contains char* as data (it better contain std::strings as data). If the list is composed of the latter, you can simply sort using the overloaded std::string's operator<, like
return str1 < str2; // true if `str1` is lexicographically before `str2`
If your list is made of C-like null-terminated strings, then you can sort them using std::strcmp like
return std::strcmp(s1, s2);
or use the std::char_traits::compare (as mentioned by #Anton) like
return std::char_traits<char>::compare(s1, s2, std::min(std::strlen(s1), std::strlen(s2)));
or sort them via temporary std::strings (most expensive), like
return std::string(s1) < std::string(s2); // here s1 and s2 are C-strings
If your list simply contains characters, then, as mentioned in the comments,
return c1 < c2; // returns true whenever c1 is before c2 in the alphabet
If you don't care about uppercase/lowercase, then you can use std::toupper to transform the character into uppercase, then always compare the uppercase.
#include <stdio.h>
#include <ctype.h>
void main(void) {
char a = 'X', b = 'M';
printf("%i\n", a < b);
printf("%i\n", b < a);
printf("%i\n", 'a' < 'B');
printf("%i\n", tolower('a') < tolower('B'));
}
prints out:
0
1
0
1
chars are still numbers, and can be compared as such. The upper case letters and lower case letters are all in order, with the upper case letters before the lower. (Such that 'Z' < 'a'.) See an ASCII table.
As you can see from this ASCII table, all of the alphanumeric characters appear in the correct alphabetical order, regarding their actual values:
"Is there any easy way to do this?"
So yes, comparing the character values will provide to have them sorted in alphabetical order.
would something like below suffice ? convert everything to upper first.
class compareLessThanChar{
public:
bool operator()(const char a, const char b)
{ return toupper(a) < toupper(b); }
}
std::multiset<char, compareLessThanChar> sortedContainer;

Applying c++ "lower_bound" on an array of char strings

I am trying the lower_bound function in C++.
Used it multiple times for 1 d datatypes.
Now, I am trying it on a sorted array dict[5000][20] to find strings of size <=20.
The string to be matched is in str.
bool recurseSerialNum(char *name,int s,int l,char (*keypad)[3],string str,char (*dict)[20],int
dictlen)
{
char (*idx)[20]= lower_bound(&dict[0],&dict[0]+dictlen,str.c_str());
int tmp=idx-dict;
if(tmp!=dictlen)
printf("%s\n",*idx);
}
As per http://www.cplusplus.com/reference/algorithm/lower_bound/?kw=lower_bound , this function is supposed to return the index of 'last'(beyond end) in case no match is found i.e. tmp should be equal dictlen.
In my case, it always returns the beginning index i.e. I get tmp equal to 0 both 1. When passed a string that is there in the dict and 2. When passed a string that is not there in the dict.
I think the issue is in handling and passing of the pointer. The default comparator should be available for this case as is available in case of vector. I also tried passing an explicit one, to no avail.
I tried this comparator -
bool compStr(const char *a, const char *b){
return strcmp(a,b)<0;
}
I know the ALTERNATE is to used vector ,etc, but I would like to know the issue in this one.
Searched on this over google as well as SO, but did not find anything similar.
There are two misunderstandings here, I believe.
std::lower_bound does not check if an element is part of a sorted range. Instead it finds the leftmost place where an element could be inserted without breaking the ordering.
You're not comparing the contents of the strings but their memory addresses.
It is true that dict in your case is a sorted range in that the sense that the memory addresses of the inner arrays are ascending. Where in relation to this str.c_str() lies is, of course, undefined. In practice, dict is a stack object, you will often find that the memory range for the heap (where str.c_str() invariably lies) is below that of the stack, in which case lower_bound quite correctly tells you that if you wanted to insert this address into the sorted range of addresses as which you interpret dict, you'd have to do so at the beginning.
For a solution, since there is an operator<(char const *, std::string const &), you could simply write
char (*idx)[20] = lower_bound(&dict[0], &dict[0] + dictlen, str);
...but are you perhaps really looking for std::find?

How can I pass the whole struct to a function including all elements?

I have a structure that I want to pass to a function which will sort the struct. However, I don't know how to pass the WHOLE structure.
What I've done is this until now:
void sort_datoteka_sifra(pole &artikli){
}
And I call it like sort_datoteka_sifra(artikli[0]) etc.. but it only passes the [0] elements, I want to pass the whole structure, so that I can use it in the function without having to call artikli[0], artikli[1] and so on in the main function.
You have several options here.
Pass the array as a pointer to its first element as well as the number of elements:
void sort_datoteka_sifra(pole *artikli, int count){
}
If count is static (known at compile time), you can also pass the array by reference:
void sort_datoteka_sifra(pole (&artikli)[100]){
}
If you don't want to hardcode the count, use a function template:
template <int N>
void sort_datoteka_sifra(pole (&artikli)[N]){
}
Use std::vector instead of C-arrays:
void sort_datoteka_sifra(std::vector<pole> &artikli){
}
Use std::sort instead of your custom sort function (#include <algorithms>) and use it with either your existing C-array or (recommended) a std::vector:
std::sort(std::begin(artikli), std::end(artikli));
You have to provide a way to compare two objects; this is done by either overloading operator< or by passing a function (or functor) to the sort algorithm:
bool comparePole(const pole & a, const pole & b) {
return /* condition when you want to have a before b */
}
std::sort(std::begin(artikli), std::end(artikli), &comparePole);
If you don't want to write a function and have C++11, you can use a lambda function:
std::sort(std::begin(artikli), std::end(artikli), [](const pole & a, const pole & b) {
return /* condition when you want to have a before b */
});
If you want to compare the elements by some member (which has a corresponding operator< overload, which is the case for simple types like int, std::string, etc.), use compareByMember from my other answer at https://stackoverflow.com/a/20616119/592323, e.g. let's say pole has an int ID by which you want to sort:
std::sort(std::begin(artikli), std::end(artikli), compareByMember(&pole::ID));
To sort a sub-array of size count, don't use std::end but:
std::sort(std::begin(artikli), std::begin(artikli) + count, &comparePole);
Of course you can combine the third option with one of the first two, i.e. provide a sort function which is implemented in terms of std::sort.
Your function requests a reference to a single element. And you obviously also pass only a single element. So, to pass the complete array, you should use a pointer, if it's an array allocated with new Or a statically allocated array, e.g.
void fun(pole* artikli);
Otherwise for C++, it's common to use std::vector and pass it by reference:
std::vector<pole> artikli;
void fun(std::vector<pole>& artikli);

Sorting a two-dimensional array of characters? 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];

Comparing voids in c++

Trying to compare voids for a sorting algorithm. I have this so far but it kinda defeats the purpose IMO if you cast them to ints. Is there a way to compare voids? My professor ran out of time and how were stuck scowering the web. Any help is appreciated. Thanks
int fcmp(const void *one, const void *two)
{
if (*(int*)one > *(int*)two) return 1;
if (*(int*)one < *(int*)two) return -1;
return 0;
}
Assuming that the idea is to use fcmp in the context of qsort, your code is perfectly valid.
Since qsort does not care for the returned value to be 1 or -1 and would take any positive or negative number, this version is even shorter, but would work with qsort just as well:
int fcmp (const void * one, const void * two)
{
return ( *(int*)one - *(int*)two );
}
The reason qsort uses void* is to let you use the same algorithm with different data types.
You are not comparing "voids" in this code. The code is casting the void pointers into int pointers, and then dereferencing the result, which means you're comparing the ints to which the pointers point to. Ideally, the function would have been written like this:
int fcmp(const int *one, const int *two)
{
if (*one > *two) return 1;
if (*one < *two) return -1;
return 0;
}
But it isn't written like that since fcmp() in this case needs to have a specific signature. Otherwise it couldn't be used in a generic way. As a callback to another function, for example.
This looks to be a standard comparison function used in several of the standard library functions like qsort() in which you call the function with some kind of array of data items along with the comparison function that indicates whether two elements are equal to each or or not and if not what is their collating order.
So what the void pointer points to is kind of up to the programmer. That is the purpose of using the void pointers in the comparison function interface because the function, such as qsort(), which is calling the comparison function just wants to know what order two array elements are to go in. It does not know what the array elements are or how to do the comparison, it just knows the starting address of the array and the size of each element and how many elements are there.
Another function from the standard library is the bsearch() function.
So to use this you might have code like the following:
see qsort() man page.
typedef struct {
int iValue;
char sName[10];
} DataValue;
// compare two elements of the array and indicate which one is higher
// or lower in collating sequence or if they are equal.
int dataComp (void *one, void *two)
{
return ((DataValue *)one)->iValue - ((DataValue *)two)->iValue;
}
int main (int argc, char *argv[])
{
DataValue myData[25];
//.. put some data stuff in the array.
// call qsort with the array. specify number of elements and size of each one
qsort (myData, sizeof(myData)/sizeof(myData[0]), sizeof(myData[0]), dataComp);
}