Java实现常见的7种排序算法
来源:互联网 发布:windows视频剪辑 编辑:程序博客网 时间:2024/06/06 21:01
主要总结一下以下常见的排序以及其java的实现,包含有:
比较排序
冒泡排序
插入排序
希尔排序
快速排序
堆排序
归并排序
1.比较排序:从第0个开始分别与后面的比较,正序不交换,反序就交换。时间复杂度n+(n-1)+.....1=(1+n)n/2=O(n^2)。
/**比较排序 * 2015年10月29日上午9:53:38 * @param data */public static void CompareSort(int[] data){for(int i=0;i<data.length;i++){for(int j=i+1;j<data.length;j++){if(data[i]>data[j]){int change=data[i];data[i]=data[j];data[j]=change;}}}}
2.冒泡排序:最后一个开始 a[n]与a[n-1]比较,正序不交换,反序交换,接着比较a[n-1]与a[n-2] ....遍历一遍可以最小的排到最上面,如此遍历n遍就可以实现排序,从底到上,如冒泡一样。时间复杂度为O(n^2)
/** * 冒泡排序 2015年10月29日上午9:53:38 * * @param data */public static void bubleSort(int[] data) {for (int i = 1; i <= data.length; i++) {for (int j1 = data.length - 1, j2 = j1 - 1; j2 >= 0; j2--, j1--) {if (data[j1] < data[j2]) {int change = data[j1];data[j1] = data[j2];data[j2] = change;}}}}
改进:去掉已经排序了的部分
/** * 冒泡排序 2015年10月29日上午9:53:38 * * @param data */public static void bubleSort(int[] data) {for (int i = 0; i <data.length; i++) {for (int j1 = data.length - 1, j2 = j1 - 1; j2 >i; j2--, j1--) {if (data[j1] < data[j2]) {int change = data[j1];data[j1] = data[j2];data[j2] = change;}}}}
进一步改进:假如已经没有可以比较的了,退出循环
/** * 冒泡排序 2015年10月29日上午9:53:38 * * @param data */public static void bubleSort(int[] data) { Boolean noFinishCompare=true;for (int i = 0; i <data.length&&noFinishCompare; i++) { noFinishCompare=false;for (int j1 = data.length - 1, j2 = j1 - 1; j2 >i; j2--, j1--) {if (data[j1] < data[j2]) {int change = data[j1];data[j1] = data[j2];data[j2] = change;noFinishCompare=true;//只要有交换就没有完成比较}}}}
3.插入排序:将要排序的数组分成两个部分,一部分是已经排序好了,一部分是原来的,一开始默认已经排序好的只有第一个数组下标。接着从第二个数组开始遍历,判断要排序的元素在已经排序的部分的位置,然后插入。比如判断第二个数组比第一个数组小,插入在左边,比它大插入在右边,确定插入位置的依据是比上一个位置小,不大于下一个位置。时间复杂度为O(n^2);
/**插入排序 * 2015年10月29日上午11:09:33 * @param data */public static void inSertSort(int[] data ){for(int i=1;i<data.length;i++){if(data[i]<data[0]){int change=data[i];//拿出data[i]for(int s=i;s>=1;s--)//从0位起将i前面的后移一位{data[s]=data[s-1];}data[0]=change;//将i放到第一位}if(data[i]>data[0]){int change=data[i];//拿出data[i]for(int s=0;s<i;s++ )//遍历已经排序的部分{ if(change>data[s]&&change<=data[s+1]){//通过大于【i】小于或等于【i+1】来确定要插入的位置 for(int e=i;e>=s+1;e--){data[e]=data[e-1]; //右移动留出插入位置}data[s+1]=change; //插入}}}}}
改进:由于前部分已经排序了的,那么判断a[i]的插入位置可以根据往前推算判断,若a[i-1]>a[i],那么a[i-1]后移以一位,知道a[i-k]<a[i],那么i-k之前的数肯定比i的小,可以将a[i]插入到a[i-k+1]的位置上:
/**插入排序 * 2015年10月29日上午11:09:33 * @param data */public static void inSertSort(int[] data ){for(int i=1;i<data.length;i++){int ai=data[i];int j;for(j=i-1;j>=0&&data[j]>ai;j--){data[j+1]=data[j];}data[j+1]=ai;}}
4.希尔排序:
原理是什么:对于无序数组 a【1】a【2】a【3】a【4】a【5】a【6】
将其划分成子序列: gap=6/2=3;
分别是 : a【1】a【4】 a【2】a【5】 a【5】a【6】 正序不交换,反序交换
那么通过排序让子序列有序得到:b【1】b【2】b【3】b【4】b【5】b【6】
可知:b【1】<b【4】 b【2】<b【5】 b【3】<b【6】
接下来 gap=3/2=1;
分别是:b【1】b【2】 b【2】b【3 】 b【3】b【4】 b【4】b【5】 b【5】b【6】
排序后得到序列:c【1】c【2】c【3】c【4】c【5】c【6】
可知c【1】<c【2】 c【2】<c【3】 】 c【3】<c【4】 c【4】<c【5】 c【5】<c【6】
结合b,可得到有序序列。
算法核心:不断的分成几个有序子序列,对子序列进行排序,最后得到基本有序的序列,然后进行一次插入排序。
public static void ShellSort(int[] datas){int gap=datas.length/2;if(datas.length>0)gap=datas.length%2==0?gap-1:gap;while(gap>=1){for(int i=0;i<=datas.length/2;i++){if(datas[i]>datas[i+gap]){int exchange=datas[i+gap];datas[i+gap]=datas[i];datas[i]=exchange;}}gap=gap/2;}inSertSort(datas);}}
希尔排序最终也是用到插入排序,目的就是尽可以有序化,减小插入排序的运算,定义一个变量用于确定它允许的次数:
/**插入排序 * 2015年10月29日上午11:09:33 * @param data */public static void inSertSort(int[] data ){for(int i=1;i<data.length;i++){int ai=data[i];int j;for(j=i-1;j>=0&&data[j]>ai;j--){System.out.println("-----num"+num++);data[j+1]=data[j];}data[j+1]=ai;}}public static void ShellSort(int[] datas){int gap=datas.length/3;if(datas.length>0)gap=datas.length%2==0?gap-1:gap;while(gap>=1){for(int i=0;i<=datas.length/2;i++){if(datas[i]>datas[i+gap]){System.out.println("-----num"+num++);int exchange=datas[i+gap];datas[i+gap]=datas[i];datas[i]=exchange;}}gap=gap/3;}inSertSort(datas);}
测试数据如下:
int[] datas = new int[] {8,15,4,55,98,14,77,35,88,21,546,875,1,65,756,43,4,87,54,11,25,66,78,95,555,423,657,442};
但是调用插入排序,打印出来的num:
-----num125
使用希尔排序的话:
-----num65而且希尔排序的步长不一样的话运算树也不一样:
public static void ShellSort(int[] datas){int gap=datas.length/3;if(datas.length>0)gap=datas.length%2==0?gap-1:gap;while(gap>=1){for(int i=0;i<=datas.length/2;i++){if(datas[i]>datas[i+gap]){System.out.println("-----num"+num++);int exchange=datas[i+gap];datas[i+gap]=datas[i];datas[i]=exchange;}}gap=gap/2;}inSertSort(datas);}
打印出来的是:
-----num61
5.快速排序:
快速排序也叫分治法,以一个基准数为标准将其分为两个部分,一个是比这个数小的部分,一个是比这个数大的部分,然后让这两个部分按照这样的法则递归下去。
分成两个有序的部分思想是:
【1】【2】【3】【4】....【k】...【n-1】【n】
先以key=【1】为基准数,从n下标往左遍历,获取到第一个比key小的【k】,交换位置:【k】【2】【3】..【m】.....【1】.。。【n-1】【n】
然后从2开始往左遍历,找到第一个比key大的【m】,交换k下标以2下标:【k】【2】【3】..【1】..【m】...【n-1】【n】
可以知道:【1】前面的数都比【1】小,【m】后面的数都比【m】大
然后继续按照这个法则,从【1】下标到【m】的下标进行排序,一直到左边的下标等于右边的下标,最终分成两个部分....【1】....
前面的比【1】小,后面的比【1】大。。
然后分成两个部分递归,从0下标到【1】前一个下标,从【1】的后一个下标到【n】下标。以此下去最终通过实现排序。
/**快速排序 * 2015年10月30日下午1:50:53 * * @param data */public static void FastSortToHalf(int[] data, int leftFirstPosition,int rightLastPosition) {int size = rightLastPosition;if (leftFirstPosition < rightLastPosition) {while (leftFirstPosition < rightLastPosition) {//通过循环分成两个部分int key = data[leftFirstPosition];while (rightLastPosition > leftFirstPosition&& data[rightLastPosition] >= key) {rightLastPosition--;}if (leftFirstPosition < rightLastPosition) {data[leftFirstPosition] = data[rightLastPosition];data[rightLastPosition] = key;}while (leftFirstPosition < rightLastPosition&& data[leftFirstPosition] <= key) {leftFirstPosition++;}if (leftFirstPosition < rightLastPosition) {int changge = data[leftFirstPosition];data[leftFirstPosition] = data[rightLastPosition];data[rightLastPosition] = changge;}}FastSortToHalf(data, 0, leftFirstPosition - 1);//对这两个部分进行递归FastSortToHalf(data, leftFirstPosition + 1, size);}}
6.堆排序:
堆排序最好最坏以及平均的情况下时间复杂度都是O(nlongn),性能上比比较排序、冒泡排序、插入排序好。
思想:需要构建与保持一个最大堆,然后利用最大堆的性质实现排序。
原理:将要排序的数组看成一个完全二叉树,对于第i个位置,如果他有parent,那么parent位置为i/2,如果他有左子树,那么左子树位置为2*i,如果他有右子树,那么右子树位置为2*i+1,构建最大堆的原理是:如果父节点比它的子节点小,那么将父节点与它子节点的最大节点交换,子节点以此类推,达到父节点永远大于子节点,如此从下往上递归,最终根节点是最大的数。创建了大项堆后,将更节点的值与最后的值交换,将0-n-1下标的项重新构造大项堆,如此递归下去,最终排序。
所以步骤有:1.构造大项堆 2.将根节点与最后项交换 3.递归。
public static void HeapSort(int[] data) { BuildBiggestHeap(data, data.length);//创建大项堆 for(int i=data.length;i>2;i--)//最后一个长度应该是3个节点 { swap(data, 0,i-1);//交换根节点与最后项 BuildBiggestHeap(data, i);//重新创建大项堆 }}/**创建大项堆 * 2015年11月2日下午3:21:02 * @param data * @param length */public static void BuildBiggestHeap(int[] data,int length) {if(length>data.length)return;for(int i=length/2-1;i>=0;i--){int parent_position=i;int left_position=i*2+1;int right_position=i*2+2;if(right_position<length){if(right_position==length-1){//这时只有一个左子节点if(data[parent_position]<data[left_position]);swap(data, left_position, parent_position);}else{//有两个子节点int lagerposition=0;lagerposition=data[left_position]>data[right_position]?left_position:right_position;lagerposition=data[lagerposition]>data[parent_position]?lagerposition:parent_position;if(lagerposition!=parent_position)swap(data, parent_position, lagerposition);}}}} //交换 private static void swap(int[] data, int i, int j) { int tmp=data[i]; data[i]=data[j]; data[j]=tmp; }
7.归并排序:
归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
排序实现思路是:将数组分成左右两个部分,将两个部分分别进行排序,然后将排序了的两个部分合并。
拆分的思路是通过递归进行不断的拆分,最终拆分成长度为2或者3的序列。
归并的思路是:构造一个缓冲数组,数组长度为要归并的两部分的长度,左部分下标为i,右部分下标为j,数组下标为k,如果a【i】<a【j】,那么将a【i】赋予s【k】,并i++,k++,反之j++,k++。当i或者j长度分配完后,应该讲i或者j剩下的部分按顺序富裕k。
所以代码实现的步骤为:1.拆分. 2.合并 并且对拆分进行递归。
<strong> </strong>private static void MergeSort(int[] data,int firstposition,int mergeiength) { if(mergeiength==2) { sortlength2(data,firstposition);//长度为2时排序 return; } if(mergeiength==3){ sortlength3(data,firstposition);//长度为3时排序 return; } int mergeleftlength=mergeiength/2; int mergerightlength=mergeiength-mergeleftlength; MergeSort(data, firstposition, mergeleftlength);//拆分左边进行递归 MergeSort(data, firstposition+mergeleftlength, mergerightlength);//拆分右边进行递归 //拆分排序后将左右两部分合并 int[] temp=new int[mergeiength];//缓存数组,将左右部分合并到缓存数组中 int tempposition=0; int i=firstposition,j=i+mergeleftlength; int leftmaxposition=firstposition+mergeleftlength; int rightmaxposition=firstposition+mergeiength; while(i<leftmaxposition&&j<rightmaxposition){ if(data[i]>data[j]) { temp[tempposition++]=data[j++]; }else { temp[tempposition++]=data[i++]; } } while(tempposition<mergeiength)//合并剩余的部分 { if(i<leftmaxposition) { temp[tempposition++]=data[i++]; } if(j<rightmaxposition){ temp[tempposition++]=data[j++]; } } System.arraycopy(temp, 0, data, firstposition, mergeiength);//拷贝到缓存数组的对应位置中 } private static void sortlength3(int[] data, int firstposition) {sortlength2(data, firstposition);//先排好前两个if(data[firstposition+2]<data[firstposition]){int s=data[firstposition+2]; data[firstposition+2]=data[firstposition+1]; data[firstposition+1]=data[firstposition]; data[firstposition]=s;}if(data[firstposition+2]>data[firstposition]&&data[firstposition+2]<data[firstposition+1]){int s=data[firstposition+2]; data[firstposition+2]=data[firstposition+1]; data[firstposition+1]=s;}}private static void sortlength2(int[] data, int firstposition) {if(data[firstposition]>data[firstposition+1])swap(data, firstposition, firstposition+1);}
- Java实现常见的7种排序算法
- 常见排序算法的java实现
- 常见经典排序算法的java实现
- 常见排序算法的java实现
- 常见内排序算法的java实现
- 常见排序算法的Java实现
- 常见的排序算法,Java实现
- Java实现常见的排序算法
- Java实现常见的排序算法
- 常见的排序算法 Java实现
- Java实现常见的排序算法
- 用Java实现几种常见的排序算法
- 用Java实现几种常见的排序算法
- 用Java实现几种常见的排序算法
- 用Java实现几种常见的排序算法
- 用Java实现几种常见的排序算法
- 用Java实现几种常见的排序算法
- 用Java实现几种常见的排序算法
- 5-28 搜索树判断 (25分)
- MP-流程表单规则
- android 垃圾清理 文件清理
- Android四大组件之Service(服务)
- [Windows] VMware Workstation 12.0.0 Pro 正式版/注册码/注册机
- Java实现常见的7种排序算法
- JVM执行Java程序的过程中管理的内存空间
- 用HttpListener 建立web服务器 实现网页浏览、文件上传
- 使用 ContentProviderOperation 来提升性能
- ALM中action使用,包括多action复用
- SVM算法
- linux下hadoop2.6.1源码64位的编译
- textview属性
- django.contrib.auth.backend-后台