`

算法初探 之 排序算法

阅读更多

摘《李开复:算法的力量》 : 算法是计算机科学领域最重要的基石之一,但却受到了国内一些程序员的冷落。许多学生看到一些公司在招聘时要求的编程语言五花八门就产生了一种误解,认为学计算机就是学各种编程语言,或者认为,学习最新的语言、技术、标准就是最好的铺路方法。其实大家都被这些公司误导了。编程语言虽然该学,但是学习计算机算 法和理论更重要,因为计算机算法和理论更重要,因为计算机语言和开发平台日新月异,但万变不离其宗的是那些算法和理论,例如数据结构、算法、编译原理、计算机体系结构、关系型数据库原理等等

许多计算机科学家认为,排序算法是算法学习中最基本的问题。那么我们就从排序这类算法开始,去看看算法究竟是什么。

排序算法解决的是一类什么具体问题呢?

输入 :n 个数的序列 <a1,a2,a3,...,an>

输出 : 输入序列的一个重排 <a'1,a'2,a'3,...,a'n>, 使得 a'1<=a'2<=a'3<=...<=a'n

输入序列通常是一个 n 元数组,但也可能由其他形式来表示,如链表。

对于这个问题,我们可以很容易联想到日常生活中的许多例子。那么我们解决这个问题的第一个思路便可以从日常生活中获得。

插入排序,这是一个对少量元素进行排序的有效算法。其工作机理和很多人打牌时,整理手中牌时的做法差不多。在开始摸牌时,我们的左手是空的,牌面朝下的放在桌上。接着,一次从桌上摸起一张牌,并将它插入到左手一把牌中的正确位置上。为了找到这张牌合适的位置,要将它与手中已有的每一张牌从右向左地进行比较。无论在什么时候,左手中的牌都是排好序的,而这些牌原先都是桌上那副牌里最顶上的一些牌。

// 主方法

INSERTION-SORT(A)

    // 从桌面上一次次取牌

     for j ← 2 to length[A]

    do

                    // 取一张牌到右手 key

                       key ← A[j]

                                // 眼睛注意的位置(将要比较的位置)

                                i ← j – 1

                                // 开始寻找合适的位置

                                while i > 0 and A[i] > key

                                do

                                        // 微调左手中的已经排好顺序的牌

          A[i + 1] ← A[i]

          // 移动眼睛,转换比较的对象

                                        i ← i – 1

                                        // 将右手中的牌放在左手牌中合适的位置上

                                 A[i + 1] ← key

 

大概的思路已经在脑子中形成了,剩下的是简单的工作:将思路转化为实实在在的代码。在这里我用 java 编写了一个静态方法。关于这个算法的具体证明过程详见《 Introduction to Algorithms .

  /** */ /**

*InsertionSort

*The time limit of this sort is O(n^2)

*<strong>O(n^2)</strong>

*
@param  element will be sorted

*在这段代码中使用了java的范型以及一个对象接口,详细情况可以参见java相关教材

*/


public   static   < Type  extends  Comparable >   void  insertionSort(Type element[]) ... {

for ( int  j = 1 ;j < element.length;j ++ ) ... {

Type key 
=  element[j];

int  i  =  j - 1 ;

while ( (i >= 0 ) && (element[i].compareTo(key) > 0 )) ... {

element[i
+ 1 =  element[i];

i
-- ;

}


element[i
+ 1 =  key;

}


}

 

如同大家打牌一样,很多人熟能生巧整理手中的牌时又准又快,而有些人却费时费力。那么一个算法也是友好有坏,在这里我只给出相关的评价指数,至于具体规定可参见相关书籍。

这个算法的时间复杂度为 O(n^2) ,空间复杂度为 O(n). 关于“ O” 符号可以在微积分类书籍上找到更为详尽的解释。

科学技术不断进步,很多新的算法应运而生。在这里再介绍一种排序算法。它在时间复杂度上有了具大提高,空间上却付出了两倍的代价。

合并排序,一种利用了“分治策略”的排序方法。分治策略:将原问题划分成 n 个规模较小而结构简单与原问题相似的子问题;递归地解决这些子问题,然后再合并其结果,就得到原问题的解。排序算法就是借助了这种思想,本质是:从中间把数组分成元素个数尽量相等的两半,分别对他们进行排序,然后再合并两个有序表。整个问题最困难的地方便是合并两个有序表,在这里我们着重看看这个过程。

再举打牌这个例子 , 假设有两堆牌正 面朝上地放在桌上,每一堆都是已经排好顺序的,最小的牌在最上面。我们希望把这两堆牌合并成一个排好序的输出堆,面朝下地放在桌上。基本步骤包括在面朝上的两堆牌中,选取顶上两张牌中较小的一张,将其取出后面朝下地放入输出堆中。重复这个步骤,直到某一堆为空为止。

     /** */ /**

     *Merge used in the mergeSort

     *<strong>O(n)</strong>

     *
@param  element Type[] the elements to be merged

     *
@param  p int the begin of the  first elements

     *
@param  q int the end of the first elements

     *
@param  r int the end of the second elements

     
*/


    
private   static   < Type  extends  Comparable >   void  merge(Type element[], int  p, int  q, int  r) ... {

           
// 确定两堆牌的起始位置
         int  nl     =     q - p + 1 ;

        
int  nr     =     r - q;

        

           
// 新建两个输入堆用于存放待组合牌
        Type[] lElement,rElement;

        lElement    
=     (Type[])java.lang.reflect.Array.newInstance(element.getClass().getComponentType(),nl);

        rElement    
=     (Type[])java.lang.reflect.Array.newInstance(element.getClass().getComponentType(),nr);

                

           
// 做记录处理
         for ( int  i = 0 ;i < nl;i ++ ) ... {

            lElement[i]    
=     element[p + i];

        }


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

            rElement[i]    
=     element[q + i + 1 ];

        }


        

           
// 开始取牌
         int  i = 0 ,j = 0 ;

        
int  k     =     p;

           
// 逐个比较,一直到一个堆为空
         while ((i < nl) && (j < nr)) ... {

            
if (lElement[i].compareTo(rElement[j]) <= 0 ) ... {

                element[k]    
=     lElement[i];

                i
++ ;

            }
else ... {

                element[k]    
=     rElement[j];

                j
++ ;

            }


            k
++ ;

        }


        

           
// 处理某一堆中 剩下的牌
         while (i < nl) ... {

            element[k]    
=     lElement[i];

            i
++ ;

            k
++ ;

        }


        
while (j < nr) ... {

            element[k]    
=     rElement[j];

            j
++ ;

            k
++ ;

        }


    }

 

这个算法的时间复杂度为 O(n log2 n), 空间复杂度为 O(2n) O(n).

至此两个算法的介绍结束,我们将这类算法扩大化,从中取出根本的东西。

数据信息中的逆序对

 

分享到:
评论

相关推荐

    十三个常用算法

    一、A*搜索算法 一(续)、A*,Dijkstra,BFS 算法性能比较及A*算法的应用 二、Dijkstra 算法初探 二(续)、彻底理解Dijkstra 算法...十二、快速排序算法之所有版本的c/c++实现 十三、通过浙大上机复试试题学SPFA 算法

    十五个经典算法研究与总结、目录+索引(定稿版)

    前言: 本人的原创作品经典算法研究系列,...十二(再续):快速排序算法之所有版本的c/c++实现 十三、通过浙大上机复试试题学SPFA 算法 十四、快速选择SELECT算法的深入分析与实现 十五、多项式乘法与快速傅里叶变换

    IOI国家集训队论文集1999-2019

    杨 培 -《非最优化算法初探》 张 辰 -《动态规划的特点及其应用》 张 力 -《类比思想在解题中的应用》 张一飞 -《冗繁削尽留清瘦——浅谈信息的充分利用》 ## 2001 高寒蕊 -《从圆桌问题谈数据结构的综合...

    QCon广州 2019年全球软件开发大会PPT合集(30份).zip

    信息流广告的排序算法演进 小游戏质量保证测试实践之路 物流仓储数据分发平台架构实践及挑战 万亿规模下高吞吐低时延查询系统架构设计 数字化转型提升企业核心竞争力-“云”会吞噬一切 日均百万订单下的高可用拼购...

    传智播客扫地僧视频讲义源码

    06_学员学习标准_排序及问题抛出 07_数组做函数参数退化问题剖析_传智扫地僧 08_数据类型基础提高 09_数据类型引申和思考 10_变量本质剖析和内存四区模型引出_传智扫地僧 11_c的学习重理解到位_对初学者_传智扫地僧 ...

    ASP.NET常见问题集锦.zip

    C#排序算法大全.txt C#编程规范.doc C#语言参考.doc Code.doc C#中的“装箱”与“拆箱”.txt Datagrid分页、排序、删除代码.txt DataList分页、增加、删除、修改实例.doc is as override示例.txt JA_ASP ...

    程序设计方法.[美]Matthias Felleisen(带书签文字版).pdf

    25.2 快速排序 236 第26章 设计算法 239 26.1 终止 240 26.2 结构递归和生成递归的比较 243 26.3 做出选择 243 第27章 主题的变更 246 27.1 分形 247 27.2 从文件到行,从表到表的表 251 27.3 二分查找 254...

    程序设计方法(How_To_Design_Programs)-MIT.pdf

    25.2 快速排序 244 第26章 设计算法 248 26.1 终止 249 26.2 结构递归与生成递归的比较 251 26.3 做出选择 252 第27章 主题的变更 256 27.1 分形 256 27.2 从文件到行,从表到表的表 260 27.3 二分查找 263 27.4 ...

    asp.net知识库

    分页存储过程:排序反转分页法 优化后的通用分页存储过程 sql语句 一些Select检索高级用法 SQL server 2005中新增的排序函数及应用 根据基本表结构及其数据生成 INSERT ... 的 SQL 简便的MS SQL 数据库 表内容 脚本 ...

Global site tag (gtag.js) - Google Analytics