そして、配列の逆のマージソートの数

マージソート

まず、マージソートの主なアイデアを思い出します。

  1. まず、2つの命じたシーケンスをマージする方法を検討?この方法は、次のコードでマージ我々はソース配列の配列決定が完了するまで、それがより長いシーケンスに短いサブシーケンスとすることができる、二つのサブ順序付けられたシーケンスをマージすることができれば、方法。
  2. 最も整然とした列を取得するにはどのようにそれをマージし始めますか?各サブシーケンスの時間だけつの要素まで分割連続配列を介して、第二の順序付けられたシーケンスであり、この方法は、我々は、サブ順序付きシーケンスの統合を達成することができます。

本研究は、この特定の理解推奨ビデオを説明し、教師は自分自身が使い慣れた言語の実装を使用して、再びそれを理解することができます従うことが、非常に慎重に言いました。

我々はいくつかの点に注意を払う必要があります。このアルゴリズムでは:

  1. 私たちは、元の配列をソートする必要があり、それは一時的な配列TMP、2つの命じたシーケンス、tmpに置か良いために必要な要素の各行、その後の要素はバック、我々はできる元の配列にポンドからtmpに配置を必要としますTMPの合併がその場合は、実行全体のアルゴリズムの配列を宣言し続けるの配列を破壊するには、最初ではなく、その中に新しい連結法のTMPへのパラメータとして渡されます。
  2. 2つの注文したシーケンスをマージするには、従来の考え方は少しTMPを置く人置く比較的後方スクラッチ、ある、添字TMP最初から;しかし、いくつかの変種のために、我々は戻ってからで比較する必要があり、タイトルは、私たちの後に拡張子を記述して、初めの終わりからのTMPの裏、TMP指数に大きな置く人人:逆の順序で配列の数を求めます。これは、この細部に使用されます。
  3. アルゴリズムの最高と最悪時間計算量はO(nlgn)で、かつ安定したソートです。

 

Java実装 

1  パブリック クラスMyMergeSort {
 2      公共 静的 ボイドマージ(INT [] NUMS){
 3。          msort(NUMS、新しい新しい INT [nums.length]、0、-nums.length 1。);
 4      }
 。5  
。6      / ** 
7       * 1部1つだけの分割要素がシーケンスに分割される有する
 。8       * @param NUMS元の配列
 。9       * @param TMP一時的アレイ
 10       * @param leftStart左配列は添え字を開始する
 。11       * @param 右端配列添え字の右端に
 12      * / 
13である     プライベート 静的 ボイド(msort 値int [] NUMSをint型 [] TMP、INT leftStart、INT {右端)
 14          IF(leftStart == 右端){
 15              リターン;
 16          }
 17          // 二分
18は         INT = MID + leftStart(右端-leftStart)/ 2 ;
 19          // 点左サブアレイ
20は         、msort(NUMS、TMP、leftStart、MID)
 21である         // 遠い右サブアレイに
22で          msort(NUMSは、TMP、MID + 1 、右端)。
 23         // マージ。
24          マージ(leftStartは、MID + 1が、右端、TMP、NUMS);
 25      }
 26は、 
27      / ** 
28       * [ルール2つの順序付けられたサブシーケンスが組み合わされます。
29       * @param leftStart左開始インデックスサブシーケンス
 30       * @param 正しい配列rightStartインデックス開始
 31である      * @param 右インデックスサブシーケンスの右端端
 32       * @param TMP一時的アレイ、2つのサブアレイ前と後の結果結果をtmpに保存されているソート
 33はある      * @param NUMS元の配列
 34がある      * / 
35      プライベート 静的 ボイド(マージINT leftStart、INT rightStart、INT右端、INT [] TMP、INT [] NUMS){
 36          INT leftEnd = rightStart-1 37          // tmpStart代表此次元素放在TMP的哪个下标位置、
38          INT tmpStart = leftStart。
39          int型の長さ=右端-leftStart + 1 40          一方(leftStart <= leftEnd && rightStart <= 右端){
 41              // 降序
 42              // TMP [tmpStart ++] =のNUMS [leftStart]> NUMS [rightStart]?NUMS [leftStart ++]:NUMS [rightStart ++];
43  
44             // 升序
45              TMP [tmpStart ++] =のNUMS [leftStart] <NUMS [rightStart]?NUMS [leftStart ++]:NUMS [rightStart ++ ];
46          }
 47          ながら(leftStart <= leftEnd){
 48               TMP [tmpStart ++] =のNUMS [leftStart ++ ]。
49          }
 50          ながら(rightStart <= 右端){
 51              TMP [tmpStart ++] =のNUMS [rightStart ++ ]。
52          }
 53          // 将TMP里有序的元素捣回到原数组。
54          用のint型 i = 0; iは長さ<; iはrightEnd-- ++ ){
 55             NUMS [右端] = tmpの[右端]。
56          }
 57      }
 58      
59      公共 静的 ボイドメイン(文字列[]引数){
 60          のint [] NUMS = 新しい INT [] {9、8、7、6、5、4、3、2、10 }。
61          マージ(NUMS)。
62          のためにINT X:NUMS){
 63              System.out.print(X + "" )。
64          }
 65      }
 66 }

 

広げます

配列を逆転しようとしています

  満足している場合、配列NUMSのために、それの逆は何ですか

私は<J && NUMS [I]> NUMS [j]を

则称 nums[i] 和 nums[j] 就构成了一对逆序对。举个例子:对于数组:[ 1,5,3,2,6 ],共存在 3 组逆序对,分别是 [5, 3]、[5,2]、[3,2] 。对于最简单的思路就是用两次 for 循环对每个元素查找其构成的逆序对数量,时间复杂度为O(n^2)。如果借用归并排序的思想,可以达到和归并排序一样的时间复杂度O(nlgn)。

  对原数组进行归并排序,在合并操作的时候就可以获得前后两个子序列的逆序对。这里是从子序列的尾部往前移动的。

Java实现

 

 1 public class CountReverse {
 2     public static int inversePairs(int[] nums){
 3         if( nums == null ||nums.length <= 1) {
 4             return 0;
 5         }
 6         int[] tmp = new int[nums.length];
 7 
 8         return mergeCount(nums, tmp, 0, nums.length-1);
 9     }
10 
11     public static int mergeCount(int[] nums, int[] tmp, int leftStart, int rightEnd){
12         if(leftStart == rightEnd){
13             tmp[leftStart] = nums[leftStart];
14             return 0;
15         }
16         int mid = leftStart + (rightEnd - leftStart)/2;
17         
18         int leftCount = mergeCount(nums, tmp, leftStart, mid);
19         int rightCount = mergeCount(nums, tmp, mid+1, rightEnd);
20 
21         int leftEnd = mid;// i 初始化为前半段最后一个数字的下标
22 
23         int tmpEnd = rightEnd;//辅助数组复制的数组的最后一个数字的下标
24         
25         int count = 0; //计数--逆序对的数目
26 
27         while(leftStart <= leftEnd && mid+1 <= rightEnd){
28             if(nums[leftEnd] > nums[rightEnd]){
29                 tmp[tmpEnd --] = nums[leftEnd --];
30                 // 因为 是两个有序的子序列。
31                 count += rightEnd - mid;
32             }else{
33                 tmp[tmpEnd--] = nums[rightEnd--];
34             }
35         }
36 
37         while (leftEnd >= leftStart) {
38             tmp[tmpEnd --] = nums[leftEnd --];
39         }
40 
41         while (rightEnd >= mid + 1) {
42             tmp[tmpEnd --] = nums[rightEnd --];
43         }
44         
45         return leftCount + rightCount + count;
46     }
47 
48     public static void main(String[] args) {
49         int[] nums = new int[] {1, 5, 3, 2, 6};
50         System.out.println(inversePairs(nums));
51     }
52 }

 

 

 

 

おすすめ

転載: www.cnblogs.com/dogeLife/p/11428558.html