算法——快速排序迭代式和递归式的Java实现
快速排序迭代式和递归式的Java实现
快速排序基于分治法的思想,在待排序表中任选一值作为中枢值 pivot,一趟快排将所有大于该值的元素置于一边,小于该值的元素置于另一边,这样一个元素在排序中的最终位置就已确定。接下来将中枢值左右两边的区域分别进行下一趟快排,直到所有的元素都有序排列。
空间效率:最好情况为 O(log2(n+1))
,最坏情况为 O(n)
,平均空间复杂度 O(log2(n))
。
时间效率:最好情况为 O(n*log2(n))
,最坏情况 O(n^2)
,平均时间复杂度 O(n*log2(n))。
快速排序是所有内部排序中平均性能最优的算法,同时也是一个不稳定的排序算法。
递归式
- 1 public class Test {
- 2
- 3 public static void main(String[] args) {
- 4
- 5 int[] nums = {2, 12, 32, 32, 43, 5, 74, 13, 87, 12, 44, 2, 41, 5, 33};
- 6
- 7 recursiveQuicksort(nums,0,nums.length-1);
- 8
- 9 System.out.println("Sorted array : " + Arrays.toString(nums));
- 10
- 11 }
- 12
- 13 //recursiveQuicksort(int[] 被排序数组, int 数组下界, int 数组上界)
- 14 private static void recursiveQuicksort(int[] nums, int low, int high) {
- 15
- 16 if(low < high){
- 17
- 18 int pivotpos = partition(nums, low, high);
- 19
- 20 recursiveQuicksort(nums, low, pivotpos -1);
- 21 recursiveQuicksort(nums, pivotpos + 1, high);
- 22
- 23 }
- 24 }
- 25
- 26 private static int partition(int[] nums, int low, int high) {
- 27
- 28 //将当前列表中第一个元素设为中枢值
- 29 int pivot = nums[low];
- 30
- 31 while(low < high){
- 32
- 33 //找到第一个小于中枢值的数,置于low的位置
- 34 while(low < high && nums[high] >= pivot){
- 35 --high;
- 36 }
- 37 nums[low] = nums[high];
- 38
- 39 //找到第一个大于中枢值的数,置于high的位置
- 40 while(low < high && nums[low] <= pivot){
- 41 ++low;
- 42 }
- 43 nums[high] = nums[low];
- 44 }
- 45
- 46 //这样一趟下来nums[low]左端都是小于中枢值的数,右端都是大于中枢值的数,一个元素的最终排序位置确定
- 47 nums[low] = pivot;
- 48
- 49 return low;
- 50 }
- 51 }
迭代式
递归的操作更加便于理解,但是递归频繁的调用函数会不断让参数和其它额外的变量入栈,从而造成栈空间的极大浪费,如果调用层次很深,还有可能造成栈溢出,而入栈也会有性能损失。因此迭代式自己模拟入栈的过程从而提高快排的效率。
- 1 public class Test {
- 2
- 3 public static void main(String[] args) {
- 4
- 5 int[] nums = {34, 32, 43, 12, 11, 32, 22, 21, 32};
- 6
- 7 System.out.println("Unsorted array : " + Arrays.toString(nums));
- 8
- 9 iterativeQuicksort(nums);
- 10
- 11 System.out.println("Sorted array : " + Arrays.toString(nums));
- 12
- 13 }
- 14
- 15 public static void iterativeQuicksort(int[] nums) {
- 16
- 17 //新建栈,模拟递归操作
- 18 Stack stack = new Stack();
- 19
- 20 stack.push(0);
- 21 stack.push(nums.length);
- 22
- 23 while (!stack.isEmpty()) {
- 24 int high = (int)stack.pop();
- 25 int low = (int)stack.pop();
- 26
- 27 if (high - low < 2) {
- 28 continue;
- 29 }
- 30
- 31 //pivot为low与high的平均值,保证随机性,降低抽到数组中最小值或最大值的概率
- 32 int p = low + ((high - low) / 2); //pivot为low与high的平均值,这样写防止溢出
- 33
- 34 //经过一趟partition后,p所在的位置已是排序后的最终位置
- 35 p = partition(nums, p, low, high);
- 36
- 37 stack.push(p + 1);
- 38 stack.push(high);
- 39
- 40 stack.push(low);
- 41 stack.push(p);
- 42 }
- 43 }
- 44
- 45 private static int partition(int[] input, int position, int start, int end) {
- 46
- 47 int l = start;
- 48 int h = end - 2;
- 49
- 50 int pivot = input[position];
- 51
- 52 //将pivot换至最右端
- 53 swap(input, position, end - 1);
- 54
- 55 //筛选pivot的最终位置
- 56 while (l < h) {
- 57 if (input[l] < pivot) {
- 58 l++;
- 59 } else if (input[h] >= pivot) {
- 60 h--;
- 61 } else {
- 62 swap(input, l, h);
- 63 }
- 64 }
- 65 //pos为pivot的最终位置
- 66 int pos = h;
- 67
- 68 //如果pivot左边的数都小于它,说明它本来就应该在最右端的位置,因此pos++
- 69 if (input[h] < pivot) {
- 70 pos++;
- 71 }
- 72 swap(input, end - 1, pos);
- 73
- 74 return pos;
- 75 }
- 76
- 77 private static void swap(int[] arr, int i, int j) {
- 78 int temp = arr[i];
- 79 arr[i] = arr[j];
- 80 arr[j] = temp;
- 81 }
- 82 }
递归与迭代
递归:重复调用函数自身实现循环
优点:
极大的减少了代码量,代码简单易读
将大问题转化成小问题,逻辑清晰
缺点:
递归不断调用函数,不断压栈,浪费空间容易造成栈溢出
频繁的入栈出栈操作也会导致性能损失
迭代:函数内某段代码实现循环,不断把变量的原值推导成新值,直到最终结果产生
优点:
效率比递归高,运行时间只随循环的增加而增加
不需要反复调用从而占用栈的空间
缺点:
代码复杂,较难理解
面对复杂问题时,难以构思代码
算法——快速排序迭代式和递归式的Java实现的更多相关文章
- 【Python算法】递归与递归式
该树结构显示了从1(根节点)到n(n个叶节点)的整个倍增过程.节点下的标签表示从n减半到1的过程. 当我们处理递归的时候,这些级数代表了问题实例的数量以及对一系列递归调用来说处理的相关工作量. 当我们 ...
- 傻瓜式理解递归之php递归
写程序这么久了,有时候别人会问道一些算法比如排序啊,递归啊,总是不知道该怎么去说,今天就来整理一下,让更多的人去傻瓜式的理解递归.递归在网络上有很多定义,但有这么一句话听的最多:递归就是自己调用自己! ...
- Python——day14 三目运算、推导式、递归、匿名、内置函数
一.三目(元)运算符 定义:就是 if...else...语法糖前提:简化if...else...结构,且两个分支有且只有一条语句注:三元运算符的结果不一定要与条件直接性关系 cmd = input ...
- day 14 三元运算符,列表字典推导式,递归,匿名函数,内置函数(排序,映射,过滤,合并)
一.三元运算符 就是if.....else..... 语法糖 前提:if和else只有一条语句 #原始版 cmd=input('cmd') if cmd.isdigit(): print('1') e ...
- 分析递归式 Solving Recurrences------GeeksforGeeks 翻译
在上一章中我们讨论了如何分析循环语句.在现实中,有很多算法是递归的,当我们分析这些算法的时候我们要找到他们的的递归关系.例如归并排序,为了排序一个数组,我们把它平均分为两份然后再重复平分的步骤.最后我 ...
- python — 生成器、推导式、递归
目录 1 生成器(函数的变异) 2 推导式 3 递归 1 生成器(函数的变异) 判断一个函数是否是生成器函数:只需看函数内部是否有yield # 生成器函数(内部是否包含yield) def func ...
- python 三元运算符、推导式、递归、匿名函数、内置函数
三目运算符 # 三目(元)运算符:就是 if...else...语法糖 # 前提:简化if...else...结构,且两个分支有且只有一条语句 # 注:三元运算符的结果不一定要与条件直接性关系 cmd ...
- 【转】位置式、增量式PID算法C语言实现
位置式.增量式PID算法C语言实现 芯片:STM32F107VC 编译器:KEIL4 作者:SY 日期:2017-9-21 15:29:19 概述 PID 算法是一种工控领域常见的控制算法,用于闭环反 ...
- C++扬帆远航——18(项目五2,递归式)
/* * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:qiushi.cpp * 作者:常轩 * 微信公众号:World ...
随机推荐
- Redis脑图
转自:http://alphawang.com/blog/redis-mind-map/ 最近梳理了下 Redis 知识图谱,画了个脑图,涵盖了 Redis 数据类型.持久化机制.主从.哨兵.集群.应 ...
- Redis常用技术
Xml配置: <?xml version='1.0' encoding='UTF-8' ?> <!-- was: <?xml version="1.0" e ...
- Spring Boot +Vue 项目实战笔记(二):前后端结合测试(登录页面开发)
前言:关于开发环境 每位 Coder 都有自己偏好的开发工具,从大的方面划分主要有文本编辑器流和 IDE 流两种,我有一段时间也喜欢用编辑器(Sublime Text.Vim),但对我来说开发效率确实 ...
- 简单C++线程池
简单C++线程池 Java 中有一个很方便的 ThreadPoolExecutor,可以用做线程池.想找一下 C++ 的类似设施,尤其是能方便理解底层原理可上手的.网上找到的 demo,基本都是介绍的 ...
- Win10 安装WSL2与 Linux子系统
Win10安装Linux子系统 1. 正常情况 步骤1 - 启用 Windows Linux版本子系统(Windows Subsystem for Linux) dism.exe /online /e ...
- ArcEngine+C# 森林资源仿真系统 核心代码
目录 第一章 基础功能的核心代码 实现滚轮缩放事件 创建或获取地理数据(导入前询问用户是否覆盖) 创建要素类(Shape) 点列数据创建要素类 Shape文件创建要素类 GDB中取出要素类 创建栅格数 ...
- 洛谷P1314 聪明的质监员 题解
题目 聪明的质监员 题解 这道题和之前Sabotage G的那道题类似,都是用二分答案求解(这道题还要简单一些,不需要用数学推导二分条件,只需简单判断一下即可). 同时为了降低复杂度,肯定不能用暴力求 ...
- MongoDB 常见问题 - 解决找不到 mongo、mongod 命令的问题
问题背景 成功安装 MongoDB 后执行 Mongo.MongoD 显示找不到命令 解决方案 echo 'export PATH="/usr/local/opt/mongodb-commu ...
- WebDriverAgent重签名爬坑记
接上一篇博文,已经配置好了Xcode环境,那接下来要完成的就是重签名WebDriverAgent.在讲重签名之前,我们还是先来了解下WebDriverAgent,熟悉的朋友,可以直接跳过. WebDr ...
- MacOS安装和卸载Java
安装java 下载地址:https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 设 ...