Java实现十大排序算法

Java实现十大排序算法

十大排序算法分别为:选择排序、冒泡排序、插入排序、快速排序、归并排序、堆排序、希尔排序、桶排序、计数排序、基数排序。

本篇只是为了方便我在代码中直接复制调用,因此原理和思想解释的并不清楚,想看原理的朋友可以参考这篇文章:Java实现十大排序算法_木梓沐丶的博客-CSDN博客,有原理和图解,写的超好。

十大排序算法的对比

image-20221226231724153

十大排序算法记忆法

《忆排序,面试我最强》 – 马士兵

选泡插, (选择、冒泡、插入)

快归堆希桶计基, (快速、归并、堆、希尔、桶、计数、基数)

恩方恩老恩一三, (选泡插复杂度是n2,快归希是nlogn,希尔是n1.3

对恩加K恩乘K, (桶计是n+k,基是n*k)

不稳稳稳不稳稳, (选、泡、插、快、归)

不稳不稳稳稳稳! (堆、希、桶、计、基)

1、选择排序(SelectionSort)

思想:每次选择一个当前未排序部分中最小的,放在最前面的位置

代码:

private static void sort (int[] arr){
    int minPos;
    for (int i = 0; i < arr.length; i++){
        minPos = i;
        for (int j = i+1; j < arr.length; j++){
 			if (arr[j] < arr[minPos]){
                minPos = j;
            }           
        }
        swap(arr,i,minPos);
    }
}

private static void swap (int[] arr,int i,int j){
	int temp = arr[i];
	arr[i] = arr[j];
	arr[j] = temp;
}

2、冒泡排序(BubbleSort)

思想:依次循环比较相邻两个数的大小,这样每次循环过后最大的那个数就到了数组尾

代码:

private static void sort(int[] arr){
    for (int end = arr.length-1; end > 0; end--){
        for (int i = 0; i < end; i++) {
            if (arr[i] > arr[i+1]){
                swap(arr,i,i+1);
            }
        }
    }
}

private static void swap(int[] arr, int i, int j){
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

3、插入排序(InsertSort)

思想:将数组中的数据从第二位开始向前找到合适的位置插入,有点类似向前的冒泡排序

代码:

private static void sort(int[] arr){
    for (int i = 1; i < arr.length; i++) {
        int j = i;
        while (j > 0 && arr[j] < arr[j-1]){
            swap(arr,j,j-1);
            j--;
        }
    }
}

private static void swap(int[] arr, int i, int j){
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

4、希尔排序(ShellSort)

思想:改进版的插入排序,首先设置一个间隔,插入排序相同间隔的每组数据,之后缩小间隔,直至间隔缩小为1

代码:

private static void sort(int[] arr){
    int h = 1;
    while (h <= arr.length/3){
        h = h*3 +1;
    }
    for (int gap = h; gap > 0; gap = (gap-1)/3 ){
        for (int i = gap; i < arr.length; i++){
            int j = i;
            while (j >= gap && arr[j] < arr[j-gap]){
                swap(arr,j,j-gap);
                j -= gap;
            }
        }
    }
}

private static void swap(int[] arr, int i, int j){
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

5、归并排序(MergeSort)

思想:递归合并两个小的有序数组,先将原数组分成两个小数组,对这两个小数组分别排序使其有序,之后合并这两个小数组,整体来说就是一直拆分源数组为两个数组,给左侧数组排序,给右侧数组排序,合并左右数组。适用于对象排序。

代码:

//数组,左边界下标,右边界下标 (arr,0,arr.length-1)
private static void sort(int[] arr,int left,int right){     
    if (left == right){
        return;
    }
    int mid = left + (right - left) / 2;
    sort(arr,left,mid);
    sort(arr,mid+1,right);
    merge(arr,left,mid+1,right);
}

//数组,第一个数组的起始下标,第二个数组的起始下标,右边界
private static void merge(int[] arr, int left, int right, int rightBound){     
    int mid = right - 1;
    int i = left, j = right, k = 0;
    int[] temp = new int[rightBound - left + 1];
    while (i <= mid && j <= rightBound){
        temp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];
    }
    while (i <= mid){
        temp[k++] = arr[i++];
    }
    while (j <= rightBound){
        temp[k++] = arr[j++];
    }
    //排完序的结果在temp数组里,因此要替换到arr数组中
    //变量分别为,源数组,源数组的起始位置,目的数组,目的数组的起始位置,要复制的长度
    System.arraycopy(temp, 0, arr, left, temp.length);
}

6、快速排序(QuickSort)

Java中Arrays.sort()用的是更强大的双轴快排!

思想:常见的实现方式就是首先挑选一个基准点,也称为轴,在轴的左侧找比轴大的,在轴的右侧找比轴小的,找到后进行交换,之后在轴的左侧部分和右侧部分继续执行相同操作。

代码:

//数组,左边界下标,右边界下标 sort(arr,0,arr.length-1)
private static void sort(int[] arr,int left,int right){     
    if (left >= right){
        return;
    }
    int mid = partition(arr, left, right);
    sort(arr,left,mid-1);
    sort(arr,mid+1,right);
}

//每次以最右侧的数为轴
private static int partition(int[] arr,int leftBound,int rightBound){
    int left = leftBound,right = rightBound - 1,pivot = arr[rightBound];
    while (left <= right){
        while (left <= right && arr[left] <= pivot){
            left++;
        }
        while (left <= right && arr[right] > pivot){
            right--;
        }
        if (left < right){
            swap(arr,left,right);
        }
    }
    swap(arr,left,rightBound);
    return left;
}

private static void swap(int[] arr, int i, int j){
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}

7、计数排序(CountSort)

思想:首先设置一个包含所有范围数据的数组count,count[i]代表i这个数据出现了多少次,最后从起始位置遍历时count[i]等于几,就在数组中追加几个i。计数排序是一种特殊的桶排序,适用于量大但是范围小的数据排序,比如高考成绩排名。

代码:

private static void sort(int[] arr){
    int k = 0;
    if (arr == null || arr.length < 2) {
        return ;
    }
    int[] count = new int[101];
    for (int i = 0; i < arr.length; i++) {
        count[arr[i]]++;
    }
    for (int i = 0; i < count.length; i++) {
        while (count[i]-- > 0){
            arr[k++] = i;
        }
    }
}

8、基数排序(BaseSort)

思想:从个位开始,循环其中最大的数的位次,每次根据位上的数进行排序。基数排序是一种特殊的桶排序,其中第二次更新count的值后count[m]代表余数<=m的数有多少个。

代码:

public static void sort(int[] arr){
    if (arr == null || arr.length < 2) {
        return;
    }
    int[] result = new int[arr.length];
    int[] count = new int[10];
    int max = Arrays.stream(arr).max().getAsInt();
    int flag = String.valueOf(max).length();
    for (int i = 0; i < flag; i++) {
        int division = (int)Math.pow(10,i);
        for (int j = 0; j < arr.length; j++) {
            count[ arr[j] / division % 10]++;
        }
        for (int m = 1; m < count.length; m++){
            count[m] = count[m] + count[m-1];
        }
        for (int n = arr.length-1; n >= 0; n--){
            result[--count[arr[n] / division % 10]] = arr[n];
        }
        System.arraycopy(result,0,arr,0,arr.length);
        Arrays.fill(count,0);
    }
}

9、桶排序(BucketSort)

思想:找到这个数组中的最小值和最大值,在最小值和最大值间建立多个桶,把数据放在对应桶中,对每个桶中的数据进行排序,排序完成后按照桶的范围大小进行顺序合并。实际生产中并不常用,原因是时间和空间不可兼得。

代码:

public static void sort(int[] arr){
    List[] buckets = new ArrayList[10];
    for (int i = 0; i < buckets.length; i++) {
        buckets[i] = new ArrayList<Integer>();
    }
    for (int i = 0; i < arr.length; i++) {
        buckets[arr[i]/10].add(arr[i]);
    }
    for (int i = 0; i < buckets.length; i++) {
        buckets[i].sort(null);
    }
    int k = 0;
    for (int i = 0; i < buckets.length; i++) {
        if (buckets[i].size() > 0){
            for (int j = 0; j < buckets[i].size(); j++) {
                arr[k++] = (int)buckets[i].get(j);
            }
        }
    }
}

10、堆排序(HeapSort)

思想:堆是一个数据结构,堆里面有两个特殊形式,分别是大顶堆和小顶堆,大顶堆的首元素是数组中最大的,就可以利用这个特性,将数组首先形成一个大顶堆,接着交换起始位置和终止位置的值,这样终止位置就是数组中最大的值了。然后把起始位置到终止位置-1的元素再次形成一个大顶堆,重复执行上述操作,最终排序完成。

代码:

private static void sort(int[] arr){
    for(int i = arr.length/2 - 1; i >= 0; i--){
        adjustHeap(arr,i,arr.length);
    }
    for(int j = arr.length - 1; j > 0; j--){
        swap(arr,0,j);
        adjustHeap(arr,0,j);
    }
}

//实际上就是对于每一个节点,比较其与其子节点中最大的那个数,并将最大的那个数交换到节点位置
private static void adjustHeap(int[] arr,int i,int length){
    int temp = arr[i];
    for(int k = i*2+1; k < length; k = k*2+1){
        if( k+1 < length && arr[k] < arr[k+1] ){
            k++;
        }
        if( arr[k] > temp ){
            arr[i] = arr[k];
            i = k;
        }else{
            break;
        }
    }
    arr[i] = temp;
}

private static void swap(int[] arr, int i, int j){
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值