4.比较排序之归并排序(递归)

  归并排序里运用到算法里很重要的一个思想——分治法:将原问题分解为几个规模较小但类似于原问题的子问题——《算法导论》。在每一层递归中都有3个步骤:

  1.分解问题
  2.解决问题
  3.合并问题的解
  举例待排序数组:{6, 5, 3, 1, 7, 2, 4},将它原始序列做分解。

  可以经过不断的递归分解可以看到已经把原始数组序列不断分解为最小单位,接下来不妨将它们看做是二叉树的叶子节点。

    

  将他们进行两两归并排序形成二叉树(也称为2路归并算法),可见二叉树的根节点即为最终序列。在这个过程中我们完成了剩余的两个步骤:解决问题和合并问题。

  理论很简单,实践很“复杂”。对于归并排序的理论从上面的二叉树就看的很明白,将原始待排序数组不断分解最后看成是二叉树的叶子节点,再把它们两两排形成新的节点,逐渐归并为一个节点,此时的节点即为排好序的数组序列。

  Java

 1 package com.algorithm.sort.merge;
 2
 3 import java.util.Arrays;
 4
 5 /**
 6  * 归并排序(递归)
 7  * Created by yulinfeng on 2017/6/23.
 8  */
 9 public class Merge {
10     public static void main(String[] args) {
11         int[] nums = {6, 5, 3, 1, 7, 2, 4};
12         nums = mergeSort(nums);
13         System.out.println(Arrays.toString(nums));
14     }
15
16     /**
17      * 归并排序
18      * @param nums 待排序数组序列
19      * @return 排好序的数组序列
20      */
21     private static int[] mergeSort(int[] nums) {
22         segment(nums, 0, nums.length - 1);
23         return nums;
24     }
25
26     /**
27      * 递归切分待排
28      * @param nums 待切分数组
29      * @param left 待切分最后第一个元素的索引
30      * @param right 待切分数组最后一个元素的索引
31      */
32     private static void segment(int[] nums, int left, int right) {
33         if (left >= right)
34             return;
35         // 找出中间索引
36         int center = (left + right) / 2;
37         // 对左边数组进行递归
38         segment(nums, left, center);
39         // 对右边数组进行递归
40         segment(nums, center + 1, right);
41         // 合并
42         merge(nums, left, center, right);
43     }
44
45     /**
46      * 两两归并排好序的数组(2路归并)
47      * @param nums 带排序数组对象
48      * @param left 左边数组的第一个索引
49      * @param center 左数组的最后一个索引,center + 1右数组的第一个索引
50      * @param right 右数组的最后一个索引
51      */
52     private static void merge(int[] nums, int left, int center, int right) {
53         int[] tmpArray = new int[nums.length];
54         int rightIndex = center + 1;   // 右数组第一个元素索引
55         int tmpIndex = left;    //临时数组索引
56         int begin = left;   // 缓存左数组第一个元素的索引,用于将排好序的数组拷贝回原数组
57         while (left <= center && rightIndex <= right) {
58             if (nums[left] <= nums[rightIndex]) {
59                 tmpArray[tmpIndex++] = nums[left++];
60             } else {
61                 tmpArray[tmpIndex++] = nums[rightIndex++];
62             }
63         }
64         while (left <= center) {
65             tmpArray[tmpIndex++] = nums[left++];
66         }
67         while (rightIndex <= right) {
68             tmpArray[tmpIndex++] = nums[rightIndex++];
69         }
70         while (begin <= right) {
71             nums[begin] = tmpArray[begin++];
72         }
73     }
74 }

  Python3

 1 #二路归并排序(递归)
 2 def merge_sort(nums):
 3     segment(nums, 0, len(nums) - 1)
 4     return nums
 5
 6 #切分待排序数组
 7 def segment(nums, left, right):
 8     if left >= right:
 9         return
10     center = int((left + right) / 2)
11     segment(nums, left, center)
12     segment(nums, center + 1, right)
13     merge(nums, left, center, right)
14
15 #两两归并排好序的数组(二路归并)
16 def merge(nums, left, center, right):
17     tmpArray = [0] * len(nums)
18     rightIndex = center + 1     #右数组的第一个元素索引
19     tmpIndex = left
20     begin = left
21     while left <= center and rightIndex <= right:
22         if nums[left] <= nums[rightIndex]:
23             tmpArray[tmpIndex] = nums[left]
24             tmpIndex += 1
25             left += 1
26         else:
27             tmpArray[tmpIndex] = nums[rightIndex]
28             tmpIndex += 1
29             rightIndex += 1
30     while left <= center:
31         tmpArray[tmpIndex] = nums[left]
32         tmpIndex += 1
33         left += 1
34     while rightIndex <= right:
35         tmpArray[tmpIndex] = nums[rightIndex]
36         tmpIndex += 1
37         rightIndex += 1
38     while begin <= right:
39         nums[begin] = tmpArray[begin]
40         begin += 1
41
42 nums = [6, 5, 3, 1, 7, 2, 4]
43 nums = merge_sort(nums)
44 print(nums)
时间: 2024-10-09 21:40:33

4.比较排序之归并排序(递归)的相关文章

“《算法》第4版第2章‘排序’”:归并排序

归并排序(Merge Sort,台湾译作:合并排序)是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用. 归并操作(Merge),也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作.归并排序算法依赖归并操作.归并排序有多路归并排序.两路归并排序 , 可用于内排序,也可以用于外排序.这里仅对内排序的两路归并方法进行讨论. 归并排序的步骤如下: 1)Divide: 将待排序序列(原问题)分成两个规模大致相等的子序列(子问题

排序(6)---------归并排序(C语言实现)

归并排序: 归并操作,也叫归并算法,指的是将两个已经排序的序列合并成一个序列的操作.归并排序算法依赖归并操作. 归并操作的过程如下: (1) 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列 (2) 设定两个指针,最初位置分别为两个已经排序序列的起始位置 (3) 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置 (4) 重复步骤3直到某一指针到达序列尾 (5) 将另一序列剩下的所有元素直接复制(抄)到合并序列尾 简单的说,就是将一个序列不断的进行

排序算法——归并排序

归并排序是分治法的典型举例. 分治法的思想是,将原有问题分解为几个规模较小但类似于原问题的子问题,递归的求解这些子问题,然后再合并这些子问题的解来建立原问题的解. 分治模式在每层递归时都有三个步骤: 分解原问题为若干子问题,这些子问题是原问题的规模较小的实例. 解决这些子问题,递归地求解各子问题.然而,若子问题的规模足够小,则直接求解. 合并这些子问题的解成原问题的解. 归并排序算法完全遵循分治模式.直观上其操作如下: 分解:分解待排序的n个元素的序列成各具n/2个元素的两个子序列. 解决:使用

处理海量数据的三大排序之——归并排序(C++)

代码实现                                                                                                                                                                                   #include "stdafx.h" #include <iostream> #include <cti

三种排序算法(归并排序、快速排序,堆排序)

归并排序:建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得到完全有序的序列:即先使每个子序列有序,再使子序列段间有序.若将两个有序表合并成一个有序表,称为二路归并. 归并排序算法稳定,数组需要O(n)的额外空间,链表需要O(log(n))的额外空间,时间复杂度为O(nlog(n)),算法不是自适应的,不需要对数据的随机读取. 工作原理: 1.申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后

归并排序递归实现

1 /* 2 * 归并排序递归实现 3 * 简介:将两个(或两个以上)有序表合并成一个新的有序表 即把待排序序列分为若干个子序列,每个子序列是有序的. 4 * 然后再把有序子序列合并为整体有序序列 5 * 时间复杂度为O(nlogn) 6 * 7 * */ 8 9 import java.util.Arrays; 10 11 public class MegerSort { 12 public int[] sort(int[] k,int low,int high) 13 { 14 int ce

在路上---学习篇(一)Python 数据结构和算法 (4) --希尔排序、归并排序

独白: 希尔排序是经过优化的插入排序算法,之前所学的排序在空间上都是使用列表本身.而归并排序是利用增加新的空间,来换取时间复杂度的减少.这俩者理念完全不一样,注定造成的所消耗的时间不同以及空间上的不同. 归并排序涉及到递归的使用,需要理解其中精髓才能更好了解归并排序,以及其他应用到递归的算法.理解其本质才能更好的应用. 希尔排序 希尔排序(Shell Sort)是插入排序的一种.也称缩小增量排序,是直接插入排序算法的一种更高效的改进版本.希尔排序是非稳定排序算法.该方法因DL.Shell于195

八大排序之归并排序

一.基本思想 归并排序,将当前序列分成若干个小的有序序列,然后逐个合并成更大的有序序列.这里所谓的若干个小的有序序列即是将序列分割成n个长度为1的序列,然后两两合并成长度为二的有序序列.然后在将这长度为二的有序序列合并为长度为四的有序序列.依次类推,最终达到原序列长度,这样,排序就完成了.这其实是归并排序递归回溯过程的描述.归并排序的正序描述可以是这样,将序列分成两个子序列,对两个子序列进行归并排序,然后将两个子序列合并到原序列中. 二.实现步骤 归并排序,有两个需要解决的问题:一.如何划分子区

经典排序算法 - 归并排序Merge sort

经典排序算法 - 归并排序Merge sort 原理,把原始数组分成若干子数组,对每个子数组进行排序, 继续把子数组与子数组合并,合并后仍然有序,直到所有合并完,形成有序的数组 举例 无序数组[6 2 4 1 5 9] 先看一下每一个步骤下的状态,完了再看合并细节 第一步 [6 2 4 1 5 9]原始状态 第二步 [2 6] [1 4] [5 9]两两合并排序,排序细节后边介绍 第三步 [1 2 4 6] [5 9]继续两组两组合并 第四步 [1 2 4 5 6 9]合并完成,排序完成 输出结

单链表的排序 快速排序 归并排序 quicksort mergesort

原理都很简单,关键是某些边界能否正确写对: #include<iostream> #include<stdio.h> using namespace std; class Node { public: int val; Node* next; Node(int val = 0):val(val),next(NULL){ } }; Node* quicksort(Node* head, Node* tail) { Node *res1 = NULL, *res2 = NULL; No