快速排序迭代式和递归式的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实现的更多相关文章

  1. 【Python算法】递归与递归式

    该树结构显示了从1(根节点)到n(n个叶节点)的整个倍增过程.节点下的标签表示从n减半到1的过程. 当我们处理递归的时候,这些级数代表了问题实例的数量以及对一系列递归调用来说处理的相关工作量. 当我们 ...

  2. 傻瓜式理解递归之php递归

    写程序这么久了,有时候别人会问道一些算法比如排序啊,递归啊,总是不知道该怎么去说,今天就来整理一下,让更多的人去傻瓜式的理解递归.递归在网络上有很多定义,但有这么一句话听的最多:递归就是自己调用自己! ...

  3. Python——day14 三目运算、推导式、递归、匿名、内置函数

    一.三目(元)运算符 定义:就是 if...else...语法糖前提:简化if...else...结构,且两个分支有且只有一条语句注:三元运算符的结果不一定要与条件直接性关系​ cmd = input ...

  4. day 14 三元运算符,列表字典推导式,递归,匿名函数,内置函数(排序,映射,过滤,合并)

    一.三元运算符 就是if.....else..... 语法糖 前提:if和else只有一条语句 #原始版 cmd=input('cmd') if cmd.isdigit(): print('1') e ...

  5. 分析递归式 Solving Recurrences------GeeksforGeeks 翻译

    在上一章中我们讨论了如何分析循环语句.在现实中,有很多算法是递归的,当我们分析这些算法的时候我们要找到他们的的递归关系.例如归并排序,为了排序一个数组,我们把它平均分为两份然后再重复平分的步骤.最后我 ...

  6. python — 生成器、推导式、递归

    目录 1 生成器(函数的变异) 2 推导式 3 递归 1 生成器(函数的变异) 判断一个函数是否是生成器函数:只需看函数内部是否有yield # 生成器函数(内部是否包含yield) def func ...

  7. python 三元运算符、推导式、递归、匿名函数、内置函数

    三目运算符 # 三目(元)运算符:就是 if...else...语法糖 # 前提:简化if...else...结构,且两个分支有且只有一条语句 # 注:三元运算符的结果不一定要与条件直接性关系 cmd ...

  8. 【转】位置式、增量式PID算法C语言实现

    位置式.增量式PID算法C语言实现 芯片:STM32F107VC 编译器:KEIL4 作者:SY 日期:2017-9-21 15:29:19 概述 PID 算法是一种工控领域常见的控制算法,用于闭环反 ...

  9. C++扬帆远航——18(项目五2,递归式)

    /* * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:qiushi.cpp * 作者:常轩 * 微信公众号:World ...

随机推荐

  1. 图解Java 垃圾回收机制

    摘要: Java技术体系中所提倡的 自动内存管理 最终可以归结为自动化地解决了两个问题:给对象分配内存 以及 回收分配给对象的内存,而且这两个问题针对的内存区域就是Java内存模型中的 堆区.关于对象 ...

  2. 笔记本Linux系统,修改合盖不待机

    最近买了一个新笔记本,所以就把老的笔记本当作服务器使用了.但是一盒笔记本的盖子就会待机,真的是麻烦.操作如下可以解决问题: 1.编辑 logind.conf 文件,命令如下 vi /etc/syste ...

  3. Linux下MySQL主从复制(GTID)+读写分离(ProxySQL)-实施笔记

    GTID概念: GTID( Global Transaction Identifier)全局事务标识.GTID 是 5.6 版本引入的一个有关于主从复制的重大改进,相对于之前版本基于 Binlog 文 ...

  4. 记一次 .NET 某流媒体独角兽 API 句柄泄漏分析

    一:背景 1. 讲故事 上上周有位朋友找到我,说他的程序CPU和句柄都在不断的增长,无回头趋势,查了好些天也没什么进展,特加wx寻求帮助,截图如下: 看的出来这位朋友也是非常郁闷,出问题还出两个,气人 ...

  5. SpringBoot笔记(1)

    一.Spring能做什么 微服务 响应式开发 分布式云开发 web开发 无服务开发(云) 批处理业务等 二.SpringBoot作用 能快速创建出生产级别的Spring应用 SpringBoot是整合 ...

  6. 基于Linux的系统排错

    1.系统引导过程概述 2.系统异常及恢复 [1]grub系统引导 1)mbr上446字节丢失 模拟问题: dd if=/dev/zero? of=/dev/vda? bs=446? count=1? ...

  7. 并发编程之:CountDownLatch

    大家好,我是小黑,一个在互联网苟且偷生的农民工. 先问大家一个问题,在主线程中创建多个线程,在这多个线程被启动之后,主线程需要等子线程执行完之后才能接着执行自己的代码,应该怎么实现呢? Thread. ...

  8. 【第二篇】- Git 安装配置之Spring Cloud直播商城 b2b2c电子商务技术总结

    Git 安装配置 在使用Git前我们需要先安装 Git.Git 目前支持 Linux/Unix.Solaris.Mac和 Windows 平台上运行. Git 各平台安装包下载地址为:http://g ...

  9. Linux下运行bash脚本显示“: /usr/bin/env: "bash\r": 没有那个文件或目录

    用 ./ 运行bash脚本文件出现 报错信息 /usr/bin/env: "bash\r": 没有那个文件或目录 错误原因:这主要是因为bash后面多了\r这个字符的原因.在lin ...

  10. 个人作业——CVPR顶会论文爬取

    main.py #保存单个界面数据 def getInfo(url): # url='https://openaccess.thecvf.com/WACV2021' header={ 'User-Ag ...