排序算法分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因为数据量太大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。这里只讨论内部排序,常见的内部排序算法有:插入排序、希尔排序、选择排序、堆排序、冒泡排序、快速排序、归并排序、及基数排序。
1、插入排序
插入排序是一种最简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序的数据,在已排序序列中从后往前扫描,找到相应位置并插入。算法步骤如下:
- 将第一个待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成未排序序列;
- 从头到尾一次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置,即满足有序的顺序,若相等,则插入到这个相等元素的后面。
插入排序java代码:
1 public class InsertSort { 2 public static void insertSort(int []data){ 3 for(int i=0;i<data.length-1;i++){ 4 int temp=data[i+1]; 5 int j=i; 6 while(j>-1&&data[j]>temp){ 7 data[j+1]=data[j]; 8 j--; 9 } 10 data[j+1]=temp; 11 } 12 } 13 public static void main(String[] args) { 14 // TODO Auto-generated method stub 15 int data[]=new int[]{12,5,44,11,50,9}; 16 insertSort(data); 17 for(int i:data){ 18 System.out.println(i); 19 } 20 } 21 22 }
2、希尔排序
希尔排序也称为递减增量排序算法,是插入排序的一种改进,其思想是:先将整个待排序的序列分割成若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。算法步骤如下:
- 选择一个增量序列t1,t2,...,tk,其中ti>tj,tk=1;
- 增量序列个数为k,对序列进行k趟插入排序;
- 每趟排序,根据对应的增量ti,将待排序序列分割成若干长度为m得子序列,然后对各子序列进行直接插入排序,当ti为1时,是对“基本有序”的整个序列排序。
希尔排序实现:
1 public class SellSort { 2 public static void sellSort(int []data){ 3 int []step=new int[]{6,3,1}; 4 int i,j,k; 5 for(int s:step){ 6 for(i=0;i<s;i++){ 7 for(j=i;j<data.length-s;j+=s){ 8 k=j; 9 int temp=data[j+s]; 10 while(k>-1&&data[k]>temp){ 11 data[k+s]=data[k]; 12 k-=s; 13 } 14 data[k+s]=temp; 15 } 16 } 17 } 18 } 19 public static void main(String[] args) { 20 // TODO Auto-generated method stub 21 int []data=new int[]{12,5,44,11,50,9,23,32}; 22 sellSort(data); 23 for(int i:data){ 24 System.out.println(i); 25 } 26 } 27 28 }
3、选择排序
选择排序是一种简单直观的排序算法,基本思想是:对待排序序列进行扫描,每次找到最小(大)的元素,然后和未排序序列的首元素进行交换,直到所有的待排序序列都是有序的为止。算法步骤如下:
- 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置;
- 再从剩余未排序序列中继续寻找最小(大)元素,然后放到已排序序列的末尾;
- 重复第二步,直到所有元素排序完毕。
选择排序实现代码:
1 public class SelectSort { 2 3 public static void selectSort(int []data){ 4 for(int i=0;i<data.length;i++){ 5 int minIndex=i;//每次记录值最小的下标 6 int temp; 7 for(int j=i+1;j<data.length;j++){ 8 if(data[j]<data[minIndex]) minIndex=j; 9 } 10 temp=data[i]; 11 data[i]=data[minIndex]; 12 data[minIndex]=temp; 13 } 14 } 15 public static void main(String[] args) { 16 // TODO Auto-generated method stub 17 int []data=new int[]{12,5,44,11,50,9}; 18 selectSort(data); 19 for(int i:data){ 20 System.out.println(i); 21 } 22 } 23 24 }
4、堆排序
堆排序是利用堆这种数据结构所设计的一种排序算法。这个堆所满足的性质是:子结点的键值总是不小于(不大于)它的父结点。算法基本步骤如下:
- 把未排序序列创建成为一个堆;
- 把堆首(为最大(小)值)和堆尾互换;
- 堆的规模减1,调整堆;
- 重复,直到所有元素排序完成。
堆排序实现:
1 public class HeapSort { 2 //初始化数组为最大堆 3 private static void initCreateHeap(int []data){ 4 for(int i=data.length/2-1;i>=0;i--){ 5 adjHeap(data,data.length,i); 6 } 7 } 8 //调整结点data[h],使之满足最大堆,n为data中剩余未排序的元素的个数 9 private static void adjHeap(int []data,int n,int h){ 10 int i=h; 11 int l=2*i+1; 12 int temp=data[i]; 13 boolean flag=true; 14 while(l<n&&flag){ 15 if(l+1<n&&data[l]<data[l+1]) l++; 16 if(temp>data[l]){ 17 flag=false; 18 }else{ 19 data[i]=data[l]; 20 data[l]=temp; 21 i=l; 22 l=2*i+1; 23 } 24 } 25 } 26 public static void heapSort(int []data){ 27 initCreateHeap(data); 28 for(int i=data.length-1;i>0;i--){ 29 int temp=data[i]; 30 data[i]=data[0]; 31 data[0]=temp; 32 adjHeap(data,i,0); 33 } 34 } 35 public static void main(String[] args) { 36 // TODO Auto-generated method stub 37 int []data=new int[]{12,5,44,11,50,9,23,32}; 38 heapSort(data); 39 for(int i:data){ 40 System.out.println(i); 41 } 42 } 43 44 }
5、冒泡排序
冒泡排序的基本思想是遍历未排序序列,把相邻的元素调整为有序,这样每次都会有最大(小)的元素出现在未排序序列的末尾,就跟冒泡泡一样,把这些元素有序地排出来了。算法步骤:
- 比较相邻的元素。如果不满足有序序列,就交换它们;
- 对每一对相邻元素都做同样的工作,从头到尾,最后末尾元素会是最大的数;
- 未排序的元素个数减1,重复以上工作。
算法实现代码:
1 public class BubbleSort { 2 public static void bubbleSort(int []data){ 3 boolean flag=false;//标志位,如果有序可以提前结束循环 4 for(int i=0;i<data.length;i++){ 5 if(flag) break; 6 flag=true; 7 for(int j=0;j<data.length-1-i;j++){ 8 if(data[j]>data[j+1]){ 9 int temp=data[j]; 10 data[j]=data[j+1]; 11 data[j+1]=temp; 12 flag=false; 13 } 14 } 15 } 16 } 17 public static void main(String[] args) { 18 // TODO Auto-generated method stub 19 int []data=new int[]{12,5,44,11,50,9}; 20 bubbleSort(data); 21 for(int i:data){ 22 System.out.println(i); 23 } 24 } 25 26 }
6、快速排序
快速排序的算法使用分治的策略来进行排序的,对于按从小到大的排序具体的实现步骤如下:
- 从数据序列中选出一个元素当基准
- 把比基准小的所有元素放到基准之前,把所有比基准大的元素放到基准之后,这样就把序列划分为以基准为分界的两个分区,基准之前分区的所有元素都比基准小,基准之后的分区的所有元素都比基准大;
- 两个分区递归的重复以上步骤,直到分区的元素个数小于1。
快速排序实现;
1 public class QuickSort { 2 public static void quickSort(int []data,int s,int e){ 3 int i=s,j=e; 4 int temp=data[s]; 5 while(i<j){ 6 while(i<j){ 7 if(data[j]<temp) { 8 data[i]=data[j]; 9 i++; 10 break; 11 } 12 j--; 13 } 14 while(i<j){ 15 if(data[i]>temp) { 16 data[j]=data[i]; 17 j--; 18 break; 19 } 20 i++; 21 } 22 } 23 data[i]=temp; 24 if(s<i)quickSort(data,s,i-1); 25 if(j<e)quickSort(data,j+1,e); 26 } 27 public static void main(String[] args) { 28 // TODO Auto-generated method stub 29 int []data=new int[]{12,5,44,11,50,9}; 30 quickSort(data,0,data.length-1); 31 for(int i:data){ 32 System.out.println(i); 33 } 34 } 35 36 }
7、归并排序
归并排序是建立在归并操作上的一种有效的排序算法,也在采用分治的策略,算法步骤如下;
- 申请空间,使其大小为两个有序序列的和,该空间用来存放合并后的序列;
- 设定指针分别指向有序序列的起始位置;
- 比较两个指针所指向的元素,选择适当的加入合并空间,并移动指针;
- 重复第3步,直到某一指针到达序列尾;
- 将另一序列剩下的元素直接复制到合并序列末尾。
归并算法实现代码:
1 public class MergeSort { 2 //一次归并,k为归并子数组的长度,temp保存归并的中间结果 3 private static void merge(int []data,int []temp,int k){ 4 int l1=0,l2,u1,u2; 5 int n=data.length; 6 int i,j,m=0; 7 8 while(l1+k<=n-1){ 9 u1=l1+k-1; 10 l2=u1+1; 11 u2=(l2+k>n)?n-1:l2+k-1; 12 13 for(i=l1,j=l2;i<=u1&&j<=u2;){ 14 if(data[i]<data[j]){ 15 temp[m++]=data[i++]; 16 }else{ 17 temp[m++]=data[j++]; 18 } 19 } 20 //若子数组1还有剩余的数据,则直接加入temp数组 21 while(i<=u1){ 22 temp[m++]=data[i++]; 23 } 24 //若子数组2还有剩余的数据,则直接加入temp数组 25 while(j<=u2){ 26 temp[m++]=data[j++]; 27 } 28 l1=u2+1; 29 } 30 //将剩余的只够一组的数据加进来 31 for(i=l1;i<n;){ 32 temp[m++]=data[i++]; 33 } 34 35 } 36 public static void mergeSort(int []data){ 37 int []temp=new int[data.length]; 38 int k=1; 39 while(k<data.length){ 40 merge(data,temp,k); 41 for(int j=0;j<data.length;j++) data[j]=temp[j]; 42 k*=2; 43 } 44 45 } 46 public static void main(String[] args) { 47 // TODO Auto-generated method stub 48 int []data=new int[]{12,5,44,11,50,9,23,32,27}; 49 mergeSort(data); 50 for(int i:data){ 51 System.out.println(i); 52 } 53 } 54 55 }
8、基数排序
基数排序也叫做桶排序,是一种非比较型的整数排序算法,基本思想是将整数按位切割成不同的数字,然后放到不同的桶里面,然后根据桶的规则有序输出。实现步骤如下:
- 初始化d个桶,d为序列中数字的进制;
- 按照关键字最低位数值依次放入桶中,然后分别按照桶号顺序元素进桶先后次序收集数据元素,这样就得到一个新的排列,这个过程称为一次基数排序;
- 然后分别按照次地位直到最高位的顺序进行一次基数排序,进行m次基数排序后就会得到有序序列,这里的m是整数序列的最高位数。
基数排序代码:
1 public class RadixSort { 2 private static void radixSort(int []data,int m,int d){ 3 int i,j,k,power=1; 4 int n=data.length; 5 Queue []q=new LinkedList[d]; 6 7 //初始化队列数组 8 for(i=0;i<d;i++){ 9 q[i]=new LinkedList(); 10 } 11 //进行m次桶排序 12 for(i=0;i<m;i++){ 13 for(j=0;j<n;j++){ 14 k=data[j]/power-(data[j]/(power*d))*d;//取得每个数第i位的值 15 q[k].add(data[j]); 16 } 17 for(k=0,j=0;j<d;j++){ 18 while(!q[j].isEmpty()){ 19 data[k++]=(Integer)q[j].remove(); 20 } 21 } 22 power*=d; 23 } 24 } 25 26 public static void main(String[] args) { 27 // TODO Auto-generated method stub 28 int []data=new int[]{710,841,342,45,686,6,429,134,68,264}; 29 int m=3,d=10;//关键字是m位d进制的 30 radixSort(data,m,d); 31 for(int i:data){ 32 System.out.println(i); 33 } 34 } 35 36 }
================================================================================================================================================
以上排序算法归纳: