C语言排序算法

数组的数据排序需要发生数据的交换,以下排序可能都会用到交换,所以先写下一个宏函数,功能为交换

#define swap(a,b) {typeof(a) temp=(a);(a)=(b);(b)=temp;}

冒泡排序:

    数据左右相比,把大的数据交换到右边,然后继续下两个数据左右相比,

    直到最大的数据交换到末尾,重复以上操作

   * 注意:在冒泡排序中一旦发现数据已经有序,立即停止排序,称为有序性敏感

    冒泡排序适合数据基本有序的情况,冒泡的效率非常高

    时间复杂度:最好O(n) 平均O(n^2)

    稳定性:稳定的

void bubble_sort(int* arr,size_t len)//把待排序的数组首地址、长度传过来
{
    bool flag = true;//解决有序性敏感
    for(int i = len-1;i>0&&flag;i--)
    {
        flag = false;
        for(int j=0;j<i;j++)
        {
            if(arr[j]>arr[j+1])
            {
				swap(arr[j],arr[j+1]);
				flag = true; 
            }
        }
    }
}

选择排序:

假定最开始的位置是最小值并记录下标min,然后与后面的数据进行比较,如果有比min为下标的数据更小的值,则更新min,如果比较后,min的位置发生了改变,则交换最开始的位置与min位置的值

    数据的交换次数少,实际的运行速度并不慢(数据交换要比赋值、数据比较耗时)

    选择排序相当于冒泡排序的变种,但是不存在有序性敏感,适合数据比较混乱情况会比冒泡快

    时间复杂度:O(n^2)

//选择排序
void select_sort(int* arr,size_t len)//把待排序的数组首地址、长度传过来
{
	for(int i=0;i<len-1;i++)
	{
		int min = i;
		for(int j = i+1;j<len;j++)
		{
			if(arr[j]<arr[min])
				min =j;
		}
		if(min != i)
			swap(arr[i],arr[min]);
	}
}

插入排序:

    把数据看成两部分,一部分是有序的,后一部分的数据与有序部分的数据逐个比较,直到找到合适的位置后,插入到该位置

    适合对已排序的数据新增数据后进行排序

    时间复杂度:O(n^2)

//插入排序
void insert_sort(int* arr,size_t len)//把待排序的数组首地址、长度传过来
{
	for(int i=1,j=0;i<len;i++)
	{
		int val =arr[i];
		for(j=i;j>0 && arr[j-1]>val;j--)
		{
			arr[j] = arr[j-1];
		}
		if(j!=i)
			arr[j] = val;
	}
}

希尔排序:

    是插入排序的增强版,由于插入排序数据移动速度比较慢,如果待排序数据很混乱时,效率比较低

    因此引入增量的概念,数据间隔增量个数进行插入排序,然后不停的缩小一倍增量,直到增量为1,此时数据从很混乱变为接近有序,以此提高排序的效率

    时间复杂度:O(nlogn)

    稳定性:不稳定的

void shell_sort(int* arr,size_t len)//把待排序的数组首地址、长度传过来
{
	for(int k = len/2;k>0;k/=2)
	{
		for(int i=k,j=0;i<len;i++)
		{
			int val = arr[i];
			for(j=i;j-k>=0 && arr[j-k] >val;j-=k)
			{
				arr[j] = arr[j-k];
			}
			if(j!=i) arr[j] =val;
		}
	}
}

快速排序:

        1、在中间位置确定为标杆p,备份标杆的数据为val

        2、在左边找到比val大的数据,找到后位置为l,把该数据赋值给p位置,更新p为l

        3、 然后从右边找比val小的数据,找到后位置为r,然后把该数据 赋值给p位置,更新p为r

        4、重复以上过程

        5、直到l和r相遇时,结束此次排序,最后把val还原赋值给p位置

        6、最终p左边都比val小,右边都比val大,实现局部有序,

        7、继续对左边部分和右边部分快排,直到全部有序

    注:

        快排的综合性是最高的,因此称为快排,也是比试中最常考的排序算法

        时间复杂度:O(nlogn)

        稳定性:不稳定的

//快速排序
void _quick_sort(int* arr,int left,int right)//调用此函数实现快排功能
{
	if(left >= right) return;
	//记录左右标杆
	int l = left,r = right;
	//找到中间位置标杆
	int p = (l+r)/2;
	//备份标杆的值
	int val = arr[p];
	while(l < r)
	{
		//从p左边找比val大的值
		while(l < p && arr[l] <= val) l++;
		//如果找到了
		if(l < p)
		{
			arr[p] = arr[l];
			p = l;
		}
		//从p的右边找比val小的值
		while(r > p && arr[r] >=val) r--;
		//如果找到了
		if(r > p)
		{
			arr[p] = arr[r];
			p = r;
		}
	}
	//还原标杆的值
	arr[p] = val;
	_quick_sort(arr,left,p-1);
	_quick_sort(arr,p+1,right);
}

void quick_sort(int* arr,size_t len)//把待排序的数组首地址、长度传过来
{
	_quick_sort(arr,0,len-1);
	
}

附:数据结构可视化网址:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值