数据结构中排序方法1(附python代码)

      近来,笔试面试总是遇到各类的排序问题,作为一个纯统计出身的直女,对数据结构那是一窍不通,然后就被花式虐了,昨天被问到归并排序,明明之前有好好看过,然而被问起来,大脑仍旧是一片空白,为了鞭策自己,准备潜心归纳一波,归纳不好的,欢迎指正啦!另外,笔者十分辣鸡,不懂c语言,以后可能会懂吧,所以附上的代码都会是python的。

冒泡排序

   这个想必大家都有所耳闻吧,实在是太普遍了,冒泡,顾名思义一下,泡泡都是从水的底端往上冒,这个泡泡在这个方法中喻指值比较小的数值,因为他比他临近的数字小,所以就一直往上冒,直到到达他的位置,好,还是认真的解释一下吧,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录位置。举个栗子

      有一个数列[9,1,5,8,3,7,4,6]有8个数,那我们循环7次,依次冒出最小的,第二小,第三小。。的数值,第一次循环,也就是i=1时,从下标为9的数字开始,依次比较,数值小的往上冒,这样通过第一次循环,数值最小的1就被找到了,并且顺利归位到了他所属的下标1

                                                                                                         来自《大话数据结构》

第二次,也就是当i=2时,顺利找到数值第二小的2,将之排到下标为2的位置,然后依次循环。。。

       时间复杂度:算算,假设有n个树,第一次循环需要比较(n-1)次,第二次需要比较(n-2)次,第n-1次需要比较1次,因此总共比较了n(n-1)/2次,所以总的时间复杂度就是

        上代码,自行体会~~

#冒泡排序(简单版)
def BubbleSort_1(arr):
    count = len(arr)
    for i in range(0,count-1):
        for j in range(0,count-1-i):
            if arr[j] > arr[j+1]:
                arr[j],arr[j+1] = arr[j+1],arr[j]
    return arr

 

       那么问题来了,如果这个数列本身就是有序的,或者只需要简单交换一个数字就能达到有序了,那有必要还每次都两两比较吗?  答:没必要。再举个栗子{2,1,3,4,5,6,7,8}这个数列,再经过第一次冒泡后,就达到有序了,在第二轮循环中,若没有发现任何数据交换,就说明此序列已经有序了,就没有必要进行后续操作了,省时省力,岂不快活。代码只需要加一个判断是否存在数据d交换的语句便可,空说无凭,继续上代码

 

#冒泡排序(优化)
def BubbleSort_2(arr):
    count = len(arr)
    for i in range(0, count):
        swapFlag = False #先假设未做交换操作  
        for j in range(i + 1, count): 
            if arr[i] > arr[j]:  
                arr[i],arr[j] = arr[j],arr[i]  
                swapFlag = True  #设置交互操作标志  
        if not swapFlag:
            break #无交换操作,表示已完成排序,退出循环  
    return arr

     再次分析一下复杂度 ,在最好的情况下,也就是排序的表本身就是有序的,那么比较次数是n-1次,此时时间复杂度为0(n)。

当最坏的情况,即待排序表是逆序的,复杂度仍为

 

简单选择排序

 冒泡排序的思想就是通过不断交换完成最终的排序,那是否可以在排序时找到合适的关键字再做交换,并且只移动一次就完成相应关键字的排序工作呢,这里引入选择排序

 基本思想:通过n-1次的关键字间的比较,从n-i+1中选出关键字最小的记录,并和第i个记录交换之

代码如下:

def Select_sort(arr):
    count = len(arr)
    for i in range(0, count):
        min = i
        for j in range(i + 1, count):
            if arr[min] > arr[j]:
                min = j
        arr[min], arr[i] = arr[i], arr[min]
    return arr

 

以序列{9,1,5,8,3,7,4,6,2}为例子,当i=0时,min开始是0,然后将arr[0]与arr[j=1]到j=8进行比较,找到最小的值1,此时对应j=1,与arr[0]交换一次,也就是说在这一轮循环中,虽比较了8次大小,却只交换了一次。如图

 

接下来,依次类推,i=2时,交换9和2的位置

直到序列有序,最多经过8次交换。

复杂度分析

   从简单选择排序的过程来看,它的最大特点即交换数据次数想当少,节约了时间。同时,无论最好最差情况,比较次数均为

对于交换次数,最好的情况当序列升序时,交换0次,当初始序列降序时,情况最差,交换次数是n-1次。基于最终排序时间是比较与交换次数总和,因此时间复杂度依然是O(n^2)

   尽管与冒泡法排序复杂度相同,但简单选择方法在性能上的排序还是要略优于冒泡排序。

 

直接插入排序

基本思想:将一个记录插入到已经排好序的有序表中,从而得到一个新的,记录数增1的有序表

解释的稍微通俗点就是,你拿到一个序列{9,1,5,8,3,7,4,6,2},从第二个数字开始与前面比较,1比9大,所以1,9交换位置,那个1,9算是个有序数列列了,现在看数字5,大小介于1和9之间,于是将之插入到1与9之间,如此循环,便能得到有序数列,代码如下

def insert_sort(arr):
    count = len(arr)
    for i in range(1,count):
        key = arr[i]
        j = i - 1
        while j >= 0:
            if arr[j] > key:
                arr[j+1] = arr[j]
                arr[j] = key
            j -= 1
    return arr

时间复杂度

 

  当最好的情况,也就是排序表本身就是有序的,那么时间复杂度为O(n)

 

  当最坏的情况,即时间表是逆序的,需要比较(n+2)(n-1)/2次,记录移动次数达到最大值(n+4)(n-1)/2次

  如果记录是随机的,依据概率相同的原则,平均比较和移动次数均为(n^2)/4,因此直接插入排序法的时间复杂度是O(n^2)

基于同样的时间复杂度,直接插入排序比冒泡法和简单选择排序的性能要好一些

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值