前言
排序算法是一个老生常谈问题,目前主要学习了选择排序、冒泡排序、插入排序、归并排序、随机快排、堆排序、计数排序、基数排序,一共八种排序方式。
名称解释
稳定性: 假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。
打印int的二进制
代码
public void print(int number){
for (int i = 31; i >= 0; i--) {
/**
* << 向左移动,空位补0,被移除的高位丢企
* >> 带符号向右移动
* >>> 不带符号向右移动 空位补0
* & 按位与 1和1 为1 其他为0
* | 任何二进制位和0进行0, 任何二进制和1进行为1
* ^ 按位异或 任何相同二进制位进行^运算,结果是0;不相同二进制位^运算结果是1.
* ~ 运算符 对位求反 1变0, 0变1
**/
System.out.print((number&(1<<i))==0?"0":"1");
}
}
选择排序
代码
public void selectSort(int[] numbers){
if (numbers==null||numbers.length<2){
return;
}
for (int i=0;i<numbers.length;i++){
int min=i;
for (int j=i+1;j<numbers.length;j++){
min= numbers[min]>numbers[j]?j:min;
}
exchange(numbers,i,min);
}
}
冒泡排序
代码
public void bubbleSort(int[] numbers){
if (numbers==null||numbers.length<2){
return;
}
for (int i=numbers.length-1;i>=0;i--){
for(int j=0;j<i;j++){
if (numbers[j]>numbers[j+1]){
exchange(numbers,j,j+1);
}
}
}
}
插入排序
代码
public void insertSort1(int[] numbers){
if (numbers==null||numbers.length<2){
return;
}
for(int i=0;i<numbers.length;i++){
for (int j=i;j>0&&numbers[j]<numbers[j-1];j--){
exchange(numbers,j,j-1);
}
}
}
归并排序
代码
public void sortArrRecursive(int[] arr,int L,int R){
//如果L==R则不要进行最后的细分
if (L==R){
return;
}
int mid=(L+R)/2;
sortArrRecursive(arr,L,mid);
sortArrRecursive(arr,mid+1,R);
merge(arr,L,mid,R);
System.out.println("排序后:"+Arrays.toString(arr));
}
/**
* description 将左右两边进行排序后放回原数组中
* param [arr, l, mid, r]
* return void
* author zhuyang
* createTime 2021/12/1 22:58
**/
private void merge(int[] arr, int l, int mid, int r) {
int i=0;
int[] help=new int[r-l+1];
int q=mid+1;
int OneL=l;
while (l<=mid&&q<=r){
help[i++]=arr[l]<arr[q]?arr[l++]:arr[q++];
}
while (l<=mid){
help[i++]=arr[l++];
}
while (q<=r){
help[i++]=arr[q++];
}
for (int i1 = 0; i1 < help.length; i1++) {
arr[OneL++]=help[i1];
}
}
随机快排
代码
public void sort(int[] arr,int l,int r){
if (l>=r){
return;
}
//这一步将随机生成的l和r进行交换,复杂度就变成了O(logN+N)
exchange(arr, l+(int)(Math.random()*(r-l+1)), r);
int[] process = process(arr, l, r);
sort(arr,l,process[0]-1);
sort(arr,process[1]+1,r);
}
/**
* @Description: 数组arr, 以arr[r]为分界,<=arr[r]的数在左边,
* 大于的在右边,等于的在中间,每次排序都会排好等于arr[r]的数,然后再排下一个
* @Author: zhuyang
* @Date: 2021-12-26
* @Param:
* @return:
**/
public int[] process(int[] arr,int l,int r){
if (l>=r){
return new int[]{-1,-1};
}
if (l==r){
return new int[]{l,r};
}
int curL=l-1;
int currR=r;
int index=l;
while (index<currR){
if (arr[index]>arr[r]){
exchange(arr,index,--currR);
}else if (arr[index]<arr[r]){
exchange(arr,index++,++curL);
}else {
index++;
}
}
//最后进行r的交换
exchange(arr,currR,r);
//进行返回
return new int[]{curL+1,currR};
}
堆排序
代码
public void heapSort(int[] arr){
// for (int i = 0; i < arr.length; i++) {
// insertValue(arr,i);
// }
//该for循环也可以将该数组变成大顶堆
for (int i = arr.length-1; i >=0; i--) {
heapify(arr,i,arr.length-1);
}
//进行交换,将大顶堆的最开始的非叶子结点进行交换
exchange(arr,0,arr.length-1);
//再进行排序,同时排查最末尾元素
int index=arr.length-1;
while (index>0){
heapify(arr,0,index);
exchange(arr,0,--index);
}
}
/**
* @Description: 将最大元素排至最初非叶子结点
* @Author: zhuyang
* @Date: 2021-12-09
* @Param:
* @return:
**/
private void heapify(int[] arr, int i, int index) {
int left=2*i+1;
while (index>left&&arr[i]<arr[left]){
int bigIndex=left+1<index&&arr[left+1]>arr[left]?left+1:left;
int bigNum=arr[bigIndex]>arr[i]?bigIndex:i;
//当arr[i]即为最大值时,停止交换
if (i==bigNum){
break;
}
exchange(arr,i,bigIndex);
i=bigIndex;
left=2*i+1;
}
}
计数排序
代码
/**
* @Description: 计数排序 计数排序要求,样本是正整数,且范围比较窄
* @Author: zhuyang
* @Date: 2021-12-12
* @Param:
* @return:
**/
public void sortProcess(int[] arr){
if (arr==null||arr.length==1){
return;
}
//进行计算最大值
int num= Integer.MIN_VALUE;
for (int i : arr) {
num=Math.max(num,i);
}
//进行创建桶
int[] bucket=new int[num+1];
for (int i = 0; i < arr.length; i++) {
bucket[arr[i]]++;
}
//进行重新排序
int index=0;
for (int i = 0; i < bucket.length; i++) {
while (--bucket[i]>=0){
arr[index++]=i;
}
}
}
基数排序
代码
/**
* @Description: 桶排序思想下的排序:基数排序
* 基数排序要求,样本是10进制的正整数
* @Author: zhuyang
* @Date: 2021-12-26
* @Param:
* @return:
**/
public void sortProcess(int[] arr){
//求最大值
int max=Integer.MIN_VALUE;
for (int i : arr) {
max=Math.max(max,i);
}
//获取其深度
int depth=getDepth(max);
//进行再次排序
sortProcess(arr,0,arr.length,depth);
}
private void sortProcess(int[] arr, int l, int r, int depth) {
//创建10个桶,因为是10进制 0~9
int[] help=new int[r-l];
//进行深度遍历
for (int i = 0; i < depth; i++) {
int[] barrel=new int[10];
//进行求arr的每一个数的每一个位数上,总的个数
for (int i1 = l; i1 < r-l; i1++) {
barrel[getDigits(arr[i1],i)]++;
}
//进行归并和
for (int i1 = 1; i1 < barrel.length; i1++) {
barrel[i1]=barrel[i1]+barrel[i1-1];
}
//进行入桶
for (int i1 = l; i1 < r-l; i1++) {
int digits = getDigits(arr[i1], i);
help[barrel[digits]-1]=arr[i1];
barrel[digits]--;
}
System.out.println(Arrays.toString(help));
//进行出桶 出桶这很重要 一定要遵循先入后出原则
int index=0;
for (int i1 = r-l-1; i1 >= 0; i1--) {
arr[i1]=help[index++];
}
}
}
public int getDepth(int number){
int num=0;
while (number>0){
number=number/10;
num++;
}
return num;
}
/**
* @Description: 数 1234324 可以分别取出 1 2 3 4 3 2 4
* @Author: zhuyang
* @Date: 2021-12-12
* @Param:
* @return:
**/
public int getDigits(int number,int depth){
int pow =(int) (number/(Math.pow(10, depth))%10);
return pow;
}
稳定性,时间复杂度,空间复杂度
总结
基数排序要求,样本是10进制的正整数,计数排序要求样本必须是正整数。
Gitee地址
https://gitee.com/zhuayng/foundation-study/tree/develop/JavaBasis