归并排序:
package learn;
public class Demo {
public static void mergeSort(int[] arr){
if(arr==null || arr.length<2){
return;
}
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);
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;//记录help当前数下标
int p1=L;//记录左边当前数下标
int p2=M+1;//记录右边当前数下标
while(p1<=M && p2<=R){
if(arr[p1]<=arr[p2]){
help[i++]=arr[p1++];
}else{
help[i++]=arr[p2++];
}
}
while (p1<=M){
help[i++]=arr[p1++];
}
while(p2<=R){
help[i++]=arr[p2++];
}
for(i=0;i<help.length;i++){
arr[i+L]=help[i];
}
}
public static void main(String[] args) {
int[] arr={4,3,5,6,5,0,1,7,8,5};
mergeSort(arr);
for(int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
}
}
小和问题:在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。(利用归并排序)
package learn;
public class Demo {
public static int smallSum(int[] arr){
if(arr==null || arr.length<2){
return 0;
}
return process(arr,0,arr.length-1);
}
public static int process(int[] arr,int L,int R){
if(L==R)return 0;
int mid=L+((R-L)>>1);
return process(arr,L,mid)+process(arr,mid+1,R)+merge(arr,L,mid,R);
}
public static int merge(int[] arr,int L,int M,int R){
int[] help=new int[R-L+1];
int i=0;//记录help当前数下标
int p1=L;//记录左边当前数下标
int p2=M+1;//记录右边当前数下标
int s=0;//记录此部分小和
while(p1<=M && p2<=R){
if(arr[p1]<arr[p2]){
s+=arr[p1]*(R-p2+1);
help[i++]=arr[p1++];
}else{
help[i++]=arr[p2++];
}
}
while (p1<=M){
help[i++]=arr[p1++];
}
while(p2<=R){
help[i++]=arr[p2++];
}
for(i=0;i<help.length;i++){
arr[i+L]=help[i];
}
return s;
}
public static void main(String[] args) {
int[] arr={1,3,4,2,5};
System.out.println(smallSum(arr));
}
}
快速排序:
package learn;
public class Demo {
public static void quickSort(int[] arr){
if(arr==null || arr.length<2){
return;
}
mySort(arr,0,arr.length-1);
}
public static void mySort(int[] arr,int l,int r){
if(l<r){
//Math.random() >=0 <1的double值
int pivot=l+(int)(Math.random()*(r-l+1));//随机产生划分值下标
swap(arr,pivot,r);
int[] p=partition(arr,l,r);
mySort(arr,l,p[0]-1);//<区域
mySort(arr,p[1]+1,r);//>区域
}
}
public static int[] partition(int[] arr,int l,int r) {
int less=l-1;//小于arr[r]的那些数的左边界
int more=r;//大于arr[r]的那些数的右边界
//l指向当前数的位置
while(l<more){//还有数未考虑,还未和右边界撞上
if(arr[l]<arr[r]){
less++;
swap(arr,less,l);//less和l交换 less和l都是已经看过的数 所以l要++ 继续看下一个数
l++;
}else if(arr[l]>arr[r]){
more--;
swap(arr,more,l);//此处l不用++ 因为more和l交换 more是我们还未看的数 现在它被换到了l 我们要看一看它比划分值大还是小
}else {
l++;
}
}
swap(arr,r,more);//和>arr[r]区域的第一个数做交换
//至此,小于arr[r]的在左边,等于的在中间,大于的在右边 然后递归实现此过程(左右分别递归,中间无需再动,中间的数已处于最终位置)
int[] p={less+1,more};
return p;//等于arr[r]的最左边和最右边
}
public static void swap(int[] arr,int i,int j) {
int x=arr[i];
arr[i]=arr[j];
arr[j]=x;
}
public static void main(String[] args) {
int[] arr={1,3,4,2,5};
quickSort(arr);
for(int i=0;i< arr.length;i++){
System.out.println(arr[i]);
}
}
}