归并排序的思路
----雨竹清风
归并排序是将两个或者两个以上的有序表组合成一个新的有序表。
思路:初始序列是n个记录,则看成n个有序元素,,每个序列的长度是1,然后两两归并,得到n/2个长度为2个或者1的有序序列,然后再两两归并。直到得到一个长度为n的有序序列为止,这种方法称为2-路归并排序。
伪代码为:
void Msort(SR[],&TR[],int s,int t){
if(s == t)
TR[s] = SR[s];
else{
m = (s + t) / 2;//将SR[]平均分为SR[s..m]和SR[m+1..t]
Msort(SR,TR2,s,m);//递归的将SR[s..m]归并为有序的TR2[s..m]
Msort(SR,TR2,m+1,t);//递归的将SR[m+1..t]归并为有序的TR2[m+1..t]
}
}
//
void Merge(SR[],&TR[],int i, int m,int n){
for(j = m + 1,k = i;i <= m&&j <= n; ++k){//由小到大并入TR[]
if(SR[i] < SR[j]) TR[k] = SR[i++];
else
TR[k] = SR[j++];
}
//将剩余元素拷贝
if(i <= m) TR[k..n] = SR[i..m];
if(j <= n) TR[k..n] = SR[j..n];
}
//
其时间复杂度为O(nlgn)。
//
下面是对归并排序使用java语言写,初用java语言写数据结构不太习惯,用了很长时间才将归并排序写出来。通过这次练习,学到了很多知识,特别是在MyEclipse中的调试技巧。
在java中写的归并排序是在链表中实现归并排序。难度比数组中大很多。
主要思想:建立一个链表,之后的归并排序就是在原有的链表上进行的交换操作。
代码如下:
![归并排序的思路 - 雨竹清风 - 雨竹清风的博客 归并排序的思路 - 雨竹清风 - 雨竹清风的博客](http://img0.ph.126.net/PV70J0bXCyjh892ClDUjOA==/6630483925026238170.png)
![归并排序的思路 - 雨竹清风 - 雨竹清风的博客 归并排序的思路 - 雨竹清风 - 雨竹清风的博客](http://img1.ph.126.net/q9hekc5GMtZwLWTMyc4yAw==/6630677439073433392.png)
主要介绍一下合并操作:
for (; i <= m && k <= t;) {
if (p.data > q.data) {
++i;
r = p;
p = p.next;
} else {//后移操作比较麻烦
// 后移
d = q;
q = q.next;
++k;
// 找最后的元素
te = p;// 设置一个变量指向s..m的最后一个元素
while (te.next != d) {
te = te.next;// 找到最后的结点
}
// 交换
r.next = d;
d.next = p;
te.next = q;
//r后移
r = r.next;
}
p指向的是s..m的元素,设置一个变量r指向p的前一个结点。
q指向的是m+1..t的元素,设置一个变量d指向q的前一个结点。te指向的是m位置的元素,这些变量的设置都为移动做的铺垫。
当p > q 时,p后移,意思是大的元素始终是放在前面,小的元素放在后面。
当p <= q时,移动:
首先q要后移一个,在此之前d要指向q,q后移之后d就指向q的前一个结点了。
找到m位置的元素,用变量te来指向。
下面就进行移动,因为q(q移动之前指的元素)所指的元素比p的要大,所以应该插入到p的前面,那么r(p的前一个位置元素)的下一个应该指向d所指元素,d的下一个相应的要指向p,而q所指的元素以及其后面的结点还没有链上,所以设置te变量,让te的下一个指向q。同时r要后移,这样移动操作就完成了。