上篇排序算法之插入-希尔-归并Java版:https://blog.csdn.net/u010597819/article/details/86646305
冒泡排序
package org.gallant.algorithm;
import static org.gallant.algorithm.SortUtil.println;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* @author 会灰翔的灰机
* @date 2020/1/19
*/
public class BubbleSort {
public static void bubbleSort(int[] data) {
int size = data.length;
while (size > 1) {
for (int i = 0; i < size - 1; i++) {
int left = data[i];
int right = data[i + 1];
if (left > right) {
data[i] = right;
data[i + 1] = left;
}
}
size--;
}
}
public static void main(String[] args) {
int[] array = SortUtil.randomArray(9);
println(array);
bubbleSort(array);
println(array);
}
}
快速排序
package org.gallant.algorithm;
import static org.gallant.algorithm.SortUtil.println;
/**
* @author 会灰翔的灰机
* @date 2020/1/19
*/
public class QuickSort {
public static void quickSort(int[] data, int start, int end) {
int pivotIndex = partitioning(data, start, end);
if (pivotIndex > -1) {
quickSort(data, start, pivotIndex);
quickSort(data, pivotIndex, end);
}
}
public static int partitioning(int[] data, int start, int end) {
int pivot = data[start];
int i = end, j = start + 1;
while (i >= j) {
int right = data[i];
int left = data[j];
// 相等的值放在右边子序列中
boolean rightLesserPivot = right < pivot;
boolean leftGreaterPivot = left >= pivot;
// 哨兵i大于基准值,继续移动
if (!rightLesserPivot) {
i--;
} else {
// 哨兵j小于基准值,并且哨兵i已经发现大于基准值的值时,移动哨兵j
if (!leftGreaterPivot) {
j++;
}
}
if (leftGreaterPivot && rightLesserPivot) {
// 哨兵i与哨兵j相遇前找到了比基准值大,比基准值小的数值,交换他们的位置
swap(data, left, j, right, i);
i--;
j++;
}
// 哨兵i与哨兵j相遇
if (i == j) {
boolean isLesserPivot = data[i] < pivot;
if (isLesserPivot) {
swap(data, pivot, start, data[i], i);
}
println(data);
return i;
}
}
return -1;
}
public static void swap(int[] data, int leftValue, int leftIndex, int rigthValue, int rightIndex){
data[rightIndex] = leftValue;
data[leftIndex] = rigthValue;
}
public static void main(String[] args) {
int[] array = SortUtil.randomArray(15);
println(array);
// 错误的理解。。。代码有问题,正解见quickSort2方法
quickSort(array, 0, array.length - 1);
println(array);
}
private static void quickSort2(int[] arr, int low, int high) {
if (low < high) {
// 找寻基准数据的正确索引
int index = getIndex(arr, low, high);
// 进行迭代对index之前和之后的数组进行相同的操作使整个数组变成有序
//quickSort(arr, 0, index - 1); 之前的版本,这种姿势有很大的性能问题,谢谢大家的建议
quickSort2(arr, low, index - 1);
quickSort2(arr, index + 1, high);
}
}
private static int getIndex(int[] arr, int low, int high) {
// 基准数据
int tmp = arr[low];
while (low < high) {
// 当队尾的元素大于等于基准数据时,向前挪动high指针
while (low < high && arr[high] >= tmp) {
high--;
}
// 如果队尾元素小于tmp了,需要将其赋值给low
arr[low] = arr[high];
// 当队首元素小于等于tmp时,向前挪动low指针
while (low < high && arr[low] <= tmp) {
low++;
}
// 当队首元素大于tmp时,需要将其赋值给high
arr[high] = arr[low];
}
// 跳出循环时low和high相等,此时的low或high就是tmp的正确索引位置
// 由原理部分可以很清楚的知道low位置的值并不是tmp,所以需要将tmp赋值给arr[low]
arr[low] = tmp;
return low; // 返回tmp的正确位置
}
}
计数排序
package org.gallant.algorithm;
import static org.gallant.algorithm.SortUtil.print;
import static org.gallant.algorithm.SortUtil.println;
/**
* @author 会灰翔的灰机
* @date 2020/1/20
*/
public class CountingSort {
public static void countingSort(int[] data) {
int max = Integer.MIN_VALUE,min = Integer.MAX_VALUE;
// 1. 查找最大值、最小值
for (int i = 0; i < data.length; i++) {
int currentValue = data[i];
if (currentValue > max) {
max = currentValue;
}
if (currentValue < min) {
min = currentValue;
}
}
// 2. 将数据根据最小值映射放入对应的桶内(index下标处)
println("max:"+max+",min:"+min);
int[] count = new int[max - min + 1];
for (int i = 0; i < data.length; i++) {
int currentValue = data[i];
print(currentValue+",");
count[currentValue - min] += 1;
}
println("");
println(count);
// 3. 根据计数桶还原数据到原数据中。计数桶中的数据由于映射的算法可知是有序的
int currentDataIndex = 0;
for (int i = 0; i < count.length; i++) {
int cnt = count[i];
if (cnt > 0) {
for (int j = 0; j < cnt; j++) {
data[currentDataIndex] = min + i;
currentDataIndex++;
}
}
}
}
public static void main(String[] args) {
int[] array = SortUtil.randomArray(11);
println(array);
countingSort(array);
println(array);
}
}
桶排序
package org.gallant.algorithm;
import static org.gallant.algorithm.SortUtil.println;
import java.util.Arrays;
import java.util.Objects;
/**
* @author 会灰翔的灰机
* @date 2020/1/20
*/
public class BucketSort {
public static void bucketSort(int[] array) {
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
// 1. 查找 数字长度 最大值、最小值
for (int currentValue : array) {
int len = getIntegerLength(currentValue);
if (len > max) {
max = len;
}
if (len < min) {
min = len;
}
}
// 2. 将数据根据数字长度以及最小长度,放入对应的桶中
println("max:"+max+",min:"+min);
Integer[][] count = new Integer[max - min + 1][array.length];
for (int i = 0; i < array.length; i++) {
int currentValue = array[i];
Integer[] bucket = count[getIntegerLength(currentValue) - min];
for (int j = 0; j < bucket.length; j++) {
if (bucket[j] == null) {
bucket[j] = currentValue;
break;
}
}
}
println(count);
// 3. 根据映射函数可知,桶的下标大的桶中的所有数据大于下标小的桶中的数据
// 所以将每个桶排序后直接拼接结果便可以得到全局有序的集合
int currentDataIndex = 0;
for (int i = 0; i < count.length; i++) {
Integer[] bucketObj = count[i];
if (bucketObj.length > 0) {
int[] bucket = Arrays.stream(bucketObj).filter(Objects::nonNull).mapToInt(Integer::intValue).toArray();
Sorts.insertSort(bucket);
for (int j = 0; j < bucket.length; j++) {
array[currentDataIndex] = bucket[j];
currentDataIndex++;
}
}
}
}
public static int getIntegerLength(int value) {
return Integer.toString(value).length();
}
public static void main(String[] args) {
int[] array = SortUtil.randomArray2(10);
println(array);
bucketSort(array);
println(array);
}
}
基数排序
- 以LSD为例,假设原来有一串数值如下所示:73, 22, 93, 43, 55, 14, 28, 65, 39, 81。首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶子中
- 接下来将这些桶子中的数值重新串接起来,成为以下的数列:81, 22, 73, 93, 43, 14, 55, 65, 28, 39。接着再进行一次分配,这次是根据十位数来分配
- 接下来将这些桶子中的数值重新串接起来,成为以下的数列:14, 22, 28, 39, 43, 55, 65, 73, 81, 93。这时候整个数列已经排序完毕;如果排序的对象有三位数以上,则持续进行以上的动作直至最高位数为止
package org.gallant.algorithm;
import static org.gallant.algorithm.SortUtil.println;
/**
* @author 会灰翔的灰机
* @date 2020/1/20
*/
public class RadixSort {
public static void radixSort(int[] array) {
int maxLen = 0;
for (int i = 0; i < array.length; i++) {
int currentValue = array[i];
int len = Integer.toString(currentValue).length();
if (len > maxLen) {
maxLen = len;
}
}
// 1. 从个位数至最高位,按每个位的数字进行分桶,逐个执行桶排序
for (int i = 0; i < maxLen; i++) {
Integer[][] buckets = new Integer[10][array.length];
// 2. 分桶
for (int j = 0; j < array.length; j++) {
int currentValue = array[j];
String currentValueStr = String.valueOf(currentValue);
// 自右向左的游标
int cursorIndex = (currentValueStr.length() - 1) - i;
int index = cursorIndex >= 0 ? Character.getNumericValue(currentValueStr.charAt(cursorIndex)) : 0;
Integer[] bucket = buckets[index];
for (int k = 0; k < bucket.length; k++) {
if (bucket[k] == null) {
bucket[k] = currentValue;
break;
}
}
}
int j = 0;
// 2. 分桶后,按照桶顺序重组数组
for (int i1 = 0; i1 < buckets.length; i1++) {
Integer[] bucket = buckets[i1];
System.out.print("当前桶 "+ i1 + " : ");
for (Integer integer : bucket) {
if (integer != null) {
System.out.print(integer + ",");
array[j++] = integer;
}
}
System.out.println();
}
System.out.println("由低位至高位遍历分桶排序,当前位数:" + (i + 1) + ",重组后数组顺序");
println(array);
}
}
public static void main(String[] args) {
int[] array = SortUtil.randomArray2(9);
println(array);
radixSort(array);
println(array);
}
}
堆排序
package org.gallant.algorithm;
import static org.gallant.algorithm.SortUtil.println;
/**
* 参考:https://www.geeksforgeeks.org/heap-sort/
* @author 会灰翔的灰机
* @date 2020/1/21
*/
public class HeapSort {
/**
* 初始数组被看作一个完全二叉树
* Input data: 4, 10, 3, 5, 1
* 4(0)
* / \
* 10(1) 3(2)
* / \
* 5(3) 1(4)
*
* The numbers in bracket represent the indices in the array
* representation of data.
*
* Applying heapify procedure to index 1:
* 4(0)
* / \
* 10(1) 3(2)
* / \
* 5(3) 1(4)
*
* Applying heapify procedure to index 0:
* 10(0)
* / \
* 5(1) 3(2)
* / \
* 4(3) 1(4)
* The heapify procedure calls itself recursively to build heap
* in top down manner.
*/
public static void heapSort(int[] array) {
int heapSize = array.length;
// 1. 构建最大堆。最大堆的每个非叶子节点都是左右子树的最大节点。即:构建之后0索引处为整棵树的最大值
for (int i = heapSize / 2 - 1; i >= 0; i--) {
heapify(array, heapSize, i);
}
for (int i = array.length - 1; i >= 0 ; i--) {
// 2. 将最大值交换至最后,剩余[0, n - 2]恢复非最大堆状态。n - 1索引处为当前最大堆中的最大值
swap(array, i, 0);
// 3. 重复步骤1,2,直至整个堆有序
heapify(array, i, 0);
}
}
public static void heapify(int[] array, int heapSize, int largestNodeIndex) {
// 初始化根节点
int largest = largestNodeIndex;
// 根节点左子节点索引
int leftChild = 2 * largestNodeIndex + 1;
// 根节点右子节点索引
int rightChild = 2 * largestNodeIndex + 2;
// 如果左子树大于根节点,更新根节点索引
if (leftChild < heapSize && array[leftChild] > array[largest]) {
largest = leftChild;
}
// 如果右子树大于根节点,更新根节点索引
if (rightChild < heapSize && array[rightChild] > array[largest]) {
largest = rightChild;
}
// 根节点索引发生变更,更新根节点
if (largest != largestNodeIndex) {
swap(array, largest, largestNodeIndex);
// 左子树或右子树发生变更,递归更新发生变更的子树
heapify(array, heapSize, largest);
}
}
public static void swap(int[] array, int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
public static void main(String[] args) {
int[] array = SortUtil.randomArray(9);
println(array);
heapSort(array);
println(array);
}
}