冒泡排序和快速排序的分析与比较

冒泡排序,就是相邻的两个元素相互比较并根据比较结果决定是否交换位置。如从小到大排序,相邻两个元素两两比较,将值更大的元素交换到右侧,如此到最后一个元素,就能确定最大的一个值,一轮排序结束。若某一轮排序交换位置的次数为0,则排序结束。

冒泡排序基于简单交换的思想,冒泡排序每趟不断将记录两两比较,并按“前小后大”的规则交换。

冒泡排序的基本思想是:

①从数组的头部开始,比较相邻两个数,如果第1个数比第2个数大,就交换他们两个。也就是让较大的数逐渐往后移动,直到数组的末尾,经过第一轮的比较,就可以找到最大的元素,并将它移动到最后一个位置。

②第一轮结束后,继续第二轮,仍然从数组的头部开始比较,直到数组的倒数第2个元素为止,经过第2轮比较,就可以找到次大的元素,并将它放到倒数第二个位置。

③以此类推,经过n-1轮“冒泡”后,就可以将所有的元素都排列好。

冒泡排序的实例(升序):

初始:  21  25  49  25  16  08  n=6

第一趟:位置0,1进行比较--判断21<25--不交换--结果:21  25  49  25  16  08

       位置1,2进行比较--判断25<49--不交换--结果:21  25  49  25  16  08

       位置2,3进行比较--判断49>25--交换--结果:21  25  25  49  16  08

       位置3,4进行比较--判断49>16--交换--结果:21  25  25  16  49  08

       位置4,5进行比较--判断49>08--交换--结果:21  25  25  16  08  49

       第一趟比较了5次,确定了最大的数字49

第二趟:位置0,1进行比较--判断21<25--不交换--结果:21  25  25  16  08  49

       位置1,2进行比较--判断25=25--不交换--结果:21  25  25  16  08  49

       位置2,3进行比较--判断25>16--交换--结果:21  25  16  25  08  49

       位置3,4进行比较--判断25>08--交换--结果:21  25  16  08  25  49

       第二趟比较了4次,确定了第二大数字25

第三趟:位置0,1进行比较--判断21<25--不交换--结果:21  25  16  08  25  49

        位置1,2进行比较--判断25>16--交换--结果:21  16  25  08  25  49

       位置2,3进行比较--判断25>08--交换--结果:21  16  08  25  25  49

       第三趟比较了3次,确定了第三大数字25

第四趟:位置0,1进行比较--判断21>16--交换--结果:16  21  08  25  25  49

        位置1,2进行比较--判断21>08--交换--结果:16  08  21  25  25  49

       第四趟比较了2次,确定了第四大数字21

第五趟:位置0,1进行比较--判断21>08--交换--结果:08  16  21  25  25  49

       第五趟比较了1次,确定了第五大数字16和最小的数字08

可以得出结论,n个记录的话,总共需要n-1趟,第x趟需要比较n-x次。

冒泡排序总共排的次数为:1+2+3+…+n-1,共 n(n-1)/2,时间复杂度为O(n2)。

快速排序是改进的交换排序。从本质上来看,快速排序是一种递归分治法。首先任意选取一个数据(通常选用数组的第一个数)作为枢轴,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,形成左右两个子表,这个过程称为一趟快速排序,然后对各子表重新选择中心元素并依此规则调整,直到每个子表的元素只剩下一个。通过一趟排序,将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分进行排序,以达到整个序列有序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。

快速排序的思路:

(1)从数列中挑出一个元素,称为 “基准”(pivot);

(2)将元素分而治之,小的置于基准值左侧,大的置于基准值右侧;

(3)基准值两侧作为两个子数列,再分别找一个基准值,重复步骤(1)。

快速排序的实现步骤:

两个指针left,right分别指向列表的第一个元素和最后一个元素,然后取一个参考值,默认为第一个列表的第一个元素list[0],称为K

然后left指向的值先和参考值K进行比较,若list[left]小于或等于K值,left就一直向右移动,left+1,直到移动到大于K值的地方,停住

right指向的值和参考值K进行比较,若list[right]大于K值,right就一直向左移动,right-1,直到移动到小于K值的地方,停住

此时,left和right若还没有相遇,即left还小于right,则二者指向的值互换

若已经相遇则说明,第一次排序已经完成,将list[right]与list[0]的值进行互换,进行之后的递归。

 下面是用python实现的冒泡排序和快速排序:

def bubble_super(arr):
    """冒泡排序"""
    loop = len(arr) - 1
    flag = 1
    if loop > 0:
        print('初始flag=',flag)
        for x in range(loop):    # 总共需要 loop 趟
            if flag ==1:
                print('第',x+1,'趟:flag=',flag)
                flag = 0
                for i in range(loop - x):   # 第x趟需要比较 loop-x 次
                    if arr[i] > arr[i + 1]:  #若发生逆序 
                        flag = 1
                        arr[i], arr[i + 1] = arr[i + 1], arr[i]   # 则交换位置
                        print('        第',i+1,'次:flag=',flag,'结果为:',arr)
                    else:
                        print('        第',i+1,'次:flag=',flag,'结果为:',arr)
            else:
                print('第',x+1,'趟:flag=',flag)
    return arr
num = [8,21,21,16,49,25]
print('最终结果:',bubble_super(num))
def split_array(nums, left, right):  # 返回调整后基准数的位置
    key = nums[left]  # nums[left]就是第一个基准点
    while left < right:
        # right下标位置开始,向左边遍历,查找不大于基准数的元素
        while left < right and nums[right] >= key:
            right -= 1
        if left < right:  # 找到小于准基数key的元素,然后交换nums[left],nums[right]
            nums[left], nums[right] = nums[right], nums[left]
        else:  # left〉=right 跳出循环
            break
        # left下标位置开始,向右边遍历,查找不小于基准数的元素
        while left < right and nums[left] < key:
            left += 1
        if left < right:  # 找到比基准数大的元素,然后交换nums[left],nums[right]
            nums[right], nums[left] = nums[left], nums[right]  
        else:  # left〉=right 跳出循环
            break
    nums[left] = key
    print('基准点',key,'的排序结果是:',nums)
    return left  # 此时left==right 所以返回right也是可以的

def quick_sort(nums, left, right):
    if left < right:
        key_index = split_array(nums, left, right)
        quick_sort(nums, left, key_index - 1)
        quick_sort(nums, key_index + 1, right)

if __name__ == "__main__":
    nums = [6,1,2,7,9,3,4,5,10,8]
    quick_sort(nums, 0, len(nums) - 1)
    print('最后的结果是:',nums)

 冒泡排序的运行结果为:

快速排序的运行结果为:

结果分析

两种算法的复杂度及稳定性比较:

排序算法

时间复杂度(平均)

时间复杂度(最坏)

时间复杂度(最好)

空间复杂度

稳定性

冒泡排序

O(n2)

O(n2)

O(n)

O(1)

稳定

快速排序

O(nlog2n)

O(n2)

O(nlog2n)

O(log2n)

不稳定

快速排序不是原地排序,需要递归调用栈的支持,而栈的长度取决于递归调用的深度(即使不用递归,也要用到用户栈)。在平均情况下,需要用到O(log2n)的栈空间,最坏情况下,栈空间可以达到O(n)

快速排序不适合对原本有序或者基本有序的记录序列进行排序。划分元素的选取是影响时间性能的关键,输入次序越混乱,所选划分元素值的随机性就越好,排序速度就越快,快速排序不是自然排序方法。

冒泡排序是从最底层元素开始比较,(与其上的元素比较)小于就往上再比,大于就交换,再用较小的往上比较,直到最高层,第一次把最大的放到最上层,第二次把第二大的放到第二层,以次类推;快速排序是先找到一个轴值,比较时把所有比轴值小的放到轴值的左边,比轴值大的放到右边,再在两边各自选取轴值再按前面排序,直到完成。

当数据量增大时,冒泡排序所用时间如下图所示:

 

快速排序所用时间如下图所示:

很明显,数据量增大时,快速排序比冒泡排序效率高出很多。如果数字只有几个的话两者比较不是很明显。快速排序是所有内部排序算法中平均性能最优的排序算法。

  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值