博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
算法手记(6)归并排序
阅读量:5931 次
发布时间:2019-06-19

本文共 3680 字,大约阅读时间需要 12 分钟。

今天我主要学习基于分治思想的归并排序算法,这是分治法的典型应用。废话不多说,下面直切正题。

概述:

将两个有序数组归并成一个更大的有序数组,我们称之为归并,人们根据这一操作发明了一种简单的递归排序算法:归并排序。

归并排序最吸引人的是它能够保证任意长度为N的数组排序所需的时间和NlogN成正比;它的主要缺点是需要额外占用的内存空间与N成正比。

分析:

实现归并的一种最简单的方法是将两个不同的有序数组归并到第三个数组中,实现的方法很简单,创建一个适当的数组然后将两个数组中的元素一个个从小到大放入这个数组。但这样带来的问题是排序大数组时,需要多次归并,每次归并都创建新的数组,这无疑会带来很大的问题。因此,我们需要一种能够实现原地归并的方法,这样就可以先将左边排序,再将右边排序,然后在数组中移动元素而不需要额外的内存空间,我们将在实现部分描述这种方法。

 

实现:

原地归并方法:

private static void merge(IComparable[] a, int lo, int mid, int hi)        {            int i = lo, j = mid + 1;            for (int k = lo; k <= hi; k++)                aux[k] = a[k];            for (int k = lo; k <= hi; k++)            {                if (i > mid)                       a[k] = aux[j++];                else if (j > hi)                   a[k] = aux[i++];                else if (less(aux[j], aux[i]))     a[k] = aux[j++];                else                               a[k] = aux[i++];            }        }

下面分别是两种不同的最终实现算法,它们都是应用高效算法设计中分治思想的典型例子。

  自顶向下的归并实现:

public class Merge    {        private static IComparable[] aux;        public static void sort(IComparable[] a)        {            aux = new IComparable[a.Length];            sort(a, 0, a.Length - 1);        }        private static void sort(IComparable[] a,int lo,int hi)        {            if (hi <= lo) return;            int mid = lo + (hi - lo) / 2;            sort(a, lo, mid);            sort(a, mid + 1, hi);            merge(a, lo, mid, hi);        }        public static bool less(IComparable v, IComparable w)        {            return v.CompareTo(w) < 0;        }        public static void exch(IComparable[] a, int i, int j)        {            IComparable temp = a[i];            a[i] = a[j];            a[j] = temp;        }        public static void show(IComparable[] a)        {             int N=a.Length;            for (int i = 0; i < N; i++)                Console.WriteLine(a[i]);        }        private static void merge(IComparable[] a, int lo, int mid, int hi)        {            int i = lo, j = mid + 1;            for (int k = lo; k <= hi; k++)                aux[k] = a[k];            for (int k = lo; k <= hi; k++)            {                if (i > mid)                       a[k] = aux[j++];                else if (j > hi)                   a[k] = aux[i++];                else if (less(aux[j], aux[i]))     a[k] = aux[j++];                else                               a[k] = aux[i++];            }        }        public static void test(int size)        {            DateTime startDate = DateTime.Now;            Data[] data = new Data[size];            Random rd = new Random();            for (int i = 0; i < size; i++)            {                data[i] = new Data { value = rd.Next(10000000) };            }            Console.WriteLine("After sort:");            Merge.sort(data);            DateTime endDate = DateTime.Now;            double time = (endDate.Hour - startDate.Hour) * 3600 * 1000 + (endDate.Minute - startDate.Minute) * 60 * 1000 + (endDate.Second - startDate.Second) * 1000 + (endDate.Millisecond - startDate.Millisecond);            if (time > 1000) time /= 1000;            Console.WriteLine("time:" + time);        }        public static void Main(string[] args)        {            test(1000);        }    }

 

自底向上的归并排序:

public static void sort(IComparable[] a)        {            int N = a.Length;            aux = new IComparable[N];            for(int sz=1;sz

用自顶向下或者自底向上实现分治类算法都很自然。归并排序算法的实现说明,当能够用一种方式解决一个问题时,也应该试试另一种方法。其中自底向上的方式适合于组织链表结构,能够将链表原地排序。

 

实际上,我目前对归并算法理解的并不深,但是其代码精炼程度和执行速度很让我惊叹。我将它和希尔排序及.NET封装的Array.Sort()进行对比试验后,发现归并排序速度和原生API速度最接近,排序10000000个随机数只需要15.672s,希尔排序需要53.937s,原生方法需要15.062s.如果大家能有讲得好的相关文章,欢迎推荐给我,不胜感激ing。

转载地址:http://uyutx.baihongyu.com/

你可能感兴趣的文章
redis 五种数据类型的使用场景
查看>>
Google云端数据库:Google Cloud SQL
查看>>
RecyclerView 梳理:点击&长按事件、分割线、拖曳排序、滑动删除
查看>>
数据中心的自动运维之路
查看>>
我刚开始认识的python!
查看>>
Maven - Eclipse使用SVN(subclipse)同步Maven项目的小技巧
查看>>
驰骋工作流引擎表单设计控件-关系类控件-明细表(2)
查看>>
怎样将io.ReadCloser转换成string
查看>>
Oracle中的Rank()函数(注明:本文是我对两篇博文进行整合而来的,下面有相关的链接)...
查看>>
iOS RSA加密 以及生成公钥 秘钥 pem文件
查看>>
SRS配置HLS分发
查看>>
redis-哨兵模式
查看>>
spring注入为null的问题
查看>>
破解网页禁用鼠标右键方法
查看>>
[leetcode] 3Sum Closest
查看>>
Android微信扫描二维码登入实现 基于ZXing开源工程
查看>>
tvOS游戏开发系列(SpriteKit)之新建tvOS游戏项目(二)
查看>>
golang 扫雷
查看>>
shell指令总结
查看>>
Dell XPS 15 9560 Linux mint
查看>>