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

快速选择排序

"你经过我每个灿烂时刻,我才真正学会如你般自由" 


         前些天有些无聊,想试试自己写的快排能否过leetcode上的排序算法题。结果是,不用截图可想而知,肯定是没过的,否则也不会有这篇文章的产出。

        这份快排算法代码在面对大量重复数的时候,时间复杂度会下降到O(n^2),这也是为什么leetcode显示最后会超时。所以如何解决呢?也许在此之前,可以先回顾回顾快排三步核心算法步骤。

——前言


快排的三个核心算法

● HOARE版

        这是最早的版本,也叫做左右指针法。不过这个算法需要值得注意的是一个地方。排升序时,一定是需要右指针先动,相反如果是排降序,则是左指针先动。        

int PartSort1(vector<int>& nums, int l, int r)
{
	// 左右指针法
	int key = nums[l];
	int left = l;
	int right = r;
	while (left < right)
	{
		// 这里需要注意取等 
		// 如果不取等可能陷入死循环
		while (left < right && nums[right] >= key)
		{
			right--;
		}

		while (left < right && nums[left] <= key)
		{
			left++;
		}

		if (left < right) {
			swap(nums[left], nums[right]);
		}
	}
	// 处理keyi
	swap(nums[left], nums[l]);
	return left;
}

        我们对上述例子进行排序后的代码为:

● 挖坑法

        

int PartSort2(vector<int>& nums, int l, int r)
{
	int key = nums[l];
	int hole = l;
	int left = l, right = r;
	while (left < right){
		// 右边找小 填左坑
		while (left < right && nums[right] >= key){
			right--;
		}
		// 填坑
		swap(nums[right], nums[hole]);
		hole = right; // 新坑
		while (left < right && nums[left] <= key){
			left++;
		}
		swap(nums[left], nums[hole]);
		hole = left; // 新坑
	}
	// hole即为最终落脚点
	return hole;
}

        

● 前后指针法

        最后的前后指针法,也在前言中用到,这里不做多的解释。

int PartSort3(vector<int>& nums, int l, int r)
{
	int key = nums[l];
	int prev = l, cur = l + 1;
	while (cur <= r)
	{
		// 找小
		if (nums[cur] < key && ++prev != cur)
		{
			// prev指向的一定是比key大的数
			swap(nums[prev], nums[cur]);
		}
		cur++;
	}
	swap(nums[prev], nums[l]);
	return prev;
}

        


快速选择排序

        可是,你使用上述的不管哪种算法,都无法跑过leetcode上面的题,都会在重复数的情况下超时!这里我们可以用到归并分治的思想,如果将一个无序数组排序成有序数组,选定其中一个数作为key,可以将这个数组分为三部分:

    int getRandom(vector<int>& nums, int l, int r)
    {
        int keyi = rand();
        return nums[keyi % (r-l+1) + l];
    } 

    void qsort(vector<int>& nums, int l, int r)
    {
        if(l < r)
        {
            int key = getRandom(nums,l,r);
            // 数组分三块
            // 先让left、right指向非法区域
            int i = l,left = l-1,right = r+1;
            // [i,right]是未处理区域
            while(i < right)
            {
                if(nums[i] < key) swap(nums[++left],nums[i++]);
                else if(nums[i] == key) i++;
                else swap(nums[--right],nums[i]);
            }

            // 递归处理其他区间
            qsort(nums,l,left);
            qsort(nums,right,r);
        }
    }

        我们终于是可以通过啦~


本篇到此结束,感谢你的阅读。

祝你好运,向阳而生~

相关文章:

  • Spring的注解开发-注解方式整合MyBatis代码实现
  • 辅助驾驶功能开发-测试篇(2)-真值系统介绍
  • 宝塔反代openai官方API接口详细教程,502 Bad Gateway问题解决
  • 【IPC 通信】信号处理接口 Signal API(6)
  • 点击router-link时候会发生什么?
  • 分类预测 | MATLAB实现WOA-FS-SVM鲸鱼算法同步优化特征选择结合支持向量机分类预测
  • 步力宝科技爆款产品定位,开创智能物联网新商业
  • 博客无限滚动加载(html、css、js)实现
  • 简化数据库操作:探索 Gorm 的约定优于配置原则
  • javaWeb学生信息管理
  • 读书笔记|《数据压缩入门》—— 柯尔特·麦克安利斯 亚历克斯·海奇
  • 网盘搜索引擎:点亮知识星空,畅享数字宝藏!
  • 【NLP的python库(03/4) 】: 全面概述
  • netty 拆包/粘包
  • 冥想第九百二十九天
  • 获取网卡上的IP、网关及DNS信息,获取最佳路由,遍历路由表中的条目(附源码)
  • 保姆级 -- Zookeeper超详解
  • watch()监听vue2项目角色权限变化更新挂载
  • 【图论C++】树的重心——教父POJ 3107(链式前向星的使用)
  • 为什么炒股人更爱融资?融券交易背后的风险与获利机会
  • 杨国荣丨阐释学的内涵与意义——张江《阐释学五辨》序
  • 河南一季度GDP为14945.58亿元,同比增长5.9%
  • 青创上海-2025浦东徒步行倒计时1天,明日浦东世博文化公园不见不散
  • 上海出台26项措施促进民营经济高质量发展,关于公平竞争、融资支持等
  • 东南亚三国行第三日|中马将在人工智能、大熊猫保护、铁路等多领域深化合作
  • 总台海峡时评:当心赖清德在关税谈判桌上把台湾送到美国盘中