排序基本概念
什么是排序
排序(sorting)的功能是将一个数据元素的任意序列,重写排列成一个按关键字有序的序列。
内部排序和外部排序
一类是整个排序过程在内存储器中进行,成为内部排序
另一类是由于待排序元素数量太大,以至于内存储器无法容纳全部数据,排序需要借助外部存储设备才能完成,这类排序成为外部排序。
稳定排序和就地排序
稳定排序:假设在待排序的文件中,存在两个或两个以上的记录具有相同的关键字,在用某种排序法排序后,若这些相同关键字的元素的相对次序仍然不变,则这种排序方法是稳定的。
其中冒泡,插入,基数,归并属于稳定排序,选择,快速,希尔,归属于不稳定排序。
比较排序和非比较排序
大部分排序都是需要通过比较首先来判断大小,作为排序的依据的。
但是也有例外的,比如计数排序、基数排序,不需要进行比较。
排序类型
排序效率
时间复杂度最高的就是三种基本排序:直接插入、简单选择、冒泡排序。
快速排序
冒泡排序的改进版,也是最好的一种内排序,还涉及到分治和递归。
是由C. A. R. Hoare在1962年提出的一种划分交换排序,它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。
它的基本思想是:
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,
然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
一趟快速排序的算法是:
1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将值为key的项与A[j]交换;
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将值为key的项与A[i]交换;
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[j]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
public static void quickSort(int[] arr) { int low = 0; int high = arr.length-1; quickSort(arr,low,high); } private static void quickSort(int[] arr,int low, int high) { if(low < high) { // 分区操作,将一个数组分成两个分区,返回分区界限索引 int index = partition(arr,low,high); // 对左分区进行快排 quickSort(arr,low,index-1); // 对右分区进行快排 quickSort(arr,index+1,high); } } private static int partition(int[] arr,int low,int high) { // 指定左指针i和右指针j int i = low; int j = high; // 将第一个数作为基准值 int x = arr[low]; // 使用循环实现分区操作 while(i < j) { // 1.从右向左移动j,找到第一个小于基准值的值 while(arr[j] >= x && i < j) { j--; } // 2.将右侧找到小于基准数的值加入到左边的位置,左指针向中间移动一个位置i++ if( i < j) { arr[i] = arr[j]; i++; } // 3.从左向右移动i,找到第一个大于等于基准值的值 arr[i] while(arr[i] < x && i < j) { i ++; } // 4.将左侧找到的大于等于基准的值加入到右边,右指针向中间移动一个位置 j-- if(i < j) { arr[j] = arr[i]; j --; } } // 使用基准值,这就是基准值的最终位置 arr[i] = x; // 返回基准值的位置索引 return i; }