常见八大排序(纯C语言版)

目录

基本排序

一.冒泡排序

二.选择排序

三.插入排序

进阶排序(递归实现)

一.快排hoare排序

1.单趟排序

快排步凑

快排的优化

(1)三数取中

(2)小区间优化

二.前后指针法(递归实现)

三.快排的非递归实现(前后指针法的非递归)

快排的挖坑法的实现

二.堆排序

1.建堆的选择

2.堆排序的实现

二希尔排序

三.归并排序(递归实现与非递归的实现)

归并排序(非递归实现)

四.非比较排序(计数排序)

计数排序的缺陷

五.排序总结

稳定性的概念

六,排序的选择题练习与巩固


欢迎各位大佬的关顾,能给个赞就好了QWQ,由于篇幅很大,可以根据目录跳转你想看的排序哦!!

基本排序

一.冒泡排序

冒泡排序即,每次相邻比较排序,每次将最小或最大固定在数组最后

void BubbleSort(int* arr, int len)
{
	for (int i = 0; i < len; i++)
	{
		int flag = 1;
		for (int j = 0; j < len - i-1; j++)
		{
			if (arr[j] > arr[j+1])
			{
				flag = 0;
				Swap(&arr[j + 1],&arr[j]);
			}
		}
		if (flag)
			break;
	}
}

二.选择排序

很明显选择排序就是去找最小或者最大的下标然后赋值给原始位置,代码实现如下

void SelectSort(int* arr, int 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;
		}
		Swap(&arr[min], &arr[i]);
	}
}

但是这种选择排序也太low了让我们来实现一个Plus版本,一次循环找到最大与最小

int SelectSortPlus(int* arr, int len)
{
	int begin = 0;
	int end = len - 1;
	for (int i = begin; i <=end-1; i++)
	{
		int min = begin;
		int max = begin;
		for (int j = i+1; j <= end; j++)
		{
			if (arr[j] < arr[min])
				min = j;
			if (arr[j] > arr[max])
				max = j;
		}
		Swap(&arr[begin], &arr[min]);
		if (begin == max)//注意这里当begin与max的下标一样的时候,会被先换导致bug
			max = min;
		Swap(&arr[end], &arr[max]);
		begin++;
		end--;
	}
}

三.插入排序

看动图可以很容易的理解插入排序就是将已排好的序的后一个与前面的进行比较,比它大或小的往后移动

void InsertSort(int* a, int len)
{
	for (int i = 0; i < len - 1; i++)
	{
		int end = i;
		int temp = a[end + 1];
		while (end >= 0)
		{
			if (temp < a[end])
			{
				a[end + 1] = a[end];
				end--;
			}
			else
			{
				break;
			}
			a[end + 1] = temp;
		}
	}
}

进阶排序(递归实现)

一.快排hoare排序

快排有着多种实现方式我们下面这个是hoare(创始人)的排序方式

快速排序是一种高效的排序现在来让我们来实现一下

1.单趟排序

想要写出一个排序首先我们要去理解这个排序的单趟 单趟如图所示

如图我们可以发现它的步骤如下

快排步凑

(1)选出基准值key 为 left

(2)右边r先走找到比key小的停止

(3)右边r找到的情况下,左边L再开始找比key大的值

(3)左边L找到的情况下停止,将这两个值进行交换

循环上面的操作

直到他们相遇,将相遇的位置的值与key值交换

这就是快排的单趟排序,接下来让我们来实现一下

void QuickSort2(int* arr, int left, int right)
{
		int key = left;
		int begin = left;
		int end = right;
		while (begin < end)
		{
			//先从右边开始找小 //注意结束条件 begin一定<end
			while (begin < end && arr[end] >= arr[key])
			{
				--end;
			}
			//再从左边找大
			while (begin < end && arr[begin] <= arr[key])
			{
				++begin;
			}
			//两边都找到了之后进行交换
			Swap(&arr[begin], &arr[end]);
		}
		//最后相遇再与key交换
		Swap(&arr[begin], &arr[key]);
	}
}

想必这里大家会有一些疑问,为什么

1.为什么要右边先走,左边先走可以吗

2.为什么最后交换key的位置就固定了

3.要怎么样才能实现排序的效果

循环的实现,既然单趟可以固定住key值在整个数里面的想要排序的位置,那我们可不可以将这个数组进行分割[left~key-1]key[key+1~right]

运用递归来实现呢

答案是肯定的

只需要每次递归进行分割,固定n的值的位置,如下图所示

如图所示很明显当我们进行递归的时候每次的位置都将被固定,从而实现了排序

代码如下

void QuickSort2(int* arr, int left, int right)
{
	//返回条件
	if (left >= right)
		return;
		int key = left;
		int begin = left;
		int end = right;
		while (begin < end)
		{
			//先从右边开始找小 //注意结束条件 begin一定<end
			while (begin < end && arr[end] >= arr[key])
			{
				--end;
			}
			//再从左边找大
			while (begin < end && arr[begin] <= arr[key])
			{
				++begin;
			}
			//两边都找到了之后进行交换
			Swap(&arr[begin], &arr[end]);
		}
		//最后相遇再与key交换
		Swap(&arr[begin], &arr[key]);
		//递归排序分割成两份
		//[left~key-1] key [key+1~right]最后相遇的指针也是一样的
		QuickSort2(arr, left, end - 1);
		QuickSort2(arr, end + 1, right);
}

到这里我们也就完成了阉割版的快排,但是距离真正的快排还是有些距离

现在的这个排序有着致命的缺陷如果说在数组已经是有些的情况下,快排的将会退化,就像是二叉树退化为单叉树一样,如果我们这时还去递归那就会有爆栈(栈溢出)的风险,原因很简单

如下图所示

如果是有序的情况下,那么递归的深度将会变成n如果数据量太大将会爆栈

所以接下来要去实现一下三数取中,小区间优化来对递归快排进行优化

快排的优化

(1)三数取中

选择key值进行,key值的选择就是为了避免这种有序情况的出现,因为选key固定key的位值,我

评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值