zoukankan      html  css  js  c++  java
  • 线性时间选择算法

    在一个由 n 个元素组成的集合中,第 i 个顺序统计量(order statistic)是该集合中第 i 小的元素。也就是说,最小值是第 1 个顺序统计量(i = 1),最大值是第 n 个顺序统计量(i = n)。

    中位数(median)是它所在集合的中点元素。当 n 为奇数时,中位数是唯一的,出现在 i = (n + 1)/2 处。当 n 为偶数时,存在两个中位数,下中位数 i = n/2 和上中位数 i = n/2 + 1 处。因此,不考虑 n 的奇偶性,中位数总是出现在 i = (n+1)/2 的中位数处。本文中所用的中位数总是指下中位数。

    选择最大值和最小值

    对于确定最大值和最小值的问题,n-1 次比较是最优的。

    对于同时获取最大值和最小值,至多需要 3(n/2) 次比较就足以同时找到。如果 n 是奇数,那么总共需要 3(n/2) 次比较。如果 n 是偶数,则可先做一次初始比较,接着做 3((n - 2)/2) 次比较。

     1   class Program
     2   {
     3     static void Main(string[] args)
     4     {
     5       int[] unsorted = 
     6         { 
     7           4, 1, 5, 2, 6, 3, 7, 9, 8, 0 
     8         };
     9 
    10       Console.WriteLine("Min: {0}", GetMinimum(unsorted));
    11       Console.WriteLine("Max: {0}", GetMaximum(unsorted));
    12 
    13       int min, max;
    14       GetBothMinMax(unsorted, out min, out max);
    15       Console.WriteLine("Min: {0}, Max: {1}", min, max);
    16 
    17       Console.Read();
    18     }
    19 
    20     static int GetMinimum(int[] a)
    21     {
    22       int min = a[0];
    23 
    24       // n-1 次比较
    25       for (int i = 1; i < a.Length; i++)
    26       {
    27         if (a[i] < min)
    28           min = a[i];
    29       }
    30 
    31       return min;
    32     }
    33 
    34     static int GetMaximum(int[] a)
    35     {
    36       int max = a[0];
    37 
    38       // n-1 次比较
    39       for (int i = 1; i < a.Length; i++)
    40       {
    41         if (a[i] > max)
    42           max = a[i];
    43       }
    44 
    45       return max;
    46     }
    47 
    48     static void GetBothMinMax(int[] a, out int min, out int max)
    49     {
    50       min = a[0];
    51       max = a[0];
    52 
    53       if (a.Length % 2 > 0) // n 为奇数
    54       {
    55         for (int i = 1; i < a.Length; i = i + 2)
    56         {
    57           if (a[i] < a[i + 1])
    58           {
    59             if (a[i] < min) min = a[i];
    60             if (a[i + 1] > max) max = a[i + 1];
    61           }
    62           else
    63           {
    64             if (a[i + 1] < min) min = a[i + 1];
    65             if (a[i] > max) max = a[i];
    66           }
    67         }
    68       }
    69       else                  // n 为偶数
    70       {
    71         for (int i = 1; i < a.Length - 1; i = i + 2)
    72         {
    73           if (a[i] < a[i + 1])
    74           {
    75             if (a[i] < min) min = a[i];
    76             if (a[i + 1] > max) max = a[i + 1];
    77           }
    78           else
    79           {
    80             if (a[i + 1] < min) min = a[i + 1];
    81             if (a[i] > max) max = a[i];
    82           }
    83         }
    84 
    85         if (a[a.Length - 1] < min) min = a[a.Length - 1];
    86         if (a[a.Length - 1] > max) max = a[a.Length - 1];
    87       }
    88     }
    89   }

    选择中位数或任意位置值

    RANDOMIZED-SELECT 算法采用快速排序算法的思想。区别是,快速排序会递归地处理划分的两边,而 RANDOMIZED-SELECT 则只处理一边。所以快速排序的期望运行时间是 Θ(n lg n),而 RANDOMIZED-SELECT 的期望运行时间为 Θ(n)。

    RANDOMIZED-SELECT 的最坏运行时间为 Θ(n2),即使是要选择最小元素也是如此。因为它是随机化的,该算法的平均情况性能较好。

      1   public class QuickFindAlgorithm
      2   {
      3     public static void TestRandomizedQuickFind()
      4     {
      5       int[] unsorted = 
      6         { 
      7           4, 1, 5, 2, 6, 3, 7, 9, 8, 0 
      8         };
      9 
     10       Console.WriteLine("Find Value : {0}",
     11         RandomizedQuickFind(unsorted, 0, unsorted.Length - 1, 1));
     12       Console.WriteLine("Find Value : {0}",
     13         RandomizedQuickFind(unsorted, 0, unsorted.Length - 1, 2));
     14       Console.WriteLine("Find Value : {0}",
     15         RandomizedQuickFind(unsorted, 0, unsorted.Length - 1, 3));
     16       Console.WriteLine("Find Value : {0}",
     17         RandomizedQuickFind(unsorted, 0, unsorted.Length - 1, 4));
     18       Console.WriteLine("Find Value : {0}",
     19         RandomizedQuickFind(unsorted, 0, unsorted.Length - 1, 5));
     20       Console.WriteLine("Find Value : {0}",
     21         RandomizedQuickFind(unsorted, 0, unsorted.Length - 1, 6));
     22       Console.WriteLine("Find Value : {0}",
     23         RandomizedQuickFind(unsorted, 0, unsorted.Length - 1, 7));
     24       Console.WriteLine("Find Value : {0}",
     25         RandomizedQuickFind(unsorted, 0, unsorted.Length - 1, 8));
     26       Console.WriteLine("Find Value : {0}",
     27         RandomizedQuickFind(unsorted, 0, unsorted.Length - 1, 9));
     28       Console.WriteLine("Find Value : {0}",
     29         RandomizedQuickFind(unsorted, 0, unsorted.Length - 1, 10));
     30 
     31       int median = RandomizedQuickFind(unsorted, 
     32         0, unsorted.Length - 1, (unsorted.Length + 1) / 2);
     33       Console.WriteLine("Find Median : {0}", median);
     34 
     35       Console.Read();
     36     }
     37 
     38     static int RandomizedQuickFind(int[] a, int p, int r, int i)
     39     {
     40       if (p == r)
     41         return a[p];
     42 
     43       int q = RandomizedPartition(a, p, r);
     44       int k = q - p + 1;
     45 
     46       if (i == k)     // the pivot value is the answer
     47       {
     48         return a[q];
     49       }
     50       else if (i < k) // i is in left side
     51       {
     52         return RandomizedQuickFind(a, p, q - 1, i);
     53       }
     54       else            // i is in right side
     55       {
     56         return RandomizedQuickFind(a, q + 1, r, i - k);
     57       }
     58     }
     59 
     60     static void RandomizedQuickSort(int[] unsorted, int left, int right)
     61     {
     62       if (!(left < right)) return;
     63 
     64       int pivotIndex = RandomizedPartition(unsorted, left, right);
     65 
     66       RandomizedQuickSort(unsorted, left, pivotIndex - 1);
     67       RandomizedQuickSort(unsorted, pivotIndex + 1, right);
     68     }
     69 
     70     static int RandomizedPartition(int[] unsorted, int left, int right)
     71     {
     72       int i = random.Next(left, right);
     73       Swap(unsorted, i, right);
     74       return Partition(unsorted, left, right);
     75     }
     76 
     77     static int Partition(int[] unsorted, int left, int right)
     78     {
     79       int pivotIndex = right;
     80 
     81       // 哨兵
     82       int sentinel = unsorted[right];
     83 
     84       // 子数组长度为 right - left + 1
     85       int i = left - 1;
     86       for (int j = left; j <= right - 1; j++)
     87       {
     88         if (unsorted[j] <= sentinel)
     89         {
     90           i++;
     91           Swap(unsorted, i, j);
     92         }
     93       }
     94 
     95       Swap(unsorted, i + 1, pivotIndex);
     96 
     97       return i + 1;
     98     }
     99 
    100     static void Swap(int[] unsorted, int i, int j)
    101     {
    102       int temp = unsorted[i];
    103       unsorted[i] = unsorted[j];
    104       unsorted[j] = temp;
    105     }
    106 
    107     static Random random = new Random(new Guid().GetHashCode());
    108   }

    本篇文章《线性时间选择算法》由 Dennis Gao 发表自博客园,任何未经作者同意的爬虫或人为转载均为耍流氓。

  • 相关阅读:
    Flask 的 请求扩展 与 中间件
    Flask的配置文件 与 session
    django中的FBV和CBV
    Flask开启多线程、多进程
    WPF获取原始控件样式
    一个40岁老码农的总结,奋斗没有意义,选择大于努力
    FastText 分析与实践
    Flask的多app应用,多线程如何体现
    Python 远程调用MetaSploit
    GitLab 7.5.3 CentOS7安装和SMTP配置
  • 原文地址:https://www.cnblogs.com/gaochundong/p/select_order_statistic_and_median_in_linear_time.html
Copyright © 2011-2022 走看看