C++ question regarding multidimensional array - c++

My C++ skills are rusty but trying to help my son with his assignment so pardon me if its very simple.
I am trying to find all of the neighbors of an element in array and seeing if that particular element is larger than all of its neighbors.
#include <iostream>
using namespace std;
int row2(int arr[][3], int n){
cout << "row2";
if (arr[1][n] > arr[0][n] && arr[1][n] > arr[0][1] && arr[1][n] > arr[1][1] && arr[1][n] > arr[2][1] && arr[1][n] > arr[2][n]){
return true;
}
else
return false;
}
int row3(int arr[][3], int n){
cout << "row3==n";
cout << n;
if (n == 0 || n == 2){
if (arr[3][n] > arr[1][n] && arr[3][n] > arr[3][1] && arr[3][n] > arr[1][1]){
cout << "row3 if";
return true;
}
else
cout << "row3 else";
return false;
}
else{
if (arr[3][1] > arr[3][2] && arr[3][1] > arr[3][0] && arr[3][1] > arr[1][2] && arr[3][1] > arr[1][0] && arr[3][1] > arr[1][1]){
return true;
}
else
return false;
}
}
When compiling I get an error in this line val = arr[counterx] [counter]; expected body of lambda expression
val4 = arr[val2], [val3];
Any pointers?
Thanks in advance!

The shown code has several bugs, and errors. Both syntax errors and logical errors.
void findit(int arr[], int sizey, int sizex)
This declares the first parameter to be a plain, garden variety array. Just a one dimensional array. Typical values in this array, that you might found would be arr[0], or arr[1], or maybe arr[x] if x was some integer variable. But then, in the this function:
val = arr[counterx] [counter];
this tries to access arr as if it was a two-dimensional array, instead: arr[something][somethingelse]. That would be a two-dimensional array, while the arr is declared as a one-dimensional array.
In your main you declare a
int arr[3][3]
which is a two-dimensional array, but then pass it to findit:
findit(arr, m,n);
However, as we've just discovered, the first parameter to findit is not a two-dimensional array, but a one dimensional array. It's clear that findit's arr should be declared as a two-dimensional array.
However there is no way, in C++, to pass a two-dimensional array to a C++ function, with unspecified first and second dimension. C++ does not work this way. In an array parameter specification, in C++, only the first array dimnension can be left unspecified. The 2nd, and all following dimensions must be specified. You could, for example, declare:
void findit(int arr[][3], int sizey, int sizex)
That would allow you to pass any two-dimensional array of ints, as long as the 2nd dimension is 3. But then passing both size parameters is meaningless. It is only necessary to explicitly pass in the size of the first dimension, since the size of the second dimension is already known.
Finally:
val4 = arr[val2], [val3];
It is unclear what this is, but this is not a valid C++ syntax. If you meant to access an element in this two-dimensional array, using the given indices, the appropriate syntax would be:
val4 = arr[val2][val3];
This addresses the fundamental compilation errors in the shown code. Unfortunately there are many, many obvious logical problems in the shown code. For example, one of the logical problems:
val = arr[counterx] [counter];
If you inspect the preceding for loops, you will discover that:
for (int counterx = -1; counter <= sizex; counter++){
So, the counterx variable will start iterating from -1, so the above will appear to try to evaluate:
val = arr[-1][counter];
In C++, no array has a value at a negative index offset, so the above logic will result in undefined behavior, and nonsensical results. If you have any kind of an array, like x[], you might find something at x[0], and at x[1], but not at x[-1]. The same applies to multi-dimensional arrays too.
This is the first logical error that was obvious to the naked eye, and there are probably a few more, here. Overall, the approach in the shown code is somewhat unclear. You might benefit from taking a step back, and redesigning the overall approach for this task, since the shown logic does not appear to be going about it correctly, in several fundamental ways.

expected body of lambda expression val4 = arr[val2], [val3];
Seems like a syntax error on this line val4 = arr[val2], [val3]; and not the one you mentioned in the question.
I assume you meant to write val4 = arr[val2][val3]; without the comma.
That being said, the values of val2 and val3 are being assigned the same value and may cause an index out of bounds exception if unchecked. Moreover, starting counter and counterx at -1 will cause out of bounds exceptions.
Moreover, you cannot pass a multidimensional array to a function without passing it as a double pointer or hardcoding the size.
EDIT 1:
I put together a solution for finding the max number in each row. It's not the most optimized code but it's quick and works. I assumed the row,col sizes could change, so I'm using std::vector instead of std:array or primitive array. However, you could revert back if you know you can hardcode int[3][3] into your solution.
#include <iostream>
#include <iterator>
#include <iostream>
#include <algorithm>
#include <array>
void findit(std::vector<std::vector<int>> arr){
for (size_t rowsIndex = 0; rowsIndex <= arr.size(); rowsIndex++){
std::vector<int> row = arr[rowsIndex];
int maxNum = *std::max_element(row.begin(), row.end());
std::cout<< "largest num in row " << rowsIndex << ": " << maxNum << std::endl;
}
}
int main(){
std::vector<std::vector<int>> arr;
arr.push_back({0, 1, 2 });
arr.push_back({4, 5, 6 });
arr.push_back({8, 9, 10});
findit(arr);
}
EDIT 2:
If you want to check a target index against adjacent indecies, there's no need to use a forloop. There are only 4 (or 8) possible indecies to check against, just easier (and efficient) to hardcode them:
#include <iostream>
#include <iterator>
#include <iostream>
#include <algorithm>
#include <array>
void checkIfIndexIsLargestInItsAdjacency(std::vector<std::vector<int>> arr, size_t targetRow, size_t targetColumn){
int targetNumber = arr[targetRow][targetColumn];
int numberToTheLeft = targetColumn > 0 ? arr[targetRow][targetColumn-1] : 0;
int numberToTheRight = targetColumn + 1 < arr[targetRow].size() ? arr[targetRow][targetColumn+1] : 0;
int numberToTheUp = targetRow > 0 ? arr[targetRow-1][targetColumn] : 0;
int numberToTheDown = targetRow + 1 < arr.size() ? arr[targetRow+1][targetColumn] : 0;
std::cout<< "targetNumber: " << targetNumber << std::endl;
std::cout<< "Number to the left: " << numberToTheLeft << std::endl;
std::cout<< "Number to the right: " << numberToTheRight << std::endl;
std::cout<< "Number to the up: " << numberToTheUp << std::endl;
std::cout<< "Number to the down: " << numberToTheDown << std::endl;
std::array<int, 4> adjacentNumbers = {numberToTheLeft, numberToTheRight, numberToTheUp, numberToTheDown};
int maxAdjacentNum = *std::max_element(adjacentNumbers.begin(), adjacentNumbers.end());
std::cout << "Target number is " << (maxAdjacentNum >= targetNumber? "smaller" : "bigger") << " than adjacent numbers" << std::endl;
}
int main(){
std::vector<std::vector<int>> arr;
arr.push_back({0, 1, 2 });
arr.push_back({4, 5, 6 });
arr.push_back({8, 9, 10});
checkIfIndexIsLargestInItsAdjacency(arr, 1, 1);
checkIfIndexIsLargestInItsAdjacency(arr, 2, 2);
}
Example output:
targetNumber: 5
Number to the left: 4
Number to the right: 6
Number to the up: 1
Number to the down: 9
Target number is smaller than adjacent numbers
targetNumber: 10
Number to the left: 9
Number to the right: 0
Number to the up: 6
Number to the down: 0
Target number is bigger than adjacent numbers

Related

Adding two adjacent elements in a vector giving a segmentation fault for odd numbers (c++)

I'm interested to understand why my C++ program is producing a segmentation fault. The task is to insert elements into a vector and to add the adjacent elements stored in such vector. The problem arises when there is an odd number of elements in the vector. I eventually got my program to work by changing idx != numbers.size() to idx < numbers.size() or idx <= numbers.size()-1. This allows the conditional statement for odd numbers to be passed and prints the last element instead of attempting an addition. Why does != not work in this instance and lead to the seg fault?
#include <iostream>
#include <vector>
using std::cout;
using std::cin;
using std::endl;
using std::vector;
int main(){
vector<int> numbers = {1, 2, 3, 4, 5};
int tmp;
/*while(cin >> tmp){
numbers.push_back(tmp);
}*/
for(decltype(numbers.size()) idx = 0; idx < numbers.size(); idx+=2){
if((numbers.size() % 2 != 0) && (idx == numbers.size() - 1)){
cout << numbers[idx] << endl;
}
else{
cout << numbers[idx] + numbers[idx+1] << " ";
}
}
cout << endl;
return 0;
}
The reason "!=" does not work with an odd size vector is that idx starts at 0 and advances by two each time.
So consider your example where the vector has size 5.
idx will have values 0, 2, 4, 6, 8 and so on, but idx will never have the value 5 because idx will always be even. This will cause bad things, such as a segmentation fault, when idx is sufficiently large that numbers[idx] does not reference readable memory.
Use of < or <=, fixes the case of odd length, because in the case of an odd length l the loop will stop when idx reaches l+1.

Count the number of repeating elements in an array

The question is to count the number of repeating elements in the given array:
Suppose the input is:
1
1 2 3 3 3
2
1 2 2 3 3 3 4 5
Then the output should be 3 for the first input and 5 for the second one.
I have written the code, according to logic its output should be 3 but I'm getting the output as 5 could anyone spot the error.
#include <bits/stdc++.h>
using namespace std;
int main() {
int a[5] = {
1,
4,
2,
4,
4
};
int b[101];
memset(b, 0, 101);
int cp = 0, i = 0;
b[a[i]] = 1;
for (int j = i + 1; j < 5; j++) {
if (b[a[j] > 0]) {
if (b[a[j]] == 1)
cp++;
cp++;
b[a[j]]++;
} else
b[a[j]] = 1;
}
cout << cp;
return 0;
}
There is a typo in your code - you wrote if(b[a[j]>0]) instead of if (b[a[j]] > 0), which produces completely different behavior.
To avoid such mistakes, you should format your code properly and give meaningful names to variables. For example, your main function could be rewritten as:
int main() {
const size_t SIZE = 5;
int a[SIZE] = {1, 4, 2, 4, 4};
const int MAX_VALUE = 100;
int count[1 + MAX_VALUE] = {};
int duplicates = 0;
for (int j = 0; j < SIZE; j++) {
if (count[a[j]] > 0)
duplicates++;
if (count[a[j]] == 1)
duplicates++;
count[a[j]]++;
}
cout << duplicates;
}
Note how I also removed a special case for the first array element - it is unnecessary and often prone to errors.
If I read something like
#include <bits/stdc++.h>
using namespace std;
and the variable names, then I assume that this question is related to some competetive programming site. So, my guess is that there are more constraints that we do not know. We see for example the magic number 101 here. Maybe there is a constraint that we have only integers in the range 0..100. Anyway, we do not know.
I would like to show a C++ solution. Basically this is using the standard approach for counting items, by using a std::map or std::unordered_map.
Please see the following code which basically consists of 2 lines. I will explain it afterwards:
#include <iostream>
#include <vector>
#include <unordered_map>
#include <numeric>
std::vector testData{ 1,4,2,4,4 };
int main() {
std::unordered_map<int, size_t> counter{};
// Count the occurence of each integer value
for (const int i : testData) counter[i]++;
// Accumulate repeating values and show result
std::cout << std::accumulate(counter.begin(), counter.end(), 0U, [](size_t c, const auto& p) { return c+(p.second > 1 ? p.second : 0U); });
return 0;
}
As said, we use the standard approach with maps. The important point here is to understand the index operator of a map. Please see here. And read:
Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist.
The important point is: It will either return a reference to a value, if it is already in the map. If not, it will create the value in the map and again return a reference to the value. And because we get a reference to the value in any way, we can simply increment it.
After we have done this for all source values from our "testData"-vector in a very simple for loop, we have the count of all values. If the count for one value is greater then 1, then it is a duplicate or "repeated".
Therefore, we just need to accumulate all counters that are greater than 1. And for this we use the dedicated function std::accumulate.
If you should have any questions, then please ask.

finding even numbers in the array issue (C++)

My code is to extract odd number and even number in an 1D array.
#include <iostream>
using namespace std;
int main() {
int a[6] = {1,6,3,8,5,10};
int odd[]={};
int even[]={};
for (int i=0; i < 6; i++) {
cin >> a[i];
}
for (int i=0; i < 6; i++) {
if (a[i] % 2 == 1) {
odd[i] = a[i];
cout << odd[i] << endl;
}
}
cout << " " << endl;
for (int i=0; i < 6; i++) {
if (a[i] % 2 == 0) {
even[i] = a[i];
cout << even[i] << endl;
}
}
return 0;
}
the output is:
1
3
5
2
1
6
It shows that it successfully extract odd numbers but the same method applied to the even number. It comes with an issue while the even number is 4.
Could anyone help me find the cause here? Thanks.
You've got an Undefined Behavior, so result may be any, even random, even formatted hard drive.
int odd[] = {} is the same as int odd[/*count of elements inside {}*/] = {/*nothing*/}, so it's int odd[0];
Result is not defined when you're accessing elements besides the end of array.
You probably have to think about correct odd/even arrays size, or use another auto-sizeable data structure.
First, although not causing a problem, you initialize an array with data and then overwrite it. The code
int a[6] = {1,6,3,8,5,10};
can be replaced with
int a[6];
Also, as stated in the comments,
int odd[]={};
isn't valid. You should either allocate a buffer as big as the main buffer (6 ints) or use a vector (although I personally prefer c-style arrays for small sizes, because they avoid heap allocations and extra complexity). With the full-size buffer technique, you need a value like -1 (assuming you intend to only input positive numbers) to store after the list of values in the arrays to tell your output code to stop reading, or store the sizes somewhere. This is to prevent reading values that haven't been set.
I don't understand your problem when 4 is in the input. Your code looks fine except for your arrays.
You can use std::vector< int > odd; and then call only odd.push_back(elem) whem elem is odd.

C++ How do I print elements of an array but leave out repeats? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
My assignment is to have the user type in how many elements are in an array then enter integer number to be put in the array. I then have to sort through the array and find the largest number and print out the elements of the array but if there is a repeat then only print that number one time. I also have to print out the number of times each element in the array occurs. For example if the user types in that there is 5 elements then enters 2, 1, 2, -3, 2 then it should print -3 with 1 count, 1 with 1 count, and 2 with 3 count. So far I have it so it will print out the elements and delete the repeats but I cant get it to print out the correct number of occurrences for each element. This is my code so far.
void findRepeats(int numbers[], int num)
{
int instances = 0;
cout << "Number" << " " << "Occurrences" << endl;
for (int i = 0; i < num; i++)
{
bool matching = false;
instances = 1;
for (int j = 0; (j < i); j++)
{
if (numbers[i] == numbers[j])
{
instances++;
matching = true;
}
}
if (!matching)
cout << numbers[i] << " " << instances << endl;
}
}
Right now its saying all number occur only 1 time
One approach that you could take, is to sort the numbers first, before deciding how many duplicates there are. That way, it will be easier to avoid printing results for the same number more than once, and you also won't have to loop through the entire array for each number.
void findRepeats(int numbers[], int num);
int main(){
int array[] = {2, 1, 2, -3, 2};
findRepeats(array,5);
}
void findRepeats(int numbers[], int num) {
//sort the array first
std::sort(numbers, numbers + num);
int last = numbers[0];
int count = 0;
cout << "Number of Occurrences\n";
for (int i = 0; i < num; i++) {
if (last == numbers[i]) {
++count;
} else {
cout << last << " " << count << '\n';
count = 1;
}
last = numbers[i];
}
if (count > 0) {
cout << last << " " << count << '\n';
}
}
prints:
Number of Occurrences
-3 1
1 1
2 3
I would use map or unordered_map to, well..., map the integer to the number of it's occurrences. It makes things quite simple, as it basically takes care of the duplicates for you.
#include <iostream>
#include <unordered_map>
using namespace std;
void reportCounts(const int numbers[], const size_t size){
unordered_map<int, unsigned int> counts;
//unfortunately range-for here would a little PIA to apply
//or at least I don't know convenient way
for(size_t i = 0; i < size; ++i) {
counts [ numbers[i] ]++; //increase `count` of i-th number
}
//print results
for(auto count : counts ){
cout << count.first << ' ' << count.second << endl;
}
}
int main(){
int array[] = {2, 1, 2, -3, 2};
reportCounts(array,5);
}
Since it's an assignment I am leaving figuring out the c++ shenaningans to you and http://cppreference.com. Keywords are map, map::iterator and maybe associative container which map in an example of.
I do understand that it might be harder to understand than plain implementation of some algorithm, but this is probably close to optimal solution in modern c++, and putting effort into understanding how and why it works should prove beneficial. One should notice how much less of code had to be written, and no algorithm had to be invented. Less implementation time, less place to make mistakes, less testing.
Search your array. For every integer, either record it, or increment your count of it. Repeat process till done, then print it.
How? you say? One approach would be to use parallel arrays to store the unique integers found, and another to store the count of integers. Then print the unique integers and their counts.
Code example of simple search algorithm:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
void print(vector<int> valueArray,vector<int> countArray){
for(unsigned int i = 0; i < valueArray.size(); ++i){
cout<<"Found value "<<valueArray[i]<<": "<<countArray[i]<<" times."<<endl;
}
}
void findRepeats(vector<int> testArray,vector<int> &valueArray,vector<int> &countArray){
for(unsigned int i = 0; i < testArray.size(); ++i){
if(valueArray.size() == 0){
valueArray.push_back(testArray[i]);
countArray.push_back(1);
}else{
bool newEntry = true;
for(unsigned int j = 0; j < valueArray.size(); ++j){
if(testArray[i] == valueArray [j]){
countArray[j]++;
newEntry = false;
break;//After find, break out of j-for-loop to save time.
}
}
if(newEntry){
valueArray.push_back(testArray[i]);
countArray.push_back(1);
}
}
}
}
int main(){
vector<int> testArray; //To store all integers entered.
vector<int> valueArray; //To store non-copied integers, dynamically, else handle it yourself.
vector<int> countArray; //To count increments of numbers found, dynamically, else handle it yourself.
testArray = {0,2,5,4,1,3,6,2,5,9,8,7,4,1,2,6,5,4,8,3,2,1,5,8,6,9,8,7,4,4,5,6,8,2,1,3,0,0,1,2,0,2,5,8};//Dummy data.
findRepeats(testArray,valueArray,countArray);//Function to find statistics on testArray.
cout<<"\nPrinting found characters, and number of times found: "<<endl;
print(valueArray,countArray);
return 0;
}
Output would be something like:
Printing found characters, and number of times found:
Found value 0: 4 times.
Found value 2: 7 times.
Found value 5: 6 times.
Found value 4: 5 times.
Found value 1: 5 times.
Found value 3: 3 times.
Found value 6: 4 times.
Found value 9: 2 times.
Found value 8: 6 times.
Found value 7: 2 times.
In the above, I used vectors for simplicity, but if you must do so with c-style arrays, one approach would be to create all three vectors the same size, and keep one integer counter for number of indices used in the valueArray and countArray; they should share, since they're related 1 to 1. And you will need to pass it to the findRepeats function as well.
Having arrays of the same size will ensure that your values and counts will fit in your array; this would happen if every number entered was unique.

Find Two Largest Numbers, C++

I'm using this approach: First find the largest among 5 numbers then save the subscript of array of the largest number in an "ivariable" after displaying the largest number, do like this
array[ivariable] = 0 ;
so that first largest set to zero and its no longer here in the array.
And do the same again, find the largest, but I'm not getting what I'm trying to.
Its a logical error.
Thanks
#include <iostream>
using namespace std;
int main(void)
{
int counter, large,number,det_2, i , large3, det_3= 0;
int det[5] = {0,0,0,0,0};
for(int k(0); k < 5 ; k++)
{
cout << "Enter the number " << endl ;
cin >> det[k] ;
}
for( i; i<5; i++)
{
large = det[i] ;
if (large > det_2)
{
det_2= large ;
counter = i ;
}
else
{
}
}
cout << "Largest among all is " << det_2 << endl;
det[i] = 0 ;
for( int j(0); j<5; j++)
{
large3 = det[j] ;
if(large3 > det_3)
{
det_3= large3 ;
}
else
{
}
}
cout << "Second largest " << large3 << endl ;
system("PAUSE");
}
You've got possible syntax and initialization errors. Fix those first:
for(int k(0); k < 5 ; k++): I've never seen an integer initialized this way. Shouldn't it be:
for (int k = 0; k < 5; k++) ? (Same with the last loop.)
Also,
for( i; i<5; i++)
The variable i is uninitialized. Variables are not initialized to any default value in C++. Because you've left it uninitialized, it might execute 5 times, no times, or 25,899 times. You don't know.
This should be:
for (i = 0; i < 5; i++)
But the whole thing could probably be a bit clearer anyway:
#include <iostream>
using namespace std;
int main(void)
{
int largest = -1;
int second_largest = -1;
int index_of_largest = -1;
int index_of_second_largest = -1;
int det[5] = {0, 0, 0, 0, 0};
for (int i = 0; i < 5; i++)
{
cout << "Enter the number " << endl;
cin >> det[i]; // assuming non-negative integers!
}
for (int j = 0; j < 5; j++) // find the largest
{
if (det[j] >= largest)
{
largest = det[j];
index_of_largest = j;
}
}
for (int k = 0; k < 5; k++) // find the second largest
{
if (k != index_of_largest) // skip over the largest one
{
if (det[k] >= second_largest)
{
second_largest = det[k];
index_of_second_largest = k;
}
}
}
cout << "Largest is " << largest << " at index " << index_of_largest << endl;
cout << "Second largest is " << second_largest <<
" at index " << index_of_second_largest << endl;
return 0;
}
Always give your variables values before you use them
det_2 = det[0];
counter = 0;
for (i = 1; i < 5; i++)
first problem I saw was that you are iterating using i as an index, but you don't initialize i.
code should be:
for(i = 0; i<5; i++)
^^^^
same goes for det_2. You compare elements against it, but do not initialize it. You should set it to det[0] before the loop where you use it.
third problem: Your "set largest value to zero after printing" sounds like it is there so that you can apply the same algorithm the second time.
You should create an additional function that gives you the index of the largest element, and call it like this:
int index = find_largest_index(a);
cout << "largest element: " << a[index] << endl;
a[index] = 0;
cout << "second largest element: " << a[ find_largest_index(a) ] << endl;
GCC 4.7.3: g++ -Wall -Wextra -std=c++0x largest.cpp
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
int main() {
std::cout << "Enter 5 numbers: ";
// Read 5 numbers.
std::vector<int> v;
for (auto i = 0; i < 5; ++i) {
int x = 0;
while (!(std::cin >> x)) {
// Error. Reset and try again.
std::cin.clear();
std::cin.ignore();
}
v.push_back(x);
}
// partition on element 3 (4th number)
std::nth_element(std::begin(v), std::next(std::begin(v), 3), std::end(v));
std::cout << "Two largest are: ";
std::copy(std::next(std::begin(v), 3), std::end(v), std::ostream_iterator<int>(std::cout, " "));
}
In the specific case of 5 elements, the algorithm you use is unlikely to make any real difference.
That said, the standard algorithm specifically designed for this kind of job is std::nth_element.
It allows you to find the (or "an", if there are duplicates) element that would end up on position N if you were to sort the entire collection.
That much is pretty obvious from the name. What's not so obvious (but is still required) is that nth_element also arranges the elements into two (or three, depending on how you look at it) groups: the elements that would short before that element, the element itself, and the elements that would sort after that element. Although the elements are not sorted inside of each of those groups, they are arranged into those groups -- i.e., all the elements that would sort before it are placed before it, then the element itself, then the elements that would sort after it.
That gives you exactly what you want -- the 4th and 5th elements of the 5 you supply.
As I said originally, in the case of just 5 elements, it won't matter much -- but if you wanted (say) the top 50000 out of ten million, choosing the right algorithm would make a much bigger difference.
nth_element isn't always suitable (or as efficient as it could be) as it needs to rearrange the input elements.
It's very common to want just the top two elements, and can be done efficiently in one pass by keeping the best and second-best values seen so far, and whenever a value you iterate over is better than the second-best, you'll either replace the second-best with it or the best, and in the latter case you also overwrite the best with the new value. That can look like this:
#include <utility>
template <typename It, typename EndIt, typename Less = std::less<>>
auto top_two(It it, EndIt end, Less less = Less{}) -> std::pair<It, It>
{
It first = it;
if (it == end || ++it == end)
return {first, end};
std::pair<It, It> results = less(*it, *first) ? std::pair{first, it} : std::pair{it, first};
while (++it != end)
if (less(*results.second, *it))
results.second = less(*results.first, *it)
? std::exchange(results.first, it) : it;
return results;
}
(See it running at http://coliru.stacked-crooked.com/a/a7fa0c9f1945b3fe)
I return iterators so the caller can know where in the input the top two elements are, should they care (e.g. to erase them from a container, or calculate their distance from begin(), or modify their values).
It you want the two lowest values, just pass std::greater<>{} as your "less" argument.
Some convenience functions to make it easier to call with containers or initializer_lists:
template <typename Container, typename Less = std::less<>>
auto top_two(const Container& c, Less less = Less{})
{
return top_two(begin(c), end(c), less);
}
template <typename T, typename Less = std::less<>>
auto top_two(const std::initializer_list<T>& il, Less less = Less{})
{
return top_two(begin(il), end(il), less);
}
If you want a general solution for the top-N elements, it's better to make N an argument and create a multiset of N top values (using a dereferencing comparison type), putting the initial N elements in, then whenever a new element is more than the **top_n.begin() value, do a top_n.insert(it); followed by top_n.erase(top_n.rbegin()); to drop the worst element: these operations are O(log N) so remain reasonably efficient even in pathological cases, such as input that is incrementing numbers.