015 python数据结构与算法:冒泡/选择排序

排序与搜索

排序算法(Sorting algorithm)是一种能将一串数据依照特定顺序进行排列的一种算法。

排序算法的稳定性

**稳定性:**稳定排序算法会让原本有相等键值的记录维持相对次序。也就是说如果一个排序算法是稳定的,当有两个相等键值的记录R和S,且原本的列表中R出现在S之前,在排序过的列表中R也将会是在S之前。
当相等的元素是无法分解的,比如像是整数,稳定性并不是一个问题。然而,假设以下的数对将要以他们的第一个数字来排序。

41)(31)(37)(56

在这个状况下,有可能产生两种不同的结果,一个是让相等键值的记录维持相对的次序,另一个是没有维持相对的次序:

31)(37)(41)(56#维持相对次序37)(31)(41)(56#次序被改变

不稳定排序算法额能回在相等的键值中改变记录的相对次序,但是稳定排序算法从来不会改变其相对次序。不稳定排序算法可以被特别的地实现为稳定,作为这件事的一个方式是人工扩充键值的比较,如此在其他方面相同键值的两个对象之间比较,(比如上面的比较中加入第二个标准:第二个键值的大小)。然而,这种次序通常牵涉到额外的空间负担。
通俗的来讲,排序之后,子序列和原来相同的就是稳定的,不相同的就是不稳定的。

冒泡排序

冒泡排序(Bubble Sort)是一种简单的排序算法,它重复的遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复的进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
冒泡排序算法的运作如下:

  • 比较相邻的元素,如果第一个比第二个大(升序),就交换他们两个。
  • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这一步做完以后,最后的元素会是最大的数。
  • 针对所有的元素重复以上的步骤,除了最后一个。
  • 持续每次对越来越少的元素重复上述的步骤,直到没有任何一对数字需要比较。

冒泡排序的分析

交换过程图示(第一次):
在这里插入图片描述
每一次遍历,都会有一个元素到达它的最终位置。
那么我们需要进行n-1次冒泡过程,每次对应的比较次数如下图所示:
在这里插入图片描述

冒泡排序实现

分析:使用顺序表或者链表都可以表示冒泡排序,这里我们选择以顺序表为例,因为交换链表节点,操作会稍微复杂一些。
为了方便在操作时交换,我们不选择交换元素,而是交换元素的下标。判断两个元素的大小,前一个元素大于后一个元素,要交换两个元素的位置。
在这里插入图片描述
因为列表下标是从0开始的,所以range要从n-1开始去遍历比较。
动画演示冒泡排序过程:
在这里插入图片描述

#冒泡算法执行过程
i 0~n-2  range(0,n-1)  j=0
i 0~n-3  range(0,n-1-1) j=1
i 0~n-4  range(0,n-1-2) j=2
#由此可以推导出来:j=n  i range(0,n-1-j)

代码实现:

def bubble_sort(alist):
    """冒泡排序"""
    n=len(alist)
    for j in range(n-1):#排序的次数,遍历列表的次数
        for i in range(0,n-1-j):#遍历列表从头到尾
            if alist[i]>alist[i+1]:
                alist[i],alist[i+1]=alist[i+1],alist[i]

if __name__=="__main__":
    li=[54,26,93,17,77,31,44,55,20]
    print(li)
    bubble_sort(li)#调用冒泡算法
    print(li)

冒泡算法中,外层循环控制循环多少次,内层循环控制从头走到尾
运行结果:
在这里插入图片描述
另外一种循环表示方式:

def bubble_sort(alist):
    for j in range(len(alist)-1,0,-1):
        # j表示每次遍历需要比较的次数,是逐渐减小的
        for i in range(j):
            if alist[i] > alist[i+1]:
                alist[i], alist[i+1] = alist[i+1], alist[i]

时间复杂度

  • 最优时间复杂度:O(n)(表示遍历一次发现没有需要交换的元素,排序结束)
  • 最坏时间复杂度:O(n2)(最坏的情况,每一次遍历都要从头走到尾)
  • 稳定性:稳定

优化冒泡算法:当在一次遍历后,没有出现元素的交换,说明已经有序,所以用一个count记录交换元素的次数。当count==0时,直接return,不需要再继续遍历。

def bubble_sort(alist):
    """冒泡排序"""
    n=len(alist)
    for j in range(n-1):
        count=0
        for i in range(0,n-1-j):
            if alist[i]>alist[i+1]:
                alist[i],alist[i+1]=alist[i+1],alist[i]
                count+=1
        if 0==count:
            return

选择排序

选择排序(Selection sort)是一种简单直观的排序算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。
选择排序的主要优点与数据移动有关。如果某个元素位于正确的最终位置上,则它不会被移动。选择排序每次交换一对元素,他们当中至少有一个将被移到其最终位置上,因此对n个元素的表进行排序总共进行至多n-1次交换。在所有的完全依靠交换去移动与安素的排序方法中,选择排序属于非常好的一种。
算法分析

alist=[54,226,93,17,77,44,55,20]
alist=[17,226,93,54,77,44,55,20]
alist=[17,20,31,        54,77,44,55,226]

相当于在列表的左边是有序的,右边是还未排序的,不断的遍历去寻找和交换,始终都是从未排序的序列中找到最小值去放到前面去。这里我们也使用数据下标去表示相应的数据。
在这里插入图片描述

def select_sort(alist):
    """选择排序"""
    n=len(alist)
    for j in range(n-1):
        min_index=j
        for i in range(j+1,n):
            if alist[min_index]>alist[i]:
                alist[i],alist[min_index]=alist[min_index],alist[i]

if __name__=="__main__":
    li=[54,26,93,17,77,31,44,55,20]
    print(li)
    select_sort(li)#调用选择算法
    print(li)

算法执行过程:
遍历列表,默认第一个元素是最小元素,依次去进行比较。
在这里插入图片描述
动画演示选择排序过程:
在这里插入图片描述

时间复杂度

  • 最优时间复杂度:O(n2)
  • 最坏时间复杂度:O(n2)
  • 稳定性:不稳定(考虑升序每次选择最大的情况)

插入排序

插入排序(Insertion Sort)是一种简单直观的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。插入排序在实现上,在从后向前扫描过程中,需要反复把已排序元素逐步向后挪位,为最新元素提供插入空间。

插入排序分析

在这里插入图片描述
动画演示插入排序过程:
在这里插入图片描述
通过插入排序和选择排序的比较可知,选择排序操作的是无序的一边,插入排序操作的是有序的一边。

def insertion_sort(alist):
    """插入排序"""
    n=len(alist)
    for j in range(1,n):#从右边无序序列中取出多少个元素执行这样的过程
        #j=[1,2,3,...,n-1]
        #i表示内层循环起始值
        i=j
        while i>0:#执行从右边的无序序列中取出第一个元素i位置的元素,然后将其插入到正确的位置
            if alist[i]<alist[i-1]:
                alist[i],alist[i-1]=alist[i-1],alist[i]
                i-=1
            else:
                break
if __name__=="__main__":
    li=[54,26,93,17,77,31,44,55,20]
    print(li)
    insertion_sort(li)#调用插入算法
    print(li)

另一种循环表示方式:

def insert_sort(alist):
    # 从第二个位置,即下标为1的元素开始向前插入
    for i in range(1, len(alist)):
        # 从第i个元素开始向前比较,如果小于前一个元素,交换位置
        for j in range(i, 0, -1):
            if alist[j] < alist[j-1]:
                alist[j], alist[j-1] = alist[j-1], alist[j]

时间复杂度

  • 最优时间复杂度:O(n)(升序排列,序列已经处于升序状态)
  • 最坏时间复杂度:O(n2)
  • 稳定性:稳定

动画演示插入排序过程:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值