归并排序+计数排序【C语言数据结构】

目录

一、归并排序

1.递归方法

归并排序主体部分的定义

归并排序调用部分的定义

2.非递归方法

1.方法一 (修边界法)

2.跳出循环法

二、计数排序


一、归并排序

归并排序的核心思想就是分而治之的思想。

对于一整个数组去直接排序比较复杂,我们可以将整个数组二分成一个个小部分,然后进行排序。

从下图中,我们可以看到,我们首先将整个数组二分,然后对每相邻的两端进行归并,并最终得到我们排序完之后的结果。

 归并排序+计数排序【C语言数据结构】_第1张图片

归并排序

 

1.递归方法

归并排序主体部分的定义

//定义我们归并排序的函数,
//第一个参数为我们待排序的数组
//第二个参数为我们的起始值
//第三个参数为我们的结束值
//第四个参数为我们辅助排序的数组
void _MergeSort(int*a,int begin,int end ,int*tmp)
{
//设置我们递归返回的条件
    if(begin>=end)
        return;
//找到我们的中间元素,便于我们下面的二分操作
    int mid=(begin+end)/2;
//我们的归并排序所采用的是类似于二叉树的后序遍历的操作。
//因为从我们上面的图中可以看出,我们首先需要将我们的数组二分成最小的部分,然后进行归并。
//这里我们需要将我们的前半段和后半段分别递归
    _MergeSort(a,begin,mid,tmp);
    _MergeSort(a,mid+1,end,tmp);

    //归并
//begin1和end1为我们第一段的起始值和结束值
//begin2和end2为我们第二段的起始值和结束值
    int begin1=begin,end1=mid;
    int begin2=mid+1,end2=end;
//用i作为我们临时数组的伪指针
    int i=begin1;
//当我们的前后两段都没有被取完的时候
    while(begin1<=end1&&begin2<=end2)
    {
//使用begin1与begin2作为我们前半段和后半段的数组指针
        if(a[begin1]>a[begin2])
        {
//将我们比较小的元素放入我们的临时数组中
            tmp[i++]=a[begin2++];
        }
        else
        {
            tmp[i++]=a[begin1++];
        }
    }
//当代码运行到这个位置,前半段和后半段一定有一个已经被取空了,
//如果是前半段被取空了,那就说明后半段区间剩下的元素一定比我们前半段的元素的大,
//所以直接将我们后半段元素剩下的部分链接到我们的临时数组的后面,反之同理
    while(begin1<=end1)
    {
        tmp[i++]=a[begin1++];
    }
    while(begin2<=end2)
    {
        tmp[i++]=a[begin2++];
    }
//将我们排序好的部分拷贝到我们的原来的待排序的数组
    memcpy(a+begin,tmp+begin,(end-begin+1)*sizeof(int));
}

归并排序调用部分的定义

//定义我们归并排序函数,第一个参数为我们的待排序数组,第二个参数为我们待排序数组的元素个数
void MergeSort(int* a, int n)
{
//开辟一块临时空间用来辅助我们的排序
    int *tmp=malloc(sizeof(int)*n);
//判断是否开辟成功
    if(tmp==NULL)
    {
        printf("malloc fail\n");
        exit(1);
    }
//调用我们上述的排序
    _MergeSort(a,0,n-1,tmp);
//释放我们的临时空间
    free(tmp);
}

2.非递归方法

非递归的方法就需要我们手动将我们的数组分段,然后对相邻两段进行归并操作,最终得到我们的结果。

归并排序+计数排序【C语言数据结构】_第2张图片

1.方法一 (修边界法)

void MergeSortNonR(int* a, int n)
{
    //开辟一块空间存储临时数组
    int*tmp=(int*)malloc(sizeof(int)*n);
//判断是否开辟成功
    if(tmp==NULL)
    {
        printf("malloc failed\n");
        exit(-1);
    }
//仿照我们上述图,我们首先将我们的全部数组划分成一个一个的单位
    int gap=1;
//当我们的分组大于我们的n的时候只会生成一组,也就是说我们的归并排序已经完成了。
    while (gap=n)
            {
                end1=n-1;
                begin2=n;
                end2=n-1;
            }
//如果我们的第二段区间已经大于等于我们的n,也就是说我们的第二段区间不存在(我们的数组下标为0到n-1)
//同上,我们需要将我们的第二段区间的边界值修饰为不存在。
            else if(begin2>=n)
            {
                begin2=n;
                end2=n-1;
            }
//如果我们第二段区间的结尾边界超出了我们的边界,我们只需要将我们的结尾调整到最后一个元素的位置即可
            else if(end2>=n)
            {
                end2=n-1;
            }
//下面进行我们的归并操作,其操作与我们上述的递归版本的排序方法是一样的。
            int j=begin1;
            while(begin1<=end1&&begin2<=end2)
            {
                if(a[begin1]

2.跳出循环法

void MergeSortNonR(int* a, int n)
{
    //开辟一块空间存储临时数组
    int*tmp=(int*)malloc(sizeof(int)*n);
    if(tmp==NULL)
    {
        printf("malloc failed\n");
        exit(-1);
    }
    int gap=1;
    while (gap=n||begin2>=n)
            {
                break;
            }
            else if(end2>=n)
            {
                end2=n-1;
            }
            int m=end2-begin1+1;

            int j=begin1;
            while(begin1<=end1&&begin2<=end2)
            {
                if(a[begin1]

二、计数排序

计数排序的核心思想就是统计我们待排序数组中每一个元素的出现过的次数,然后按照元素的大小从前往后输出。

void CountSort(int* a, int n)
{
//首先定义我们的最小值和最大值,这样定义的话,我们只需要创建max-min个元素的数组
//就可以大大减少我们空间上的开辟大小
    int min=a[0],max=a[0];
//分别寻找我们的最大值和最小值
    for(int i=1;imax)
        {
            max=a[i];
        }
    }
//生成我们的最大值减最小值个数组元素区间
    int range=max-min+1;
//开辟我们统计数组的大小
    int*count=(int*)malloc(sizeof(int)*range);
//判断是否开辟成功
    if(count==NULL)
    {
        printf("malloc faild\n");
        exit(-1);
    }
//将我们统计数组的每一个元素置空,也就是0
    memset(count,0,sizeof(int)*range);
//统计我们的每一个元素的个数,这里不要忘了我们需要将我们每一个元素的数值大小减去我们的最小值
    for(int i=0;i

 

你可能感兴趣的:(数据结构(C/C++),排序,数据结构,c语言,排序算法)