Algorithm 如何使用最多两次交换对三个变量进行排序?

Algorithm 如何使用最多两次交换对三个变量进行排序?,algorithm,Algorithm,以下算法可以使用运算符(b,c,a)->(b,a,c)->(a,b,c)->(a,b,b,c)对K类型的三个变量x、y和z进行排序。然而,一次交换就足够了:(c,b,a)->(a,b,c) 在所有情况下,用最多两次交换对三个变量进行排序的最简单算法是什么?找到最小的,这需要两次比较,然后将其交换到第一个位置。 然后比较其余2个,必要时交换 if (x < y) { if (z < x) swap(x,z); } else { if (y < z) swap(x,y);

以下算法可以使用
运算符(b,c,a)->(b,a,c)->(a,b,c)->(a,b,b,c)对
K
类型的三个变量
x
y
z
进行排序。然而,一次交换就足够了:(c,b,a)->(a,b,c)


在所有情况下,用最多两次交换对三个变量进行排序的最简单算法是什么?

找到最小的,这需要两次比较,然后将其交换到第一个位置。 然后比较其余2个,必要时交换

if (x < y) {
   if (z < x) swap(x,z);
} else {
  if (y < z) swap(x,y);
  else swap(x,z);
} 
if(z<y) swap(y,z);
if(x如果(z找到最小值并与第一个值交换。找到第二个最小值并与第二个值交换。最多交换两次


这基本上是,它最多只能执行n-1交换。

在表中对a进行编码。我链接的Wikipedia文章应该可以帮助您提供参考,以防您需要在其他情况下(即更大的数组)在表中放置什么.

我认为您想要的是在每个步骤中找到最佳交换,而不仅仅是一个有效的交换。要做到这一点,只需在列表的后面找到元素和元素之间的最大差异并交换它们。在3元组中,有三种可能的交换,1-3、1-2和2-3。在每个步骤中,找到这三种交换和d之间的最大差异o这一点。非常确定,在最坏的情况下,3个元素会进行两次交换。只有在交换与比较元素相比成本相对较高的情况下才有意义,否则可能不值得预先进行额外的分析。

如果您没有进行适当的交换,您可以在不进行任何交换的情况下执行。

很酷的问题:)

如果程序集对您可用,并且值适合于寄存器,那么您可能可以通过将它们加载到寄存器中并进行一些比较,跳到正确的场景以将值放回,从而非常快地完成此操作。也许您的编译器已经进行了这种优化


无论哪种方式,如果性能是您的目标,请查看生成的机器代码并在那里进行优化。对于这样一个小的算法,您可以从中挤出性能。

我最近不得不解决一个类似的问题-有效地排序三个值。在你的问题中,你要专注于互换操作。如果您需要的是性能,请将注意力集中在比较操作和分支上!当用三个值排序这样一个“微小”数组时,一个好的想法是考虑使用额外的存储,这适合于这么少的值。我提出了一种专门的“合并排序”(见下面的代码)

正如tenfour所建议的那样,我查看了程序集,下面的代码编译成一组紧凑的内联CPU寄存器操作,速度非常快。附加变量“arr12”也存储在CPU寄存器中。排序需要两个或三个比较操作。该函数可以很容易地转换为模板(为了清楚起见,这里不提供)

2次互换,3次比较

2到3次比较,0到1.7次互换 老问题,新答案。。。以下算法对
x
y
z
进行排序,根据它们的值和0到1.7次交换操作进行2到3次比较

void sort3(K& x, K& y, K& z)
{    
    if (y < x) {
        if (z < x) {
            if (z < y) {
                swap(x, z);
            } else {
                K tmp = std::move(x);
                x = std::move(y);
                y = std::move(z);
                z = std::move(tmp);
            }
        } else {
            swap(x, y);
        }
    } else {
        if (z < y) {
            if (z < x) {
                K tmp = std::move(z);
                z = std::move(y);
                y = std::move(x);
                x = std::move(tmp);
            } else {
                swap(y, z);
            }
        }
    }
}
void sort3(K&x、K&y、K&z)
{    
if(y
那么,它是如何工作的呢?它基本上是一种展开插入排序:如果值已经排序(需要两次比较才能检查),那么算法不会交换任何内容。否则,它将执行1或2次交换操作。然而,当需要2次交换操作时,算法“旋转”值,以便执行4次移动而不是6次(交换操作应花费3次移动,)

只有3个值的6种可能排列。该算法进行所需的比较,以了解我们正在处理的置换。然后它进行交换并离开。因此,该算法有6条可能的路径(包括由于数组已排序而不执行任何操作的路径)。虽然它仍然是人类可读的,但对4个值进行排序的等效优化算法将有24条不同的路径,并且更难读取(对于n个值,有n!种可能的排列)


因为我们已经2015了,你好像在使用C++,我冒昧地使用了swap rotate thingy,以确保swap rotate thingy足够有效,甚至可以用于可移动但不可复制的类型。

这可以用一个与所有可能的比较组合相关的真值表来说明,以了解我们如何最好地优化您在这里提到的swap

值| x x、 y,z | y | y | y

x、 z,y | y | n | y

y、 x,z | n | y | y

y、 z,x | n | y | n

z、 x,y | y | n | n

z、 y,x | n | n | n

通过以这种方式构建问题,我们可以很容易地看到,通过最初检查并交换第一个和第三个元素,交换后第一个元素中的最低值可以是x或y。这简化了之后的if检查,因此我们可以在x>y时交换第一个和第二个元素,或者在y>z时交换第二个和第三个元素

if (x > z) {
    swap(x,z);
}

if (x > y) {
    swap(x,y);
} else if (y > z) {
    swap(y,z);
}
不需要任何嵌套的if条件。最多2次掉期只需2-3次简单比较。

不,你需要
void sort(int& a, int& b, int& c)
{
   swap(a, min(a, min(b, c)));
   swap(b, min(b, c));
}
void sort3(K& x, K& y, K& z)
{    
    if (y < x) {
        if (z < x) {
            if (z < y) {
                swap(x, z);
            } else {
                K tmp = std::move(x);
                x = std::move(y);
                y = std::move(z);
                z = std::move(tmp);
            }
        } else {
            swap(x, y);
        }
    } else {
        if (z < y) {
            if (z < x) {
                K tmp = std::move(z);
                z = std::move(y);
                y = std::move(x);
                x = std::move(tmp);
            } else {
                swap(y, z);
            }
        }
    }
}
if (x > z) {
    swap(x,z);
}

if (x > y) {
    swap(x,y);
} else if (y > z) {
    swap(y,z);
}