• 【数据结构】:算法(一)


    算法基础

    1、什么是算法?

    算法(Algorithm):一个计算过程,解决问题的方法
    

    2、复习:递归

    递归的两个特点:

    • 调用自身
    • 结束条件

    两个重要递归函数的对比:

    # 由大到小
    def func3(x):
        if x > 0 :
            print(x)
            func3(x-1)
    
    # func3(5)
    # 5 4 3 2 1
    
    # 由小到大
    def func4(x):
        if x > 0 :
            func4(x-1)
            print(x)
    
    func4(5)
    # 1 2 3 4 5
    

      

    3、时间复杂度

    时间复杂度:用来评估算法运行效率的一个东西:

    print('Hello World')            # 0(1)
    
    for i in range(n):                  # O(n)
        print('Hello World')
    
    for i in range(n):                   # O(n^2)
        for j in range(n):
            print('Hello World')
    
    for i in range(n):                   # O(n^3)
        for j in range(n):
            for k in range(n):
                print('Hello World')
    

    第一个打印了一次时间复杂度为O(1);第二个打印了n次,所以时间复杂度为O(n);第三四个依次为n²和n的3次方

    那么看看下面代码中的时间复杂度为多少?

    # 非O(3) 而是O(1)
    print('Hello World')
    print('Hello Python')
    print('Hello Algorithm')
    
    # 非O(n²+n) 而是O(n²)
    for i in range(n):
        print('Hello World')
            for j in range(n):
                print('Hello World')
    
    # 非O(1/2n²) 而是O(n2)
    for i in range(n):
        for j in range(i): 
            print('Hello World')
    

    再看看下面代码: 

    # 时间复杂度 O(log2n) 或 O(logn)
    while n > 1:
        print(n)
        n = n // 2
    
    # n=64输出:
    # 64
    # 32
    # 16
    # 8
    # 4
    # 2
    

    小结:

    时间复杂度是用来估计算法运行时间的一个式子(单位)。

    一般来说,时间复杂度低的算法比复杂度低的算法快。

    常见的时间复杂度(按用时排序)

    • O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n2logn)<O(n3)

    不常见的时间复杂度(看看就好)

    • O(n!) O(2n) O(nn) …

    如何一眼判断时间复杂度?

    • 循环减半的过程O(logn)
    • 几次循环就是n的几次方的复杂度

    4、空间复杂度

    空间复杂度:用来评估算法内存占用大小的一个式子

    列表查找

    列表查找:从列表中查找指定元素

    • 输入:列表、待查找元素
    • 输出:元素下标或未查找到元素

    1、顺序查找

    从列表第一个元素开始,顺序进行搜索,直到找到为止

    def linear_search(data_set, value):  
        for i in data_set:       
            if data_set[i] == value:    
                return i  
        return

    时间复杂度为O(n)

    2、二分查找

    有序列表的候选区data[0:n]开始,通过对待查找的值与候选区中间值的比较,可以使候选区减少一半

    # 正宗的二分查找
    data = [i for i in range(9000000)]
    import time
    def cal_time(func):
        def inner(*args,**kwargs):
            t1 = time.time()
            re =  func(*args,**kwargs)
            t2 = time.time()
            print('Time cost:',func.__name__,t2-t1)
            return re
        return inner
    
    @cal_time
    def bin_search(data_set,val):
        low = 0
        high = len(data_set) - 1
        while low <= high:
            mid = (low + high)//2
            if data_set[mid] == val:
                return mid
            elif data_set[mid] < val:
                low = mid +1
            else:
                high = mid -1
    
    bin_search(data, 999)
    # Time cost: bin_search 0.0005002021789550781

    时间复杂度为O(logn),运行后会发现执行的很快,下面对比下之前Alex讲过的二分查找

    # Alex的low版本
    data = [i for i in range(9000000)]
    import time
    def cal_time(func):
        def inner(*args,**kwargs):
            t1 = time.time()
            re =  func(*args,**kwargs)
            t2 = time.time()
            print('Time cost:',func.__name__,t2-t1)
            return re
        return inner
    
    def _binary_search(dataset, find_num):
        if len(dataset) > 1:
            mid = int(len(dataset) / 2)
            if dataset[mid] == find_num:  # find it
                print("找到数字", dataset[mid])
            elif dataset[mid] > find_num:  # 找的数在mid左面
                return _binary_search(dataset[0:mid], find_num)
            else:  # 找的数在mid右面
                return _binary_search(dataset[mid + 1:], find_num)
    
    @cal_time
    def binary_search(dataset, find_num):
        _binary_search(dataset, find_num)
    
    binary_search(data, 999)
    # Time cost: binary_search 0.4435563087463379
    

    3、练习  

    现有一个学员信息列表(按id增序排列),格式为:

    [
    {id:1001, name:"张三", age:20},
    {id:1002, name:"李四", age:25},
    {id:1004, name:"王五", age:23},
    {id:1007, name:"赵六", age:33}
    ]

    修改二分查找代码,输入学生id,输出该学生在列表中的下标,并输出完整学生信息

    import random
    import time
    
    # 生成随机列表
    def  random_list(n):
        result = []
        ids = list(range(1001,1001+n))
        n1 = ['','','','']
        n2 = ['','','','','']
        n3 = ['','','','']
        for i in range(n):
            age = random.randint(18,60)
            id = ids[i]
            name = random.choice(n1)+random.choice(n2)+random.choice(n3)
            dic = {'id':id,'name':name,'age':age}
            result.append(dic)
        return result
    
    # 二分查找
    def cal_time(func):
        def inner(*args,**kwargs):
            t1 = time.time()
            re =  func(*args,**kwargs)
            t2 = time.time()
            print('Time cost:',func.__name__,t2-t1)
            return re
        return inner
    
    @cal_time
    def bin_search(data_set,val):
        low = 0
        high = len(data_set) - 1
        while low <= high:
            mid = (low + high)//2
            if data_set[mid]['id'] == val:
                return mid
            elif data_set[mid]['id'] < val:
                low = mid +1
            else:
                high = mid -1
    
    
    student_list = random_list(100000)
    bin_search(student_list, 999)
    # Time cost: bin_search 0.0004999637603759766
    学员id查询.py

    列表排序(lowB三人组)

    概述

    列表排序:

    将无序列表变为有序列表

    应用场景:

    • 各种榜单
    • 各种表格
    • 给二分排序用
    • 给其他算法用
    排序low B三人组:
    冒泡排序
    选择排序
    插入排序
    快速排序
    排序NB二人组:
    堆排序
    归并排序
    没什么人用的排序:
    基数排序
    希尔排序
    桶排序
    几种排序的对比

    1、冒泡排序(low)

    排序思路:首先,列表每两个相邻的数,如果前边的比后边的大,那么交换这两个数,每次循环都会选中一个最大的数,然后依次把列表排序;

    import random
    import time
    
    def call_time(func):
        def inner(*args,**kwargs):
            t1 = time.time()
            re = func(*args,**kwargs)
            t2 = time.time()
            print('Time cost:',func.__name__,t2-t1)
            return re
        return inner
    
    @call_time
    def bubble_sort(data):
        for i in range(len(data)-1):
            for j in range(len(data)-i-1):
                if data[j] > data[j+1]:
                    data[j],data[j+1] = data[j+1],data[j]
        return data
    data = list(range(10000))
    random.shuffle(data)
    
    bubble_sort(data)
    # Time cost: bubble_sort 17.608235836029053
    

    时间复杂度:O(n²)

    优化:

    @call_time
    def bubble_sort_1(data):
        for i in range(len(data)-1):
            exchange = False                # 没有交换 表示前边都已经排好了 执行退出
            for j in range(len(data)-i-1):
                if data[j] > data[j+1]:
                    data[j],data[j+1] = data[j+1],data[j]
                    exchange = True
            if not exchange:
                break
        return data
    

      

    2、选择排序(low)

    排序思路:一趟遍历记录最小的数,放到第一个位置; 再一趟遍历记录剩余列表中最小的数,继续放置;或遍历最大的放到最后

    import random
    import time
    
    def call_time(func):
        def inner(*args,**kwargs):
            t1 = time.time()
            re = func(*args,**kwargs)
            t2 = time.time()
            print('Time cost:',func.__name__,t2-t1)
            return re
        return inner
    
    @call_time
    def select_sort(li):
        for i in range(len(li)-1):
            max_loc = 0
            for j in range(len(li)-i-1):
                if li[max_loc] < li[j]:
                    max_loc = j
            li[len(li)-i-1],li[max_loc] = li[max_loc],li[len(li)-i-1]
    
    
    data = list(range(10000))
    random.shuffle(data)
    
    select_sort(data)
    # Time cost: select_sort 10.837876319885254
    

    时间复杂度:O(n²)  

    def select_sort(li):
        for i in range(len(li)-1):
            min_loc = i
            for j in range(i+1,len(li)):
                if li[j] < li[min_loc]:
                    min_loc = j
            li[i],li[min_loc] = li[min_loc],li[i]
    从前面开始排

    3、插入排序(low)

    插入思路:列表被分为有序区和无序区两个部分。最初有序区只有一个元素。 每次从无序区选择一个元素,插入到有序区的位置,直到无序区变空

    import random
    import time
    
    def call_time(func):
        def inner(*args,**kwargs):
            t1 = time.time()
            re = func(*args,**kwargs)
            t2 = time.time()
            print('Time cost:',func.__name__,t2-t1)
            return re
        return inner
    
    @call_time
    def insert_sort(li):
        for i in range(1,len(li)):
            for k in range(i-1,-1,-1):
                if li[i] < li[k]:
                    li[i],li[k] = li[k],li[i]
                    i = k
                else:
                    break
    
    data = list(range(10000))
    random.shuffle(data)
    
    insert_sort(data)
    # Time cost: insert_sort 9.358688592910767
    

    时间复杂度:O(n²)  

    def insert_sort(li):
        for i in range(1,len(li)):
            tmp = li[i]
            j = i -1 
            while j >=0 and li[j] > tmp:
                li[j+1] = li[j]
                j = j -1
            li[j+1] = tmp
    老师的写法

    快速排序

    快速排序:快

    • 好写的排序算法里最快的
    • 快的排序算法里最好写的

    快排思路:

    • 取一个元素p(第一个元素),使元素p归位;
    • 列表被p分成两部分,左边都比p小,右边都比p大;
    • 递归完成排序。

    示图:

    记住要领

    • 右手左手一个慢动作!右手左手慢动作重播

    代码:

    import random
    import time
    
    def call_time(func):
        def inner(*args,**kwargs):
            t1 = time.time()
            re = func(*args,**kwargs)
            t2 = time.time()
            print('Time cost:',func.__name__,t2-t1)
            return re
        return inner
    
    def quick_sort_x(data,left,right):
        if left < right:
            mid = partition(data,left,right)
            quick_sort_x(data,left,mid-1)
            quick_sort_x(data,mid+1,right)
    
    def partition(data,left,right):
        tmp = data[left]
        while left < right:
            while left < right and data[right] >= tmp:
                right -=1
            data[left] = data[right]
            while left < right and data[left] <= tmp:
                left +=1
            data[right] = data[left]
        data[left] = tmp
        return left
    
    @call_time
    def quick_sort(data):
        quick_sort_x(data, 0, len(data)-1)
    
    
    data = list(range(10000))
    random.shuffle(data)
    
    quick_sort(data)
    #Time cost: quick_sort 0.05100655555725098
    

    时间复杂度:O(nlogn)  

  • 相关阅读:
    20191224 Spring官方文档(Overview)
    20191224 Spring官方文档(启动)
    20191209 【归档】Linux就该这么学
    20191209 Linux就该这么学(6)
    20191209 Linux就该这么学(5)
    20191209 Linux就该这么学(4)
    20191209 Linux就该这么学(1-3)
    20191128 Spring Boot官方文档学习【目录】
    加密在卷积神经网络上的应用
    Federated Optimization: Distributed Machine Learning for On-Device Intelligence
  • 原文地址:https://www.cnblogs.com/lianzhilei/p/6538017.html
Copyright © 2020-2023  润新知