插入排序 :不断的将后面的数据插入到前面的有序数据中。
冒泡排序:通过从0交换相邻数据,保证第一轮n-1次交换后最大数据在倒数第一位;第二轮n-2次交换后,第二大数据在倒数第二位
选择排序:第一轮:从1~n-1中找最小的数据与第0为交换,保证最小数据在第一位;
冒泡和选择排序区别在于:在交换的方式上 冒泡算法,每次比较如果发现较小的元素在后面,就交换两个相邻的元素。 而选择排序算法的改进在于:先并不急于调换位置,先从A[1]开始逐个检查,看哪个数最小就记下该数所在的位置P,等一躺扫描完毕,再把A[P]和A[1]对调,这时A[1]到A[10]中最小的数据就换
快排代码
递归退出的边界条件:left >= right
操作中的边界条件 : left < right
排序算法:
原地排序:原地排序算法,就是特指空间复杂度是 O(1) 的排序算法
稳定的排序算法:经过某种排序算法排序之后,如果两个等值的数据的前后顺序没有改变
如何在 O(n) 的时间复杂度内查找一个无序数组中的第 K 大元素?
利用快排思想,每次用于比较的数据a,假设其最终index为p,那其为该无序数组中的第p+1大的元素,如果
p+1==k,则第k大元素就是a,否则在其中的一侧中。
归并和快排区别?
归并:先分区后处理,代码上就是先递归,后merge
快排:先处理后排序,代码上就是先sort 后递归
作业:
如何用递归代码来实现归并排序:merge(A,p,q) = merge(A,p,r)+merge(A,r,q) 边界r>=q
快速排序代码 再来一次
n个无序数组查找第k大元素
现在你有 10 个接口访问日志文件,每个日志文件大小约 300MB,每个文件里的日志都是按照时间戳从小到大排序的。你希望将这 10 个较小的日志文件,合并为 1 个日志文件,合并之后的日志仍然按照时间戳从小到大排列。如果处理上述排序任务的机器内存只有 1GB,你有什么好的解决思路,能“快速”地将这 10 个日志文件合并吗?
构建10个文件流,每次读取一条,比较获取最小的一条,放入新的空间,然后读取下一条
线性排序
本质上不再进行原值之间的比较,而是通过分类等巧妙的方案实现数据的排序,实例如:
桶、基数、计数排序
桶排序:比较适合用在外部排序中。所谓的外部排序就是数据存储在外部磁盘中,数据量比较大,内存有限,无法将数据全部加载到内存中。
订单金额的桶排序
1)扫描订单金额,1-10万
2)分成100桶,第一个范围 1-1000,第二个1001-2000...
3)桶内快排
有序将桶合并即可。
时间复杂度的计算:
n个订单,m个桶,每个桶数据n/m 每个桶内时间复杂度 n/mlogn/m
整体复杂度 m*n/mlogn/m = nlogn/m~~ n
上面如果某个桶数据特别多,再用桶的思想处理。
桶排序比较适合用在外部排序中。所谓的外部排序就是数据存储在外部磁盘中,数据量比较大,内存有限,无法将数据全部加载到内存中。
计数排序:
需要排序的n个数据,所处的范围不大,如最大值为k,我们把数据划分成k个桶。
如高考分数排名:50万考生,分数范围:0-900
实例,分数: 2 1 0 2 1 4
第一个数组 index:分数 value:分数个数 0-1 1-2 2-2 3-0 4-1
第二个数组 index:分数 value:个数的累加 0-1 1-3 2-5 3-5 4-6
第三个数组开始存放学生,index:index value:学生分数
注意:处理第二个数组获取第三个数组时,一定是先处理value相同的部分,上面的实例即为2-5, 其含义是 2放到第5个位置,即index为4,且同时2-5中对5减去1 2-4
4-2 -》 0-1 1-3 2-4 3-5 4-6
2-1,4-2 -》 0-1 1-2 2-4 3-5 4-6
0-0,2-1,4-2 -》 0-0 1-2 2-4 3-5 4-6
0-0,2-1,3-2,4-2 -》 0-0 1-2 2-3 3-5 4-6
0-0,1-1,2-1,3-2,4-2 -》 0-0 1-1 2-3 3-5 4-6
0-0,1-1,2-1,3-2,4-2,5-4 -》 0-0 1-1 2-3 3-5 4-5
结束。
计数排序适用场景:
数据范围不大的场景,如果数据范围k比n大很多,不适合使用计数排序
针对非整数或负整数,需要转化为正数
基数排序:
多次使用稳定排序算法 。
稳定排序: 即 1 2 3 2,即排序前后两个2的位置没有发生变化
手机号排序:
先按照最后一位来排序手机号码,然后,再按照倒数第二位重新排序,以此类推,最后按照第一位重新排序。经过 11 次排序之后,手机号码就都有序了。
例如:桶排序即可
适用场景:
1) 可以分割成位来进行比较
2) 位之间有递进关系,如a 数据的高位比 b 数据大,那剩下的低位就不用比较了
3) 每位数据的范围不可太大,否则无法适用线性排序
问题:
根据年龄给100万用户排序:
1 150岁
计数排序即可,150个桶
对 D,a,F,B,c,A,z 这个字符串进行排序,要求将其中所有小写字母都排在大写字母的前面,但小写字母内部和大写字母内部不要求有序
计数排序:先统计length,大写字母个数,大写字母个数为大写字母开始村内方的位置,别的放到前面。
巧妙的逻辑:用两个指针a、b:a指针从头开始往后遍历,遇到大写字母就停下,b从后往前遍历,遇到小写字母就停下,交换a、b指针对应的元素;重复如上过程,直到a、b指针相交。
高性能排序选择:
线性排序需要特定要求,排除
快排和归并排序,归并耗内存,一般使用快排
快排O(n2)怎么避免,选择合适的分区点?
1) 三数取中发
2) 随机法
java中的sort算法:
归并排序: 分区 + 排序 + 归并 --已弃用,最坏O(n2)
时间轴排序: --推荐
合理分区 + 反转倒叙 + 合并
public class Sort {
/**
* desc: 选择排序:时间复杂度O(n2)
*/
public static void choseSort(int[] array){
int length = array.length;
int temp = 0;
for(int i=0; i<length; i++){
for(int j=i+1;j<length;j++){
if(array[j]<array[i]){
temp = array[i];
array[i] =array[j];
array[j]=temp;
}
}
}
}
/**
* desc: 冒泡排序:时间复杂度O(n2)
*/
public static void puppleSort(int[] array){
int length = array.length;
int temp = 0;
for(int i=0; i<length; i++){
for(int j=0;j<length-1-i;j++){
if(array[j] > array[j+1]){
temp = array[j+1];
array[j+1] = array[j];
array[j] = temp;
}
}
}
}
/**
* desc: 插入排序:时间复杂度O(n2)
*/
public static void insertSort(int[] array){
int length = array.length;
for(int i=1; i<length; i++){
int temp = array[i];
int index = i;
for(int j=i-1;j>=0;j--){
if(temp<array[j]){
array[j+1]=array[j];
index = j;
}else{
break;
}
}
array[index] = temp;
}
}
/**
* desc: 快排:时间复杂度O(nlogn)
*/
public static void quickSort(int[] arr, int left, int right){
if(left >= right){
return;
}
int l = left;
int r = right;
int tmp = arr[left];
while( l < r){
while(arr[r] >= tmp && l < r){
r --;
}
if(l<r){
arr[l] = arr[r];
l++;
}
while(arr[l] < tmp && l < r){
l ++;
}
if(l < r){
arr[r] = arr[l];
r--;
}
}
arr[l] = tmp;
quickSort(arr,left,l-1);
quickSort(arr,l+1,right);
}
/**
* desc: 借鉴快排的思想,从n个无序数组中查找第n大的数
*/
public static int findN(int[] arr, int k, int left, int right){
if(k > arr.length){
return -1;
}
int l = left;
int r = right;
int tmp = arr[left];
while(l < r){
while(l < r && arr[r] > tmp){
r --;
}
if(l < r){
arr[l] = arr[r];
l++;
}
while(l<r && arr[l]<tmp){
l++;
}
if(l<r){
arr[r] = arr[l];
r--;
}
}
arr[l] = tmp;
if(l+1 == k){
return arr[l];
}else if(l+1 < k ){
return findN(arr,k,l+1,right);
}else{
return findN(arr,k,left,l-1);
}
}
/**
* desc: 归并排序,注意先归后并
*/
public static void mergeSort(int[] arr, int left, int right){
if(left >= right){
return ;
}
// 避免直接right导致的溢出问题
int middle = left + ((right - left) >> 1);
mergeSort(arr, left, middle);
mergeSort(arr, middle+1, right);
merge(arr, left, middle, right);
}
/**
* desc: 有序数组的合并
*/
public static void merge(int[] arr, int left, int middle, int right){
int[] temp = new int[arr.length];
int k =left,l = left,m =middle+1;
while(l<=middle && m <=right){
if(arr[l] >= arr [m]){
temp[k++]=arr[m++];
}else{
temp[k++]=arr[l++];
}
}
while(l<=middle){
temp[k++]=arr[l++];
}
while(m <=right){
temp[k++]=arr[m++];
}
for(int i=left; i<=right; i++){
arr[i]=temp[i];
}
}
/**
* desc: 遍历数组
*/
public static void ergodicArray(int[] array){
for(int i=0; i<array.length; i++){
System.out.print(array[i]+",");
}
System.out.println();
}
/**
* desc: 计数排序,如通过统计值出现的次数,定位其所在的位置
* 适用场景:50万考生,分数范围0-800的排序
* bound:最大值
*/
public static void countSort(int[] arr, int bound){
// index为传入arr的值,value为arr某值出现的次数
int[] valueTime = new int[bound];
int length = arr.length;
for(int i=0;i<length;i++){
valueTime[arr[i]] = valueTime[arr[i]] +1;
}
// index为传入arr的值,value为arr某值及比起小的值出现的次数的累加,该累加值决定实际值所在的下标
int[] vlueAccum = new int[bound];
vlueAccum[0]=valueTime[0];
for(int i=1 ; i<bound; i++){
vlueAccum[i] = vlueAccum[i-1] + valueTime[i];
}
// 临时数组
int[] temp = new int[length];
for(int i = 0;i<length; i++){
temp[vlueAccum[arr[i]]-1] = arr[i];
vlueAccum[arr[i]] = vlueAccum[arr[i]]-1;
}
for(int i=0; i<length; i++){
arr[i] = temp[i];
}
}
public static void main(String[] args) {
Random rm = new Random();
rm.nextInt(9);
int[] arr = new int[50];
for(int i=0; i<50; i++){
arr[i]=rm.nextInt(9);
}
ergodicArray(arr);
countSort(arr,9);
ergodicArray(arr);
char c = 'A';
//
// int[] array = {11, 9, 14, 13, 8, 8, 19};
System.out.println(findN(array,2,0,array.length-1));
// ergodicArray(array);
// mergeSort(array,0, array.length-1);
insertSort(array);
insertSort(array);
// ergodicArray(array);
}
}