9、排序
9.1排序的基本概念与分类
假设含有 n 个记录的序列为{r1,r2,…,rn}其相应的关键字分别为{k1,k2,…kn},需确定1,2,……,n的一种排列p1,P2,…pn,使其相应的关键字满足kp1<=kp2……<=kpn(非递减或非递增)关系,即使得序列成为一个按关键字有序的序列(rp1,rp2,……,Fpn},这样的操作就称为排序。
排序的稳定性
假设ki=kj(1<=i<=n,1<=j<=n,i≠j),且在排序前的序列ri领先于rj(即i<j)如果排序后ri仍领先于rj,则称所用的排序方法是稳定的;反之,若可能使得排序后的序列中rj领先ri,则称所用的排序方法是不稳定的。
内排序与外排序
内排序是在排序整个过程中,待排序的所有记录全部被放置在内存中。外排序是由于排序的记录个数太多,不能同时放置在内存,整个排序过程需要在内外存之间多次交换数据才能进行。
对于内排序来说,算法性能主要受3个方面影响
-
时间性能
排序是数据处理中经常执行的一种操作,往往属于系统的核心部分,因此排序算法的时间开销是衡量其好坏的最重要的标志。在内排序中,主要进行两种操作:比较和移动。比较指关键字之间的比较,这是要做排序最起码的操作。移动指记录从一个位置移动到另一个位置,事实上,移动可以通过改变记录的存储方式来予以避免(这个我们在讲解具体的算法时再谈)。总之,高效率的内排序算法应该是具有尽可能少的关键字比较次数和尽可能少的记录移动次数。
-
辅助空间
评价排序算法的另一个主要标准是执行算法所需要的辅助存储空间。辅助存储空间是除了存放待排序所占用的存储空间之外,执行算法所需要的其他存储空间。
-
算法的复杂性
注意这里指的是算法本身的复杂度,而不是指算法的时间复杂度。显然算法过于复杂也会影响排序的性能。
根据排序过程中借助的主要操作,我们把内排序分为插入排序,交换排序,选择排序,归并排序
排序用到的结构与函数
用于排序的顺序表结构
#define maxsize 10 //用于要排序数组个数最大值
typedef struct
{
int r[maxsize+1]; //用于存储要排序数组,r[0]用作哨兵或临时变量
int length; //用于记录顺序表的长度
}SqList;
数组元素交换函数
//交换L中数组r的下标为i和j的值
void swap(SqList *L,int i,int j)
{
int temp=L->r[i];
L->r[i]=L->r[j];
L->r[j]=temp;
}
9.2冒泡排序
最简单排序实现
冒泡排序(Bubble Sort)一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。
/*对顺序表L作交换排序(冒泡排序初级版)*/
void BubbleSort0(SqList *L)
{
int i,j;
for(i=1;i<L->length;i++)
{
for(j=i+1;j<=L->1ength;j++)
{
if(L->r[i]>L->r[j])
{