C++ を使用して、挿入ソート、ヒル ソート、バブル ソート、クイック ソート、および選択ソート アルゴリズムを実装します。
1. 挿入ソート
挿入ソートは、一般に直接挿入ソートとも呼ばれます。これは、少数の要素を並べ替える場合に効率的なアルゴリズムです。挿入ソートは最も単純なソート方法であり、その基本的な考え方は、ソートされた順序付きリストにレコードを挿入し、レコード数が 1 増加した新しい順序付きリストを生成することです。実装プロセスでは 2 層ループを使用し、外側のループで最初の要素を除くすべての要素を検索し、内側のループで現在の要素の前の順序付きリストに挿入する位置を検索して移動します。
挿入ソートは、多くの人がポーカーの手をソートするのと同じように機能します。左手を空にし、カードをテーブルの上に裏向きにして置きます。次に、テーブルからカードを一度に 1 枚ずつ取り出し、左手の正しい位置に挿入します。カードの正しい位置を見つけるには、すでに手札にあるすべてのカードと右から左に比較します。左手に持っているカードは常にソートされており、これらのカードがテーブルの山の一番上のカードであることがわかります。
挿入ソートとは、ソート対象の要素のうち、前の n-1 (n>=2) 個の番号がすでに順番に並んでいると仮定して、n 番目の番号を前に並べたシーケンスに挿入し、自分の位置に適したものを見つけることを意味します。 , そのため、n 番目の番号に挿入されるシーケンスも順序通りになります。この方法では、シーケンス全体がソートされるまですべての要素が挿入されます。これを挿入ソートと呼びます。
#include<iostream>
using namespace std;
int main()
{
int arr[6]={
9,7,6,5,4,3};
//遍历数组,依次进行比较
for(int i=0;i<5;i++){
/*
比较i和i+1,如果升序排序,则判断第i个元素是否大于第i+1个
元素,如果是,则将第i+1个元素依次与之前的所有元素进行比较并
排序,完成后将第i个元素插入到第i+1个元素的位置上。降序也是
同样的原理。
*/
if(arr[i]>arr[i+1]){
//交换
//从第i个元素开始交换
int j=i;
//将需要插入的元素使用变量temp保存
int temp=arr[i+1];
/**
将第i个元素之前的所有元素进行一次重新排序,保证第0-i个元素
之间是排好序的。
*/
while(j>=0&&temp<arr[j]){
arr[j+1]=arr[j];
j--;
}
arr[j+1]=temp;
}
}
//打印输出排序结果
for(int i=0;i<6;i++){
cout<<arr[i]<<" ";
}
}
2. ヒルソート
シェルのソートは、「ディミニシング インクリメント ソート」としても知られる挿入ソートの一種で、直接挿入ソート アルゴリズムのより効率的かつ改良されたバージョンです。ヒル ソートは不安定なソート アルゴリズムです。このメソッドは、1959 年に提案された DLShell にちなんで名付けられました。
ヒル ソートでは、添字の特定の増分によってレコードをグループ化し、直接挿入ソート アルゴリズムを使用して各グループをソートします。増分が徐々に減少するにつれて、各グループにはますます多くのキーワードが含まれます。増分が 1 に減少すると、ファイル全体がグループ化されると、アルゴリズムは終了します。
#include<iostream>
using namespace std;
int main()
{
int arr[6]={
9,7,6,5,4,3};
//控制步长
for(int gap=6/2;gap>0;gap/=2){
//遍历所有的组
for(int i=0;i<gap;i++){
//遍历每个组中的所有元素
for(int j=i-gap;j>=0;j-=gap){
/*
比较第j个元素和第j+gap个元素,不满足排序规则的交换
元素顺序。
*/
if(arr[j]>arr[j+gap]){
int t=arr[j];
arr[j]=arr[j+gap];
arr[j+gap]=t;
}
}
}
}
//打印输出排序结果
for(int i=0;i<6;i++){
cout<<arr[i]<<" ";
}
}
3. バブルソート
バブル ソートは、コンピューター サイエンスの分野における比較的単純な並べ替えアルゴリズムです。
ソート対象の要素の列を繰り返し訪問し、隣接する 2 つの要素を順番に比較し、順序 (大から小、頭文字 Z から A など) が間違っている場合は要素を交換します。要素を訪問する作業は、隣接する要素を交換する必要がなくなるまで、つまり要素列がソートされるまで繰り返されます。
このアルゴリズムの名前は、ちょうど炭酸飲料の二酸化炭素の泡が最終的に上部に浮かぶのと同じように、より小さい要素が交換によってシーケンスの上部に (昇順または降順で) ゆっくりと「浮く」という事実に由来しています。したがって、「バブリング」という名前が付けられています。
バブルソートアルゴリズムの原理は次のとおりです。
- 隣接する要素を比較します。最初のものが 2 番目のものより大きい場合は、両方を交換します。
- 隣接する要素の各ペアに対して、最初の最初のペアから最後の最後のペアまで同じことを行います。この時点では、最後の要素が最大の数値である必要があります。
- 最後の要素を除くすべての要素に対して上記の手順を繰り返します。
- 比較する数値のペアがなくなるまで、要素の数を減らしながら上記の手順を繰り返します。
#include <iostream>
using namespace std;
int main()
{
int array[8] = {
8,7,6,5,4,3,2,1};
//打印输出排序前的数组
cout<<"排序前的数组为:";
for (int i = 0; i < 8; i++){
cout<<array[i]<<" ";
}
//冒泡排序
for(int i=0;i<8;i++){
for(int j=0;j<8-1-i;j++){
if(array[j]>array[j+1]){
int temp=array[j];
array[j]=array[j+1];
array[j+1]=temp;
}
}
}
//打印输出排序后的数组
cout<<"\n排序后的数组为:";
for (int i = 0; i < 8; i++){
cout<<array[i]<<" ";
}
return 0;
}
4. クイックソート
クイック ソート アルゴリズムは、複数の比較と交換によるソートを実装しており、そのソート プロセスは次のとおりです。
(1) まずカットオフ値を設定し、カットオフ値を基準に配列を左右に分割します。
(2) カットオフ値以上のデータを配列の右側に集め、カットオフ値未満のデータを配列の左側に集めます。このとき、左側の各要素はカットオフ値より小さく、右側の各要素はカットオフ値以上になります。
(3) すると、左右のデータを独立してソートすることができます。左側の配列データの場合、境界値をとってデータのこの部分を左右に分割し、小さい値を左側に配置し、大きい値を右側に配置します。右側の配列データも同様に処理できます。
(4) 上記のプロセスを繰り返すと、これが再帰的定義であることがわかります。左部分を再帰的にソートした後、右部分の順序を再帰的にソートします。左部分と右部分のデータのソートが完了すると、配列全体のソートも完了します。
原理ソート対象の配列が A[0]...A[N-1] であると仮定すると、まずデータ (通常は配列の最初の番号) をキー データとしてランダムに選択し、それより小さいすべての番号を入れます。左側では、それより大きいすべての数値が右側に配置されます。このプロセスはクイック ソートと呼ばれます。クイックソートは安定した並べ替えアルゴリズムではないことに注意してください。つまり、複数の同一の値の相対位置がアルゴリズムの終了時に変わる可能性があります。
ワンパスクイックソートのアルゴリズムは次のとおりです。
1) ソート開始時に 2 つの変数 i、j を設定します: i=0、j=N-1;
2) 最初の配列要素をキー データとしてkeyに割り当てます。つまり、key = A[0];
3) j から前方検索、つまり後ろ (j–) から前方検索して、キーより小さい最初の値 A[j] を見つけ、A[j] と A[i] の値を交換します];
4) i から後方検索、つまり前方 (i++) から後方検索し、キーより大きい最初の A[i] を見つけ、A[i] と A[j] の値を交換します。
5) ステップ 3 と 4 を繰り返します。j; 手順 3 と 4 で、修飾された値が見つからない場合、つまり、3 の A[j] がkeyより小さくなく、 4 の A[i] がkeyより大きくない場合、 j の値を変更します。そして i は、見つかるまで j=j-1 、 i=i+1 になります。条件を満たす値を見つけて交換すると、i ポインタと j ポインタの位置は変わりません。さらに、私はj のプロセスは、i++ または j– が完了したときと正確に一致する必要があり、この時点でサイクルが終了します。
並べ替えデモ
初期シーケンス {xi} が 5、3、7、6、4、1、0、2、9、10、8 であるとします。
このとき、ref=5、i=1、j=11、後ろから前に見て、5より小さい最初の数字はx8=2なので、順序は、2、3、7、6、4、となります。 1、0、5、9、10、8。
このとき、i=1、j=8、前から後ろに見て、5 より大きい最初の数字は x3=7 なので、順序は 2、3、5、6、4、1、0、7、9 となります。 、10、8。
このとき、i=3、j=8、8桁目から見て、最初の5より小さい数字はx7=0なので、2、3、0、6、4、1、5、7、9、 10、8。
このとき、i=3、j=7、3位から見て最初の5より大きい数字はx4=6なので、2、3、0、5、4、1、6、7、9、10となります。 、8.
このとき、i=4、j=7、7桁目から見て、最初の5より小さい数字はx6=1なので、2、3、0、1、4、5、6、7、9、 10、8。
この時、i=4、j=6、4位から探索、6位まで、5より大きい数がある、この時、i=j=6、refが区切り線となり、前の数字それより小さく、その後の数字がそれより大きい場合は、前後2つの部分についても同様の方法でソートできます。
#include <iostream>
using namespace std;
void Qsort(int arr[], int low, int high){
if (high <= low){
return;
}
int left = low;
int right = high;
int key = arr[low];
while (true)
{
//将比key小的值放key左边,比key大的值放key右边
/*从左向右找比key大的值*/
while (arr[left] <= key)
{
left++;//从左往右,下标递增
//当遍历到最后一个元素时,结束循环
if (left == high){
break;
}
}
/*从右向左找比key小的值*/
while (arr[right] >= key)
{
right--; //从右往左,下标递减
//当遍历到第一个元素时,结束循环
if (right == low){
break;
}
}
// cout<<"left:"<<left<<" right:"<<right<<"\n";
/*
当比key小的数全在左边,比key大的数全在右边时,表
示第一次排序完成,结束循环
*/
if (left >= right){
break;
}
/*
将比key小的数移到左边,比key大的数移到右边,
交换left,right对应的值
*/
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
}
/*分别对左右两边的数字进行排序,
中枢值与right对应值交换*/
arr[low] = arr[right];
arr[right] = key;
Qsort(arr, low, right - 1);
Qsort(arr, right + 1, high);
}
int main()
{
int arr[] = {
52, 64, 59, 52, 75, 28, 98, 30, 25};
//获取数组长度
int len = sizeof(arr)/sizeof(arr[0]);
//打印排序前的数组
cout<<"排序前:";
for(int i = 0; i < len; i++)
{
cout << arr[i] << " ";
}
//调用快速排序函数
Qsort(arr, 0, len- 1);
//打印排序后的数组
cout<<"\n排序后:";
for(int i = 0; i < len; i++)
{
cout << arr[i] << " ";
}
return 0;
}
5、選択ソート
選択ソートは、シンプルで直感的なソート アルゴリズムです。その動作原理は次のとおりです。最初に並べ替えるデータ要素から最小 (または最大) 要素を選択し、それをシーケンスの開始位置に格納し、その後、並べ替えられていない残りの要素から最小 (最大) 要素を見つけます。そしてそれをソートされたシーケンスの最後に置きます。ソートされるすべてのデータ要素の数がゼロになるまで、同様に続きます。選択ソートは不安定なソート方法です。
ソートのアイデア: まず、ソートされていないシーケンス内で最小 (最大) の要素を見つけて、それをソートされたシーケンスの先頭に格納します。次に、引き続きソートされていない残りの要素から最小 (最大) の要素を見つけて、それをシーケンスの最後に置きます。ソートされたシーケンス。すべての要素がソートされるまで続きます。
具体的な実装方法:
①初期状態:非順序領域は R[0…n-1](合計 n 個の要素)、順序付き領域は空です。
②最初の仕分け
変数 i を設定し、i を 0 から n-2 まで循環させ、配列内の要素 i と要素 i+1 のサイズを比較します。R[i+1] が R[i] より小さい場合は、変数 k を使用します。彼の位置を覚えておいてください (つまり、k=i+1)。ループの終わりまでに、R 内の最小の数値の位置が見つかっているはずです。次に、最小の要素が R の最初の要素ではない場合は、R[0...0] と R[1...n-1] が次になるように最初の要素と値を交換させます。レコード数が 1 増加する新しい順序付けされた領域と、レコード数が 1 減少する新しい無秩序領域。
……
③i回目の旅行の仕分け
i 回目のソートが開始されると、現在の順序付き領域と順序なし領域はそれぞれ R[0...i-1] と R[i...n-1] になります。このソートでは、現在の非順序領域から最小のキーを持つレコード R[k] が選択され、それが非順序領域の最初のレコード R と交換され、R[0...i] と R がそれぞれレコード数になります。 1 増加した新しい秩序領域と、レコード数が減少した新しい無秩序領域。
図 1 の例: (最小値を見つけて選択を並べ替える)
#include<iostream>
using namespace std;
/*遍历寻找当前序列中的最小值,返回最小值的下标*/
int selectMin(int arr[],int i,int len){
int min=i;
for(;i<len;i++){
if(arr[i]<arr[min]){
min=i;
}
}
return min;
}
int main()
{
int arr[]={
5,8,2,4,1,6};
int len=sizeof(arr)/sizeof(arr[0]);
for(int i=0;i<len;i++){
//接收当前序列的最小值下标
int j=selectMin(arr,i,len);
//判断最小值是否为当前元素,如果不是,则交换最小值和当前元素的位置
if(i!=j){
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
for(int i=0;i<len;i++){
cout<<arr[i]<<" ";
}
}