当前位置: 首页 > article >正文

选择排序+快速排序递归版(二)

目录

  • 选择排序
    • 代码
    • 对于if条件那里的解释:
  • 快速排序递归版
    • 代码
    • 时间复杂度分析
  • 提问

选择排序

推荐更优化一点的版本:选出最小的数和最左边位置的数交换,选出最大的和最右边的位置的数交换

代码

// 选择排序
void SelectSort(int* a, int n)
{
	int begin = 0, end = n - 1;
	while (begin < end)
	{
		int mint = begin, maxt = begin;
		for (int i = begin + 1; i <= end; ++i)
		{
			if (a[i] < a[mint]) mint = i;
			else if (a[i] > a[maxt]) maxt = i;
		}
		swap(&a[begin], &a[mint]);
		if (a[begin] == a[maxt])
		// 如果maxt和begin位置重叠,begin和mint换了,mint位置的值就是最大的了
		{
			maxt = mint;
		} 
		swap(&a[end], &a[maxt]);
		begin++;
		end--;
	}
}

int main()
{
	int a[] = { 2,32,13,4,4,53,12 };
	int n = sizeof(a) / sizeof(a[0]);
	SelectSort(a, n);
	for (int i = 0; i < n; ++i)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
	return 0;
}

对于if条件那里的解释:

在这里插入图片描述
时间复杂度分析:

最好情况是O(N^2) 数组是有序的,也要过一边数组
外面走一遍数组,里面也走一遍数组
最坏情况:O(N^2) 最坏情况也一样

快速排序递归版

快排有三种方法:
1.霍尔排序
2.前后指针
3.挖坑法
在这里插入图片描述

  1. 左边找大,右边找小,跟key比较大小,(设key是左边第一个位置的数)然后交换,小的放左边,大的放右边
  2. 这样快排就类型于一个完全二叉树的结构,左边递归,右边也递归
  3. 相遇就停止,让相遇位置的数和最左边的数交换

在这里插入图片描述

代码

// 得到的是数是中间大的(下标)
int Getmidi(int* a, int left, int right)
{
	int mid = left + (right - left) / 2;// 防溢出
	// left mid right
	if (a[left] < a[mid])
	{
		if (a[mid] < a[right])
			return mid;
		else if (a[left] > a[right])//left right mid
			return left;
		else
			return right;
	}
	else// mid left
	{
		if (a[right] > a[left])
			return left;
		else if (a[right] < a[mid])
			return mid;
		else
			return right;
	}
}
// 快排
void QuickSort(int* a, int left, int right)
{
	// [0,0] [2,1]保证没有这两种情况
	if (left >= right) return;

	// 小区间优化,小于10个数不用分割区间,再递归
	if ((right - left + 1) < 10)
	{
		// 数组不一定在开头0位置
		InsertSort(a + left, right - left + 1);
	}
	else 
	{
		// 三数取中
		int midi = Getmidi(a, left, right);
		swap(&a[midi], &a[left]);

		int keyi = left;
		int begin = left, end = right;
		while (begin < end)
		{
			// 右边找小
			while (begin < end && a[keyi] <= a[end])
				end--;
			// 左边找大
			while (begin < end && a[keyi] >= a[begin])
				begin++;
			// 交换两个数
			swap(&a[begin], &a[end]);
		}
		// 交换keyi位置的值
		swap(&a[begin], &a[keyi]);
		// [begin,keyi - 1] keyi [keyi + 1,end]
		keyi = begin;
		// 递归左区间和右区间
		QuickSort(a, left,keyi - 1);
		QuickSort(a, keyi + 1, right);
	}
}
// 简单快速排序实现
int main()
{
	// 对三数取中的测试
	/*int a[10] = { 10,2,3,4,2,5,7,8,9,6 };
	int left = 0, right = 9;
	int mid = Getmidi(a, left, right);
	printf("%d\n", mid);*/

	int a[10] = { 1,3,342,3442,3,4,2,3,9,10 };
	
	QuickSort(a, 0, 9);
	for (int i = 0; i < 10; ++i)
	{
		printf("%d ", a[i]);
	}
	printf("\n");

	return 0;
}

时间复杂度分析

有logN层,每层都是N个数(遍历了一遍数组)
时间复杂度O(N*logN)

提问

非常重要

  1. int key = a[left]
    swap(&key,&a[begin]) 为什么这样是错的?
    原因是key是局部变量,只是key变成a[begin]的值,而本身数组中的a[left]没有改变
  2. 有序的场景为什么快排会溢出?
    <>递归的深度太深会溢出
    <>左边找大找一次就找到了,右边找小要找到他两相遇也找不到小,相当于遍历一遍数组,keyi = begin,少一个数,如此下去就是等差数列,时间复杂度是O(N*N),这样会导致栈溢出
  3. 为什么Dubug版本会爆,而release不爆?
    <> 因为Dubug版本下有调试信息,优化不高
    <> 有调试的话,每个栈桢会大些,>= 1万就爆了
    <> release版本无调试,栈桢开得小,可容纳量增大
  4. 怎么解决有序的情况(有序的话,时间复杂度为O(N))?
    <> 选keyi可以解决这种情况
    <> 选keyi的方法:选到中间大的数
    <> 1.随机数选keyi
    <> 2.三数取中,最左边,最右边,中间的三个数取中间大的数(用下标,方便选出来的值和最左边交换,保证逻辑不变)
  5. 快排的优化?
    <> 快排的递归类型于完全二叉树,最后几层占总递归数的90%左右
    <> 比如: 对最后五个值的递归进行优化,最后五个值要递归7次
    在这里插入图片描述
    <> 小区间优化,不再递归分割排序,减少递归的次数
    比如:小于10个数就进行插入排序,因为插入排序是小范围排序中最优的(比冒泡,选择好),大于等于10个数就进行快排
  6. <> a1[i] = rand() + i; 重复不多
    <> a1[i] = rand(); 重复较多,rand()产生的随机数不重复的有3万多个
  7. 为什么相遇位置的数比keyi位置的数小?
    在这里插入图片描述
  8. 挖坑法对单趟排序是怎么进行优化的?
    挖坑法没有效率的提升,但是更容易理解
    挖坑发是左边是坑,右边先走找小,值放入左边,然后右边是坑,左边走找大,左边值放入右边,然后左边又是坑,如此类推

在这里插入图片描述


http://www.kler.cn/a/396877.html

相关文章:

  • linux企业中常用NFS、ftp服务
  • 数仓建设之Oracle常见语法学习
  • Nginx: 实现Websocket代理
  • 【项目开发】Web App vs Native App,开发者作何选择?
  • Flume和kafka的整合
  • SASS 控制指令详解@for、@if、@each、@while
  • 缓存冲突(Cache Conflict)
  • Spring:IOC实例化对象bean的方式
  • 蔚来Java面试题及参考答案
  • 冷启动 VS 热启动
  • 职场汇报技巧:选择合适的汇报形式与提供数据依据
  • C++ 的发展
  • ArkUI---使用弹窗---@ohos.promptAction (弹窗)
  • Linux 实现自动登陆远程机器
  • Qt之QTreeWidget通过撤销栈移除item
  • 软考之RESTful 架构的特点
  • uview Collapse折叠面板无法动态设置展开问题(微信小程序)
  • Docker在微服务架构中的应用
  • 算法之二分查找优化:leetcode34:在排序数组中查找元素的第一个和最后一个位置
  • 用 Python 从零开始创建神经网络(七):梯度下降(Gradient Descent)/导数(Derivatives)
  • 27-压力测试
  • ASFSSA-VMD多策略改进的麻雀搜索算法优化变分模态分解
  • JavaWeb之AJAX
  • 操作系统——虚拟存储器(含思维导图)
  • 使用pytest+openpyxl做接口自动化遇到的问题
  • 丹摩征文活动 |【前端开发】HTML+CSS+JavaScript前端三剑客的基础知识体系了解