这个博客写的很好,而且还有每个排序算法的动画,非常值得一看。

一、概览

java实现十大排序算法_i++

 

 

二、java实现



public class SortUtils {
/**
* 1.插入排序
* 从第二个元素开始和前面的有序序列进行比较,
* 如果小于有序元素的最后一个,则向前再向前,一直找到合适的位置插入
* 然后插入位置的元素和它之后的元素统一向后移动一位
* 插入排序理解起来不难,难点在于边界的确定
*/

public static void insertSort(Integer[] arr) {
//第一个数据肯定有序,所以从第二个数据开始跟有序序列做比较
for (int i = 1; i < arr.length; i++) {
Integer data = arr[i];
int j = i - 1;
//从后向前寻找arr[i]的插入位置
while (data < arr[j] && j > 0) {
j--;
}
//把j+1~i的所有数据统一向后移动一位,移动是逆序从后向前进行的
for (int k = i; k > j; k--) {
arr[k] = arr[k - 1];
}
arr[j + 1] = data;
}
}

/**
* 2.冒泡排序,最好理解
* 一趟排序就可以把最大元素交换到队尾,然后下一次对前n-1个元素继续冒泡排序
* @param arr
*/
public static void bubbleSort(Integer[] arr) {
int length = arr.length;
for (int i = 0; i < length; i++) {
for (int j = 0; j < length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
exchange(arr, j, j + 1);
}
}
}
}

/**
* 3.选择排序
* 始终选择未排序序列中的最小元素,插入到已排序序列的最后
*
* @param arr
*/
public static void selectSort(Integer[] arr) {
int length = arr.length;
for (int j = 0; j < length; j++) {
Integer minD = Integer.MAX_VALUE;
int index = 0;
for (int i = j; i < length; i++) {
if (arr[i] < minD) {
minD = arr[i];
index = i;
}
}
//循环结束,找到了最小元素和最小元素的下标
Integer old = arr[j];
arr[j] = minD;
arr[index] = old;

}
}

/**
* 4.希尔排序
* 可以认为是插入排序的改进版
* 通过将原数组分解成不同步长的子序列,对子序列进行插入排序
* 不断缩短步长,直到步长为一
*
* @param arr
*/
public static void shellSort(Integer[] arr) {
//初始步长为数组长度的一半
int step = arr.length / 2;
//while循环内部还是一个插入排序,与基本插入排序相比多了下标越界的校验
while (step > 0) {
for (int i = step; i < arr.length; i++) {
Integer data = arr[i];
int j = i - step;
//从后向前寻找arr[i]的插入位置
while (j >= 0 && data < arr[j]) {
j = j - step;
}
//把j+1~i的所有数据统一向后移动一位,移动是逆序从后向前进行的
for (int k = i; k > j && k - step >= 0; k = k - step) {
arr[k] = arr[k - step];
}
arr[j + step] = data;
}
step = step / 2;
}
}

/**
* 5.归并排序
* 对数组进行递归的拆分,直到每个数组只有一个元素,此时一定是有序的
* 然后将这两个最小的有序数组进行合并再合并
*
* @param arr
*/
public static void mergeSort(Integer[] arr, int start, int end) {
if (start < end) {
int q = (start + end) / 2;
mergeSort(arr, start, q);
mergeSort(arr, q + 1, end);
merge(arr, start, q, end);
}
}

private static void merge(Integer[] arr, int start, int q, int end) {
//新建两个辅助数组,n1,n2是实际存放元素的长度
int n1 = q - start + 1;
int n2 = end - q;
//每个数组多一个哨兵元素空间
Integer[] left = new Integer[n1 + 1];
Integer[] right = new Integer[n2 + 1];
//将原数组的元素复制到辅助数组
for (int i = 0; i < n1; i++) {
left[i] = arr[start + i];
}
for (int j = 0; j < n2; j++) {
right[j] = arr[q + 1 + j];
}
//哨兵元素
left[n1] = Integer.MAX_VALUE;
right[n2] = Integer.MAX_VALUE;
int m = 0;
int n = 0;
for (int k = start; k <= end; k++) {
if (left[m] < right[n]) {
arr[k] = left[m];
m++;
} else {
arr[k] = right[n];
n++;
}
}
}

/**
* 6.快速排序
* 通过一趟排序将待排记录分隔成独立的两部分,
* 其中一部分记录的关键字均比另一部分的关键字小,
* 则可分别对这两部分记录继续进行排序,以达到整个序列有序。
*
* @param arr
*/

public static void quickSort(Integer[] arr, int start, int end) {
if (start < end) {
int q = partition(arr, start, end);
quickSort(arr, start, q - 1);
quickSort(arr, q + 1, end);
}
}

/**
* 分区是快速排序的关键
* 将一个数组根据基准分成小于基准值和大于基准值的两部分
* 特点:需要两个游标
*
* @param arr
* @param start
* @param end
* @return
*/
private static int partition(Integer[] arr, int start, int end) {
//默认以最后一个元素为基准
Integer base = arr[end];
//i代表较小值的最大索引,j代表未知元素最小索引
int i = start - 1;
for (int j = start; j < end; j++) {
if (arr[j] <= base) {
i++;
exchange(arr, i, j);
}
}
exchange(arr, i + 1, end);
return i + 1;

}

public static void exchange(Integer[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}

/**
* 7.堆排序:需要借助堆数据结构
*
* @param arr
*/
public static void heapSort(Integer[] arr) {
MHeap<Integer> heap = new MHeap<>();
for (Integer integer : arr) {
heap.insert(integer);
}
for (int i = 0; i < arr.length; i++) {
arr[i] = heap.pop();
}
}

/**
* 8.计数排序
* 统计数组中小于一个元素所有元素的个数,这个个数正好就是它在新数组中的下标
*
* @param arr
*/
public static Integer[] countSort(Integer[] arr) {
Integer[] result = new Integer[arr.length];
Integer[] c = new Integer[100];
Arrays.fill(c, 0);
for (int i = 0; i < arr.length; i++) {
c[arr[i]] = c[arr[i]] + 1;
}

for (int i = 1; i < c.length; i++) {
c[i] = c[i] + c[i - 1];
}
for (int i = 0; i < arr.length; i++) {
Integer index = c[arr[i]];
result[index - 1] = arr[i];
}
return result;
}

/**
* 9.基数排序
* 按照从低位到高位的顺序依次对数组进行排序
* 基数排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。
*
* @param arr
*/
public static void radixSort(Integer[] arr, int d) {
//从个位到十位再到百位
for (int i = 1; i <= d; i++) {
doRadixSort(arr, i);
}
}

/**
* 借用临时数组存放每次基数排序的结果
*
* @param arr
* @param degree
*/
private static void doRadixSort(Integer[] arr, int degree) {
//临时数组
Integer[][] tempArray = new Integer[10][10];
Integer[] indexArray = new Integer[10];
Arrays.fill(indexArray, 0);
for (Integer integer : arr) {
int intByDegree = getIntByDegree(integer, degree);
Integer idx = indexArray[intByDegree];
tempArray[intByDegree][idx] = integer;
indexArray[intByDegree] = indexArray[intByDegree] + 1;
}

int nd = 0;
for (int i = 0; i < tempArray.length; i++) {
Integer len = indexArray[i];
for (int j = 0; j < len; j++) {
arr[nd] = tempArray[i][j];
nd++;
}
}

}

/**
* 获取最大数的位
*
* @param maxVal
* @return
*/
private static int getDegree(Integer maxVal) {
int i = 0;
while (maxVal != 0) {
i++;
maxVal = maxVal / 10;
}
return i;
}

/**
* 1-个位,2=10位
* 获取当前位的值
*
* @param data
* @param degree
* @return
*/
private static int getIntByDegree(Integer data, int degree) {
return (int) ((data / Math.pow(10, degree - 1)) % 10);
}

/**
* 10.桶排序
* 桶是有序的,对桶内数据再排序,然后合并
* 关键是如何进行分桶,使得每个桶的元素相差不大
*
* @param arr
*/
public static void bucketSort(Integer[] arr) {
int bucketNum = 0;
//获取最大数的位数,即为桶数
for (Integer integer : arr) {
if (bucketNum < getDegree(integer)) {
bucketNum = getDegree(integer);
}
}
Integer[] indexArray = new Integer[bucketNum];
Arrays.fill(indexArray, 0);
//构造m*n的二维数组,m是桶数
Integer[][] buckets = new Integer[bucketNum][arr.length];
//遍历原数组,根据特征把数放入不同的桶
for (Integer integer : arr) {
//不同位的数放入不同桶
int degree = getDegree(integer);
int idx = degree - 1;
//indexArray存放二级索引
Integer index = indexArray[idx];
buckets[idx][index] = integer;
indexArray[idx] = indexArray[idx] + 1;
}
//对每个桶分别排序
for (int i = 0; i < bucketNum; i++) {
Integer[] bucket1 = buckets[i];
Integer length = indexArray[i];
quickSort(bucket1, 0, length - 1);
}
int newIndex = 0;
//将桶的数据重新放回数组
for (int i = 0; i < bucketNum; i++) {
Integer len = indexArray[i];
for (int j = 0; j < len; j++) {
arr[newIndex] = buckets[i][j];
newIndex++;
}
}
}

public static void main(String[] args) {
Integer[] array = {76, 1, 43, 22, 5, 34, 547, 17, 18, 9};
// insertSort(array);
// bubbleSort(array);
// selectSort(array);
// heapSort(array);
// quickSort(array,0,array.length-1);
// mergeSort(array, 0, array.length - 1);
// shellSort(array);
// Integer[] array1 = countSort(array);
// bucketSort(array);
radixSort(array, 3);
System.out.println(Arrays.toString(array));
}
}