编程之美-电梯调度-快速排序-查找第K大数
亚洲微软研究院所在的希格玛大厦一共有6部电梯。在高峰时间,每层都有人上下,电梯每层都停。实习生小飞常常会被每层都停的电梯弄的很不耐烦,于是他提出了这样一个办法:
由于楼层并不算太高,那么在繁忙的上下班时间,每次电梯从一层往上走时,我们只允许电梯停在其中的某一层。所有乘客从一楼上电梯,到达某层后,电梯停下来,所有乘客再从这里爬楼梯到自己的目的层。在一楼的时候,每个乘客选择自己的目的层,电梯则计算出应停的楼层。
问:电梯停在哪一层楼,能够保证这次乘坐电梯的所有乘客爬楼梯的层数之和最少?
分析:如果只有两个人到不同的楼层,A到4楼,B到9楼,那么电梯停在[4,9]区间之间,他们爬楼梯的总和都是一样的,共爬5个楼层。
如果有三个人:A到4楼,B到6楼,C到9楼,那么停在6楼的时候爬的楼层最少。
如果有四个人:A到4楼,B到5楼,C到7楼,D到11楼,那么停在[5,7]区间之间时,爬的楼层总和最少。
由上可得,就是找中位数的问题。本文用快速排序查找。
快速排序(Quicksort)是对冒泡排序的一种改进.
它的基本思路是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据比另外一部分的所有数据都要小,然后再按此方法对这两部分分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列.
时间复杂度: T(n)=θ(nlogn)
样例演示:
代码主体:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System.Collections.Generic; 2 3 namespace QuickSortArithmetic 4 { 5 /// <summary> 6 /// 用快速排序查找第K大的数 7 /// </summary> 8 public class QuickSortOfKMaxNum 9 { 10 //最后返回的第K大的数 11 private int? _theKmaxNum = null; 12 //第K大的数的顺序,也就是K 13 public int K;//改为小写k试试 14 15 public int? TheKmaxNum { get; set; } 16 17 public int? GetKmaxNum(List<int> list, int k) 18 { 19 K = k - 1; 20 QuickSort(list, 0, list.Count - 1); 21 return TheKmaxNum; 22 } 23 24 public void QuickSort(List<int> list, int _left, int _right) 25 { 26 if (_left > _right) 27 return; 28 29 //把数据集的最左边和最右边标量保存下来 30 int left = _left, right = _right; 31 32 //选取数据集的第一个数为基准数,并保存在变量x上 33 int x = list[left]; 34 while (left < right) 35 { 36 //从数据集的最右边开始找,在找到比x小的数之前,不断的从右边向左边查找, 37 //直到找到比x小的数,每次比较都向左边移动一个距离right-- 38 while (x < list[right] && left < right) 39 right--; 40 41 //如果找到比x小的数,那么就就和left位置的数交换数值, 42 //第一次运行时是第一个位置,交换之后,第一个位置就是比x小的数值,第right位置的数值就是x的数值 43 //同时left++,即向右边移动一个距离,因为left位置的数值就是刚刚交换过来比x小的数,不需要比较了 44 if (list[right] < x && left < right) 45 { 46 Swap(list, left, right); 47 left++; 48 } 49 50 //右边查找到一个符合的数之后,反过来开始从左边标量left向右边right查找比x大的数 51 //直到找到符合的数,每次比较都想右边移动一个距离left++ 52 while (list[left] < x && left < right) 53 left++; 54 55 //如果找到比x大的数,那么就和right位置的数交换 56 if (x < list[left] && left < right) 57 { 58 Swap(list, left, right); 59 right--; 60 } 61 } 62 list[left] = x; 63 64 //因为经过上面排序之后,已经知道在K之前的数都比K小,在K之后的数都比K大, 65 //如果刚好left(此时left和right相等)等于K,那么left位置的值就是第K大的数 66 if (left == K) 67 TheKmaxNum = list[left]; 68 69 //如果left大于K,那么就是说第K大的数至少比left位置的数大, 70 //而比left位置大的数都在它的右边,所以只需要从右边开始找 71 else if (left > K) 72 { 73 QuickSort(list, left + 1, _right); 74 } 75 else 76 { 77 QuickSort(list, _left, left - 1); 78 } 79 } 80 81 private void Swap(List<int> s, int i, int j) 82 { 83 int temp = s[j]; 84 s[j] = s[i]; 85 s[i] = temp; 86 } 87 } 88 }
执行代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 using System; 2 using System.Collections.Generic; 3 4 namespace QuickSortArithmetic 5 { 6 class Program 7 { 8 static void Main(string[] args) 9 { 10 List<int> s = new List<int>(); 11 Random rd = new Random(); 12 for (int i = 0; i < 10; i++) 13 { 14 s.Add(rd.Next(0, 50)); 15 } 16 17 //第K大的数 18 QuickSortOfKMaxNum quick = new QuickSortOfKMaxNum(); 19 int? kmax = quick.GetKmaxNum(s, 4); 20 } 21 } 22 }
生命不息,奋斗不止!