排序算法总结
Posted Al_tair
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法总结相关的知识,希望对你有一定的参考价值。
排序算法总结
大家好呀!我是小笙,本节是我对排序算法的一个总结
各种排序算法
稳定性:一组数列在排序的时候,相同的值的相对位置是否发生变化
选择排序
概述:将某一个数列中最大的值或者最小的值与该数列的第一个进行交换,然后缩小数列范围(不包括第一个)依次反复则可以排好序
时间复杂度:o(n^2)
空间复杂度:o(1)
public class SelectionSort
public static void main(String[] args)
int[]nums = new int[]1,8,67,3,5;
sort(nums);
System.out.println(Arrays.toString(nums));
/**
* 选择排序 升序排序
* @param nums 数组
*/
public static void sort(int[] nums)
int len = nums.length;
if(nums == null || len < 2)
return;
else
for (int i = 0; i < len-1; i++)
int minIndex = i;
for (int j = i+1; j < len; j++)
minIndex = nums[j] < nums[minIndex]? j:minIndex;
int temp = nums[minIndex];
nums[minIndex] = nums[i];
nums[i] = temp;
冒泡排序
概述:类似与泡泡浮出水面,比如将最大值的值向右端浮动,浮动过程中出现左边的值大于右边的值,则需要进行交换,确保最大值最后落在最右端,依次反复
时间复杂度:o(n^2)
空间复杂度:o(1)
public class BubbleSort
public static void main(String[] args)
int[]nums = new int[]1,8,67,3,5;
sort(nums);
System.out.println(Arrays.toString(nums));
/**
* 冒泡排序 升序排序
* @param nums 数组
* 可以进行优化: 如果内循环一次发现没有发生交换操作,则可以认为已经排好序并跳出循环
*/
public static void sort(int[] nums)
int len = nums.length;
if(nums == null || len < 3)
return;
else
for (int i = len-1; i >= 0; i--)
for (int j = 0; j < i; j++)
if(nums[j] > nums[j+1])
int temp = nums[j];
nums[j] = nums[j+1];
nums[j+1] = temp;
插入排序
概述:实现很像冒泡排序,注意两次循环方向,插入排序是同向的,冒泡是反向的,插入无非就是从第二数开始,插入到前面的数列中也能保持有序,在数组上的实现也就只能是层层交换,但是如果是链表可能就更好理解什么是插入概念?
时间复杂度:o(n^2)
空间复杂度:o(1)
public class InsertSort
public static void main(String[] args)
int[]nums = new int[]1,8,67,3,5;
sort(nums);
System.out.println(Arrays.toString(nums));
/**
* 直接插入排序 升序
* @param nums 数组
*/
public static void sort(int[] nums)
int len = nums.length;
if(nums == null || len < 2)
return;
else
for (int i = 1; i < len; i++)
// 注意:看起来像冒泡,但是因为数组插入的时候, ,所以通过比较前移来实现也是一样的效果
for(int j = i;j >= 0 && nums[j] < nums[j-1];j--)
int temp = nums[j];
nums[j] = nums[j-1];
nums[j-1] = temp;
希尔排序
希尔排序实质上是一种分组插入方法,它的基本思想是: 对于n个待排序的数列,取一个小于n的整数step(step被称为步长)将待排序元素分成若干个组子序列,所有距离为step的倍数的记录放在同一个组中;然后,对各组内的元素进行直接插入排序。 这一趟排序完成之后,每一个组的元素都是有序的。然后减小step的值,并重复执行上述的分组和排序。重复这样的操作,当step=1时,整个数列就是有序的
时间复杂度:希尔排序的时间复杂度与增量(即,步长step的选取有关。例如,当增量为1时,希尔排序退化成了直接插入排序,此时的时间复杂度为o(N²),而Hibbard增量的希尔排序的时间复杂度为o(N3/2)
空间复杂度:o(1)
public class ShellSort
// 测试
public static void main(String[] args)
int a[] = 80,30,60,40,20,10,50,70;
System.out.println(Arrays.toString(a));
shellSort(a, a.length);
System.out.println(Arrays.toString(a));
/**
* 希尔排序
* @param a 待排序的数组
* @param n 数组的长度
*/
public static void shellSort(int[] a, int n)
// gap为步长,每次减为原来的一半。
for (int step = n / 2; step > 0; step /= 2)
// 共gap个组,对每一组都执行直接插入排序
for (int i = 0 ;i < step; i++)
groupSort(a, n, i, step);
/**
* 对希尔排序中的单个组进行排序
* @param a 待排序的数组
* @param n 数组总的长度
* @param i 组的起始位置
* @param step 组的步长
*/
public static void groupSort(int[] a, int n, int i,int step)
for (int j = i + step; j < n; j += step)
// 如果a[j] < a[j-step],则寻找a[j]位置,并将后面数据的位置都后移。
if (a[j] < a[j - step])
int tmp = a[j];
int k = j - step;
while (k >= 0 && a[k] > tmp)
a[k + step] = a[k];
k -= step;
a[k + step] = tmp;
归并排序
概述:分成2部分,分别排好序,在通过比较大小归并到统一的数组中
时间复杂度: o(nlogn)
空间复杂度:o(n)
// 思路
// 1.整体就是一个简单递归,左边排好序、右边排好序、让其整体有序
// 2.让其整体有序的过程里用了外排序方法
// 3. 利用master公式来求解时间复杂度
public class MergeSort
public static void main(String[] args)
int[]nums = new int[]1,8,67,3,5,3,4,56,67;
// 可以选择数组的一段进行排序
sort(nums,4,nums.length-1);
System.out.println(Arrays.toString(nums));
/**
* 归并算法(升序排序)
* 递归算法(分治)
*/
public static void sort(int[] nums,int L,int R)
if(L == R)
return;
else
// 中点位置
int mid = L + ((R-L) >> 1);
sort(nums,L,mid);
sort(nums,mid+1,R);
merge(nums,L,mid,R);
/**
* 归并数据
*/
public static void merge(int[] nums,int L,int M,int R)
int[] arr = new int[R-L+1];
// 数组的下标
int index = 0;
// L ~ M 的数组下标
int p0 = L;
// M+1 ~ R 的数组下标
int p1 = M + 1;
while(p0 <= M && p1 <= R)
arr[index++] = nums[p0] > nums[p1]?nums[p1++]:nums[p0++];
while(p0 <= M)
arr[index++] = nums[p0++];
while(p1 <= R)
arr[index++] = nums[p1++];
for (int i = 0; i < R-L+1; i++)
nums[L+i] = arr[i];
求最小数和
题目理解:就是遍历数组,依次累积左侧小于当前位置的数字
public class SmallSum
/**
* 对等数法来测试归并方法的正确性
*/
public static void main(String[] args)
int testNum = 5000000;
while(testNum-- >= 0)
int[] nums = random(10,10);
if(SimpleSum(nums,0,nums.length-1) != mergeSort(nums,0,nums.length-1))
System.out.println("sorry,test error!");
return;
System.out.println("测试" + (5000000 - testNum) + "组数");
System.out.println("right,you are great!");
/**
* 暴力解法
*/
public static int SimpleSum(int[] nums,int L,int R)
int sum = 0;
for (int i = L; i < R; i++)
for (int j = i+1; j <= R; j++)
if(nums[j] > nums[i])
sum += nums[i];
return sum;
/**
* 归并排序的过程计算最小和
*/
public static int mergeSort(int[] nums,int L,int R)
if(L == R)
return 0;
else
int mid = L + ((R-L) >> 1);
return mergeSort(nums,L,mid) + mergeSort(nums,mid+1,R) + merge(nums,L,mid,R);
/**
* 归并数据
*/
public static int merge(int[] nums,int L,int M,int R)
int[] arr = new int[R-L+1];
int index = 0;
int p0 = L;
int p1 = M+1;
// 归并数据时候求最小和
int sum = 0;
while(p0 <= M && p1 <= R)
if(nums[p1] <= nums[p0])
arr[index++] = nums[p1++];
else
sum += nums[p0]*(R-p1+1);
arr[index++] = nums[p0++];
while(p0 <= M)
arr[index++] = nums[p0++];
while(p1 <= R)
arr[index++] = nums[p1++];
for (int i = 0; i < arr.length; i++)
nums[i+L] = arr[i];
return sum;
/**
* 随机生成 size 个 1 ~ value 值的数组
* @param size 数组长度
* @param value 数组值
*/
public static int[] random(int size,int value)
int[] nums = new int[size];
for (int i = 0; i < size-1; i++)
nums[i] = (int)(Math.random()*value + 1);
return nums;
数组的逆序对
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数
举例:
输入: [7,5,6,4]
输出: 5
解释:逆序对 [7,5] [7,6] [7,4] [5,4] [6,4] 五对
通过归并的形式解决
class Solution
public int reversePairs(int[] nums)
if(nums.length < 2)
return 经典十大排序算法(含升序降序,基数排序含负数排序)Java版完整代码建议收藏系列