python面试之算法基础(排序算法总结与实现)

冒泡排序(稳定):

冒泡排序实现的过程主要是分为两步,第一步利用一层循环控制数列的冒泡的次数,第二步利用第二层循环控制从第一个数值位置“冒出”的元素数值不断与之后的数值比较之后(也就是冒泡中的数值始终是比较之后的最大值(或最小值))放在合适的位置,也就是逐次将大(小)数,次大(小)数。。。往后放,最终形成一个有序的序列。程序实现如下:

def maopao_sort(list):
    n = len(list)
    for j in  range(0,n-1):#注意和负数下标作区别
        for  i in range(0,n-1-j):
            if list[i]>list[i+1]:
                list[i],list[i+1] = list[i+1],list[i]
    return list
  • 最优时间复杂度:O(n) (表示遍历一次发现没有任何可以交换的元素,排序结束。)
  • 最坏时间复杂度:O(n2)
选择排序(不稳定):

整个排序过程和插入排序的思想有些相似,默认形成两个子序列,一个有序序列,一个无序序列,不断地从无序列中选择出最大值(或最小值)往有序序列中填充,填充的过程只是简单的在有序序列后面追加,因为有序序列本身就已经满足按照之后最大值(或最小值)选出来的。程序实现如下:

def select_sort(slist):
    length = len(slist)
    for j in range(0,length-2):
        min = j
        for i in range(j+1,length-1):
            if slist[min] > slist[i]:
                min = i
        slist[min],slist[j] = slist[j],slist[min]
    return slist
  • 最优时间复杂度:O(n2)
  • 最坏时间复杂度:O(n2)
插入排序(稳定):

插入排序的思想和选择排序类似,也是分成两个序列,有序序列和无序序列,不同的插入排序是不在无序列中挑选,而是不断直接选取无序序列第一个数值,在有序序列中比较,来确定有序序列中的准确位置。代码实现如下:

def insert_sort(slist):
    length = len(slist)
    for j in range(1,length):
        for i in range(j,0,-1):
            if slist[i] > slist[i-1]:
                slist[i],slist[i-1] = slist[i-1],slist[i]
    return slist
  • 最优时间复杂度:O(n) (升序排列,序列已经处于升序状态)
  • 最坏时间复杂度:O(n2)

希尔排序(不稳定):

希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止,程序如下:

def shell_sort(slist):
    length = len(slist)
    gap  = length // 2
    while gap > 0:
        print('gap =',gap)
        for j in range(gap,length):
            i = j
            while i >= gap  :
                if slist[i] > slist[i-gap]:
                    slist[i],slist[i-gap] = slist[i-gap],slist[i]
                i = i - gap
        gap = gap // 2
    return slist
  • 最优时间复杂度:根据步长序列的不同而不同

  • 最坏时间复杂度:O(n2)


快速排序(不稳定)

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

步骤为:

  1. 从数列中挑出一个元素,称为"基准"(pivot),
  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区结束之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会结束,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去

'''
1. 不可变对象作为函数参数,相当于C系语言的值传递。
2. 可变对象作为函数参数,相当于C系语言的引用传递。
可变对象是(list,dict,set)不可变对象是(init,float,str,tuple)
'''

def fast_sort(slist,start,end):
    if start >= end:
        return
    low = start
    high = end
    mid_slist = slist[start]
    while low < high:
        while high > low and slist[high] >= mid_slist:
            high -= 1
        slist[low] = slist[high]
        while  high > low and  slist[low] < mid_slist:
            low += 1
        slist[high] = slist[low]
    slist[low] = mid_slist

    fast_sort(slist,start,low-1)
    fast_sort(slist,low+1,end)
  • 最优时间复杂度:O(nlogn)
  • 最坏时间复杂度:O(n2)

归并排序(稳定):

归并排序的思想就是先递归分解数组,再合并数组。

将数组分解最小之后,然后合并两个有序数组,基本思路是比较两个数组的最前面的数,谁小就先取谁,取了后相应的指针就往后移一位。然后再比较,直至一个数组为空,最后把另一个数组的剩余部分复制过来即可。代码如下:

'''给定序列实现归并排序:slist = [13,14,94,33,82,25,59,94,65,23,45,27,73,25,39,10]
归并排序的稳定性是稳定的
'''

def merge_sort(slist):
    if len(slist) <= 1:
        return slist

    mid = len(slist) // 2

    left_list = merge_sort(slist[:mid])
    right_list = merge_sort(slist[mid:])

    result_list = []
    left_flag,right_flag = 0,0

    while (left_flag < len(left_list)) and (right_flag < len(right_list)):
        if left_list[left_flag] < right_list[right_flag]:
            result_list.append(left_list[left_flag])
            left_flag += 1
        else:
            result_list.append(right_list[right_flag])
            right_flag += 1
    result_list +=left_list[left_flag:]
    result_list +=right_list[right_flag:]

    return result_list

  • 最优时间复杂度:O(nlogn)

  • 最坏时间复杂度:O(nlogn)


时间紧促,难免出错,如有异议,烦请留言。。。。共同讨论。。。。。



你可能感兴趣的:(python)