热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

数据结构&算法入门

数据类型和算法的简介什么是数据结构与算法数据结构是存储,组织数据的方式算法是完成一个目标的方法和思路为什么要学数据结构与算法?公司的核心价值

数据类型和算法的简介

什么是数据结构与算法

  • 数据结构是存储,组织数据方式
  • 算法是完成一个目标的方法思路

为什么要学数据结构与算法?

  1. 公司的核心价值点起始与数据,数据可以预判趋势,指导方向,解决实际问题,掌握了公司的数据,就掌握了公司运营和发展的命脉
  2. 是做技术的基础中的基础,是高技术人才的必备能力
  3. 装逼利器

简介

  • 什么是数据结构,什么是算法,他们之间的关系,抽象数据类型

  • 数据结构:

    • 数据组织的方式
    • 数据的种类有很多种:整型,浮点型,字符串。。。
    • 数据的组织方式:字典,列表,元组。。。
    • 举例子:数据:‘老王’ 10 ‘男’ 组织方式:列表:[‘老王’,10, ‘男’], 字典{name:’老王’,age:18,gender:’男’}

    数据结构的形式

  • 物理形式
    • 顺序表
    • 链表
  • 逻辑形式

    • 集合,线性,树形,图型

    • 算法

    • 解决问题的方法和思路
    • 公司的核心是数据,数据的组织方式是数据结构,怎么利用这些数据结构完成公司的业务需求,就用到了算法
    • 评判算法的好坏的标准:算法复杂度
    • 时间复杂度:完成一个目标所花费的时间
    • 空间复杂度:完成一个目标所花费的内存空间

数据结构和算法的关系

  • 数据结构+算法 == 程序,也就是业务需求

    • 程序 + 语言 == 编程
  • 举例子:天天生鲜中的图片,商品信息,用户信息这些数据,有各自的组织方式,存储起来,单个的数据是没有意义的,将它们放在需求场景中–开发一个可以访问的,可以购买东西的网站 。数据就有了意义,处理这些数据完成一些功能,如将数据图片存储到fastDFS中的思路和方法就是算法。

抽象数据类型

  • 而纯粹的数据加上对这些数据的操作动作,数据+动作,形成了一个新的东西– 抽象数据类型,abstrat data type(ADT)
    • 抽象数据类型就是将数据和在这个数据上的运算捆绑在一起。
    • 如魂斗罗中的人物是一种数据类型,打子弹是动作,点击空格键使人物发子弹,那么按一下空格键就生成了一个 抽象数据类型:人物打子弹
  • 为什么引入抽象数据类型的概念
    • 为了将数据类型的表示和运算从程序中单独隔离开来,使得他们有自己的独立作用。简单的说,就是将数据代入场景,使数据场景化。

总结:

  • 数据结构:数据的组织方式
  • 算法:解决问题的方法和思路
    • 评判算法的好坏:算法复杂度:事件复杂度,空间复杂度
  • 关系:数据结构+算法==程序,程序+语言==编程
  • 抽象数据结构: 数据场景化

入门

目标:

  • 算法的特性,评判标准
  • 算法复杂度的定义,分类及计算规则
  • 性能分析模块timeit的使用

入门案例

  • 如果a+b+c=1000,且a^2+b^2=c^2(a,b,c为自然数),求出所有a,b,c的组合?

  • 思路:

    • 1.全试,a遍历0-1000,b遍历0-1000,c遍历0-1000,满足两个条件的结果输出
    • 2.试两个,a遍历0-1000,b遍历0-1000,然后输出满足,c=1000-(a+b), a^2+b^2=c^2的所有结果

代码实现:

算法1

import time


start_time = time.time()
for a in range(1001):
    for b in range(1001):
        for c in range(1001):
            if a+b+c==1000 and a**2+b**2==c**2:
                print("满足条件的a,b,c=%d,%d,%d" % (a,b,c))

end_time = time.time()
time_cost = end_time-start_time
print('算法1消耗的时间为:%f'%time_cost)
print('complete')

结果:

算法2

import time

# 猜两个数字
start_time = time.time()
for a in range(1001):
    for b in range(1001):
        c = 1000-a-b
        if a**2+b**2==c**2:
            print("满足条件的a,b,c=%d,%d,%d" % (a, b, c))

end_time = time.time()
time_cost = end_time-start_time
print('算法2消耗的时间为:%f'%time_cost)
print('complete')

结果:
满足条件的a,b,c=0,500,500
满足条件的a,b,c=200,375,425
满足条件的a,b,c=375,200,425
满足条件的a,b,c=500,0,500
算法2消耗的时间为:1.842306
complete
  • 算法的特性:
  • 量入出,题题能解 ,行有意步步可为
  • 五个特性:
    • 入,输入:要有输入
    • 出,输出:要有输出
    • 题题能解,有穷性:代码要在有限的步骤内完成,不能无限循环,且时间可接受
    • 行有意,确定型:算法的每一步都有确定的含义,不会出现二义性
    • 步步可为,可行性:算法的每一步都是可执行的,都是在有限的执行次数内完成的

评判算法的好坏–算法复杂度

  • 上面的解决同一个问题使用的时间::1.842306, 差了 倍。也就是说解决同一个的问题的方法和思路,也就是算法不同,消耗的时间,计算机资源可能会千差万别,那么怎么判断一个算法的好坏呢?–算法复杂度
  • 算法复杂度
    • 时间复杂度:算法完成所耗费的时间
    • 空间复杂度:算法完成所耗费的计算机内存资源

时间复杂度

  • 做一件事需要耗费的时间: 抬手,看一集电视剧,跑完整个马拉松

数学表达方式

  • 大O记法: O(规律)
    • 以之前的例子的算法2为例,执行的次数规律为:n*n*10
    • 若g(n)表示计算次数的规律,则g(n)=n*n*10
    • 使用大O记法就是O(g(n))–>O(n*n*10),假设n无穷大,就可以忽略10这个数字的影响,可计为O(n^2)
    • 使用T(n)表示算法的时间算法复杂度,即T(n)=O(n^2)
    • T(n)=O(n^2)为算法2的渐近时间复杂度,简称为时间复杂度

时间复杂度的分类

  • 最优时间复杂度:算法完成需要的最少步骤操作–梦想
  • 最坏时间复杂度:算法完成需要的最多的步骤操作–工作最低要求
  • 平均时间复杂度:算法完成需要的多少基本操作–没有意义

    工作中跟老板谈的时候,要谈最坏时间复杂度

基本计算规则

  • 常数结构
    • T(n)=O(1):可见的有限的步骤,例子:22岁结婚
  • 顺序结构
    • T(n)=O(n):顺序结构,步骤不可见,但终归是顺序的,可执行完的,例子:22岁前所做的事情
  • 循环结构
    • 简单循环
    • T(n)=O(n^数字):批量执行多次,如上面的例子
    • 递归循环
    • T(n)=O(logn):同样的步骤重复多次:切棍子,一次切一半
  • 分支结构

    • 多分支if语句,找一个时间最长的作为标准时间

      1. 判断一个算法的效率时,往往只需要关注操作数量的最高次项,其他的次要项和常数项可以忽略。
      2. 没有特殊说明,我们所说的算法时间复杂度就是最坏时间复杂度

空间复杂度

  • 是一个算法在运行过程中临时占用存储空间大小的量度
  • 在代码上的表现形式就是,同一个功能的实现,我是用两行代码,还是三行代码,两行代码的空间复杂度就低
  • 只有在代码量非常大的时候,才会考虑空间复杂度
  • 用空间换时间:一个无差别劳动的计件工作,用一个人干,和用8个人干,8个人肯定要快一点,但是用的钱就多一点。有时候,空间复杂度大一点,会节约时间,用空间换时间,也是值得的

示例:

  • 上面的例子中
算法1的时间复杂度:T(n)1 = n^3 算法2的时间复杂度:T(n)2 = n^2 n^2<n^3 算法2的时间复杂度更低一点,则算法2的效率高一点 

常见的时间复杂度

  • 例子(执行步骤) 阶 非正式术语
  • 12 O(1) 常数阶
  • 2n+1 O(n) 线性阶
  • 3n^3+2n^2+3 O(n^3) 指数阶
  • 5log2^n+4 O(logn) 对数阶

  • 时间复杂度函数的图形的趋势越陡,时间复杂度越高

  • 则 :O(1)
  • 时间复杂度越高,执行步越多,耗费时间时间越多效率越低

性能分析模型

  • 掌握timeit模块的使用规则
  • 使用timeit模块测试代码

timeit模块

  • timeit模块是一个用来测试一小段代码的执行速度的模块

  • 核心代码:

代码1:

class timeit.Timer(stmt='pass', setup='pass', timer=)

代码2:

timeit.Time.timeit(number=10000)

  • 代码1详解:

    • Timer是测量小段代码执行速度的类
    • stmt(statement):要测试代码语句块,如果是函数,调用函数的形式
    • 如: 测试函数”fun1“ 就写”fun1()“
    • setup:运行代码时需要的设置
    • 如:测试当前文档的func1语句块 ,就写”from _main_ import func1“
    • timer:一般省略
  • 示例:

time1 = timeit.Time("fun1", "from __main__ import func1")

  • 代码2详解:
  • timeit.Timer.timeit()是Timer类中用来测试语句执行速度的实例方法
  • number表示执行代码的次数
  • 返回执行次数的平均时间,是一个float的秒数

  • 示例:

timeit.Timer.timeit(number=10000)

测试示例

  • 需求:给一个列表里添加1000个数字

  • 方法(算法)

    • 列表的内置属性:list.append()
    • 列表拼接:list1 + list2
    • 列表推导式:[i for i in range()]
    • 列表属性转换:list(range())
  • 代码:

列表的内置属性:list.append()

import timeit
def T1():
  li = []
  for i in range(1000):
  li.append(i)
timer1 = timeit.Timer("T1()","from __main__ import T1")
print("内置属性: %f seconds" % timer1.timeit(number=1000))

内置属性: 0.234965 seconds

列表拼接:list1 + list2

import timeit
def T2():
  li = []
  for i in range(1000):
  li = li + [i]
timer2 = timeit.Timer("T2()","from __main__ import T2")
print("列表拼接: %f seconds" % timer2.timeit(number=1000))

列表拼接: 4.817975 seconds

列表推导式:[i for i in range()]

import timeit
def T3():
  li = [i for i in range(1000)]
timer3 = timeit.Timer("T3()","from __main__ import T3")
print("列表推导: %f seconds" % timer3.timeit(number=1000))

列表推导: 0.085915 seconds

列表属性转换:list(range())

import timeit 
def T4():
  list=list(range(1000))
timer3 = timeit.Timer("T4()", "from __main__ import T4")
print("列表属性:%f second"%timer3.timeit(1000))

属性转换: 0.042624 seconds
  • 可见列表属性的效率最高,因为list()是用C写的

小结

  • 测试代码块的执行速度模块:timeit
  • timeit.Timer(“fun1()”,”from _main_ import fun1”)
  • time = timeit.Timer.timeit(1000)

数据结构

目标

  • 线性表的特性和分类
  • 顺序表形式,结构,示例
  • 三种链表的特性,示例

线性表

定义

  • 将一大堆同类型数据,按照某种关系,一次排列出来,形成的一条线
  • 示例: 100 200 300 400 。。。 n

分类

  • 顺序表
    • 将元素顺序的存放在一块连续的存储区里,元素之间的存储关系由他们的存储顺序自然展示
    • ”排排坐吃果果“
  • 链表
    • 将元素存放在通过链接构造起来的一系列存储块中。也就是说,这种表不但有自己的数据信息,也有下一个数据节点的地址信息。
    • ”吃套餐“

顺序表

表现形式

  • 基本布局
    • 存储同类数据
  • 元素外置
    • 存储不同类数据

基本布局

  • 简单来说,就是存储多个同类型的数据,每个数据占用一个固定存储空间,多个数据组合在一起的时候,物理地址就会连续起来
  • 逻辑地址:m = 起始值 + 偏移量*(元素总数-1)

元素外置

  • 适用于存储不同类型的数据。因为不同类型数据占用存储的空间不一样,不能按照基本布局的方式来存储。
  • 虽然他们的数据占用的空间不一样,但是他们的逻辑地址的数据是相同的数据,可以把他们的逻辑地址存储在一个固定的空间里,然后通过调用新生成的相同类型数据的逻辑地址来找到数据数据的逻辑地址,再通过逻辑地址找到数据本身真正的逻辑地址,通过真正的逻辑地址找到数据数据内容

顺序表结构

  • 基本信息+存储元素
  • 基本信息
    • 地址容量
    • 元素个数
  • 因为顺序表有两种表现形式,所以有两种结构
    • 基本布局:一体式结构
    • 元素外置:分离式结构

一体式结构

这里写图片描述

  • 存储表信息与元素存储区以连续的方式安排在一块存储块里,形成了一个完整的顺序表对象。

  • 特点:

    • 因为整体,所以易于管理,顺序表创建后,元素存储区就固定了

分离式结构

这里写图片描述

  • 顺序表对象里保存的基本信息(地址容量+元素个数)和元素存储空间的一个逻辑地址,通过逻辑地址找到响应数据的真正地址。

  • 特点:灵活,可以随意调整

示例:

  • 我们在设定数据表的时候,会首先申请我要使用的存储空间。而存储空间不是一成不变的。接下来,我们来介绍一下元素存储内容变化时顺序表的变化。

  • 存储内容的变化,无非是少或者多,少会造成存储空间的浪费,多的话,存储空间发生变化。 我们接下来主要是对存储内容更改或者存储内容大于计划空间的这两种情况进行分析。

内容更改

  • 一体式:

    • 因为一体式,基本信息和存储元素是一个整体的对象,而且一旦定义了,就不会再更改了
    • 存储空间一旦大于计划容量,若要存储更多内容,只能整体搬迁,即整个顺序表对象(指存储书序表的结构信息的区域)改变了

    • 示例:
      这里写图片描述

  • 分离式:

    • 因为分离式,基本信息和存储元素是两个独立的对象,它们彼此间使用基本信息后面的逻辑地址来链接,所以存储数据变动,只不过存储的逻辑地址变动,而存储对象中的基本信息没有发生变动,所以,对于顺序表对象来说,没有发生变动

    这里写图片描述

    • 通过上面的两种顺序表结构的内容更新实践案分析,数据发生变动,我们推荐使用分离式顺序表结构,为什么?因为对象没有变动,一体式相当于重新开辟了一片空间,产生了一个新的顺序表对象,没有分离式简单省事。
    • 接下来分析数据内容增加的情况,只分析分离式顺序表结构

空间扩容

  • 采用分离式结构的顺序表,可以在不改变对象的前提下,将数据存储区更换为存储空间更大的区域。所有使用这个顺序表的地方都不必修改。只要程序的运行环境(计算机系统)还有空闲存储, 这种表结构就不会因为数据存储区空间不足满了而导致操作无法进行。人们把采用这种技术实现的顺序表称为动态顺序表,因为其容量可以在使用中动态变化。
  • 目前动态顺序表的库容策略分为两大类:线性增长,倍数增长
线性增长
  • 数据存储区容量一旦发生不足,每次扩充增加固定数目的存储区容量,如每次扩充增加4个元素位置。
  • 特点:
    • 确定性:因为增加数量有限制,所以节省空间
    • 不确定性:扩充操作可能频繁操作,随时发生

这里写图片描述

倍数增长
  • 数据存储区容量一旦发现不足,每次扩容加倍,如:
    • 当前容量8,容量不足的时候,就扩容8,最终容量为16
    • 当前容量为16,容量不足的时候,就扩容16,最终容量为32
    • 。。。
    • 如此循环往复,每次扩充的容量都是相当于当前容量的大小
特点
  • 确定性:每次增加容量会很大,所以扩充操作的执行此说不会频繁发生
  • 不确定性:容量扩容后,可能会造成空间的资源浪费

这里写图片描述

  • 可以看到倍数增长的方式是空间换时间,因为目前的空间代价越来越小,所以我们工作中推荐使用倍数增长的方式来调整容量空间

  • 单一元素的值就是顺序表

顺序表常见操作

  • 增删改查
  • 插头,插尾,乱插
  • 插头插尾:保序增加
  • 乱插:非保序增加,不推荐使用,不容易控制

  • 时间复杂度:

    • 乱插,插尾:O(1)
    • 插头:O(n)
  • 删头,删尾,乱删
  • 删头和删尾为保序删除
  • 乱删为非保序删除,一般不用
  • 事件复杂度
    • 删尾,乱删:O(1)
    • 删头:O(n)

总结

  • 顺序表形式:基本布局(同类元素) + 元素外置(不同类元素)
  • 顺序表结构:一体式 + 分离式(灵活)
  • 顺序表的容量扩容策略:线性(频繁)+倍增(工作推荐)
  • 顺序表元素的增加:头[保序,O(n)] + 尾[保序,O(1)] + 位置 [非保序、O(1)]
  • 删除:头[保序,O(n)] + 尾[保序,O(1)] + 位置[非保序,O(1)]

推荐阅读
  • 本文介绍了在Python3中如何使用选择文件对话框的格式打开和保存图片的方法。通过使用tkinter库中的filedialog模块的asksaveasfilename和askopenfilename函数,可以方便地选择要打开或保存的图片文件,并进行相关操作。具体的代码示例和操作步骤也被提供。 ... [详细]
  • Python瓦片图下载、合并、绘图、标记的代码示例
    本文提供了Python瓦片图下载、合并、绘图、标记的代码示例,包括下载代码、多线程下载、图像处理等功能。通过参考geoserver,使用PIL、cv2、numpy、gdal、osr等库实现了瓦片图的下载、合并、绘图和标记功能。代码示例详细介绍了各个功能的实现方法,供读者参考使用。 ... [详细]
  • 本文介绍了Python爬虫技术基础篇面向对象高级编程(中)中的多重继承概念。通过继承,子类可以扩展父类的功能。文章以动物类层次的设计为例,讨论了按照不同分类方式设计类层次的复杂性和多重继承的优势。最后给出了哺乳动物和鸟类的设计示例,以及能跑、能飞、宠物类和非宠物类的增加对类数量的影响。 ... [详细]
  • 使用nodejs爬取b站番剧数据,计算最佳追番推荐
    本文介绍了如何使用nodejs爬取b站番剧数据,并通过计算得出最佳追番推荐。通过调用相关接口获取番剧数据和评分数据,以及使用相应的算法进行计算。该方法可以帮助用户找到适合自己的番剧进行观看。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • javascript  – 概述在Firefox上无法正常工作
    我试图提出一些自定义大纲,以达到一些Web可访问性建议.但我不能用Firefox制作.这就是它在Chrome上的外观:而那个图标实际上是一个锚点.在Firefox上,它只概述了整个 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • 展开全部下面的代码是创建一个立方体Thisexamplescreatesanddisplaysasimplebox.#Thefirstlineloadstheinit_disp ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 从零学Java(10)之方法详解,喷打野你真的没我6!
    本文介绍了从零学Java系列中的第10篇文章,详解了Java中的方法。同时讨论了打野过程中喷打野的影响,以及金色打野刀对经济的增加和线上队友经济的影响。指出喷打野会导致线上经济的消减和影响队伍的团结。 ... [详细]
  • 也就是|小窗_卷积的特征提取与参数计算
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了卷积的特征提取与参数计算相关的知识,希望对你有一定的参考价值。Dense和Conv2D根本区别在于,Den ... [详细]
  • C++中的三角函数计算及其应用
    本文介绍了C++中的三角函数的计算方法和应用,包括计算余弦、正弦、正切值以及反三角函数求对应的弧度制角度的示例代码。代码中使用了C++的数学库和命名空间,通过赋值和输出语句实现了三角函数的计算和结果显示。通过学习本文,读者可以了解到C++中三角函数的基本用法和应用场景。 ... [详细]
  • 本文介绍了机器学习手册中关于日期和时区操作的重要性以及其在实际应用中的作用。文章以一个故事为背景,描述了学童们面对老先生的教导时的反应,以及上官如在这个过程中的表现。同时,文章也提到了顾慎为对上官如的恨意以及他们之间的矛盾源于早年的结局。最后,文章强调了日期和时区操作在机器学习中的重要性,并指出了其在实际应用中的作用和意义。 ... [详细]
author-avatar
元顿20130208
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有