データ構造-挿入ソート(C言語)

1つ、直接挿入ソート

1.1基本的な考え方

直接挿入ソートは単純な挿入ソート方法です。基本的な考え方は
、すべてのレコードが挿入されるまで、キーコード値のサイズに従って1つずつソートされた順序付けられたシーケンスにソートされるレコードを挿入することです。新しい順序付けられたシーケンスを取得します。
実際には、ポーカーをプレイするときは、挿入ソートのアイデアを使用します
ここに画像の説明を挿入します

1.2コードの実装

次の図に示すように、配列[0、end]がすでに順序付けられた配列であると仮定して、最初に1行のみの並べ替えを挿入するコードを記述します。次に、並べ替えられる要素添え字はend + 1、添え字です。 (end +1)要素はtmpに格納され、a [end]と比較されます。tmp<a [end]ある限り、添え字がendある要素は後方に移動し、endは左に移動します。後方に移動すると、スペースが確保されます。 Insert tmpの場合、tmpが条件を満たさなくなるまで、ループ停止し、tmpを適切な位置end +1に挿入します。
ここに画像の説明を挿入します

このようにして、挿入ソートのコードを書くことができます

		int end=i;	//有序数组最后一个元素的下标
		int tmp = a[end + 1]; //待插入元素存入临时变量tmp
		while (end >= 0)
		{
    
    

			if (tmp < a[end])			//如果待插入元素比end下标的元素小
			{
    
    
				a[end + 1] = a[end];	//1.end下标元素向后挪方便tmp的插入
				--end;					//2.end左移进行下一轮的比较
			}
			else                        //如果待插入元素大于或等于end下标的元素退出循环
			{
    
    
				break;
			}
		}
		a[end + 1] = tmp;				//将tmp插入到数组当中

完全なコードは、挿入ソートを実現するために末尾を移動するだけで済みます。デフォルトではend = 0です。つまり、最初の要素が順序付けられ、最後が後方に移動し、各要素が前の順序の要素と比較されます。これで、endの開始条件は0から開始し、end = n-2になります。これは、end = n-2の場合、ソートされる要素のインデックスがn-1、つまりインデックスであるためです。配列の最後の要素の、終了の間隔は[0、n-2]です。通常、この間隔を左閉と右開、つまり[0、n-1)と記述します。

// 插入排序
void InsertSort(int* a, int n)
{
    
    
	//默认第一个数已经是有序
	for (int i = 0; i < n-1; ++i)
	{
    
    
		int end=i;	//有序数组最后一个元素的下标
		int tmp = a[end + 1]; //待插入元素存入临时变量tmp
		while (end >= 0)
		{
    
    

			if (tmp < a[end])			//如果待插入元素比end下标的元素小
			{
    
    
				a[end + 1] = a[end];	//1.end下标元素向后挪方便tmp的插入
				--end;					//2.end左移进行下一轮的比较
			}
			else                        //如果待插入元素大于或等于end下标的元素退出循环
			{
    
    
				break;
			}
		}
		a[end + 1] = tmp;				//将tmp插入到数组当中
	}
}

試験結果

//打印数组
void PrintArr(int* a, int n)
{
    
    
	for (int i = 0; i < n; ++i)
	{
    
    
		printf("%d ", a[i]);
	}
	printf("\n");
}

void TestInsertSort()
{
    
    
	int a[] = {
    
     2,4,7,2,6,4,5,7,8,32,33,11 };
	int n = sizeof(a) / sizeof(a[0]);
	PrintArr(a, n);
	InsertSort(a, n);
	PrintArr(a, n);
}

int main()
{
    
    
	TestInsertSort();
	system("pause");
	return 0;
}

ここに画像の説明を挿入します

1.3機能の概要

直接挿入ソートの特徴の要約:

  1. 要素のセットが近いほど、直接挿入ソートアルゴリズムの時間効率が高くなります。
  2. 時間計算量:O(N ^ 2)
  3. スペースの複雑さ:O(1)、安定ソートアルゴリズムです
  4. 安定性:安定

第二に、ヒルソート

1.1基本的な考え方

ヒルソート法は、減増分法とも呼ばれます。ヒルソート方法の基本的な考え方は次のとおりです:
最初に整数ギャップ(通常はgap = gap / 3 + 1)を選択し、ソートする配列をギャップグループ分割し、ギャップの距離を持つすべての要素を同じグループに配置します、および各グループ内の要素が並べ替えられます。次に、整数ギャップ再選択し、上記のグループ化と並べ替えの作業繰り返します。場合時間= 1つのGAP、その後直接挿入ソートを実行し確保するためにすべてのこと要素順序付けします。

1.2コードの実装

同様に、配列の長さがn = 10、gap = gap / 3 + 1であると仮定し、最初に一連のソートコードを記述します。
ここに画像の説明を挿入します

  1. ギャップ= 4の場合、配列は(9,7,3)、(1,4,5)、(2,8)、(5,6)の4つのグループに分割され、これら4つのグループで挿入ソートを実行します。結果は(3,7,9)、(1,4,5)、(2,8)、(5,6)です。
    ギャップ= 4の並べ替えのプロセスをマスターした後、最初にこの並べ替えを記述しましょう。

まずが可変端アレイ9の最初の要素から= 0開始を定義する、次の要素はエンド+ギャップ要素は添字TMP挿入される下部が7で、我々は、としてマーク法律、端要素4行く、4を見つけることができます5の場合、endの区間添え字は[0,5]であると判断できます。通常、右側の区間を開いた区間に変換します。たまたま[0、n-gap)であることがわかります。信じられない場合は、ステップ2、3の分析を引き続き確認して、一連の並べ替えコードを記述できます。

gap = gap/3+1;
for (int i = 0; i < n - gap; ++i)	//i从0开始到n-gap结束
{
    
    
	int end = i;			
	int tmp = a[end + gap];			//每次增加gap的步长作为插入元素
	while (end >= 0)
	{
    
    
		if (tmp < a[end])			//如果待插入元素比end下标的元素小
		{
    
    
			a[end + gap] = a[end];	//1.end下标元素向后挪方便tmp的插入,这里end挪动的步长是gap而不是1了
			end -= gap;				//2.end左移进行下一轮的比较,同理左移gap步长
		}
		else       //如果待插入元素大于或等于end下标的元素退出循环
		{
    
    
			break;
		}

		a[end + gap] = tmp;	//将tmp插入到数组当中
	}
}

ここに画像の説明を挿入します

  1. ギャップ= 2、配列は2つのグループ(3,2,7,8,9)、(1,5,4,6,5)に分割され、これら2つのグループに対してそれぞれ挿入ソートを実行すると、結果は(2 、3、7、8、9)、(1、4、5、5、6)。このステップでは、終了の間隔が[0、8)、8 = n-gap = 10-2であることがわかります。

ここに画像の説明を挿入します

  1. ギャップ= 1、配列は2つのグループ(3,2,7,8,9)、(1,5,4,6,5)に分割され、これら2つのグループに対してそれぞれ挿入ソートを実行すると、結果は(2 、3、7、8、9)、(1、4、5、5、6)。このステップでは、終了の間隔が[0、9)、9 = n-gap = 10-1であることがわかります。また、このステップは、挿入ソートの終了の終了条件がn-1 = 10であることも証明します。 -1 = 9

ヒルソートの手順を理解したら、ギャップのループコードを4から2、次に1に記述するだけですこの手順は非常に簡単です。最初にgap = nを定義し、毎回gap = gap / 3 +1をループします。 、最後の+1は、ギャップが1に等しくなることを保証することです。これは、配列が正しいことを保証することです。

// 希尔排序
void ShellSort(int* a, int n)
{
    
    
	//1.gap>1时为预排序,让数列更接近有序
	//2.gap=1为直接插入排序,保证有序
	int gap = n;	
	while (gap > 1)
	{
    
    
		gap = gap / 3 + 1;					//通常的
		for (int i = 0; i < n - gap; ++i)	//i从0开始到n-gap结束
		{
    
    
			int end = i;			
			int tmp = a[end + gap];			//每次增加gap的步长作为插入元素
			while (end >= 0)
			{
    
    
				if (tmp < a[end])			//如果待插入元素比end下标的元素小
				{
    
    
					a[end + gap] = a[end];	//1.end下标元素向后挪方便tmp的插入,这里end挪动的不长是gap而不是1了
					end -= gap;				//2.end左移进行下一轮的比较,同理左移gap步长
				}
				else                        //如果待插入元素大于或等于end下标的元素退出循环
				{
    
    
					break;
				}

				a[end + gap] = tmp;				//将tmp插入到数组当中
			}
		}
	}
	
}

試験結果

void TestShellSort()
{
    
    
	int a[] = {
    
     2,4,7,2,6,4,5,7,8,32,33,11 };
	int n = sizeof(a) / sizeof(a[0]);
	PrintArr(a, n);
	ShellSort(a, n);
	PrintArr(a, n);
}
int main()
{
    
    
	//TestInsertSort();
	TestShellSort();
	system("pause");
	return 0;
}

ここに画像の説明を挿入します

1.3機能の概要

ヒルソーティングの機能の概要:

  1. ヒルソートは、直接挿入ソートの最適化です。
  2. ギャップ> 1の場合、それらはすべて事前にソートされています。目的は、配列を順序に近づけることです。ギャップ== 1の場合、配列はすでに順序に近いため、非常に高速になります。このようにして、全体として、最適化された効果を達成することができます。それを認識した後、パフォーマンステストを比較できます。
  3. ヒルソートの時間計算量は計算が容易ではなく、推定する必要があり、平均時間計算量は次のように導き出されます。O(N 1.3—N 2)
  4. 安定性:不安定

おすすめ

転載: blog.csdn.net/qq_40076022/article/details/112848217