C++ more then one max values

Pages: 12
Is there any C++ function that returns the highest values in an (int) vector, e.i.
{4, 0, 2, 4}?
Hope there is a function that can return: "The highest values are at position 0 and at position 3".

max_element shows only one element.

I could manage this with for-loop and if-statments, but...

Thank you, guys.


 
vector <int> n = {4, 0, 2, 4}

Last edited on
You could make a function yourself that takes as an argument a vector if ints and an int to indicate how many of the highest values you want to return. Then you return a vector of ints.
I don't know if there is a standard library function that is more suitable for this but you can use max_element
http://www.cplusplus.com/reference/algorithm/max_element/

The idea would be to find the largest element and iterate thereon to find all successive values that are equivalent to the largest value.

Like so:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <vector>
#include <algorithm> // for max_element 

int main()
{
	std::vector <int> n = { 4, 0, 2, 4 };

	std::cout << "Highest elements found at the locations:\n";
	auto max = std::max_element(n.begin(), n.end());
	for (auto itr = max; itr != n.end; itr++) {
		if (*itr == *max) {
			std::cout << itr - n.begin() << ' ';
		}
	}
	std::cin.get();
}


It appears that max_element returns an iterator of type:
"std::_Vector_iterator<std::_Vector_val<std::conditional_t<true, std::_Simple_types<int>, std::_Vec_iter_types<int, size_t, ptrdiff_t, int *, const int *, int &, const int &>>>>"
What the heck?

Is there any way of knowing the type of something? Like for example the return value of max_element? I had to get the debugger to spit it out but isn't there another way? C++ References I know especially don't mention types of iterators.
closed account (E0p9LyTq)
Is there any way of knowing the type of something?

Use the typeid operator.

https://en.cppreference.com/w/cpp/language/typeid
Thanks FurryGuy ;)
another way to do this is just to return the value and the count of the value. You don't have to have a vector with {4,4,4,4,4,4,4,4....} in it, just say 4 with 20 copies etc.
if you need the actual positions, you can make a vector of them, I see no way around it. For that it depends on the usage. If you only need to go over the vector once after finding them all, don't store it, just get the max value and then do a one pass loop that does what it needs to do, without saving the positions at all. If you need to reuse the positions multiple times, then save them.
Last edited on
@Grime
There is an error in line 11, I don't know how to correct it.
I'm sorry I forgot parenthesis
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <vector>
#include <algorithm> // for max_element 

int main()
{
	std::vector <int> n = { 4, 0, 2, 4 };

	std::cout << "Highest elements found at the locations:\n";
	auto max = std::max_element(n.begin(), n.end());
	for (auto itr = max; itr != n.end(); itr++) {
		if (*itr == *max) {
			std::cout << itr - n.begin() << ' ';
		}
	}
	std::cin.get();
}


But if you don't know how to correct it then you should not be using this code.

Like H00G0 said write it manually, it's the same thing. What's important, in my opinion, is that you must understand the code you're using. And you must understand it COMPLETELY.

You'll understand this code later on, so don't bother about it.
keyword - Iterators

Or you could still use max_element and do something like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <vector>
#include <algorithm> // for max_element 

int main()
{
	std::vector <int> n = { 4, 0, 2, 4 };

	std::cout << "Highest elements found at the locations:\n";
	int max = *std::max_element(n.begin(), n.end());
	for (int i = 0; i < n.size(); i++) {
		if (n[i] == max) {
			std::cout << i << ' ';
		}
	}
	std::cin.get();
}


However I would suggest working up logic to find the highest element first, yourself. As an exercise.

HINT: make a temporary variable and assign it the value of the first element in the vector. Then iterate through every other element in the vector using a for-loop and if you find an element that is larger than your temporary variable then put the new value into the temporary variable.
Last edited on
This will do it, shamelessly modified from the example here: http://www.cplusplus.com/reference/algorithm/max_element/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>
#include <vector>
#include <array>

using std::cout;
using std::vector;
using std::array;

template <class ForwardIterator>
std::vector<ForwardIterator> maxElements(ForwardIterator first, ForwardIterator last)
{
    std::vector<ForwardIterator> result;
    if (first == last) return result;

    ForwardIterator largest = first;
    result.push_back(first);
    while (++first != last) {
	if (*largest < *first) {
	    result.clear();
	    largest = first;
	    result.push_back(first);
	} else if (*largest == *first) {
	    result.push_back(first);
	}
    }
    return result;
}

int
main()
{
    std::array<std::array<int,5>, 5> arrays {{
	{{2,2,3,4,5}},
	{{4,0,2,4,0}},
	{{2,2,2,3,3}},
	{{2,4,2,3,4}},
	{{3,3,2,2,3}}
      }};

    for (unsigned i=0; i<5; ++i) {
	std::vector<array<int,5>::iterator> maxVals = maxElements(arrays[i].begin(), arrays[i].end());
	cout << "Max values at ";
	for (auto & p : maxVals) {
	    cout << p-arrays[i].begin()<< ' ';
	}
	cout << '\n';
    }
    return 0;
}

@Grime
You're right, I'm a beginner and still don't manage pointers and iterators, so your second solution is for my level.
Thank you for your effort. And, yes, I could did it manually, just thought there is a function for that. Maybe I do expect to much of c++ :/
not only is there no function, but you can get really inefficient if careless.
this would do it: (pseudocode, real code needs to ensure found before changing a location of course)
value = max(..);
loop
x = array.find(value);
array[x] = differentvalue;
until not found anymore
but each find is going to re-iterate the array, which is wasteful, and max iterated once already as well. your own loop will be more efficient than trying to glue together the provided algorithms. Its a O(n) problem, and the above is ~N*N. if you used find from where you left off it would do it efficiently but you would have to track the index offsets manually.

remove would tell you how many you had, but not where, efficiently.
Last edited on
Grime wrote:
C++ References I know especially don't mention types of iterators.

Both on this site and on cppreference it is possible to read from the function signature that the returned iterator has the same type as the iterators that you passed as argument.

http://www.cplusplus.com/reference/algorithm/max_element/
https://en.cppreference.com/w/cpp/algorithm/max_element
Well, that's what I finally cooked:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

int main()
{
int r;
cout << "Number of rows: ";
cin >> r;

char table[r][100 + 1];

for(int i = 0; i <r; i++)	 //last column with null-char
    table[i][100+1]='\0';

string sText;

int d;

cin.ignore(1000, '\n');
for(int i = 0; i < r; i++)
{
    cout << "Input text: ";         //a real sentence e.i. Good morning people.
    getline(cin, sText);
    d = sText.length();

    for(int j = 0; j < d; j++)
    {
         table[i][j] = sText[j];
    }
}

char alpha;
cout << "Input any alphanumeric: "; cin >> alpha;

int f = 0;
int q = 0;
vector <int> fr;

for(int i = 0; i < r; i++)
{
    f = count(table[i], table[i]+strlen(table[i]), alpha);
    if (f > 0) {q = f;}
    fr.push_back(f);
}

//*************************************

if (q > 0)  //if any alpha
{
    cout << "Max occ. in row(s):\n";

    int how_many = *max_element(fr.begin(), fr.end()); 	

    for (size_t i = 0; i < fr.size(); i++)
    {
        if (fr.at(i) == how_many)
            cout << i << ' ';	
    }
}
else
    cout << "Nop. No such character.";

return 0;
}


Improvements are welcome :)

And my next quest is how to enumerate the number of spaces instead alphanumeric character. Why on Earth the space is still exotic character in 21. st?
Last edited on
Line 15: char table[r][100 + 1]; Variable length arrays aren't standard C++, although some compilers support them.

Why not makes this a vector of strings instead? That way you don't have to worry about how long the strings are, or how many you get. Notice that many of the bugs I mention below would disappear if you used strings.

Line 18: An array of size N is indexed with values 0 to N-1, so table[i][100+1] is out of bounds.

Lines 31-34. You forgot to null-terminate the string. Also, what if they give you a string with more than 100 character? It will go out of bounds. You could replace this loop with strcpy(table[i]. sText.c_str()) to fix the null-termination problem, but you'll still have the out-of-bounds problem. All of these problems go away if table is a vector of strings.

Line 47. You could just say q += f; which is shorthand for q = q+f;
@dhayden
Thank you for your suggestions.

Why not makes this a vector of strings instead?

Because my homework. But, I'll try to, just for myself.

Line 18: An array of size N is indexed with values 0 to N-1, so table[i][100+1] is out of bounds.

I think it's not. Table was declared as [r][100+1]. Only first dimension changes its value.

You forgot to null-terminate the string.

I read somewhere that strings are null-terminating by default. Is that right?

what if they give you a string with more than 100 character

It will be just cut out. For this specific purpose, a 100 is more then enough. But, I'll do it with vectors of strings.

Line 47. You could just say q += f; which is shorthand for q = q+f;

The only purpose of variable q is to indicate if given alphanumeric was found. Maybe, there is another way.




New version:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <algorithm>

using namespace std;

int main()
{
int r;
cout << "Number of rows: ";
cin >> r;

vector <string> vs;

string sText;

cin.ignore(1000, '\n');
for(int i = 0; i < r; i++)
{
    cout << "Input text: ";         //a real sentence e.i. Good morning people.
    getline(cin, sText);
    vs.push_back(sText);
}

char alpha;
cout << "Input any alphanumeric: "; cin >> alpha;

int f = 0;
int q = 0;
vector <int> fr;

for(int i = 0; i < r; i++)
{
    f = count(vs.at(i).begin(), vs.at(i).end(), alpha);
    if (f > 0) {q = f;}
    fr.push_back(f);
}

//*************************************

if (q > 0)  //if any alpha
{
    cout << "Max occ. in row(s):\n";

    int how_many = *max_element(fr.begin(), fr.end()); 	

    for (size_t i = 0; i < fr.size(); i++)
    {
        if (fr.at(i) == how_many) 
            cout << i << ' ';
    }
}
else
    cout << "Nop. No such character.";

return 0;
}
Last edited on
Looks good!
Looks good!

Thanks to you also :-)

I'd like to know how to instead an alphanumeric character input one whitespace. Tried key Space, then Alt+32, no result. Read that for special character it must be used backslash, but there is no solution for space.
Can you reword your question? I can probably answer it, but I don't know what you mean.

If you need to use spaces in your input, then you need to use getline() instead of cin.
In this code above an user needs to input /from keyboard/ one alphanumeric character.
I'd like to know how to input a special character, precisously whitespace.
Last edited on
Pages: 12