概念
1.排序算法等我稳定性:如果a=b,在排序之前,a在b的前面,如果排序之后,a仍然在b的前面,那么算法就是稳定的,否在算法就是不稳定的;
2.内排序和外排序:排序方法根基在排序过程是否完全在内存,分为内排序和外排序。内排序是指在排序期间数据元素全部存放在内存的排序;外排序是指排序期间的全部元素个数太多,不能同时存放在内存,必须根据排序过程的要求,不断在内存外存之间移动的排序。适用于内部排序的排序方法称为内部排序方法,反之则为外部排序方法;
性能评估
排序的时间开销可用算法执行的数据比较次数和数据移动次数来衡量。
排序算法
插入排序
基本方法:每步将一个待排序的元素,按其排序码的大小,插入到前面已经排好序的一组元素的适当位置上去,直到元素全部插入位置。可以选择不同的方法在已经排好序的有序数据表中寻找插入位置。依据查找方法的不同,有多种插入排序法:
1)直接插入排序:假设升序排列,V[2], V[0], V[1]逐渐增大,现在V[3]要参与排序,则先比较V[3],V[1],如果V[3]<V[1],则让[V3]=V[1],实现将V[3]置于temp中,元素比temp大,就顺次往后移动,直到找到插入位置;
2)折半插入排序:折半搜索比顺序搜索快,因此折半插入就平均性能来说比直接插入排序要快。在元素的初始排列已经按排好序或者接近有序时,直接插入排序比折半插入排序的排序码比较次数要少。折半插入排序的元素移动次数与直接插入排序相同,依赖于元素的初始排列。折半插入排序是一个稳定的排序方法。
3)希尔排序:又称为缩小增量排序。基本思想:设待排序元素序列有n个元素,首先取一个gap<n作为间隔,将全部元素分为gap个自子序列,所有距离为gap的元素放在同一个子序列中,在每一个自序列中分别施行直接插入排序。然后缩小间隔gap,例如取gap=gap/2,重复上述的子序列划分和排序工作。直到最后gap=1,将所有的元素放在同一个序列中排序为止。整个排序的排序码比较次数和元素移动次数都比直接插入排序少。它是一种不稳定的排序算法。很多排序应用程序都选用了希尔排序算法。
快速排序
也叫分区排序,是目前应用最广泛的排序,它是不稳定的。快速哦排序算法采用分治法进行排序,其基本思想:任取待排序元素序列中的某个元素(例如第一个元素)作为基准,按照该元素的排序码大小,将整个元素序列划分为左右两子序列,左侧子序列中的元素都小于基准元素的排序码,右侧子序列中所有的元素都大于或者等于基准元素的排序码,基准元素则排在两个子序列之间。分别对这两个子序列重复以上的方法,知道所有的元素都排在相应的位置上为止。
此处的元素移动使用的是交换元素的方法。
快速排序源码:
//快速排序法 public class QuickSort { public static void main(String[] args) { // TODO Auto-generated method stub int list[] = {10, 4, 12, 3, 7, 9, 1, 21, 16, 14, 25, 13, 48, 23, 27, 32};//快速排序所用序列 int length = list.length; for(int i = 0; i < length; i++){ System.out.print(list[i] + " "); } System.out.println(); quickSort(list, 0, length-1); for(int i = 0; i < length; i++){ System.out.print(list[i] + " "); } } public static void quickSort(int list[], int left, int right){ if(left >= right) return; int index = left; int base = list[left];//以left为基准 int temp = 0; for(int i = left+1; i <= right; i++){ if(list[i] < base){ //交换 temp = list[i]; list[i] = list[index]; list[index] = temp; index++; } } list[index] = base; quickSort(list, left, index-1); quickSort(list, index+1, right); } }
选择排序
基本思想:每一趟在后面n-i个待排序元素中选出排序码最小的元素作为有序元素序列的第i个元素。待到第n-2趟作完,待排序元素只剩下一个就不用再选了。下面是三种选择排序方法:
1)直接选择排序:基本步骤:
a)在一组元素V[i]~V[i-1]中选择具有最小排序码的元素;
b)若它不是这组元素中的第一个元素,则将它与这一组的第一个元素对调;
c)在这组元素中剔除这个具有最小排序码的元素,在剩下的元素V[i+1]~V[n-1]中重复执行第a)b)步,直到剩余元素只有一个为止。直接选择排序是一种不稳定的排序方法;
2)锦标赛排序;
3)堆排序:根据要排序的建立最大(小)堆,然后操作堆,通过删除元素,调整堆得到排序的结果。
归并排序
归并排序也是基于分治法的,归并排序将待排序的元素序列分成两个长度相等的子序列,为每一个子序列排序,然后再将它们合并成一个序列,合并两个子序列的过程称为两路归并。归并算法描述:在执行两路归并算法时,先把待归并元素序列L1复制到辅助数组L2中,再从L2归并到L1中。在归并过程中,用变量s1,s2分别做L2中两个表的当前检测指针,用变量t做归并后在L1中的当前存放指针。当S1和S2都在两个表的表长内变化的时候,根据L2.Vector[s1]与L2.Vector[s2]的排序码的大小,依次把排序码小的元素排放到新表L1.Vector[t]中,当S1与S2中有一个已经超出表长时,将另一个表中剩余的部分照抄到新表L1.Vector[]中。
归并排序的主要问题是它需要一个与原数组一样大的辅助数组空间。归并排序是一种稳定的排序方法。
源码:
public class MergeSort { public static void main(String[] args) { // TODO Auto-generated method stub int list[] = {10, 4, 12, 3, 7, 9, 1, 21, 16, 14, 25, 13, 48, 23, 27, 32};//归并排序所用序列 System.out.print("原先:"); for(int i = 0; i < list.length; i++){ System.out.print(list[i] + " "); } System.out.println(); int arrayTemp[] = new int[list.length]; mergeSort(list, arrayTemp, 0, list.length-1); System.out.print("排序:"); for(int i = 0; i < list.length; i++){ System.out.print(list[i] + " "); } } public static void mergeSort(int originList[], int tempList[], int start, int end){ if(start != end){ int mid = (start + end) / 2; mergeSort(originList, tempList, start, mid); mergeSort(originList, tempList, mid+1, end); //等于说左边也排好了,右边也排好了 merge(originList, tempList, start, end); }else{ return; } } public static void merge(int originList[], int tempList[], int start, int end){ for(int i = 0; i < originList.length; i++){ tempList[i] = originList[i];//先复制 } int mid = (start + end ) / 2; int indexA = start; int indexB = mid+1; int index = start; while(indexA <= mid && indexB <= end){ if(tempList[indexA] < tempList[indexB]){ originList[index] = tempList[indexA]; indexA++; index++; }else{ originList[index] = tempList[indexB]; index++; indexB++; } } //完毕的时候 while(indexA <= mid){ originList[index] = tempList[indexA]; index++; indexA++; } while(indexB <= end){ originList[index] = tempList[indexB]; index++; indexB++; } } }