快速排序和归并排序的区别,有代码
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(’转发一下吧!’)
以上是关于快速排序和归并排序的区别,有代码的主要内容,如果未能解决你的问题,请参考以下文章