常见的五类排序算法图解和实现(归并类:二路归并排序)

归并类的排序算法

归并:将两个或两个以上的有序表组合成一个新的有序表。

内部排序中,通常采用的是 2-路归并排序。即:将两个位置相邻的记录有序子序列归并为一个记录有序的序列。归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

图解如下

看成是 n 个有序的子序列(长度为 1),然后两两归并。

得到 n/2 个长度为2 或 1 的有序子序列。继续亮亮归并

最后一趟

代码如下:

 1 //二路一次归并过程的算法
 2 //low为本次二路归并排序的第1有序区的第1个元素,i指向第1个元素, mid为第1有序区的最后1个元素
 3 void merge(int List[], int low, int mid, int high)
 4 {
 5     //mid+1为第2有序区第1个元素,mid为第1有序区的最后1个元素
 6     //i 指向第 1 有序区的第 1 个元素
 7     int i = low;
 8     //j 指向第 2 有序区的第 1 个元素,high 为第 2 有序区的最后一个元素
 9     int j = mid + 1;
10     //temp数组暂存合并的有序序列
11     int *temp = new int[high - low + 1];
12     //设置临时数组的指示标志 k
13     int k = 0;
14     //内存分配失败
15     if(!temp){
16         cout<<"数组分配失败!";
17         exit(0);
18     }
19     //顺序选取两个有序区的较小元素,存储到t数组中,因为是递增排序
20     while(i <= mid && j <= high){
21         //较小的元素,存入temp临时数组中
22         if(List[i] <= List[j]){
23             temp[k++] = List[i++];
24         }else{
25             temp[k++] = List[j++];
26         }
27     }// end of while
28     //比完之后,假如第1个有序区仍有剩余,则直接全部复制到 temp 数组
29     while(i <= mid){
30         temp[k++] = List[i++];
31     }
32     //比完之后,假如第2个有序区还有剩余,则直接全部复制到 temp 数组
33     while(j <= high){
34         temp[k++] = List[j++];
35     }
36     //将排好序的序列,重存回到 list 中 low 到 high 区间
37     for(i = low, k = 0; i <= high; i++, k++){
38         List[i] = temp[k];
39     }
40     //delete [] 删除动态数组的内存
41     delete []temp;
42 }
43
44 //递归实现二路归并排序(也就是分治法的思想)
45 void mergeSort(int List[], int low, int high)
46 {
47     //二路归并排序,分为二路
48     int mid = (low + high) / 2;
49     //终止条件,low >= high, 不是while,且不含等号,否则死循环
50     if(low < high)
51     {
52         //递归过程,二路归并排序递归过程
53         mergeSort(List, low, mid);
54         mergeSort(List, mid + 1, high);
55         //归并
56         merge(List, low, mid, high);
57     }
58 }
59
60 int main(void)
61 {
62     int source[7] = {49, 38, 65, 97, 76, 13, 27};
63
64     mergeSort(source, 0, 6);
65
66     for (int i = 0; i < 7; i++) {
67         printf(" %d  ", source[i]);
68     }
69
70     return 0;
71 }

上述代码使用的是递归的方式,递归函数里,递归语句之前的语句和各级被调的递归函数执行顺序一致,而递归语句之后的语句和被调的递归函数执行顺序相反。这就是为什么 merge 函数要放在递归语句(两条递归语句)之后,因为是逆向执行的。联系二路归并排序的过程!!

还可以使用非递归的方式,代码如下:

 1 //非递归算法实现二路归并排序,length代表数组长度,即数组最大下标是 legth - 1
 2 void mergeSort(int List[],int length)
 3 {
 4     //回忆图解的过程,二路归并算法的流程,不同于递归,递归是先递归语句,然后归并函数,这样归并函数是倒序执行(和递归函数执行顺序相反)
 5     int size = 1;
 6     int low;
 7     int mid;
 8     int high;
 9     //size 是标记当前各个归并序列的high-low,从1,2,4,8,……,2*size
10     while(size <= length - 1)
11     {
12         //从第一个元素开始扫描,low代表第一个分割的序列的第一个元素
13         low = 0;
14         //当前的归并算法结束的条件
15         while(low + size <= length - 1)
16         {
17             //mid代表第一个分割的序列的最后一个元素
18             mid = low + size - 1;
19             //high 代表第二个分割的序列的最后一个元素
20             high = mid + size;
21             //判断一下:如果第二个序列个数不足size个
22             if(high > length - 1){
23                 //调整 high 为最后一个元素的下标即可
24                 high = length - 1;
25             }
26             //调用归并函数,进行分割的序列的分段排序
27             merge(List, low, mid, high);
28             //打印出每次归并的区间
29             cout << "low:" << low << " mid:" << mid << " high:" << high << endl;
30             //下一次归并时第一序列的第一个元素位置
31             low = high + 1;
32         }// end of while
33         //范围扩大一倍,二路归并的过程
34         size *= 2;
35     }// end of while
36 }

二路归并排序算法分析

每趟归并的时间复杂度为O(n),共需进行 log2 n 趟。

二路归并排序的时间复杂度:等于归并趟数与每一趟时间复杂度的乘积。时间复杂度为O(nlog2n)。

利用二路归并排序时,需要利用与待排序数组相同的辅助数组作临时单元,故该排序方法的空间复杂度为O(n),比前面介绍的其它排序方法占用的空间大。

由于二路归并排序中,每两个有序表合并成一个有序表时,若分别在两个有序表中出现有相同排序码,则会使前一个有序表中相同排序码先复制,后一有序表中相同排序码后复制,从而保持它们的相对次序不会改变。所以,二路归并排序是一种稳定的排序方法。

归并的思想主要用于外部排序:

外部排序可分两步

①待排序记录分批读入内存,用某种方法在内存排序,组成有序的子文件,再按某种策略存入外存。

②子文件多路归并,成为较长有序子文件,再记入外存,如此反复,直到整个待排序文件有序。

外部排序可使用外存、磁带、磁盘,最初形成有序子文件长取决于内存所能提供排序区大小和最初排序策略,归并路数取决于所能提供排序的外部设备数。

 

辛苦的劳动,转载请注明出处,谢谢……

http://www.cnblogs.com/kubixuesheng/p/4355865.html

时间: 2024-12-03 12:03:57

常见的五类排序算法图解和实现(归并类:二路归并排序)的相关文章

常见的五类排序算法图解和实现(多关键字排序:基数排序以及各个排序算法的总结)

基数排序思想 完全不同于以前的排序算法,可以说,基数排序也叫做多关键字排序,基数排序是一种借助"多关键字排序"的思想来实现"单关键字排序"的内部排序算法. 两种方式: 1.最高位优先,先按照最高位排成若干子序列,再对子序列按照次高位排序 2.最低位优先:不必分子序列,每次排序全体元素都参与,不比较,而是通过分配+收集的方式. 多关键字排序 例:将下表所示的学生成绩单按数学成绩的等级由高到低排序,数学成绩相同的学生再按英语成绩的高低等级排序.        第一个关键

常见的五类排序算法图解和实现(插入类:直接插入排序,折半插入排序,希尔排序)

基本的五类排序算法(插入,选择,交换,归并,基数排序).排序:将数据元素的一个任意序列,重新排列成一个按关键字有序的序列. 排序的稳定性:待排序列中有大于等于2个相同的项,且排序前后,相同项的相对位置是否发生了变化(如果变化了就是不稳定的排序,不变化就是稳定的) 内部排序:若整个排序过程不需要访问外存便能完成,则称此类排序问题为内部排序:(待排序列全部放入内存) 插入累排序:(直接插入,折半插入,希尔排序) 直接插入排序: 先将序列中第 1 个记录看成是一个有序子序列, 然后从第 2 个记录开始

常见的五类排序算法图解和实现(选择类:简单选择排序,锦标赛排序,树形选择排序,堆排序)

选择类的排序算法 简单选择排序算法 采用最简单的选择方式,从头到尾扫描待排序列,找一个最小的记录(递增排序),和第一个记录交换位置,再从剩下的记录中继续反复这个过程,直到全部有序. 具体过程: 首先通过 n –1 次关键字比较,从 n 个记录中找出关键字最小的记录,将它与第一个记录交换. 再通过 n –2 次比较,从剩余的 n –1 个记录中找出关键字次小的记录,将它与第二个记录交换. 重复上述操作,共进行 n –1 趟排序后,排序结束. 如图   过程图解 令 k=i:j = i + 1: 目

常见的五类排序算法图解和实现(交换类:冒泡排序,递归的快速排序)

冒泡排序算法: 总的来说就是两两交换,反复直到有序,第一个记录和第二个记录,若逆序则交换,然后比较第二个和第三个记录,以此类推,直到第 n 个记录和第 n-1个记录比较完毕为止,第一趟排序,结果关键字最大的记录被安排在最后一个位置.对前 n-1个记录继续冒泡排序,使得关键字次大的记录安排在第 n-1个位置.如此重复,直到没有需要交换的记录为止(仅仅是第一个和第二个交换过为止).整个一趟趟的选出最值的过程,仿佛是那水里的气泡,咕嘟咕嘟的往上翻的过程. 递增冒泡排序过程图解: 一般先比较第一个元素和

深入浅出交换类排序算法(转)

1)冒泡排序 冒泡排序在众多排序算法中算比较简单的一个,基本思想是重复的进行整个数列的排序,一次比较两个元素(两两排序),如果它们顺序不符合就交换,重复这样直到数列没有再需要交换的数为止(结束条件).就好像气泡一样,轻的气泡会往上漂浮,在不断漂浮的过程中,发生了两两交换过程,所以叫冒泡排序. 其实也可以用生活中的例子理解,就比如: 在军训排队时,按个子高的和个子矮的的顺序进行排列,个子高的和个子矮的会进行两两进行比较. 我们来大致看下算法的流程: 选一组序列 4, 3 , 5, 6, 2, 1 

5种java排序算法汇总工具类_java

工具类简单明了地总结了java的快速排序,希尔排序,插入排序,堆排序,归并排序五种排序算法,代码中并没有对这几种排序算法的一个说明,关于思想部分希望在自行查阅相关说明,这里只是对这几种算法进行一个概括,以供大家使用. public class Sort { public static <AnyType extends Comparable<? super AnyType>> void insertionSort(AnyType[] a) { insertionSort(a, 0,

图解程序员必须掌握的Java常用8大排序算法_java

这篇文章主要介绍了Java如何实现八个常用的排序算法:插入排序.冒泡排序.选择排序.希尔排序 .快速排序.归并排序.堆排序和LST基数排序,分享给大家一起学习. 分类1)插入排序(直接插入排序.希尔排序) 2)交换排序(冒泡排序.快速排序) 3)选择排序(直接选择排序.堆排序) 4)归并排序 5)分配排序(基数排序) 所需辅助空间最多:归并排序 所需辅助空间最少:堆排序 平均速度最快:快速排序 不稳定:快速排序,希尔排序,堆排序. 先来看看8种排序之间的关系: 1.直接插入排序 (1)基本思想:

排序算法(Java)——那些年面试常见的排序算法

前言 排序就是将一组对象按照某种逻辑顺序重新排列的过程.比如信用卡账单中的交易是按照日期排序的--这种排序很可能使用了某种排序算法.在计算时代早期,大家普遍认为30%的计算周期都用在了排序上,今天这个比例可能降低了,大概是因为现在的排序算法更加高效.现在这个时代数据可以说是无处不在,而整理数据的第一步往往就是进行排序.所有的计算机系统都实现了各种排序算法以供系统和用户使用. 即使你只是使用标准库中的排序函数,学习排序算法仍然有很大的实际意义: - 排序算法往往是我们解决其他问题的第一步 - 排序

数据结构——排序算法总结

  排序(Sorting)就是将一组对象按照规定的次序重新排列的过程,排序往往是为检索而服务的,它是数据处理中一种很重要也很常用的运算.例如我们日常学习中的查字典或者书籍的目录,这些都事先为我们排好序,因此大大降低了我们的检索时间,提高工作效率.   排序可分为两大类:   内部排序(Internal Sorting):待排序的记录全部存放在计算机内存中进行的排序过程:   外部排序(External Sorting):待排序的记录数量很大,内存不能存储全部记录,需要对外存进行访问的排序过程.