データ構造-選択ソートアニメーションデモ


序文

提示:本人不喜欢用专业术语来记录知识点,所以接下来会用例题+白话文的方式记录:

選択ソートの主なアイデアは、各パスでソートされるシーケンスからキーワード値が最小のレコードを選択することです。つまり、最初のパスで、n個のレコードからキー値が最小のレコードを選択します。 2番目のパスでは、残りのレコードから、シーケンス全体のすべてのレコードが選択されるまで、n-1レコードの中でキー値が最小のレコードを選択します。このようにして、レコードが選択された順序から、キー値の順序で順序付けられたシーケンスを取得できます。


提示:以下是本篇文章正文内容,下面案例可供参考

3.選択ソート

1.直接選択ソート

考え:

まず、すべてのレコードの中でキーワード値が最小のレコードを選択し、最初のレコードと交換してから、残りのレコードからキーワード値が2番目に小さいレコードを選択して、2番目のレコードと位置を交換します。すべてのレコードがソートされるまで。

  • 直接選択ソートのプロセス全体を示す、インターネットからのより古典的なgifを次に示します。
    ここに画像の説明を挿入

例:

ソートされる8つのレコードのキーワードシーケンスが{5、3、6、4、7、1、8、2}であると想定します。ソートプロセスを次の図に示します。
赤い色はソートされた番号です。一般的に、[角括弧]
ここに画像の説明を挿入
最初のシーケンスの代わりに、それを順序付けられていないシーケンスとして扱い
、次に順序付けられていないシーケンスから最小のものを選択し、順序付けられていないシーケンスの最初の番号と交換して、順序付けられたシーケンスを形成します
。順序付けされていないシーケンスから最小のものを選択します。順序付けられていないシーケンスの最初の番号と交換します。次の各手順
について
も同様です。各シーケンスをトラバースした後、順序付けられたシーケンスのレコード数+ 1、順序付けされていないシーケンスの数-1 、

コード部分:

public void  selectSort(){
    
    
 RecordNode temp;  //定义一个零时变量temp
   for(int i=0; i<this.curlen-1;i++)   //进行i-1次遍历,this.curlen:数组的长度
    {
    
     int  min=i; 
      for(int j=i+1;j<this.curlen; j++)   //找到一个最小的
   if (r[j].key.compareTo(r[min].key)<0)                            
            min=j; 
      if (min!=i)
       {
    
    temp=r[i];      //以下是交换代码
         r[i]=r[min];  
         r[min]=temp;}
    }
 }

パフォーマンス分析

⑴。時間計算量:
O(n 2) ⑵。
必要な補助スペース:
O(1)
⑶。アルゴリズムの安定性:
ソートが不安定

2、ツリー選択ソート

考え:

  • これは、ツリー選択ソートのプロセス全体を示すインターネット上の比較の古典的な図です。
    画像の説明を追加してください
    最初にn個のレコードを比較し、比較の結果、キーワード値が小さい方が勝者として親ノードに上げられます。最初のステップの比較の結果として、比較の勝者(キーワード値が小さい方)が保持されます。次に、キーワードのペアワイズ比較がこのレコードで実行され、以下同様に、レコードが最小のキーワード値が選択されます。
    このプロセスは、n個のリーフノードを持つ完全な二分木で表すことができます。

例1:

(1)

8つのキーのシーケンス{52、39、67、95、70、8、25、¯52¯}の場合、ツリー選択ソートを使用して最小のキー値を選択するプロセスでは、次の図に示す完全な二分木を使用できます。代表する。
ここに画像の説明を挿入
キーワードがすべて最後のレイヤーのリーフノードにあることがわかります。
どのように選択しますか?2つのPKは、若い方が親ノードに移動し、52と39、39が上昇し、67と95、67が上昇し、70と8、8が上昇します。
前のレベルでは、若い方が上昇します。親ノードに移動し、最後のキーワードが一番上に最小

(2)

上記の質問1(1)の例と同じように、2番目に小さい値を見つけます
ここに画像の説明を挿入
質問1(1)の例では、最小のものが見つかり、それが無限大「∞」と見なされ、2つのPKを使用できます。次に小さいものを見つけ、2番目に小さいものを見つけます。次に、それを無限大に置き換え、親ノードを取得するたびにこれらの最小のものを見つけて、というように、最後に並べ替えます。

パフォーマンス分析

(1)スペースの複雑さ
ツリー選択ソートはソート時間を短縮しますが、より多くの追加のストレージスペースを使用します。
⑵、時間
計算量ツリー選択ソートの時間計算量はO(nlog 2 n)です。⑶
、アルゴリズムの安定性
ツリー選択ソートは安定したソートアルゴリズムです。

3.ヒープソート

意味:

ヒープは、次のプロパティを満たすシーケンス{r 0、r1 。。。 rn-1 }です。

ビッグトップヒープの場合:ri i > = r 2i + 1 && ri i > = r 2i + 2
スモールトップヒープの場合:ri i +22i<= ri&& r2i + 1= r<ノードがすべて子ノードよりも小さいノードは、スモールトップヒープと呼ばれます



  • これは、トップヒープのサイズを示すインターネット上の古典的なグラフです。
    大きなトップヒープのルートノードの値は、シーケンス全体で最大である必要があり
    ます。小さなトップヒープのルートノードの値は、シーケンス全体で最小の
    ここに画像の説明を挿入
    r2i + 1はriですr2i + 2の左の子はriの右の子です

したがって、ヒープの意味は、完全なバイナリツリー内のすべての非終端ノード(親ノード)の値が、その左右の子ノードの値より大きくない(または小さくない)ことを示しています。

  • これは、インターネットからのより古典的なgifです。
    ここに画像の説明を挿入

方法:

まず、ソートされるレコードのシーケンスは完全なバイナリツリーに対応し、初期ヒープに変換されます(つまり、初期ヒープが最初に構築されます)。このとき、ルートノードのキー値が最大(または最小)になり、ルートノードと最後のノード(つまり、n番目のノード)の位置が交換されます。最後のノードを除いて、最初のn- 1つのノードは依然として完全なバイナリツリーを構成し、それらをヒープに調整します。また、ルートノードと最後のノード(つまり、n-1番目のノード)を交換します。ルートノードが1つだけ残るまでこのプロセスを繰り返すと、順序付きリストが表示されます。

「フィルタリング」する方法は?

いわゆる「スクリーニング」とは、調整プロセスを指します。左右のサブツリーがヒープである完全な二分木の場合、ルートノードを「調整」すると、二分木全体もヒープになります。

例:

並べ替える前のキーワードの順序は
{40、55、49、73、12、27、98、81、64、36}です。

下の写真の箱の中では、茶色のものが交換されており、緑色のものは移動する必要がありません。

「スクリーニング」はトップダウンのプロセスです。
各親ノードは子ノードよりも大きいため、大きなトップヒープであること
ここに画像の説明を挿入
がわかりますが、並べ替えた後、最大値の98を最後に配置し、添え字は9になりますが、これは12を移動する必要があります。つまり、最大値を最後のノードの値と交換する必要があります
ここに画像の説明を挿入
が、98と12を交換した後はヒープではないため、「フィルタリング」する必要があります。それでも大きなトップヒープに調整されます
。上から下にスクリーニングする必要がありますが、最大値が見つかって最後に配置されているため、最大値98をランク付けする必要がないことに注意してください。 。
最初に12、81、および49を見てください。これがビッグトップヒープの場合、81をトップに配置する必要があり、81と12が交換されますが
ここに画像の説明を挿入
、ビッグトップヒープではありません。次に、73、12と36が比較され、大きい方が上がって交換されるので、73と12が交換さ
ここに画像の説明を挿入
れてから、55と64が比較されます。大きい方が上がります。
ここに画像の説明を挿入
この場合、再び大きなトップヒープになります。
ルートノード81が最大で、無秩序なシーケンスの最後の1つと交換されます。ここでは12です。など、各フィルターは最大のものを見つけることができるので、ソートされます

「初期ヒープを構築する」方法は?

大きなトップヒープを構築する場合は、トップルートノードを最大にする必要があります
小さなトップヒープを構築する場合は、トップルートノードを最小にする必要があります

例:

ヒープ構築は、ボトムアップの「スクリーニング」プロセスです。

例:並べ替え前のキーワードシーケンスは
{40、55、49、73、12、27、98、81、64、36}です。最初
ここに画像の説明を挿入
に添え字4と9を見ると、36は12より大きく、36は上に
なります。左下を見てください。下付き文字3、7、8、81は73より大きく、64、81は上に
なり、右下付き文字2、5、6、98は27、49、98より大きくなり
ここに画像の説明を挿入
ます。下付き文字1、3、4、81で55、36より大きく、81が上がる
ここに画像の説明を挿入
が、問題が見つかります。下付き文字3、7、8、これら3つの数字(55、73、64)は大きくなりません。トップヒープ
なので、3つの数値を比較した後、73まで移動し
ここに画像の説明を挿入
、下付き文字0、1、2、98が81、40、98よりも大きいことを確認しますが
ここに画像の説明を挿入
、下付き文字2、5、6、これらは3つの数値(40、27、49)は大きなトップヒープを形成できない
ため、3つの数値を比較すると、49が上がり
ここに画像の説明を挿入
ます。これで、左右のサブツリーがヒープに調整されました。最後に、ルートノードのみを調整する必要があります。バイナリツリー全体が「ヒープ」になるようにします。
これは、ヒープを構築するプロセスです。下から上にスクリーニングします(最大数に応じて、この質問では、4、3、2、および1から調整します)。調整プロセス中は、サブツリーを壊す可能性ヒープ、調整を続ける必要があります。

コードセクション

public class HeapSort {
    
    
	public static void heapSort(int[] arr) {
    
    
		if (arr == null || arr.length == 0) {
    
    
			return;
		}
		int len = arr.length;
		// 构建大顶堆,这里其实就是把待排序序列,变成一个大顶堆结构的数组
		buildMaxHeap(arr, len);
 
		// 交换堆顶和当前末尾的节点,重置大顶堆
		for (int i = len - 1; i > 0; i--) {
    
    
			swap(arr, 0, i);
			len--;
			heapify(arr, 0, len);
		}
	}
 
	private static void buildMaxHeap(int[] arr, int len) {
    
    
		// 从最后一个非叶节点开始向前遍历,调整节点性质,使之成为大顶堆
		for (int i = (int)Math.floor(len / 2) - 1; i >= 0; i--) {
    
    
			heapify(arr, i, len);
		}
	}
 
	private static void heapify(int[] arr, int i, int len) {
    
    
		// 先根据堆性质,找出它左右节点的索引
		int left = 2 * i + 1;
		int right = 2 * i + 2;
		// 默认当前节点(父节点)是最大值。
		int largestIndex = i;
		if (left < len && arr[left] > arr[largestIndex]) {
    
    
			// 如果有左节点,并且左节点的值更大,更新最大值的索引
			largestIndex = left;
		}
		if (right < len && arr[right] > arr[largestIndex]) {
    
    
			// 如果有右节点,并且右节点的值更大,更新最大值的索引
			largestIndex = right;
		}
 
		if (largestIndex != i) {
    
    
			// 如果最大值不是当前非叶子节点的值,那么就把当前节点和最大值的子节点值互换
			swap(arr, i, largestIndex);
			// 因为互换之后,子节点的值变了,如果该子节点也有自己的子节点,仍需要再次调整。
			heapify(arr, largestIndex, len);
		}
	}
 
	private static void swap (int[] arr, int i, int j) {
    
    
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
}

パフォーマンス分析

(1)、時間計算量:
O(nlog 2 n)

(2)、必要な補助スペース:
O(1)

(3)アルゴリズムの安定性:
不安定なソート方法です


要約する

直接選択ソート

まず、すべてのレコードの中でキーワード値が最小のレコードを選択し、最初のレコードと交換してから、残りのレコードからキーワード値が2番目に小さいレコードを選択して、2番目のレコードと位置を交換します。すべてのレコードがソートされるまで。

ツリーソート

最初にn個のレコードを比較します。比較の結果、キーワード値が小さい方が勝者として親ノードに上げられ、比較の勝者(キーワード値が小さい方)が最初のレコードとして取得されます。比較のステップ。結果は保持されます。次に、キーワードのペアワイズ比較がこのレコードに対して実行され、以下同様に、キーワード値が最小のレコードが選択されるまで続きます。

ヒープソート

昇順で並べ替える場合は、大きなヒープを作成する必要があります。
降順で並べ替える場合は、小さなヒープを作成する必要があります。

フィルタリングとは、破壊された後に比較して交換することです。大きい方は上から下へと上がり
ます。ヒープの構築は、下から上への「スクリーニング」のプロセスです。

おすすめ

転載: blog.csdn.net/rej177/article/details/124368585