数据结构(data-structure)和算法(algorithm)一

138 阅读7分钟

数据结构(data-structure)和算法(algorithm)一

初步认识算法(algorithm)

  • 数据结构是由组织和存储数据的方式,算法就是解决问题的一系列步骤和规则

  • 数据结构关注着数据段额组织和存储方式,它定义了数据元素之间的关系、操作和访问方式

    • 常见的数据结构含有:数组,链表、栈、队列、数、图
    • 不同的数据结构适用于不同的不同的应用场景,他们具备了各自的优缺点和适用性
  • 算法就是解决问题的一些列操作以及规则,它描述了如何通过一系列的操作来转换输入数据为输出结果

    • 算法可以用于搜索、排序、计算、优化等各种问题的处理
    • 算法的优秀性的话体现在其代码的正确性、效率、可读性、可维护性等特点
  • 数据结构和算法之间密切关联,他们相互影响并且作用于问题的解决,选择核时的数据结构可以提高

    • 算法的效率和性能
    • 高效算法的设计可以充分的利用数据结构的特性

如何区分代码的优劣呐???

  • 不同的程序解决问题的方式不同

    • 这个时候,我们就需要对代码进行评审
    • 代码的可读性,可维护性
    • 代码的运行效率等等都是有关系的

算法一 —— 高斯公式求和

遍历求和

"""
    累加求和: 1-1000,10000, 100000
"""
import time
​
# 开始书写一个工具函数来实现判断我们的算法的运行时间
def get_time(fn):
    def run(number, *args, **kwargs):
        start_time = time.time()
        fn(number, *args, **kwargs)
        run_time = time.time() - start_time
        print("函数运行时间为: %10.15f" % run_time)
    return run
​
​
@get_time
def my_sum(number, *args, **kwargs):
    count = 0
    for i in range(1, number + 1):
        count += i
    print(count)
​
​
my_sum(1000)  # 0.000000000000000
my_sum(10000)  # 0.000996351242065
my_sum(100000)  # 0.002002477645874

从上方面的简单的例子,我们就可以知道一点,我们的程序的运行时间是从数字的大小来间接性的决定了运行时间了

这个就用的是我们的线性的结构的算法,但是有没有一种更加好用的算法来实现求取数字之和呐?????

这个时候就出现了使用我们的高斯公式来实现求取我们的数字之和了

高斯公式求和

"""
    累加求和: 1-1000,10000, 100000
"""
import time
​
# 开始书写一个工具函数来实现判断我们的算法的运行时间
def get_time(fn):
    def run(number, *args, **kwargs):
        start_time = time.time()
        fn(number, *args, **kwargs)
        run_time = time.time() - start_time
        print("函数运行时间为: %10.15f" % run_time)
    return run
​
​
@get_time
def my_sum_by_gao_si(number, *args, **kwargs):
    # 高斯就是使用的是: 数字累加,使用 (首项 + 尾项) * 项数 / 2
    count = (1 + number) * number / 2
    print(count)
​
my_sum_by_gao_si(1000)  # 0.000000000000000
my_sum_by_gao_si(10000)  # 0.000000000000000
my_sum_by_gao_si(100000)  # 0.000000000000000

我们的一个程序的运行的效果的话就是实现的使用我们的一些特定的算法来实现的

那么一个程序中如何理解我们的人为的判断我们的代码的运行速度呐???

  • 程序运行的步骤

    • 从共享变量中拷贝一份出来进入自己的内存空间
    • 对其进行运算操作
    • 回写进共享内存
  • 这个时候,在程序中的赋值的次数就是来人为的判断一个程序的运行效率的标准之一了

  • 对于累加实现的求和的效果的话就是

    • 时间复杂度就是:

      • count = 0 这里是一次 1
      • count = count + i 这里就是 1 * N
      • 那么最后的时间复杂度就是: 1 + N
      • 这个时候,时间复杂度就可以简单的理解为是一个线性的变化,这个时候 N 就是程序的运行规模
  • 利用高斯公式实现求和的效果

    • 时间复杂度的话:

      • count = (1 + number) * number / 2 只有一次的赋值次数 1
      • 这个时候,我们的计算的规模就是固定的 1,这种求和的算法就不会随着问题的规模增长而增长
      • 时间复杂度这个时候就是常量级了,并不会随着程序的规模的增大而增大了

但是需要i注意的是我们的相同的算法的话,使用不同的编程语言进行书写,这个时候体现出来的效果又有所不同了

所以说最后我们的算法的评估应该忽略存在的外部因素的(编程语言的不同就是一个外部因素

Golang | Python | Java | JavaScript | C++ | C

算法二 —— 百钱百鸡

  • 问题描述

    a + b + c = 1000

    num01 ** 2 + num02 ** 2 == num03 ** 2

    求取所有的 a, b, c 的组合数目

使用穷举法求取组合数

通过上面的我们可以得到的信息的是:

三个数字的话满足的条件是: 每个数字的范围是在 1000 以内的

第二个需要满足的条件是: a + b + c == 1000

第三个需要满足的条件使: num01**2 + num02**2 == num03**2

"""
    a + b + c = 1000
    a^2 + b^2 = c^2
    求取所有的 a, b, c 的组合
"""
import time
​
# 开始书写一个工具函数来实现判断我们的算法的运行时间
def get_time(fn):
    def run(num, *args, **kwargs):
        start_time = time.time()
        fn(num, *args, **kwargs)
        run_time = time.time() - start_time
        print("函数运行时间为: %10.15f" % run_time)
    return run
​
​
@get_time
def get_times(num, *args, **kwargs):
    """
    穷举法
    :param num: 规定数字
    :return:
    """
    count = 0
    # 第一种方法: 使用穷举实现
    for num01 in range(1, num + 1):
        for num02 in range(1, num + 1):
            for num03 in range(1 + num + 1):
                if num01 + num02 + num03 == 1000 and num01**2 + num02**2 == num03**2:
                    count += 1
    print(f"符合条件的组合有 {count} 个")
​
get_times(1000)  # 36.302951097488403
  • 这种题目使用穷举法实现的时候的问题的总规模:

    • 就是我们的使用赋值次数为:N
    • 本次的算法枚举的话: T = N * N * N = 1000 * 1000 * 1000
    • 这个时候的时间复杂度的规模就是 N的三次方

算法优化

这个时候,我们就可以通过总数来实现获取我们的组合数, c = 1000 - a- b

通过这一步的运算,我们就可以实现一点的是,时间复杂度就从 N的三次方 转化为 N的二次方

"""
    a + b + c = 1000
    a^2 + b^2 = c^2
    求取所有的 a, b, c 的组合
"""
import time
​
# 开始书写一个工具函数来实现判断我们的算法的运行时间
def get_time(fn):
    def run(num, *args, **kwargs):
        start_time = time.time()
        fn(num, *args, **kwargs)
        run_time = time.time() - start_time
        print("函数运行时间为: %10.15f" % run_time)
    return run
​
​
@get_time
def get_times(num, *args, **kwargs):
    count = 0
    # 第一种方法: 使用穷举实现
    for num01 in range(1, num + 1):
        for num02 in range(1, num + 1):
            num03 = 1000 - num01 - num02
            if num01 + num02 + num03 == 1000 and num01**2 + num02**2 == num03**2:
                count += 1
    print(f"符合条件的组合有 {count} 个")
​
get_times(1000)  # 0.445182800292969

所以说通过上面的两个简单的小例子,我们就可以知道一点的是,我们的一个代码的优劣评判的标准就是

一个程序的运行时间来进行的一个初步的判断的

这个就是我们的算法复杂度问题了!!!

通过算法复杂度可以初步的判断一个程序的代码的优劣情况