By repeating the same logic for five numbers or is there a much better way of doing that?
It depends on exactly what you mean by "repeating the same logic" and on how you measure "better".
It is possible to determine the median of five items with use of just six comparisons (but no fewer). In principle, this could be coded as a pure decision tree (no swaps or use of temporary variables). That would be a pretty close five-element analog of the code presented in the question. It would be very efficient, and it would not modify the input, but it would be hard to read or understand (not to mention long).
It would also be possible to introduce some temporary variables to that decision-tree approach that would make it shorter somewhat easier to follow, at the cost of a small amount of overhead and probably a little less computational efficiency.
Or it would be possible to sort the input and choose the middle element from the result. That could be fairly easy to understand, depending on implementation details, but it would be much less efficient.
Or it would be possible to implement a partial sort to save a little time vs a full sort, yet still be pretty clear (at the point of use, but not necessarily overall). An early-terminating selection sort could do this, or a quickselect implementation. These are still comparatively less efficient than the decision-tree style approaches, and rather more code.
If efficiency were a key consideration then I would at least test this variation on the "decision tree with temporaries" approach:
int median_of_five(int a, int b, int c, int d, int e) {
struct pair { int x, y; };
struct pair temp1;
struct pair temp2;
struct pair pair1;
struct pair pair2;
// arrange a, b, c, and d into two pairs, each having its elements in order
if (a <= b) {
temp1 = (struct pair) { a, b };
} else {
temp1 = (struct pair) { b, a };
}
if (c <= d) {
temp2 = (struct pair) { c, d };
} else {
temp2 = (struct pair) { d, c };
}
// order the two pairs by their first elements
if (temp1.x <= temp2.x) {
pair1 = temp1;
pair2 = temp2;
} else {
pair1 = temp2;
pair2 = temp1;
}
/*
* These mathematical relationships now hold:
*
* pair1.x <= pair1.y
* pair1.x <= pair2.x <= pair2.y
*
* The order of e relative to the others determines how we proceed.
*/
if (pair1.y <= e) {
// pair1.x <= pair1.y <= e; pair1.x <= pair2.x <= pair2.y
if (pair2.x < pair1.y) {
// pair1.x <= pair2.x < pair1.y <= e; pair2.x <= pair2.y
// return the lesser of pair1.y and pair2.y
return (pair1.y <= pair2.y) ? pair1.y : pair2.y;
} else {
// pair1.x <= pair1.y < e, pair2.x; pair2.x <= pair2.y
// return the lesser of e and pair2.x
return (e <= pair2.x) ? e : pair2.x;
}
} else {
// pair1.x, e <= pair1.y; pair1.x <= pair2.x <= pair2.y
if (pair2.x <= e) {
// pair1.x <= pair2.x <= e <= pair1.y; pair2.x <= pair2.y
// return the lesser of e and pair2.y
return (e <= pair2.y) ? e : pair2.y;
} else {
// pair1.x, e <= pair1.y, pair2.x; pair2.x <= pair2.y
// return the lesser of pair1.y and pair2.x
return (pair1.y <= pair2.x) ? pair1.y : pair2.x;
}
}
}
That can of course be adapted for input in the form of an array instead of five individual values.
The six-level "full decision tree" version is not something I really want to contemplate writing.