十大排序算法
各个排序的时间复杂度和空间复杂度:
比较排序
交换排序之快排2.0的代码
package com.example.myapplication;
public class QuickSort2 {
public static void main(String[] args) {
int arr[] = {10, 20, 30, 50, 2, 9, 3, 8, 11};
quickSort(arr, 0, arr.length - 1);
}
private static void quickSort(int[] arr, int l, int r) {
if (l < r) {
//i左指针,j右指针
int i = l;
int j = r;
int x = arr[i];
while (i < j) {
//从右往左找到第一个小于x的数
while (i < j && arr[j] > x)
j--;
//找到,放入i的位置,i向右移动
if (i < j) {
arr[i++] = arr[j];
}
//从左往右找到第一个大于x的数
while (i < j && arr[i] < x)
i++;
//找到,放入前面j的位置,j向左移动
if (i < j) {
arr[j--] = arr[i];
}
}
arr[i] = x;
printArr(arr);
//递归
quickSort(arr, l, i - 1);
quickSort(arr, i + 1, r);
}
}
}
//第一次循环结束后以10分割,10左边的全是小于10的,10右边的全是大于10的
交换排序之快排3.0的代码
package com.example.myapplication;
public class QuickSort3 {
public static void main(String[] args) {
int arr[] = {10, 20, 30, 50, 2, 9, 3, 8, 11};
quickSort(arr, 0, arr.length - 1);
}
private static void quickSort(int[] arr, int L, int R) {
if (L < R) {
int[] p = partation(arr, L, R);
quickSort(arr, L, p[0] - 1);
quickSort(arr, p[1] + 1, R);
}
}
private static int[] partation(int[] arr, int l, int r) {
//1、l往后,more往前调整,前面高就调整交换快排序
//2、确定x的位置,位置前后重复的操作
int less = l - 1;
int more = r;
while (l < more) {
if (arr[l] < arr[r]) {
++less;
l++;
swap(arr, ++less, l++);
} else if (arr[l] > arr[r]) {
swap(arr, --more, l);
} else {
l++;
}
}
swap(arr, more, r);
printArr(arr);
return new int[]{less + 1, more};
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
//第一次循环结束后:确定11前是小于11,11后的数大于11
交换排序之冒泡排序代码
package com.example.myapplication;
public class bubbleSort {
public static void main(String[] args) {
int arr[] = {10, 20, 30, 50, 2, 9, 3, 8, 11};
bubbleSort(arr);
}
//i控制外循环,j控制内循环
//第一次内循环结束,最大的数放在最后一位
private static void bubbleSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
//比较内循环的相邻的j,将大的放到后面
if (arr[j] > arr[j + 1]) {
swap(arr, j, j + 1);
}
}
}
}
//交换
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
//第一次循环结束后,确认内循环最后一个数为最大
插入排序之简单插入排序
package com.example.myapplication;
public class InsertionSort {
public static void main(String[] args) {
int arr[] = {10, 20, 30, 50, 2, 9, 3, 8, 11,6};
InsertionSort(arr);
}
private static void InsertionSort(int[] arr) {
int preIndex, current;
for (int i = 1; i <= arr.length - 1; i++) {
//preIndex为i往前指针
preIndex = i - 1;
current = arr[i];
//大于current的元素后移动,直到碰到小于current的值,
while (preIndex >= 0 && arr[preIndex] > current) {
arr[preIndex + 1] = arr[preIndex];
preIndex--;
}
arr[preIndex + 1] = current;
}
}
}
//内循环保证i元素往前是有序的
插入排序之希尔排序
package com.example.myapplication;
public class ShellSort {
public static void main(String[] args) {
int arr[] = {8,9,1,7,2,3,5,4,6,0};
ShellSort(arr);
}
private static void ShellSort(int[] arr) {
int len = arr.length;
for (int gap = (int) Math.floor(len/2); gap > 0; gap = (int) Math.floor(gap / 2)) {
for (int i = gap; i < len; i++) {
int j = i;
int current = arr[i];
//交换gap距离的数据
while (j - gap >= 0 && current < arr[j - gap]) {
arr[j] = arr[j - gap];
j = j - gap;
}
arr[j] = current;
}
}
}
}
//第一次内循环确保gap(10/2)的两个数据有序
选择排序之简单选择排序
package com.example.myapplication;
public class SelectSort {
//选择排序
public static void main(String[] args) {
int arr[] = {10, 20, 30, 50, 2, 9, 3, 8, 11};
SelectSort(arr);
}
private static void SelectSort(int[] arr) {
int len = arr.length;
int minIndex;
//找到最小的索引
for (int i = 0; i < len - 1; i++) {
minIndex = i;
for (int j = i + 1; j < len; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
System.out.println(minIndex);
}
}
swap(arr, i, minIndex);
}
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
//第一次内循环,选出最小的数
选择排序之简单堆排序
package com.example.myapplication;
public class heapSort {
// 大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
// 小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]
// [4,6,8,5,9]-buildMaxHeap->[9,6,8,5,4]-->
static int arr[] = {4, 6, 8, 5, 9};
static int len = arr.length;
public static void main(String[] args) {
HeapSort(arr);
len = arr.length;
}
//根据大根堆排序
private static void HeapSort(int[] arr) {
buildMaxHeap(arr);
for (int i = arr.length - 1; i > 0; i--) {
swap(arr, 0, i);
len--;//重点
heapify(arr, 0);
}
}
//建立大顶堆,顶部元素最大,确保大顶堆
//返回小于或等于一个给定数字的最大整数,向下取整,堆层级
private static void buildMaxHeap(int[] arr) {
for (int i = (int) Math.floor(len / 2); i >= 0; i--) {
//从下往上调整
heapify(arr, i);
}
}
//调整一个子树的大根堆
private static void heapify(int[] arr, int i) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int largest = i;
if (left < len && arr[left] > arr[largest]) {
largest = left;
}
if (right < len && arr[right] > arr[largest]) {
largest = right;
}
if (largest != i) {
swap(arr, i, largest);
//从上往下递归
heapify(arr, largest);
}
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
private static void printArr(int arr[]) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + ",");
}
System.out.println(" ");
}
}
//大根堆--根元素最大,
//建立大根堆,确认最大值,和最后的元素交换,除去最后的元素,剩下的再构建大根堆
归并排序法之二路归并
package com.example.myapplication;
public class mergeSort {
//归并排序--基于完全二叉树
public static void main(String[] args) {
int[] arr = {9, 8, 7, 6, 5, 4, 3, 2, 1};
sort(arr);
}
public static void sort(int[] arr) {
int[] temp = new int[arr.length];
//在排序前,先建好一个长度等于原数组长度的临时数组,避免递归中频繁开辟空间
sort(arr, 0, arr.length - 1, temp);
}
//1.从中间分组
//2.左边有序--》1,2,3
//3.右边有序--》1,2,3
//4.合并有序
//重点
//左9,8,7,6,5 右4,3,2,1
//左9,8,7 右6,5 左4,3 右2,1
//左9,8 右7
//分组,直到组内只有两个元素,选择
private static void sort(int[] arr, int left, int right, int[] temp) {
if (left < right) {
int mid = (left + right) / 2;
System.out.println("left-----" + left);
System.out.println("right-----" + right);
System.out.println("mid-----" + mid);
sort(arr, left, mid, temp);//左边归并排序,使得左子序列有序
printArr(arr);
System.out.println("1-----");
sort(arr, mid + 1, right, temp);//右边归并排序,使得右子序列有序
printArr(arr);
System.out.println("2-----");
merge(arr, left, mid, right, temp);//将两个有序子数组合并操作
printArr(arr);
System.out.println("3-----");
}
}
//temp数组存放从小到大的值
private static void merge(int[] arr, int left, int mid, int right, int[] temp) {
int i = left;//左序列指针
int j = mid + 1;//右序列指针
int t = 0;//临时数组指针
//temp中存放最小的值
while (i <= mid && j <= right) {
if (arr[i] <= arr[j]) {
temp[t++] = arr[i++];
} else {
temp[t++] = arr[j++];
}
}
while (i <= mid) {//将左边剩余元素填充进temp中
temp[t++] = arr[i++];
}
while (j <= right) {//将右序列剩余元素填充进temp中
temp[t++] = arr[j++];
}
t = 0;
//将temp中的元素全部拷贝到原数组中
while (left <= right) {
arr[left++] = temp[t++];
}
}
private static void printArr(int arr[]) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + ",");
}
System.out.println(" ");
}
}
//元素不断递归,直至成为两个元素,使用临时数组,从小到大选择值
非比较排序
基数排序
package com.example.myapplication;
public class RadixSort {
//基数排序(Radix Sort)是桶排序的扩展,根据键值的每位数字来分配桶
//高位优先,又称为最有效键(MSD),它的比较方向是由左至右;
//低位优先,又称为最无效键(LSD),它的比较方向是由右至左;
//利用分配和收集两种基本操作
//没考虑负数
public static void main(String[] args) {
int[] arr = {166,19, 48, 1117000, 2226, 5, 4, 3, 2, 301, 22, 44, 33, 44,14};
int maxbit = new RadixSort().maxbits(arr);
radixSort(arr, arr.length - 1, maxbit);
printArr(arr);
}
/*
* 排序数组中最大数字的位数
*
* @param array
* @return
*/
public static int maxbits(int[] arr) {
int max = Integer.MIN_VALUE;
// 找到最大数
for (int i = 0; i < arr.length; i++) {
max = Math.max(max, arr[i]);
}
int res = 0;
// 算出位数
while (max != 0) {
res++;
max /= 10;
}
return res;
}
// 设计了两个辅助数组,一个是 count[],一个是 bucket[]。
// count 用于记录在某个桶中的最后一个元素的下标,
//bucket桶
private static void radixSort(int[] arr, int end, int digit) {
int begin = 0;
//往0-9个桶里面存放数据
final int radix = 10;
int i = 0, j = 0;
int[] count = new int[radix];
int[] bucket = new int[end - begin + 1];
//根据位数循环
for (int d = 1; d <= digit; d++) {
// 初始化count
for (i = 0; i < radix; i++) {
count[i] = 0;
}
//计算每个桶里面的数字 --LSD
// int[] arr = {19, 48, 1117000, 2226, 5, 4, 3, 2, 301,22,44,33,44};
// 根据个位数//1117000 //301 //02 22 //03 33 //04 44 44 //05 //2226 //0 //48 //19
// 根据十位数//1117000 301 02 03 04 05 //19 //22 2226 //33 //44 44 48
for (i = begin; i <= end; i++) {
j = getDigit(arr[i], d);
count[j]++;
}
//重点count计算与前面数之和
for (i = 1; i < radix; i++) {
count[i] = count[i] + count[i - 1];
}
//1 2 3 6 9 10 11 11 12 13
//从后往前统计
for (i = end; i >= begin; i--) {
j = getDigit(arr[i], d);
bucket[count[j] - 1] = arr[i];//重点
count[j]--;
}
//重新赋值arr
for (i = begin, j = 0; i <= end; i++, j++) {
arr[i] = bucket[j];
}
}
}
/**
* 求每位数上的数
*
* @param x
* @param d
* @return
*/
// x/1%10; //个位数字
// x/10%10; // 十位数字
// x/100%10; //百位数字
// x/1000%10; //千位数字
public static int getDigit(int x, int d) {
return ((x / ((int) Math.pow(10, d - 1))) % 10);
}
private static void printArr(int arr[]) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + ",");
}
System.out.println(" ");
}
}
原理:按照位数依此往0-9个桶里面存放数据
//外循环控制位数,内循环排序,第一次外循环得到按个位数排序
//统计每个桶里面的元素个数,然后从后往前,把数组里面的数据存放到桶中
bucket[count[j] - 1] = arr[i];
桶排序
package com.example.myapplication;
import java.util.ArrayList;
import java.util.Collections;
public class bucketSort {
public static void main(String[] args) {
int arr[] = {10, 20, 30, 50, 2, 9, 3, 8, 11, 444};
bucketSort(arr);
printArr(arr);
}
private static void bucketSort(int[] arr) {
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for (int i = 0; i < arr.length; i++) {
max = Math.max(max, arr[i]);
min = Math.min(min, arr[i]);
}
int bucketNum = (max - min) / arr.length + 1;
//*********重点********
ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum);
for (int i = 0; i < bucketNum; i++) {
bucketArr.add(new ArrayList<Integer>());
}
//桶是个ArrayList
for (int i = 0; i < arr.length; i++) {
int num = (arr[i] - min) / arr.length;
System.out.println(num);
bucketArr.get(num).add(arr[i]);
}
//对每个桶进行排序
for (int i = 0; i < bucketArr.size(); i++) {
Collections.sort(bucketArr.get(i));
}
System.out.println(bucketArr);
int index = 0;
for (int i = 0; i < bucketArr.size(); i++) {
for (int j = 0; j < bucketArr.get(i).size(); j++) {
arr[index++] = bucketArr.get(i).get(j);
}
}
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
private static void printArr(int arr[]) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + ",");
}
System.out.println(" ");
}
}
设置 (max - min) / arr.length + 1个桶
按照 (arr[i] - min) / arr.length 存放数据到桶里
每个桶进行单独排序
计数排序
package com.example.myapplication;
/**
* 计数排序,数字,填充
*/
public class CountSort {
public static void main(String[] args) {
int arr[] = {10, 20, 30, 50, 2, 9, 3, 8, 11};
CountSort(arr);
printArr(arr);
}
private static void CountSort(int[] A) {
// 找出数组A中的最大值
int max = Integer.MIN_VALUE;
for (int num : A) {
max = Math.max(max, num);
}
// 初始化计数数组count--max
int[] count = new int[max + 1];
// 对计数数组各元素赋值
for (int num : A) {
count[num]++;
}
printArr(count);
// 创建结果数组
int[] result = new int[A.length];
// 创建结果数组的起始索引
int index = 0;
// 遍历计数数组,将计数数组的索引填充到结果数组中
for (int i = 0; i < count.length; i++) {
while (count[i] > 0) {
A[index++] = i;
count[i]--;
}
}
printArr(count);
}
public int[] countSort2(int[] A) {
// 找出数组A中的最大值、最小值
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for (int num : A) {
max = Math.max(max, num);
min = Math.min(min, num);
}
// 初始化计数数组count
// 长度为最大值减最小值加1
int[] count = new int[max - min + 1];
// 对计数数组各元素赋值
for (int num : A) {
// A中的元素要减去最小值,再作为新索引
count[num - min]++;
}
// 创建结果数组
int[] result = new int[A.length];
// 创建结果数组的起始索引
int index = 0;
// 遍历计数数组,将计数数组的索引填充到结果数组中
for (int i = 0; i < count.length; i++) {
while (count[i] > 0) {
// 再将减去的最小值补上
result[index++] = i + min;
count[i]--;
}
}
// 返回结果数组
return result;
}
public int[] countSort3(int[] A) {
// 找出数组A中的最大值、最小值
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for (int num : A) {
max = Math.max(max, num);
min = Math.min(min, num);
}
// 初始化计数数组count
// 长度为最大值减最小值加1
int[] count = new int[max - min + 1];
// 对计数数组各元素赋值
for (int num : A) {
// A中的元素要减去最小值,再作为新索引
count[num - min]++;
}
// 计数数组变形,新元素的值是前面元素累加之和的值-------------新
for (int i = 1; i < count.length; i++) {
count[i] += count[i - 1];
}
// 创建结果数组-
int[] result = new int[A.length];
// 遍历A中的元素,填充到结果数组中去
for (int j = 0; j < A.length; j++) {
result[count[A[j] - min] - 1] = A[j];
count[A[j] - min]--;
}
return result;
}
public int[] countSort4(int[] A) {
// 找出数组A中的最大值、最小值
int max = Integer.MIN_VALUE;
int min = Integer.MAX_VALUE;
for (int num : A) {
max = Math.max(max, num);
min = Math.min(min, num);
}
// 初始化计数数组count
// 长度为最大值减最小值加1
int[] count = new int[max - min + 1];
// 对计数数组各元素赋值
for (int num : A) {
// A中的元素要减去最小值,再作为新索引
count[num - min]++;
}
// 计数数组变形,新元素的值是前面元素累加之和的值
for (int i = 1; i < count.length; i++) {
count[i] += count[i - 1];
}
// 创建结果数组
int[] result = new int[A.length];
// 遍历A中的元素,填充到结果数组中去,从后往前遍历-------------倒叙遍历,保证顺序
for (int j = A.length - 1; j >= 0; j--) {
result[count[A[j] - min] - 1] = A[j];
count[A[j] - min]--;
}
return result;
}
private static void printArr(int arr[]) {
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + ",");
}
System.out.println(" ");
}
}
初始化基数数组
for (int num : A) { count[num]++; }
对应的count数组位置元素+1,
最后将count数组中的元素放到A中