文件从逻辑上可分为排序顺序文件、一般(即非排序)顺序文件;从物理储上可分为连续文件、链接文件。(参考 文件及查找-MarchOn)
将文件的记录按记录关键字值递增或递减顺序重新组织,得到有序的文件记录。通常指的是连续顺序文件的排序,当然链接顺序文件也可;当记录只包含关键字时即为元素的排序。
分类
分类法1:内排序、外排序:排序是否完全在内存进行。(外排序用于数据量大而无法一次全装入内存的数据文件的排序,通常用多路归并法)。
分类法2:连续顺序文件排序、链接顺序文件排序
分类法3:稳定排序、不稳定排序:关键字值一样的文件记录在排序前后相对位置保持不变的排序是稳定排序。
时间效率
排序过程的基本动作包括元素比较和元素移动
衡量:排序算法的时间效率主要用排序过程中元素间的比较次数来衡量。
几个下界:
1、基于元素交换进行排序的算法的平均时间复杂度下限为Ω(nlgn),可用决策树证明(n个元素有n!种排列,每确定两个数的大小关系进入一棵子树,故复杂度为 O( ln(n!) ) =O(nlgn))。显然,桶排序、基数排序不是基于元素交换的排序,故不适用此结论;
2、基于相邻元素交换进行排序的算法平均时间复杂度下限为Ω(n2)(此下界比上述的下界更紧),且是稳定的。基于相邻元素交换或顺序移动(顺序移动本质上就是相邻元素交换)的排序算法是稳定的,如冒泡、插入(插入排序插入时本质上也是相邻元素交换)。
该下界的证明:基于交换的排序实际上就是消除序列中的逆序偶的过程,每次相邻交换最多消除一个逆序使总逆序数减1(相邻交换不会使逆序数增加,若不是相邻交换则可能会增加),而一个序列的平均逆序数为n(n-1)/4(因为一个序列L和其反序列Lr的逆序数和为n(n-1)/2),故此时为消除逆序最少要进行O(n2)次交换,即为一个下界。当然此下界对有些算法可能不够紧。
内排序
以下n为元素个数。
1、插入排序
思路:依次将未排序序列的第一个元素插入到前面已排序序列中的应在位置,也称简单插入排序或直接插入排序。是稳定排序。分为顺序插入、折半插入,后者与前者相比减少了比较次数(寻找插入位置)但移动次数不变。
复杂度:时间平均O(n2)、最好O(n)、最坏O(n2);空间O(1)。
趟数:n-1。
比较次数(对顺序插入而言):序列递增时最少,为n-1;递减时最多,为n(n-1)/2。(这里从后往前找该元素在前面已排序序列的插入位置,若从前往后找则结论相反即递减时最少)
代码(顺序插入与折半插入):(由于当前待插入元素前的序列已经有序,因此可以通过复制来实现元素后移从而避免交换,减少操作步骤)
1 //插入排序,依次将元素插入到元素前面的已排序序列中。 n-1趟 2 void insertSort1(int k[],int n) 3 {//顺序插入 4 int i,j,tmp; 5 for(i=1;i<n;i++) 6 { 7 tmp=k[i]; 8 for(j=i-1;j>=0 && k[j]>tmp;j--)//若为≥则非稳定 9 { 10 k[j+1]=k[j]; 11 } 12 k[j+1]=tmp; 13 } 14 } 15 16 void insertSort2(int k[],int n) 17 {//折半插入,采用折半查找应插入的位置。移动元素的次数不变,但比较次数(找元素应在的位置)少了 18 int i,j,tmp; 19 int low,mid,high; 20 for(i=1;i<n;i++) 21 { 22 tmp=k[i]; 23 24 low=0,high=i-1; 25 while(low<=high) 26 { 27 mid=low+(high-low)/2; 28 if(k[mid]>tmp) high=mid-1;//若为≥则非稳定 29 else low=mid+1; 30 } 31 32 for(j=i-1;j>=low;j--) 33 { 34 k[j+1]=k[j]; 35 } 36 k[j+1]=tmp; 37 } 38 } 39 40 insertSort