排序算法(二) 快速排序

一、什么是快速排序?

       快速排序是对冒泡排序的改进,本质上都是通过交换两个元素来消除逆序。

       在冒泡排序中,由于扫描过程中只对相邻的两个元素进行比较,因此在互换两个相邻元素时只能消除一个逆序

       而在快速排序中,能通过两个不相邻的元素的交换,消除待排序记录中的多个逆序,则速度较冒泡排序有极大的提高。


二、快速排序实现算法思路:

     (1)、快速排序算法是一个递归过程:

                  一个问题能通过递归来解决,则说明其能够将一个大问题分解为无数个小问题;而且这些小问题的解决算

           法与大问题的解决算法是一毛一样的,只是问题规模的差别。

                  所以快速排序可以分解为无数的小问题,每一个小问题的解决方法都一样。

     (2)、那么这个解决方法是什么呢?

                  首先在待排序记录中找一个支柱元素结点(一般都是找序列的第一个元素,因为简单),使用这个支柱结

           点将序列划分为两个子序列。

                   怎么划分呢?   将大于等于支柱结点值的元素放到支柱结点的右边(子序列1);将小于支柱结点值得元

           素放到支柱结点的左边(子序列2);然后理所应当这个支柱结点就在两个子序列的交接点上。在此时,我们

           如果把整个序列看成三个元素:子序列2  <  支柱结点  <  子序列1,是不是有序的呢?

        (3)、理解了这一点,就好办了!

                  我们把一个最开始的大序列通过支柱结点划分为两个子序列,再将每个子序列划分为两个子子序列。。。

           当所有的子序列的长度为0 或 1 时,而且经过(2)步骤的元素交换后。那么当前整个序列就已经是一个有序

           序列了。


          下图为一次划分实例:

 

                            


     (4)、我们来详细描述一下每一次划分过程的交换算法(一趟快速排序)


               <1>. 将序列的第一个元素用变量x保存(则下标为0的元素位置空下来了),用low 和 high两个下标变量来存

                  储序列两端的下标。其中low是序列左端下标(下标为 0),high为序列的右端下标(下标为序列长度- 1)

                  , low  <  high ;


               <2>. 因为low位置是空的,所以可以放一个元素;因为是左端空了,所以从右端由 high 从右端向左端递减寻

                  找比支柱结点 x 值小的元素放入 low 的位置,low下标向后挪一个位置(low++)。然后是 high位置空了。


               <3>. 因为high位置是空的,所以可以放一个元素;因为是右端空了,所以从左端由 low 从左端向右端递增寻

                  找比支柱结点 x 值大的元素放入 high的位置,high下标向前挪一个位置 (high--)。然后又是 low 位置空

                  了。    由此转去循环执行<2>、<3>过程。直到 low < high 条件不在被满足,退出循环。


               <4>. 将支柱结点的值保存在low = high 的下标位置。


               <5>. 一趟排序完成。


源代码:


#include <stdio.h>

/*
**功能: 进行一趟快速排序
**参数说明:
**@record : 子序列数组;  @low : 序列左端下标;  @high : 序列右端下标
**返回值 :  支柱结点下标
*/
int QKPass(int record[], int low, int high)
{
	int x = record[low];   //保存支柱结点值

	while (low < high)
	{
	   /*
		*      因为low位置是空的,所以可以放一个元素;因为是左端空了,所以从右端由
		*  high 从右端向左端递减寻找比支柱结点 x 值小的元素放入 low 的位置,low下
		*  标向后挪一个位置(low++)
		*/
		while (low < high && record[high] >= x)
		{
			high--;
		}
		if (low < high)
		{
			record[low] = record[high];
			low++;
		}

	   /*
		*      经过上面操作后,high位置是空的,所以可以放一个元素;因为是右端空了,
		*  所以从左端由low 从左端向右端递增寻找比支柱结点 x 值大的元素放入 high的
		*  位置,high下标向前挪一个位置 (high--)。
		*/
		while (low < high && record[low] < x)
		{
			low++;
		}
		if (low < high)
		{
			record[high] = record[low];
			high--;
		}
	}

	record[low] = x;   //将支柱结点的值保存在low = high的位置
}

/*
**功能: 快速排序入口点
**参数说明: 
**@record : 记录序列数组;  @low : 序列左端下标;  @high : 序列右端下标
**返回值 : 无
*/
void QKSort(int record[], int low, int high)
{
	if (low < high)
	{
		int position;   //保存支柱结点下标

		position = QKPass(record, low, high);  //进行一趟快速排序,找到支柱结点的下标
		QKSort(record, low, position - 1);  //对序列2进行快速排序
		QKSort(record, position + 1, high); //对序列1进行快速排序
	}
}


int main(void)
{
	int record[] = { 48,62,35,77,55,14,35,98 };
	int len = sizeof(record) / sizeof(record[0]);
	int i = 0;

	printf("排序前: \n");
	for (i = 0;i < len;i++)
	{
		printf("%d  ", record[i]);
	}
	puts("");

	QKSort(record, 0, len - 1);

	printf("排序后: \n");
	for (i = 0;i < len;i++)
	{
		printf("%d  ", record[i]);
	}
	puts("");

	return 0;
}

运行截图:
                                                            

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值