计数排序是一个非基于比较的排序算法,该算法于1954年由 Harold H. Seward 提出。它的优势在于在对一定范围内的整数排序时,它的复杂度为Ο(n+k)(其中k是整数的范
围),快于任何比较排序算法。 当然这是一种牺牲空间换取时间的做法,而且当
O(k)>O(nlog(n))的时候其效率反而不如基于比较的排序(基于比较的排序的时间复杂度在
理论上的下限是O(nlog(n)), 如归并排序,堆排序)
计数排序是一种适合于最大值和最小值的差值不是不是很大的排序,也就是说重复的数据
会比较多的情况。
package complex;
import java.util.Arrays;
public class CountSort {
public static void main(String[] args) {
int[] arr={17,19,15,18,16,12,13,14,15,14,18,19,16,13,11,12,15,14};
countSort(arr);
System.out.println(Arrays.toString(arr));
}
public static void countSort(int[] arr){
// 1.找到数组中最大的值和最小值。
int max=arr[0];
int min=arr[0];
for (int i = 0; i < arr.length; i++) {
if (arr[i]>max){
max=arr[i];
}
if (arr[i]
1959年Shell发明,第一批突破O(n2)时间复杂度的排序算法,是简单插入排序的改进
版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增
量排序
算法核心思想是先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,
具体算法描述:
先根据数组的长度/n,获取增量K(第一次n为2)
按增量序列个数k进行分组,一般可以分成k组;
根据以分好的组进行插入排序;(每组排序,根据对应的增量k来找到当前组的元
素)
当每组都排序完毕之后,回到第一步将n*2再次分组进行插入排序,直到最终k=1的
时候,在执行一次插入排序完成最终的排序注:增量是同一组元素在数组中隔了多少个元素。
package complex;
import java.util.Arrays;
public class ShellSort {
public static void main(String[] args) {
int[] arrs={4,6,3,7,2,65,98,4,5,2,3,6};
shellSort(arrs);
System.out.println(Arrays.toString(arrs));
}
public static void shellSort(int[] arrs){
int increment=arrs.length/2;
while (increment>=1){
for (int i = 0; i < arrs.length; i+=increment) {
int num=arrs[i];
for (int j = i-increment; j >=0 ; j-=increment) {
if (num
快速排序是对冒泡排序的一种改进,通过分而治之的思想减少排序中交换和遍历的次数,整个过程可以通过递归的方式完成。
1,首先通过比较算法,找到基准数,比较过程通过交换,最终达到基准数左边的数字都比较右边的要小。
1.分别在头尾设置两个指针,并且再将尾部元素作为比较基准值
2.移动L和R两个指针,直到重合,然后交换基准数字
2.然后以基准数作为中轴,将数组分为两部分,分别执行1步骤的算法(可以通过递
归实现),直到无法再次分割排序完毕。
package complex;
import java.util.Arrays;
/**
* 1.创建左右两个指针,将最后一个值作为基准值,通过不断交换将数组分为左右两部
*分,左边的比右边的要小。
* 2.先判断左指针和基准的值,如果小于等于就向后移动,直到遇到比基准值大的值
* 3.再判断右边指针和基准值,如果大于等于就向前移动,直到遇到比基准值小的值
* 4.然后交换左右指针的值。
* 5.循环上述操作,直到左右指针重合,然后交换重合值和基准值
* 6.将以left和right的重合位置作为中轴,将数组分为两部分,左右分别执行分解的
* 操作,直到排序完毕
* */
public class QuickSort {
public static void main(String[] args) {
int[] arr = {5,8,6,9,3,4,5,69,4,8,5,1,10,5,6,9,3};
quickSort(arr, 0, arr.length - 1);
System.out.println(Arrays.toString(arr));
}
public static void quickSort(int[] arr, int left, int right) {
//退出条件
if (left>=right){
return;
}
int start=left;
int end=right;
int t = end;
int mid;
while (start != end) {
while(arr[start] <= arr[t]&&start=arr[t]&&start
一个含直接或间接调用本函数语句的函数被称之为递归函数,它必须满足以下两个条件:
1在每一次调用自己时,必须是(在某种意义上)更接近于解;
2必须有一个终止处理或计算的准则。
void func(){
//递归条件
if(condition){
func();
}else{
//退出递归
return;
}
归并排序是利用归并的思想实现的排序方法,该算法采用经典的分治策略即将问题分成些小的问题然后递归求解,而治的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之.
归并排序是稳定排序,它也是一种十分高效的排序,能利用完全二叉树特性的排序一般性能都不会太差。java中Arrays.sort()采用了一种名为TimSort的排序算法,就是归并排序的优化版本。
归并排序核心思想是先分再治,具体算法描述如下:
1.先将未排序数组/2进行分组,然后再将分好组的数组继续/2再次分组,直到无法分组,这个就是分的过程
2.然后在将之后再把两个数组大小为1的合并成一个大小为2的,再把两个大小为2的合并成4的,同时在合并的过程中完成数组的排序,最终直到全部小的数组合并起来,这个
就是治的过程.
治的过程中会为两个数组设计两个游标,和一个新的数组.
分别比较两个游标的对应数组的元素,将小的插入到新的数组中然后向后移动较小的数组的游标,继续进行比较.反复前面两步,最终将两个数组中的元素排序合并到新的数组中
package complex;
import java.util.Arrays;
public class MergeSorts {
public static void main(String[] args) {
int[] arr={7,4,6,3,98,56,24,13,78,99};
mergeSorts(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
}
public static void mergeSorts(int[] arr,int start,int end){
//定义结束语句
if (start>=end){
return;
}
//定义中间变量
int mid=(start+end)/2;
//获取左边数组的分解。
mergeSorts(arr, start, mid);
//获取右边数组的分解。
mergeSorts(arr,mid+1,end);
//得到左边数组
for (int i = start; i <=mid ; i++) {
System.out.print(arr[i]+ " ");
}
System.out.print("---");
//得到右边数组
for (int i = mid+1; i <=end; i++) {
System.out.print(arr[i]+ " ");
}
System.out.println();
//合并
//创建临时数组
int[] temp= new int[end+1];
int i=start;//左边的游标
int j=mid+1;//右边的游标
int t=0;//临时数组的游标
//左右数组比较并排序
while (i<=mid&&j<=end){
if (arr[i]<=arr[j]){
temp[t++]=arr[i++];
}else {
temp[t++]=arr[j++];
}
}
while (i<=mid){
temp[t++]=arr[i++];
}
while (j<=end){
temp[t++]=arr[j++];
}
//最后将临时数组复制到原数组
t=0;
while (start<=end){
arr[start++]=temp[t++];
}
System.out.println(Arrays.toString(temp));
}
}
注意: 可以创建一个全局的temp大小和原始数组一直复用,以避免重复创建temp数组浪费内存,这样的就使得归并排序的空间复杂度是O(n)