快速排序和归并排序的区别,有代码

Posted 湾区人工智能

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了快速排序和归并排序的区别,有代码相关的知识,希望对你有一定的参考价值。

数据结构和算法分析是程序员面试必考内容,接下来打算刷常见面试题,顺便分享给大家。刷,刷,刷,一般中级题目刷300道,刷3遍,国内大部分公司offer随便拿。想进顶级互联网公司,要刷一些高级题目,大概30%难度题目就行,想节省时间,个人推荐报个靠谱培训班。

排序理念比较:


归并排序merge sort思路:

归并排序中间劈一刀,两边再排序,然后把左右两个合并。就是先局部有序,再整体有序。

快速排序思路:

随便选择一个数字作为中间点,小于放在左边,大于放在右边。递归对左右两个部分排序。就是先整体有序,后局部有序。


归并排序优缺点

优点:容易掌握,用处广泛。分治思想很重要

缺点:花费O(n)的额外空间,因为要合并两个数组,不可能在原地合并数组,必须要开辟新的空间来合并。所以这种算法败给了快速排序算法。


稳定性比较:


稳定就是同样的数字,比如两个1,排序前后两个1位置不变。

归并排序能够保证原来的顺序,很稳定。

快排不够稳定。

复杂度比较


时间复杂度:

复杂度都是nlogn,本质是有区别的。

快排的平均复杂度是nlogn,最坏会达到n平方的复杂度。每次都选择最左边的数字,导致左边只有一个数字,右边有其他数字。

归并排序复杂度最好,最坏,平均都是nlogn。是严格的nlogn复杂度。

空间复杂度:

快排空间复杂度是原地排序,不用额外空间呢。

归并排序需要额外的O(N)空间,因为要合并两个数组,不可能在原地合并数组,必须要开辟新的空间来合并


464. 整数排序 II

给一组整数,按照升序排序。使用归并排序,快速排序,堆排序或者任何其他 O(n log n) 的排序算法。


样例

给出 [3, 2, 1, 4, 5], 排序后的结果为 [1, 2, 3, 4, 5]。


归并排序merge sort思路:


归并排序中间劈一刀,两边再排序,然后把左右两个合并。就是先局部有序,再整体有序。

归并排序优缺点


优点:容易掌握,用处广泛。分治思想很重要


缺点:花费O(n)的额外空间,因为要合并两个数组,不可能在原地合并数组,必须要开辟新的空间来合并。所以这种算法败给了快速排序算法。


归并排序复杂度最好,最坏,平均都是nlogn。是严格的nlogn复杂度。



class Solution():
    def sortIntegers2(self, A):
        if not A:
            return 
        temp = [0] * len(A)
        return self.mergeSort(A, 0, len(A) - 1, temp)

    def mergeSort(self, A, start, end, temp):
        if start >= end:
            return
        #无脑先分为两半
        #先递归到左边进行排序
        self.mergeSort(A, start, (start + end)//2, temp)
        #再递归到右边进行排序
        self.mergeSort(A, (start + end)//2 + 1, end, temp)
        #合并数组的左右两部分
        return self.merge(A, start, end, temp)

    #合并两个子数组
    def merge(self, A, start, end, temp):
        middle = (start + end) // 2
        leftIndex = start  #左侧子数组指针
        rightIndex = middle + 1  #右侧子数组指针
        index = leftIndex

        # 比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置
        while leftIndex <= middle and rightIndex <= end:
            if A[leftIndex] < A[rightIndex]:
                temp[index] = A[leftIndex]
                index += 1 
                leftIndex += 1 
            else:
                temp[index] = A[rightIndex]
                index += 1 
                rightIndex += 1 
        #最后有可能剩下一个数组还没有结束
        while leftIndex <= middle:
            temp[index] = A[leftIndex]
            index += 1 
            leftIndex += 1
        while rightIndex <= end:
            temp[index] = A[rightIndex]
            index += 1 
            rightIndex += 1 
        #把临时数组的值依次给
        for i in range(start, end+1):
            A[i] = temp[i]
        #A = temp
        return A 



obj = Solution()
a = [3,2,1,4,5]
b = obj.sortIntegers2(a) 
print(b)

快速排序思路:


随便选择一个数字作为中间点,小于放在左边,大于放在右边。递归对左右两个部分排序。就是先整体有序,后局部有序。


快排不够稳定。

时间复杂度:


复杂度都是nlogn,本质是有区别的。


快排的平均复杂度是nlogn,最坏会达到n平方的复杂度。每次都选择最左边的数字,导致左边只有一个数字,右边有其他数字。

快排空间复杂度是原地排序,不用额外空间呢。


class Solution:
    # @param {int[]} A an integer array
    # @return nothing
    def sortIntegers2(self, A):
        # Write your code here
        self.quickSort(A, 0, len(A) - 1)

    def quickSort(self, A, start, end):
        if start >= end:
            return

        left, right = start, end  #start和end固定,以后只需要不停改变left和right的值就行了
        #注意1:拿到中间指针对应的数组值,而不是拿到中间指针的值

        # key point 1: pivot is the value, not the index
        pivot = A[(start + end) // 2]
        #注意2: left <= right 而不是 left < right

        # key point 2: every time you compare left & right, it should be 
        # left <= right not left < right
        while left <= right:
            #注意3:A[left] < pivot 而不是<=

            while left <= right and A[left] < pivot:
                left += 1

            while left <= right and A[right] > pivot:
                right -= 1

            if left <= right:
                A[left], A[right] = A[right], A[left]

                left += 1
                right -= 1
        #注意4:经过上面的交换,这里关系变为了right < left

        self.quickSort(A, start, right)
        self.quickSort(A, left, end)





决心和意志是学好编程的关键。
生命不息,刷题不止!
程序员之路,别怂,就是干!




扫码关注的工资会翻倍


print_r('关注一下吧');
var_dump('关注一下吧');
NSLog(@"关注一下吧!")
System.out.println("关注一下吧!");
console.log("点个赞吧!");
print("点个赞吧!");
printf("点个赞吧!");
cout << "点个赞吧!" << endl;
Console.WriteLine("转发一下吧!");
fmt.Println("转发一下吧!")
Response.Write("转发一下吧!");
alert(’转发一下吧!’)



以上是关于快速排序和归并排序的区别,有代码的主要内容,如果未能解决你的问题,请参考以下文章

算法排序02——归并排序介绍及其在分治算法思想上与快排的区别(含归并代码)

重学数据结构和算法之归并排序快速排序

算法浅谈——分治算法与归并快速排序(附代码和动图演示)

归并排序和快速排序

python实现快速排序归并排序

python实现快速排序归并排序