首页 > 其他分享 >非递归随机快排

非递归随机快排

时间:2023-02-20 11:06:00浏览次数:32  
标签:arr 递归 int pro 快排 随机 left public arr2


之前写过递归形式的随机快排,但是发现效率并不理想,今天正好复习算法,就索性将递归的改为非递归的。

任何递归形式的方法都是系统压栈的,而我们可以自己压栈,也就是说所有的递归都可以改为非递归方法。

同样,先放出荷兰国旗问题:懂了这个才有学习快排的基础

递归形式的快排就不写了,可以参考这个,虽然写的不怎么详细:

 

说白了,思路就是自己压栈,不过最好先看懂递归的,自己创建一个栈,然后partition的结果是返回数组的左边界,等于区域的两个边界,以及数组的有边界。将这个数据压进栈中,退出整个过程的条件就是栈不为空,进入while之后,先将栈顶的数组拿出来,如果这个数组的左边界<右边界,才可以继续进行partition,然后这个partition的过程又分为做部分的partition,和右部分的partition,这两个部分的partition同样都需要先判断是否左边界<右边界,否则直接舍弃这次partition。当栈为空的时候,整个过程结束。

我是用了比较器的思想来进行验证自己的算法的正确与否的,数据量设定为 100,0000,这样的数据量足返回true,足以证明是正确的了。

下面看代码,过程中使用到了自己写的工具类,放到最后面:

/**
* 非递归随机快排
* @author BarryLee
* @2018年8月16日@上午10:42:30
*/
public class _03quicksort {
public void quicksort(int[]arr) {
if(arr==null || arr.length<2) {
return;
}
process(arr, 0, arr.length-1);
}
public void process(int[]arr,int left,int right) {
if(left<right) {
Stack<Integer[]>stack = new Stack<>();
Random r = new Random();
Utils.swap(arr, r.nextInt(right-left+1)+left, right);
stack.push(partition(arr, left, right, arr[right]));
while(!stack.isEmpty()) {
Integer[]pro = stack.pop();
if(pro[0]<pro[3]) {
if(pro[0]<pro[1]) {
Utils.swap(arr, r.nextInt((pro[1]-1)-pro[0]+1)+pro[0], pro[1]-1);
stack.push(partition(arr, pro[0], pro[1]-1, arr[pro[1]-1]));
}
if(pro[2]<pro[3]) {
Utils.swap(arr, r.nextInt(pro[3]-(pro[2]+1)+1)+pro[2]+1, pro[3]);
stack.push(partition(arr, pro[2]+1, pro[3], arr[pro[3]]));
}
}
}
}
}
public Integer[] partition(int[]arr,int left,int right,int num) {
int i = left;
int less = left-1;
int more = right;
while(i<more) {
if(arr[i]<num) {
Utils.swap(arr, i++, ++less);
}else if(arr[i]>num) {
Utils.swap(arr, i, --more);
}else {
i++;
}
}
Utils.swap(arr, more, right);
return new Integer[] {left,less+1,more,right};
}

//测试 - 1000000数据测试
@Test
public void testQuickSort() {
for(int i = 0;i<1000000;i++) {
int[]arr1 = Utils.randomArr(30, 50);
int[]arr2 = Utils.copyArr(arr1);
quicksort(arr1);
Arrays.sort(arr2);
if(!Utils.isEqual(arr1, arr2)) {
System.out.println(false);
Utils.printArr(arr1);
Utils.printArr(arr2);
return ;
}
}
System.out.println(true);
}

}
public class Utils {
/**
* 交换两个数
* @param arr
* @param i
* @param j
*/
public static void swap(int[] arr,int i,int j){
if(arr[i]==arr[j])return;
arr[i] = arr[i]^arr[j];
arr[j] = arr[i]^arr[j];
arr[i] = arr[i]^arr[j];
}

/**
* 打印一维数组
* @param arr
*/
public static void printArr(int[]arr) {
for (int i : arr) {
System.out.print(i+" ");
}
System.out.println();
}
/**
* 打印一维数组
* @param arr
*/
public static void printArr(Integer[]arr) {
for (Integer i : arr) {
System.out.print(i+" ");
}
System.out.println();
}

/**
* 打印二维数组
* @param arr
*/
public static void printArr(int[][]arr) {
for (int[] is : arr) {
for (int i : is) {
System.out.print(i+" ");
}
System.out.println();
}
System.out.println();
}

/**
* 生成一个一维随机数组
* @param len
* @param val
* @return
*/
public static int[] randomArr(int len ,int val){
int arr[] = new int[len];
for (int i = 0; i < arr.length; i++) {
arr[i] = (int)(val*Math.random()-val*Math.random());
}
return arr;
}

/**
* 判断两个数组是否相等
* @param arr1
* @param arr2
* @return
*/
public static boolean isEqual(int arr1[], int arr2[]) {
if (arr1 == null || arr2 == null || arr1.length == 0 || arr2.length == 0 || arr1.length != arr2.length) {
return false;
}
for (int i = 0; i < arr2.length; i++) {
if (arr1[i] != arr2[i]) {
return false;
}
}
return true;
}

public static int[] copyArr(int[]arr) {
if(arr==null || arr.length==0) {
return new int[] {};
}
int[]arr2 = new int[arr.length];
for(int i = 0;i<arr.length;i++) {
arr2[i] = arr[i];
}
return arr2;
}
}

--------------------------假装有分割线(2018.10.2)----------------------------------

下面是我今天改版的随机快排,代码稍微简洁了一些,看起来,舒服,思路是我想要的那种

package sort;

import java.util.Arrays;
import java.util.Random;
import java.util.Stack;

import org.junit.Test;

import pubs.MyUtils;

/*
* 随机快排 - 非递归版
*/
public class QuickSort2 {
public static void quickSort(int[]arr) {
if(null==arr || arr.length<2) {
return;
}
process(arr,0,arr.length-1);
}

private static void process(int[] arr, int left, int right) {
if(left<right) {
Stack<int[]>stack = new Stack<>();
stack.push(partition(arr, left, right));
while(!stack.isEmpty()) {
int[]p = stack.pop();
if(p[0]<p[1]-1) {//不能是p[0]+1<p[1]-1,因为p[0]是left,还没排好序
stack.push(partition(arr, p[0],p[1]-1));
}
if(p[2]+1<p[3]) {
stack.push(partition(arr, p[2]+1, p[3]));
}
}
}
}
private static int[] partition(int[]arr ,int left,int right) {
int n = arr[new Random().nextInt(right-left)+left];
int less = left-1;
int more = right+1;
int i = left;
while(i<more) {
if(arr[i]>n) {
MyUtils.swap(arr, i, --more);
}else if(arr[i]<n) {
MyUtils.swap(arr, i++, ++less);
}else {
i++;
}
}
return new int[] {left,less+1,i-1,right};
}
@Test
public void test() {
boolean isTrue = true;
for(int i = 0;i<100000;i++) {
int[]arr1 = MyUtils.randomArr(100, 30);
int[]arr2 = MyUtils.copyArr(arr1);
quickSort(arr1);
Arrays.sort(arr2);
if(!MyUtils.isEqual(arr1, arr2)) {
isTrue = false;
MyUtils.printArr(arr2);
MyUtils.printArr(arr1);
break;
}
}
System.out.println(isTrue);
}
}

 

标签:arr,递归,int,pro,快排,随机,left,public,arr2
From: https://blog.51cto.com/u_15741949/6067954

相关文章

  • 【YBT2023寒假Day10 B】随机游走(记忆化搜索)
    随机游走题目链接:YBT2023寒假Day10B题目大意有n个点排成环,你一开始在1号点,每次可以等概率选择左边跳两格,左边跳一格,右边跳一格,右边跳两格。走到一个走过的点就停......
  • C/C++学生随机抽号演讲计分系统[2023-02-19]
    C/C++学生随机抽号演讲计分系统[2023-02-19]学生随机抽号演讲计分系统(★★★★)设计一款用于课程大作业检查或比赛计分的软件,基本功能:(1)设置本课程的学生总数(2)根据......
  • 用set做一轮无重复纯随机
    前端时间面腾讯的时候,一位老师问了一个相当有趣的问题:假设存在一个音乐播放器,里面有一个100首歌的歌单。现在需要做一个随机播放功能,要求不重复的随机播放完一百首歌。当时......
  • 输出不重复的随机数
    packagecom.fqs.demo1;importjava.util.Random;publicclassOnly3{publicstaticvoidmain(String[]args){//输出不重复的随机数范围0,1,2,3,......
  • 经典递归
    汉诺塔问题描述有三根柱子,分别名为A,B,C。初始时,在柱子A上有n个圆盘,他们从上往下,盘子的大小是从小到大。在移动和摆放的过程中,小盘子必须在大盘子上面。在保证规则的......
  • 传参的方式 输出不重复的 随机数
    packagecom.fqs.demo1;importjava.util.Random;publicclassOnly2{publicstaticvoidmain(String[]args){//用传参方式输出不重复的随机数......
  • 算法刷题-无重复字符的最长子串(哈希表、字符串)、数字 1 的个数(递归、数学)、对称二
    无重复字符的最长子串(哈希表、字符串)给定一个字符串,请你找出其中不含有重复字符的**最长子串**的长度。示例1:输入:s="abcabcbb"输出:3解释:因为无重复字符......
  • Golang基础-随机数
    import"math/rand"n:=rand.Intn(100)//nisarandomint,0<=n<100f:=rand.Float64()//fisarandomfloat64,0.0<=f<1.0x:=[]string{"a","b",......
  • java中用递归实现树形结构
    本文以一个多级菜单的案列描述了在java中如何用递归来组装树形结构的数据。java中生成树形结构主要分为两步,(1)在源数据list中找到所有的根节点(2)递归为每一个根节......
  • 算法随想Day17【二叉树】| 二叉树题目的递归解法总结
    总结思考:目前涉及基于二叉树的特性,进行递归的方案有如下:左右子树不相干的递归回溯,左右子树不相干的递归:用前序遍历,先处理"中"节点,判断是否达到终止条件进行相关处理(终止......