几种常见的排序算法学习总结

目录

1.冒泡排序

2.选择排序

3.插入排序

4.希尔排序

5.快速排序

6.归并排序

7.基数排序


1.冒泡排序

 把数组上下放置,每次将最下面的数依次向上比较,较大数向上移动,第一轮过后,最大的数放在了最顶部,第二轮过后次大的数放在次顶部.. 直到数组拍好序。过程就像水中的泡泡向上走一样,所以称之为“冒泡排序”;下面为核心代码

for (int i = 0; i < arr.length; i++) {

    for (int j = 0; j < arr.length - i - 1; j++) {

        if (arr[j] >= arr[j+1]){

            int temp = arr[j];
            arr[j] = arr[j+1];
            arr[j+1] = temp;

        }
    }

}

下面给出完整代码

public class BubblingSort {

    public static void main(String[] args) {
        int[] arr = {8,6,67,5,2,3,45,2354,45};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }

    public static void sort(int[] arr){
        boolean flag = false;
        for (int i = 0; i < arr.length; i++) {

            for (int j = 0; j < arr.length - i - 1; j++) {
                if (arr[j] >= arr[j+1]){
                    flag = true;
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
            if (flag){
                flag = false;
            }else{
                System.out.println("在进行到第" + (i+1) + "次排序时 退出!因为已经排序完成!");
                break;
            }
        }

    }

}

2.选择排序

选择排序与冒泡排序有点类似,选择排序思路为:

第一次排序:

找到数组中最小的数,将这个数与数组第一个位置交换

第二次排序:

从第二个位置开始,找到数组中最小的数,将这个数与数组第2个位置交换

第三次排序:

从第三个位置开始,找到数组中最小的数,将这个数与数组中第3个位置交换

...

核心代码

for (int i = 0; i < arr.length - 1; i++) {
    int min = arr[i]; //保存最小的数
    int index = i;    //存最小数的下标
    for (int j = i + 1; j < arr.length; j++) {
        if (min > arr[j]) {
            index = j;
            min = arr[j];
        }
    }
    //交换位置
    if (index != i) {
        arr[index] = arr[i];
        arr[i] = min;
    }
}

完整代码

public class SelectingSort {
    public static void main(String[] args) {
        int[] arr = {8, 6, 67, 5, 2, 3, 45, 2354, 45};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }

    public static void sort(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) {
            int min = arr[i];
            int index = i;
            for (int j = i + 1; j < arr.length; j++) {
                if (min > arr[j]) {
                    index = j;
                    min = arr[j];
                }
            }
            //交换位置
            if (index != i) {
                arr[index] = arr[i];
                arr[i] = min;
            }
        }

    }
}

       

3.插入排序

插入排序将数组看作一个有序数组和一个无序数组,每次将无序数组的第一个数,插入到有序数组中。思路为:

将第一个数看作是有序数组,剩下的为无序数组

1.把无序数组第一个数与有序数组的数比较,然后插入到合适的位置,形成新的有序数组,和新的无序数组

2.把无序数组第一个数与有序数组的数比较,然后插入到合适的位置,形成新的有序数组,和新的无序数组

3...

核心代码

for (int i = 1; i < arr.length; i++) {
    int sor = arr[i]; //无序数组的第一个数
    int sorIndex = i -1; //有序数组的最后一个数的下标
    //寻找合适的位置
    while ( sorIndex >= 0 && sor < arr[sorIndex]){
        //当sor从后向前依次与有序数组的数相比,当sor小时,将有序数组的数向后移动一格
        //后移
        arr[sorIndex+1]=arr[sorIndex];
        sorIndex --;
    }
    //已经找到合适的位置,为sorIndex +1 ;插入进行插入
    arr[sorIndex+1] = sor;
    System.out.println( "第"+i+"次排序结果为:" +Arrays.toString(arr));
}

完整代码

public class InsertionSort {
    public static void main(String[] args) {

        int[] arr = {6,5,2,3,84,32,45};
        sort(arr);

        
    }

    public static void sort(int[] arr){

        for (int i = 1; i < arr.length; i++) {
            int sor = arr[i]; //无序数组的第一个数
            int sorIndex = i -1; //有序数组的最后一个数的下标
            //寻找合适的位置
            while ( sorIndex >= 0 && sor < arr[sorIndex]){
                //当sor从后向前依次与有序数组的数相比,当sor小时,将有序数组的数向后移动一格
                //后移
                arr[sorIndex+1]=arr[sorIndex];
                sorIndex --;
            }
            //已经找到合适的位置,为sorIndex +1 ;插入进行插入
            arr[sorIndex+1] = sor;
            System.out.println( "第"+i+"次排序结果为:" +Arrays.toString(arr));

        }

    }

}

4.希尔排序

希尔排序时希尔(Donald Shell)提出的一种算法。希尔排序也是一种插入排序,它是简单插入排序的经过改进之后的一种更高效的版本,也被称为缩小增量排序

希尔排序基本思想:

        希尔排序是把数组(记录)按下标的一定增量进行分组,对每组使用直接排序算法排序;随着增量的减小,每组包含的关键词越来越多,当增量减小到1时,整个文件恰被分成一组,算法终止;

思路:

1.将数组(记录)长度的2分之一作为增量,分为(增量)个组:对每组使用希尔排序

2.将增量的2分之一作为新的增量,分为(增量)个组,对每组使用希尔排序

3将增量的2分之一作为新的增量,分为(增量)个组,对每组使用希尔排序

4...

核心代码

for (int gap = arr.length / 2; gap > 0 ; gap /= 2){
    for (int i = gap; i < arr.length; i++) {
        // 遍历各组中所有的元素(共gap组,每组有arr.length/gap个元素),步长gap
        //这里使用移动法Sell排序
        int sorIndex = i;
        int sor = arr[i];
        //寻找合适的位置
        while(sorIndex - gap >= 0 && sor < arr[sorIndex - gap]){
            //后移
            arr[sorIndex] = arr[sorIndex - gap];
            sorIndex -= gap;
        }
        arr[sorIndex] = sor;
    }
    //System.out.println("第"+(++count)+"次希尔排序后的结果为:" + Arrays.toString(arr));
}

完整代码

public class ShellSort {
    public static void main(String[] args) {

        int[] arr = {1,5,436,7,6,78,45,9};
        
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }
    
    public static void sort(int[] arr){
        int temp = 0;
        int count = 0 ;//计数器
        for (int gap = arr.length / 2; gap > 0 ; gap /= 2){

            for (int i = gap; i < arr.length; i++) {
                // 遍历各组中所有的元素(共gap组,每组有arr.length/gap个元素),步长gap
                //这里使用移动法Sell排序
                int sorIndex = i;
                int sor = arr[i];
                //寻找合适的位置
                while(sorIndex - gap >= 0 && sor < arr[sorIndex - gap]){
                    //后移
                    arr[sorIndex] = arr[sorIndex - gap];
                    sorIndex -= gap;
                }
                arr[sorIndex] = sor;
            }
            //System.out.println("第"+(++count)+"次希尔排序后的结果为:" + Arrays.toString(arr));
        }
    }
    
}

5.快速排序

例:将记录的最后一条作为参考,把比它小的数放左边,比它大的数放右边,分成两组,每个组重复此操作

核心代码

    public static void sort(int[] arr ,int star ,int end){

        //1.以最后一位数字为基准,将数组分割为两边的数
        int base = arr[end-1];
        int baseIn = end-1;
        int temp = 0 ;//临时变量用来交换
        for (int i = end - 2 ; i >= star; i--) {
            if (arr[i] > base){
                //放右边
                //从i开始到baseIn 使用移动法,把它移动到base右边
                temp = arr[i];
                int t_1 = i;
                while ( t_1 < baseIn){
                    arr[t_1]  = arr[t_1 + 1];
                    t_1++;
                }
                arr[baseIn] = temp;
                baseIn --;
            }
        }
        if (baseIn - star > 1){//当前面还有数组要排序时
            sort(arr,star,baseIn);
        }
        if ( (end - 1 - baseIn) > 1){//当后面还有数组要排序时
            sort(arr, baseIn, end);
        }

    }

还有一种是韩老师课堂上的,以记录中位数为参考数,将左边校参考数大数与右边较小数交换

public static void quickSort(int[] arr,int left,int right){
    int l = left;//左下标
    int r = right;//右下标
    //pivot:中轴值
    int pivot = arr[ (left + right ) /2];
    int temp = 0 ;//临时变量,作为交换时使用
    //while循环的目的是让比pivot 值小的放左边
    while (l < r){
        //再pivot的左边一直找,找到大于等于pivot的值才退出
        while ( arr[l] < pivot){
            l ++;
        }
        //在pivot的右边一直找,找到小于等于pivot的值才退出
        while ( arr[r] > pivot){
            r --;
        }
        //如果 l >= r 说明pivot左右两边的值,已经按照左边全都是小于等于pivot,右边全是大于等于pivot
        if ( l >= r){
            break;
        }
        //交换
        temp = arr[l];
        arr[l] = arr[r];
        arr[r] = temp;
        //如果交换完后,发现这个arr[l] == pivot 值,就 l-- ,前移
        if (arr[l] == pivot){
            r--;
        }
        //如果交换完后,发现这个arr[r] == pivot 值,就 r++ ,后移
        if (arr[r] == pivot){
            l++;
        }
    }
    if (l==r){
        l += 1;
        r -= 1;
    }
    //向左递归
    if (left < r){
        quickSort(arr,left,r);
    }
    if (right > l){
        quickSort(arr,l,right);
    }
}

以第一个数为基准

public void QuickSort(int arr[], int start, int end)
{
    if (start >= end)
        return;
    int i = start;
    int j = end;
    // 基准数
    int baseval = arr[start];
    while (i < j)
    {
        // 从右向左找比基准数小的数
        while (i < j && arr[j] >= baseval)
        {
            j--;
        }
        if (i < j)
        {
            arr[i] = arr[j];
            i++;
        }
        // 从左向右找比基准数大的数
        while (i < j && arr[i] < baseval)
        {
            i++;
        }
        if (i < j)
        {
            arr[j] = arr[i];
            j--;
        }
    }
    // 把基准数放到i的位置
    arr[i] = baseval;
    // 递归
    QuickSort(arr, start, i - 1);
    QuickSort(arr, i + 1, end);
}

6.归并排序

归并排序是利用递归的思想实现的排序方法,该算法利用经典的分治策略(分治法将问题分解成一些小的问题然后递归求解,而治的阶段则将分的阶段得到的各个答案“缝补”在一起,即分而治之)

 完整代码

public class MergetSort {
    public static void main(String[] args) {
        int[] arr = {8,4,5,7,1,3,6,2};
        int[] temp = new int[arr.length];
        mergeSort(arr,0, arr.length-1,temp);

        System.out.println(Arrays.toString(arr));
    }

    public static  void mergeSort(int[] arr,int left, int right,int[] temp){
        if (left < right){
            int mid = (left + right) /2;
            System.out.println("left: " + left + " ;right: " + right);
            //向左递归进行分解
            mergeSort(arr, left, mid, temp);
            //向右递归进行分解
            mergeSort(arr, mid + 1, right, temp);
            merge(arr,left,mid,right,temp);
        }
    }
    /**
     * 合并数组
     * @param arr 原始数组
     * @param left 左数左下标
     * @param mid 中间位置
     * @param right 右数下标
     * @param temp  临时数组
     */
    public static void merge(int[] arr,int left,int mid, int right,int[] temp){
        int i = left; // 初始化i,左边有序序列的初始索引
        int j = mid + 1; //初始化j,右边有序序列的初始索引
        int t = 0; // 指向temp数组的当前索引

        //1.先把左右两边的数据(都是有序的)按照规则拷贝到temp数组
        while (i <= mid && j <= right){//当有一边的数据没有填充完
            if (arr[i] <= arr[j]){
                //左边跟右边的比较,发现左边的更小,把小的拷贝到temp
                temp[t] = arr[i];
                i++;
            }else {
                temp[t] = arr[j];
                j++;
            }
            t++;

        }

        //2.把有剩余数据的一边的数据一次全部填充到temp
        while (i <= mid){//左边的数组还没填充完
            temp[t] = arr[i];
            i++;
            t++;
        }
        while (j <= right){
            temp[t] = arr[j];
            j++;
            t++;
        }
        //3.将temp数据的元素拷贝到arr[]数组中
        //注意,并不是每次都拷贝所有
        t = 0 ;
        int tempLeft = left;
        while (tempLeft <= right){
            arr[tempLeft] = temp[t];
            tempLeft++;
            t++;
        }


    }


}

7.基数排序

基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。

第一步

以LSD为例,假设原来有一串数值如下所示:

73, 22, 93, 43, 55, 14, 28, 65, 39, 81

首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶子中:

0

1 81

2 22

3 73 93 43

4 14

5 55 65

6

7

8 28

9 39

第二步

接下来将这些桶子中的数值重新串接起来,成为以下的数列:

81, 22, 73, 93, 43, 14, 55, 65, 28, 39

接着再进行一次分配,这次是根据十位数来分配:

0

1 14

2 22 28

3 39

4 43

5 55

6 65

7 73

8 81

9 93

第三步

接下来将这些桶子中的数值重新串接起来,成为以下的数列:

14, 22, 28, 39, 43, 55, 65, 73, 81, 93

这时候整个数列已经排序完毕;如果排序的对象有三位数以上,则持续进行以上的动作直至最高位数为止。

完整代码

public class RadixSort {
    public static void main(String[] args) {
        int arr[] = {53,3,542,748,14,214};
        readisSort(arr);
    }

    //基数排序方法
    public static void readisSort(int[] arr){

        //第一轮(针对每个元素的个位数进行排序)
        //定义一个二位数组,表示10个通,每个桶就是一个二维数组
        //2.为了防止数组越界,我们只能将长度定为arr.length
        //3.很明显,桶排序是一个用空间换时间的排序方法
        int[][] bucket = new int[10][arr.length];

        //为了记录每个桶中实际存放的多少个数据,我们定义一个一维数组,
        //bucketElementCounts[1] 就是bucket[1]里面的存放个数
        int[] bucketElementCounts = new int[10];
        //为了知道排序的次数,我们需要得到记录的最大数
        int max = arr[0];
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] > max){
                max = arr[i];
            }
        }
        //int maxLength = (max + "").length();
        int maxLength = (int)Math.log10(max) + 1;
        int index;
        for (int i = 0; i < maxLength; i++) {

            for (int j = 0; j < arr.length; j++) {
                //取出每个元素的个位
                int digitOfElement = arr[j] / (int)Math.pow(10,i) % 10;
                bucket[digitOfElement][bucketElementCounts[digitOfElement]++] = arr[j];
            }
            //按照这个桶的顺序(一维数组的下标依次取出数据,放入原来数据)
            index = 0 ;
            for (int k = 0; k < bucket.length; k++) {
                if (bucketElementCounts[k]!=0){
                    for (int l = 0; l < bucketElementCounts[k]; l++) {
                        arr[index++] = bucket[k][l];
                    }
                }
                //将记录桶存放的数归零
                bucketElementCounts[k] = 0;
            }
            System.out.println("第"+(i+1)+"轮处理"+Arrays.toString(arr));
        }
        

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值