C语言中笔试必须掌握的四大排序算法

每日一句

Take care of yourself.
照顾好你你自己

内容

昨天写一道关于排序的题,就顺势复习一下写一篇关于排序的博客好了。

C语言中排序有很多种,但是笔试题中最多的还是四种排序算法,也就是,冒泡排序,插入排序,快速排序和选择排序,还有很多像是希尔排序堆排序等,都没有在笔试题中看到这里就不介绍了。

排序的时间复杂度

排序法时间复杂度最大时间复杂度是否稳定
冒泡O(n^2)O(n^2)稳定
选择O(n^2)O(n^2)不稳定
插入O(n^2)O(n^2)稳定
快排O(nlogn)O(n^2)不稳定

一般两层循环的时间复杂度就是O(n^2),但是为什么快排有个最大时间复杂度呢,看到快速排序你就会知道。

冒泡排序(Bubble sort)

大名鼎鼎的冒泡排序必须放在第一个介绍,它是很多公司笔试题中都会出现的一道题。首先来看看它的排序过程。
图片是通过 https://visualgo.net/en 模拟出来的,大家兴趣可以去看一下,里面有很多常用的算法图解,很好用
在这里插入图片描述
它的原理是:比较相邻的元素,如果前面一个比后面一个大(小),那么就交换两个数的位置,然后一直往后(前)比较,每次循环都会得到一个最大(小)的数。
知道了原理我们再写就很好写了。
为了代码看起来简洁,我用一个交换函数来交换两个数和一个计算长度的函数来计算长度

void swapNum(int *a, int *b) //交换两个数
{
	int tmp;
	tmp = *a;
	*a = *b;
	*b = tmp;
}

int arrlen(int *arr)  //计算数组长度
{
	int i = 0;
	while(*(arr+i) != -1)
	{
		i++;
	}
	return i;
}

冒泡排序算法:

void bubbleSort(int *arr)
{
    int i, j;
	
    for(i = 0; i < arrlen(arr)-1; i++)
    {
        for(j = 1; j < arrlen(arr); j++)
        {
            if(arr[j] < arr[j - 1])
            {
				swapNum(&arr[j],&arr[j-1]);
            }
			//printnum(arr);
        }
    }
}

可能看起来有点复杂,其实只是这两个函数带来了代码量,个人习惯,也可以直接在函数参数里传一个数组长度来直接计算,这样写的好处是对动态数组的处理。
printnum()函数就是一个遍历打印,加上就可以看到它的冒泡过程,很形象。

选择排序(Selection sort)

还是来看看图解:
在这里插入图片描述
算法原理:在未排序的数列中找到最大(小)的数,放到已排序的数列末尾。

void selectionSort(int *arr)
{
	int min;
	int i = 0, j;
	for(; i < arrlen(arr)-1; i++)
	{
		min = i;
		for(j = i+1; j < arrlen(arr); j++)
		{
			if(arr[j] < arr[min])
				min = j;
		}
		swapNum(&arr[i],&arr[min]);
	}
}

插入排序(Insertion sort)

动图:
在这里插入图片描述
原理:默认第一个数已排序,从第二个数开始,将要排序的数依次跟前面的数比较,如果要排序的数比前面的数要小(大),就将前面的数往后移(或交换),直到遇到大于或等于要排序的数,就将这个数插入即可。

看代码:

void insertionSort(int *arr)
{
	int n,index;
	int i = 1;
	for(; i < arrlen(arr); i++)
	{
		n = i-1;
		index = arr[i];
		while(n > 0 && arr[n]>index)
		{
			arr[n + 1] = arr[n];
			n--;
		}
		arr[n+1] = index;
	}
}

快速排序(Quick sort)

动图
在这里插入图片描述

原理:快排对于数据量大的时候是比较好用的,它是将第一个数作为基准值,将比这个基准值小的数放在它的左边,将比这个基准值大的数放在它的右边,形成两个分区,再对这两个分区重复上述操作,直到各分区只有一个数为止。
在这里插入图片描述

还有一种方法是进入函数时就以中间那个值为基准值,然后将左边和右边分为两块分别递归,但实际操作比将第一个数作为基准值更复杂。
代码:(以第一个数为基准值)

void quickSort2(int *arr, int left, int right)
{
	int mid = left , i = left+1, index = mid + 1;
	if(right <= left) // 递归结束条件
		return ;
	while(i < right) //循环遍历,分组数据。
	{
		if(arr[i] < arr[mid])
		{
			swap(&arr[i],&arr[index]);
			index ++;
		}		
		i++;
	}
	index -= 1;
	swapNum(&arr[mid],&arr[index]);
	quickSort2(arr,left,index); 
	quickSort2(arr,index+1,right);
}

以中间数值数为基准值:

void quickSort(int *arr, int left, int right)
{
	int mid = left + (right-left)/2, i = left;
	int index = 0;
	if(right <= left)
		return ;
	
	int tmp,temp;
	temp = arr[mid];
	while(i <= right)
	{
		if(arr[i] < temp)
		{
			swapNum(&arr[i],&arr[left+index]);
			index ++;
		}
		if(arr[i] == temp)
		{
			tmp = i;
		}		
		i++;
	}
	swapNum(&arr[tmp],&arr[left+index]);
	quickSort(arr,left,left+index);
	quickSort(arr,left+index+1,right);
}

这种排序法用到了递归,所以对递归也有要求,如果对递归又兴趣的小伙伴可以去搜索汉诺塔问题,最经典的递归算法。
最后献上我的主函数,可动态申请空间

void printnum(int *arr)
{
	int i = 0;
	for(;i <arrlen(arr); i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}

int main()
{
	int *a = malloc(sizeof(int)*10);
	int i = 0;
	while(~scanf("%d", a+i))
	{
		if(*(a+i) == -1)
			break;
		i++;
	} 
	//bubbleSort(a);
	//selectSort(a);
	//insertionSort(a);
	quickSort2(a,0,arrlen(a)-1);
	printnum(a);
	return 0;
}

感谢观看,如有疑问,欢迎指出。

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值