排序二:二分查找法优化插入排序
通俗的插排是对一个整型数组进行升序排序,可以看出每个元素插入到队列中经过两个步骤:先是挨个比较,找到自己所在的位置;然后把后面的数据全部移位,然后把元素插入。
要把数据插入,移位是必不可少了。那么,挨个比较倒是可以优化,因为要插入的队列已经是排序好的,我们可以使用二分法来减少比较的次数。
二分法的时间复杂度为O(log 2 n),而线性查找的复杂度为O(n)。
在对50000个随机数进行测试比较中,发现加了二分查找的插排比普通的插排速度快了将近一倍!(通俗插排7888ms,优化插排4852ms)
下面是测试程序源码:
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Linq;
5 using System.Text;
6 using System.Threading.Tasks;
7
8 namespace InsertSort
9 {
10 class Program
11 {
12 static void Main(string[] args)
13 {
14 int[] arr = new int[50000];
15
16 Random rd = new Random();
17 for (int i = 0; i < arr.Length; i++)
18 {
19 arr[i] = rd.Next();
20 }
21
22 Stopwatch watch = new Stopwatch();
23 watch.Start();
24 //InsertSortCommon(arr); //通俗插排7888ms
25 InsertSortOptimize(arr); //优化插排4852ms
26 watch.Stop();
27
28 Console.WriteLine(watch.ElapsedMilliseconds.ToString());
29 }
30
31 /// <summary>
32 /// 通俗插排
33 /// </summary>
34 public static void InsertSortCommon(int[] arr)
35 {
36 int temp, j;
37 for (int i = 1; i < arr.Length; i++)
38 {
39 temp = arr[i];
40 for (j = i - 1; j >= 0 && temp < arr[j]; j--)
41 {
42 arr[j + 1] = arr[j];
43 }
44 arr[j + 1] = temp;
45 }
46 }
47
48 /// <summary>
49 /// 优化插排
50 /// </summary>
51 public static void InsertSortOptimize(int[] arr)
52 {
53 int temp, j, position;
54 for (int i = 1; i < arr.Length; i++)
55 {
56 temp = arr[i];
57 position = BinSearchNum(arr, temp, 0, i - 1);
58 for (j = i - 1; j >= position; j--)
59 arr[j + 1] = arr[j];
60 arr[j + 1] = temp;
61 }
62 }
63
64 /// <summary>
65 /// 二分查找(因为不是查找与其相等值得位置,所以和传统的二分查找略有不同)
66 /// </summary>
67 public static int BinSearchNum(int[] arr, int searchNum, int low, int high)
68 {
69 int mid = 0;
70 while (low <= high)
71 {
72 mid = (low + high) / 2;
73 if (searchNum < arr[mid])
74 high = mid - 1;
75 else if (searchNum > arr[mid])
76 low = mid + 1;
77 else
78 return mid;
79 }
80 return low;//这块的返回值需要注意,为什么要这么写?
81 }
82 }
83 }
参考文献:
http://hi.baidu.com/sangwf/item/5cc1ae54d9a2889408be1722