【算法导论学习】快速排序

本文深入解析了快速排序算法,包括其基本理念、具体实现步骤、递归分治策略、数组分割技巧及C语言代码示例。介绍了主元选择、指针遍历等关键操作,并对比了lomuto和霍尔两种不同的划分方法。

快速排序的基本理念

快速排序本质上还是分治法来进行排序,所以还是参考这个前面提到的分析方法。

所以快速排序可以分为三个部分:
在这里插入图片描述

具体实现

选一个数,把比他小的放前面,比他大的放后边,然后通过递归不断缩小范围,直到全部排序好。

方法

主要分为两个板块:

  1. 递归分治
  2. 数组分割

其中递归分治中就用到了数组分割

递归分治

很好理解,就是把数组拆分为三个部分:

  1. 主元x,这个是标杆,围绕他来划分数组
  2. 比主元小的部分
  3. 比主元大的部分
数组分割

首先选择一个主元x,主元可以任意选择,这里以选择最后一个元素为例。
同时设立两个指针变量i,j:
其中j指向最左元素,i指向最左元素的左边一个元素(其实没什么必要,可以改为i,j都指向最左元素)

下面展示的是在分割过程中数组的状态
在这里插入图片描述

然后将j向后遍历,如果遇到比x大的元素则收纳,到比x小的就将其通过交换调到前面去。
在交换之前i指针向后移指向比主元大部分的第一个元素,保证在交换后i是指向的比x小的最后一个元素
在这里插入图片描述
在最后,将主元与(>x)部分的第一个元素交换,以确保顺序不乱

在算法导论中提到的方法是lomuto划分,还有一种常见的是霍尔提出的划分方法
lomuto划分的两个指针都是从左边开始,霍尔划分是从两边开始,在下面的伪代码部分我会提供霍尔划分的伪代码

伪代码
  1. 递归排序
    在这里插入图片描述
  2. 数组划分
    lomuto:
    在这里插入图片描述
    霍尔:
    在这里插入图片描述
C语言代码
#include<stdio.h>

//自己写的数组交换函数 
void swap(int A[], int i, int j)
{
	int temp = A[i];
	A[i] = A[j];
	A[j] = temp;
}

int HoarePartition(int A[],int p,int r)
{
    int i=p;
    int j=r;
    int x=A[i];
    while(i<j)
    {
    	//j从右边开始找比x小的元素 
        while(i<j && A[j]>=x) 
			j--;
        if(i<j)
            A[i]=A[j];
            
        //i从左边开始找比主x的元素 
        while(i<j && A[i]<=x)
            i++;
        if(i<j)
            A[j]=A[i];
    }
    A[i]=x;
    return i;
}

//进行分割排序,同时返回主元 
int partition(int A[],int p,int r)
{
	int x = A[r];
	int i = p-1;
	int j;
	
	//j从第一位开始往后遍历,遇到比x大的就收纳,遇到比x小的就将其与调到前面去(通过交换) 
	for(j = p; j <= r-1; j++)
	{
		if(A[j]<=x)
		{
			i = i+1;
			swap(A, i, j);
		}
	}
	//最后一步将主元x放到正确的位置 
	swap(A, i+1, r);
		return i + 1;
} 

int quicksort(int A[], int p, int r)
{
	if(p<r)
	{
		//q是主元,那么q左边的就是小于A[q]的,右边就是大于A[q]的 
		int q = partition(A, p, r);
		//递归排序,递归出口就是上面的if条件 
		quicksort(A, p, q-1);
		quicksort(A, q+1, r);
	}
}

int main()
{
	int A[] = {2, 5, 3, 1, 10, 4};
    int n = 6;
    quicksort(A, 0, n-1);
	for(int i; i<n; i++)
	{
	    printf("%d ",A[i]);
	}
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值