Java 中常见的排序算法
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 中常见的排序算法相关的知识,希望对你有一定的参考价值。
其实小编是不太想写关于java的相关文章,因为是这个编程语言实在是会用的人太多了,网上的博文数不胜数,没必要在重复造轮子了,但是虽然java这门语言会用的人很多,但是会用、掌握、熟练、和精通可不是闹着玩的,想要达到精通的级别,小编敢说,一个正规的开发公司能过达到精通java的开发人员屈指可数,所以小编这里就跳过关于java哪些简单的API 、语法,直接给大家介绍一些相对提升能力,并且不是那么基础的知识,说不定以后面试就会用到,尤其是排序,真的,不晓得为啥都喜欢在面试的时候出排序的题,实际大数据开发中真正手写排序的还真不多,我想可能是各个面试官想要看到的是,各个应聘者是否能够get到排序算法的精髓吧。好了,每次写博客都要废话一堆,自我检讨,但是不想改变,接下来小编介绍几种创建的排序算法以及他们的java实现。
1. 冒泡排序
原理:从第一个元素开始,和它相邻的比较,如果前面一个元素大于后面一个元素,就把他们互换位置。
原理图:
代码实现:
public static void main(String[] args)
int arr[] = 15, 16, 145, 91, 9, 5, 0 ;
int temp1=0;
for(int i=0;i<arr.length-1;i++) //控制循环次数:arr.length-1
for(int j=0;j<arr.length-i-1;j++) //控制比较次数:arr.length-i-1
if(arr[j]>arr[j+1])
temp1=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp1;
增强版冒泡排序:
public static void main(String[] args)
int arr[] = 1,0,2,3,4,5,6,7,8 ;
int temp1;
for(int i=0;i<arr.length-1;i++) //控制循环次数:arr.length-1
boolean flag=true; //判断内层循环是否执行
for(int j=0;j<arr.length-i-1;j++) //控制比较次数:arr.length-i-1
if(arr[j]>arr[j+1])
temp1=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp1;
flag=false;
if(flag) //如果内层循环的if一次都没有执行,说明已经排序结束
break;
2.选择排序
原理:从第一个位置开始,将他与后面的所有元素比较,如果前面大于后面的,就交换位置。
原理图:
代码实现:
public static void main(String[] args)
int arr[] = 45,15,48,9,3,65,22 ;
for(int i=0;i<arr.length-1;i++) //控制位置,从第一个位置开始,到倒数第二个位置
for(int j=i+1;j<arr.length;j++) //当前位置的下一个位置开始,与后面的所有比较
if(arr[i]>arr[j])
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
3. 插入排序
原理:从第二个元素位置开始,将他与他之前的元素比较,如果比之前的元素小,就将他插入到,那个元素的前面。
原理图:
代码实现:
public static void main(String[] args)
int arr[] = 45, 15, 48, 9, 3, 65, 22 ;
// 插入排序
int temp1;
for (int i = 1; i < arr.length; i++) //从第二个数开始,一直到最后一个数
for (int j = 0; j < i; j++) //i之前的所有数,全部比较
if (arr[i] < arr[j])
temp1 = arr[i];
for (int k = i; k > j; k--) //将前面的数据把后面的覆盖,从j开始,一直到i
arr[k] = arr[k - 1];
arr[j] = temp1;
4. 快速排序
原理:先选取一个基准点,作用:基准点左侧小于基准点的数据 基准点右侧放的数据都是大于基准点的数据。基准点:最常用的基准点选第一个,最终一个大数组不停的进行查分 拆分的最终结果每个数组只有一个元素。
原理图:
解释:大循环中有两个循环,一个是从右往左,找比基准点小的,一个是从左往右找比基准点大的(找到之后,与基准点交换位置)。最终大循环,在left>=right时结束。
(2) 快排拆分:
解释:使用递归的方式,将数组左右两边一次次拆分,直到left>=right时,递归结束。
代码实现:
public class QuickSort
public static void main(String[] args)
int arr[]= 2,7,1,2,8,1,3,9,415,189,123;
sort(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
public static void sort(int [] arr,int left ,int right)
//递归的出口,当左侧==右侧
if(left>=right)
return;
//获取基准点
int point=getPoint(arr,left,right);
//左边排序(递归)
sort(arr,left,point-1);
//右边排序(递归)
sort(arr,point+1,right);
public static int getPoint(int [] arr,int left ,int right)
int key=arr[left];
while(left<right)
//从右向左循环,只要右边的比基准点大,就继续循序
while(key<=arr[right]&&left<right)
//每循环一次,right的索引向左移一个
right--;
//交换基准点的位置
arr[left]=arr[right];
//从左向右循环,只要左边的比基准点小,就继续循序
while(arr[left]<=key&&left<right)
left++;
//交换基准点
arr[right]=arr[left];
//最后给基准点赋值
arr[left]=key;
return left;
注意:了解快速排序有助于了解MR的map-reduce过程,因为在MRmap阶段环形缓冲区满了之后,会将数据溢写到文件中,这个过程中就是使用了快速排序。
5. 计数排序
原理:对一个已有数组进行排序,那么就新建一个数组,数组长度为数组中元素的最大值+1。并把已有数组中的元素,对应上新建数组的下标,放入里面,新建数组的元素为,已有数组中元素的出现次数。
原理图:
解释:新创建一个数组,长度为需要排序的数组的最大值+1,遍历数组,将数组中的值分别找到新数组的索引,将索引处的元素+1,最后,遍历输出新数组的下标(只输出相应的值>0的下标,并且值为多少就输出几次)。
代码实现:
public class CountSort
public static void main(String[] args)
int arr[]= 2,7,1,2,8,1,3,9,415,189,123;
sort(arr,415);
System.out.println(Arrays.toString(arr));
public static void sort(int arr[],int max)
int index=0;
int newarr[]=new int [max+1];
for(int i=0;i<arr.length;i++)
newarr[arr[i]]++;
for(int i=0;i<newarr.length;i++)
if(newarr[i]!=0)
for(int j=0;j<newarr[i];j++)
arr[index++]=i;
注意:了解计数排序,有助于了解hbase的布隆过滤器,布隆过滤器的特点就是,我说没有就没有,我说有不一定有(有一定的误判率)。
6. 归并排序(两路)
原理:针对多个有序的数据集进行排序。(时间复杂度:n*logN)
归并排序有两个阶段:
一个是归:将一个数据集拆分到每一个小的数据集只有一个元素。
实现一个数据集的归:
public static void chai(int arr[],int first,int last,int [] newarr)
if(first>=last)
return;
//找中间点
int mid=(first+last)/2;
//左边归
chai(arr,first,mid,newarr);
//右侧拆
chai(arr,mid+1,last,newarr);
//拆完之后并
meger(arr,first,last,mid,newarr);
一个是并:将两个有序的数据集,合并成为一个有序的大数据集。
实现两个有序数据集的并:
public int[] bing(int arr1[], int arr2[])
//创建一个最终结果的数组:长度为arr1和arr2长度之和
int newarr[] = new int[arr1.length+arr2.length];
//新数组的元素标记
int index=0;
//记录arr1和arr2的下标
int arr1_index=0;
int arr2_index=0;
//只要有一个数组,遍历结束,就停止循环
while(arr1_index<arr1.length&&arr2_index<arr2.length)
//进行判断,将数据存储在新数组中
if(arr1[arr1_index]<arr2[arr2_index])
newarr[index++]=arr1[arr1_index++];
else
newarr[index++]=arr2[arr2_index++];
//可能是arr1没有遍历完全
while(arr1_index<arr1.length)
newarr[index++]=arr1[arr1_index++];
//可能是arr2没有遍历完全
while(arr2_index<arr2.length)
newarr[index++]=arr2[arr2_index++];
return newarr;
完整代码实现:
public class bingSort
public static void main(String[] args)
int arr[]= 1,8,7,6,11,2,4;
int newarr[]=new int[arr.length];
System.out.println(Arrays.toString(arr));
chai(arr,0,arr.length-1,newarr);
System.out.println(Arrays.toString(newarr));
//归
public static void chai(int arr[],int first,int last,int [] newarr)
if(first>=last)
return;
//找中间点
int mid=(first+last)/2;
//左边归
chai(arr,first,mid,newarr);
//右侧拆
chai(arr,mid+1,last,newarr);
//拆完之后并
meger(arr,first,last,mid,newarr);
/**
* 并
* @param arr 原数组
* @param first 开始位置
* @param last 结束位置
* @param mid 中间位置
* @param newarr 存放最终结果的数组
*/
public static void meger(int arr[],int first,int last,int mid,int [] newarr)
//第一个数据集的起始下标
int arr1_start=first;
//第一个数据集的终止下标
int arr1_end=mid;
//第二个数据集的起始下标
int arr2_start=mid+1;
//第二个数据集的终止下标
int arr2_end=last;
int index=0;
while(arr1_start<=arr1_end&&arr2_start<=arr2_end)
if(arr[arr1_start]<arr[arr2_start])
newarr[index++]=arr[arr1_start++];
else
newarr[index++]=arr[arr2_start++];
while(arr1_start<=arr1_end)
newarr[index++]=arr[arr1_start++];
while(arr2_start<=arr2_end)
newarr[index++]=arr[arr2_start++];
/**
* 因为归并排序,需要使用两个有序的数据集,而arr一开始时无需的,所有每一次归并的时候
* 需要将归并好之后的那一段数据集,赋值到arr中,使之后的归并仍然有序
*/
//赋值的循环的次数,是本次归并的元素的个数
for(int i=0;i<index;i++)
//每次赋值的时候,是从first开始
arr[first+i]=newarr[i];
注意:在MR程序中,其中有两个阶段使用到了归并,一个是在缓冲区溢写小文件时,最后会将多个小文件归并成一个大文件,另一个则是在reduce拉去map处理的数据到本地是会生成很多小文件,此时也会做一次归并。
7. 二分法查找数据
原理:在已经排好序的基础上,将数组元素折半查找。
原理图:
代码实现:
public static void main(String[] args)
int arr[] = 1, 2, 3, 4, 5, 6, 7, 8 ;
// 二分法查数据
int num = new Scanner(System.in).nextInt(); //查找的数
int start = 0;
int end = arr.length - 1;
int middle = (start + end) / 2;
while (true)
//如果end<start说明全部找完也没有找到
if (end < start)
System.out.println(num + "不在此数组中");
break;
if (arr[middle] > num)
end = middle - 1;
else if (arr[middle] < num)
start = middle + 1;
else
System.out.println("这个数的索引下标为" + middle);
break;
middle = (start + end) / 2;
以上是关于Java 中常见的排序算法的主要内容,如果未能解决你的问题,请参考以下文章