as火柴人

导航

排序算法

一,冒泡排序

  1.思想

  冒泡排序,从左往右依次比较,将大的轮换到最右边,然后循环,已经排位的大 的不用参加新一轮的轮换。

  内层循环负责把左边的数依次与右边的轮换。外层循环负责控制轮换的终止位置。

  2.注意:

  循环range(列表长度),还是list[]切片,一定要搞清楚,不能写错。对于列表都是从0开始标号,所以结束位置是n-1

  比较轮换的时候,i到n-2就可以了,也就是说i的终止位置,【n-2,n-3,n-4....1】

 

def bubble_sort(alist):
    n = len(alist)
    for j in range(n - 1, 0, -1):#-1是步长,放在后面,不能放中间
        count=0
        for i in range(0, j):
            if alist[i] > alist[i + 1]:
                alist[i], alist[i + 1] = alist[i + 1], alist[i]
                count+=1
        if count==0:
            break
if __name__=="__main__":
    alist=[54,26,93,17,77,31,44,55,20]
    print(alist)
    bubble_sort(alist)
    print(alist)

 

  • 最优时间复杂度:O(n) (表示遍历一次发现没有任何可以交换的元素,排序结束。)
  • 最坏时间复杂度:O(n2)
  • 稳定性:稳定

二,选择排序

  选择排序,找出序列里面最小值,往左放。一般循环是找找最小值的位置,最后在这个循环外面跟最左边未排序的进行交换,不能轮换。

  内循环:找最小值的位置,外循环。控制未排列的序列和最小值和最左位置的交换。

   

def select_sort(alist):
    n = len(alist)
    for j in range(0, n - 1):
        min_index = j
        for i in range(j, n):
            if alist[i] < alist[min_index]:
                min_index = i#这里只能给坐标转换值,不能动列表里面的值。
if min_index != j:#循环结束找到最小值位置,才动列表的值 alist[min_index], alist[j] = alist[j], alist[min_index] if __name__ == "__main__": alist = [54, 26, 93, 17, 77, 31, 44, 55, 20] select_sort(alist) print(alist)

三,插入排序

 

 

 

 

插入排序,是依次将序列从右边与左边已经排好的轮换。但是和冒泡不同的是,不需要一个个比较,当比较到相应位置就停止。

内循环控制插入过程,和冒泡类似,用i和i+1相比较。

def insert_sort(alist):
    n = len(alist)
    for j in range(1, n):
        for i in range(j, 0, -1):
            if alist[i] < alist[i - 1]:
                alist[i], alist[i - 1] = alist[i - 1], alist[i]
            else:#当直接找到了比这个待排序大的就停止排序
                break

注意:range(i-1,-1,-1):中间不能放-1,最小放0

  • 最优时间复杂度:O(n) (升序排列,序列已经处于升序状态)
  • 最坏时间复杂度:O(n2)
  • 稳定性:稳定。。一般跟冒泡类似的,轮换性质的都是稳定的

四。希尔排序

五,快速排序(划分交换排序)

  1. 思想:(选择一个中间值作为一个分割线,分开序列)

  通过第一个值作为中值(注意这里中值并不意味着最后位置是最中间)对整个数列进行划分,然后从右开始做判断,交换进行排序,最后要求:规则:这个中值的左边都小于它,右边都大于它。

  将list[0]提出来,0位空缺

  low游标初始指向0,和high游标指向尾部,在指向空值时不能挪动。high游标先动,直到有不满足规则的,交换空缺和high的值。然后让low游标移动

  以中值左右划分之后的序列再迭代进行快速排序。

  

 2.注意:

  迭代的时候再函数里面进行,不是定义之后。在其他函数里面反复调用,那样不是迭代。

  迭代的输入要始终都是要处理的列表,只是不能传入切片,因为切片是取列表的一部分

  if 语句是判断并不能当循环用。

  想用两段代码交替进行,就在外部加一个while,这样循环起来。

  递归的终止一定要写,而且写在函数内部,列表的两边只剩下一个元素时,就可以停止了。

  空位=值a,这样就可以把a赋给空位,a为为空。

3.代码。思路

def quick_sort(alist, first, last):
    #递归的结束条件千万不能忘记
    if first >= last:
        return
    mid_value = alist[first]
    low = first
    high = last
    while low < high:
        while low < high and alist[high] >= mid_value:
            high -= 1
        alist[low] = alist[high]
        while(low < high and alist[low] < mid_value):
            low += 1
        alist[high] = alist[low]#赋值的时候,不用交替赋值,因为这里high的值是0,直接这样赋值,就能让low得到high的空值。
    alist[low] = mid_value
    quick_sort(alist, 0, low-1)#左边序列的左边子序列开始始终是0,结束是需要low控制
    quick_sort(alist, low + 1, last)#右边序列的之后的子序列的右边子序列始终是last。
#关于迭代要清楚

if __name__ == "__main__":
    alist = [54, 26, 93, 17, 77, 31, 44, 55, 20]
    print(alist)
    n = len(alist)
    quick_sort(alist, 0, n-1)#传入的last一定要是n-1,因为这里是直接对n-1位置进行对比。
    print(alist)

 

其中wid2左,是第二次快排的时候,中间值。

每一次迭代的两次划分都是用相同的输入变量。左边都是【0,wid-1】,右边都是【wid+1,last】

 4.时间复杂度

       最优排序时间复杂度:当wid正好可以把序列一分为二,迭代会依次把n/2/2/2/2/...,.一直到1停止,这里进行了x次的除2:x=log(n)

    每次迭代函数内部要n次,需要O(nlog(n))

       最差时间复杂度:每次wid只能把序列分成自己和其他:O(n的平方)

       不稳定:因为交换有可能造成相同值的顺序被打乱。

posted on 2018-11-22 21:42  as火柴人  阅读(277)  评论(2)    收藏  举报