数据结构之各种排序的实现与效率分析

合集下载

数据结构-内排序

数据结构-内排序

Shell排序的性能分析
Shell排序的时间复杂度在O(nlog2n)和O(n2)间, Knuth的 统计结论是,平均比较次数和记录平均移动次数在n1.25与 1.6n1.25之间
Shell排序是一种不稳定的排序方法
最后谈一下delta的取法。 Shell最初的方案是delta=n/2, delta=delta/2,直到delta=1。Knuth的方案是delta=delta/3 +1。其它方案有:都取奇数为好;或delta互质为好等等。 而使用象1, 2, 4, 8, …或1, 3, 6, 9, …这样的增量序列就不太 合适,因为这样会使几个元素多次被分到一组中,从而造 成重复排序,产生大量无用的比较操作
另外,在无序子表中向前移动的过程中,如果没 有交换元素,则说明无序子表已有序,无须再做 排序
24
冒泡排序算法实现
1 void bubble_sort(RecType R[ ], int n) { 2 //待排序元素用一个数组R表示,数组有n个记录
3 int i, j; 4 bool swap=TRUE; //判断无序子表是否已有序的变量
内排序和外排序 按照排序过程中使用内、外存的不 同将排序方法分为内排序和外排序。若待排序记录全 部在内存中,称为内排序;若待排序记录的数量很大, 以致内存一次不能容纳全部记录,在排序过程中需要 进行内、外存交换,称为外排序。本章仅讨论内排序
内排序可分为五大类:插入排序、交换排序、选择排 序、归并排序和基数排序
直接插入排序(straight insert sort) 折半插入排序(binary insert sort) Shell排序(Shell sort)
10
10.2.1 直接插入排序举例

数据结构-数据结构内排序

数据结构-数据结构内排序

数据结构-数据结构内排序数据结构数据结构内排序在计算机科学中,数据结构内排序是一项至关重要的任务。

简单来说,排序就是将一组数据按照特定的顺序进行排列,比如从小到大或者从大到小。

为什么要进行排序呢?想象一下,如果我们有一堆杂乱无章的数据,要从中找到我们需要的信息,那可真是大海捞针。

但如果这些数据是有序的,我们就能更快更准确地找到目标。

常见的数据结构内排序方法有很多,比如冒泡排序、插入排序、选择排序、快速排序、归并排序等等。

下面咱们就来一个个看看。

先来说说冒泡排序。

这就像是水里的泡泡,小的泡泡会往上浮,大的泡泡会往下沉。

在数据中,每次比较相邻的两个元素,如果顺序不对就进行交换,一轮下来,最大的元素就“浮”到了末尾。

然后再对剩下的元素重复这个过程,直到所有元素都有序。

虽然它的原理简单,但是效率可不太高,特别是对于大规模的数据。

插入排序呢,就像是我们在整理扑克牌。

每次拿到一张新牌,就把它插入到已经排好序的牌中合适的位置。

从第二个元素开始,将它与前面已经排好序的元素逐个比较,找到合适的位置插入。

这个方法在数据量较小或者基本有序的情况下表现还不错。

选择排序则是每次从待排序的数据中选择最小(或最大)的元素,放到已排序序列的末尾。

它的优点是实现简单,但同样效率不是很高。

接下来是快速排序,这可是个厉害的角色。

它选择一个基准元素,将数据分为比基准小和比基准大的两部分,然后对这两部分分别进行排序。

快速排序的平均性能非常好,是实际应用中经常使用的排序算法之一。

最后说说归并排序。

它的思路是把数据分成两半,分别排序,然后再把排好序的两部分合并起来。

归并排序是一种稳定的排序算法,也就是说相同元素的相对顺序在排序前后不会改变。

那怎么判断一个排序算法的好坏呢?主要看三个方面:时间复杂度、空间复杂度和稳定性。

时间复杂度说的是算法执行所需要的时间与数据规模之间的关系。

比如冒泡排序的时间复杂度是 O(n²),而快速排序的平均时间复杂度是O(nlogn)。

排序的实验报告范文

排序的实验报告范文

排序的实验报告范文数据结构实验报告实验名称:实验四排序学生姓名:班级:班内序号:学号:日期:2022年12月21日实验要求题目2使用链表实现下面各种排序算法,并进行比较。

排序算法:1、插入排序2、冒泡排序3、快速排序4、简单选择排序5、其他要求:1、测试数据分成三类:正序、逆序、随机数据。

2、对于这三类数据,比较上述排序算法中关键字的比较次数和移动次数(其中关键字交换计为3次移动)。

3、对于这三类数据,比较上述排序算法中不同算法的执行时间,精确到微秒(选作)。

4、对2和3的结果进行分析,验证上述各种算法的时间复杂度。

编写测试main()函数测试线性表的正确性。

2、程序分析2.1存储结构说明:本程序排序序列的存储由链表来完成。

其存储结构如下图所示。

(1)单链表存储结构:结点地址:1000HA[2]结点地址:1000H1080H……头指针地址:1020HA[0]头指针地址:1020H10C0H……地址:1080HA[3]地址:1080HNULL……地址:10C0HA[1]地址:10C0H1000H……(2)结点结构tructNode{intdata;Node某ne某t;};示意图:intdataNode某ne某tintdataNode某ne某t2.2关键算法分析一:关键算法(一)直接插入排序voidLinkSort::InertSort()直接插入排序是插入排序中最简单的排序方法,其基本思想是:依次将待排序序列中的每一个记录插入到一个已排好的序列中,直到全部记录都排好序。

(1)算法自然语言1.将整个待排序的记录序列划分成有序区和无序区,初始时有序区为待排序记录序列中的第一个记录,无序区包括所有剩余待排序的记录;2.将无须去的第一个记录插入到有序区的合适位置中,从而使无序区减少一个记录,有序区增加一个记录;3.重复执行2,直到无序区中没有记录为止。

(2)源代码voidLinkSort::InertSort()//从第二个元素开始,寻找前面那个比它大的{Node某P=front->ne某t;//要插入的节点的前驱while(P->ne某t){Node某S=front;//用来比较的节点的前驱while(1){if(P->ne某t->data<S->ne某t->data)//P的后继比S的后继小则插入{inert(P,S);break;}S=S->ne某t;if(S==P)//若一趟比较结束,且不需要插入{P=P->ne某t;break;}}}}(3)时间和空间复杂度最好情况下,待排序序列为正序,时间复杂度为O(n)。

掌握数据结构的关键技巧

掌握数据结构的关键技巧

掌握数据结构的关键技巧数据结构是计算机科学中非常重要的基础知识,它是指数据元素之间的关系,以及对这些数据元素进行操作的方法。

掌握数据结构的关键技巧对于编程能力的提升至关重要。

下面将介绍几个帮助你掌握数据结构的关键技巧。

一、深入理解基本数据结构1. 数组(Array):数组是最基本的数据结构之一,它是一组连续的内存空间,用于存储相同类型的数据。

掌握数组的基本操作,如插入、删除、查找等,是学习数据结构的第一步。

2. 链表(Linked List):链表是由节点组成的数据结构,每个节点包含数据和指向下一个节点的指针。

理解链表的特点和操作方式,能够帮助你更好地理解指针和内存管理。

3. 栈(Stack)和队列(Queue):栈和队列是两种常用的数据结构,它们分别遵循“先进后出”和“先进先出”的原则。

掌握它们的基本操作和应用场景,有助于解决实际编程中的问题。

二、熟练掌握常见算法1. 排序算法:排序算法是数据结构中的重要内容,包括冒泡排序、快速排序、归并排序等。

熟练掌握各种排序算法的原理和实现方式,能够提高程序的效率和性能。

2. 查找算法:查找算法用于在数据集中查找特定元素,包括线性查找、二分查找等。

了解不同查找算法的特点和适用场景,能够帮助你快速定位和处理数据。

3. 图算法:图是一种复杂的数据结构,图算法包括深度优先搜索(DFS)、广度优先搜索(BFS)等。

掌握图算法可以解决网络分析、路径规划等实际问题。

三、多练习、多实践1. 刷题:通过刷LeetCode、牛客网等在线编程平台的题目,可以帮助你熟练掌握数据结构和算法的应用。

不断挑战自己,解决各种难题,提高编程能力。

2. 实际项目:将所学的数据结构和算法运用到实际项目中,通过实践来加深理解和掌握。

参与开源项目、编程比赛等活动,锻炼自己的编程技能。

四、不断学习、持续改进1. 学习资料:阅读相关的书籍、博客、论文等,了解数据结构和算法的最新发展和应用。

保持学习的热情,不断充实自己的知识库。

数据结构-第十章-内部排序

数据结构-第十章-内部排序

0
1
2
3
4
5
6
7
8
i=5
MAXINT 49 2 3
MAXINT 49 6 3 MAXINT 49 6 3 MAXINT 49 6 8
38 1
38 1 38 1 38 1
65 97 5 0
65 5 65 5 65 5 97 0 97 0 97 0
76 4
76 4 76 4 76 4
13
27
49
i=6



最坏情况下,待排记录按关键字非递增有序 排列(逆序)时,第 i 趟时第 i+1 个对象 必须与前面 i 个对象都做排序码比较, 并且 每做1次比较就要做1次数据移动。总比较 次 数 为 (n+2)(n-1)/2 次 , 总 移 动 次 数 为 (n+4)(n-1)/2。 在平均情况下的排序码比较次数和对象移 动次数约为 n2/4。因此,直接插入排序的 时间复杂度为 O(n2)。 直接插入排序是一种稳定的排序方法。
折半插入排序 (Binary Insertsort)
基本思想 既然每个要插入记录之前的纪录 已经按关键字有序排列,在查找插入位 臵时就没有必要逐个关键字比较,可以 使用折半查找来实现。由此进行的插入 排序称之为折半插入排序。
折半插入排序的算法
void BInsertSort (SqList &L){ for (i=2;i<=L.length;++i){ L.r[0]=L.r[i]; low=1;high=i-1; //查找范围由1到i-1 while(low<=high){ m=(low+high)/2; if LT(L.r[0].key,L.r[m].key) high=m-1; else low=m+1; }//while 折半查找 for (j=i-1;j>=high+1;--j) L.r[j+1]=L.r[j]; //折半查找结束后high+1位臵即为插入位臵 L.r[high+1]=L.r[0]; }//for }//BInsertSort

数据结构排序实验报告

数据结构排序实验报告

数据结构排序实验报告数据结构排序实验报告引言:数据结构是计算机科学中的重要概念之一,它涉及到数据的组织、存储和操作方式。

排序是数据结构中的基本操作之一,它可以将一组无序的数据按照特定的规则进行排列,从而方便后续的查找和处理。

本实验旨在通过对不同排序算法的实验比较,探讨它们的性能差异和适用场景。

一、实验目的本实验的主要目的是通过实际操作,深入理解不同排序算法的原理和实现方式,并通过对比它们的性能差异,选取合适的排序算法用于不同场景中。

二、实验环境和工具实验环境:Windows 10 操作系统开发工具:Visual Studio 2019编程语言:C++三、实验过程1. 实验准备在开始实验之前,我们需要先准备一组待排序的数据。

为了保证实验的公正性,我们选择了一组包含10000个随机整数的数据集。

这些数据将被用于对比各种排序算法的性能。

2. 实验步骤我们选择了常见的五种排序算法进行实验比较,分别是冒泡排序、选择排序、插入排序、快速排序和归并排序。

- 冒泡排序:该算法通过不断比较相邻元素的大小,将较大的元素逐渐“冒泡”到数组的末尾。

实现时,我们使用了双重循环来遍历整个数组,并通过交换元素的方式进行排序。

- 选择排序:该算法通过不断选择数组中的最小元素,并将其放置在已排序部分的末尾。

实现时,我们使用了双重循环来遍历整个数组,并通过交换元素的方式进行排序。

- 插入排序:该算法将数组分为已排序和未排序两部分,然后逐个将未排序部分的元素插入到已排序部分的合适位置。

实现时,我们使用了循环和条件判断来找到插入位置,并通过移动元素的方式进行排序。

- 快速排序:该算法通过选取一个基准元素,将数组分为两个子数组,并对子数组进行递归排序。

实现时,我们使用了递归和分治的思想,将数组不断划分为更小的子数组进行排序。

- 归并排序:该算法通过将数组递归地划分为更小的子数组,并将子数组进行合并排序。

实现时,我们使用了递归和分治的思想,将数组不断划分为更小的子数组进行排序,然后再将子数组合并起来。

数据结构实验排序

数据结构实验排序

数据结构实验报告排序一、实习目的熟悉几种典型的排序方法,并对各种算法的特点、使用范围和效率有进一步的了解。

二、实例排序是计算机科学中非常基本且使用频繁的运算,在计算机系统软件和应用软件中都有广泛的应用。

下面给出的是冒泡排序、快速排序的实现与比较。

/* 源程序的头文件sort.h */void getra ndat(Data ary[],i nt cou nt) /* 产生一批随机数,准备排序*/{ long int a=100001;int i;for(i=0;i<cou nt;i++){ a=(a*125)%2796203;ary[i].key=(i nt)a;}} /* getra ndat */void prdata(Data ary[],i nt count) I*输出数据的函数*/{ int i; char ch;printf( n“);for(i=0;i<count;i++) printf( “ %6c”,ary[i].key);printf( n“);printf( "\n\n 打回车键,结束显示。

“);ch=getch();} I* prdata *I[两种排序方法的比较源程序]I* sortcmp.c *I#in clude <stdio.h>#in clude <stdlib.h>#define MAX 1000 I*数组最大界限*Itypedef int ElemType; I* 关键字的类型*Itypedef struct{ ElemType key;int shu;}Data;Data ar[MAX],br[MAX];typedef struct{ int lo,hi;}Selem;typedef struct{ Selem elem[MAX];int top;}SqStack;SqStack s1;/* 函数声明*/void bubble(Data ary[],int n);void getrandat(Data ary[],int count) ; void qksort(Data ary[],int n);void hoare(Data ary[],int l,int h); void init_s(SqStack *s);void push(SqStack *s,Selem e); Selem pop(SqStack *s);void prdata(Data ary[],int count); int empty(SqStack s);/* 主函数*//* 其它属性域*//* 一个纪录的结构体类型*//* 栈的元素结构体类型*//* 一维数组子域*//* 栈顶指针子域*//* 栈的顺序结构体类型*//* 产生一批随机数,准备排序*//* 进栈一个元素*/ /* 输出数据的函数*/void main(){ int k,n,j; j; char ch;do { printf("\n\n\n");printf("\n\n 1. 产生一批随机数准备排序");printf("\n\n 2. 一般情况的起泡排序");printf("\n\n 3. 有序情况的起泡排序");printf("\n\n 4. 一般情况的快速排序");printf("\n\n 5. 有序情况的快速排序");printf("\n================== printf("\n 请输入您的选择 scanf("%d",&k); switch(k){ case 1:{ printf("the number ofdatas:"); /*scanf("%d",&n);getrandat(ar,n); for(j=0;j<n;j++)br[j]=ar[j]; prdata(ar,n); } break;case 2:{ for(j=0;j<n;j++) ar[j]=br[j];bubble(ar,n); prdata(ar,n); } break;case 3: { bubble( ar,n); prdata(ar,n);} break;=================="); (1,2,3,4,5,6)");输入数据个数 *//*产生 n 个随机数 *//* 保留复原始数据 *//* 恢复原始数据 */ /* 对 n 个数据起泡排序 *//* 排序后输出 *//* 有序情况的起泡排序 */ 恢复原始数据*//* 对 n 个数据快速排序 *//* 排序后输出 *//* 有序情况的快速排序 */case 4:{ for(j=0;j<n;j++) ar[j]=br[j]; /*qksort(ar,n); prdata(ar,n);} break;case 5:{ qksort(ar,n);prdata(ar,n);} break;case 6: exit(0);} /* switch */printf("\n --------------- ");}while(k>=1 && k<6);printf("\n 打回车键,返回。

数据结构第9章 排序

数据结构第9章 排序

R[3] 10
R[4] 60
R[5] 25
R[6] 30
R[7] 18 18 18 18
18 36 20

10 10 36
60 60 60
25 25 25
30 30 30
【算法】直接插入排序 void D_InsertSort(datatype R[ ], int n) { /*对排序表R[1]..R[n]进行直接插入排序,n是记录的 个数*/ for(i=2; i<=n; i++) if (R[i].key<R[i-1].key) {R[0]=R[i]; /*将R[i]插入R[1].. R[i-1]中, R[0]为监测哨*/ for(j=i-1; R[0].key<R[j].key; j--) R[j+1]=R[j]; /*后移记录*/ R[j+1]=R[0]; /*插入到合适位置*/ } }
空间性能:除排序表以外的内存占用情况。 时间性能:比较关键码的次数,数据移动的次数。 它们往往是排序表规模(n)的函数
6. 记录和排序表的数据结构
一般采用顺序结构存储排序表。 记录和排序表的类型定义如下: #define MAXNUM … /* MAXNUM 为足够大的数 typedef struct { keytype key; …… } datatype; datatype R[MAXNUM]; /*关键码字段*/ /*其它信息*/ /*记录类型*/ /*定义排序表的存储
第一趟排序结果,使得间隔为5的字表有序: P=3
29 7 41 30 11 39 50 76 41 13 10 0 80 78 86
子序列分别为:{29,30,50,13,78},{7,11,76,100,86}, {41,39,41,80}。第二趟排序结果: P=1
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

各种排序的实现与效率分析一、排序原理(1)直接插入排序基本原理:这是最简单的一种排序方法,它的基本操作是将一个记录插入到已排好的有序表中,从而得到一个新的、记录增1的有序表。

效率分析:该排序算法简洁,易于实现。

从空间来看,他只需要一个记录的辅助空间,即空间复杂度为O(1).从时间来看,排序的基本操作为:比较两个关键字的大小和移动记录。

当待排序列中记录按关键字非递减有序排列(即正序)时,所需进行关键字间的比较次数达最小值n-1,记录不需移动;反之,当待排序列中记录按关键字非递增有序排列(即逆序)时,总的比较次数达最大值(n+2)(n-1)/2,记录移动也达到最大值(n+4)(n-2)/2.由于待排记录是随机的,可取最大值与最小值的平均值,约为n²/4.则直接插入排序的时间复杂度为O(n²).由此可知,直接插入排序的元素个数n越小越好,源序列排序度越高越好(正序时时间复杂度可提高至O(n))。

插入排序算法对于大数组,这种算法非常慢。

但是对于小数组,它比其他算法快。

其他算法因为待的数组元素很少,反而使得效率降低。

插入排序还有一个优点就是排序稳定。

(2)折半插入排序基本原理:折半插入是在直接插入排序的基础上实现的,不同的是折半插入排序在将数据插入一个有序表时,采用效率更高的“折半查找”来确定插入位置。

效率分析:由上可知该排序所需存储空间和直接插入排序相同。

从时间上比较,折半插入排序仅减少了关键字间的比较次数,为O(nlogn)。

而记录的移动次数不变。

因此,折半查找排序的时间复杂度为O(nlogn)+O(n²)= O(n²)。

排序稳定。

(3)希尔排序基本原理:希尔排序也一种插入排序类的方法,由于直接插入排序序列越短越好,源序列的排序度越好效率越高。

Shell 根据这两点分析结果进行了改进,将待排记录序列以一定的增量间隔dk 分割成多个子序列,对每个子序列分别进行一趟直接插入排序, 然后逐步减小分组的步长dk,对于每一个步长dk 下的各个子序列进行同样方法的排序,直到步长为1 时再进行一次整体排序。

因为不管记录序列多么庞大,关键字多么混乱,在先前较大的分组步长dk下每个子序列的规模都不大,用直接插入排序效率都较高。

尽管在随后的步长dk 递减分组中子序列越来越大,但由于整个序列的有序性也越来越明显,则排序效率依然较高。

这种改进抓住了直接插入排序的两点本质,大大提高了它的时间效率。

效率分析:希尔排序有以下几个关键特性:(1) 希尔排序的核心是以某个增量dk 为步长跳跃分组进行插入排序,由于分组的步长dk 逐步缩小,所以也叫“缩小增量排序”插入排序。

其关键是如何选取分组的步长序列才能使得希尔方法的时间效率最高;(2) 待排序列记录的个数n 、跳跃分组步长逐步减小直到为1时所进行的扫描次数T、增量的和、记录关键字比较的次数以及记录移动的次数或各子序列中的反序数等因素都影响希尔算法的时间复杂度:其中记录关键字比较的次数是重要因素,它主要取决于分组步长序列的选择;(3) 希尔方法是一种不稳定排序算法,因为其排序过程中各趟的步长不同,在第k 遍用dk 作为步长排序之后,第k +1 遍排序时可能会遇到多个逆序存在,影响排序的稳定性。

(3)冒泡排序基本原理:冒泡排序分为若干趟进行,每一趟排序从前往后比较每两个相邻的元素的大小(因此一趟排序要比较n-1对位置相邻的数)并在每次发现前面的那个数比紧接它后的数大时交换位置;进行足够多趟直到某一趟跑完后发现这一趟没有进行任何交换操作(最坏情况下要跑n-1趟,这种情况在最小的数位于给定数列的最后面时发生)。

事实上,在第一趟冒泡结束后,最后面那个数肯定是最大的了,于是第二次只需要对前面n-1个数排序,这又将把这n-1个数中最大的数放到整个数列的倒数第二个位置。

这样下去,冒泡排序第i 趟结束后后面i个数都已经到位了,第i+1趟实际上只考虑前n-i个数(需要的比较次数比前面所说的n-1要小)。

效率分析:冒泡排序在给出的序列为正序排列时是最好的情况,这时每一次比较都不需要要进行交换操作。

因此冒泡排序最好情况下需要交换0次。

给出的序列逆序排列是最坏的情况,这时每一次比较都要进行交换操作。

一次交换操作需要3次赋值实现,因此冒泡排序最坏情况下需要赋值3n(n-1)/2次。

比较次数方面,无论数据如何,每次排序均要比较n(n-1)/2次。

(4)快速排序基本原理:快速排序是对冒泡排序的一种改进,它的基本思想是,通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

快速排序采用了分治法的思想,把大的问题分解为同类型的小问题。

一般分如下步骤:(1)选择一个中枢元素(有很多选法,我的实现里使用第一个元素为中枢的简单方法)(2)以该中枢元素为基准点,将小于中枢的元素放在中枢后集合的前部分,比它大的在集合后部分,待集合基本排序完成后(此时前部分元素小于后部分元素),把中枢元素放在合适的位置。

(3)根据中枢元素最后确定的位置,把数组分成三部分,左边的,右边的,枢纽元素自己,对左边的,右边的分别递归调用快速排序算法即可。

这里的重点与难点在于第二步,这一步的方法是以第一个元素为中枢元素,刚开始时使用低指针指向中枢元素。

当中枢元素在低指针位置时,此时我们判断高指针指向的元素是否小于中枢元素,如果大于中枢元素则高指针继续向头移动,如果小于则与中枢元素交换,此时中枢元素被移到了高指针位置;当中枢元素在高指针位置时,我们此时判断低指针指向的元素是否大于中枢元素,如果小于中枢元素则低指针继续向尾移动,如果大于则与中枢元素交换,此时中枢元素又回到了低指针位置;这时是拿高还是低指针所指向的元素与中枢比较时根据前面逻辑来处理,直到高低指针指向同一位置则完成一轮排序,然后再对中枢元素两边的序列进行同样的操作直到排序完成效率分析:快速排序的平均时间为kn ln(n),其中n为待排时间中记录的个数,k为某个常数,经验证明,在所有同数量级的此类排序方法中,快速排序的常数因子k最小。

因此,就平均时间而言,快速排序时最好的一种内部排序。

快速排序在最好的情况时是正序,比较次数和移动次数均为O(n ln(n)),最坏状况下,比较次数和移动次数均为n(n-1)/2次。

(5)简单选择排序基本原理:每一趟从待排序的数据元素中选出最小(或最大)的一个元素,顺序放在已排好序的数列的最后,直到全部待排序的数据元素排完。

选择排序不像冒泡排序算法那样先并不急于调换位置,第一轮(i=1)先从array[i]开始逐个检查,看哪个数最小就记下该数所在的位置于min中,等一轮扫描完毕,如果找到比array[i-1]更小的元素,则把array[min]和a[i-1]对调,这时array[i]到最后一个元素中最小的元素就换到了array[i-1]的位置。

如此反复进行第二轮、第三轮…直到循环至最后一元素效率分析:选择排序在第i次选择时赋值和比较都需要n-i次(在n-i+1个数中选一个出来作为当前最小值,其余n-i个数与当前最小值比较并不断更新当前最小值),然后需要一次赋值操作。

总共需要n(n-1)/2次比较。

交换次数与序列的初始排列有关。

交换在最好状况下是待排数据为正序,交换为0次。

最坏情况是每一趟都要进行交换,总的对象移动次数为3(n-1)直接选择排序是一种不稳定的排序方法。

(6)堆排序基本原理:堆实质上是满足如下性质的完全二叉树:树中任一非叶结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。

堆排序其实最主要的两个过程:第一步,创建初始堆;第二步,交换根节点与最后一个非叶子节第一步:从最后一个非叶子节点为开始向前循环每个会支节点,比较每个分支节点与他左右子节点,如果其中某个子节点比父节点大,则与父节点交换,交换后原父节点可能还小于原子节点的子节点,所以还需对原父节点进行调整,使用原父节点继续下沉,直到没有子节点或比左右子节点都大为止,调用过程可通过递归完成。

当某个非叶子节点调整完毕后,再处理下一个非叶子节点,直到根节点也调整完成,这里初始堆就创建好了,这里我们创建的是大顶堆,即大的元素向树的根浮,这样排序最后得到的结果为升序,因为最大的从树中去掉,并从数组最后往前存放。

第二步:将树中的最后一个元素与堆顶元素进行交换,并从树中去掉最后叶子节点。

交换后再按创建初始堆的算法调整根节点,如此下去直到树中只有一个节点为止。

效率分析:堆排序对n较大的文件还是有效的,对记录较少的文件效率较低。

因为堆排序其主要运行时间都耗费在建初始对和调整建新堆时进行的反复筛选上。

对深度为k的对,筛选中关键字比较次数最多为2(n-1)次,则在建含n个元素、深度为h的堆时,总进行的关键字比较次数不超过4n。

由此,堆排序在最坏的情况下,其时间复杂度为O(n ln(n))。

(7)归并排序基本原理:归并排序分两步操作:第一步将数组分解成更小的数组,直到数组只有一个元素为止,每次划分点为(len – 1)/2=mid,将数组分成[from,mid]和[mid+1,to],第二步就是将分解的数组两两合并,合并后的数组是有序的,直到合并成一个数组为止,合并过程中会用到一个临时数组,用来存储合并后的结果。

每次合并后,将数组的数据传给原数组对应的位置。

二、测试数据(2)当n = 100时的一组随机数据的测试结果:(4)当n = 500时的一组随机数据的测试结果:(5)具体有序数据的(数组元素为1~10)的测试结果:三、分析前面所述的各种方法各有优点适用场合也不同。

通常选择排序方法的是考虑的因素有如下4点:(1)待排序的记录数目n的大小(2)记录本身数据量的大小,即记录中除关键字外其他信息量的大小(3)关键字结构及其分布情况(4)堆排序的稳定性要求从以上实验结果可观察的结论如下:(1)如果待排记录的个数n较小,则可采用直接插入排序或折半插入排序(2)如果待排记录的个数n较大,应该选择时间复杂度为O(n ln(n))的排序方法,如快速排序,堆排序或归并排序。

<1>快速排序是处理大量数据的最好方法。

当待排序序列的关键字是随机分布时,快速排序的平均时间复杂度最优,但是在待排序序列基本有序时,将蜕化为冒泡排序,其时间性能将不如堆排序或归并排序。

<2>堆排序所需的辅助空间少于快速排序,并且在最坏的情况下时间复杂度不会变化。

<3>归并排序所需的时间比堆排序省,但是它所需的辅助存储空间最多(3)快速排序、堆排序、希尔排序和直接选择排序都是不稳定的排序法,直接插入排序法、冒泡排序法、归并排序法都是稳定的排序法。

相关文档
最新文档