package com.wyw.algorithm.sort;
/**
* 快速排序 -随机快排 复杂度 O(N*logN) , 如果不以随机数做标杆,直接以数组最后一个数做标杆,复杂度O(N^2)
* 思路:
* 1.随机找一个数放在数组最后,作为标杆
* 2.小于标杆值的放左边,等于标杆值的放中间,大于标杆值的放右边, 把数组划分成3块后,将标杆值 和 大于区的最左边一个值交换,即标杆值放在等于区 (荷兰国旗问题)
* 3.前提:小于区边界不能越过大于区边界,分别将 小于区 和大于区的 递归(非递归方法 自己压栈,弹出,和递归类似) 第1,2 步骤
*/
public static void main(String[] args) {
int[] arr = {2,4,7,5,4,3,1,8,2,54,32};
quicklySort01(arr);
//quicklySort02(arr);
print(arr);
}
public static void quicklySort01(int[] arr){
if (arr == null || arr.length < 2){
return;
}
sort(arr,0,arr.length -1);
}
//随机快排-递归版
public static void sort(int[] arr,int left,int right){
if (left >= right) {
return;
}
//随机找一个数放到数组最后一位作为标杆 随机快排
int s = left + (int) (Math.random() * (right - left + 1)) ;
swap(arr,s,right);
int[] equ = hlgqCompair(arr,left,right); //得到 < arr[X] | = arr[x] | > arr[x]
sort(arr,left,equ[0]-1); // < arr[X] 继续用荷兰国旗排序
sort(arr,equ[1]+1,right); // > arr[X] 继续用荷兰国旗排序
}
//荷兰国旗问题 : 将数组 L....R 范围 排序成 < arr[R] 区 在左边, == arr[R] 在中间, > arr[R] 在右边
private static int[] hlgqCompair(int[] arr,int L,int R){
if (L > R){
return new int[]{-1,-1};
}
if (L == R){
return new int[]{L,R};
}
int left = L -1 ; // < arr[R] 区 左边界
int right = R; // > arr[R] 区 右边界
int index = L; //当前位置
while (index < right){
if (arr[index] < arr[R]){ //如果当前位置的值小于 标杆的值,则当前位置和 小于包围圈的右边第一位交换,当前位置后移,小于包围圈往右扩
swap(arr,index,left + 1);
left ++;
index ++;
}else if(arr[index] > arr[R]){ //如果当前位置的值大于 标杆的值,则当前位置和大于包围圈的左边第一位交换,当前位置不变(新换过来的值还没比较),大于包围圈向左扩
swap(arr,index,right-1);
right --;
}else{ //如果当前位置的值 等于标杆的值,则当前位置后移一位,其他不变
index ++;
}
}
swap(arr,right,R); // 将标杆和 > 区 右边界交换,实现 < arr[R] 在左边, > arr[R] 在右边, == arr[R] 在中间
return new int[]{left+1,right};
}
//随机快排-非递归版
private static void quicklySort02(int[] arr){
if (arr == null || arr.length < 2){
return;
}
//随机找一个数放到数组最后一位作为标杆 随机快排
int s = (int) (Math.random() * arr.length) ;
swap(arr,s,arr.length-1);
int[] equ = hlgqCompair(arr,0,arr.length-1); //得到 < arr[X] | = arr[x] | > arr[x]
Stack<Op> stack = new Stack<>();
stack.push(new Op(0,equ[0]-1));
stack.push(new Op(equ[0]+1,arr.length-1));
while (!stack.empty()){
Op op = stack.pop();
int l = op.l;
int r = op.r;
if (l < r){
int ss = l + (int) (Math.random() * (r - l +1)) ;
swap(arr,ss,r);
int[] equu = hlgqCompair(arr,l,r); //得到 < arr[X] | = arr[x] | > arr[x]
stack.push(new Op(l,equu[0]-1));
stack.push(new Op(equu[0]+1,r));
}
}
}
//定义一个类,记录要比较的数组下标位置
public static class Op {
private int l;
private int r;
public Op(int l, int r) {
this.l = l;
this.r = r;
}
}
private static void swap(int[] arr,int i, int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
private static void print(int[] arr){
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]);
System.out.print(" ");
}
System.out.println();
}
package com.wyw.algorithm.sort;
/**
* 归并排序
* 拆分成两个有序的数组,再 对比合并成一个有序的数组,递归多次
* @author wyw
* @date 2021/11/7
*/
public class Code05_margeSort {
public static void main(String[] args) {
int [] arr = {9,6,11,3,5,12,8,7,10,15,14,4,1,13,2};
sort(arr,0,arr.length-1);
print(arr);
}
/**
* left : 传进来的部分数据的 数组起始位置下标
* right : 传进来的部分数据的 mind+1 位置下标
* rightBound : 传进来的部分数据的 结束位置下标
* @param arr
* @param left
* @param right
* @param rightBound
*/
static void marge(int[] arr,int left,int right,int rightBound){
int mind = right-1;
int [] temp = new int[rightBound-left+1];
int i = left;
int j = right;
int k = 0;
while(i <= mind && j <=rightBound){
temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];
}
while(i <= mind){temp[k++] =arr[i++];}
while(j<=rightBound){temp[k++]=arr[j++];}
System.out.println("left="+left+"right="+right+"rightBound="+rightBound);
//print(temp);
//int n = 0;
/*for (int l = left,n = 0; l <rightBound-left+1 ; l++,n++) {
arr[l] = temp[n];
}*/
//print(arr);
for (int l = 0; l < temp.length; l++) {
arr[left+l] = temp[l];
}
}
/**
*
* @param arr
* @param left 传进来的部分数据的 数组起始位置下标
* @param right 传进来的部分数据的 数组结束位置下标
*/
public static void sort(int[] arr, int left, int right){
if(left == right) return;
int mind = left + (right - left)/2;
sort(arr,left,mind);
sort(arr,mind+1,right);
marge(arr,left,mind+1,right);
}
public static void swap(int[] arr , int i,int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void print(int[] arr){
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
System.out.println("");
}
}
package com.wyw.algorithm.sort;
/*
* 插入排序
* 思路:首先默认第一个元素是有序的,从第二个元素开始和前面的元素比较,
* 方法一:比前面的元素小就交换,反之不交换,直到最后一个元素。(交换)
* 方法二: 比前面的元素小,前面的值就往后移,直到找到正确的位置 后, 插入的该位置 (把需要插入的值用临时变量存起来,直到找到正确的位置后再插入)
* @author wyw
* @date 2021/11/6
*/
public class Code03_insertSort {
public static void main(String[] args) {
int[] arr = {2,6,3,5,7,9,0,3,6,23,6,5,97,100,24,25};
sort(arr);
print(arr);
}
/**
* 把i位置的数与i 前面位置的数依次比较 ,同时 把值往后移一位 ,直到找到 正确的位置 之后 再插入
* 和 sort2 比就是 不用每次交换赋值,而是找到正确的位置在赋值, 即省了一次赋值动作
* @param arr
*/
public static void sort(int[] arr){
for (int i = 1; i < arr.length; i++) {
int temp = arr[i]; //把即将要插入的值用临时变量记录下,留出空位,让前面的值 往后移
int n = i; //记录 移动之后的 空位
for (int j = i; j >0 ; j--) {
if (temp < arr[j-1]){
arr[j] = arr[j-1]; //把 j-1 位置的值 往后移
n = j-1; //记录 移动之后的 空位
}else{
break;
}
}
arr[n] = temp;
}
}
/**
* 把i位置的值和i前面的值 依次比较,如果小就交换
* @param arr
*/
public static void sort2(int[] arr){
for (int i = 1; i < arr.length; i++) {
for (int j = i; j > 0; j--) {
if (arr[j] < arr[j-1])
swap(arr,j,j-1);
}
}
}
public static void swap(int[] arr , int i,int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void print(int[] arr){
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
System.out.println("");
}
}