排序(一):https://blog.csdn.net/weixin_56697114/article/details/116431495
目录
1、归并排序
1)递归
定义:定义方法时,在方法内部调用方法本身,称之为递归.
注意事项:在递归中,不能无限制的调用自己,必须要有边界条件,能够让递归结束,因为每一次递归调用都会在栈内存开辟
新的空间,重新执行方法,如果递归的层级太深,很容易造成栈内存溢出。
package paixu;
//求n的阶乘
public class Digui {
public static void main(String[] args) {
int sum = suan(5);
System.out.println(sum);
}
public static int suan(int n) {
if(n==1) {
return 1;
}
return n*suan(n-1);
}
}
2)归并排序
原理:尽可能的一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元素个数是
1为止。然后进行排序并合并成新的组,再进行排序合并,直到剩下一个组。
步骤:
1)不断拆分直到每个子组元素个数为1,每两个子组进行比较
2)定义三个指针,i 为assist的指针,p1为第一个子组的指针,p2为第二个子组的指针
3)遍历,通过比较 p1 和 p2 的值,将小的放到assist的 i 中,将小的指针往后移一个格,同时 i 也往后移一个格
4)将assist填充的部分放到 a 中同样的位置
package paixu;
import java.util.Arrays;
//归并排序
public class Guib {
//归并需要的辅助数组
private static int[] assist;
//对a进行排序
public static void sort(int[] a) {
assist = new int[a.length];
//lo为最小索引,hi为最大索引
int lo = 0;
int hi = a.length-1;
sort(a, lo, hi);
}
//对a从lo到hi进行排序
public static void sort(int[] a, int lo, int hi) {
if(hi<=lo) {
return;
}
int mid = lo+(hi-lo)/2;
//对lo到mid进行排序
sort(a, lo, mid);
//对mid+1到hi进行排序
sort(a, mid+1, hi);
//将两个数组进行归并
merge(a, lo, mid, hi);
}
public static void merge(int[] a, int lo, int mid, int hi) {
//定义3个指针
int i = lo;
int p1 = lo;
int p2 = mid+1;
while(p1<=mid && p2<=hi) {
if(a[p1]<=a[p2]) {
assist[i++] = a[p1++];
}else{
assist[i++] = a[p2++];
}
}
while(p1<=mid) {
assist[i++] = a[p1++];
}
while(p2<=hi) {
assist[i++] = a[p2++];
}
for(int index=0; index<=hi; index++) {
a[index] = assist[index];
}
}
public static void main(String[] args) {
int[] a = {6,5,4,3,2,1};
sort(a);
System.out.println("结果:"+Arrays.toString(a));
}
}
2、快速排序
原理:O(nlogn)
1)找一个基准值,基准值左边存放比它小的,右边存放比它大的,再定义两个指针 l(左指针) r (右指针)
2)l 从左到右遍历,当发现比基准值大的停止。r 从右到左,当发现比基准值小的停止
3)当 l 和 r 遍历结束后,如果 l<r 就交换两值,再继续遍历直到 l>=r跳出遍历,找到基准值应该在的位置
4)再交换基准值与这个位置的值,返回这个位置的返回值mid
5)根据mid分成两组 lo,mid-1 mid+1,hi,继续以上
package paixu;
import java.util.Arrays;
//快速排序
public class Kuaisu {
public static void sort(int[] a) {
int lo = 0;
int hi = a.length-1;
sort(a, lo, hi);
}
public static void sort(int[] a, int lo, int hi) {
if(hi <= lo) {
return;
}
int mid = suan(a,lo,hi);
sort(a, lo, mid-1);
sort(a, mid+1, hi);
}
public static int suan(int[] a, int lo, int hi) {
int b = a[lo];
//定义两个指针
int l = lo;
int r = hi;
while(true) {
while(a[r]>b) {
if(r==lo) {
break;
}
r--;
}
while(a[l]<=b) {
if(l==hi) {
break;
}
l++;
}
if(l>=r) {
break;
}else {
swap(a, l, r);
}
System.out.println(Arrays.toString(a));
}
swap(a,lo,r);
return r;
}
//交换
public static void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
public static void main(String[] args) {
int[] a = {6,5,4,3,2,1};
sort(a);
System.out.println("结果:"+Arrays.toString(a));
}
}
3、排序的稳定性
稳定性的定义:
数组arr中有若干元素,其中A元素和B元素相等,并且A元素在B元素前面,如果使用某种排序算法排序后,能够保
证A元素依然在B元素的前面,可以说这个该算法是稳定的。
稳定性的意义: 多次排序才有意义。例,如图,当按销量从高到低排序,如果销量相同时,价格的排序不变,则稳定。
好处:1、保留了价格的排序 2、少进行一次排序,节省资源
排序方式的稳定性:
1)冒泡排序:a[j+1]<a[j] 只有小于时相邻两个才进行判断,所以稳定。
2)选择排序:{5(1),8 ,5(2), 2, 9 },排序后{2,5(2),5(1),8,9},5(1)跑到5(2)后面,所以不稳定。
3)插入排序:a[j]>a[j+1],只有大于时相邻两个才会进行交换,所以稳定。
4)希尔排序:{5(1),8 ,5(2), 2, 9 },排序后{2,5(2),5(1),8,9},5(1)跑到5(2)后面,所以不稳定。
5)归并排序: 当等于的时候前面的还是放在前面,所以稳定。
6)快速排序:在基准值的右侧找一个比基准值小的元素,在基准值的左侧找一个比基准值大的元素,然后交换这两个元素,是不稳定的。