七大排序算法

直接插入排序(稳定)

我们认为在一组数中,可以分为三个部分,有序区,无序区和待排序区,例如下图:

在这里插入图片描述

蓝色部分是有序区,黄色部分表示即将要排序的,灰色是无序区,那么我们怎么在有序部分找到黄色应该插入的位置呢?
1.从后往前找。可以从蓝色部分的后面往前找,分别和黄色比较,找到相应的位置
2.二分方式找。
代码如下:

void InsertSort(int array[], int size)
{
	int key;
	int i, j;
	for (i = 1; i < size; i++)
	{
		key = array[i];
		for (j = i - 1; j >= 0; j--)
		{
			if (key >= array[j])
			{
				break;
			}
			else {
				array[j + 1] = array[j];
			}
		}
		array[j+1] = key;
	}
}

时间复杂度: 最好/最坏 O(n)/O(n^2)
空间复杂度: O(1)

希尔排序(不稳定)

希尔排序也是插排的一种,在排序之前会先做预排序,例如下面这组数据

在这里插入图片描述

希尔排序会先分组进行插叙,例如上面的数组相同颜色的圈代表一组,先在每一组进行排序,然后不断的重复,那么这就需要考虑分组策略了:
1.分组间隔越大,排序次数越少
2.分组间隔越小,结果越有序
一般情况下:我们会把一组数据分为几组呢?一般情况gap=size/3+1;

代码:

void _InsertSort(int array[], int size, int gap)
{
	for (int g = 0; g < gap; g++)
	{
		int key;
		int i, j;
		for (i = gap + g; i < size; i+=gap) {
			key = array[i];
			for (j = i - gap; j >= 0; j -= gap) {
				if (key >= array[j]) {
					break;
				}
				else {
					array[j + gap] = array[j];
				}
			}
			array[j + gap] = key;
		}
		
	}
}
void ShellSort(int array[], int size)
{
	int gap = size;
	while (1) {
		gap = gap / 3 + 1;
		_InsertSort(array, size, gap);
		if (gap == 1)
		{
			break;
		}
	}
}

时间复杂度: 最好/平均/最差 O(n)/O(n^(1.2~1.3) ) /O(n^2)
空间复杂度: O(1)

选择排序(不稳定)

每次在序列中选出最大(最小),交换到最后,简而置之,然后循环

代码:

void Swap(int *a, int *b)
{
	int t = *a;
	*a = *b;
	*b = t;
}
void SelectSort(int array[], int size)
{
	for (int i = size; i >1; i--)
	{
		int max = 0;
		for (int j = 1; j < i; j++)
		{
			if (array[j] > array[max]) {
				max = j;
			}
		}
		Swap(array + max, array + i - 1);
	}
}

上面这种是每次选出最大的或者最小放好位置,当然,我们也可以,每次既选出最大的,也选出最小的同时放好位置。

代码:

void Swap(int *a, int *b)
{
	int t = *a;
	*a = *b;
	*b = t;
}
void SelectSort1(int array[], int size)
{
	int left = 0;
	int right = size - 1;
	while (left < right)
	{
		int min = left;
		int max = left;
		for (int j = left + 1; j <= right; j++)
		{
			if (array[j] > array[max])
			{
				max = j;
			}
			if (array[j] < array[min])
			{
				min = j;
			}
		}
		Swap(array + left, array + min);
		if (max == left)
		{
			max = min;
		}
		Swap(array + right, array + max);
		left++;
		right--;
	}
}

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

堆排序(不稳定)

堆排序的思想其实就是,每次找到最大值与最后一个元素交换,然后向下调整。排序的过程其实很简单,主要在于创建大堆和堆的向下调整。

void AdjustDown(int array[], int size, int root)
{
	int left = 2 * root + 1;
	int right = 2 * root + 2;
	if (left >= size)
	{
		return;
	}
	int max = left;
	if (right<size&&array[right]>array[left])
	{
		max = right;
	}
	if (array[root] >= array[max])
	{
		return;
	}
	Swap(array + root, array + max);
	AdjustDown(array, size, max);
}
void CreateHeap(int array[], int size)
{   //创建大堆
	//从最后一个非叶子结点到0
	//不断的进行向下调整
	for (int i = size / 2 - 1; i >= 0; i--)
	{
		AdjustDown(array, size, i);
	}
}
void HeapSort(int array[], int size)
{
	CreateHeap(array, size);
	for (int i = 0; i < size; i++)
	{
		Swap(array, array + (size - i - 1));
		AdjustDown(array,size-i-1,0);
	}
}

时间复杂度:O(N*logN)
空间复杂度:O(1)

冒泡排序(稳定)

冒泡排序是最常见的排序,思想也很简单,就是挨个交换,不断循环。

在这里插入图片描述

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

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

快速排序(不稳定)

基本思想:分治算法
1.找一个基准值
1>找边上的
2.比基准值小的都放到基准值的左边
比基准值大的都放到基准值的右边
3.终止条件
1>小区间有序 区间长度==1
2>小区间没有数 区间长度<=0

将区间按照基准值划分为左右两半部分的常见方式有:

方法一:hoare法

快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基
本思想为:任取待排序元素序列中的某元素作为基准值,按照该排序码将
待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序
列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元
素都排列在相应位置上为止。

int Partition(int array[], int left, int right)
{
	int begin = left;
	int end = right;
	while (begin < end)
	{
		while (begin < end&&array[begin] <= array[right])
		{
			begin++;
		}
		while (begin < end&&array[end] >= array[right])
		{
			end--;
		}
		Swap(array + begin, array + end);
	}
	Swap(array + begin, array + right);
	return begin;
}
void _QuickSort(int array[],int left,int right)
{
	if (left == right)
	{
		return;
	}
	if (left > right)
	{
		return;
	}
	int div = Partition(array, left, right);
	_QuickSort(array, left, div - 1);
	_QuickSort(array, div + 1, right);
}
void QuickSort(int array[], int size)
{
	_QuickSort(array, 0, size - 1);
}

挖坑法

挖坑法其实就是提前将基准值存起来,这样基准值的位置其实就是一个坑,可以被别的元素填。挖坑法的具体过程就是将最后一个元素作为基准值,然后begin从前遍历,遇到比基准值大的就去填基准值的坑,end从后往前遍历,遇到比基准值小的再去填begin的坑。

int Partition_02(int array[], int left, int right)
{
	int begin = left;
	int end = right;
	int priot = array[right];
	while (begin < end)
	{
		while (begin < end&&array[begin] <= priot)
		{
			begin++;
		}
		array[end] = array[begin];
		while (begin < end&&array[end] >= priot)
		{
			end--;
		}
		array[begin] = array[end];
	}
	array[begin] = priot;
	return begin;
}
void _QuickSort(int array[],int left,int right)
{
	if (left == right)
	{
		return;
	}
	if (left > right)
	{
		return;
	}
	int div = Partition_01(array, left, right);
	_QuickSort(array, left, div - 1);
	_QuickSort(array, div + 1, right);
}
void QuickSort(int array[], int size)
{
	_QuickSort(array, 0, size - 1);
}

快慢指针法

快慢指针也叫前后指针,当然并不是一个从前一个从后遍历,而是一前一后遍历,两个指针都从头开始向后遍历,快的指针每次都向后移动,只有当快的指针所指的值小于基准值时,快慢指针所指的值进行交换,并且慢指针向后移动,否则,慢指针不动。

int Partition_03(int array[], int left, int right)
{
	int fast = left;
	int slow = left;
	while (fast<right)
	{
		if (array[fast] < array[right])
		{
			Swap(array + fast, array + slow);
			slow++;
			fast++;
		}
		else {
			fast++;
		}
	}
	Swap(array + right, array + slow);
	return slow;
}
void _QuickSort(int array[],int left,int right)
{
	if (left == right)
	{
		return;
	}
	if (left > right)
	{
		return;
	}
	int div = Partition_03(array, left, right);
	_QuickSort(array, left, div - 1);
	_QuickSort(array, div + 1, right);
}
void QuickSort(int array[], int size)
{
	_QuickSort(array, 0, size - 1);
}

时间复杂度:O(nlogn)
空间复杂度:O(1)

归并排序

基本思想:
将待排序的元素序列分成两个长度相等的子序列,对每一个子序列排序,
然后将他们合并成一个序列。如下图:

在这里插入图片描述

递归方法

void Merge(int array[], int left,int mid, int right,int a[])
{//合并函数
	int left_i = left;
	int right_i = mid + 1;
	int k = left;
	while (left_i <= mid && right_i <= right) {
		if (array[left_i] <=array[right_i])
		{
			a[k++] = array[left_i++];
		}
		else {
			a[k++] = array[right_i++];
		}
	}
	while (left_i <= mid)
	{
		a[k++] = array[left_i++];
	}
	while (right_i <= right)
	{
		a[k++] = array[right_i++];
	}
	for (int i = left; i <= right; i++)
	{
		array[i] = a[i];
	}
}
void _MergeSort(int array[], int left, int right,int a[])
{//分组函数
	if (left == right)
	{
		return;//区间长度为1
	}
	if (left > right)
	{
		return ;//区间长度为0
	}
	int mid = left + (right - left) / 2;
	_MergeSort(array, left, mid, a);
	_MergeSort(array, mid + 1, right, a);
	Merge(array, left, mid, right, a);

}
void MergeSort(int array[], int size)
{//接口函数
	int*a = (int *)malloc(sizeof(int)*size);//用于存放合并后的数组
	_MergeSort(array, 0, size - 1, a);
	free(a);
}

非递归方法

void MergeSortLoop(int array[],int size ) {
	int*extra = (int *)malloc(sizeof(int)*size);//用于存放合并后的数组
	for (int i = 1; i < size; i *= 2)
	{
		for (int j = 0; j < size; j = j + 2 * i)
		{
			int left = j;
			int mid = j + i;
			int right = mid + i;
			if (mid >= size) {
				continue;
			}
			if (right > size) {
				right = size;
			}
			Merge(array, left,mid-1, right-1, extra);
		}
	}
	free(extra);
}

这里代码不唯一,看个人区间分配,我用的是左闭右闭的区间。

时间复杂度:O(n)
空间复杂度:O(n)

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值