
Robert W. Floyd
1 Floyd-Rivest 算法
Floyd-Rivest 算法是一种选择算法,用于在不同元素的数组中找到第k个最小元素。它类似于快速选择算法,但在实际运行中有更好的运行时间。 和 QuickSelect 一样,该算法基于分区的思想工作。对数组进行分区后,分区元素会在正确的排序位置结束。如果数组有所有不同的元素,检索第(k+1) 个个最小元素与排序后检索第(k+1) 个个元素相同。因为完全排序是昂贵的(需要 O(N log N) 来计算),所以 Floyd-Rivest 算法利用分区在 O(N) 时间内完成相同的工作。
算法流程:
- 如果所考虑的数组 S 的大小足够小,则直接应用快速选择算法来获得第 K 个最小元素。这个大小是算法的任意常数,作者选择它作为 600 。
- 否则,使用随机抽样选择 2 个枢轴- newLeftIndex 和 newRightIndex,使得它们具有包含第 K 个最大元素的最高概率。然后,递归调用该函数,数组的左右边界现在设置为 newLeftIndex 和 newRightIndex。
- 像快速选择一样,在划分子阵列后,需要设置左右边界,使它们包含 K 最大的元素。 围绕 K 分割数组后,第 K 个元素处于其正确的排序位置。因此,左右边界以这样一种方式设置,即所考虑的子阵列包含数组[k]。

2 源程序
using System;
 using System.Collections;
 using System.Collections.Generic;
namespace Legalsoft.Truffer.Algorithm
 {
     /// <summary>
     /// 弗洛伊德-瑞文斯特算法
     /// Floyd Rivest Algorithm
     /// </summary>
     public static partial class Algorithm_Gallery
     {
         private static int Sign(double x)
         {
             return (x < 0) ? -1 : (x > 0) ? 1 : 0;
         }
        private static void Swap(ref int[] arr, int i, int j)
         {
             int temp = arr[i];
             arr[i] = arr[j];
             arr[j] = temp;
         }
        private static int Floyd_Rivest(int[] arr, int left, int right, int k)
         {
             int i;
             while (right > left)
             {
                 if ((right - left) > 600)
                 {
                     int n = right - left + 1;
                     i = k - left + 1;
                     double z = Math.Log(n);
                     double s = 0.5 * Math.Exp(2 * z / 3);
                     double sd = 0.5 * Math.Sqrt(z * s * (n - s) / n) * Sign(i - n / 2);
                     int newLeft = Math.Max(left, (int)(k - i * s / n + sd));
                     int newRight = Math.Min(right, (int)(k + (n - i) * s / n + sd));
                     Floyd_Rivest(arr, newLeft, newRight, k);
                 }
                int t = arr[k];
                 i = left;
                 int j = right;
                 Swap(ref arr, left, k);
                 if (arr[right] > t)
                 {
                     Swap(ref arr, left, right);
                 }
                while (i < j)
                 {
                     Swap(ref arr, i, j);
                     i++;
                     j--;
                    while (arr[i] < t)
                     {
                         i++;
                     }
                     while (arr[j] > t)
                     {
                         j--;
                     }
                 }
                 if (arr[left] == t)
                 {
                     Swap(ref arr, left, j);
                 }
                 else
                 {
                     j++;
                     Swap(ref arr, right, j);
                 }
                if (j <= k)
                 {
                     left = j + 1;
                 }
                 if (k <= j)
                 {
                     right = j - 1;
                 }
             }
             return arr[k];
         }
     }
 }
  
POWER BY 315SOFT.COM

3 源代码
using System;
using System.Collections;
using System.Collections.Generic;namespace Legalsoft.Truffer.Algorithm
{/// <summary>/// 弗洛伊德-瑞文斯特算法/// Floyd Rivest Algorithm/// </summary>public static partial class Algorithm_Gallery{private static int Sign(double x){return (x < 0) ? -1 : (x > 0) ? 1 : 0;}private static void Swap(ref int[] arr, int i, int j){int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}private static int Floyd_Rivest(int[] arr, int left, int right, int k){int i;while (right > left){if ((right - left) > 600){int n = right - left + 1;i = k - left + 1;double z = Math.Log(n);double s = 0.5 * Math.Exp(2 * z / 3);double sd = 0.5 * Math.Sqrt(z * s * (n - s) / n) * Sign(i - n / 2);int newLeft = Math.Max(left, (int)(k - i * s / n + sd));int newRight = Math.Min(right, (int)(k + (n - i) * s / n + sd));Floyd_Rivest(arr, newLeft, newRight, k);}int t = arr[k];i = left;int j = right;Swap(ref arr, left, k);if (arr[right] > t){Swap(ref arr, left, right);}while (i < j){Swap(ref arr, i, j);i++;j--;while (arr[i] < t){i++;}while (arr[j] > t){j--;}}if (arr[left] == t){Swap(ref arr, left, j);}else{j++;Swap(ref arr, right, j);}if (j <= k){left = j + 1;}if (k <= j){right = j - 1;}}return arr[k];}}
}