排序的基本概念与分类
假设含有n个记录的序列为{r1 , r2 , … rn},其相应的关键字分别为{k1 , k2 , … kn},需确定1, 2, … n的一种排列p1 , p2 … pn ,使其相应的关键字满足kp1<=kp2 … kpn ,非递减(非递增)关系,即使得序列称为一个按关键字有序的序列{rp1 , rp2 … rpn},这样的操作就称为排序。
排序的稳定性
假设ki = kj (1<=i<=n, 1<=j<=n, i≠j),且在排序前的序列中ri 领先于rj(即i<j)。如果排序后ri 仍领先于rj ,则称所用的排序方法是稳定的;反之,若可能使得排序后的序列中rj 领先于ri ,则称所用的排序方法是不稳定的。
内排序与外排序
内排序是在排序整个过程中,待排序的所有记录全部被放置在内存中。外排序时由于排序的记录个数太多,不能同时放置在内存中,整个排序过程需要在内外存之间多次交换数据才能进行。(这里主要介绍内排序)
对内排序来说,排序算法的性能主要受三个方面影响:
(1)时间性能,即高效的内排序算法应该是具有尽可能少的关键字比较次数和尽可能少的记录移动次数。
(2)辅助空间
(3)算法复杂度
根据排序过程中借助的主要操作,把内排序分为插入排序、交换排序、选择排序和归并排序。
排序用到的结构与函数
仅作示例:
#define MAXSIZE 10000
typedef struct
{
int r[MAXSIZE];
int length;
}SqList;
void swap(SqList *L, int i, int j)
{
int temp = L->r[i];
L->r[i] = L->r[j];
l->r[j] = temp;
}
冒泡排序
冒泡排序(Bubble Sort)是一种交换排序,它的基本思路时:两两比较相邻记录的关键字,如果反序则交换,知道没有反序的记录为止。
//初级版
void BubbleSort(SqList *L)
{
for(int i = 0; i < L->length; i++)
{
for(int j = i + 1; j <= L->length; j++)
{
if(L->r[i] > L->r[j])
{
swap(L, i, j);
}
}
}
}
void BubbleSort1(SqList *L)
{
for(int i = 0; i < L->length; i++)
{
for(int j = L->length - 1; j >= i; j--)
{
if(L->r[j] > L->r[j + 1])
{
swap(L, j, j + 1);
}
}
}
}
//改进
void BubbleSort2(SqList *L)
{
int flag = 1;//标记目前是否已经有序
for(int i = 0; i < L->length && flag; i++)
{
flag = 0;
for(int j = length - 1; j >= i; j--)
{
if(L->r[j] > L->[j + 1])
{
swap(L, j, j + 1);
flag = 1;
}
}
}
}
算法复杂度为O(n2)。
简单选择排序
简单选择排序(Simple Selection Sort)就是通过n - i次关键字间的比较,从n - i + 1个记录中选出关键字的最小记录,并和第i(1<=i<=n)个记录交换。
void SelectSort(SqList *L)
{
int min;
for(int i = 0; i < L->length; i++)
{
min = i;
for(int j = i + 1; j < L->length; j ++)
{
if(L->r[min] > L->r[j])
min = j;
}
if( i != min)
swap(L, i, min);
}
}
其时间复杂度为O(n2),但其性能会略优于冒泡排序。
直接插入排序
直接插入排序(Straight Insertion Sort)的基本操作时将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录增1的有序表。
voi