【数据结构】比较排序--交换排序

交换排序

  • 冒泡排序
  • 快速排序

冒泡排序

一次确定一个最大值或者最小值,两两比较,将最大值或者最小值交换到最右边或者最左边,N个元素需要N-1次排序

void BubbleSort(int* num, int len)
{
	if (num == NULL || len <= 0)
		return;
	//确定循环躺数
	for (int i = 0; i < len - 1; i++)
	{
		//确定比较次数
		for (int j = 0; j < len - 1 - i; j++)
		{
			if (num[j]>num[j + 1])
				Swap(&num[j], &num[j + 1]);
		}
	}
}


分析
冒泡排序最好情况的时间复杂度为:O(n)最坏情况为O(n2)
空间复杂度为O(1)
稳定

快速排序(冒泡排序的改进)

基本思想
任取待排序元素序列中某元素作为基准值,按照该排序码将待排序集合分割为两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程
代码:

void QuickSort(int* num, int left, int right)
{
	if (num == NULL)
		return;
	//递归出口
	if (left >= right)
		return;
	//按照基准值将待排序区间划分为两个子区间
	int div = PartSort1(num, left, right);
	//子问题排序左子区间
	QuickSort(num, left, div - 1);
	//子问题排序右子区间
	QuickSort(num, div + 1, right);
}

接下来我们实现QuickSort

  • hoare版本(采用3数取中法优化)
int PartSort3(int* num, int begin, int end)
{
	int prev = begin - 1;
	int cur = begin;
	int key = num[end];
	while (cur < end)
	{
		//++prev=cur说明这个元素时第一个元素或者这是一段连续的小于基准的序列
		if ((num[cur] < key) && (++prev != cur))
			Swap(&num[cur], &num[prev]);
		cur++;
	}
	//把基准元素放在所有小于基准元素的紧邻后边,可以达到基准的左边小于基准,右边大于基准
	Swap(&num[++prev], &num[end]);
	return prev;
}
  • 挖坑法
int PartSort2(int* num, int begin, int end)
{
	int key = num[end];//把基准值拿出来(挖一个坑)
	while (begin < end)
	{
		//1.左边找到大于基准值的元素,并放入坑里
		while ((begin < end) && (num[begin] <= key))
			begin++;
		num[end] = num[begin];
		//2.右边找到小于基准值的元素,并放入坑里
		while ((begin < end) && (num[end] >= key))
			end--;
		num[begin] = num[end];
	}
	//3.把拿出来基准值放入坑里
	num[begin] = key;
	//返回基准值的位置
	return begin;
}
  • 前后指针
int PartSort3(int* num, int begin, int end)
{
	int prev = begin - 1;
	int cur = begin;
	int key = num[end];
	while (cur < end)
	{
		//++prev=cur说明这个元素时第一个元素或者这是一段连续的小于基准的序列
		if ((num[cur] < key) && (++prev != cur))
			Swap(&num[cur], &num[prev]);
		cur++;
	}
	//把基准元素放在所有小于基准元素的紧邻后边,可以达到基准的左边小于基准,右边大于基准
	Swap(&num[++prev], &num[end]);
	return prev;
}

分析
快排的最坏场景:待排序列是有序的,左右子序列数有一个为空,二叉树深度为n,则时间复杂度为O(nn),空间复杂度为O(n)。
最好场景:每次选的数都是序列最中间的数字,二叉树深度为logN,时间复杂度为O(N
logN ).空间复杂度为O(logN)
不稳定的

快排的优化
底层区间优化


void QuickSort1(int* num, int left, int right)
{
	if (num == NULL)
		return;
	//递归出口
	if (left >= right)
		return;
	//小区间优化(替换掉后边几层的递归)
	if (right - left + 1 < 10)
		InsertSort(num, right - left + 1);
	int div = PartSort1(num, left, right);
	QuickSort1(num, left, div - 1);
	QuickSort1(num, div + 1, right);
}

将递归快排改为循环快排
栈的相关函数:https://blog.csdn.net/weixin_41892460/article/details/82973851

void QuickSortNonR(int* num, int left, int right)
{
	if (num == NULL || right <= left)
		return;
	Stack st;
	StackInit(&st);
	//先将整个区间压栈
	StackPush(&st, left);
	StackPush(&st, right);
	while (StackEmpty(&st) != 0)
	{
		//取栈顶并且出栈
		int end = StackTop(&st);
		StackPop(&st);
		int begin = StackTop(&st);
		StackPop(&st);
		//先划分主区间,固定好一个基准
		int div = PartSort1(num, begin, end);
		//如果左子序列还有大于1个元素,继续压栈
		if (begin < div - 1)
		{
			StackPush(&st, begin);
			StackPush(&st, div - 1);
		}
		//如果右子序列还有大于1个元素,继续压栈
		if (div + 1 < end)
		{
			StackPush(&st, div + 1);
			StackPush(&st, end);
		}
	}
	StackDestroy(&st);
}

猜你喜欢

转载自blog.csdn.net/weixin_41892460/article/details/83045978