目 录CONTENT

文章目录

算法 | 快速排序

RobKing
2022-08-20 / 0 评论 / 0 点赞 / 68 阅读 / 927 字

快速排序

平均时间复杂度为O(nlogn),不是稳定排序

递归实现

// 快速排序
// 算法思想:通过交换元素找到一个 基准 使得左边所有元素小于这个基准,右边所有元素大于这个基准
//之后左右两边循环执行这样的操作
func QuickSort(arr []int) {
    quickSort(arr, 0, len(arr)-1)
}

// 从0-len(arr)-1
func quickSort(arr []int, start, end int) {
    if start < end{
        // 找到基准 下标
        pivot := partition(arr, start, end)
        // 左边
        quickSort(arr, start, pivot - 1)
        // 右边
        quickSort(arr, pivot + 1, end)
    }
}

// 找到基准
// 直接先选择第一个元素
// 从后往前遍历,大于则移动;从前往后遍历,小于则移动。目的就是使得左边小于基准,右边大于基准,移动完之后交换左右元素
// 最后交换左指针和基准位置的值,左指针的位置即是基准的下标
func partition(arr []int, start, end int) int {
    p := arr[start]
    left, right := start, end
    for left < right {
        // 直到 右边元素小于第一个元素(基准)
        for left < right && arr[right] > p {	
            right --
        }
        // 直到 左边元素大于第一个元素(基准)
        for left<right && arr[left] <= p {
            left ++
        }
        // 交换这两个元素 使得小的在前面 大的在后面
        arr[left], arr[right] = arr[right], arr[left]
    }
    //将基准元素 移动到合适的位置 这个位置左边小于它,右边大于它
    arr[left], arr[start] = arr[start], arr[left]
    return left
}

非递归实现

// 快速排序 非递归实现
// 算法思想:用一个栈来保存开始和结束点,形成分区就会入栈,之后出栈寻找基准就是排序的过程
func sortArray(nums []int) []int {
    // 快速排序 非递归
    quickSort(nums, 0, len(nums)-1)
    return nums
}

func quickSort(nums []int, start, end int) {
    // 使用栈保存下标
    stack := make([]int, 0)
    if start < end {
        // 入栈 先右后左
        stack = append(stack, end)
        stack = append(stack, start)
        for len(stack) != 0 {
            // 出栈来排序
            l := stack[len(stack)-1]
            stack = stack[:len(stack)-1]
            r := stack[len(stack)-1]
            stack = stack[:len(stack)-1]
            // 找到 基准
            pivot := partition(nums, l, r)
            // 是否左边形成分区
            if pivot - 1 > l {	
                stack = append(stack, pivot - 1)
                stack = append(stack, l)
            }
            // 右边是否形成分区
            if pivot + 1 < r {
                stack = append(stack, r)
                stack = append(stack, pivot + 1)
            } 
        }
    }   
}

// 寻找基准
func partition(nums []int, start, end int) int {
    p := nums[start]
    i, j := start, end
    for i<j {
        for i<j && nums[j] > p {
            j--
        }
        for i<j && nums[i] <= p {
            i++
        }
        nums[i], nums[j] = nums[j], nums[i]
    }
    nums[i], nums[start] = nums[start], nums[i]
    return i
}

CPP 实现

class Solution {
public:
    vector<int> sortArray(vector<int>& nums) {
        // 快速排序
        // 思路:先找到一个基准,使小于基准的放到左边,大于的放到右边,按照同样的方式排序左右
        if(nums.size() == 0) return nums;
        // 快排
        quickSort(nums, 0, nums.size() - 1);
        return nums;
    }
    void quickSort(vector<int>& nums, int left, int right) {
        if (left >= right) return ;

        int p = nums[left + right >> 1], i = left, j = right;
		// i < j 也可以
        while (i <= j) {
            // 直到 左边元素小大于中间基准元素
            while(nums[i] < p) i ++;
            // 直到 右边元素小于中间基准元素	
            while(nums[j] > p) j --;
            // 这里之后 i ++, j -- 是因为 交换后的顺序肯定是正确的
            // 之所以要判断,是因为 可能一个指针到基准位置了  (4, 6, 5, 3)
            // 之所以是 i <= j 而不是 i < j 是因为当他们相等的时候,都需要移动指针,不然就一直指在这了
            if (i <= j) swap(nums[i ++], nums[j --]);
        }
		// 最后变成两段,从 [l, j] 是小于等于 x的
        // 从 [i, r] 是大于等于x的
        quickSort(nums, left, j);
        quickSort(nums, i, right);
    }
};
0

评论区