理解与应用排序算法(快速排序C实现)

目录

一、排序的定义

二、内排序方法

三、插入排序

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;
}

  • 32
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值