插入排序、快速排序,你还记得吗?

算法往往是我们入门软件开发的一个基础,而排序,一般是算法中的基础。我一直觉得,自己的基础没有打好,自己学计算机也是半路出家,到现在还后悔上大学的时候没有疯狂的学习。闲话不说了,说说今天的主题。

我试着让我写的东西可以浅显易懂,毕竟,我一直觉得,突然间看别人写的代码总是很别扭的

问:你会写插入排序吗?

答: 我们至少曾经会的,现在很多人都已经忘记了,以下是我的代码

用的是List<int>而没有选有数组,这个不是重点,重点是,总觉得写的很乱,不信你看看下面的插入排序,是书上用数组实现的

 

我相信,如果你像我一样笨写出了第一种代码,那么看到第二种实现方式后会有一种冲动,我靠,太牛了。尤其是把最里面花括号中代码封装为那个著名的swap(int a,int b)之后。

但是,其实,光做到这一步,还远远不够,请看下面的插入排序

这段代码省去了swap()方法,因为我们从前往后遍历依次使用swap后达到的效果其实就是把后面的一个数字移到前面的某个地方然后把中间的数字全部向后退一格。我们来看看效率吧,我获取了小于200,000的190,000个不重复的随机的数数组,下图中iSort1是第二种方法,iSort3是第三种方法,(第一种list<int>方式我就不测试了)前者是接近三分三十秒,后者只有125毫秒,这个,不是差的一点两点吧

而iSort2,我是突然手痒,试用swap的另外一种实现方式arrInt[j - 1] = arrInt[j - 1] - arrInt[j];arrInt[j] = arrInt[j - 1] + arrInt[j];arrInt[j - 1] = arrInt[j] - arrInt[j - 1];终于发现原来这种非主流的方法比常规的方法慢。

不过话说回来,iSort的效率这么高,真的是意想不到。

 

问:你是怎么调用这几个方法并且方便快捷的处理和显示运行时间的?

答: 我还是和上一篇一样,用了策略模式,然后让这些排序的方法继承一个抽象类

且看代码

非常简单的抽象类

下面只是对类的一个调用,大家也可以直接跳过

 

然后在main方法中写如下代码

List<ChooseSort2> listCS2 = new List<ChooseSort2>();//以泛型的方式存储以下几种类
listCS2.Add(new ChooseSort2(new iSort1(), count));
listCS2.Add(new ChooseSort2(new iSort2(), count));
listCS2.Add(new ChooseSort2(new iSort3(), count));

int Num = 1;
Console.WriteLine("以下为循环" + Num + "次一共所需的时间");
foreach (ChooseSort2 cs2 in listCS2)
{
    cs2.ToSort(arrInt, Num);
}

就ok了

 

 

问:你还记得大明湖畔的快速排序吗?

答: 只借助大脑的情况下,我真的记得不是很清楚了,不过我最后还是写了出来

后来我发现,写出这种代码,只能用来考计算机二级,和之后的代码一比,速度,实在是太慢、太慢了,根本就不是什么快速排序我突然觉得,自己还有还有很多很多东西要去学习,甚至是最简单的排序算法

 

书中的思路是这样的,数组分成四段,第一段,第一个数字(下标为low,大小假设为t),第二段,存放小于等于t的数字,第三段,大于等于t的数字,最后一段是未知,我们集中在第三段进行排序,排序完成后将第一段的t移到中间去

紧接着,有出现了另外一种方法

数组分成四段,第一段,第一个数字(下标为low,大小假设为t),第二段,存放小于等于t的数字,最后一段是大于等于t的数字,中间一段是未知,我们集中在第三段进行排序,排序完成后将第一段的t移到中间去,简而言之,作者称为双向划分,可以避免最坏情况的出现(未排序时就已经是顺序的)

我们来看一下效果吧

因为我生成的数列是19000位的随机数列,所以这里没有测试极端情况,故而qSort2和qSort3效果差不多,但是,我的qSort1就再一次差的不是一点半点了。

最后,作者又提出了另一个思路:在quickSort方法的中的第一步判断if(l>u)return改动以下,if(u-l)<cutoff return,也就是说,作者认为快速排序花费了大量的精力对小范围进行排序,所以决定对这小范围改用其他排序,改动方法倒是很简单,

1.cutoff赋值

2.依照上面改动if语句

3.调用iSort进行排序

但是我发现,效果不是很明显,可能我们的编程环境和当时作者的环境有所区别吧。

关于cutoff的取值,我是从1开始每次乘以2的方式进行试探, for (int i = 1; i < 200000; i += i),感觉效果还真有点(和qSort3比较)

就先写到这儿吧,欢迎大家指正,有什么写的不清楚的地方也欢迎提意见,需要完整代码可以留下邮箱

 

 

问:快速排序还有啥补充的

答:这一部分本来是要写在评论里的,但是不清楚CSDN总是不允许我评论,所以我只好以编辑原文的方式补上了

快速排序我后来又试了之前的代码实现,(之前是list<int>,我改成了数组),发现运行时间只有上述方法中qSrot3的40%左右,不过在极端情况下应该没有qSort3快吧,顺便贴上代码

 

 

 

仔细比较了一下,其实快速排序的这几种都是大同小异,至于“小异”怎么讲呢,我且细说:
1.参照物的不同
    qSort1,qSort2,qSort3,都是取的第一个数字作为比较的参照物,这样的有一个缺点,一直要用第一个数字,为了方便起见这三种方法都选择了将其始终保持在第一位,直至一轮qSort方法完成后再通过一个swap()调过去,这一步调用,就显得拖沓。
2.跳出quickSort的时机不同,qSort0的代码如下
if (left < j) 
    quickSort(left, j); 
if (right > i) 
    quickSort(i, right);
而qSort1,qSort2,qSort3则是在调用quickSort后进行判断
所以说,真的是大同小易
我觉得,通过这样一番比较,对软件开发中的基本用法有了更深的了解,或者是,本人还是处于打基础阶段
3.排序变换数值顺序的方法不同
qSort1是除了最后一个数字集体向后退一,然后把最后一个数字放到最前面,这无疑不是什么好方法,当然,要比一步步冒泡好一点
而qSort2,qSort3,qSort0都是找准位置,一个swap搞定
4.貌似都有点冗余

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值