线性时间选择算法

简介:

在一个由 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   }
复制代码





目录
相关文章
|
9天前
|
算法 数据挖掘
WINBUGS对随机波动率模型进行贝叶斯估计与比较
WINBUGS对随机波动率模型进行贝叶斯估计与比较
16 0
|
4月前
|
算法 定位技术
插值、平稳假设、本征假设、变异函数、基台、块金、克里格、线性无偏最优…地学计算概念及公式推导
插值、平稳假设、本征假设、变异函数、基台、块金、克里格、线性无偏最优…地学计算概念及公式推导
|
机器学习/深度学习 传感器 人工智能
【优化指派】基于禁忌搜索算法求解指派优化问题(耗时最短)附Matlab代码
【优化指派】基于禁忌搜索算法求解指派优化问题(耗时最短)附Matlab代码
|
机器学习/深度学习 传感器 算法
【蝴蝶算法】基于随机惯性权重策略+最优邻域扰动策略+动态转换概率策略的蝴蝶算法求解单目标优化问题附matlab代码IBOA
【蝴蝶算法】基于随机惯性权重策略+最优邻域扰动策略+动态转换概率策略的蝴蝶算法求解单目标优化问题附matlab代码IBOA
|
算法 编译器 应用服务中间件
加权随机设计与实现
加权随机,是指当我们从某种容器中随机选择一个元素,每个元素被选中的机会并不相等,而是由相对“权重”(或概率)被选中的,也就是说我们想要有“偏心”的得到某种随机结果。
78629 1
加权随机设计与实现
用c/c++代码求解时分秒针重合次数
用c/c++代码求解时分秒针重合次数
|
算法 API
分治法——线性时间选择
分治法——线性时间选择
118 0
加权平均的重要作用
加权平均的重要作用
504 0
加权平均的重要作用
|
人工智能 开发者
概率与频率 | 学习笔记
快速学习概率与频率
47 0
概率与频率 | 学习笔记
|
机器学习/深度学习 传感器 算法
基于变因子加权学习与邻代维度交叉策略的改进乌鸦算法求解单目标优化问题含Matlab代码
基于变因子加权学习与邻代维度交叉策略的改进乌鸦算法求解单目标优化问题含Matlab代码