算法导论Java实现-合并排序(包含习题2.3-2)

简介:
 
  1. package lhz.algorithm.chapter.two; 
  2.  
  3. /** 
  4.  * 《合并排序》,利用分治思想进行排序。(针对习题2.3-2) 
  5.  * 《算法导论》原文摘要: 
  6.  * The  merge sort algorithm closely follows the divide -and-conquer paradigm . Intuitively, it  
  7.  *  operates as follows.  
  8.  * •   Divide: Divide the  n-element sequence to be sorted into two subsequences of  n/2  
  9.  *     elements each.  
  10.  * •   Conquer: Sort the two subsequences recursively using merge sort.  
  11.  * •   Combine: Merge the two sorted subsequences to produce the sorted answer.  
  12.  * The recursion "bottoms out" when the sequence to be sorted has length 1,  in which case there  
  13.  * is no work to be done, since every sequence  of length 1 is already in sorted order.  
  14.  * The key operation of the merge sort algorithm is  the merging of two sorted sequences in the  
  15.  * "combine" step. To perform the merging,  we use an auxiliary procedure MERGE( A,  p,  q,  r ),  
  16.  * where A is an array and  p,  q, and r  are indices numbering elements of the array such that  p ≤  q <  r . The procedure assumes that the subarrays  A[p  q] and A[q + 1   r ] are in sorted order.  
  17.  * It  merges  them to form a single sorted subarray that replaces the current subarray  A[p  r].  
  18.  *  
  19.  * Our MERGE procedure takes time Θ ( n), where n = r - p + 1 is the number of 
  20.  * elements being merged, and it works as follows. Returning to our card-playing 
  21.  * motif , suppose we have two piles of cards face up on a table. Each pile is 
  22.  * sorted, with the smallest cards on top. We wish to merge the two piles into a 
  23.  * single sorted output pile, which is to be face down on the table. Our basic 
  24.  * step consists of choosing the smaller of the two cards on top of the face-up 
  25.  * piles, removing it from its pile (which exposes a new top card), and placing 
  26.  * this card face down onto the output pile. We repeat this step until one input 
  27.  * pile is empty, at which time we just take the remaining input pile and place 
  28.  * it f ace down onto the output pile. Computationally, each basic step takes 
  29.  * constant time, since we are checking just two top cards. Since we perform at 
  30.  * most n basic steps, merging takes Θ( n) time. 
  31.  *  
  32.  * 伪代码: 
  33.  *  MERGE(A, p, q, r)  
  34.  *1  n1  ← q -  p + 1  
  35.  *2  n2  ← r -  q  
  36.  *3  create arrays  L[1   n1  + 1] and  R[1   n2  + 1]  
  37.  *4  for  i ← 1  to n1   
  38.  *5       do L[i] ← A[p +  i - 1]  
  39.  *6  for  j ← 1  to n2   
  40.  *7       do R[j] ← A[q +  j]  
  41.  *8  L[n1  + 1] ← ∞ (∞代表到达最大值,哨兵位) 
  42.  *9  R[n2  + 1] ← ∞  
  43.  *10  i ← 1  
  44.  *11  j ← 1  
  45.  *12  for  k ← p to r  
  46.  *13       do if  L[i] ≤ R[j]  
  47.  *14              then A[k] ← L[i]  
  48.  *15                   i ← i + 1  
  49.  *16              else A[k] ← R[j]  
  50.  *17                   j ← j + 1  
  51.  *@author lihzh(苦逼coder)
  52.  * 本文地址:http://mushiqianmeng.blog.51cto.com/3970029/730242
  53.  */ 
  54. public class MergeSort { 
  55.      
  56.     private static int[] input = new int[] { 21549867103 }; 
  57.  
  58.     /** 
  59.      * @param args 
  60.      */ 
  61.     public static void main(String[] args) { 
  62.         mergeSort(input); 
  63.         //打印数组 
  64.         printArray(); 
  65.     } 
  66.      
  67.     /** 
  68.      * 针对习题2.3-2改写,与伪代码不对应 
  69.      * @param array 
  70.      * @return 
  71.      */ 
  72.     private static int[] mergeSort(int[] array) { 
  73.         //如果数组的长度大于1,继续分解数组 
  74.         if (array.length > 1) { 
  75.             int leftLength = array.length / 2
  76.             int rightLength = array.length - leftLength; 
  77.             //创建两个新的数组 
  78.             int[] left = new int[leftLength]; 
  79.             int[] right = new int[rightLength]; 
  80.             //将array中的值分别对应复制到两个子数组中 
  81.             for (int i=0; i<leftLength; i++) { 
  82.                 left[i] = array[i]; 
  83.             } 
  84.             for (int i=0; i<rightLength; i++) { 
  85.                 right[i] = array[leftLength+i]; 
  86.             } 
  87.             //递归利用合并排序,排序子数组 
  88.             left = mergeSort(left); 
  89.             right = mergeSort(right); 
  90.             //设置初始索引 
  91.             int i = 0
  92.             int j = 0
  93.             for (int k=0; k<array.length; k++) { 
  94.                 //如果左边数据索引到达边界则取右边的值 
  95.                 if (i == leftLength && j < rightLength) { 
  96.                     array[k] = right[j]; 
  97.                     j++; 
  98.                 //如果右边数组索引到达边界,取左数组的值 
  99.                 } else if (i < leftLength && j == rightLength) { 
  100.                     array[k] = left[i]; 
  101.                     i++; 
  102.                 //如果均为到达则取,较小的值 
  103.                 } else if (i < leftLength && j < rightLength) { 
  104.                     if (left[i] > right[j]) { 
  105.                         array[k] = right[j]; 
  106.                         j++; 
  107.                     } else { 
  108.                         array[k] = left[i]; 
  109.                         i++; 
  110.                     } 
  111.                 }  
  112.             } 
  113.         }  
  114.         return array; 
  115.         /* 
  116.          * 复杂度分析: 
  117.          * 由于采用了递归,设解决长度为n的数组需要的时间为T(n),则分解成两个长度为n/2的子 
  118.          * 数组后,需要的时间为T(n/2),合并需要时间Θ(n)。所以有当n>1时,T(n)=2T(n/2)+Θ(n), 
  119.          * 当n=1时,T(1)=Θ(1) 
  120.          * 解这个递归式,设Θ(1)=c,(c为常量),则Θ(n)=cn。 
  121.          * 有上式可得T(n/2)=2T(n/4)+Θ(n/2),T(n/4)=2T(n/8)+Θ(n/4)....依次带入可得 
  122.          * 所以可以有T(n)=nT(1)+Θ(n)+2Θ(n/2)+4Θ(n/4)...+(2^lgn)Θ(n/(2^lgn)),其中共有lgn个Θ(n)相加。 
  123.          * 即T(n)=cn+cnlgn 
  124.          * 所以,时间复杂度为:Θ(nlgn) 
  125.          */ 
  126.     } 
  127.      
  128.     private static void printArray() { 
  129.         for (int i : input) { 
  130.             System.out.print(i + " "); 
  131.         } 
  132.     } 

 

     本文转自mushiqianmeng 51CTO博客,原文链接:http://blog.51cto.com/mushiqianmeng/730242,如需转载请自行联系原作者






相关文章
|
6天前
|
存储 算法 安全
探究‘公司禁用 U 盘’背后的哈希表算法与 Java 实现
在数字化办公时代,信息安全至关重要。许多公司采取“禁用U盘”策略,利用哈希表算法高效管理外接设备的接入权限。哈希表通过哈希函数将设备标识映射到数组索引,快速判断U盘是否授权。例如,公司预先将允许的U盘标识存入哈希表,新设备接入时迅速验证,未授权则禁止传输并报警。这有效防止恶意软件和数据泄露,保障企业信息安全。 代码示例展示了如何用Java实现简单的哈希表,模拟公司U盘管控场景。哈希表不仅用于设备管理,还在文件索引、用户权限等多方面助力信息安全防线的构建,为企业数字化进程保驾护航。
|
14天前
|
监控 算法 网络协议
Java 实现局域网电脑屏幕监控算法揭秘
在数字化办公环境中,局域网电脑屏幕监控至关重要。本文介绍用Java实现这一功能的算法,涵盖图像采集、数据传输和监控端显示三个关键环节。通过Java的AWT/Swing库和Robot类抓取屏幕图像,使用Socket进行TCP/IP通信传输图像数据,并利用ImageIO类在监控端展示图像。整个过程确保高效、实时和准确,为提升数字化管理提供了技术基础。
50 15
|
3月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
109 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
6天前
|
运维 监控 算法
企业局域网监控软件中 Java 优先队列算法的核心优势
企业局域网监控软件是数字化时代企业网络安全与高效运营的基石,犹如一位洞察秋毫的卫士。通过Java实现的优先队列算法,它能依据事件优先级排序,确保关键网络事件如异常流量、数据泄露等被优先处理,保障系统稳定与安全。代码示例展示了如何定义网络事件类并使用PriorityQueue处理高优先级事件,尤其在面对疑似风险时迅速启动应急措施。这一核心技术助力企业在复杂网络环境中稳健前行,护航业务腾飞。
50 32
|
5天前
|
Java 程序员
Java 排序神器:Comparable 和 Comparator 该怎么选?
嗨,大家好,我是小米!今天和大家聊一聊Java社招面试中常考的经典问题——Comparable和Comparator的区别。Comparable定义对象的自然排序,适用于单一固定的排序规则;Comparator则是策略接口,用于定义自定义排序规则,适用于多样化或多变的排序需求。掌握这两者的区别是理解Java排序机制的基础,也是面试中的加分题。结合实际项目场景深入探讨它们的应用,能更好地打动面试官。如果你觉得有帮助,欢迎点赞、收藏、分享,期待你的一键三连!我们下期见~ 我是小米,一个喜欢分享技术的程序员,关注我的微信公众号“软件求生”,获取更多技术干货!
37 20
|
5天前
|
存储 监控 算法
探秘局域网桌面监控:深入剖析 Java 语言核心算法
在数字化办公时代,局域网桌面监控如同企业的“智慧鹰眼”,确保工作效率与数据安全。本文以Java为载体,揭示哈希表在监控中的关键应用。通过高效的数据结构和算法,哈希表能快速索引设备连接信息,大幅提升监控的时效性和响应速度。代码示例展示了如何用Java实现设备网络连接监控,结合未来技术如AI、大数据,展望更智能的监控体系,助力企业在数字化浪潮中稳健前行。
|
5天前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
24 2
|
20天前
|
缓存 算法 搜索推荐
Java中的算法优化与复杂度分析
在Java开发中,理解和优化算法的时间复杂度和空间复杂度是提升程序性能的关键。通过合理选择数据结构、避免重复计算、应用分治法等策略,可以显著提高算法效率。在实际开发中,应该根据具体需求和场景,选择合适的优化方法,从而编写出高效、可靠的代码。
29 6
|
2月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(下)(c语言实现)(附源码)
本文继续学习并实现了八大排序算法中的后四种:堆排序、快速排序、归并排序和计数排序。详细介绍了每种排序算法的原理、步骤和代码实现,并通过测试数据展示了它们的性能表现。堆排序利用堆的特性进行排序,快速排序通过递归和多种划分方法实现高效排序,归并排序通过分治法将问题分解后再合并,计数排序则通过统计每个元素的出现次数实现非比较排序。最后,文章还对比了这些排序算法在处理一百万个整形数据时的运行时间,帮助读者了解不同算法的优劣。
163 7
|
2月前
|
搜索推荐 算法 C语言
【排序算法】八大排序(上)(c语言实现)(附源码)
本文介绍了四种常见的排序算法:冒泡排序、选择排序、插入排序和希尔排序。通过具体的代码实现和测试数据,详细解释了每种算法的工作原理和性能特点。冒泡排序通过不断交换相邻元素来排序,选择排序通过选择最小元素进行交换,插入排序通过逐步插入元素到已排序部分,而希尔排序则是插入排序的改进版,通过预排序使数据更接近有序,从而提高效率。文章最后总结了这四种算法的空间和时间复杂度,以及它们的稳定性。
135 8