1、插入排序
插入排序是一种通过不断地把新元素插入到已排好序的数据中的排序算法,常用的插入排序算法包括直接插入排序和shell排序。
(1)直接插入排序
直接插入排序实现比较简单,但是直接插入没有充分的利用已插入的数据已经排序这个事实,因此有很多针对直 接插入排序改进的算法,例如折半插入排序等,下边是直接插入排序的Java实现:
public static void insertSort(int[] elements){ for(int i = 1;i <elements.length; i++) { int j = -1; //找到element[i]应该摆放的位置,此处可以利用查找算法进行优化 while(j <= i && elements[i] > elements[++j]); if(j < i) { //将j之后的数据移动一位,然后把elements[i]移动到j处 int temp = elements[i]; for(int k = i-1;k >= j;k--) { elements[k+1] = elements[k]; } elements[j] = temp; } } }
(2)希尔排序(Shell排序)
Shell排序也是对直接插入排序算法的一种优化,因此可以说直接插入排序是一种特殊的Shell排序,Shell排序对直 接插入排序的优化主要体现在,Shell排序通过使用一个增量序列(递减),每次把要排序的数组分成几个子数组,然后 对子数组进行插入排序,这样可以减少比较和移动数据的次数,Shell排序是一种非常高效的排序算法,该算法的思想 是:
1.以h(h一般取n/2)为间隔将n个元素列分为几个小组,在每个小组内按直接插入法排序
2.令h=h/2,重复第1步
3.当h=1时,排序结束(此时相当于直接插入排序,不过由于数据已经基本排好序,因此比较次数和移动次数比直 接插入排序少很多)
Shell排序的Java实现如下:
public static void shellSort(int[] elements){ for(int h = elements.length/2;h > 0;h /= 2) { for(int i = h;i < elements.length; i++) { int j = i % h; while(j <= i && elements[i] > elements[j]) j += h; //找到element[i]应该摆放的位置 if(j < i) { //将j之后的数据移动h位,然后把elements[i]移动到j处 int temp = elements[i]; for(int k = i-h;k >= j;k -= h) { elements[k+h] = elements[k]; } elements[j] = temp; } } } }
2、选择排序
选择排序是常用内部排序的一种,常见的实现算法有直接选择排序算法和堆排序算法。
(1)直接选择排序
选择排序的基本思想是每次从待排数据中选择第n小的数据放到排序列表的第n个位置,假如共有N个数据待排,那 么经过N-1次排序后,待排数据就已经按照从小到大的顺序排列了。
直接选择排序算法的思想比较简单:(假设数据放在一个数组a中,且数组的长度是N)
1:从a[0]-a[N-1]中选出最小的数据,然后与a[0]交换位置
2:从a[1]-a[N-1]中选出最小的数据,然后与a[1]交换位置(第1步结束后a[0]就是N个数的最小值)
3:从a[2]-a[N-1]中选出最小的数据,然后与a[2]交换位置(第2步结束后a[1]就是N-1个数的最小值)
以此类推,N-1次排序后,待排数据就已经按照从小到大的顺序排列了。
直接选择排序的java实现如下:
public static void selectionSort(int[] elements){ for(int i = 0; i < elements.length-1; ++i) { int k = i; for(int j = i; j < elements.length; ++j) { if(elements[k] > elements[j]) { k = j; } } if(k != i) { //交换元素 int temp = elements[i]; elements[i] = elements[k]; elements[k] = temp; } } }
(2)堆排序
堆排序算法和直接选择排序算法最大的不同在于,堆排序算法充分利用大顶堆和完全二叉树的性质,保留每次排序 后的结构,同时由于每次比较只是比较根节点和它的子节点,因此大大降低了比较的次数和交换的次数,从而提高效率,堆排序算法的时间复杂度是O(nlogn,以2为底)。
堆排序算法的思想是:(假设数据放在一个数组a中,且数组的长度是N)
1:以数组a为数据,建立一个大顶堆(这样对于二叉树的每个节点,根节点总是比子节点大,其实没必要要求二叉树的每个子树也是大顶堆)
2:交换大顶堆的根节点和数组a中的最后一个节点(最后一个节点不在参与后边的工作)
重复上边的工作,经过N-1次后,数组a已经排好序。
堆排序算法的java实现如下:
public static void heapSort(int[] elements){ for(int i = elements.length-1; i > 0; i--) { buildHeap(elements,i);//建堆 swap(elements,0,i);//交换根节点和最后一个节点 } } private static void buildHeap(int[] elements,int lastIndex){ int lastParentIndex = (lastIndex-1)/2;//获得最后一个父节点 for(int i = lastParentIndex; i >=0; i--) { int parent = elements[i]; int leftChild = elements[i*2+1];//左节点肯定存在 int rightChild = leftChild; if(i*2+2 <=lastIndex) { rightChild = elements[i*2+2];//右节点不一定存在 } int maxIndex = leftChild<rightChild?i*2+2:i*2+1; if(parent < elements[maxIndex]) { swap(elements,i,maxIndex); } } } private static void swap(int[] elements,int firstIndex,int secondIndex){ int temp = elements[firstIndex]; elements[firstIndex] = elements[secondIndex]; elements[secondIndex] = temp; }
3、交换排序
交换排序是另一种经常使用的内部排序策略,常见的算法有冒泡排序和快速排序,之所以把冒泡排序和快速排序归类为交换排序,是因为这两种算法的主要工作是不断的交换元素来达到排序的目的。
(1) 冒泡排序
冒泡排序是最经典的交换排序,它的算法思想是:(假设数据存放在数组a[n]中)
1.比较a[0]和a[1],如果a[0]>a[1],则交换a[0],a[1],然后比较新的a[1](可能是原来的a[0])和a[2],如果 a[1]>a[2],则交换 a[1],a[2],以此类推,直到a[n-2]和a[n-1]比较完毕,这样,a中的最大数就“沉底”了,即a[n-1]是数组a中的最大值。
2.从头开始继续第1步的操作,所不同的是本次比较到a[n-2]即可结束,这样数组a中的次大值就被交换到a[n-2]的位置。
3.以此比较n-1次,数组a就按照从小到大的顺序排好了。(也可以判断是否有交换发生,如果一趟比较没有发生交换,则表示数组a已经排好序)。
冒泡排序的java实现如下:
public static void bubbleSort(int[] elements){ for(int i = elements.length-1; i > 0; i--) { for(int j = 0; j < i;j++) { if(elements[j] > elements[j+1]) { swap(elements,j,j+1);//交换两个元素 } } } } private static void swap(int[] elements,int i,int j){ int temp = elements[i]; elements[i] = elements[j]; elements[j] = temp; }
(2)快速排序
另一种经典的交换排序是快速排序,快速排序的效率很高,但是空间复杂度较大,因为快速排序使用了递归,而递归的实现需要一个栈。快速排序的算法思想是:(假设数据存放在数组a[n]中)
1.如果待比较的数组长度为0或者1,则不用比较,直接返回。
2.如果待比较的数组长度大于1,则随机的选择一个中枢值(centrum),然后分别从数组的两端开始遍历,并且把从左边遍历找到的大于centrum的元素和从右边遍历找到的小于centrum的元素进行交换,直到数组遍历完毕(即:左边遍历指针指向的索引大于或等于右边遍历指针指向的索引)。
3.交换中枢元素和右边遍历指针指向的元素,这样原来的数组以中枢元素为界分成了两个数组,且左边数组的元素都不大于中枢,右边数组的元素都不小于中枢,然后分别对两个子数组分别进行快速排序。
快速排序的java实现如下:
public static void quickSort(int[] elements,int begin,int end){ if(begin < end) { int centrum = elements[begin];//选择第一个元素作为中枢 int front = begin+1; int back = end; while(front <= back) { while((front <= end) && (elements[front] < centrum)) front++; while((back >= begin) && (elements[back] > centrum)) back--; if(front < back) { swap(elements,front,back); }else{ break; } } if(begin < back) swap(elements,begin,back); quickSort(elements,begin,back-1); quickSort(elements,back+1,end); } } private static void swap(int[] elements,int i, int j){ int temp = elements[i]; elements[i] = elements[j]; elements[j] = temp; }
注:以上代码摘自网络。