张仰彪选择排序法, 请大家评判一下

zhangyangbiao513211 2008-01-23 02:06:11

张仰彪选择排序法

本排序法是在选择排序法的基础上发展而来的。
选择排序法是寻找当前排序位置后边最小的一个数据,然后将此最小数据与当前排序位置上的数据进行交换,经过不断重复上述步骤,数组排序完毕。
本排序法的原理与选择排序法基本相同,但本排序法在排序时不仅寻找当前排序位置后边最小的一个数据,而且将当前排序位置后边次小的数据也顺便找出,然后将最小数据和次小数据交换到当前位置和当前位置后边第一个位置上。
这样,本排序法一次排序循环就可以排好两个数据,排序的循环次数比选择排序法少了一半,但这并不意味着本排序法的整个排序过程就可以大幅节省数据比较和交换的总次数。因为很容易知道数据交换次数在这种情况下是不应该变的,而数据比较的次数也只有在较少的情况下本排序法才会比选择排序法少。
比如,在当前排序位置后边查到一个最小数据a[x]后,如果接下来遇到的数据a[x+1]比此最小数据a[x]还小,那么就可以直接把刚才的最小数据a[x]视为次小数据而记下它的位置下标,在这种情况下就省掉了一次数据比较。只不过随着最小数据越来越小以及越查越接近数组尾部,继续遇到更小数据的可能也越来越小。
很多情况下,在当前排序位置后边查到一个最小数据a[x]后,接下来遇到的数据a[x+1]比此最小数据a[x]要大,所以它不可能成为新的最小数据,但它却可能比当前排序位置上的数据要小,从而成为新的次小数据,这就比须进行比较才能确定。依此类推,在类似这样的情况下,虽然本排序法与选择排序法相比其排序步骤少了1/2,但本排序法的每一个排序步骤内的数据交换次数都是双倍的,而数据比较次数则达不到双倍,合计起来总数有一定幅度的减少。
至于本排序法的数据比较次数究竟比选择排序法减少了多少,这涉及一个几率问题,在最好的情况下可以减少25%,在最坏的情况下可以减少0 %,正常情况下可以减少12.5 %。
例如:处理完全反序的待排序数组,当前几次排序时,由于总是可以在数组的尾部查到一个最小数据来与数组头部的大数据进行交换,所以此时由于每次循环都可以将两个小数据排好序,所以此时的数据比较次数比选择排序法少50 %。但随着当前排序位置逐渐后移,当查到最后一个最小数据时,它的后面总有多个比它大的数据,必须再将这些数据与次小数据进行比较,看它们是否小于次小数据,这就又增加了比较次数,合计起来本排序法的数据比较次数比选择排序法减少了12.5 %。
所以总的来说,本选择排序法是有一定的进步意义的。

下面给出双选择排序法的C语言代码:
-------------------------------------------------------------------------------------------------------
# include < stdio.h >
void main ( )
{
int a [10];
int i,x; /* 记录排序的次数和当前排序的位置 */
int min1, min2 ,min3; /* 记录查到的最小、次小等数据的位置 */
int temp; /* 数据交换时的存储中介 */

printf ( " Input 10 numbers:\n" );
for ( i=0;i < 10;i++ ) /* 输入任意10个整数 */
scanf ( " %d",&a[i] );
printf ( " \n" );

for ( i=0;i < =8;i +=2 ) /* 排序时一个循环向前跨两步 */
{
min1=i; min2=i+1; /* 若查不到更小的数据,最小数据就在当前位置,
将次小的初值设为i+1,是为了处理最小就是当前的特殊情况*/
for ( int x = i+1;x < =9;x ++ ) /* 查找当前位置(含)后面两个小数据 */
{
if ( a[x] < a[min1] )
{
min2=min1; /* 先将原先最小数据的下标存到min2里 */
min1=x; /* 再将新查到的最小数据的位置存到min1里 */
}
} /* 获得当前位置后边的最小和次小数据的位置*/

for(x=min1+2; x<9; x++) /* 在最小数后面的找出一个最小的*/
{ /* 因为最小数后面的数虽然都比最小大,但却可能小于次小0*/
min3=min1+1;
if(a[x]<a[min3]) min3=x;
} /*即使当前就是最小,仍可用此for( )循环找到一个次小*/
if(a[ min3] <= a[min2]) min2=min3; /* 这才是真正的次小*/
/* 之所以用<=,是尽可能把次小的位置向后定*/
if(min2!=i) /* 次小不在当前位置,先交换最小不会错移次小*/
{
temp=a[min1]; /*先交换最小到当前位置*/
a[min1]=a[i];
a[i]=temp;

temp=a[min2]; /*然后再交换次小到当前之后*/
a[min2]=a[i+1];
a[i+1]=temp;
}
else /*min2=i, 次小在当前位置上,此时先交换最小会错移次小*/
{
if(min1=i+1) /*次小在当前位置,后边第一个就是最小*/
{
temp=a[min2]; /*将次小和最小互换位置即可*/
a[min2]=a[min1];
a[min1]=temp;
}
else /*次小在当前位置,后边相隔一个以上才是最小*/
{
temp=a[min2]; /*先交换次小到当前之后*/
a[min2]=a[i+1];
a[i+1]=temp;

temp=a[min1]; /*然后再交换最小到当前位置*/
a[min1]=a[i];
a[i]=temp;
}
}
}

printf ( " The sorted numbers is:\n" );
for ( i=0;i < 10;i ++ ) /* 输出排好序的10个整数 */
printf ( " %d",a[i] );
printf ( " \n" );
}
----------------------------------------------------------------------------------------------------


< 完 >






...全文
995 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
yui 2010-11-05
  • 打赏
  • 举报
回复
楼主纯粹是来给大家增添乐趣的,大家百度一下就知道了
beargo 2010-11-05
  • 打赏
  • 举报
回复
太闲了..搜了一下..原来楼主05年前就拿这个出来娱乐了...三年后的08年还是"执着"!不知道楼主再过两年后的今天整出啥名堂了!待解!!
longwin798 2010-11-05
  • 打赏
  • 举报
回复
11楼的分析非常有道理,搞算法,复杂度是一个非常重要的概念,在考虑复杂度时,我们通常是常数C都不用考虑的。。。我也刚开始学算法,还有很多不懂的地方需要学习,不过楼主分析问题并解决问题的精神值得赞扬!!多动手,多动脑,学得最快
nix_fire 2010-11-04
  • 打赏
  • 举报
回复
算法错误
j8daxue 2009-07-10
  • 打赏
  • 举报
回复
LZ继续下去,
把这段时间忍过,
一旦得到社会和IT各界人士的认可,
绝对是名胜大震,
而且能为中国在排序算法上划上一笔,
以后各个学校的计算机系上数据结构都会学习你的算法,
肯定被国家信息产业部门拿去做教授了,
光是想想就觉得多么光明的未来.

如果能被国外认可,
说不定哈佛就叫你去做名誉教授了.

帮LZ想个好名字ZYB排序,类似SHELL排序.以后千万不能忘记我啊.
cheng_fengming 2009-07-09
  • 打赏
  • 举报
回复
不管怎么说 有这样钻研的思想和意识是值得赞扬和学习的!
neohope 2009-07-09
  • 打赏
  • 举报
回复
呵呵,你挺有干劲的吗
1.要想得到别人的认可,那你的算法是要经得住考验的,你的算法在任何情况下都能正常工作吗?你自己做过大量测试吗?你的算法时间复杂度及空间复杂度如何?在什么情况下适用,什么情况下不适用?你的算法易于理解吗,有教学或实践意义吗?要是上面任何一条没有的话,别人不会认可你的

2.研究算法是好的,但要耐得住寂寞,看起来你接触的排序算法并不多,还处于教学时选用的那些易于理解的方法,要想成功就要多学一些深入的东西,实用的东西,然后通过总结经验,才能生化出属于你的东西

3.你要是自己觉得不错,可以找个老师商量一下,将1里面的工作做完,至少可以出篇论文吧

jlp999 2009-07-09
  • 打赏
  • 举报
回复
佩服楼主
knowledge_Is_Life 2008-04-30
  • 打赏
  • 举报
回复
不会,帮顶
stroustrupfans 2008-01-28
  • 打赏
  • 举报
回复
楼上想错了,这两个常数是同一个,可以约去,楼上的楼上是对的
stroustrupfans 2008-01-27
  • 打赏
  • 举报
回复
有个细节,两个常数不一样

10000 * log2 10000 * 常数C1 = 1秒,
一亿 * log2 一亿 * 常数C2 = 多少?这两个等式左右分别相除

左边是(一亿 * log2 一亿 * 常数C1 )/(10000 * log2 10000 * 常数C2)

C1/C2 = C3,结果带有常数,例如这个常数是2,或者1/2,对运算结果有乘以这个常数系数的影响。


stroustrupfans 2008-01-27
  • 打赏
  • 举报
回复
楼主是初学者吧?你为什么老在选择排序上动脑子,而不去学习快速排序,堆排序之类的?

我觉得你缺乏计算复杂度的概念,你可能听说过,但并不理解,所以对你的算法究竟有多大价值,
比如和经典的选择排序比较起来,你的改进意味着什么?和快速排序比起来是个什么价值,缺乏正确认识。

选择排序复杂度是C1*N*N,C1是个常数系数,N是排序数据个数,快速排序是C2*N*logN,
光看公式无法获得深刻认识,给你算一下,

例如在一台早期的电脑上,一万个数用选择排序,耗时1秒,因为选择排序的复杂度是N的平方,
N=10000, N的平方10000*10000,乘以一个常数系数C,10000*10000*C,等于一秒,

那么现在有一亿个数据,N=一亿,平方,乘以同样的常数系数C,100000000 * 100000000 * C 等于几秒?

两个等式左右分别相除,右边就是秒数,左边(100000000 * 100000000 * C)/ (10000 * 10000 * C)

约去常数C,交换乘除顺序,
(1000000000 / 10000) * (100000000 / 10000) = 10000 * 10000 = 1亿

耗时一亿秒,就是27777小时,就是1157.407天,就是3.109年!这几乎不能用选择排序了,
而10亿个数据,就要用310.9年,更不可能计算了。

就算楼主你的算法仍然是选择排序,复杂度还是C*N*N,只是常数C小了,
即使提高了2倍的速度,一亿个数也需要1.585年,10亿个数需要155.45年
还是几乎不能用,只是常数系数C的改变,没有根本提高。

看看用快速排序,复杂度是C*log2N,在另一台更慢的机器上,一万个数,用快速排序,也耗时一秒,
那么一亿个数,耗时多少?

10000 * log2 10000 * 常数C = 1秒,
一亿 * log2 一亿 * 常数C = 多少?这两个等式左右分别相除

左边是(一亿 * log2 一亿 * 常数C )/(10000 * log2 10000 * 常数C) 约去常数,

=(一亿 * log2 一亿 )/(10000 * log2 10000 ) = (一亿 / 1万) * (log2 一亿 / log2 一万)

用对数换底公式

= 一万 * (ln 一亿 / ln 一万) = 一万 * 2 = 2万秒,就是5.556小时,5个多小时,完全可以。

如果N是10亿,我算了一下,快速排序用62.5小时,还是可以耐心等,而选择排序需要300多年,
就算你的算法提高选择排序一倍速度(这么显著的改进实际上不可能做到),也需要150年,还是不能用。

你看,对一万个数据,选择排序和快速排序都可以,相差不多,假设选择排序用一秒,对一亿个数据,
选择排序就从一秒猛增到3年多,因为它的复杂度是N*N,平方关系,N扩大了一万倍,运算次数就增大一亿倍,
如果N扩大10万倍,运算次数就增大100亿倍,也就是说10亿个数据,需要300多年,
根本不可能计算了,谁能等那么长时间?

快速排序,如果一万个数据用一秒,一亿个数据用5个多小时,因为它的复杂度是N*log2N,
log2N在N比较大的时候,比N小多了,

不知道楼主是否获得一些对选择排序的性能和快速排序的性能巨大差别的直观认识?
这是因为他们复杂度一个是N*N,一个是N*log2N,在N比较小的时候,N和log2N差别不是很大,
N越大,差别越巨大。N*N这种复杂度的算法,在N不太大的情况下可以用,N太大了就不能用了。

而楼主你改进的这几个算法,还是冒泡,选择,计数,只是改进了常数C,打个比方说,比如原来是N*N*0.5,
你改进为N*N*0.4,这对于N比较大的情况,例如对于10亿个数,300年,还是240年,都是不可能等待的,
楼主的改进就没有多少价值了。对于N比较小的情况,效果确实明显,比如原来用1秒,现在用0.8秒,
但对有些用户来说0.2秒可能觉得无所谓。

楼主是否对选择排序的性能和快速排序的性能差别有了直观认识?对你的所做改进的价值有了正确认识?

举这个例子并不是说对算法的常数系数的改进没有价值,有些场合下,很关键很有价值,具体例子不举了。

楼主是个初学者吧?热情可嘉,独立思考的精神可嘉,但我建议你学学堆排序,快速排序,
其中的思想对你很有启发,用到的编程技巧比如递归对你学编程也很有促进,把一本算法书学完,
不要老在一个算法上打转,这样进度太慢了,你可以学完一本书后回过头来再思考。
学而不思则罔,思而不学则殆!

本人学识有限,抛砖引玉











  • 打赏
  • 举报
回复
选择排序法在排序时,当找到当前排序位置后边最小的数据时,在此之前找到的那个最小数据很可能就是次小数据,
如果将它与最小数据一起排好序,就会减少很多数据比较次数,有何不可?
z_wenqian 2008-01-25
  • 打赏
  • 举报
回复
觉得好就自己用吧。

不要一直发这种帖。

大家对你的方法已经有了定论。

效率不高又什么意思。

还是自己捂住,偷着乐吧。
FALLEAFCSHARP 2008-01-25
  • 打赏
  • 举报
回复
减少的似乎不是比较次数吧,拿几个数据数数.

已经给你分析过了.兄弟仍需努力啊.
FALLEAFCSHARP 2008-01-25
  • 打赏
  • 举报
回复
减少的似乎不是比较时间吧,拿几个数据数数.

已经给你分析过了.兄弟仍需努力啊.
FALLEAFCSHARP 2008-01-24
  • 打赏
  • 举报
回复
革命要彻底,不要改良.你的算法我看了,只能算改良,不能在根本上改变算法的面貌.

如果找一个极端情况,不如做一个循环链表,把后边所有的数据的次序都搞定...

问题是这样只能增加代码的复杂性不能从根本上提高算法的效率.

反证:
1. 那么你又是用什么算法把后边的数据排序的呢???
2. 这个算法是不是比你说的选择排序法快呢???
3. 如果这个算法比选择排序法快,你为什么要用选择排序法而不用这个???
结论:
1. 如果你后边也用选择排序,那么算法不会变快.
2. 如果你后边用更快的方法,那么这个算法就扔掉吧.
3. 从你的代码来看,你是在用效率更低的方法.

记住,一种新理论需要建议在反复认证和实验的基础上,要能经受的住考验.
ivan_fhf 2008-01-24
  • 打赏
  • 举报
回复
int i,x; /* 记录排序的次数和当前排序的位置 */
for ( int x = i+1;x < =9;x ++ ) /* 查找当前位置(含)后面两个小数据 */
这样的定义变量会引起二义性,LZ的想法值得可嘉!
wjdlt_1997 2008-01-23
  • 打赏
  • 举报
回复
代码的错误太多……
  • 打赏
  • 举报
回复
不好意思,应该是: if(min1==i+1)
谢谢楼上这位朋友.
加载更多回复(2)

33,028

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧