归并排序

LeetCode 23 Hard,K个链表归并

一世执手 提交于 2020-02-17 09:04:02
本文始发于个人公众号: TechFlow ,原创不易,求个关注 链接 Merge k Sorted Lists 难度 Hard 描述 Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 给定K个有序链表,要求将它所有的元素归并到一个链表,并且有序。 样例: Input: [ 1->4->5, 1->3->4, 2->6 ] Output: 1- >1->2->3->4->4->5->6 题解 按照惯例,我们还是先来看最简单的解法,也就是暴力法。 暴力 这题当中,暴力的方法也很简单,非常简单粗暴,那就是先把所有元素取出来,排序之后再放到链表当中去。但是这么做说实话有点脱裤子放屁,我们分析一下复杂度也会发现,假设所有的元素个数是n,那么最后的复杂度应该就是排序所消耗的复杂度,也就是 \(O(nlogn)\) ,和K没有一点关系,而且我们也完全没有用上这K个链表当中的元素都是有序的这个信息,显然这是不科学的。 我们对上面的纯暴力方法稍稍做一些优化,想办法把K个链表当中元素有序的信息用上。用上的方法也很简单,我们之前做归并排序的时候曾经做过两个数组的归并,我们用同样的方法,只不过我们这次换成是K个链表而已。也就是说我们每次遍历这K个链表的头元素

归并排序

徘徊边缘 提交于 2020-02-15 12:23:01
归并排序分治法的一个典型且基本的应用。它的基本思想是:将对N个对象的问题转换成两次对N/2个对象的问题。归并排序减少了数据的比较次数,转而增加了数据的移动次数,使得排序速度相对较快。该算法的递推公式T(N) = 2T(N/2) + O(N)表明其算法复杂度上限为O(NlogN)。下面是其C++代码: 1 #include<cstring> 2 #include<cstdio> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 7 int innersort(int* A,int left,int right,int* CPY) 8 {//[left,mid]and[mid+1,right]; 9 if(right==left)return 0; 10 int mid=(left+right)/2; 11 int i=left,k=mid+1; 12 int cur=left; 13 while(i!=mid+1&&k!=right+1) 14 { 15 if(A[i]>A[k])CPY[cur++]=A[k++]; 16 else CPY[cur++]=A[i++]; 17 }//一定有一侧的数据会最先完成排序 18 while(i!=mid+1)CPY[cur++]=A[i++]; 19

MapReduce的shuffle过程详解

筅森魡賤 提交于 2020-02-14 13:40:43
shuffle概念   shuffle的本意是洗牌、混洗的意思,把一组有规则的数据尽量打乱成无规则的数据。而在MapReduce中,shuffle更像是洗牌的逆过程,指的是将map端的无规则输出按指定的规则“打乱”成具有一定规则的数据,以便reduce端接收处理。其在MapReduce中所处的工作阶段是map输出后到reduce接收前,具体可以分为map端和reduce端前后两个部分。在shuffle之前,也就是在map阶段,MapReduce会对要处理的数据进行分片(split)操作,为每一个分片分配一个MapTask任务。接下来map()函数会对每一个分片中的每一行数据进行处理得到键值对(key,value),其中key为偏移量,value为一行的内容。此时得到的键值对又叫做“中间结果”。此后便进入shuffle阶段,由此可以看出shuffle阶段的作用是处理“中间结果”。 此处应该想一下,为什么需要shuffle,它的作用是什么? 在了解shuffle的具体流程之前,应先对以下两个概念有所了解: block块(物理划分)   block是HDFS中的基本存储单位,hadoop1.x默认大小为64M而hadoop2.x默认块大小为128M。文件上传到HDFS,就要划分数据成块,这里的划分属于物理的划分(实现机制也就是设置一个read方法

Java数据结构——归并排序

我怕爱的太早我们不能终老 提交于 2020-02-13 17:35:20
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序是一种稳定的排序方法。 比如初始数组:[3,5,6,7,8,4,1,2] ①分成了两个大小相等的子数组:[3,5,6,7],[8,4,1,2] ②再划分成了四个大小相等的子数组:[3,5],[6,7],[8,4],[1,2] ③此时,left < right 还是成立,再分:[3],[5],[6],[7],[8],[4],[1],[2] 此时,每个数组中的left == right,再根据递归的策略,每两个进行归并: merge([3],[5]) 得到 [3,5] merge([6],[7]) 得到[6,7] merge([3],[5],[6],[7]) 得到[3,5,6,7] 最终得到 有序数组。 import java.util.Arrays; import java.util.Date; public class Main { public static void main(String[] args) { int[] arr = new int[10]; int[] temp = new

归并算法经典应用——求解逆序数

纵饮孤独 提交于 2020-02-13 08:27:03
本文始发于个人公众号: TechFlow ,原创不易,求个关注 在之前介绍线性代数行列式计算公式的时候,我们曾经介绍过逆序数:我们在列举出行列式的每一项之后,需要通过逆序数来确定这一项符号的正负性。如果有忘记的同学可以回到之前的文章当中复习一下: 线性代数行列式 如果忘记呢,问题也不大,这个概念比较简单,我想大家很快就能都搞清楚。 今天的这一篇文章,我想和大家聊聊逆序数的算法,也是一道非常经典的算法题,经常在各大公司的面试题当中出现。 我们先来回顾一下逆序数的定义,所谓逆序数指的是数组当中究竟存在多少组数对,使得排在前面的数大于排在后面的数。我们举个例子,假设当下有一个数组是: [1, 3, 2]。 对于数对(3, 2)来说,由于3排在2前面,并且3 > 2,那么就说明(3, 2)是一对逆序数对。整个数组当中所有逆序数对的个数就是逆序数。 我们从逆序数的定义当中不难发现,逆序数其实是用来衡量一个数组有序程度的一个指标。逆序数越大,说明这个数组递增性越差。如果逆序数为0,说明这个序列是严格递增的。如果一个长度为n的数组的逆序数是 \(C_n^2\) ,那么说明这个数组是严格递减的,此时逆序数最大。 那么,我们怎么快速地求解逆序数呢? 暴力解法 显然,这个问题可以暴力求解,我们只需要遍历所有的数对,然后判断是否构成逆序即可,最后累加一下所有逆序数对的个数就是最终的答案。

2-路归并排序的递归写法

最后都变了- 提交于 2020-02-12 08:15:21
《算法笔记》中摘取 2-路归并排序的递归写法非常简单,只需要反复将当前区间[left, right]分为两半,对两个子区间[left, mid]与[mid +1, right]分别递归进行归并排序,然后将两个已经有序的合并为有序序列即可。 const int maxn = 100; //将数组A的[L1, R1]与[L2, R2]区间合并为有序区间(此处L2记为R1 + 1) void merge(int A[], int L1, int R1, int L2, int R2) { int i = L1, j = L2; //i指向A[L1], j指向A[L2] int temp[maxn], index = 0; //temp临时存放合并后的数组,index为其下标 while(i <= R1 && j <= R2) { if(A[i] <= A[j]) { //如果A[i] <= A[j] temp[index++] = A[i++]; //将A[i]加入序列temp } else { //如果A[i] > A[j] temp[index++] = A[j++];//将A[j]加入序列temp } } while(i <= R1) temp[index++] = A[i++]; //将[L1, R1]的剩余元素加入序列temp while(j <= R2) temp[index

【书上讲解】归并排序的非递归写法

你说的曾经没有我的故事 提交于 2020-02-12 08:14:17
描述 【题解】 让区间的长度L为1,2,4,...2^(n-1) 然后对每个位置i开始的长度为L的区间归并有序,用归并排序的方法就好,然后i跳转到i+L 复杂度仍然是log2(n)*n级别的,注意写的时候的一些细节。 比如一定要让最后L>=n的情况进行过一次,不然无法保证整个序列是有序的 【代码】 /* 归并排序非递归写法 */ #include <cstdio> const int N = 1e5; int a[N+10],b[N+10]; int n; //把a这个数组在l1..r2这个区间分成两段[l1,r1]和[l2,r2];然后进行合并 void _Merge(int a[],int b[],int l1,int r1,int l2,int r2){ int i = l1,j = l2,k = l1; while (i<=r1 && j<= r2){ if (a[i]<=a[j]) b[k++]=a[i++]; else b[k++] = a[j++]; } while (i<=r1) b[k++] = a[i++]; while (j<=r2) b[k++] = a[j++]; } void _merge(int a[],int b[],int L){ int i = 1; while (i+L-1<n){//把i..i+L-1这个区间合并 _Merge(a,b,i,i

归并排序

╄→гoц情女王★ 提交于 2020-02-11 21:19:29
归并排序 归并排序(英语:Merge sort,或mergesort),是创建在归并操作上的一种有效的排序算法。1945年由约翰·冯·诺伊曼首次提出。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行。 为了不重复造轮子。 归并原理参考: https://blog.csdn.net/csdn_blog_lcl/article/details/78027038 递归原理参考: https://blog.csdn.net/weixin_42199022/article/details/99304964 以下是我的代码 vs编译通过 head.h # ifndef HEAD_H # define HEAD_H # include <iostream> # include <time.h> # include <iomanip> using namespace std ; void merge ( int * a , int first , int mid , int last , int * a1 ) ; void merge_sort ( int * a , int first , int last , int * a1 ) ; void Array_generate ( int * a , int len ) ;

刷题No24. sort-list(排序)(java)【链表】

血红的双手。 提交于 2020-02-11 19:05:44
题目: 在O(n log n)的时间内使用常数级空间复杂度对链表进行排序。 思路: 由于题目要求,时间复杂度要求为O(n log n),所以,需要用归并排序。 找到链表的中间节点 通过中间节点将链表1分为2 两个链表进行比较,比较完之后进行合并。 代码: package com.company; import java.util.List; public class TestNo24 { //定义单链表 static class ListNode{ int val; ListNode next; ListNode(int x){ val = x; next = null; } public String toString(){ if(this.next == null){ return String.valueOf(this.val); } return this.val + "->" + this.next.toString(); } } public static void main(String[] args) { TestNo24 t = new TestNo24(); ListNode head = new ListNode(4); head.next = new ListNode(5); head.next.next= new ListNode(7); head

归并排序

本秂侑毒 提交于 2020-02-10 17:44:43
归并排序 将给定的包含n个元素的局部数组“分割”为俩个局部数组,每个数组包含 n/2 个元素。 对两个局部数组分别进行归并排序。 通过归并把两个已经排序的局部数组“整合”成一个数组。 举例:以 a = [9,6,7,2,5,1,8,4,2]进行归并排序 注:红色数字代表执行顺序。 代码: import java . util . Arrays ; public class MergeSort { public static void mergeSort ( int [ ] arr , int left , int right ) { //直到分割到单个元素,停止分割 if ( left + 1 < right ) { int mid = ( left + right ) / 2 ; //分割为2个数组 mergeSort ( arr , left , mid ) ; mergeSort ( arr , mid , right ) ; //合并2个数组 merge ( arr , left , mid , right ) ; } } public static void merge ( int [ ] arr , int left , int mid , int right ) { //申请额外空间存储排序结果 int [ ] result = new int [ right -