zoukankan      html  css  js  c++  java
  • 排序算法优化思考

    近行情很不好,公司这几天的动作比较大,总的来说就是要与员工共同度过这段艰难时刻,虽然也没看到有福同享,但是有难还是得一起来担的。面对行业不景气,作为一名励志的程序猿也不能闲着,这不,为了将之前的基础知识给补上,也为了今后的进一步发展,这段时间一直在学习C的数据结构与算法,书是我浩哥推荐的,看完了近半内容,书的质量还是不错的,知识正确性至少有保证,其传授的思想也多是带着读者一步一步思考,如何改进、完善算法。这些方面我认为挺好,学了不少,也收获不小,感谢浩哥推书,行业十几年经历对我这种小萌新还是非常有借鉴作用,链接已放文末,有兴趣的道友可以拜读。

    期博文总结归纳几种排序算法,分别为选择、插入、冒泡、希尔排序。老实说,在没有学习之前虽知道有这几种排序算法,但就其差别还不是非常清楚。于是有了这篇博文,对四类排序算法的思考。世界之大、算法无尽,如果仅仅是照搬算法的代码,可能花费你的一生也不一定能阅尽所有,所以在学习算法之前必须先有一个正确的观念——算法被创造出来的目的是解决问题,问题的解决方法不只有唯一一种,我们学习的也仅仅是在一定条件下的最优解。接下来讲解的几种排序算法都是比较经典且容易理解,适用小量数据排序

    选择排序

    介绍算法之前我们聊一聊影响算法效率的相关因素,我们不得不区分时间与空间的概念,空间即算法占用的系统内存,时间即算法从开始执行到结束执行所花费的时间,这两者在算法中非常矛盾,一般的,如果想要算法执行时间短,算法就会越复杂,占用的内存空间就越多,二者不可兼得,所以在算法设计之初,就必须要提前规划牺牲其中一部分。具体来说影响时间效率的本质是算法中的内部循环,算法中的变量、指针、结构体则影响算法的占用内存,所以提高算法的效率需要从两者入手。选择排序中对从小到大排序设计思路是遍历一遍所有数据,将最小数据选出来放在首位,接着遍历一遍剩余数据,选出次小数据并放入第二位,以此类推,最后的最大数据就被放在了数组尾部。算法思路非常简单,代码量也不大,但是牺牲了执行的时间,其执行时间与N^2成正比。

    void selection(int *a,int n)        //选择排序 先选出最小的元素与前面元素交换
    {
        int i,j,temp;
        for(i = 0;i < n-1;i++)
        {
            int min = i;
            for(j = i+1;j < n;j++)
                if(a[j] < a[min])
                    min = j;
            {
                temp = a[min];
                a[min] = a[i];
                a[i] = temp; 
            }
        }
    }
    

    上面是这几天学到的一种选择排序的优化算法,其设计思路没有改变,对第二个for循环进行了优化,对比在第二个for循环中交换数据,极大提高了执行效率,将数据交换的次数减少到了一次。

    插入排序

    我们打扑克的时候,为了便于出牌,我们会将手中扑克按照从小到大或是从大到小的顺序依次排列,插入排序算法的设计思想也是如此,在数组左边依次排序,对右边出现的数据依次与其左边的数据做比较,直至确认其位置。算法实现非常直接,但是不高效,对比常用与优化之后的用例,优化方案用三种方法来对算法进行改善。(i)首先将数组中最小的元素放在第一位 (ii)在内部循环中只做一个简单赋值,而不是执行交换操作 (iii)当元素插入到正确位置就终止内循环。
    常用:

    void insertion(int *a,int n)        //两两互换 
    {
        int i,j,temp;
        for(i = 1;i < n;i++)
            for(j = i;j > 0;j--)
                if(a[j-1] > a[j])
                {
                    temp = a[j];
                    a[j] = a[j-1];
                    a[j-1] = temp;
                }
    }
    

    优化:

    void insertions(int *a,int n)        //两两互换 
    {
        int i,j,temp;
        for(i = n-1;i > 0;i--)            //将最小元素放在第一位
            if(a[i] < a[i-1])
            {
                    temp = a[i];
                    a[i] = a[i-1];
                    a[i-1] = temp;
            }
        for(i = 2;i < n;i++)
        {
            j = i;
            temp = a[i];
            while(temp < a[j-1])        //循环找出a[i]元素在左边排序中的位置
            {
                a[j] = a[j-1];
                j--;
            }
            a[j] = temp;
        }
    }
    

    冒泡排序

    泡排序非常简单,其算法思想为:遍历文件,如果邻近的两个元素大小顺序不对,就将两者交换,重复这样的操作直至所有数据排好序。可以发现冒泡算法与常规的插入算法类似,其主要差别在于冒泡算法从右往左移动,插入是从左向右移动。

    void bubble(int *a,int n)
    {
        int i,j,temp;
        for(i = 0;i < n-1;i++)
            for(j = n-1;j > i;j--)
                if(a[j-1] < a[j])   //大数往前冒泡
                {
                    temp = a[j];
                    a[j] = a[j-1];
                    a[j-1] = temp;
                }
    }
    

    一般来说,排序算法的运行时间是和算法执行的比较次数,元素移动或交换的次数成正比的。在选择排序中,平均使用${N2}/2$次的比较,N次交换,插入排序中,平均使用${N2}/4$次比较与${N2}/4$次的交换,冒泡排序中,平均使用${N2}/2$次比较,${N2}/2$次交换。可以发现上述三种算法执行时间都是与N2相关。

    希尔排序

    尔排序是插入排序的扩展,其本质还是插入排序,希尔排序改进了插入排序只能进行相邻比较的缺陷,允许一定步长间的比较与元素交换,如固定步长4,a[0]与a[4]比较交换,a[4]与a[8]可以比较交换,最终选出所有元素中以4为间隔的元素中的最值放入a[0],接着使步长为1,依次使用插入排序。研究表明就不同步长序列,其算法执行时间不同,对于步长满足3h+1规律的,其算法执行时间与N^(3/2)成正比。较上述三类排序,希尔排序算法明显改善了执行时间。

    void shellsort(int *a,int n)
    {
        int i,h;
        for(h = 0;h <= (n-1)/9;h = h*3+1);  //首次增量值
        for(;h > 0;h /= 3)
            for(i = h;i < n;i = i+h)
            {
                int j = i,item = a[i]; 
                while((item < a[j-h])&&j >= h)
                {
                    a[j] = a[j-h];
                    j -= h;
                }
                a[j] = item;
            }
    }
    

    当然,算法间的执行效率比较都是建立在N无穷大时,N越大,四类算法间的时间差距越明显

    创作不易,白嫖不好,各位的支持和认可,就是我创作的最大动力,我们下篇文章见!

    清风 | 文 【原创】

    如果本篇博客有任何错误,请批评指教,不胜感激 !
    [浩哥博客]:https://coolshell.cn/articles/4102.html

  • 相关阅读:
    JavaScrip中构造函数、prototype原型对象、实例对象三者之间的关系
    (字符缓冲流)文本排序案例
    Annotation注解的应用(打印异常信息)
    Annotation(注解)
    Java关键技术强化
    基本数据类型与引用数据类型的区别
    EKT反射
    bootstrap的概念
    Servlet强化
    java数据库连接池
  • 原文地址:https://www.cnblogs.com/wdg-blog/p/12727024.html
Copyright © 2011-2022 走看看