归并排序的利用

归并排序可以用其O(nlgn)的速度解决很多问题,另外在其归并的过程中,还可以做一些小动作。

例如:求一系列点[1,3,8,4,.....]的逆序对数,或正序对数。(两两比较左小于右为正序)

然后,就有了《灯塔问题》这个题目。

/*  灯塔的坐标为(x,y),且各不相同,灯塔处于另外一个灯塔的东北角90度范围,或西南角90度范围内,才能互相照射到。

/*  给定N个(x,y)坐标,求能互相照射到的对数。(网上可以搜索到此题。)

Input

3
2 2
4 3
5 1

Output

1

解答:此题是在归并的基础上,利用正序对的数目来记录答案。首先根据x来排一次序,然后再对y排序时,小动作出现在merge的时候:当左边那个要比较的点小于右边那个要比较的点,那左边那个点对应的正序对数目增加的个数为(右边剩余点的个数n2-j)这个要分析透彻,不然很容易出错。(相同方式可以知道求逆序时:左边点大于右边点,逆序对+=n1-i)

  1 //@version: v2.0
  2 //@author: jackxu_cn
  3
  4 #include<cstdio>
  5 //#define DEBUG
  6
  7 typedef struct lighthouse_t{
  8     long x;
  9     long y;
 10 }LightHouse;
 11
 12 void sort(long start, long end, bool rec);
 13 void merge(long start, long mid, long end, bool rec);
 14
 15
 16 long num=0;
 17 LightHouse* a;
 18 int main()
 19 {
 20     long n,i;
 21     scanf("%ld",&n);
 22     a= new LightHouse[n];
 23     for(i = 0; i < n; i++)
 24         scanf("%ld %ld",&a[i].x,&a[i].y);
 25
 26     sort(0, n-1, false);
 27 #ifdef DEBUG
 28     for(i=0;i<n;i++)
 29         printf("---->%ld %ld\n",a[i].x,a[i].y);
 30 #endif
 31     sort(0, n-1, true);
 32
 33
 34     printf("%ld\n",num);
 35     return 0;
 36 }
 37
 38
 39 void sort(long start, long end, bool record)
 40 {
 41     if (start < end) {
 42         long mid = (start + end) >> 1;
 43         sort(start, mid, record);
 44         sort(mid+1, end, record);
 45         merge(start, mid, end, record);
 46     }
 47 }
 48
 49
 50
 51
 52 void merge(long start, long mid, long end, bool record)
 53 {
 54     long n1 = mid - start+1;
 55     long n2 = end - mid;//end-(mid+1)+1
 56     LightHouse *left=new LightHouse[n1];
 57     LightHouse *right=new LightHouse[n2];
 58     long i, j, k;
 59
 60     for (i = 0; i < n1; i++) /* left holds a[start..mid] */
 61         left[i] = a[start+i];
 62     for (j = 0; j < n2; j++) /* right holds a[mid+1..end] */
 63         right[j] = a[mid+1+j];
 64
 65     i = j = 0;
 66     if (record){
 67         for(k=start; k<=end; k++)
 68         {
 69             if(i>=n1 && j<n2)//left:0  right:>0
 70             {
 71                 a[k]=right[j++];
 72                 //num+=n1;
 73             }else if(i<n1 && j>=n2)//left:>0 right:0
 74             {
 75                 a[k]=left[i++];
 76             }else//left>0 right>0
 77             {
 78                 if (left[i].y <= right[j].y)     {a[k]= left[i++]; num+=n2-j;}
 79                 else                             {a[k]= right[j++];}
 80             }
 81         }
 82     }else
 83     {
 84         for(k=start; k<=end; k++)
 85         {
 86             if(i>=n1 && j<n2)//left:0  right:>0
 87             {
 88                 a[k]=right[j++];
 89             }else if(i<n1 && j>=n2)//left:>0 right:0
 90             {
 91                 a[k]=left[i++];
 92             }else//left>0 right>0
 93             {
 94                 if (left[i].x <= right[j].x)     a[k]= left[i++];
 95                 else                             a[k]= right[j++];
 96             }
 97         }
 98     }
 99     delete[] left;
100     delete[] right;
101 }

 
时间: 2024-10-07 18:53:48

归并排序的利用的相关文章

排序算法之归并排序

一.分治法的思想 把复杂的问题分解,再分解,成为很小的问题,解决这些小问题之后合并,再合并.这就是分治法的思想. 通常分治法是递归的. 二.归并排序 归并排序就是利用分治法,把无序的数列拆分成多个子数列,子数列再拆分成多个子数列,直至只子数列只有2个数,然后排序,合并,再排序,在合并...直到只剩一个有序的数列. 归并排序算法的核心就是:两个各自有序的数列合并成一个完全有序的数列. 三.Java代码实现 public class MergeSort {     public static voi

转载:归并排序

归并排序是利用递归和分而治之的技术将数据序列划分成为越来越小的半子表,再对半子表排序,最后再用递归步骤将排好序的半子表合并成为越来越大的有序序列,归并排序包括两个步骤,分别为: 1)划分子表 2)合并半子表 首先我们来讨论归并算法,归并算法将一系列数据放到一个向量中,索引范围为[first,last],这个序列由两个排好序的子表构成,以索引终点(mid)为分界线,以下面一个序列为例 7,10,19,25,12,17,21,30,48 这样的一个序列中,分为两个子序列 7,10,19,25  和

[经典算法] 归并排序

题目说明: 归并排序是建立在归并操作上的一种有效的排序算法.该算法也是采用分治法(Divide and Conquer)的一个非常典型的应用.算法复杂度为O(N*logN). 题目解析: 归并排序是利用递归和分而治之的技术将数据序列划分成为越来越小的半子表,再对半子表排序,最后再用递归步骤将排好序的半子表合并成为越来越大的有序序列. 归并排序包括两个步骤: 1)划分子表 2)合并半子表 伪代码: 合并排序伪代码(使用哨兵): merge(A,p,q,r): n1 <-- q-p+1 n2 <-

归并排序详解

说一说归并排序 归并排序:归并排序(英语:Merge sort,或mergesort),是创建在归并操作上的一种有效的排序算法,效率为O(n log n).1945年由约翰·冯·诺伊曼首次提出.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,且各层分治递归可以同时进行. 归并排序的核心思想是将两个有序的数列合并成一个大的有序的序列.通过递归,层层合并,即为归并. 如图,从下到上,每一步都需要将两个已经有序的子数组合并成一个大的有序数组,如下是实现合并的具体代码,请

海量数据面试题----分而治之/hash映射 + hash统计 + 堆/快速/归并排序

1.从set/map谈到hashtable/hash_map/hash_set 稍后本文第二部分中将多次提到hash_map/hash_set,下面稍稍介绍下这些容器,以作为基础准备.一般来说,STL容器分两种: 序列式容器(vector/list/deque/stack/queue/heap), 关联式容器.关联式容器又分为set(集合)和map(映射表)两大类,以及这两大类的衍生体multiset(多键集合)和multimap(多键映射表),这些容器均以RB-tree完成.此外,还有第3类关

排序算法--归并排序(merge)

归并排序是利用递归和分而治之的技术将数据序列划分成为越来越小的半子表,再对半子表排序,最后再用递归步骤将排好序的半子表合并成为越来越大的有序序列,归并排序包括两个步骤,分别为: 1)划分子表  2)合并半子表 时间复杂度是Θ(nlgn),优于插入排序算法. 算法描述    1) 申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列    2) 设定两个指针,最初位置分别为两个已经排序序列的起始位置    3) 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到

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

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

Python实现排序(冒泡、快排、归并)

Thomas H.Cormen 的<算法导论>上介绍的几个经典排序算法的Python实现. 1.冒泡排序: 简单的两重循环遍历,使最小(最大)的值不断地往上升(下沉)而实现的排序,算法时间为O(n2). 代码如下: 1 def up_sort(a): 2 # 冒泡排序 3 4 a_length = len(a) 5 while True: 6 i = 0 7 j = 1 8 9 while True: 10 if a[i] > a[j]: 11 a[i], a[j] = a[j], a[

排序算法2——(希尔、堆、归并)

一.希尔排序 希尔排序也被称为“缩小增量排序”,是一种效率更高的插入排序,步长为1时希尔排序就是插入排序. 原理:先将待排序的数组元素分成多个子序列(这些子序列是以相对步长为区分单位的,相隔步长相同的元素在同一个组中),使得每个子序列的元素个数相对较少,然后对各个子序列分别进行插入排序,待整个排序序列“基本有序后”,最后再对所有元素进行一次插入排序. 示例代码如下: 1 public class shell { 2 public static void shellSort(int array[]