论坛: 编程破解 标题: 内部排序算法比较[转载] 复制本贴地址    
作者: Garu [syshunter]    版主   登录
内部排序算法比较


--------------------------------------------------------------------------------

  排序算法是数据结构学科经典的内容,其中内部排序现有的算法有很多种,究竟各有什么特点呢?本文力图设计实现常用内部排序算法并进行比较。分别为起泡排序,直接插入排序,简单选择排序,快速排序,堆排序,针对关键字的比较次数和移动次数进行测试比较.

问题分析和总体设计

ADT OrderableList{
数据对象:D={ai| ai∈IntegerSet,i=1,2,…,n,n≥0}
数据关系:R1={〈ai-1,ai〉|ai-1, ai∈D, i=1,2,…,n}
基本操作:
InitList(n)
操作结果:构造一个长度为n,元素值依次为1,2,…,n的有序表。
Randomizel(d,isInverseOrser)
操作结果:随机打乱
BubbleSort( )
操作结果:进行起泡排序
InserSort( )
操作结果:进行插入排序
SelectSort( )
操作结果:进行选择排序
QuickSort( )
操作结果:进行快速排序
HeapSort( )
操作结果:进行堆排序
ListTraverse(visit( ))
操作结果:依次对L种的每个元素调用函数visit( )
}ADT OrderableList

待排序表的元素的关键字为整数.用正序,逆序和不同乱序程度的不同数据做测试比较,
对关键字的比较次数和移动次数(关键字交换计为3次移动)进行测试比较.
要求显示提示信息,用户由键盘输入待排序表的表长(100-1000)和不同测试数据的组数(8-18).每次测试完毕,要求列表现是比较结果.
要求对结果进行分析.

详细设计
1、起泡排序
算法:核心思想是扫描数据清单,寻找出现乱序的两个相邻的项目。当找到这两个项目后,交换项目的位置然后继续扫描。重复上面的操作直到所有的项目都按顺序排好

代码:
代码:

bubblesort(struct rec r[],int n)
{
int i,j;
struct rec w;
unsigned long int compare=0,move=0;
for(i=1;i<=n-1;i++)
  for(j=n;j>=i+1;j--)
  {
    if(r[j].key<r[j-1].key)
    {
    w=r[j];
    r[j]=r[j-1];
    r[j-1]=w;
    move=move+3;
    }
    compare++;
  }
printf("\nBubbleSort compare= %ld,move= %ld\n",compare,move);
}



2、直接插入排序
算法:经过i-1遍处理后,L[1..i-1]己排好序。第i遍处理仅将L[i]插入L[1..i-1]的适当位置,使得L[1..i]又是排好序的序列。要达到这个目的,我们可以用顺序比较的方法。首先比较L[i]和L[i-1],如果L[i-1]≤ L[i],则L[1..i]已排好序,第i遍处理就结束了;否则交换L[i]与L[i-1]的位置,继续比较L[i-1]和L[i-2],直到找到某一个位置j(1≤j≤i-1),使得L[j] ≤L[j+1]时为止

代码:
代码:

insertsort(struct rec r[],int n)
{
int i,j;
unsigned long int compare=0,move=0;
for(i=2;i<=n;i++)
  {compare++;
    r[0]=r[i];
    move++;
    j=i-1;
  while(r[0].key {r[j+1]=r[j];
j--;
move++;
++compare;}
  r[j+1]=r[0];
  move++;
  }
  printf("\nInsertSort compare= %ld,move= %ld\n",compare,move);
}



3、简单选择排序
算法:首先找到数据清单中的最小的数据,然后将这个数据同第一个数据交换位置;接下来找第二小的数据,再将其同第二个数据交换位置,以此类推。

代码:
代码:

selectsort(struct rec r[],int n)
{
unsigned long int compare=0,move=0;
int i,j,k;
struct rec w;
for(i=1;i<=n-1;i++)
{      k=i;
    for(j=i+1;j<=n;j++)

    { if(r[j].key>r[k].key) {k=j; compare++; }
    w=r[i];
    r[i]=r[k];
    r[k]=w;
    move=move+3;

    }
}
printf("\nSelectSort compare= %ld,move= %ld\n",compare,move);
}



4、快速排序
算法:首先检查数据列表中的数据数,如果小于两个,则直接退出程序。如果有超过两个以上的数据,就选择一个分割点将数据分成两个部分,小于分割点的数据放在一组,其余的放在另一组,然后分别对两组数据排序。
通常分割点的数据是随机选取的。这样无论你的数据是否已被排列过,你所分割成的两个字列表的大小是差不多的。而只要两个子列表的大小差不多


代码:
代码:

q(struct rec r[],int s,int t)
{
int i=s,j=t;
if(s<t)
{
  r[0]=r[s];    ++a;  c++;
  do{
while(j>i&&r[j].key>=r[0].key)
  {j--;
    ++a; }
if(i<j)
{ r[i]=r[j];
  i++;
  c++; }
while(i<j&&r[i].key<=r[0].key)
  {i++;
    ++a; }
if(i<j)
  { r[j]=r[i];
    j--;
    c++; }
    } while(i<j);
r[i]=r[0];
c++;
q(r,s,j-1);
q(r,j+1,t);
}
}



5. 堆排序
(1) 基本思想:
堆排序是一树形选择排序,在排序过程中,将R[1..N]看成是一颗完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系来选择最小的元素。
(2) . 堆的定义: N个元素的序列K1,K2,K3,...,Kn.称为堆,当且仅当该序列满足特性:
Ki≤K2i Ki ≤K2i+1(1≤ I≤ [N/2])


代码:
代码:

sift(struct rec r[],int l,int m)
{
int i,j;
struct rec w;
i=l; j=2*i;
w=r[i];
while(j<=m)
{
  if(j<m&&r[j].key<r[j+1].key)  { j++;
  }
  if(w.key<r[j].key)
  {
  r[i]=r[j];
  i=j;
  j=2*i;
  }
  else j=m+1;
  }
  r[i]=w;
}

heapsort(struct rec r[],int n)
{
  unsigned long int compare=-1,move=-1;
  struct rec w;
  int i;
  int a;
  for(i=n/2;i>=1;i--) a=sift(r,i,n);
  compare++;
  move++;

  for(i=n;i>=2;i--)
  {
    w=r[i];
    r[i]=r[1];
    r[1]=w;
    a=sift(r,1,i-1);
    compare+=a;
    move+=a;
  }
}



小结:
1.学会使用随机函数randomize( ) 为数组赋初值要在头文件中添加#include
2.在做此程序之前基本上是在理解了各种排序过程以后完成的
3.对排序算法的总结:
(1)若n较小(如n≤50),可采用直接插入或直接选择排序。
 当记录规模较小时,直接插入排序较好;否则因为直接选择移动的记录数少于直接插人,应选直接选择排序为宜。
(2)若文件初始状态基本有序(指正序),则应选用直接插人、冒泡或随机的快速排序为宜;
(3)若n较大,则应采用时间复杂度为O(nlgn)的排序方法:快速排序、堆排序或归并排序。
 快速排序是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;
 堆排序所需的辅助空间少于快速排序,并且不会出现快速排序可能出现的最坏情况。这两种排序都是不稳定的。


[此贴被 Garu(syshunter) 在 08月11日12时49分 编辑过]

地主 发表时间: 04-08-11 12:48

回复: kert_t8 [kert_t8]   论坛用户   登录
经典,收藏

另外
引用:

快速排序是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短

但是问题是什么叫做“带排序的关键字是随机分布”
n个关键字就会有n!个排列方式,我感觉正确的计算方法应该把这n!种排列方式统统作为输入,排序一遍,然后把总时间除以n,这样的出来的时间可以算做随机分布是的平均时间吧。所以我相信应该说快速排序的平均时间最短时正确的,但是如何通过分析程序的方式得出这样的结论呢?

B1层 发表时间: 04-08-15 09:45

回复: bug_me [bug_me]   论坛用户   登录
这是用数学的方法算出它的时间复杂度的
正确的方法就是你所说的那样
因为它是随机的,所以必须求得平均时间方为有效

B2层 发表时间: 04-08-15 11:10

回复: Garu [syshunter]   版主   登录
re:b1层:
带排序的关键字是随机分布 是 待排序的关键字是随机分布。作者笔误。


B3层 发表时间: 04-08-15 12:18

回复: kert_t8 [kert_t8]   论坛用户   登录
阿弥陀佛,我还没有咬文嚼字到那个分上
我的意思是,如何通过分析程序的方法分析出他的平均时间

算法导轮和程序设计艺术两本书似乎用了不同的计量方法,不过我都还没有很明白,所以问这个问题
在kurth写的xx设计艺术里面就用到了概率统计的方法,但是算法导轮没有,这我就不明白了,晕啊!

待我再想一想

B4层 发表时间: 04-08-16 17:32

回复: Garu [syshunter]   版主   登录
http://www.ciu.net.cn/Article_Show.asp?ArticleID=576
思考你的问题也帮我把基础补了一遍,感谢。

B5层 发表时间: 04-08-16 19:14

回复: windflower [windflower]   论坛用户   登录
任何一个看过《数据结构》的,都知道。

B6层 发表时间: 04-08-16 22:35

回复: kert_t8 [kert_t8]   论坛用户   登录
好网站
思考中

B7层 发表时间: 04-08-17 16:59

回复: TecZm [teczm]   版主   登录
收藏。楼主继续

B8层 发表时间: 04-08-17 17:13

论坛: 编程破解

20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon

粤ICP备05087286号