快速排序分析推导图
class Untitled {
public static void main(String[] args) {
System.out.println("hello https://tool.lu/");
int[] array = {6,1,2,7,9,3,4,5,10,8};
quick(array, 0, array.length - 1);
for(int i = 0; i < array.length; i++){
System.out.println(" " + array[i]);
}
}
public static void quick(int[] array, int left, int right) {
if(left > right){
return;
}
// 1、确定基数
int base = array[left];
// 2、定义i
int i = left;
// 3、定义j
int j = right;
//如果i和j不相遇,那么就一直检索
while(i != j){
// 右侧索引检测,如果值大于等于基数 就继续检索, 并且不超过i
while(array[j] >= base && j > i){
j--;
}
// 左侧检索,如果值小于等我基数,就检索,同样不能超过j
while(array[i] <= base && j > i){
i++;
}
// 能走到这 说明找到对应索引了,要把j 和i位置值交换
int num = array[i];
array[i] = array[j];
array[j] = num;
}
// 走到这里 说明相遇了, 相遇要把基数 和 此时位置交换
array[left] = array[i]; //array[j]也可以
array[i] = base;
// 接下来重复排左边的
quick(array, left, i - 1);
// 重复排右边的
quick(array, j + 1, right);
}
}
二、归并排序
归并排序基本思想:
合并相邻有序子序列:
再来看看治阶段,我们需要将两个已经有序的子序列合并成一个有序序列,比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],来看下实现步骤
代码如下:
public static void main(String[] args) {
// 冒泡排序
// BubbleSort();
// 选择排序
// selecterSort();
// 插入排序 8万数据 4s
// insertSort();
//希尔交换排序 8万数据 17s 80万1s 800万4s
// shellSort();
// 希尔移动排序 8万数据不到1s
//shellMove();
// 快排 8万数据 和80 万都不到1s 800万2s
// int[] arr = {6,1,2,7,9,3,4,5,10,8};
// quickSort(arr, 0, arr.length - 1);
// System.out.println(Arrays.toString(arr));
//归并排序
int[] arr = {6,1,2,7,9,3,4,5,10,8};
int[] copy = new int[arr.length];
mergeSort(arr, 0, arr.length - 1, copy);
System.out.println(Arrays.toString(arr));
}
/**
* 分 + 合方法
*/
private static void mergeSort(int[] arr, int left, int right, int[] temp) {
if(left < right) {
System.out.println("left :" + left + " right:" + right);
int mid = (left + right) / 2; //中间索引
//向左递归进行分解
mergeSort(arr, left, mid, temp);
//向右递归进行分解
mergeSort(arr, mid + 1, right, temp);
//合并
merge(arr, left, mid, right, temp);
}
}
/**
* @param arr 排序组
* @param left 左边有序序列左指针
* @param mid 中间索引
* @param right 右边有序序列右指针
* @param temp 中转的数组
* 合并的方法
*/
private static void merge(int[] arr, int left, int mid, int right, int[] temp) {
// 左指针
int i = left;
// 右指针
int j = mid + 1;
// 中转数组的下标
int postison = 0;
//1、把左右两侧数据添加到临时数组
// 直到左边或右边,有一边处理完毕
while (i <= mid && j <= right){ // 没有到边一直循环
if(arr[i] <= arr[j]) {
temp[postison] = arr[i];
i += 1;
postison += 1;
}else {
temp[postison] = arr[j];
j += 1;
postison += 1;
}
}
// 2、有一边到头了,把剩余的全部方法临时数组
while (i <= mid){ //左边没有到头
temp[postison] = arr[i];
i += 1;
postison += 1;
}
while (j <= right){ //右边没有到头
temp[postison] = arr[j];
j += 1;
postison += 1;
}
// 3 、将temp数组的元素拷贝到arr
// 注意,并不是每次都拷贝所有
postison = 0;
int tempLeft = left;
while (tempLeft <= right){
arr[tempLeft] = temp[postison];
tempLeft += 1;
postison += 1;
}
}
三、基数排序
基数排序图文说明:
1、将数组 {53, 3, 542, 748, 14, 214} 使用基数排序, 进行升序排序
代码实现:
public static void radixSort(){
int[] arr = {53, 3, 542, 748, 14, 214};
// 1、首先找到在最大数,然后计算出最大的长度
int max = 0;
for(int i = 0; i < arr.length; i++) {
if(arr[i] > max) {
max = arr[i];
}
}
int length = (max + "").length();
// 2、创建2维数组,10个桶, 0 - 9, 然后大小为了防止长度不够,大小都统一成arr.length
int[][] bucket = new int[10][arr.length];
// 3、创建保存每个桶存放的数量 坐标
int[] bucketElementCounts = new int[10];
/**
* 推导每一次过程
*/
// 4.1、比较个位数放入桶中。
for(int i = 0; i < arr.length; i++) {
// 找到个位数字
int digitOfElement = arr[i] % 10;
// 放入对应位置桶中, 第二个参数:每个桶对用的位置, 加进去之后 还要在++
bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[i];
bucketElementCounts[digitOfElement]++;
}
// 4.2 按照这个顺序取出来,在放入原数组中去
int index = 0;
for(int i = 0; i < bucketElementCounts.length; i++) {
// !=0 说明在对应的同放入数据了
if(bucketElementCounts[i] != 0) {
// 遍历每个桶的存入的数量
for(int l = 0; l < bucketElementCounts[i]; l++) {
arr[index] = bucket[i][l];
index++;
}
}
// 每次处理完毕之后,都把存的位置 变成0
bucketElementCounts[i] = 0;
}
System.out.println("第 1 轮,对个位的排序处理 arr =" + Arrays.toString(arr));
// 第二轮
for(int i = 0; i < arr.length; i++) {
// 把十位数字放入对应的桶中
int digitOfElement = arr[i] / 10 % 10;
bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[i];
bucketElementCounts[digitOfElement]++;
}
// 取出来放入原数组
index = 0;
for(int i = 0; i < bucketElementCounts.length; i++) {
if(bucketElementCounts[i] != 0) {
for(int l = 0; l < bucketElementCounts[i]; l++) {
arr[index] = bucket[i][l];
index++;
}
}
bucketElementCounts[i] = 0;
}
System.out.println("第 2轮,对个位的排序处理 arr =" + Arrays.toString(arr));
// 第二轮
for(int i = 0; i < arr.length; i++) {
// 把十位数字放入对应的桶中
int digitOfElement = arr[i] / 100 % 10;
bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[i];
bucketElementCounts[digitOfElement]++;
}
// 取出来放入原数组
index = 0;
for(int i = 0; i < bucketElementCounts.length; i++) {
if(bucketElementCounts[i] != 0) {
for(int l = 0; l < bucketElementCounts[i]; l++) {
arr[index] = bucket[i][l];
index++;
}
}
bucketElementCounts[i] = 0;
}
System.out.println("第 3轮,对个位的排序处理 arr =" + Arrays.toString(arr));
/** ====================华丽的分割线=====================*/
// n 代表每次是找的位数上的值
for(int i = 0, n = 1; i < length; i++, n *= 10) {
//(针对每个元素的对应位进行排序处理), 第一次是个位,第二次是十位,第三次是百位..
// 找到个位数字, 放入对应桶中
for(int j = 0; j < arr.length; j++) {
int digitOfElement = arr[j] / n % 10;
bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
bucketElementCounts[digitOfElement]++;
}
// 遍历每一个桶取出桶中数据,放入原数组
int index = 0;
for(int k = 0; k < bucketElementCounts.length; k++) {
// 取出对应桶存放的位置
if(bucketElementCounts[k] != 0) {
// 遍历每个位置,根据位置取出桶中数据,放入原数组
for(int l = 0; l < bucketElementCounts[k]; l++) {
arr[index] = bucket[k][l];
index++;
}
}
bucketElementCounts[k] = 0;
}
System.out.println("第 " + (i+1) +"轮,对个位的排序处理 arr =" + Arrays.toString(arr));
}
System.out.println("结果,对个位的排序处理 arr =" + Arrays.toString(arr));
}