归并排序&求逆序对数
来源:互联网 发布:ios开发中的数据库 编辑:程序博客网 时间:2024/05/04 23:20
归并排序:
基本原理:与插入排序使用的“增量”方法不同,归并排序使用另外一种策略:分治法
分治策略基本思想:将原问题划分成n个规模较小而结构与原问题相似的小问题;递归地解决这些子问题,然后再合并其结果,就得到原问题的解。
分治模式在每一层递归上都有三个步骤;
分解(Divide):将原问题分解成这一系列子问题。
解决(Conquer):递归地解各子问题。若子问题足够小,则直接求解。
合并(Combine):将子问题的结果合并成原问题的解。
合并排序算法完全依照了上述模式,直观地操作如下:
分解:将n个元素分成各含n/2个元素的子序列;
解决:用合并排序法对两个子序列递归地排序;
合并:合并两个已排序的子序列以得到排序结果;
时间复杂度:O(nlgn)
代码实现:
#include<stdio.h>#define N 10 int A[N] ;void Merge(/*A*/int p,int q,int r) ;void MergeSort(/*A*/int p,int r) ;int main(void){int i,n ;freopen("in.txt","r",stdin) ;while(scanf("%d",&n) != EOF){for(i = 0 ; i < n ; i++){scanf("%d",&A[i]) ;}printf("You have input the List:\n") ;for(i = 0 ; i < n ; i++){printf("%-3d",A[i]) ;}printf("\n") ;MergeSort(/*A*/0,n-1) ; //not n but n-1printf("After Sort:\n") ;for(i = 0 ; i < n ; ++i){printf("%-3d",A[i]) ;}printf("\n\n") ;}return 0 ;}void MergeSort(/*A*/int p,int r) {int q = 0 ;if(p < r){q = p + (r-p)/2 ; //noticeMergeSort(/*A*/p,q) ;MergeSort(/*A*/q+1,r) ;Merge(/*A*/p,q,r) ;}}void Merge(/*A*/p,q,r) {int L[N], R[N] ;int i,j,k ;int nLeft,nRight ;nLeft = q + 1 - p ; //noticenRight = r - q ; //noticefor(i = 0 ; i < nLeft ; ++i ){L[i] = A[p+i] ;}for(j = 0 ; j < nRight ; ++j){R[j] = A[q+j+1] ; //notice}i = 0 ;j = 0 ;for(k = p ; k < r && i<nLeft && j<nRight ; k++ ){if(L[i] <= R[j]){A[k] = L[i] ; i++ ;}else{A[k] = R[j] ; j++ ;}}if(i >= nLeft){for(; k <= r ; ++k,++j) {A[k] = R[j] ;}}else{for(; k <= r ; ++k,++i){A[k] = L[i] ;}}}
以上结论摘自《算法导论》
----------------------------------------------------------------------------
算法导论思考题:2-4逆序对
d)给出一个算法,它能用O(nlgn)的最坏情况运行时间,确定n个元素的任何排列中逆序对的数目。(提示:修改合并排序)
答:其实就是合并两个子序列时,出现右边元素小于左边元素的情况,亦即R[j]<L[i]时,出现逆序对。此时L[i+1...n1]里的元素均比R[j]大,而R[j]又在它们的后面。所以,此时的逆序对数:n1-i。后面的元素以此类推。
代码实现:
#include<stdio.h>#define N 10 int A[N] ;int nTotalInversion = 0 ;void Merge(/*A*/int p,int q,int r) ;void MergeSort(/*A*/int p,int r) ;int main(void){int i,n ;freopen("in.txt","r",stdin) ;while(scanf("%d",&n) != EOF){nTotalInversion = 0 ;for(i = 0 ; i < n ; i++){scanf("%d",&A[i]) ;}printf("You have input the List:\n") ;for(i = 0 ; i < n ; i++){printf("%-3d",A[i]) ;}printf("\n") ;MergeSort(/*A*/0,n-1) ; //not n but n-1printf("The Inversions are %d.\n\n",nTotalInversion) ;}return 0 ;}void MergeSort(/*A*/int p,int r) {int q = 0 ;if(p < r){q = p + (r-p)/2 ; //noticeMergeSort(/*A*/p,q) ;MergeSort(/*A*/q+1,r) ;Merge(/*A*/p,q,r) ;}}void Merge(/*A*/p,q,r) {int L[N], R[N] ;int i,j,k ;int nLeft,nRight ;nLeft = q + 1 - p ; //noticenRight = r - q ; //noticefor(i = 0 ; i < nLeft ; ++i ){L[i] = A[p+i] ;}for(j = 0 ; j < nRight ; ++j){R[j] = A[q+j+1] ; //notice}i = 0 ;j = 0 ;for(k = p ; k < r && i<nLeft && j<nRight ; k++ ){if(L[i] <= R[j]){A[k] = L[i] ; i++ ;}else{nTotalInversion += nLeft - i ; //hereA[k] = R[j] ; j++ ;}}if(i >= nLeft){for(; k <= r ; ++k,++j) {A[k] = R[j] ;}}else{for(; k <= r ; ++k,++i){A[k] = L[i] ;}}}
练习题6.5-8
大概思路:先利用每个链表的头元素来建立一个最大堆或者最大堆,然后再做类似堆排序的操作。但是这里要注意的是用到了额外空间数组B来储存排序后的元素。而且在交换树根和堆的最后一个元素之后,还要检查链表是否为空,从而更新heap-size[A]的值。时间复杂度:O(nlgk)
伪代码实现:
K-Road-MegerSort(A,k,n){BuildMinHeap(A,k) ; //use the K List's first data to build the heapi <- n ;j <- 0 ;nHeapSize <- k ;while i > 0do B[j] <- A[1]->data ; j <- j + 1 ; if A[1]->next = NULL //if the one List is empty. then exchange A[1] <-> A[nHeapSize] ; nHeapSize <- nHeapSize - 1 ; MinHeapify(A,1) ; else then MinHeapify(A,1) ; i <- i - 1 ; }
- 归并排序求逆序对数)
- 归并排序&求逆序对数
- 归并排序求逆序对数
- 归并排序求逆序对数
- 归并排序求逆序对数
- 求逆序对数(利用归并排序)
- POJ 2299 归并排序 求逆序对数
- 归并排序算法求逆序对数
- 归并求逆序对数
- 归并求逆序对数
- 归并排序及利用归并排序求逆序对数
- 归并排序-逆序对数
- 归并排序求 逆序对数 TOJ 1455 Ultra-QuickSort
- POJ 2299 Ultra-QuickSort(归并排序求逆序对数)
- POJ2299——归并排序求逆序对数
- 归并排序与分治法求逆序对数
- POJ 1804 Brainman (归并排序 -- 求逆序对数)
- 归并排序的实现及利用其求逆序对数
- Uva 562 Dividing coins
- js日历插件(附截图和源码)
- Oracle里scott的由来
- POJ题目分类
- 都是指针数据成员“惹的祸”
- 归并排序&求逆序对数
- 面向对象的三个基本特征 和 五种设计原则
- SuSE下配置ssh自动登录
- Uva 624 CD
- 众数问题
- 比较常用的Oracle的SQL语句语法
- Geoserver的安装配置(组合OpenLayers使用)
- 学习OpenCV彩色图像的通道的分离(split)与合成(merge)
- POJ 1860