经典的八种排序算法:
- 冒泡排序
- 选择排序
- 插入排序
- 希尔排序
- 快排
- 归并排序
- 堆排序
- 基数排序
下面给出Java的代码实现。
纯手打,有问题欢迎评论区讨论。
package com.guo.demo.algorithm;
import java.util.Arrays;
import java.util.Random;
/**
* 八大排序
* @date 2021年12月20日
* @author guowl
*/
public class Sort {
public static void main(String[] args) {
// int[] nums = new int[10];
// for (int i = 0; i < nums.length; i++) {
// nums[i] = new Random().nextInt(1000);
// }
int[] nums = new int[] {3,6,5,1,3,2,6,8,6,4,35,6,7,32,6};
System.out.println("排序前: " + Arrays.toString(nums));
quickSort(nums, 0, nums.length - 1);
System.out.println("排序后: " + Arrays.toString(nums));
}
/**
* 冒泡排序
* @param nums
*/
public static void bubbleSort(int[] nums) {
boolean flag = true; // 在一轮中是否发生了元素交换
for (int i = 0; i < nums.length - 1 && flag; i++) {
// int i = nums.length - 1; i > 0; i--
// int j = 0; j < i; j++
flag = false;
for (int j = 0; j < nums.length - 1 - i; j++) {
if (nums[j + 1] > nums[j]) {
int temp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = temp;
flag = true;
}
}
}
}
/**
* 选择排序
* @param nums
*/
public static void selectSort(int[] nums) {
for (int i = 0; i < nums.length - 1; i++) {
int min = i;
for (int j = i; j < nums.length; j++) {
if (nums[j] < nums[min]) {
min = j;
}
}
if (min != i) {
int temp = nums[min];
nums[min] = nums[i];
nums[i] = temp;
}
}
}
/**
* 插入排序
* @param nums
*/
public static void insertSort(int[] nums) {
for (int i = 1; i < nums.length; i++) {
int num = nums[i];
int j = i - 1;
for (; j >= 0 && num < nums[j]; j--) {
nums[j + 1] = nums[j];
}
nums[j + 1] = num;
}
}
/**
* 希尔排序
* @param nums
*/
public static void shellSort(int[] nums) {
int[] d = new int[] {5,3,1}; // 增量数组
for (int k = 0; k < d.length; k++) {
int dk = d[k];
for (int i = dk; i < nums.length; i++) {
int num = nums[i];
int j = i - dk;
for (; j >= 0 && num < nums[j]; j -= dk) {
nums[j + dk] = nums[j];
}
nums[j + dk] = num;
}
}
}
/**
* 快排
* @param nums
* @param left
* @param right
*/
public static void quickSort(int[] nums, int left, int right) {
if (left >= right)
return;
// 取随机下标与首元素交换作为基准元素
int randomIndex = left + new Random().nextInt(right - left + 1);
swap(nums, left, randomIndex);
// 荷兰国旗分割法
int[] p = partition3(nums, left, right);
quickSort(nums, left, p[0] - 1);
quickSort(nums, p[1] + 1, right);
// int p = partition1(nums, left, right);
// quickSort(nums, left, p - 1);
// quickSort(nums, p + 1, right);
}
/**
* 分割函数: 填坑法
* @param nums
* @param i
* @param j
* @return
*/
private static int partition1(int[] nums, int i, int j) {
int pivot = nums[i]; // 取首元素为基准元素
while (i < j) {
while (i < j && nums[j] >= pivot)
j--;
nums[i] = nums[j];
while (i < j && nums[i] <= pivot)
i++;
nums[j] = nums[i];
}
nums[i] = pivot;
return i;
}
/**
* 分割函数: 交换法
* @param nums
* @param i
* @param j
* @return
*/
private static int partition2(int[] nums, int i, int j) {
int pivot = nums[i]; // 取首元素为基准元素
int p = i;
while (i < j) {
while (i < j && nums[j] >= pivot)
j--;
while (i < j && nums[i] <= pivot)
i++;
if (i < j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
nums[p] = nums[i];
nums[i] = pivot;
return i;
}
/**
* 荷兰国旗式分割法: 分成左中右三部分, 小于区, 等于区, 大于区
* 返回等于区的左右边界下标
* @param nums
* @param left
* @param right
* @return
*/
private static int[] partition3(int[] nums, int left, int right) {
// 可取首或尾元素做基准元素, 这里取首元素
int p = left;
int pivot = nums[p];
int i = left + 1; // i用来遍历数组
// left充当小于区的最右元素下标
// right充当大于区的最左元素下标
++right; // 初始时right往右移一位
while (i < right) {
if (nums[i] < pivot) {
swap(nums, i++, ++left);
} else if (nums[i] > pivot) {
swap(nums, i, --right);
} else {
i++;
}
}
swap(nums, p, left);
return new int[] {left, right - 1};
}
/**
* 归并排序
* @param nums
* @param left
* @param right
*/
public static void mergeSort(int[] nums, int left, int right) {
if (left == right)
return;
int mid = (left +right) / 2;
mergeSort(nums, left, mid);
mergeSort(nums, mid + 1, right);
merge(nums, left, mid, right);
}
/**
* 合并数组nums[left...mid]和nums[mid + 1, right]
* @param nums
* @param left
* @param mid
* @param right
*/
private static void merge(int[] nums, int left, int mid, int right) {
int[] merge = new int[right - left + 1];
int i = left;
int j = mid + 1;
int k = 0;
while (i <= mid && j <= right) {
if (nums[i] <= nums[j]) {
merge[k++] = nums[i++];
} else {
merge[k++] = nums[j++];
}
}
while (i <= mid) {
merge[k++] = nums[i++];
}
while (k <= right) {
merge[k++] = nums[j++];
}
// 复制回原数组
k = 0;
// while (k < merge.length) {
// nums[left++] = merge[k++];
// } // while写法
for (; k < merge.length; k++) {
nums[left++] = merge[k];
}
}
/**
* 堆排序
* @param nums
*/
public static void heapSort(int[] nums) {
// 建堆: 从最后一个非叶子节点开始到根节点进行调整
for (int i = (nums.length / 2) - 1; i >= 0; i--) {
sift(nums, i, nums.length - 1);
}
// 从后往前, 将堆顶元素与待排序部分的尾元素交换,
// 经过交换后已排序区扩大一位, 待排序区缩小一位
// 重新调整待排序区
// 重复以上步骤
for (int i = nums.length - 1; i > 0; i--) {
swap(nums, 0, i);
sift(nums, 0, i - 1);
}
}
/**
* 调整堆: 将堆顶元素从上往下调整
* @param nums
* @param left
* @param right
*/
private static void sift(int[] nums, int left, int right) {
int top = nums[left];
int i = left;
int j = 2 * i + 1;
while (j <= right) {
// 左右节点的较小者
if (j < right && nums[j + 1] < nums[j]) {
j = j + 1;
}
if (nums[j] < top) {
nums[i] = nums[j];
i = j;
j = 2 * i + 1;
} else {
break;
}
}
nums[i] = top;
}
/**
* 基数排序
* @param nums
*/
public static void radixSort(int[] nums) {
int max = nums[0]; // 最大的数
int[] temp = new int[nums.length];
int[] buckets = new int[10];
for (int i = 1; i < nums.length; i++) {
if (nums[i] > max) {
max = nums[i];
}
}
// d:1, 10, 100, 1000, ...; 即个位, 十位, 百位, 千位...
for (int d = 1; max / d > 0; d *= 10) {
for (int i = 0; i < buckets.length; i++) {
buckets[i] = 0;
}
// 1) 先在buckets中存放各位元素的数量
for (int i = 0; i < nums.length; i++) {
// digit: nums[i]在d位的值, 如342在10位的值为4, 在100位的值为3
// 在该位没有值的计算结果为0, 实现了补0的效果, 如12在1000位无值, 计算结果为0
int digit = (nums[i] / d) % 10;
buckets[digit]++;
}
// 2) 再更新buckets各位在temp数组中的下标
for (int i = 1; i < buckets.length; i++) {
buckets[i] += buckets[i - 1];
}
// 从后往前将nums数组按位存放到temp数组
for (int i = nums.length - 1; i >= 0; i--) {
// 通过buckets获取nums[i]在temp数组中存放的位置
// 此时buckets在步骤 2)的处理的用处就体现出来了
int index = --buckets[(nums[i] / d) % 10];
temp[index] = nums[i];
}
// 将temp数组复制回nums数组
for (int i = 0; i < temp.length; i++) {
nums[i] = temp[i];
}
}
}
/**
* 将nums[i]与nums[j]的值交换
* @param nums
* @param i
* @param j
*/
private static void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}