【算法设计与分析课程笔记】并归排序和逆序数计算Merge Sort and Counting Inversions
感觉不是计算机专业 一直做和编程相关的应用 但是没有上过那些算法的基础课会遇到越来越多的问题。在guokrMOOC学院中看到这门Stanford的算法设计和分析的课程就选了。课程下面有帖子讨论你为什么要选这门课,有很多回复都是说不是从计算机专业毕业但是做应用开发,现在觉得基础确实很重要。课程的量比较大,这里的记录就简略一些,这部分课程内容的编程题是计算一个有100000个数的序列中的逆序数对的个数。
并归排序(Merge Sort)是一种使用分治法(Divided-and-Conquer)思路设计的排序算法
并归排序的过程
Divide 将n个元素分成两个包含n/2个元素的的子序列
Conquer 用并归排序对两个子序列进行排序
Merge 将两个已排序的子序列合并得到结果
并归排序每次将序列分成长度为原先一半的子序列再进行并归排序 进行logN层Divide之后只剩下长度为1或2的子序列
然后再对这些子序列进行合并就可以,所以我们只要关注Merge的过程
先写主体的递归循环
1 int MergeSort(int a, int b)
2 {
3 if (a < b) //判定序列长度是否大于1,不判定会造成无限循环
4 {
5 int count = 0;
6 int mid = (a + b) / 2;
7 count += MergeSort(a, mid);
8 count += MergeSort(mid + 1, b);
9 count += Merge(a, mid, b);
10 return count;
11 }
12 return 0;
13 }
Merge(int a, int mid,int b)是对两个子序列进行合并的函数
a 和 b分别代表序列下标的开始和结束
对于一个从A[a]到A[b]的序列 我们分割为两个子序列 A[a]到A[mid] 和A[mid+1]到A[b]
这里的返回值count为逆序数
接下来的写合并的函数Merge
1 int Merge(int a, int mid, int b)
2 {
3 int count = 0;
4
5 int i = a; //i为第一个序列的索引
6 int j = mid + 1; //j为第一个序列的索引
7 int k = a; //k为合并后序列的索引
8
9 while (i <= mid&& j <= b)
10 {
11 if (A[i] <= A[j])
12 {
13 T[k++] = A[i++];
14 }
15 else
16 {
17 if (A[i] >= A[j])
18 {
19 T[k++] = A[j++];
20
21 count += j - k; //移动一个元素后消除的逆序数
22 }
23 }
24 }
25
26 //此时两个子序列已经有一个完全被合并 把另一个序列的剩余元素合并
27 while (i<=mid)
28 {
29 T[k++] = A[i++];
30 }
31 while (j <= b)
32 {
33 T[k++] = A[j++];
34 }
35 //将合并后的数组复制到原数组
36 for (int i = a; i <= b; i++)
37 {
38 A[i] = T[i];
39 }
40
41 return count;//返回此次合并的逆序数
42 }
在并归排序中进行逆序数的计算是逼直接计算逆序数的效率高的 并归排序的时间复杂度是O(n*log(n)) 直接计算是O(n^2)
移动一个元素后消除的逆序数为j - k还是要画图理解一下