编程之美-电梯调度-快速排序-查找第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)

样例演示:

 

代码主体:

View Code
 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 }

 

执行代码:

View Code
 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 }

 

 

posted @ 2012-12-18 15:39  四龙须  阅读(458)  评论(8编辑  收藏  举报