程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

2023-06(2)

五分钟带你了解Java基本排序算法

发布于2021-06-12 14:23     阅读(647)     评论(0)     点赞(6)     收藏(0)


冒泡排序

冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。就像煮开水中的气泡一样,不停的往上冒。

原理:

  • 比较相邻的元素。如果前一个元素比后一个元素大,就交换这两个元素的位置。
  • 对每一对相邻元素做同样的工作,从开始第一对元素到结尾的最后一对元素。最终最后位置的元素就是最大 值。

静图:

在这里插入图片描述

动图:

在这里插入图片描述

实现:

package 排序算法.冒泡排序;

/**
 * @author shu
 * @date 2021/6/7
 * @description
 */
public class Bubble {
    /*
    对数组a中的元素进行排序
    */
    public static void sort(Comparable[] a) {
        /**
         * 分析:需要排序的数据[4,5,6,3,2,1]
         * 拿数组的最后一个元素,以此与前面的数据进行比较,
         * 如果a[j]>a[j+1],表示前面的元素比后面的值大,
         * 需要交换位置, a[temp]=a[j],a[i]=a[j+1],a[j+1]=a[temp]
         * 注意:这里不能直接a[i]=a[j+1],需要一个中间变量,
         * 你可以把他理解为男女相亲,需要中间人介绍才能认识
         */
        //最外层控制冒泡的数据
        for (int i = a.length - 1; i > 0; i--) {
            //内层控制需要排序的数据
            for (int j = 0; j < i; j++) {
                if (greater(a[j], a[j + 1])) {
                    exch(a, j, j + 1);
                }
            }
        }
    }

    /*
    比较v元素是否大于w元素
    */
    private static boolean greater(Comparable v, Comparable w) {
        return v.compareTo(w) > 0;
    }

    /*
    数组元素i和j交换位置
    */
    private static void exch(Comparable[] a, int i, int j) {
        Comparable t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
}

时间复杂度分析:

  • 【6,5,4,3,2,1】最坏的情况下

元素比较的次数为: (N-1)+(N-2)+(N-3)+…+2+1=((N-1)+1)*(N-1)/2=N^2/2-N/2

元素交换的次数为: (N-1)+(N-2)+(N-3)+…+2+1=((N-1)+1)*(N-1)/2=N^2/2-N/2

总执行次数为: (N2/2-N/2)+(N2/2-N/2)=N^2-N

  • 所以按照规则时间复杂度:O(N^2)

选择排序

选择排序是一种更加简单直观的排序方法,对元素进行依次比较,在交换位置。

原理:

  • 每一次遍历的过程中,都假定第一个索引处的元素是最小值,和其他索引处的值依次进行比较,如果当前索引处 的值大于其他某个索引处的值,则假定其他某个索引出的值为最小值,最后可以找到最小值所在的索引
  • 交换第一个索引处和最小值所在的索引处的值

静图:

在这里插入图片描述

动图:
在这里插入图片描述

实现:

package 排序算法.选择排序;

/**
 * @author shu
 * @date 2021/6/9
 * @description 选择排序算法
 */
public class Selection {
        /*
         对数组a中的元素进行排序
        */
    public static void sort(Comparable[] a) {
        /**
         *          [4,6,8,7,9,2,10,1]
         * 分析:一:选择排序是初始化一个最小值,与后面的值依次进行比较,如果比初始值小,就交换值
         *      二:i <= a.length - 2:如果是最后一个值进行++,没有意义
         */

        //外层控制的使可以选择的次数
        for (int i = 0; i <= a.length - 2; i++) {
            //假定本次遍历,最小值所在的索引是i
            int minIndex = i;
            //内层控制比较
            for (int j = i + 1; j < a.length; j++) {

                if (greater(a[minIndex], a[j])) {
                //跟换最小值所在的索引
                    minIndex = j;
                }
            }
            //交换i索引处和minIndex索引处的值
            exch(a, i, minIndex);
        }
    }

    /*
    比较v元素是否大于w元素
    */
    private static boolean greater(Comparable v, Comparable w) {
        return v.compareTo(w) > 0;
    }

    /*
    数组元素i和j交换位置
    */
    private static void exch(Comparable[] a, int i, int j) {
        Comparable t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
}

时间复杂度分析:

  • 数据比较次数: (N-1)+(N-2)+(N-3)+…+2+1=((N-1)+1)*(N-1)/2=N^2/2-N/2
  • 数据交换次数: N-1
  • 时间复杂度:N2/2-N/2+(N-1)=N2/2+N/2-1,时间复杂度为O(N^2)

插入排序

插入排序(Insertion sort)是一种简单直观且稳定的排序算法。 插入排序的工作方式非常像人们排序一手扑克牌一样。开始时,我们的左手为空并且桌子上的牌面朝下。然后,我 们每次从桌子上拿走一张牌并将它插入左手中正确的位置。为了找到一张牌的正确位置,我们从右到左将它与已在 手中的每张牌进行比较。

原理:

  • 把所有的元素分为两组,已经排序的和未排序的
  • 找到未排序的组中的第一个元素,向已经排序的组中进行插入
  • 倒叙遍历已经排序的元素,依次和待插入的元素进行比较,直到找到一个元素小于等于待插入元素,那么就把待 插入元素放到这个位置,其他的元素向后移动一位

静图:

在这里插入图片描述

动图:

在这里插入图片描述

实现:

package 排序算法.插入排序;

/**
 * @author shu
 * @date 2021/6/9
 * @description 插入排序
 */
public class Insert {

    /*
    对数组a中的元素进行排序
   */
    public static void sort(Comparable[] a) {
        /**
         * 分析:插入排序:将已排序数据和未排序数据分组,
         * 已排序的最后一个元素,和未排序的第一个元素进行标记,
         * 如果已排序的最后一个元素比未排序的第一个元素大,则交换
         */
        //外层控制未排序的数据
        for (int i = 1; i < a.length; i++) {
            //内层控制倒叙已排序的数据
            for (int j = i; j >0 ; j--) {
                //如果已排序的最后一个元素比未排序的第一个元素大,则交换
                if(greater(a[j-1],a[j])){
                    exch(a,j-1,j);
                }else {
                    break;
                }
            }
        }



    }

    /*
    比较v元素是否大于w元素
    */
    private static boolean greater(Comparable v, Comparable w) {
        return v.compareTo(w) > 0;
    }

    /*
    数组元素i和j交换位置
    */
    private static void exch(Comparable[] a, int i, int j) {
        Comparable t = a[i];
        a[i] = a[j];
        a[j] = t;
    }

}

时间复杂度分析:

  • 比较的次数为: (N-1)+(N-2)+(N-3)+…+2+1=((N-1)+1)*(N-1)/2=N^2/2-N/2
  • 交换的次数为: (N-1)+(N-2)+(N-3)+…+2+1=((N-1)+1)(N-1)/2=N^2/2-N/2
  • 总执行次数为: (N2/2-N/2)+(N2/2-N/2)=N2-N,时间复杂度为**O(N2)**

希尔排序

希尔排序是插入排序的一种,又称“缩小增量排序”,是插入排序算法的一种更高效的改进版本。

原理:

  • 选定一个增长量h,按照增长量h作为数据分组的依据,对数据进行分组
  • 对分好组的每一组数据完成插入排序
  • 减小增长量,最小减为1,重复第二步操作

静图:
在这里插入图片描述

动图:

在这里插入图片描述

实现:

  • 增量确定规则
//最大增量确定规则
int h=1
while(h<5){
h=2h+1//3,7
}
//循环结束后我们就可以确定h的最大值;
h的减小规则为:
h=h/2
package 排序算法.希尔排序;

/**
 * @author shu
 * @date 2021/6/9
 * @description 希尔排序
 */
public class Shell {
    /*
   对数组a中的元素进行排序
  */
    public static void sort(Comparable[] a) {
        /**
         * 分析: 希尔排序是对插入排序的优化,缩小的比较的次数,提高了效率
         */
        //确定增长量h的最大值
        int N = a.length;
        int h=1;
        while(h<N/2){
            h=h*2+1;
        }
        while (h>=1) {
            //最外层控制需要比较的数据
            for (int i = h; i < N; i++) {
                //内存控制排序数据的初始值
                for (int j = i; j >=h ; j-=h) {
                    if (greater(a[j-h],a[j])){
                        exch(a,j,j-h);
                    }else{
                        break;
                    }
                }

            }
            h/=2;
        }


    }

    /*
    比较v元素是否大于w元素
    */
    private static boolean greater(Comparable v, Comparable w) {
        return v.compareTo(w) > 0;
    }

    /*
    数组元素i和j交换位置
    */
    private static void exch(Comparable[] a, int i, int j) {
        Comparable t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
}

归并排序

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子 序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序 表,称为二路归并。

原理:

  • 尽可能的一组数据拆分成两个元素相等的子组,并对每一个子组继续拆分,直到拆分后的每个子组的元素个数是 1为止
  • 将相邻的两个子组进行合并成一个有序的大组
  • 不断的重复步骤2,直到最终只有一个组为止

静图:
在这里插入图片描述

实现:

package 排序算法.归并排序;

/**
 * @author shu
 * @date 2021/6/9
 * @description 归并排序
 */
public class Merge {
    /**
     * 分析:归并排序是一数组的中位数将数组分组,
     * 并且先建一个临时数组,依靠三个数组的索引完成排序
     * 最后将临时数组的值赋值给原有的数组
     */

    private static Comparable[] assist;//归并所需要的辅助数组

    /*
    对数组a中的元素进行排序
    */
    public static void sort(Comparable[] a) {
        //初始化临时数组
        assist=new Comparable[a.length];
        //定义一个最小索引
        int lo=0;
        //定义一个最大索引
        int hi=a.length-1;
        //进行排序
        sort(a,lo,hi);
    }

    /*
    对数组a中从lo到hi的元素进行排序
    */
    private static void sort(Comparable[] a, int lo, int hi) {
        //判断一下,是否索引输入错误
        if(hi <= lo){
            return;
        }
        //求中位数
        int mid = lo + (hi - lo) / 2;
        //进行前一个分组
        sort(a, lo, mid);
        //进行后一个分组
        sort(a,mid+1,hi);
        //进行归并
        merge(a,lo,mid,hi);
    }

    /*
    对数组中,从lo到mid为一组,从mid+1到hi为一组,对这两组数据进行归并
    */
    private static void merge(Comparable[] a, int lo, int mid, int hi) {
        //定义三个指针
        int p1=lo;
        int p2=mid+1;
        int i=lo;
        //遍历
        while (p1<=mid && p2<=hi){
            if(less(a[p1],a[p2])){
                assist[i++]=a[p1++];
            }else{
                assist[i++]=a[p2++];
            }
        }
        //未遍历完的P1数组
        while (p1<=mid){
            assist[i++]=a[p1++];
        }
        //未遍历完的P2数组
        while (p2<=hi){
            assist[i++]=a[p2++];
        }
        //将辅助数组的数据放到原数组中
        for (int index=lo;index<=hi;index++){
            a[index]=assist[index];
        }
    }

    /*
    比较v元素是否小于w元素
    */
    private static boolean less(Comparable v, Comparable w) {
        return v.compareTo(w) < 0;
    }

    /*
    数组元素i和j交换位置
    */
    private static void exch(Comparable[] a, int i, int j) {
        Comparable t = a[i];
        a[i] = a[j];
        a[j] = t;
    }

}

快速排序

快速排序是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一 部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序 过程可以递归进行,以此达到整个数据变成有序序列。

原理:

  • 首先设定一个分界值,通过该分界值将数组分成左右两部分
  • 将大于或等于分界值的数据放到到数组右边,小于分界值的数据放到数组的左边。此时左边部分中各元素都小于 或等于分界值,而右边部分中各元素都大于或等于分界值
  • 然后,左边和右边的数据可以独立排序。对于左侧的数组数据,又可以取一个分界值,将该部分数据分成左右两 部分,同样在左边放置较小值,右边放置较大值。右侧的数组数据也可以做类似处理
  • 重复上述过程,可以看出,这是一个递归定义。通过递归将左侧部分排好序后,再递归排好右侧部分的顺序。当 左侧和右侧两个部分的数据排完序后,整个数组的排序也就完成了

静图:

在这里插入图片描述

实现:

package 排序算法.快速排序;

/**
 * @author shu
 * @date 2021/6/10
 * @description
 */
public class Quick {
    public static void sort(Comparable[] a) {
        //最小索引
        int lo = 0;
        //最大索引
        int hi = a.length - 1;
        sort(a, lo,hi);
    }
    private static void sort(Comparable[] a, int lo, int hi) {
        //安全校验
        if(hi<=lo){
            return;
        }
        //中位数
        int partition = partition(a, lo, hi);
        //递归调用
        sort(a,lo,partition-1);
        sort(a,partition+1,hi);
    }

    public static int partition(Comparable[] a, int lo, int hi) {
        Comparable key = a[lo];//把最左边的元素当做基准值
        int left = lo;//定义一个左侧指针,初始指向最左边的元素
        int right = hi + 1;//定义一个右侧指针,初始指向左右侧的元素下一个位置
        //进行切分
        while (true) {
            //先从右往左扫描,找到一个比基准值小的元素
            while (less(key, a[--right])) {//循环停止,证明找到了一个比基准值小的元素
                if (right == lo) {
                    break;//已经扫描到最左边了,无需继续扫描
                }
            }
            //再从左往右扫描,找一个比基准值大的元素
            while (less(a[++left], key)) {//循环停止,证明找到了一个比基准值大的元素
                if (left == hi) {
                    break;//已经扫描到了最右边了,无需继续扫描
                }
            }
            if (left >= right) {
            //扫描完了所有元素,结束循环
                break;
            } else {
            //交换left和right索引处的元素
                exch(a, left, right);
            }
        }
        exch(a,lo,right);
        return right;
    }


    /*
    数组元素i和j交换位置
    */
    private static void exch(Comparable[] a, int i, int j) {
        Comparable t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
    /*
    比较v元素是否小于w元素
    */
    private static boolean less(Comparable v, Comparable w) {
        return v.compareTo(w) < 0;
    }
}

原文链接:https://blog.csdn.net/weixin_44451022/article/details/117749652



所属网站分类: 技术文章 > 博客

作者:哦哦好吧

链接:http://www.javaheidong.com/blog/article/222239/b8158b2b35d5dcaf4b41/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

6 0
收藏该文
已收藏

评论内容:(最多支持255个字符)