归并排序

排序|归并排序

Deadly 提交于 2020-11-28 04:11:59
归并( Merge )排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列。 归并 :将两个已经排好序的集合合并到一个集合众,并且 保证新的集合也是有序的 。 核心点 :只有一个元素的集合是已经排好序的集合。归并排序是建立在归并操作上的一种有效的排序算法。归并排序算法是采用分治法( Divide And Conquer )的一个非常典型的应用。 归并排序流程: 1.对任意的元素数目为m集合,可以分成m个只有一个元素的子集合。 2.对其m个元素只有一个的集合实现归并操作,可以得到[m/2]个新的子集合([ 如果m不是偶数 ],细节问题,多出的单独保留,即存有[m/2 + 1]个集合),关键的是这些新的集合也是有序的。 3.重复2的操作,直至最后只有一个集合。 由于各子集合始终保持有序,最终的集合也是有序的,也就得到了排序后的集合,算法目的实现。 在这里,我们不是用递归来实现。按照思想,归并排序的实现代码如下: //归并排序 public static void MergeSort(int[] array) { //以空间换取时间 int[] temp = new int[array.Length]; //size子数组的长度 //默认为1个元素的子集合(即铁定已排好序的集合) int size

排序-归并排序

倖福魔咒の 提交于 2020-11-28 03:40:21
零、数据结构和算法系列目录 数据结构和算法系列目录(不断更新): http://my.oschina.net/liuzeli/blog/128278 一、归并排序简介 归并排序和插入排序一样,其核心是基于比较的,所以也是比较排序中的一种。归并排序运用的分治算法的思想。在介绍归并排序的同时也简单的介绍一下分治算法,这种算法的核心讲解会在后续的博客中介绍。回国头来继续说归并排序。归并排序有着很好的应用场景,它适合给大规模的数据排序,当数据量非常大时,内存排序困难可以对归并排序稍加改动让其支持分批从硬盘读取数据并进行排序,最后把结果进行合并。归并排序(二路归并)的主要思路就是假设两个数组A和数组B分别已经是排序好的,再对这两个数组A和B进行合并成为一个新的排序好的数组。这一步是归并排序的核心步骤,如果对于这个待排序数组来说,开始先对数组两个两个元素进行排序,在对其合并变成4个元素为一组,在变成8个元素为一组,从而到最后完成所有数据的排序。 二、分治算法的简介 分治算法的主要核心是分而治之的思想,即把原文题进行分解,分解成若干的子问题,在对子问题进行求解,在对所有子问题的答案进行合并从而得到原问题的结果。可以表示成下面叙述的过程。 1. 分解:将原问题分解成若干个规模较小且相对独立的的与原问题形式相同的子问题。 2. 求解:若子问题规模较小并且容易解决时将对其进行求解,否则递归的解决子问题

归并排序

浪尽此生 提交于 2020-04-05 15:00:18
https://www.bilibili.com/video/BV1Zt411o7Rn?p= 25 参考:这个视频借鉴的归并写法 主要逻辑在对排好后的两个数组进行归并逻辑,就是有一个指向第一个数组的指针i和指向第二个数组的指针j 进行比较并将小的结果放进临时数组,直到一方遍历完成为止,然后再把没有遍历完的数组以此进入数组即可 private static void mergeSort(int[] arr,int start,int end){ if(start >= end){ return; } int mid = (start + end) / 2; mergeSort(arr,start,mid); mergeSort(arr,mid + 1,end); merge(arr,start,mid,end); } private static void merge(int[] arr,int start,int mid,int end){ int[] temp = new int[end - start + 1]; int i = start;// 记录第一个数组的下标 int j = mid + 1;// 记录第二个数组的下标 int index = 0;// 记录第新数组的下标 while (i <= mid && j <= end){ if(arr[i] < arr[j])

原地归并算法

独自空忆成欢 提交于 2020-04-04 05:16:15
归并排序算法(mergesort)是将一个序列划分为同样大小的两个子序列,然后对两个子序列分别进行排序,最后进行合并操作,将两个子序列合成有序的序列.在合成的过程中,一般的实现都需要开辟一块与原序列大小相同的空间,以进行合并操作。这儿有比较全的排序算法: http://www.cnblogs.com/xkfz007/archive/2012/07/01/2572017.html 之前使用过的归并排序,都是需要重新开辟新空间的。一般需要开辟的空间为n(数组大小),所以空间复杂度是O(n). 其实可以对于归并可以不需要开辟新的空间就可以直接进行归并的方法,即原地归并。 其主要思想就是,因为需要归并的部分是有序的,所以需要找到两个序列中第二个序列小于第一个序列的部分,比如对序列[<1, 3, 5, 7>, <2, 4, 6, 8>]进行归并操作。2就是第二个序列中小于第一个序列中的<3,5,7>部分,需要调节<3,5,7>,与2的位置。然后不断的进行扫描。其中进行调整的时候,用到的是对序列的循环移动,循环左移或循环右移。这样就不需要新的空间了。 C++代码如下: void rotate_right(int *v,int sz,int n){ reverse(v,v+sz); reverse(v,v+n); reverse(v+n,v+sz); } void merge(int *v

排序之归并排序

六眼飞鱼酱① 提交于 2020-04-03 05:01:16
阐述: 归并排序是将两个有序表合并成新的有序表; 而子序列的划分是递归地将待排序集合折半划分多个子序列,类似一个二叉树, 另外上面的递归操作大多会涉及分治思想,通俗讲就是各个分支上的子序列的有序,为最大的序列的有序埋下基础。 所以需要lgN趟的二路合并(假设集合的规模是N),每趟合并的复杂度是O(N),故其时间复杂度无论是在最好情况下还是在最坏情况下均是O(N*lgN)。 归并排序在划分子序列,二路合并有序集合时并没有改变两个相同元素的相对位置,故而是稳定的。 但是,归并排序需要额外的临时存储空间来暂存归并好的结果,所以空间复杂度是O(N)。 归并排序的关键字是:有序集合的合并;子序列的划分方式(如二路归并是通过递归地折半划分) 效果图: 大家可以看到处理每一趟归并的走位,就像我们遍历二叉树的顺序。 代码(c#): /// <summary> /// 归并排序入口 /// </summary> public static void DoMergeSort_Entrance() { List<int> listNum = new List<int>() { 25, 19, 6, 58, 34, 10, 7, 98, 160, 0 }; DoMergeSort_Sort(listNum, 0, listNum.Count - 1); } /// <summary> /// 归并排序,

递归归并排序 二路归并排序

五迷三道 提交于 2020-03-31 15:34:53
归并算法的两种方法: 1、使用分治法的递归归并算法: /*递归归并排序 *将有二个有序数列list[first...mid]和list[mid+1,...last]合并 *list:待排序数组 *first:子序列1的下界 *mid:子序列1的上界 *last:子序列2的上界 *temp:临时保存数组 */ void Merge(element list[], int first, int mid, int last, element temp[]) { int i = first, j = mid + 1; int m = mid, n = last; int k = 0; while (i <= m && j <= n) { if (list[i] < list[j]) temp[k++] = list[i++]; else temp[k++] = list[j++]; } while (i <= m) temp[k++] = list[i++]; while (j <= n) temp[k++] = list[j++]; for (i = 0; i < k; i++) list[first + i] = temp[i]; return ; } /*递归归并排序 *分治,完成递归归并 *list:待排序数组 *first:list下界 *last:list上界 *temp

归并排序

风流意气都作罢 提交于 2020-03-28 08:18:18
问题描述: 通过归并排序,从小到大排序一个数组。 算法实现: 相关变量初始化:    int num = 8; int[] arr = new int[num]; int[] temp = new int[num];算法调用: mergeSort(arr, 0, arr.length - 1, temp);主要方法: public void mergeSort(int[] arr, int lo, int hi, int[] temp) { if(lo >= hi) return; int mid = lo + (hi - lo) / 2; mergeSort(arr, lo, mid, temp); mergeSort(arr, mid + 1, hi, temp); merge(arr, lo, mid, hi, temp);}private void merge(int[] arr, int lo, int mid, int hi, int[] temp) { int i = lo; int j = mid + 1; for(int k = lo; k <= hi; k++) { temp[k] = arr[k]; } for(int k = lo; k <= hi; k++) { if(i > mid) arr[k] = temp[j++]; else if(j > hi)

归并排序基本原理及实现

陌路散爱 提交于 2020-03-28 04:29:09
一、归并(Merge) 1. 概念 将两个 有序数列 合并成一个有序数列,我们称之为 “归并”。 2. 算法思路及实现 设两个有序的子序列(相当于输入序列)放在同一序列中相邻的位置上:array[low..m],array[m + 1..high],先将它们合并到一个局部的暂存序列 temp (相当于输出序列)中,待合并完成后将 temp 复制回 array[low..high]中,从而完成排序。 在具体的合并过程中,设置 i,j 和 p 三个指针,其初值分别指向这三个记录区的起始位置。合并时依次比较 array[i] 和 array[j] 的关键字,取关键字较小(或较大)的记录复制到 temp[p] 中,然后将被复制记录的指针 i 或 j 加 1,以及指向复制位置的指针 p 加 1。重复这一过程直至两个输入的子序列有一个已全部复制完毕(不妨称其为空),此时将另一非空的子序列中剩余记录依次复制到 array 中即可。 c语言实现如下: void merge(int* array, int low, int mid, int high) { assert(array && low >= 0 && low <= mid && mid <= high); int* temp = (int*)malloc((high - low + 1) * sizeof(int)); if (!temp

MergeSort,归并排序

假装没事ソ 提交于 2020-03-26 16:06:50
package _Sort.Algorithm /** * https://www.geeksforgeeks.org/merge-sort/ * https://www.cnblogs.com/chengxiao/p/6194356.html * best/worst/average Time complexity are O(nlogn), Space complexity is O(n), stable * # is Divide and Conquer algorithm * Basic idea * 1. find the middle point to divide the array into two halves; * 2. Call MergeSort for first halves; * 3. Call MergeSort for second halves; * 4. Merge two halves; * */ class MergeSort { fun sortArray(array: IntArray): IntArray { //create temp array first, avoid create temp in recursion val tempArray = IntArray(array.size) val left = 0 val

瑞士轮(归并排序)

早过忘川 提交于 2020-03-26 06:20:33
瑞士轮 时间限制: 1 Sec 内存限制: 128 MB 题目描述 在双人对决的竞技性比赛,如乒乓球、羽毛球、国际象棋中,最常见的赛制是淘汰赛和循环赛。前者的特点是比赛场数少,每场都紧张刺激,但偶然性较高。后者的特点是较为公平,偶然性较低,但比赛过程往往十分冗长。 本题中介绍的瑞士轮赛制,因最早使用于1895年在瑞士举办的国际象棋比赛而得名。它可以看作是淘汰赛与循环赛的折衷,既保证了比赛的稳定性,又能使赛程不至于过长。 2*N名编号为1~2N的选手共进行R轮比赛。每轮比赛开始前,以及所有比赛结束后,都会对选手进行一次排名。排名的依据是选手的总分。选手的总分为第一轮开始前的初始分数加上已参加过的所有比赛的得分和。总分相同的,约定编号较小的选手排名靠前。 每轮比赛的对阵安排与该轮比赛开始前的排名有关:第1名和第2名、第3名和第4名、……、第2K – 1名和第2K名、…… 、第2N – 1名和第2N名,各进行一场比赛。每场比赛胜者得1分,负者得0分。也就是说除了首轮以外,其它轮比赛的安排均不能事先确定,而是要取决于选手在之前比赛中的表现。 现给定每个选手的初始分数及其实力值,试计算在R轮比赛过后,排名第Q的选手编号是多少。我们假设选手的实力值两两不同,且每场比赛中实力值较高的总能获胜。 输入 输入的第一行是三个正整数N、R、Q,每两个数之间用一个空格隔开,表示有2*N名选手、R轮比赛