第10章 快速排序

【排序思想】

通过一趟排序,将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,再分别对这两部分记录进行下一趟排序,以达到整个序列有序。

【排序过程】

设待排序的记录序列是 R [ s t ] R[s…t] ,在记录序列中任取一个记录 (一般取 R [ s ] R[s] ) 作为参照(又称为基准或枢轴),以 R [ s ] . k e y R[s].key 为基准重新排列其余的所有记录,方法是:

  1. 所有关键字比基准小的放 R[s] 之前;
  2. 所有关键字比基准大的放 R[s] 之后。

R [ s ] . k e y R[s].key 最后所在位置i作为分界,将序列 R [ s t ] R[s…t] 分割成两个子序列,称为一趟快速排序。

【一趟快速排序方法】

从序列的两端交替扫描各个记录,将关键字小于基准关键字的记录依次放置到序列的前边;而将关键字大于基准关键字的记录从序列的最后端起,依次放置到序列的后边,直到扫描完所有的记录。

设置指针 l o w low h i g h high ,初值为第1个和最后一个记录的位置。

设两个变量 i , j i, j ,初始时令 i = l o w , j = h i g h i=low, j=high ,以 R [ l o w ] . k e y R[low].key 作为基准 (将 R [ l o w ] R[low] 保存在 R [ 0 ] R[0] 中) 。

① 从 j j 所指位置向前搜索:将 R [ 0 ] . k e y R[0].key R [ j ] . k e y R[j].key 进行比较:

  1. R [ 0 ] . k e y R [ j ] . k e y R[0].key ≤ R[j].key :令 j = j 1 j=j-1 ,然后继续进行比较, 直到 i = j i=j R [ 0 ] . k e y > R [ j ] . k e y R[0].key > R[j].key 为止;
  2. R [ 0 ] . k e y > R [ j ] . k e y R[0].key > R[j].key R [ j ] R [ i ] R[j] \Rightarrow R[i] ,腾空 R [ j ] R[j] 的位置, 且令 i = i + 1 i=i+1

② 从 i i 所指位置起向后搜索:将 R [ 0 ] . k e y R[0].key R [ i ] . k e y R[i].key 进行比较:

  1. R [ 0 ] . k e y R [ i ] . k e y R[0].key ≥ R[i].key :令 i = i + 1 i=i+1 ,然后继续进行比较, 直到 i = j i=j R [ 0 ] . k e y < R [ i ] . k e y R[0].key < R[i].key 为止;
  2. R [ 0 ] . k e y < R [ i ] . k e y R[0].key < R[i].key R [ i ] R [ j ] R[i] \Rightarrow R[j] ,腾空 R [ i ] R[i] 的位置, 且令 j = j 1 j=j-1

③ 重复①、②,直至 i = j i=j 为止, i i 就是 R [ 0 ] R[0] (基准) 所应放置的位置。

【一趟排序示例】

设有 6 个待排序的记录,关键字分别为 29, 38, 22, 45, 23, 67,一趟快速排序的过程如图10-7所示。

完整代码如下:

#include <stdio.h>

#define	TRUE		1			//真 
#define	FALSE		0			//假
#define	OK			1			//通过
#define	ERROR		0			//错误
#define MAXSIZE 20					//用作示例的顺序表的最大长度
#define LT(a,b) ((a)<(b))					
#define LQ(a,b) ((a)<=(b))
typedef int Status;

/* 记录类型 */
typedef int KeyType;				//定义关键字类型为整数类型
typedef struct						//顺序表结构 
{
	KeyType key;					//关键字项 
	//使用结构体便于使用中扩展 
}RcdType;

/* 顺序表类型 */
typedef struct
{
	RcdType r[MAXSIZE+1];			//r[0]闲置或用作哨兵单元
	int length;						//顺序表长度 
}SqList_sort;

//1.创建一个任意顺序的序列。
Status CreateSortList(SqList_sort *L)
{
	printf("请输入元素个数:"); 
	scanf("%d", &((*L).length));
	
	if((*L).length > MAXSIZE)
		return ERROR;
	printf("请依次输入元素的关键字:\n"); 
	for(int i = 1; i <= (*L).length; i++)
		scanf("%d", &((*L).r[i].key));

	return OK;
}

//2.输出序列L。
void Traverse(SqList_sort L)
{
	for(int i = 1; i <= L.length; i++)
		printf("%d ", L.r[i].key);	
	printf("\n");
}

//3.划分。算法10.6(a):完成一趟快速排序。
int Partition_1(SqList_sort *L, int low, int high)
{
	int pivotkey;	
	RcdType tmp;
	
	pivotkey = (*L).r[low].key;					//用子表第一个记录作枢轴记录 
	
	while(low<high)								//从表的两端交替地向中间扫描 
	{
		while(low<high && (*L).r[high].key>=pivotkey)
			high--;
		
		tmp = (*L).r[high];						//将比枢轴记录小的记录交换到低端 
		(*L).r[high] = (*L).r[low];
		(*L).r[low] = tmp;
		
		while(low<high && (*L).r[low].key<=pivotkey)
			low++;
		
		tmp = (*L).r[high];						//将比枢轴记录大的记录交换到高端
		(*L).r[high] = (*L).r[low];
		(*L).r[low] = tmp; 
	}
	
	return low;									//返回枢轴所在位置 
}

//4.划分。算法10.6(b):完成一趟快速排序。
int Partition_2(SqList_sort *L, int low, int high)
{
	int pivotkey;
	
	(*L).r[0] = (*L).r[low];					//用子表第一个记录作枢轴记录
	pivotkey = (*L).r[low].key;					//枢轴记录关键字 
	
	while(low<high)								//从表的两端交替地向中间扫描 
	{
		while(low<high && (*L).r[high].key>pivotkey)
			high--;
		
		(*L).r[low] = (*L).r[high];				//将比枢轴记录小的记录交换到低端 
		
		while(low<high && (*L).r[low].key<=pivotkey)
			low++;
		
		(*L).r[high] = (*L).r[low];				//将比枢轴记录大的记录交换到高端
	}
	
	(*L).r[low] = (*L).r[0];					//枢轴记录到位 
	
	return low;									//返回枢轴所在位置 
}

//5.算法10.8:对顺序表L中的子序列L.r[low..high]作快速排序。 
void QSort(SqList_sort *L, int low, int high)
{
	int pivotloc;
													
	if(low<high)								//长度大于1 
	{
	//	pivotloc = Partition_1(L, low, high);	//将(*L).r[row..high]一分为二
		
		pivotloc = Partition_2(L, low, high);	//将(*L).r[row..high]一分为二
	
		QSort(L, 1, pivotloc-1);				//对低子表递归排序,pivotloc是枢轴位置 
		QSort(L, pivotloc+1, high);				//对高子表递归排序 
	} 
}

//6.算法10.7:对顺序表L作快速排序。
void QuickSort(SqList_sort *L)
{
	QSort(L, 1, (*L).length);
}

int main(int argc, char *argv[])
{
	SqList_sort L;
	
	CreateSortList(&L);
	
	QuickSort(&L); 
	Traverse(L);
	printf("\n");
	
	return 0;
}
发布了674 篇原创文章 · 获赞 103 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/qq_42815188/article/details/103972019