Код для вычисления "медианы пяти" в C#
Примечание: пожалуйста, не интерпретируйте это как "вопрос домашней работы."Это просто вещь, которую мне любопытно знать:)
средний из пяти, иногда используется в качестве упражнения в разработке алгоритмов и вычислимых используя только 6 сравнения.
каков наилучший способ реализовать это "медиана пяти с использованием 6 сравнений" в C# ? Все мои попытки, похоже, приводят к неудобному коду : (мне нужен хороший и читаемый код, пока все еще используя только 6 сравнений.
public double medianOfFive(double a, double b, double c, double d, double e){
//
// return median
//
return c;
}
Примечание: Я думаю, что я должен найти алгоритм"":
я оказался не в состоянии четко объяснить алгоритм как Azereal сделал в своем посте на форуме. Поэтому я буду ссылаться на его пост здесь. От http://www.ocf.berkeley.edu/~wwu/cgi-bin/yabb/YaBB.cgi?board=riddles_cs;action=display;num=1061827085
Ну я поставил эту проблему в один моей задания и я обратился к этому форум для помощи, но никакой помощи не было. В конце концов я понял, как это делается.
запустите mergesort с первыми 4 элементами и упорядочьте каждую пару (2 сравнения)
Сравните два нижних из каждой пары и исключить самый низкий из возможности (3 сравнения)
добавить в 5-й номер, выделенный в число без пары и сравнить пара (4 сравнения)
сравните две самые низкие из двух новых пар и исключите нижнюю (5 сравнения)
сравните один сам по себе и нижний из последней пары и Нижний число-медиана
возможная медиана находится в пределах parentesis
(54321)
5:4 3:2 2 сравнение
(4
4:2 3 сравнения
2(4
1:3 4 сравнения
2(4
4:1 5 сравнения
1,2(4
4:3 6 сравнения
1,2(3)4,5
три медианы
EDIT: как ваш запрос и чтобы предотвратить получение большего количества downvotes, это код C++, который я написал, чтобы найти медиану из пяти. Не против это неловкость:
double StageGenerator::MedianOfFive(double n1, double n2, double n3, double n4, double n5){
double *a = &n1, *b = &n2, *c = &n3, *d = &n4, *e = &n5;
double *tmp;
// makes a < b and b < d
if(*b < *a){
tmp = a; a = b; b = tmp;
}
if(*d < *c){
tmp = c; c = d; d = tmp;
}
// eleminate the lowest
if(*c < *a){
tmp = b; b = d; d = tmp;
c = a;
}
// gets e in
a = e;
// makes a < b and b < d
if(*b < *a){
tmp = a; a = b; b = tmp;
}
// eliminate another lowest
// remaing: a,b,d
if(*a < *c){
tmp = b; b = d; d = tmp;
a = c;
}
if(*d < *a)
return *d;
else
return *a;
}
Он должен быть более компактным, не так ли ?
EDIT:
как указал @pablito в своем ответе. Встроенный список.Sort () не может выполнить это требование, так как он использует до 13 сравнений :]
10 ответов
это в основном просто факторинг кода подкачки и сортировки из вашего примера c++:
private static void Swap(ref double a, ref double b) {
double t = a;
a = b;
b = t;
}
private static void Sort(ref double a, ref double b) {
if (a > b) {
double t = a;
a = b;
b = t;
}
}
private static double MedianOfFive(double a, double b, double c, double d, double e){
// makes a < b and c < d
Sort(ref a, ref b);
Sort(ref c, ref d);
// eleminate the lowest
if (c < a) {
Swap(ref b, ref d);
c = a;
}
// gets e in
a = e;
// makes a < b
Sort(ref a, ref b);
// eliminate another lowest
// remaing: a,b,d
if (a < c) {
Swap(ref b, ref d);
a = c;
}
return Math.Min(d, a);
}
Я нашел этот пост интересным, и в качестве упражнения я создал это, которое делает только 6 сравнений и ничего больше:
static double MedianOfFive(double a, double b, double c, double d, double e)
{
return b < a ? d < c ? b < d ? a < e ? a < d ? e < d ? e : d
: c < a ? c : a
: e < d ? a < d ? a : d
: c < e ? c : e
: c < e ? b < c ? a < c ? a : c
: e < b ? e : b
: b < e ? a < e ? a : e
: c < b ? c : b
: b < c ? a < e ? a < c ? e < c ? e : c
: d < a ? d : a
: e < c ? a < c ? a : c
: d < e ? d : e
: d < e ? b < d ? a < d ? a : d
: e < b ? e : b
: b < e ? a < e ? a : e
: d < b ? d : b
: d < c ? a < d ? b < e ? b < d ? e < d ? e : d
: c < b ? c : b
: e < d ? b < d ? b : d
: c < e ? c : e
: c < e ? a < c ? b < c ? b : c
: e < a ? e : a
: a < e ? b < e ? b : e
: c < a ? c : a
: a < c ? b < e ? b < c ? e < c ? e : c
: d < b ? d : b
: e < c ? b < c ? b : c
: d < e ? d : e
: d < e ? a < d ? b < d ? b : d
: e < a ? e : a
: a < e ? b < e ? b : e
: d < a ? d : a;
}
спасибо. Я знаю, что ваши сообщения довольно старые, но это было полезно для моей проблемы.
Мне нужен был способ вычислить медиану 5 регистров SSE / AVX (4 поплавка / 8 поплавков сразу или 2 двойника / 4 двойника сразу):
без каких-либо условных переходов
только с инструкциями min/max
Если функции min / max запрограммированы для скалярных регистров с условными скачками, мой код не является оптимальным в термин сравнения. Но если функции min/max закодированы с соответствующими инструкциями CPU, мой код очень эффективен, потому что при выполнении CPU не выполняется условный переход.
template<class V>
inline V median(const V &a, const V &b, const V &c)
{
return max(min(a,b),min(c,max(a,b)));
}
template<class V>
inline V median(const V &a, const V &b, const V &c, const V &d, const V &e)
{
V f=max(min(a,b),min(c,d)); // discards lowest from first 4
V g=min(max(a,b),max(c,d)); // discards biggest from first 4
return median(e,f,g);
}
Это довольно уродливо и может использовать некоторый рефакторинг, но он явно проходит через все сравнения и свопы, чтобы вы могли видеть, что происходит.
public double medianOfFive(double a, double b, double c, double d, double e){
double median;
// sort a and b
if(a > b) // comparison # 1
{
double temp = a;
a = b;
b = temp;
}
// sort c and d
if(c > d) // comparison # 2
{
double temp = c;
c = d;
d = temp;
}
// replace the lower of a and c with e
// because the lowest of the first four cannot be the median
if(a < c) // comparison # 3
{
a = e;
// re-sort a and b
if(a > b) // comparison # 4
{
double temp = a;
a = b;
b = temp;
}
}
else
{
c = e;
// re-sort c and d
if(c > d) // comparison # 4
{
double temp = c;
c = d;
d = temp;
}
}
// eliminate a or c, because the lowest
// of the remaining four can't be the median either
if(a < c) // comparison #5
{
if(b < c) // comparison #6
{
median = c;
}
else
{
median = b;
}
}
else
{
if(d < a) // comparison #6
{
median = a;
}
else
{
median = d;
}
}
return median;
}
интересная тема здесь:
цитата из ниток:
цифры в массив.
используйте три сравнения и перетасуйте числа так, чтобы a[1]
Если a[3] > a[2], то проблема достаточно простой. Если a[2]
Итак, a[3] a[4], то решение является меньшим из A[3] и a[5]. В противном случае решение является меньшим из[2] и[4].
просто чтобы проверить, сколько сравнений:
class MyComparable : IComparable
{
public static int NumberOfComparisons = 0;
public int NumPart { get; set; }
#region IComparable Members
public int CompareTo(object obj)
{
NumberOfComparisons++; //I know, not thread safe but just for the sample
MyComparable mc = obj as MyComparable;
if (mc == null)
return -1;
else
return NumPart.CompareTo(mc.NumPart);
}
#endregion
}
class Program
{
static void Main(string[] args)
{
List<MyComparable> list = new List<MyComparable>();
list.Add(new MyComparable() { NumPart = 5 });
list.Add(new MyComparable() { NumPart = 4 });
list.Add(new MyComparable() { NumPart = 3 });
list.Add(new MyComparable() { NumPart = 2 });
list.Add(new MyComparable() { NumPart = 1 });
list.Sort();
Console.WriteLine(MyComparable.NumberOfComparisons);
}
}
результат 13.
для полноты, вопрос является частным случаем сеть сортировки, который кнут (Искусство программирования, vol 3) крышки в большой детали. The классической работе Э. К. Батчер на эту тему кратко и стоит прочитать.
это должно помочь
private Double medianofFive(double[] input)
{
Double temp;
if (input[0] > input[1])//#1 - sort First and Second
{
temp = input[0];
input[0] = input[1];
input[1] = temp;
}
if (input[2] > input[3])//#2 sort Third and Fourth
{
temp = input[2];
input[2] = input[3];
input[3] = temp;
}
// replace the smaller of first and third with 5th, then sort
int smallerIndex = input[0] < input[2] ? 0 : 2;//#3
input[smallerIndex] = input[4];
//sort the new pair
if(input[smallerIndex]>input[smallerIndex+1])//#4
{
temp = input[smallerIndex];
input[smallerIndex] = input[smallerIndex+1];
input[smallerIndex+1] = temp;
}
//compare the two smaller numbers
// then compare the smaller of the two's partner with larger of the two
// the smaller of THOSE two is the median
if (input[2] > input[0])
//#5
{
temp = input[2] > input[1] ? input[1] : input[2];//#6
}
else
{
temp = input[0] > input[3] ? input[3] : input[0];//#6
}
return temp;
}
-- In Haskell the solution could look like
import Data.Function
median5By pred [a,b,c,d,e] = fst $ merge2 c' d' where
merge2 = merge2By pred
merge2By pred x y = if x `pred` y then (x,y) else (y,x)
((_,b'), de ) = merge2By (pred `on` fst) (merge2 a b) (merge2 d e)
((_,c'),(d',_)) = merge2By (pred `on` fst) (merge2 b' c) de
main = print $ median5By (<) [2,5,4,1,3]
интересно, сколько сравнений в образце MSDN...
public static double Median(this IEnumerable<double> source) {
if (source.Count() == 0) throw new InvalidOperationException("Cannot compute median for an empty set.");
var sortedList = from number in source
orderby number
select number;
int itemIndex = (int)sortedList.Count() / 2;
if (sortedList.Count() % 2 == 0) {
// Even number of items.
return (sortedList.ElementAt(itemIndex) + sortedList.ElementAt(itemIndex - 1)) / 2; } else {
// Odd number of items.
return sortedList.ElementAt(itemIndex); }
}