データ構造---一般的な並べ替えとクイック並べ替え(c言語)

一般的に使用される並べ替え

バブルソート

バブルソートアルゴリズムのアイデア

  • 配列の先頭から始めて、隣接する2つの要素のサイズを継続的に比較、配列の最後まで、大きい方の要素を徐々に後方に移動させます(2つの要素の値を交換します)。比較の最初のラウンドの後、最大の要素が見つかり、最後の位置に移動できます。
  • 第1ラウンドの後、第2ラウンドに進みます。比較は依然として配列の先頭から行われ、大きい要素は配列の最後から2番目の要素まで徐々に後方に移動します。2回目の比較の後、次に大きい要素が見つかり、最後から2番目の位置に配置されます。
  • 同様に、** n-1(nは配列の長さ)**ラウンドの「バブリング」を実行した後、すべての要素を配置できます。

バブルソートC言語の実装

#include <stdio.h>

int main(){
    
    

    int nums[10] = {
    
    4, 5, 2, 10, 7, 1, 8, 3, 6, 9};
    int i, j, temp, isSorted;

    //优化算法:最多进行 n-1 轮比较

    for(i=0; i<10-1; i++){
    
    

        isSorted = 1; //假设剩下的元素已经排序好了

        for(j=0; j<10-1-i; j++){
    
    

            if(nums[j] > nums[j+1]){
    
    

                temp = nums[j];

                nums[j] = nums[j+1];

                nums[j+1] = temp;

                isSorted = 0; //一旦需要交换数组元素,就说明剩下的元素没有排序好

            }

        }

        if(isSorted) break; //如果没有发生交换,说明剩下的元素已经排序好了
}

    for(i=0; i<10; i++){
    
    

        printf("%d ", nums[i]);
    }

    printf("\n");

    return 0;
}

挿入ソート

単純挿入ソートアルゴリズムの原理

  • 並べ替えるシーケンス全体から要素を選択し、すでに順序付けられているサブシーケンスに挿入して、要素に1を加えた順序付けされたサブシーケンスを取得ます。シーケンス全体に挿入される要素が0になるまで、シーケンス全体がすべて順序付けられます。 。

実際のアルゴリズムでは、シーケンスの最初の要素を順序付けられたシーケンスとして選択することがよくあり(要素は確実に順序付けられているため)、シーケンス全体が順序付けられるまで、次の要素を前の順序付けられたシーケンスに徐々に挿入します。

概略図は次のとおりです。
ここに写真の説明を挿入

ソートコードの実装を挿入します。

#include <stdio.h>

/*
直接插入排序:
    直接插入排序就是从待排序列中选出一个元素,插入到已经有序的元素之中,直到所有的元素都插入到有序序列中所有的元素就全部
有序了。
    通常的做法就是将第一个元素看做是有序的元素(即待排序列的第一个元素看做是有序序列),然后我们将第二个元素和有序序列(即
第一个元素)作比较,按正确的序列插入到序列中去。然后在将第三个元素和前面有序序列(即整个待排序列的前两个元素)作比较,将第
三个插入到前两个元素中去,使得前三个元素有序。以此类推,直到所有的元素都有序。
*/

void insertSort(int *arr[],int len);

int main(int argc, char *argv[])
{
    
    
    int arr[5]={
    
    
        3,89,72,43,1
    };
    insertSort(arr,5);
    int i;
    for(i=0;i<5;i++){
    
    
        printf("%d ",arr[i]);
    }
    return 0;
}

/*
简单插入排序函数
*/
void insertSort(int *arr[],int len){
    
    
    int i;
    int j;
    int temp;  //定义一个临时变量,用于交换数据时存储
    for(i=1;i<len;i++){
    
      //因为我们要对该待排序列的每一个元素都和前面的已排好序的序列进行插入,所以我们会对序列进行遍历
        for(j=0;j<i;j++){
    
      //第二层循环主要用于对已排好序的序列进行扫描,和要插入进来的数据进行逐一比较,然后决定插入到哪里
            if(arr[j]>arr[i]){
    
    //从前往后对已排好序的元素和待插入元素进行大小比较,然后直到找到一个元素比被插入元素大,则交换位置
                temp=arr[i];
                arr[i]=arr[j];
                arr[j]=temp;
            }
        }
    }
}

並べ替えを選択

選択ソートアルゴリズムの原則

  • 選択ソートは、シンプルで直感的なソートアルゴリズムです。バブルソーティングと非常によく似ています。n-1ラウンドを比較します。各ラウンドはn–1–i回比較し、各ラウンドは最大値または最小値を見つけます。
  • ただし、バブルソートでは、各ラウンドで見つかった最大値が右端に配置され、選択的ソートでは、各ラウンドで検出された最大値が左端に配置されます。また、アルゴリズムでは、バブルソーティングとは、隣接する番号を1つずつ比較することです。例として、小さいものから大きいものへの並べ替えを取り上げます。前面が背面よりも大きい限り、最大の番号がフロートするまで2つの番号が交換されます。 「右端など。選択ソートでは、最初の要素の添え字を最初に保存してから、次のすべての番号を最初の要素と順番に比較します。小さい番号が見つかった場合は、小さい番号の添え字が記録され、次に次のすべての番号が記録されます。番号は、最小の番号の添え字が見つかるまで、小さい番号と順番に比較されます。次に、番号が左端に配置されます。つまり、添え字が0の番号が交換されます。最小数の添え字が0の場合、交換する必要はありません。
  • したがって、選択ソートアルゴリズムは、最初に最小番号の添え字が0であるかどうかを判断します。そうでない場合は、最小番号が最初の要素ではないことを意味します。次に、番号が最初の要素と交換され、ラウンド内の最小番号がその番号が見つかり、左端に配置されました。
  • 2回目のラウンドでは、新しいシーケンスの2番目の要素の添え字も保存され、後続のすべての番号が2番目の要素と順番に比較されます。小さい番号が検出された場合は、小さい番号の添え字が記録され、その後、後続のすべての番号が記録されます。の番号は、最後に最小の番号が見つかるまで、小さい番号と順番に比較されます。この最小の番号は、シーケンス全体で「2番目に小さい」番号です。次に、この番号の添え字が1に等しいかどうかを判断します。1に等しくない場合は、「2番目に小さい」番号が2番目の要素ではないことを意味し、番号と2番目の要素が交換されるため、2番目のラウンドは次のようになります。 「2番目に小さい」番号を見つけて、2番目の位置に配置します。シーケンス全体が小さいものから大きいものにソートされるまで、この方法を繰り返します。
  • 最大から最小にソートされている場合は、最大数の添え字を記録し、各ラウンドで最大数を見つけて左側に配置します。

ソートアルゴリズム実装の選択:

# include <stdio.h>
int main(void)
{
    
    
    int i, j;  //循环变量
    int MinIndex;  //保存最小的值的下标
    int buf;  //互换数据时的临时变量
    int a[] = {
    
    5, 5, 3, 7, 4, 2, 5, 4, 9, 1, 8, 6};
    int n = sizeof(a) / sizeof(a[0]);  //存放数组a中元素的个数
    for (i=0; i<n-1; ++i)  //n个数比较n-1轮
    {
    
    
        MinIndex = i;
        for (j=i+1; j<n; ++j)  //每轮比较n-1-i次, 找本轮最小数的下标
        {
    
    
            if (a[MinIndex] > a[j])
            {
    
    
                MinIndex = j;  //保存小的数的下标
            }
        }
        if (MinIndex != i)  /*找到最小数之后如果它的下标不是i则说明它不在最左边, 则互换位置*/
        {
    
    
            buf = a[MinIndex];
            a[MinIndex] = a[i];
            a[i] = buf;
        }
    }
    printf("最终排序结果为:\n");
    for (i=0; i<12; ++i)
    {
    
    
        printf("%d ", a[i]);
    }
    printf("\n");
    return 0;
}

マージソート

マージソートアルゴリズムの原理:

  • (マージソート)は、マージ操作に基づく効果的なソートアルゴリズムです。このアルゴリズムは、除算と征服の方法(除算と征服)を使用する非常に一般的なアプリケーションです。既存の順序付けられたサブシーケンスを組み合わせて、完全に順序付けられたシーケンスを取得します。つまり、最初に各サブシーケンスを順番に作成し、次にサブシーケンスを順番に作成します。2つの順序付きリストが1つの順序付きリストにマージされる場合、それは双方向マージと呼ばれ、使用時間のためにスペースを犠牲にするアルゴリズムです。

これは再印刷されたソースから来ています:
マージアルゴリズム:

マージアルゴリズムのコアステップは次のとおりです。

  • 壊す
  • マージ

ここに写真の説明を挿入

  • マージソートは、ソートされる要素のシーケンスの初期入力状態に依存しないため、2つのサブシーケンスの長さは、分割されるたびに基本的に同じになります。したがって、マージソートが最適であり、平均時間の複雑さの最悪および最悪はO(n * log2 ^ n)です。 )、安定した並べ替えアルゴリズムです
  • マージソートの最適化、つまり挿入ソートを使用して小規模なサブアレイを処理すると、通常、マージソートの実行時間を10%〜15%短縮できます。

マージアルゴリズムの実装(c言語)

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
 
//分组归并
void _Merge(int *a, int begin1, int end1, int begin2, int end2, int *tmp)
{
    
    
	int index = begin1;
	int i = begin1, j = begin2;
	//注意:当划分的区间足够小时,begin1==end1,begin2==end2
	while (i <= end1&&j <= end2){
    
    
		if (a[i]<=a[j])
			tmp[index++] = a[i++];
		else
			tmp[index++] = a[j++];
	}
	//将左边元素填充到tmp中
	while (i <= end1)
		tmp[index++] = a[i++];
	//将右边元素填充的tmp中
	while (j <= end2)
		tmp[index++] = a[j++];
	//将tmp中的数据拷贝到原数组对应的序列区间
	//注意:end2-begin1+1
	memcpy(a + begin1, tmp + begin1, sizeof(int)*(end2 - begin1 + 1));
}
//归并排序
void MergeSort(int *a, int left, int right, int *tmp)
{
    
    
	if (left >= right)
		return;
	assert(a);
	//mid将数组二分
	int mid = left + ((right - left) >> 1);
	//左边归并排序,使得左子序列有序
	MergeSort(a, left, mid, tmp);
	//右边归并排序,使得右子序列有序
	MergeSort(a, mid + 1, right, tmp);
	//将两个有序子数组合并
	_Merge(a, left, mid, mid + 1, right, tmp);
}
//打印数组
void PrintArray(int *a, int len)
{
    
    
	assert(a);
	for (int i = 0; i < len; i++)
		printf("%d ", a[i]);
	printf("\n");
}
int main()
{
    
    
	int a[] = {
    
     10, 6, 7, 1, 3, 9, 4, 2 };
	int *tmp = (int *)malloc(sizeof(int)*(sizeof(a) / sizeof(int)));
	memset(tmp, -1, sizeof(a) / sizeof(int));
	MergeSort(a, 0, sizeof(a) / sizeof(int)-1, tmp);
	PrintArray(a, sizeof(a) / sizeof(int));
	system("pause");
	return 0;
}

クイックソート

クイックソートアルゴリズムのアイデア:

  • 最初要素の特定の場所を見つけ、データを2つの部分に分割します
  • 左側のものは一般的に上記の方法に基づいています。要素の特定の位置を見つけて、それを2つの部分に分割することもできます。
  • 類推により、再帰的思考を使用して、最初の要素が最終的に見つかります
    ここに写真の説明を挿入

クイックソートの実装:

#include <stdio.h>
#include <stdlib.h>

int FindPos(int * a,int low,int high)
{
    
    
    int val = a[low];

    while(low < high)
    {
    
    
        while(low < high && a[high] <= val)
            --high;
        a[low] = a[high];

        while(low < high && a[low] <= val)
            ++low;
        a[high] = a[low];
    } //终止while循环之后,low和high一定是相等的
    a[low] = val;

    return low;   //low可以改为high,返回的是位置
}

void QuickSort(int * a,int low,int high)
{
    
    
    int pos;
    if(low < high)
    {
    
    
        pos = FindPos(a,low,high);
        QuickSort(a,low,pos-1);
        QuickSort(a,pos+1,high);
    }
}

int main()
{
    
    
    int a[6] = {
    
    -2,1,0,5,4,3};
    int i;
    QuickSort(a,0,5);   //第二个参数表示第一个元素的下标  第三个参数表示最后一个元素的下标
    for(i = 0; i < 6; ++i)
    {
    
    
        printf("%d",a[i]);
    }

    printf("\n");
    return 0;
}

おすすめ

転載: blog.csdn.net/qq_41782149/article/details/93378947