前言:排序算法是入门数据结构预算法知识的基础,本文主要按基本概念到算法原理再到算法实现的学习路线来讲解归并排序算法和快速排序算法,层层递进,环环相扣,非常适合读者学习。此外,如果小编表述的有问题,非常欢迎各位读者在评论区留言与批评指正,谢谢!
目录
1、归并排序算法
1.1基本概念
归并排序算法是一种基于递归思想的高效排序算法,通过从上至下的逐层二分与从下至上的逐层归并,从而完成对序列的排序。
递归方法就是不断直接或间接调用自身的方法,是一个很有用的程序设计技术。这个方法不断把原始问题分解成子问题,子问题又继续分解成新的子问题。子问题在实质上和原始问题是一样的,但是它比原始问题更简单也更小。因为子问题和原始问题具有相同的性质,所以可以用不同的参数调用这个方法,这称作递归调用,当问题达到某个终止条件时,将结果返回调用者。
1.2算法原理
以序列{ 2, 8, 12, 6, 9, 4, 6, 15}为例,先对该序列从上至下逐层二分,
然后从下至上逐层归并,p1,p2两个指针分别指向左右两个子序列的第一个元素,help[]是空数组,用来存放归并后的元素的,i为help[]的索引,初始值i=0。归并过程是这样进行的:比较left[p1]和right[p2]的大小,
①如果left[p1]<=right[p2],help[i++]=left[p1++];
②如果left[p1]>right[p2],help[i++]=right[p2++];
③指针p1或p2指向越过了数组left或数组right,则说明left或right中的元素全部放入了help数组中,right或者left数组中有元素没有放入help中,则需要将剩余元素全部放入help中,即:help[i++]=right[p2++]或者help[i++]=left[p1++]。
1.3算法实现
public class MergeSort {
//归并算法
public static void mergeSort(int[] arr) {
process(arr, 0, arr.length - 1);
}
//递归过程
public static void process(int[] arr, int L, int R) {
if (L == R) {
return;
}
int mid = L + ((R - L) >> 1);//等同于mid=L+(R-L)/2,也等同于mid=(L+R)/2,这种方法中L+R可能越界,会出问题
process(arr, L, mid);
process(arr, mid + 1, R);
merge(arr, L, mid, R);
}
//归并过程
public static void merge(int[] arr, int L, int M, int R) {
int[] help = new int[R - L + 1];
int i = 0;
int p1 = L;
int p2 = M + 1;
while (p1 <= M && p2 <= R) {
help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
}
while (p1 <= M) {
help[i++] = arr[p1++];
}
while (p2 <= R) {
help[i++] = arr[p2++];
}
for (int j = 0; j < help.length; j++) {
arr[L + j] = help[j];
}
}
//算法测试
public static void main(String[] args) {
int[] arr = { 2, 8, 12, 6, 9, 4, 6, 15};
mergeSort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
运行结果:
2、快速排序算法
2.1基本概念
快速排序算法是是一个时间复杂度为o(N*logN),空间复杂度为o(logN)的排序算法,不具备稳定性。在众多排序算法中,如果单从运行速度的角度考虑,推荐优先使用快排,实验证明快排是速度最快的算法,这里说的快排指的是随机快排。
快速排序就是基于三色旗问题(也就是荷兰国旗问题)的思想采用递归编程技术而形成的算法,三色旗问题具体就是:在数组中随机选择一个数,小于这个数的放在数组的左边, 大于这个数的放在数组的右边,等于这个数的放在数组的中间。通过不断递归三色旗问题从而实现序列的排序。
2.2算法原理
同样以序列{ 2, 8, 12, 6, 9, 4, 6, 15}为例,下图是第一次进行三色图问题,
这时相当于将数组划分为三个区域:<区,=区,>区。等于区不用管,<区和>区继续上面的操作,即不断向下递归,就能成功实现排序。
2.3代码实现
public class QuickSort {
public static void quickSort(int[] arr){
process(arr,0,arr.length-1);
}
public static void process(int[] arr,int L,int R){
if (L<R){//L<R这个边界条件要想清楚,边界条件没设好,就会导致递归时出现栈溢出
//在数组中随机选一个数作为判断标志,并将这个数和最后一个数交换位置
swap(arr,L+(int)(Math.random()*(R-L+1)),R);
int[] p=partition(arr,L,R);
process(arr,L,p[0]-1);//<区
process(arr,p[1]+1,R);//>区
}
}
public static void swap(int[] arr,int i,int j){
//函数功能是交换两数的位置
int temp;
temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
public static int[] partition(int[] arr,int L,int R){
//该函数的功能是根据随机选出的数,小于这个数的放在数组的左边,大于这个数的放在数组右边,等于这个数的放在中间。
//并返回<区的右边界和>区的左边界
int less=L-1;//<区初始右边界
int more=R;//>区初始左边界
while (L<more){//L表示当前值的位置
if(arr[L]<arr[R]){
swap(arr,++less,L++);
}else if(arr[L]>arr[R]){
swap(arr,--more,L);
}else {
L++;
}
}
swap(arr,more,R);
return new int[] {less+1,more};//想清楚arr[less]在<区内,而arr[more]不在>区内,
// 因为more这个位置本来在>区,但是由于最后一次得和R位置上的数交换,所以more位置上的这个数变成了=区
}
public static void main(String[] args) {
int[] arr = {2, 8, 12, 6, 9, 4, 6, 15};
quickSort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
运行结果: