归并排序

C语言归并排序

痴心易碎 提交于 2020-01-22 00:12:09
归并:两两合并排序再合并。涉及三个操作:两两合并、排序、再合并。 该算法是采用分治法的一个非常典型的应用,且各层分治递归可以同时进行。 对于一个无序的长序列,可以分解为很多个有序的子序列,然后依次进行归并。我们把原始长序列依次分解,直到每个子序列都只有一个元素的时候,再依次把所有的序列进行归并排序,直到合并成一个序列。 下面呢,举个例子:{2,6,5,7,4,1,8,3} 1.{2,6,5,7},{4,1,8,3} (将原始序列从中间分为左、右两个子序列) 2.{2,6},{5,7},{4,1},{8,3} (将左序列和右序列再分别从中间分为左、右两个子序列) 3.{2},{6},{5},{7},{4},{1},{8},{3} (重复以上步骤,直到每个子序列都只有一个元素,可认为每一个子序列都是有序的) 以上三步为“分” 接下来,进行两两合并,排序,再合并,再排序 1.{2,6},{5,7},{1,4},{3,8} 2.{2,5,6,7},{1,3,4,8} 3.{1,2,3,4,5,6,7,8} 归并排序完成 归并排序的代码 Merge函数:将一个无序的序列进行分解(分解到每个序列只有1个元素为止) prx函数:排序 void merge ( int a [ ] , int l , int r ) //a数组为序列,l为序列的第一个元素位置,r为最后一个元素位置 { if ( l

leetcode_148. 排序链表

帅比萌擦擦* 提交于 2020-01-21 19:01:33
在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。 示例 1: 输入: 4->2->1->3 输出: 1->2->3->4 示例 2: 输入: -1->5->3->4->0 输出: -1->0->3->4->5 解析:对时间空间复杂度有要求,那么就必须思考用什么方法进行排序 对于时间复杂度O(nlogn) ,可以考虑归并排序或者快速排序 而归并排序在链表的情况下,可以优化为O(1)的空间复杂度。 因此本题采用归并排序 归并排序的要点在于两点,分治的拆分链表,以及合并两个链表 我们分别处理这两个功能,并归纳为函数 对于自顶向下的归并排序,通常采用递归调用,每个递归函数的功能便是找到目前的中心,并对两端进行递归调用,最后合并后返回上一层。 而这样的整个过程,必然会产生函数的递归调用,并因此消耗额外的函数栈空间。不符合题目要求的O(1)空间复杂度要求。 因此我们需要将递归修改为迭代。 我们转变方向,自下而上的进行归并排序。 对自顶向下的一般归并方法进行分析,发现最终的函数调用顺序是: 对1、2两个节点进行归并 对3、4两个节点进行归并 对1-4四个节点进行归并 对5、6两个节点进行归并 对7、8两个节点进行归并 对5-8四个节点进行归并 对1-8八个节点进行归并。。。 可以看出, 整个过程其实是先每两个一组进行合并,然后每四个一组,八个,十六个

P 1035 插入与归并

耗尽温柔 提交于 2020-01-21 15:34:55
转跳点 : 🐏 1035 插入与归并 (25分) 根据维基百科的定义: 插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。 归并排序进行如下迭代操作:首先将原始序列看成 N 个只包含 1 个元素的有序子序列,然后每次迭代归并两个相邻的有序子序列,直到最后只剩下 1 个有序的序列。 现给定原始序列和由某排序算法产生的中间序列,请你判断该算法究竟是哪种排序算法? 输入格式: 输入在第一行给出正整数 N ( ≤100);随后一行给出原始序列的 N 个整数;最后一行给出由某排序算法产生的中间序列。这里假设排序的目标序列是升序。数字间以空格分隔。 输出格式: 首先在第 1 行中输出 Insertion Sort 表示插入排序、或 Merge Sort 表示归并排序;然后在第 2 行中输出用该排序算法再迭代一轮的结果序列。题目保证每组测试的结果是唯一的。数字间以空格分隔,且行首尾不得有多余空格。 输入样例 1: 10 3 1 2 8 7 5 9 4 6 0 1 2 3 7 8 5 9 4 6 0 输出样例 1: Insertion Sort 1 2 3 5 7 8 9 4 6 0 输入样例 2: 10 3 1 2 8 7 5 9 4 0 6 1 3 2 8 5 7 4 9 0 6

2020.1.20每日一题“归并排序”

佐手、 提交于 2020-01-21 04:42:45
归并排序是什么 归并排序顾名思义有一个化归合并的过程,那要合并在这之前就有分离,这就是归并排序的步骤:先将要排序的一串数字劈开,劈到最小有序数列(也就是一个一个的时候,只有一个那肯定有序啊);第二步再将他们逐渐合并,继而变成一个有序数列。 为什么要用归并排序 算法复杂度: 最好情况:O(nlogn) 最坏情况:O(nlogn) 平均情况:O(nlogn) 空间复杂度:O(n) 稳定性:稳定 从以上的数据 可以看出归并排序比普通的排序在复杂度上有了很好的提升。 归并排序的代码实现: 上面这个代码还可用于求逆序数对的个数。 关键就是这段代码: 来源: CSDN 作者: LeBronGod 链接: https://blog.csdn.net/LebronGod/article/details/104055745

归并排序

南笙酒味 提交于 2020-01-20 22:38:19
归并排序 归并排序是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再将子序列合并。若将两个有序表合并成一个有序表,称为二路归并。归并排序是一种稳定的排序方法。 归并算法的时间复杂度为O(n log n) 。 归并的引入 我们可以先以两个有序的序列来先感受一下: a数组:1 2 3 6 b数组:4 5 7 8 我们对这两个序列进行排序合并,可以先定义两个指针i,j,再创建一个数组c,分别指向a,b,然后比较i,j指向的数,哪个小,就存入c数组,然后指针向后移动一位,直到a或b其中一个遍历完,再把剩余的数都存入c数组。 归并的步骤 1,分解:将一段无序数字一直分,直到每组只剩一个数字 2,合并:两两合并,按照小的就存进新数组这个思路 我们引入一张图片直观感受一下 代码 # include <stdio.h> void merge ( int a [ ] , int b [ ] , int star , int mid , int end ) //这里是进行两两合并的排序 { int i = star ; int j = mid + 1 ; int k = star ; while ( i != mid + 1 && j != end + 1 ) { if ( a [ i ] <= a [ j ] ) { b [ k ++ ] = a [

归并排序(C++实现)

扶醉桌前 提交于 2020-01-20 05:05:18
归并排序:是分治算法的典型应用,通过将无序数组分成更小的子数组,利用单个数字总是有序的特性,对子数组进行排序,最后合并。首先把一个数组中的元素,按照某一方法,先拆分了之后,按照一定的顺序各自排列,然后再归并到一起,使得归并后依然是有一定顺序的。类似二叉树结构,时间复杂度O(nlogn),最坏情况O(nlogn),是一种稳定排序方法。主要实现过程示意图如下: #include<iostream> #include<vector> using namespace std; #子数组排序 void merge(vector<int>&A, int left, int mid, int right) { int n1 = mid - left+1; int n2 = right - mid; vector<int>L(n1); vector<int>R(n2); for (int i = 0;i < n1;i++) L[i] = A[left + i]; for (int j = 0;j < n2;j++) R[j] = A[mid + j+1]; int i = 0, j = 0; for (int k = left;k <= right;k++) { if (j >= n2 || (i < n1 && L[i] <= R[j])) { A[k] = L[i++]; } else { A

归并排序

ぐ巨炮叔叔 提交于 2020-01-19 22:38:04
归并排序 1.简单介绍: 采用的叫分治的思想,将数组划分为两个子数组,然后递归将每个子数组再进行划分,直到数组中只剩一下一个元素,然后开始排序合并,直到将所有的子数组合并完成,整个数据就是有序的啦。时间复杂度:NlogN。 2.原理 图解 思路:先将无序序列利用二分法划分为两个子序列,直至每个子序列只有一个元素,一个元素序列必然有序,然后再对有序子序列两两进行合并排序。合并方法是循环的将两个有序子序列当前的首元素进行比较,较小的元素取出,放入合并序列的左边空置位,直至其中一个子序列的最后一个元素放入合并序列中。最后将另一个子序列的剩余元素按顺序逐个放入合并序列尾部。 3.代码: 排序过程: int c[1000],a[1000]; void paixu(int a[1000],int l,int mid,int r) { long long int i=l,j=mid+1,k=0; while(i<=mid&&j<=r) { if(a[i]<=a[j]) c[k++]=a[i++]; else { m+=mid-i+1; c[k++]=a[j++]; } } while(i<=mid) c[k++]=a[i++]; while(j<=r) c[k++]=a[j++]; for(i=l;i<=r;i++) { a[i]=c[i-l]; } } 归并过程 void merge(int

归并排序

北慕城南 提交于 2020-01-19 13:58:48
归并排序 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列 归并排序的过程 1.先将数列分半,直到不可再分。 2.将左右半边比较排序,排的过程中存入一个过渡数组。 3.将过渡数组赋回原数据。 代码实现 void gb ( int s , int t ) //s是初项,t是末项 { int i , j , k , mid ; if ( s < t ) { mid = ( s + t ) / 2 ; gb ( s , mid ) ; gb ( mid + 1 , t ) ; //对半分开 i = s ; j = mid + 1 ; k = s ; while ( i <= mid && j <= t ) //当一个区间没有元素时循环停止 { if ( a [ i ] <= a [ j ] ) { tmp [ k ++ ] = a [ i ++ ] ; } else { tmp [ k ++ ] = a [ j ++ ] ; // sum+=mid-i+1;(如果是求逆序数,加上这一句) } //将更小的值赋给过渡数组 } while ( i <= mid ) tmp [ k ++ ] = a [ i ++ ] ; while ( j <= t ) tmp [ k ++ ] = a [ j ++ ] ; /

归并排序

你说的曾经没有我的故事 提交于 2020-01-19 13:13:28
归并排序 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列 归并排序的过程 1.先将数列分半,直到不可再分。 2.将左右半边比较排序,排的过程中存入一个过渡数组。 3.将过渡数组赋回原数据。 代码实现 void gb ( int s , int t ) //s是初项,t是末项 { int i , j , k , mid ; if ( s < t ) { mid = ( s + t ) / 2 ; gb ( s , mid ) ; gb ( mid + 1 , t ) ; //对半分开 i = s ; j = mid + 1 ; k = s ; while ( i <= mid && j <= t ) //当一个区间没有元素时循环停止 { if ( a [ i ] <= a [ j ] ) { tmp [ k ++ ] = a [ i ++ ] ; } else { tmp [ k ++ ] = a [ j ++ ] ; // sum+=mid-i+1;(如果是求逆序数,加上这一句) } //将更小的值赋给过渡数组 } while ( i <= mid ) tmp [ k ++ ] = a [ i ++ ] ; while ( j <= t ) tmp [ k ++ ] = a [ j ++ ] ; /

[图解] 归并排序

廉价感情. 提交于 2020-01-18 05:19:12
[图解] 归并排序 1. 图示过程 (1) 归并排序的流程 (2) 合并两个有序数组的流程 2. 动图展示 3. Java代码实现 public static void mergeSort(int[] arr) { sort(arr, 0, arr.length - 1); } public static void sort(int[] arr, int L, int R) { if(L == R) { return; } int mid = L + ((R - L) >> 1); sort(arr, L, mid); sort(arr, mid + 1, R); merge(arr, L, mid, R); } public static void merge(int[] arr, int L, int mid, int R) { int[] temp = new int[R - L + 1]; int i = 0; int p1 = L; int p2 = mid + 1; // 比较左右两部分的元素,哪个小,把那个元素填入temp中 while(p1 <= mid && p2 <= R) { temp[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++]; } // 上面的循环退出后,把剩余的元素依次填入到temp中 //