データ構造とアルゴリズム - 挿入&ヒル&マージ

    1: 仕分けの紹介

     私たちは通常、ソートアルゴリズムをどのような側面から分析しますか?

        1. 時間効率: アルゴリズムの実行にかかる時間を決定します (O(1))。

        2. 空間の複雑さ:

        3. 比較と交換の数: 並べ替えには必ず 2 つの操作が含まれ、そのうちの 1 つは間違いなく比較です。交換。

        4.安定性:それは何ですか?1 9 3 5 3

                最初のタイプ: 1 3 3 5 9

                2 番目のタイプ: 1 3 3 5 9 どれが安定していますか? 2 つの同一の数値を並べ替えた後も、それらの相対的な位置は変わりません。

        安定した並べ替えのポイントは何ですか? 申請書はどこにありますか?

                1. 電子商取引における注文の並べ替え:まず、注文は金額順に小口から大口まで並べられ、同じ金額の注文は注文時刻によって並べ替えられます。注文センターから来たとき、すでに時間に合わせて手配していました。並べ替えアルゴリズムを選択します: 不安定な並べ替えアルゴリズムを選択した場合は 2 回比較する必要がありますが、安定した並べ替えアルゴリズムを選択した場合は 1 つのフィールドを比較するだけで済みます。

        2 つの核となるアイデア:

        次のような問題があるとします:ポーカーをプレイするそれを 2 つの部分に分割します。1 つの部分は手札にあるカード (すでに並べ替えられている) であり、もう 1 つの部分は取得するカード (順序付けされていない) です。

        順序なしシーケンスを順序付きシーケンスに 1 つずつ挿入します。順序付けられた配列に新しいデータを追加した後、データの順序を維持するにはどうすればよいでしょうか? 配列を走査し、データを挿入する場所を見つけて、それを挿入するだけです。

        3: 具体的な手順

        1. 配列をソートされたセグメントとソートされていないセグメントに分割します。初期化時にソートされた端には要素が 1 つだけあります

        2. 並べ替えられていないセグメントから要素を取得し、並べ替えられたセグメントに要素を挿入し、挿入後も要素が順序どおりであることを確認します。

        3. 未ソートのセグメント要素がすべて追加されるまで、上記の操作を繰り返します。

       4: たとえば:

        次の例を見てください: 挿入ソート 7 8 9 0 4 3

        7 8 9 0 4 3

        7 8 9 0 4 3

        7 8 9 0 4 3

        0 7 8 9 4 3

        0 4 7 8 9 3

        0 3 4 7 8 9

        上記の操作から、挿入ソートでは要素の比較と要素の移動が行われることがわかります。ソート対象の列の数値をソート間隔に挿入する場合、適切な位置が見つかるまでその数値をソート間隔の数値と比較し、挿入ポイントの後の要素を後方に移動する必要があります。

        5: 挿入ソートコードの実装、

package sort;

/**
 * 插入排序
 */
public class InsertionSort {
	/**
	 * 
	 1.将数组分成已排序段和未排序段。初始化时已排序端只有一个元素 
	 2.到未排序段取元素插入到已排序段,并保证插入后仍然有序
	 3.重复执行上述操作,直到未排序段元素全部加完。
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		int a[] = { 9, 8, 7, 0, 1, 3, 2 };
		int n = a.length;
		//这里面会有几层循环 2
		//时间复杂度:n^2
		//最好的情况:什么情况下:O(n); O(1)
		//for(){		//分段
		for(int i = 1 ; i < n;i++){		//为什么i要从1开始? 第一个不用排序,我们就把数组从i分开,0~I的认为已经排好序
			int data = a[i];
			int j = i -1;
			for(;j>=0;j--){//从尾到头 1+2+3+4+5+...+n=>
				if(a[j] > data){
					a[j+1] = a[j];		// 数据往后移动
				}else{	//因为前面已经是排好序的 那么找到一个比他小的就不用找了,因为前面的肯定更小
					break; //O(1)		如果这个break执行的越多 那么我是不是效率就越高?
				}
			}	
			a[j+1] = data;
			System.out.print("第" +i +"次的排序结果为:");
			for(j = 0 ; j < n;j++){
				System.out.print(a[j]+" ");
			}
			System.out.println();
		}
		
	}

}

        6:最適化(ヒルソート==>挿入ソート改良版)

        ヒル ソートでは、添字の特定の増分でレコードをグループ化し、直接挿入ソート アルゴリズムを使用して各グループをソートします。増分が徐々に減少するにつれて、各グループにはますます多くのキーワードが含まれます。増分が 1 に減少すると、ファイル全体がグループ化されます。ちょうど 1 つのグループに分割され、アルゴリズムは終了します。

        まず、ファイル内のすべてのレコードをグループ化するための最初の増分として、n より小さい整数 d1 を取得します。距離が d1 の倍数であるすべてのレコードは、同じグループに配置されます。まず各グループ内で直接挿入ソートを実行し、次に 2 番目の増分 d2<d1 を取得し、取得した増分 = 1 (<...<d2<d1) (つまり、すべてのレコードが配置される) になるまで上記のグループ化とソートを繰り返します。同じグループ内での挿入ソート。

特定のプロセスを見てみましょう: 増分に従ってセグメント化: add=n/2 n=10 =>5,2,1 7 8 9 0 4 3 1 2 5 10 取得する増分は 5 2 1 7 8 9 0 です。 4 3 1 2 5 10: 分割された配列要素はすべて同じでソートが完了します: 3 1 2 0 4 7 8 9 5 3 2 4 8 5: 増分が 2 の要素が 1 つのグループに分割されます。グループを 1 ずつ増分する時間: これは完全なシーケンスですが、時間計算量は依然として O(n^2) です

        7: マージソート (中心となるアイデア: 再帰 + 分割統治)

        主に時間計算量を分析します: nlogn

        

package sort;

import java.util.Arrays;

public class MegrSort {

	public static void main(String[] args) {

		int data[] = { 9, 5, 6, 8, 0, 3, 7, 1 };
		//拆分
		megerSort(data, 0, data.length - 1);
		System.out.println(Arrays.toString(data));
		//JDK里面的排序源码

	}

	public static void megerSort(int data[], int left, int right) { // 数组的两端
		if (left < right) { // 相等了就表示只有一个数了 不用再拆了
			int mid = (left + right) / 2;
			//拆分从最左边到中间
			megerSort(data, left, mid);
			//拆分右边从中间+1到最右边
			megerSort(data, mid + 1, right);
			// 分完了 接下来就要进行合并,也就是我们递归里面归的过程
			meger(data, left, mid, right);
		}
	}

	public static void meger(int data[], int left, int mid, int right) {
		int temp[] = new int[data.length];		//借助一个临时数组用来保存合并的数据
		
		int point1 = left;		//表示的是左边的第一个数的位置
		int point2 = mid + 1;	//表示的是右边的第一个数的位置
		
		int loc = left;		//表示的是我们当前已经到了哪个位置了
		while(point1 <= mid && point2 <= right){
			if(data[point1] < data[point2]){
				temp[loc] = data[point1];
				point1 ++ ;
				loc ++ ;
			}else{
				temp[loc] = data[point2];
				point2 ++;
				loc ++ ;
			}
		}
		//接下来要干嘛呢?合并排序完成 了吗?
		while(point1 <= mid){
			temp[loc ++] = data[point1 ++];
		}
		while(point2 <= right){
			temp[loc ++] = data[point2 ++];
		}
		for(int i = left ; i <= right ; i++){
			data[i] = temp[i];
		}
	}
}

        このコードは、マージソートアルゴリズムを実装します。マージ ソートは、配列を 2 つのサブ配列に分割し、それらを再帰的に並べ替えてから、2 つの順序付けされたサブ配列を 1 つの順序付けされた配列にマージする分割統治アルゴリズムです。コード内のmegerSortメソッドはマージ ソートの主要なメソッドであり、配列と 2 つのインデックス値をパラメータとして受け取り、ソートする必要がある配列とソートする必要がある範囲を示します。左のインデックスが右のインデックスより小さい場合は、配列を半分に分割し、megerSort左半分と右半分でそれぞれメソッドを再帰的に呼び出します。再帰呼び出しが終了したら、megerメソッドを呼び出して、2 つの順序付けられた部分配列を 1 つの順序付けられた配列にマージします。megerこのメソッドは、マージされた結果を保持する一時配列を作成しますtemp変数point1および は、point2それぞれ左半分と右半分の開始位置を表します。変数はloc現在のマージ位置を表します。ループ内で、左右の部分配列の要素サイズを比較し、小さい方の部分配列を一時配列に入れ、対応するポインターを後方に移動します。ループが終了すると、残りの要素が 1 つずつ一時配列に入れられます。最後に、一時配列の要素が元の配列内の対応する位置にコピーされて戻されます。マージ ソート プロセス全体は再帰的であり、要素が 1 つだけになるまで再帰ごとに配列が 2 つの半分に分割されます。配列全体のソートは、ソートされた 2 つのサブ配列をマージすることによって実現されます。最後に、メソッドを再帰的に呼び出すことによってmegerSort配列全体が並べ替えられます。

Guess you like

Origin blog.csdn.net/qq_67801847/article/details/132670609