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
配列全体が並べ替えられます。