1.快速排序
快速排序是Hoare在1962年提出的一种二叉树结构的交换排序的方法,采用了递归的思想
思想:任取待排序的元素序列中的某元素作为基准值,按照原来的顺序将序列分为两个子序列,
左子序列中的所有元素均小于基准直,右子树的所有序列中的元素均大于基准直,然后左右子序列重复该过程,直到所有元素都排在相应的位置上。
先写出大致的框架,与二叉树的前序遍历非常之像,写递归框架可以照着二叉树前序遍历写出来,
后续只要分析如何按照基准直对区间中的数据划分即可
java
public static void QuickSort(int[] array,int start,int end){
//递归结束的条件
if(start >= end){
return;
}
//如果子区间的数据越来越少了,直接采用 范围插入排序 更快
if(end-start+1 < 10){
insertSort(array,start,end);
return;
}
//三数取中原因:
//如果这个序列是接近有序的,1 2 3 4 5 6 7 8 9 11 10
//基准值一般选取最左侧的数据 1,那么每次递归1的左侧没有子序列,只有右侧
//所以会大大提高时间复杂度,
//那么就取最左,最有,最中三个数据的中位数,
//将中位数与第一个数交换,这样返回的基准直就不是1了,而是与1交换的数
int index = midTreeNum(array,start,end);
swap(array,start,index);
//寻找基准直位置的下标
//该方法有很多种,等下面我们一一介绍
int par = paririon(array,start,end);
//按照基准直,将其左右两个子区间进行排序
QuickSort(array,start,par-1);
QuickSort(array,par+1,end);
}
//挖坑法
private static int paririon(int[]array,int left,int right){
int temp = array[left];
while (left < right){
while (left < right && array[right]<=temp){
right--;
}
array[left] = array[right];
while (left < right && array[left] > temp){
left++;
}
array[right] =array[left];
}
array[left] = temp;
return left;
}
//找到中间值的下标
private static int midTreeNum(int[]array,int left,int right){
//中间位置下标
int mid = left+(right-left)/2;
if(array[left]<array[right]){
if(array[mid]<array[left]){
return left;
}else if(array[mid]>array[right]){
return right;
}else {
return mid;
}
}else {
if(array[mid]>array[left]){
return left;
}else if(array[mid]<array[right]){
return right;
}else {
return mid;
}
}
}
private static void insertSort(int[]array,int left,int right){
for(int i=left+1;i<=right;i++){
int temp = array[i];
int j = i-1;
for(;j>=0;j--){
if(array[j] > temp){
array[j+1] = array[j];
}else {
break;
}
}
array[j+1] = temp;
}
}
paririon 方法使用用来找到基准直的,通过找到的基准直将序列化分为两个子区间,再通过递归不断排序,缩小子区间,直到子区间就一个数字。
int index = midTreeNum(array,start,end);
这条语句什么意思? 就是取到三个数的中位数
三数取中原因:
如果这个序列是接近有序的,1 2 3 4 5 6 7 8 9 11 10
基准值一般选取最左侧的数据 1,那么每次递归1的左侧没有子序列,只有右侧
所以会大大提高时间复杂度,
那么就取最左,最有,最中三个数据的中位数,
将中位数与第一个数交换,这样返回的基准直就不是1了,而是与1交换的数
上面查找基准值的paririon方法是挖坑法
下面例举Hoare法查找基准值
java
//Hoare法
private static int paririon2(int[]array,int left,int right){
int i = left;
int temp = array[left];
while (left < right){
while (left < right && array[right] >= temp){
right--;
}
while (left < right && array[left]<=temp){
left++;
}
swap(array,left,right);
}
swap(array,left,i);
return left;
}
快速排序总结:
1.整体综合性能与使用场景都是比较好的,才敢较快排
2.时间复杂度:O(N*logN);
3.空间复杂度:O(logN);
4.稳定性:不稳定
2.归并排序
建立在归并操作上的有效排序算法,该算法采用分治法的一个典型的应用。将已有的子序列合并,得到完全有序的序列。
使每个子序列有序,再使每个子序列之间有序。
归并排序:
更多是解决磁盘中的外排序问题。
时间复杂度:O(N*logN)
空间复杂度:O(N)
稳定性:稳定
代码实现
java
//归并排序
public static void mergeSort(int[]array){
megeFun(array,0,array.length-1);
}
public static void megeFun(int[]array,int left,int right){
if(left >=right){
return;
}
//分解
int mid = left+(right-left)/2;
megeFun(array,left,mid);
megeFun(array,mid+1,right);
//合并
merge(array,left,mid,right);
}
public static void merge(int[]array,int left,int mid,int right){
int[] temp = new int[right-left+1];
int sl = left;
int el = mid;
int sr = mid+1;
int er = right;
int k = 0;
while (sl<=el && sr<=er){
if(array[sl] <= array[sr]){
temp[k++] = array[sl++];
}else{
temp[k++] = array[sr++];
}
}
while (sl<=el){
temp[k++] = array[sl++];
}
while (sr<=er){
temp[k++] = array[sr++];
}
for (int i = 0; i < k; i++) {
array[i+left] = temp[i];
}
}
3.计数排序
又叫做鸽巢原理,是对哈希直接定址法的变形应用
1.统计相同元素的出现的次数
2.根据统计结果将序列收回到原来的序列中
时间复杂度:O(max(N,范围))
空间复杂度:O(范围)
稳定性:稳定
代码:
java
public static void countSort(int[]array){
//遍历数组找到最大最小值
int mindex= array[0];
int maxdex = array[0];
for (int i = 0; i < array.length; i++) {
if(maxdex<array[i]){
maxdex = array[i];
}
if(mindex>array[i]){
mindex = array[i];
}
}
//已经找到最大与最小值了,定义数组
int[]count = new int[maxdex-mindex+1];
for (int i = 0; i < array.length; i++) {
int val = array[i]-mindex;
count[val]++;
}
//count数组以数据为下标,出现的次数为值
int index = 0;//array的下标
for (int i = 0; i < count.length ; i++) {
while (count[i]>0){
array[index] = i+mindex;
index++;
count[i]--;
}
}
}