快速排序(双指针法)

一、快速排序的思想是什么

从数组中选取一个元素作为基准值,将待排序的数组分成左右两部分,左边的部分小于基准值,右边的部分大于基准值。左右两部分继续如此递归下去,不断分裂,直到待排序数组的元素为1,此时递归条件结束。

所以,我们重点关心的就是,在一段待排序数组中选一个基准值(一般选择待排序数组的第一个元素);使用左右两个指针向中间移动,左边的指针在比基准值大的下标时停下,右边的指针在比基准小的下标时停下,双方交换数组元素,继续向左、向右移动。

这一轮的移动到什么地方停止呢?那就是在左右指针下标值相等的时候,将这个下标值的元素与基准值元素交换。一轮下来,这个基准值位置确定,就不会再发生改变了。以它为分界线,分成左右两部分,剩下的排序它都不用参与了。

分开了左右两段之后,我们把左右段看成各自独立的待排序数组就好,做法与上面一致,只不过此时的待排序数组比较短了。使用递归实现就非常方便。

在不断的分裂过后,待排序数组只为一个元素的时候,排序就结束了。

 

二、为什么要使用快速排序?

从时间复杂度分析,排序一轮的执行次数与冒泡排序类似,一个长度为n的数组执行次数都是n;差别在排序的轮数;假设一个长度为8的数组,冒泡排序不管情况是好还是坏,都是执行7轮(n*n);对于快速排序,最差的情况才是7轮,一般为3轮(n * ).

三、代码(c语言)

下面是c语言实现代码,可以参考一下

#include <stdio.h> 

/*
  快速排序,双指针、递归实现 ;固定一个自定义变量,作为数据调换的中转空间。
*/
/*

int partion(int * num, int startindex, int endindex)
{
    
    int temp, left, right;
    int pivot = num[startindex];
    left = startindex;
    right = endindex;
    while(left != right){
        //从右边向左边遍历,大于基准值向左移动,小于基准值停下
        while(left < right && num[right] > pivot){
            right--;
        }
        //从左边向右边遍历,小于基准值向右移动,大于于基准值停下
        while(left < right && num[left] <= pivot){
            left++;
        } 
        
        //交换左右指针的值
        if(left < right)
        {
            temp = num[left];
            num[left] = num[right];
            num[right] = temp;    
        }
        
    }
    temp = num[left];
    num[left] = num[startindex];
    num[startindex] = temp;
    return left;
}
*/

/* 挖坑法
   左右指针数值吊换的时候,坑不断移动
 */ 
int partion(int * num, int startindex, int endindex)
{
    
    int temp, left, right, index;
    int pivot = num[startindex];
    index = startindex;
    left = startindex;
    right = endindex;
    while(left != right){
        while(left < right && num[right] > pivot){
            right--;
        }
        num[index] = num[right];
        index = right;
        
        while(left < right && num[left] <= pivot){
            left++;
        } 
        num[index] = num[left];
        index = left;    
    }
    num[left] = pivot;
    return left;
}

void quicksort(int * num, int startindex, int endindex)
{
    if(startindex >= endindex){
        return ;
    }
    int pivot_index = partion(num, startindex, endindex);
    quicksort(num, startindex, pivot_index - 1);
    quicksort(num, pivot_index+1, endindex);
}

int main()
{
    int num1[] = {6, 1, 2, 7, 9, 3, 4 ,5, 10};
    quicksort(num1,0, 8);
    for(int i = 0; i < 9; i++)
        printf("%d ", num1[i]);
}

<think>好的,我现在需要帮助用户了解双指针法的实现和应用场景。首先,我得回顾一下双指针法的基本概念,确保自己理解正确。根据用户提供的引用内容,特别是引用[1]和[4],双指针法主要是用两个指针在数组或字符串中高效解决问题,比如处理有序数组、移除元素或合并数组等。 接下来,我应该明确双指针法的分类。根据引用[3]和[4],常见的类型包括对撞指针和快慢指针。对撞指针通常用于有序数组,比如两数之和的问题,而快慢指针可能用于检测循环或移除元素。需要分别举例子说明这两种类型的实现步骤。 然后,应用场景部分需要覆盖用户提到的引用内容,比如合并有序数组(引用[2])、移除元素、判断回文等。每个场景最好给出具体的例子,比如LeetCode题目,这样用户更容易理解。 实现示例部分,用户可能需要代码示例,但用户的问题中提到了Python的快速排序示例,但双指针法的示例可能用其他语言如JavaScript或C。不过用户现在可能希望看到Python的示例,或者至少清晰的伪代码。需要确保代码符合用户提到的引用中的案例,比如合并数组或移除元素。 另外,用户提供的引用[4]提到了快速排序中的双指针应用,这里可能需要简要说明在快速排序中如何利用双指针进行分区操作,这也是一个重要的应用场景。 需要注意用户的引用中有提到逆向双指针在合并数组中的应用,比如引用[2]中的LeetCode88题,这可能需要在应用场景中特别指出逆向处理的情况,避免覆盖原有数据。 最后,生成的相关问题需要围绕双指针法的优化、与其他算法比较、具体应用等展开,帮助用户进一步学习。 现在需要组织这些信息,确保结构清晰,分点说明实现步骤、应用场景,并给出代码示例。同时,引用正确的来源,比如在合并数组时引用[2],在快速排序部分引用[4]等。</think>### 双指针法实现与应用场景详解 #### 一、双指针法原理 双指针法通过维护两个指针(通常为索引或位置标记)在数组或字符串中协同遍历,以$O(n)$或$O(n \log n)$的时间复杂度解决特定问题[^1]。其核心思想是通过指针的移动条件,减少不必要的遍历次数,提升效率。 #### 二、实现方式分类 1. **对撞指针** - **定义**:两个指针从数组两端向中间移动,适用于有序数组。 - **示例代码(两数之和)**: ```python def two_sum(nums, target): left, right = 0, len(nums)-1 while left < right: current_sum = nums[left] + nums[right] if current_sum == target: return [left+1, right+1] # 假设索引从1开始 elif current_sum < target: left += 1 else: right -= 1 return [] ``` **应用场景**:有序数组的两数之和(如LeetCode 167题)[^3]。 2. **快慢指针** - **定义**:两个指针以不同速度移动,常用于检测循环或删除重复项。 - **示例代码(移除元素)**: ```python def remove_element(nums, val): slow = 0 for fast in range(len(nums)): if nums[fast] != val: nums[slow] = nums[fast] slow += 1 return slow ``` **应用场景**:移除数组中特定值(如LeetCode 27题)。 3. **分离指针(逆向双指针)** - **定义**:两个指针分别操作不同数组,避免覆盖原始数据。 - **示例代码(合并有序数组)**: ```python def merge_sorted_arrays(nums1, m, nums2, n): p1, p2, p = m-1, n-1, m+n-1 while p1 >= 0 and p2 >= 0: if nums1[p1] > nums2[p2]: nums1[p] = nums1[p1] p1 -= 1 else: nums1[p] = nums2[p2] p2 -= 1 p -= 1 nums1[:p2+1] = nums2[:p2+1] ``` **应用场景**:合并两个有序数组(如LeetCode 88题)[^2]。 #### 三、核心应用场景 1. **有序数组操作** - 两数之和、三数之和、最接近的三数之和等[^3]。 2. **字符串处理** - 判断回文字符串(对撞指针)、反转字符串中的元音字母等。 3. **链表问题** - 链表中环的检测(快慢指针)、相交链表判断。 4. **快速排序优化** - 双指针用于划分基准值的左右子序列,提升分区效率(如引用[4]中的快速排序实现)。 #### 四、算法优势 - **时间复杂度低**:多数问题可优化至$O(n)$。 - **空间复杂度低**:通常为$O(1)$,原地操作。 - **逻辑清晰**:通过指针条件简化复杂遍历逻辑。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值