声明:作者比较懒,写这篇文章是为了以后用到的时候CV,所以注释写的不详细,也没有针对算法进行讲解,敬请谅解。
目录
冒泡排序
public static void bubbleSort(int[] arr) {
int temp = 0;
//外层for循环表示排序的趟数
for (int i = 0; i < arr.length - 1; i++) {
//内层for循环表示这一趟需要比较的次数
for (int j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
System.out.println("bubbleSort后的数组:");
System.out.println(Arrays.toString(arr));
}
选择排序
public static void selectSort(int[] arr) {
int temp = 0, min = 0;
//外层for循环表示排序的趟数
for (int i = 0; i < arr.length - 1; i++) {
min = i;
//循环查找最小值,记录最小值的index
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[min]) {
min = j;
}
}
if (min != i) {
temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
}
}
System.out.println("selectSort后的数组:");
System.out.println(Arrays.toString(arr));
}
插入排序
public static void insertSort(int[] arr) {
//插入排序在序列基本有序的前提下效率是很高的,所以从后往前插入是一个更好的选择
int temp = 0;
//外循环表示排序的趟数
//每次选取第i+1张牌,从后往前开始比较,插入到比它小的第一张牌的后面
for (int i = 1; i < arr.length; i++) {
int positon = i;
for (int j = positon - 1; j >= 0; j--) {
if (arr[positon] < arr[j]) {
temp = arr[positon];
arr[positon] = arr[j];
arr[j] = temp;
positon--;
}
}
}
System.out.println("insertSort后的数组:");
System.out.println(Arrays.toString(arr));
}
归并排序
public static void mergeSort(int[] arr) {
int[] temp = new int[arr.length];
merge(arr, temp, 0, arr.length - 1);
System.out.println("nmergeSort后的数组:");
System.out.println(Arrays.toString(arr));
}
public static void merge(int[] arr, int[] temp, int left, int right) {
//当left==right时,已经达到最小数组
if (left < right) {
int middle = (left + right) / 2;
//分而治之,把原数组分成左右两个数组
merge(arr, temp, left, middle);
merge(arr, temp, middle + 1, right);
//把分而治之的两个数组归并在一起
mergeSortedArray(arr, temp, left, middle, right);
}
}
public static void mergeSortedArray(int[] arr, int[] temp, int left, int middle, int right) {
int i = left;
int j = middle + 1;
int k = 0;
//双指针进行比较,当其中一个指针走到末尾时结束循环
while (i <= middle && j <= right) {
temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];
}
//此时其中一个指针已经走到了末尾,依次赋值完成归并
while (i <= middle) {
temp[k++] = arr[i++];
}
while (j <= right) {
temp[k++] = arr[j++];
}
//将排序完成后temp数组中的值放回原数组中
for (i = 0; i < k; i++) {
//i + left表示temp中的值在arr中对应的位置
arr[i + left] = temp[i];
}
}
快速排序
public static void quickSort(int[] arr) {
quick(arr, 0, arr.length - 1);
System.out.println("quickSort后的数组:");
System.out.println(Arrays.toString(arr));
}
public static void quick(int[] arr, int low, int high) {
//当low>=high时,已经完成排序
if (low >= high) {
return;
}
int i = low, j = high;
//选择基准值这里选择的是数组中间的那个元素为基准值
// int pivot = arr[(low + high) / 2];
// int temp = 0;
// temp = arr[low];
// arr[low] = arr[(low + high) / 2];
// arr[(low + high) / 2] = temp;
int pivot = arr[low];
//双指针让基准归位
while (i < j) {
//从后往前走,当找到比pivot小的值的时候退出循环
while (arr[j] >= pivot && i < j) {
j--;
}
//第一次运行时,相当于覆盖了pivot的值
// 把比pivot小的值移到arr[i]的位置,并把arr[j]的位置让了出来
if (i < j) {
arr[i] = arr[j];
}
//从前往后走,当找到比pivot大的值的时候退出循环
while (arr[i] <= pivot && i < j) {
i++;
}
// 把比pivot大的值移到arr[i]的位置,并把arr[i]的位置让了出来
if (i < j) {
arr[j] = arr[i];
}
}
arr[i] = pivot;//基准归位
//分成左右两个数组继续运行
quick(arr, low, i - 1);
quick(arr, i + 1, high);
}
堆排序
public static void heapSort(int[] arr) {
int last = arr.length - 1;
//建立堆
buildMaxHeap(arr);
//把最大堆的根结点放到数组的末尾,并限制数组的可操作长度
//然后调整为最大堆,并重复以上操作,直到last=0
while (last > 0) {
swap(arr, 0, last--);
adjustHeap(arr, 0, last);
}
System.out.println("heapSort后的数组:");
System.out.println(Arrays.toString(arr));
}
public static void buildMaxHeap(int[] arr) {
int len = arr.length;
//从最后一个结点的父结点开始调整
for (int i = (len - 1) / 2; i >= 0; i--) {
adjustHeap(arr, i, len - 1);
}
}
//i表示即将进行调整的元素的位置,last表示未调整完成的数组尾
//下沉调整,类比于堆的删除操作
public static void adjustHeap(int[] arr, int i, int last) {
int temp = arr[i];//保存父结点和两个子结点中的最大值
int largest = i;//记录父结点与两个子结点中的最大值的index
int left = 0, right = 0;//表示两个子结点的index
//当左结点大于最后一个结点时退出循环
while (left <= last) {
left = 2 * i + 1;
right = left + 1;
//与左孩子进行比较
if (left <= last && temp < arr[left]) {
largest = left;
temp = arr[largest];
}
//与右孩子进行比较
if (right <= last && temp < arr[right]) {
largest = right;
temp = arr[largest];
}
//在这一轮中i的值没有发生改变,此时已经调整好,退出循环
if (largest == i) {
break;
}
//完成交换,并把i指向交换后的index继续调整
swap(arr, i, largest);
i = largest;
temp = arr[i];
}
}
//交换函数
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
希尔排序
public static void shellSort(int[] arr) {
//第一种增量是Donald Shell提出的增量,即折半降低直到1
//第二种增量Hibbard:{1, 3, ..., 2k-1}
//第三种增量Sedgewick:{1, 5, 19, 41, 109...}该序列中的项或者是9*4^i - 9*2^i + 1或者是4^i - 3*2^i + 1
//第一层循环表示增量序列
//第二三层表示按照增量序列进行插入排序
//按照第一种增量序列进行希尔排序
// for (int gap = arr.length / 2; gap >= 1; gap /= 2) {
// for (int i = gap; i < arr.length; i += gap) {
// int positon = i;
// for (int j = positon - gap; j >= 0; j -= gap) {
// if (arr[positon] < arr[j]) {
// swap(arr, positon, j);
// positon -= gap;
// }
// }
//
// }
//Kunth 增量序列:1,4,13,40.121, ...(3n+1)
int gap = 1;
while (gap < arr.length / 3) {
gap = gap * 3 + 1;
}
for (; gap >= 1; gap /= 3) {
for (int i = gap; i < arr.length; i += gap) {
int positon = i;
for (int j = positon - gap; j >= 0; j -= gap) {
if (arr[positon] < arr[j]) {
swap(arr, positon, j);
positon -= gap;
}
}
}
}
System.out.println("shellSort后的数组:");
System.out.println(Arrays.toString(arr));
}
//交换函数
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
计数排序
//计数排序是一个牺牲空间换取时间的排序方法
public static void countSort(int[] arr) {
//获得数组的范围min-max
int max = arr[0], min = arr[0];
for (int i = 0; i < arr.length; i++) {
max = Math.max(max, arr[i]);
min = Math.min(min, arr[i]);
}
//将数组中的值统计到count中
int[] count = new int[max - min + 1];
for (int i = 0; i < arr.length; i++) {
count[arr[i] - min]++;
}
//读取count中的数,完成赋值
int position = 0;
for (int i = 0; i < arr.length; i++) {
while (count[position] == 0) {
position++;
}
arr[i] = position + min;
count[position]--;
}
System.out.println("countSort后的数组:");
System.out.println(Arrays.toString(arr));
}
桶排序
public static void bucketSort(int[] arr) {
int max = arr[0], min = arr[0];
int len = arr.length;
for (int i = 0; i < len; i++) {
max = Math.max(max, arr[i]);
min = Math.min(min, arr[i]);
}
//桶的数量,桶的数量越多,速度越快,这里选取的桶的数量为(max-min)/len + 1
int bucketNum = (max - min) / len + 1;
ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum);
for (int i = 0; i < bucketNum; i++) {
bucketArr.add(new ArrayList<Integer>());
}
//把数组中的元素放到桶里
for (int i = 0; i < len; i++) {
int positon = (arr[i] - min) / len;
bucketArr.get(positon).add(arr[i]);
}
//调用其他的排序方法对桶内元素进行排序
for (int i = 0; i < bucketNum; i++) {
Collections.sort(bucketArr.get(i));
}
//把桶拼接到一起
int position = 0;
for (int i = 0; i < bucketNum; i++) {
for (int j = 0; j < bucketArr.get(i).size(); j++) {
arr[position++] = bucketArr.get(i).get(j);
}
}
System.out.println("bucketSort后的数组:");
System.out.println(Arrays.toString(arr));
}
基数排序
public static void radixSort(int[] arr) {
int len = arr.length;
int[][] radixArr = new int[10][arr.length];
int[] counter = new int[10];
//找到数组中最大的值,以此来判断排序的次数
int max = 0;
for (int i = 0; i < len; i++) {
max = Math.max(max, arr[i]);
}
//n用以对arr[i]位数的处理
int n = 1;
while (max > 0) {
//将arr中的值放到radixArr中
for (int i = 0; i < len; i++) {
int index = (arr[i] / n) % 10;
radixArr[index][counter[index]] = arr[i];
counter[index]++;
}
//把radixArr中的数据放回原数组
int position = 0;
for (int i = 0; i < radixArr.length; i++) {
for (int j = 0; j < counter[i]; j++) {
arr[position++] = radixArr[i][j];
}
}
//重置计数器
for (int i = 0; i < 10; i++) {
counter[i] = 0;
}
max /= 10;
n *= 10;
}
System.out.println("radixSort后的数组:");
System.out.println(Arrays.toString(arr));
}
测试代码
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class Sort {
public static void main(String[] args) {
int[] arr = new int[1000];
for (int i = 0; i < arr.length; i++) {
arr[i] = i;
}
System.out.println("原数组:");
System.out.println(Arrays.toString(arr));
//打乱数组
shuffle(arr);
//冒泡排序升序
bubbleSort(arr);
//排序测试
testIncreasing(arr);
//打乱数组
shuffle(arr);
//选择排序升序
selectSort(arr);
//排序测试
testIncreasing(arr);
//打乱数组
shuffle(arr);
//选择排序升序
insertSort(arr);
//排序测试
testIncreasing(arr);
//打乱数组
shuffle(arr);
//归并排序升序
mergeSort(arr);
//排序测试
testIncreasing(arr);
//打乱数组
shuffle(arr);
//快速排序升序
quickSort(arr);
//排序测试
testIncreasing(arr);
//打乱数组
shuffle(arr);
//堆排序升序
heapSort(arr);
//排序测试
testIncreasing(arr);
//打乱数组
shuffle(arr);
//希尔排序升序
shellSort(arr);
//排序测试
testIncreasing(arr);
//打乱数组
shuffle(arr);
//希尔排序升序
countSort(arr);
//排序测试
testIncreasing(arr);
//打乱数组
shuffle(arr);
//希尔排序升序
bucketSort(arr);
//排序测试
testIncreasing(arr);
//打乱数组
shuffle(arr);
//希尔排序升序
radixSort(arr);
//排序测试
testIncreasing(arr);
}
//打乱数组
public static void shuffle(int[] arr) {
Random random = new Random();
for (int i = 0; i < arr.length; i++) {
int j = i + random.nextInt(arr.length-i);
swap(arr, i, j);
}
System.out.println("打乱后的数组");
System.out.println(Arrays.toString(arr));
}
// //计时器
// public static void timer() {
// //获取程序运行时间的代码,可以用于比较不同算法之间的效率,数据量较小时,
// //可以把System.currentTimeMillis()换成System.nanoTime()
// long startTime = System.currentTimeMillis(); //获取开始时间
// //doSomething(); //要测运行时间的程序代码
// long overTime = System.currentTimeMillis(); //获取结束时间
// System.out.println("程序运行时间为:" + (overTime - startTime) + "毫秒");
// }
//测试arr是否是递增序列
public static void testIncreasing(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
if (arr[i] > arr[i + 1]) {
System.out.println("非递增序列!!!\n");
return;
}
}
System.out.println("递增序列,排序成功!\n");
}
}
总结
排序算法 | 时间复杂度 | 空间复杂度 | 稳定性 |
---|---|---|---|
冒泡排序 | 稳定 | ||
插入排序 | 不稳定 | ||
选择排序 | 稳定 | ||
归并排序 | 稳定 | ||
快速排序 | 不稳定 | ||
堆排序 | 不稳定 | ||
希尔排序 | 不稳定 | ||
计数排序 | | 稳定 | |
桶排序 | 稳定 | ||
基数排序 | | 稳定 |