由于快速排序每一轮都可以将一个元素正确的归位,所以我们可以利用快速排序的思想来定位中位数。
1)我们就以数组的arr[0]为基准参照,如果第一轮快排过后,arr[0]的位置恰好被归位到arr.Length/2,则arr[0]肯定就是中位数;
2)如果arr[0]归位后,位置小于arr.Length/2(假如是i),则中位数肯定在arr[i+1]到arr[arr.Length-1]之间。
3)如果arr[0]归位后,位置大于arr.Length/2(假如是j),则中位数肯定在arr[0]到arr[j-1]之间。
4)递归即可。
1 using System; 2 using System.Diagnostics; 3 using System.Linq; 4 using System.Threading; 5 6 namespace MiddleNumber 7 { 8 class Program 9 { 10 //static int[] _arr = { 4, 5,10, 15, 19, 14, 10, 10 }; 11 static Stopwatch _stopwatch = new Stopwatch(); 12 static void Main(string[] args) 13 { 14 int[] _arr = GetNumbers(40000); 15 _stopwatch.Start(); 16 var arrList = _arr.ToList(); 17 arrList.Sort(); 18 Console.WriteLine(arrList[_arr.Length / 2]); 19 _stopwatch.Stop(); 20 Console.WriteLine("sort方法后去中间位置的数,毫秒数{0}",_stopwatch.ElapsedMilliseconds); 21 _stopwatch.Reset();
_stopwatch.Start(); 22 Console.WriteLine(GetMiddleNum(_arr, 0, _arr.Length / 2)); 23 _stopwatch.Stop(); 24 Console.WriteLine("快排求中位数,毫秒数{0}",_stopwatch.ElapsedMilliseconds); 25 Console.ReadKey(); 26 } 27 //利用快速排序的思想寻找中位数,快排的每一轮可以完全确定一个元素的归位。 28 private static int GetMiddleNum(int[] arr, int idx, int middle) 29 { 30 int i = 0; 31 int j = arr.Length - 1; 32 while (true) 33 { 34 while (i != j && arr[j] >= arr[0]) 35 j--; 36 while (i != j && arr[i] <= arr[0]) 37 i++; 38 if (i != j) 39 Exchange(ref arr[i], ref arr[j]); 40 if (i == j) 41 { 42 if (i != 0) 43 Exchange(ref arr[i], ref arr[0]); 44 if (i + idx == middle) 45 return arr[i]; 46 else if (i + idx > middle) 47 return GetMiddleNum(arr.Take(i).ToArray(), idx, middle); 48 else 49 return GetMiddleNum(arr.Skip(i + 1).ToArray(), i + 1 + idx, middle); 50 } 51 } 52 } 53 //注意这里有个陷阱: 54 //var t = new int[] {10}; //只有一个元素10 55 //Exchange(ref t[0],ref t[0]); 56 //这样的话,结果t[0]=0;而不再是10,达不到交换的目的;自己想想为什么 57 static private void Exchange(ref int a, ref int b) 58 { 59 a = a ^ b; 60 b = b ^ a; 61 a = a ^ b; 62 } 63 //产生随机数 64 private static int[] GetNumbers(int x) 65 { 66 var arr = new int[x]; 67 for (int i = 0; i < x; i++) 68 { 69 Thread.Sleep(100); 70 arr[i] = new Random().Next(1, x); 71 } 72 return arr; 73 } 74 } 75 }
但是测出来时间差别不大,不知道为何。100000个随机数,时间也一样。