线性时间选择算法

在一个由 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 发表自博客园,任何未经作者同意的爬虫或人为转载均为耍流氓。

线性时间选择算法,布布扣,bubuko.com

时间: 2024-11-23 02:21:39

线性时间选择算法的相关文章

Top k问题(线性时间选择算法)

问题描述:给定n个整数,求其中第k小的数. 分析:显然,对所有的数据进行排序,即很容易找到第k小的数.但是排序的时间复杂度较高,很难达到线性时间,哈希排序可以实现,但是需要另外的辅助空间. 这里我提供了一种方法,可以在O(n)线性时间内解决Top k问题.关于时间复杂度的证明,不再解释,读者可以查阅相关资料.具体的算法描述如下: 算法:LinearSelect(S,k) 输入:数组S[1:n]和正整数k,其中1<=k<=n: 输出:S中第k小的元素 1. If  n<20  Then  

重拾算法之路——线性时间选择

***************************************转载请注明出处:http://blog.csdn.net/lttree******************************************** 第一章:分治与递归 线性时间选择 算法描述: 给定线性序集中n个元素和一个整数k,1 ≤ k ≤ n,要求找出这n个元素中第k小的元素.即如果将这n个元素依其线性序排列时,排在第k个位置的元素即为要找的元素.当k=1时,就是找最小元素,k=n时,就是找最大元素,

【分治法】线性时间选择(转)

转自:http://blog.csdn.net/liufeng_king/article/details/8480430 线性时间选择问题:给定线性序集中n个元素和一个整数k,1≤k≤n,要求找出这n个元素中第k小的元素,(这里给定的线性集是无序的). 1.随机划分线性选择 线性时间选择随机划分法可以模仿随机化快速排序算法设计.基本思想是对输入数组进行递归划分,与快速排序不同的是,它只对划分出的子数组之一进行递归处理. 程序清单如下: 1 //2d9-1 随机划分线性时间选择 2 #includ

经典算法之线性时间选择的C实现方法

线性时间选择问题,实际上是随机快速排序算法的一个引申,ie,通过对随机快速排序算法的小小改动就可以实现. 算法依然参考算法导论中的相关内容,需要注意的是, 代码中 的id 是指 所要 找的量在 现有区间 [low, high]中的位置, 因而,需要涉及 一定转化. ps: mid - low + 1 表示 我们划分出来的第一个区间的长度大小. 源代码如下: // =====================[随机选择 ]================== // @ author : zhyh20

初学算法-快速排序与线性时间选择(Deterministic Selection)的C++实现

快速排序算法其实只做了两件事:寻找分割点(pivot)和交换数据. 所谓寻找分割点,既找到一个预计会在中间位置附近的点,当然尽量越接近中点越好. 所谓交换数据,就是把比这个分割点小的数据,最终都放在分割点左边,比它大的都放在右边. 设要排序的数组是A[left]--A[right],首先任意选取一个数据(一般算法:使用随机数选取一个区间内的数. 文艺算法:取A[left].A[right]和A[rand()]的中值. 二笔算法:选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,

[图解算法] 线性时间选择——//递归与分治策略//【图解才是最直观】

1 #include <ctime> 2 #include <iostream> 3 using namespace std; 4 5 template <class Type> 6 void Swap(Type &x,Type &y); 7 8 inline int Random(int x, int y); 9 10 template <class Type> 11 void BubbleSort(Type a[],int p,int r

线性表算法-插入

线性表算法-插入

线性表算法-删除

线性表算法-删除

线性表算法-合并

线性表算法-合并