归并排序算法(C语言)

本文详细介绍了归并排序的原理及其实现方式,包括递归式和循环式的代码示例,并分析了其时间复杂度和空间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

归并排序:
思想:利用将两个的有序数据序列合并成一个新的有序数据序列,在如何分成两个有序数据的问题下,采用分治算法。


时间复杂度:O(n*logn)
空间复杂度:O(n)
是否稳定: 稳定


这里写图片描述


代码实现如下:

1。递归式

#include <stdio.h>
#include <windows.h>
#include <malloc.h>
#include <string.h>
#pragma warning (disable:4996)

void MergeData(int* arr, int left, int mid, int  right, int* tmp)
{
    int begin1 = left;
    int end1 = mid;
    int begin2 = mid;
    int end2 = right;
    int count = left;

    while ((begin1 < end1) && (begin2 < end2))// 两个有序数组的合并
    {
        if (arr[begin1] <= arr[begin2])
        {
            tmp[count++] = arr[begin1++];
        }
        else{
            tmp[count++] = arr[begin2++];
        }
    }

    while (begin1 < end1) { //第二个数组已全部注入到排序数组中,第一数组有剩余元素
        tmp[count++] = arr[begin1++];
    }

    while (begin2 < end2) { //第二个数组未排完
        tmp[count++] = arr[begin2++];
    }
}
//区间为左闭右开 [)
void MergeSort(int* arr, int left, int right, int* tmp)//分治算法
{
    if (right - left > 1)//递归出口
    {
        int mid = left + ((right - left) >> 1);
        MergeSort(arr, left, mid, tmp);
        MergeSort(arr, mid , right, tmp);
        MergeData(arr, left, mid, right, tmp);//数据排序
        memcpy(arr + left , tmp + left, sizeof(arr[0]) * (right - left));//拷贝排序已好的数据
    }

}

void Sort(int* arr, int size) //开辟一个辅助空间
{
    int* tmp = (int*)malloc(sizeof(arr[0])*size);//申请空间
    if (NULL == tmp) //检验空间是否申请成功
        return;
    MergeSort(arr, 0, size, tmp);
    free(tmp);//堆上空间用完要释放,否则导致内存泄露
}

void printf_arr(int arr[],int size) //打印数组
{
    int i = 0;
    for (; i < size; i++)
    {
        printf("%d ", arr[i]);
    }
}
int main()
{
    //int arr[10] = {2,7,1,4,3,9,6,0,5,8};
    int arr[10] = { 4,4,6,7,3,0,9,3,5,2 };
    int size = sizeof(arr) / sizeof(arr[0]);

    Sort(arr, size);
    printf_arr(arr, size);

    system("pause");
    return 0;
}

2。循环式


#include <stdio.h>
#include <windows.h>
#include <malloc.h>
#include <string.h>
#pragma warning (disable:4996)

void MergeData(int* arr, int left, int mid, int  right, int* tmp)
{
    int begin1 = left;
    int end1 = mid;
    int begin2 = mid;
    int end2 = right;
    int count = left;

    while ((begin1 < end1) && (begin2 < end2))
    {
        if (arr[begin1] <= arr[begin2])
        {
            tmp[count++] = arr[begin1++];
        }
        else{
            tmp[count++] = arr[begin2++];
        }
    }

    while (begin1 < end1) { 
        tmp[count++] = arr[begin1++];
    }

    while (begin2 < end2) {
        tmp[count++] = arr[begin2++];
    }
}

void R_MergeSort(int* arr, int size)
{
    int* tmp = (int*)malloc(sizeof(arr[0])*size);
    if (NULL == tmp)
        return ;
    int gap = 1;
    int left, mid, right;
    int i;
    while (gap < size)
    {
        for (i = 0; i < size; i += 2*gap)
        {
            left = i;
            mid = left + gap;
            if (mid > size){
                mid = size;
            }
            right = mid + gap;
            if (right > size){
                right = size;
            }
            MergeData(arr, left, mid, right, tmp);
        }
        memcpy(arr, tmp, sizeof(arr[0]) * size);
        gap *= 2;
    }

    free(tmp);
}


void printf_arr(int arr[],int size) 
{
    int i = 0;
    for (; i < size; i++)
    {
        printf("%d ", arr[i]);
    }
}
int main()
{
    //int arr[10] = {2,7,1,4,3,9,6,0,5,8};
    int arr[10] = { 4,4,6,7,3,0,9,3,5,2 };
    int size = sizeof(arr) / sizeof(arr[0]);

    R_MergeSort(arr, size);
    printf_arr(arr, size);

    system("pause");
    return 0;
}
二路归并排序是一种高效的排序算法,它结合了分治策略和归并操作,将数组分成两个独立的部分分别进行排序,然后将结果合并。下面是使用C语言实现的基本步骤: 1. **划分**:将待排序的数组分为两部分,通常根据数组长度的一半进行划分。 2. **递归排序**:对每部分递归地应用二路归并排序,直到每个部分只剩一个元素(这已经是有序的)。 3. **合并**:将两个已排序的部分合并成一个有序的数组。这个过程是通过比较两个指针指向的元素,将较小的元素放入结果数组,然后移动对应的指针。 以下是一个简单的C语言版本的二路归并排序代码示例: ```c #include <stdio.h> #include <stdlib.h> // 归并两个已排序的区间 void merge(int *arr, int left, int mid, int right) { int i, j, k; int n1 = mid - left + 1; int n2 = right - mid; // 创建临时数组 int L[n1], R[n2]; for (i = 0; i < n1; i++) L[i] = arr[left + i]; for (j = 0; j < n2; j++) R[j] = arr[mid + 1 + j]; i = 0; j = 0; k = left; while (i < n1 && j < n2) { if (L[i] <= R[j]) arr[k++] = L[i++]; else arr[k++] = R[j++]; } // 将剩余未复制的元素添加到结果数组 while (i < n1) arr[k++] = L[i++]; while (j < n2) arr[k++] = R[j++]; } // 二路归并排序函数 void mergeSort(int *arr, int left, int right) { if (left < right) { int mid = left + (right - left) / 2; mergeSort(arr, left, mid); mergeSort(arr, mid + 1, right); // 合并 merge(arr, left, mid, right); } } int main() { int arr[] = {9, 7, 5, 11, 12, 2, 14, 3, 10}; int n = sizeof(arr) / sizeof(arr); printf("Before sorting:\n"); for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } mergeSort(arr, 0, n - 1); printf("\nAfter sorting:\n"); for (int i = 0; i < n; i++) { printf("%d ", arr[i]); } return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值