• 排序3——C语言


    1. 归并排序

    归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。

    思路:将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
    下图为归并的全过程
    在这里插入图片描述
    将序列分割,若子区间无序,对子区间再分割,直至子区间有序(只有一个数时)再进行合并(相当于合并两个有序数组)。合并数据时,不能直接覆盖再原数组,会造成数据丢失,因此需要开辟一个辅助数组。

    //归并排序
    //复杂度O(N*logN)
    void _MergeSort(int* array, int* tmp, int begin, int end)//左右闭区间
    {
    	//只有一个值,不用归并
    	if (begin == end)
    		return;
    
    	//分成两组分别递归,归并
    	int mid = (begin + end) / 2;
    	_MergeSort(array, tmp, begin, mid);
    	_MergeSort(array, tmp, mid + 1, end);
    
    	int begin1 = begin, end1 = mid;
    	int begin2 = mid + 1, end2 = end;
    	int i = begin;
     
        //归并过程
    	while (begin1 <= end1 && begin2 <= end2)
    	{
    		if (array[begin1] <= array[begin2])
    		{
    			tmp[i++] = array[begin1++];
    		}
    		else
    		{
    			tmp[i++] = array[begin2++];
    		}
    	}
    
    	while (begin1 <= end1)
    	{
    		tmp[i++] = array[begin1++];
    	}
    	while (begin2 <= end2)
    	{
    		tmp[i++] = array[begin2++];
    	}
    
    	//拷贝回原数组
    	memcpy(array + begin, tmp + begin, sizeof(int) * (end - begin + 1));
    }
    
    void MergeSort(int* array, int numsArr)
    {
    	//开辟辅助数组
    	int* tmp = (int*)malloc(sizeof(int) * numsArr);
    	if (tmp == NULL)
    	{
    		return;
    	}
    
    	_MergeSort(array, tmp, 0, numsArr - 1);
    
    	free(tmp);
    	tmp = NULL;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    归并排序的缺点,空间复杂度为O(N),即额外需要一块辅助空间。

    2. 计数排序

    计数排序的思路:

    1. 统计相同元素出现次数(遍历一遍数据即可)
    2. 根据统计的结果将序列回收到原来的序列中

    举例如下图
    在这里插入图片描述
    这里会面临两个问题

    1. 数据过大,数据范围分散
    2. 数据有负数,下标没有负数
      问题一会导致一个问题,开的辅助空间很大,比如数据为{ 1 ,19 ,33,50,69},五个数需要开辟70个空间,太浪费。事实上,计数排序不适用于数据范围分散的情况,如果当数据范围很大很 分数时,就不要采用计数排序了。

    问题二可以采用相对映射的方法来解决。让每一个数都减去最小值,那么如果有负数,减去最小值(也是负数,可能是本身)之后的值肯定大于等于0,就可以满足数组的下标了。还原回去时,数据再加上最小值即可。

    //计数排序
    //时间复杂度O(N+range),空间复杂度O(range)
    //适合于数据范围小的情况
    void CountSort(int* array, int numsArr)
    {
        //最大最小值
    	int max = array[0], min = array[0];
    	for (int i = 1; i < numsArr; i++)
    	{
    		if (array[i] < min)
    			min = array[i];
    		if (array[i] > max)
    			max = array[i];
    	}
        //开空间
    	int range = max - min + 1;
    	int* count = (int*)calloc(range, sizeof(int));
    	if (count == NULL)
    		return;
    
    	//统计每个数出现的次数(相对映射)
    	for (int i = 0; i < numsArr; i++)
    	{
    		count[array[i] - min]++;
    	}
    	//修改数组
    	int j = 0;
    	for (int i = 0; i < range; i++)
    	{
    		while (count[i]--)
    		{
    			array[j++] = i + min;
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    3. 各排序的稳定性及复杂度

    有关常见排序就介绍完毕了,总结一下复杂度和稳定性。一个排序的稳定性是指,两个相同的值在排序前后的相对位置没有改变,则该排序为稳定排序。否则不稳定。

    冒泡排序
    相邻数据不等才会进行交换,因此为稳定排序。时间复杂度:O(N^2)空间复杂度O(1)

    直接插入排序
    数据不相等才会进行插入,两个相等的数,在插入前后不会改变相对位置,因此为稳定排序
    时间复杂度O(N^2)空间复杂度O(1)

    归并排序
    稳定排序,时间复杂度O(N*logN)空间复杂度O(N)

    希尔排序
    不稳定排序,且看下面的例子。时间复杂度O(N^1.3)空间复杂度O(1)
    在这里插入图片描述
    直接选择排序
    不稳定,例子如下图,时间复杂度O(N^2)空间复杂度O(1)
    在这里插入图片描述
    堆排序
    不稳定,例子如下图,时间复杂度O(N*logN)空间复杂度O(1)
    在这里插入图片描述

    快速排序
    不稳定,例子如下图,时间复杂度O(N*logN)空间复杂度O(logN)
    在这里插入图片描述
    总结:三稳定四不稳定。关于常用排序就介绍完了。

  • 相关阅读:
    SpringBoot笔记
    HttpURLConnection详解及使用
    python编程小知识tips 20220720
    单元测试方法-cmockery实践
    什么是AMQP?
    为什么要用scrapy爬虫库?而不是纯python进行爬虫?
    Win10 180天后怎么才能继续体验,自动保持续期,无需手动JH
    22-07-20 西安 SpringCloud(01)
    黑马程序员微服务Docker实用篇
    缓存篇—缓存雪崩
  • 原文地址:https://blog.csdn.net/qq_74245477/article/details/138160096