LeetCode—1.快速排序算法

1.基本思想

  快速排序算法(Quick Sort)是冒泡算法的一种改进,是一种不稳定的排序算法。其主要思想是通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据要比另一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,最终整个数据变成了有序序列。

冒泡排序(Bubble Sort)是一种简单的排序算法。它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换。
冒泡排序算法的运作如下:
1.比较相邻的元素。如果第一个比第二个大(升序),就交换他们两个。
2.对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
3.针对所有的元素重复以上的步骤,除了最后一个。
4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

2.算法原理

  快速排序算法运作如下:

  1. 从数列中挑出一个元素,称为基准(pivot),
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。分区操作结束之后,基准元素就处于最终排序后它的位置。
  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序,直至所有子数列只剩下一个元素为止

3.分区—partition

  以下两种方法掌握其一就行

1.挖坑法

在这里插入图片描述

在开始的时候4,1下面都有指针,分别对应的l、r指针,第一个坑为4,由于r指针指向的1小于4,所以1移到l指针指向的坑,此时原1出处为坑,l指针向右移动一位,指向7,由于l指针指向的7大于4,所以7移动到l指针指向的坑,此时原7处为坑,重复该操作直到l指针与r指针相重合,此时该处就为4.
以上就完成了分区操作,
接下来再递归地把小于基准值元素的子数列和大于基准值元素的子数列排序,直至所有子数列只剩下一个元素为止

2.指针交换法

  核心思想就是找到两边不满足条件的指针然后交换指针。
在这里插入图片描述

基准为4,l指针指向7,r指针指向1,由于1<4<7,不满足条件,所以两个指针交换,r指针移动一位,1<4<8,满足条件,r指针移动一位,1<4<2右边不满足条件,需移动左边,l指针移动一位,6<4<2,两边均不满足条件,两个指针交换,r指针移动一位,2<4<3,右边不满足条件,l指针移动一位,5<4<3,两个指针交换,r指针向左移动一位,此时双指针重合并指向3,3与4对调。
以上便是指针交换法。

4.怎么选取基准

  1. 选取第一个元素作为基准
  2. 随机选择一个元素作为基准

5.时间复杂度

  快速排序的平均时间复杂度是O(nlogn),最坏情况下的时间复杂度是O(n^2)。

选取第一个元素作为基准时,n个元素,每个元素遍历一次,此时,时间复杂度为O(n^2)

6.LeetCode

  215.在未排序的数组中找到第k个最大的元素(需要找的是数组排序后第k个最大的元素)

输入:[3,2,1,5,6,4]和k
输出:5

class Solution:
    def findKthElement(self, nums, k):
        '''
        找到数组中第k个最大元素,
        快速排序每一轮确定一个位置,如果我们想要的位置的元素确定了,那么排序就结束了
        :param nums: 数组
        :param k: k
        :return: 返回第k个最大元素
        '''
        return self.quickSort(nums, k)

    def quickSort(self, nums, k):
        # 找到我们要寻找元素的位置
        k = len(nums) - k
        # 左右指针的位置
        left, right = 0, len(nums) - 1  # 0,4
        while left < right:
            # 进行分区操作,得到确定的位置,将确定的位置与k进行比较后,对子数据集进行分区操作
            j = self.partition(nums, left, right)
            if j == k:
                break
            elif j < k:
                left = j + 1
            else:
                right = j - 1
        # 跳出循环有两个条件:一种是j=k,一种是left=right,两种情况下均可满足j=k
        return nums[k]

    def partition(self, nums, left, right):
        '''
        分区操作—挖坑法,确定某个元素的位置
        :param nums: 数组
        :param left: 左指针
        :param right: 右指针
        :return: 返回确定元素的位置
        '''
        pivot = nums[left]
        # quickSort函数中也有left、right函数
        i, j = left, right
        # 跳出循环的条件是:i = j,此时,即为元素的位置
        while i < j:
            # 跳出条件是找到小于基准的元素nums[j]或i=j
            while i < j and nums[j] > pivot:
                j -= 1
            if i < j:
                nums[i] = nums[j]
                i += 1

            # 找到大于基准的元素nums[i]
            while i < j and nums[i] <= pivot:
                i += 1
            if i < j:
                nums[j] = nums[i]
                j -= 1
        # i = j时
        nums[i] = pivot
        return i


def main():
    nums = [3, 2, 1, 5, 6, 4]
    k = 2
    s = Solution()
    kth_element = s.findKthElement(nums, k)
    print('数组中第%d个最大元素为%d' % (k, kth_element))


if __name__ == '__main__':
    main()

代码已上传至https://github.com/Libra-1023/leetcode

猜你喜欢

转载自blog.csdn.net/weixin_46649052/article/details/114296843