数据结构学习第五天---归并排序与二分查找

1、归并排序

归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。

可以看到这种结构很像一棵完全二叉树,本文的归并排序我们采用递归去实现(也可采用迭代的方式去实现)。阶段可以理解为就是递归拆分子序列的过程,递归深度为log2n。

注意:在我们的快排中!我们的一切操作都是在原有 的列表之上进行操作的,并没有生成新的列表。但是我们的归并排序的时候,我们需要先切分,这时候我们切分之后会形成新的列表,然后是对新的列表进行操作的!这就是区别

代码的实现:

#coding=utf8


def  merger_sort(alist):
    """归并排序"""
    #1、首先对alist这个列表进行拆分
    n = len(alist)     #   n :7
    if n <= 1:
        return alist
    mid = n//2
    # 这里的left是采用归并排序后形成的有序的新的列表
    left_list = merger_sort(alist[:mid])

    # 这里的right是采用归并排序后形成的有序的新的列表
    right_list = merger_sort(alist[mid:])

    #合并两个有序的子序列。然后返回一个新的有序的列表
    #合并的时候存在两个游标。left指向左边的序列,right指向右边的序列
    left_pointer , right_pointer = 0 , 0
    result = []


    while left_pointer < len(left_list) and right_pointer < len(right_list):
        # 如果左边有序队列的指针所指的值要比右边有序队列指针所指的值要小! 然后就把小 的值放再新的序列中
        if left_list[left_pointer] <= right_list[right_pointer]:
            result.append(left_list[left_pointer])
            #追加到新的列表中以后,然后指针移动!
            left_pointer += 1
        else:
            result.append(right_list[right_pointer])
            #追加过后 ,指针移动
            right_pointer += 1

    result += left_list[left_pointer:]
    result += right_list[right_pointer:]
    return result

if __name__ == "__main__":
    li = [123,]
    print(li)
    sort_list = merger_sort(li)
    print(li)
    print(sort_list)

执行说明,debug之后发现!他首先使用的alist是整个整体! 然后先左边的拆分调用! 然后在一步一步的往上走! 当吧左边的都排好序以后,这时候在执行右边 的alist!整个过程都是这样的!

归并排序的时间复杂度:上面说了递归深度为log2n  ,所以,我们的最优时间复杂度是O(nlog2n) ,最坏的时间复杂度是O(nlog2n) , 它是稳定性很好的一个排序算法。

2、二分 查找(搜索算法)

二分查找在查找之前必须是排序之后的。还有就是就是说这些元素必须是相邻存储的! 就是支持下标索引的,也就是 顺序表! ,链表是不支持的。

上来就定义到整个列表的中间 的位置 ,将列表分为两个部分,然后比较需要查找的那个元素跟中间元素的大小, 看看应该去中间元素的左边找,还是右边找, 然后在对左边或者是右边的列表再次找到中间元素,然后再次查找,这就是二分查找的原理。

二分查找的实现(递归版本的实现):

递归与非递归的区别就在于!递归就是不断的生成新的列表的!之间 中间元素mid = n / 2 就好,但是非递归的时候不生成新的列表!这时候我们就需要使用下标来实现了。

#coding=utf8
def binary_search(alist,item):
    """二分查找"""
    n = len(alist)

    #判断递归停止的条件
    if n>=1:
        # 取中间元素
        mid = n/2
        #判断:如果alist[mid],这个位置的元素等于我们要查找的这个元素,就返回一个true
        if alist[mid] == item:
            return True
        #判断:如果alist[mid]这个位置的元素小于我们要查找的元素,那么我们就递归的调用二分查找,将中间值的左边的列表进行下次二分
        elif item < alist[mid]:
           return binary_search(alist[:mid],item)
        #判断:如果是item>alist[mid]这个值!那么我们就将这个中间值的右边这个序列继续进行 二分
        else:
            return binary_search(alist[mid+1:],item)

二分查找的实现(非递归版本的实现):

#非递归版本的二分查找
def binary_search_2(alist,item):
    """二分查找  费递归版本"""
    n = len(alist)
    first = 0
    last = n-1
    while first <= last:
        mid = (first + last) // 2
        if alist[mid] ==item:
            return True
        elif item < alist[mid]:
            last = mid -1
        else:
            first  = mid + 1

二分查找的时间复杂度:

最优时间复杂度是O(1)! 二分查找的最坏时间复杂度是O(logn)

猜你喜欢

转载自blog.csdn.net/weixin_41928342/article/details/86173736