排序算法之----归并排序,快速排序,堆排序

1 归并排序

分而治之(divide - conquer);每个递归过程涉及三个步骤
第一, 分解: 把待排序的 n 个元素的序列分解成两个子序列, 每个子序列包括 n/2 个元素.
第二, 治理: 对每个子序列分别调用归并排序MergeSort, 进行递归操作
第三, 合并: 合并两个排好序的子序列,生成排序结果.
时间复杂度:O(nlogn)

public static void mergeSort(int[] arr){
	if(arr == null || arr.length < 2){
		return;
	}
	mergeSort(arr,0,arr.length-1);
}
public static void mergeSort(int[] arr,int L,int R){
	if(L == R){
		return;
	}
	int mid = L + (R-L)/2;
	mergeSort(arr,L,mid);
	mergeSort(arr,mid+1,R)
	merge(arr,L,mid,R);
}
public static void merge(int[] arr,int L,int mid,int R){
	int[] help = new int[R - L + 1];//辅助数组
	int p1 = L;
	int p2 = mid + 1;
	int i = 0;
	 // 把较小的数先移到新数组中
	while(p1 <= mid && p2 <= R){
		help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
	}
	 // 把左边剩余的数移入数组 
	while(p1 <= mid){
		help[i++] = arr[p1++];
	}
	// 把右边剩余的数移入数组
	while(p2 <= R){
		help[i++] = arr[p2++];
	}
	 // 把新数组中的数覆盖nums数组
	for(int j=0; j < help.length; j++){
		arr[L + j] = help[j];
	}
}

2快速排序

本文为经典快排的改进版–随机快排

  • 是一种比较快的排序,适合基本无序的数据
  • 从数列中挑取最后一个元素(最后一个元素随机选出)做基准,重新排列,所有比基准小的放前面,比基准大的放后面
  • 分成两拨后,继续递归的使用上述方法,最终有序
  • 时间复杂度:O(nlogn)
public static void quickSort(int[] arr) {
	if (arr == null || arr.length < 2) {
		return;
	}
	quickSort(arr, 0, arr.length - 1);
}
public static void quickSort(int[] arr,int L,int R){
	if(L < R){
		swap(arr, L + (int)(Math.random()*(R - L + 1)), R);//在数组中随机选取一个作为基准
		int[] p = partition(arr, L, R);
		quickSort(arr, L, p[0] - 1);
		quickSort(arr, p[1] + 1, R);
	}
}
/*
less指针为小于基准的区域,初始指向-1,
more指针为大于基准的区域,初始指向基准位置,
开始时让数组第一位即L与基准相比,小于则交换L与less前一位,L+1;
大于则交换L与more的后一位,L继续与基准比较;相等则L+1
由于基准没参与交换,所以每次遍历完之后要交换more位置与基准位置,确保有序
*/
public static int[] partition(int[] arr,int L,int R){
	int less = L - 1;
	int more = R;
	while(L < more){//
		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};//返回基准值相等的左右边界
}
public static void swap(int[] arr, int i, int j) {
	int tmp = arr[i];
	arr[i] = arr[j];
	arr[j] = tmp;
}
//简化下代码
public class QuickSort {
    public static void quickSort(int[] arr){
        if(arr==null || arr.length<2){
            return;
        }
        quickSort(arr,0,arr.length-1);
    }
    private static void quickSort(int[] arr, int L, int R) {
        if(L < R){
            swap(arr,L+(int)(Math.random()*(R-L+1)),R);
            int[] p = partition(arr,L,R);
            quickSort(arr,L,p[0]);
            quickSort(arr,p[1],R);
        }
    }
    private static int[] partition(int[] arr, int L, int R) {
        int less = L-1,more = R+1;
        int target = arr[R];
        while(L < more){
            if(arr[L] < target){
                swap(arr,++less,L++);
            }else if(arr[L] > target){
                swap(arr,--more,L);
            }else{
                L++;
            }
        }
        //返回基准值左右的下标,比如{1,2,2,3},返回1,3的下标
        return new int[]{less,more};
    }
    public static void swap(int[] arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

3堆排序

1 将序列构建成大顶堆。
2 将根节点与最后一个节点交换,然后断开最后一个节点
3 重复第一、二步,直到所有节点断开。

  • 时间复杂度:O(nlogn)
public static void heapSort(int[] arr){
	if(arr == null || arr.length < 2){
		return;
	}
	for(int i=0; i<arr.length; i++){
		heapInsert(arr,i);
	}
	int size = arr.length;
	swap(arr, 0, --size);
	while(size > 0 ){
		heapify(arr, 0, size);
		swap(arr, 0, --size);
	}
}
public static void heapInsert(int[] arr,int index){
	while(arr[index] > arr[(index - 1) / 2]){
		swap(arr, index, (index - 1) / 2);
		index = (index - 1) / 2;
	}
}
public static void heapify(int[] arr,int index,int size){
	int left = index * 2 + 1;
	while(left < size){
		int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;
		largest = arr[largest] > arr[index] ? largest : index;
		if(largest == index){
			break;
		}
		swap(arr, largest, index);
		index = largest;
		left = index * 2 + 1;
	}
}
public static void swap(int[] arr, int i, int j) {
	int tmp = arr[i];
	arr[i] = arr[j];
	arr[j] = tmp;
}

排序算法平均时间复杂度最坏时间复杂度空间复杂度是否稳定
冒泡排序O(n2)O(n2)O(1)
选择排序O(n2)O(n2)O(1)不是
直接插入排序O(n2)O(n2)O(1)
归并排序O(nlogn)O(nlogn)O(n)
快速排序O(nlogn)O(n2)O(logn)不是
堆排序O(nlogn)O(nlogn)O(1)不是
希尔排序O(nlogn)O(ns)O(1)不是
计数排序O(n+k)O(n+k)O(n+k)
基数排序O(N∗M)O(N∗M)O(M)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值