目录
一、排序的定义
二、内排序方法
三、插入排序
3.1 直接插入排序
3.1 折半插入排序
3.1 链表插入排序
四、交换排序
五、起泡排序
六、快速排序
一、排序的定义
稳定排序和非稳定排序
设文件f=(R1......Ri......Rj......Rn)中记录Ri、Rj(i≠j,i、j=1……n)的key相等,即Ki=Kj。
若在排序前Ri领先于Rj,排序后Ri仍领先于Rj,则称这种排序是稳定的,其含义是它没有破坏原本已有序的次序。
内排序和外排序
若待排文件 f 在计算机的内存储器中,且排序过程也在内存中进行,称这种排序为内排序。
若排序中的文件存入外存储器,排序过程借助于内外存数据交换(或归并)来完成,则称这种排序为外排序。
二、内排序方法
各种内排序方法可归纳为以下五类:
(1)插入排序
(2)交换排序
(3)选择排序
(4)归并排序
......
三、插入排序
直接插入排序
折半插入排序
链表插入排序
Shell(希尔)排序
……
3.1 直接插入排序
设待排文件f=(R1R2......Rn)相应的key集合为k ={k1k2......kn}。
排序方法
先将文件中的(R1)看成只含一个记录的有序子文件,然后从R2起,逐个将R2至Rn按key插入到当前有序子文件中,最后得到一个有序的文件。插入的过程上是一个key的比较过程,即每插入一个记录时,将其key与当前有序子表中的key进行比较,找到待插入记录的位置后,将其插入即可。
设文件记录的key集合k={50,36,66,76,95,12,25,36}
3.1 折半插入排序
排序算法的T(n)=O(n2),是内排序时耗最高的时间复杂度。
折半插入排序方法
先将(R[1])看成一个子文件,然后依次插入R[2]……R[n]。但在插入R[i]时,子表[R[1]……R[i-1]]已是有序的,查找R[i]在子表中的位置可按折半查找方法进行,从而降低key的比较次数。
3.1 链表插入排序
设待排序文件f=(R1 R2……Rn),对应的存储结构为单链表结构:
表置为空表,然后依次扫描链表中每个结点,设其指针为p,搜索到p结点在当前子表的适当位置,将其插入。
设含4个记录的链表如图:
四、交换排序
“起泡”排序(Bubble Sort)
“快速”排序(Quick Sort)
4.1 起泡排序
设记录key集合k={50,36,66,76,95,12,25,36},排序过程如下:
4.2 快速排序
设记录的key集合k={50,36,66,76,36,12,25,95},每次以集合中第一个key为基准的快速排序过程如下:
五、快速排序实现
#include <stdio.h>
#include <stdlib.h>
#define N 15
// 函数声明
int quick_sort(int *data, int low, int high);
int partion(int *data, int low, int high);
int compare(const void *p1, const void *p2);
int main(int argc, char *argv[])
{
int i;
int data[N] = {0};
// 使用种子值10初始化随机数生成器
srandom(10);
// 生成随机数组
for(i = 0; i < N; i++){
data[i] = random() % 100;
}
// 打印原始数组
for(i = 0; i < N; i++){
printf("%d ", data[i]);
}
puts("");
// 调用快速排序算法对数组进行排序
quick_sort(data, 0, N-1);
// 打印排序后的数组
for(i = 0; i < N; i++){
printf("%d ", data[i]);
}
puts("");
return 0;
}
// 快速排序的分区函数
int partion(int *data, int low, int high){
int temp = data[low];
while(low < high){
// 从右向左找到第一个比基准值小的元素
while(low < high && temp <= data[high]){
high--;
}
// 将比基准值小的元素移到左边
data[low] = data[high];
// 从左向右找到第一个比基准值大的元素
while(low < high && temp >= data[low]){
low++;
}
// 将比基准值大的元素移到右边
data[high] = data[low];
}
// 将基准值放置到最终位置
data[low] = temp;
return low;
}
// 快速排序函数
int quick_sort(int *data, int low, int high){
int t;
// 检查输入数组是否为空
if(data == NULL){
return -1;
}
// 递归结束条件
if(high <= low){
return 0;
}
// 分区,并获取基准值的位置
t = partion(data, low, high);
// 对基准值左边的子数组进行递归排序
quick_sort(data, low, t-1);
// 对基准值右边的子数组进行递归排序
quick_sort(data, t+1, high);
return 0;
}
// 比较函数,用于qsort函数的排序
int compare(const void *p1, const void *p2){
return (*(const int *)p1 - *(const int *)p2);
}
注意:
1、compare函数是为qsort函数准备的,但在这个示例中并未使用qsort。
2、quick_sort函数返回了0,但在实际应用中,我们通常不需要这个返回值,因为排序函数主要是修改数组的内容。但是,检查数组是否为空并返回-1是一个好的做法,可以捕获潜在的错误。
六、快速排序测试题
1、利用快速排序对以下数据进行排序1,5,7,8,3,5,9,4,1,0
#include <stdio.h>
#include <stdlib.h>
int quick_sort(int *data, int low, int high);
int partion(int *data, int low, int high);
int main(int argc, char *argv[])
{
int data[] = {1, 5, 7, 8, 3, 5, 9, 4, 1, 0};
int i;
for(i = 0; i < 10; i++){
printf("%d ", data[i]);
}
puts("");
quick_sort(data, 0, 9);
for(i = 0; i < 10; i++){
printf("%d ", data[i]);
}
puts("");
return 0;
}
int partion(int *data, int low, int high){
int temp = data[low];
while(low < high){
while(low < high && temp <= data[high]){
high--;
}
data[low] = data[high];
while(low < high && temp >= data[low]){
low++;
}
data[high] = data[low];
}
data[low] = temp;
return data[low];
}
int quick_sort(int *data, int low, int high){
int t;
if(data == NULL){
return -1;
}
if(low >= high){
return 0;
}
t = partion(data, low, high);
quick_sort(data, low, t-1);
quick_sort(data, t+1, high);
return 0;
}