第一章:基本概念

news2024/11/24 22:37:26

什么是数据结构 ?

其实官方没有统一定义!!!

“数据结构是数据对象,以及存在于该对象的实例和组成实例的数据元素之间的各种联系。这种联系可以通过定义相关的函数给出。” - Sartaj Sahni 《数据结构、算法与应用》

“数据结构是ADT(抽象数据类型 Abstract Data Type)的物理实现。” - Clifford A.Shaffer 《数据结构与算法分析》

“数据结构(data structure)是计算机中存储、组织数据的方式。通常情况下,精心选择的数据结构可以带来最优效率的算法。” - 中文维基百科

灵魂拷问之如何在书架上摆放图书?

我刚听到这个问题时,第一反应是我知道怎么摆放,就先分类,然后按名称顺序排呗!其实不是的,首先这个问题就不严谨,它没有明确说书架是什么样的,家里的书架能和图书馆的一样嘛!规模差很多的,自然摆放方式就会不同(下面我们考虑如何在图书馆里摆放书籍)。

其实有两个主要的操作(接下来方法的比较将从这两点出发):

1、新书插入
2、找到某本指定书籍

方法 1:随便放

  • 操作 1:新书插入
    哪里有空放哪里,一步到位!
  • 操作 2:找到指定书籍
    …累死找不到

方法 2:按照书名的拼音字母顺序排放

  • 操作 1:新书插入
    新进一本《啊Q正传》 …,完蛋,后面的全部移动一遍
  • 操作 2:找到指定书籍
    二分查找

方法 3:先区域类别划分,然后按照书名顺序排放

  • 操作 1:新书插入
    先定类别,二分查找确定位置,移出空位
  • 操作 2:找到指定书籍
    先定类别,再二分查找

总结:其实书架可以当作是计算机中的存储,而插入规则可以看作是数据的组织方式,此时你应该对数据结构有一定了解了。

什么是算法 ?

算法是指对特定问题求解步骤的一种描述。
算法只是对问题求解方法的一种描述,它不依赖于任何一种语言,既可以用自然语言、程序设计语言(C、C++、Java、Python 等)描述,也可以用流程图、框图来表示。

在我们的生活中,算法无处不在。我们每天早上起来,刷牙、洗脸、吃早餐,都是算着时间,以免上班或上课迟到等。其实这些都是算法。

算法的特征

  1. 有穷性:算法是由若干条指令组成的有穷序列,总是在执行若干次后结束,不可能永不停止。
  2. 确定性:每条语句有确定的含义,无歧义。
  3. 可行性:算法在当前环境条件下可以通过有限次运算实现。
  4. 输入输出:有零个或多个输入,一个或多个输出。

“好”算法具有以下特征:

  1. 正确性:指算法能够满足具体问题的需求,程序运行正常,无语法错误,能够通过典型的软件测试,达到预期的需求。
  2. 易读性:算法遵循标识符命名规则,简洁易懂,注释语句恰当适量,方便自己和他人阅读,便于后期调试和修改。
  3. 健壮性:对非法数据及操作有较好的反应和处理。
  4. 高效性:指算法运行效率高,即算法运行所消耗的时间短。算法时间复杂度就是算法运行需要的时间。
  5. 低存储性:指算法所需要的存储空间低。算法占用的空间大小称为空间复杂度

除了 1-3 中的基本标准外,我们对好的算法的评判标准就是**高效率、低存储

算法复杂性

时间复杂度

算法运行需要的时间,一般将算法的执行次数作为时间复杂度的度量标准。

举个例子:

int sum = 0;                        // 运行1次
int total = 0;                      // 运行1次
for (int i = 1; i <= n; i++) {      // 运行n+1次
    sum += i;                       // 运行n次
    for (int j = 1; j <= n; j++) {  // 运行n*(n+1)次
        total += i*j;               // 运行n*n次
    }
}

把所有语句的运行次数加起来: 1 + 1 + n + 1 + n + n ∗ ( n + 1 ) + n ∗ n 1+1+n+1+n+n*(n+1)+n*n 1+1+n+1+n+n(n+1)+nn,可以用一个函数T(n)表达:
T ( n ) = 2 n 2 + 3 n + 3 T(n)=2n^2+3n+3 T(n)=2n2+3n+3

当 n 足够大时,例如 n = 1 0 5 n=10^5 n=105 时, T ( n ) = 2 × 1 0 10 + 3 × 1 0 5 + 3 T(n)=2\times10^{10}+3\times10^5+3 T(n)=2×1010+3×105+3,我们可以看到算法运行时间主要取决于第一项,后面的甚至可以忽略不计。

注意:不是每个算法都能直接计算运行次数。有些算法,如排序、查找、插入等算法,可以分为最好、最坏和平均情况分别求算法渐近复杂度,但我们考查一个算法通常考查最坏的情况,而不是考查最好的情况,最坏情况对衡量算法的好坏具有实际的意义

空间复杂度

算法占用的空间大小。一般将算法的辅助空间作为衡量空间复杂度的标准。

举个例子:

void swap(int x, int y) 
{
    int temp;
    temp = x;  // temp 为辅助空间
    x = y;
    y = temp;
}

趣味故事:一棋盘的麦子

有一个古老的传说,有一个国王的女儿不幸落水,水中有很多鳄鱼,国王情急之下下令:“谁能把公主救上来,就把女儿嫁给他。”很多人纷纷退让,一个勇敢的小伙子挺身而出,冒着生命危险把公主救了上来,国王一看是个穷小子,想要反悔,说:“除了女儿,你要什么都可以。”小伙子说:“好吧,我只要一棋盘的麦子。您在第 1 个格子里放一粒麦子,在第 2 个格子里放 2 粒,在第 3 个格子里放 4 粒,在第四个格子里放 8 粒,以此类推,每一个格子里的麦子粒数都是前一格的两倍。把这 64 个格子都放好了就行,我就要这么多。”国王听后哈哈大笑,觉得小伙子的要求很容易满足,满口答应。结果发现,把全国的麦子都拿来,也填不完这 64 格…国王无奈,只好把女儿嫁给了这个小伙子。(学好算法能娶到公主!!!

解析:

棋盘上的 64 个格子究竟要放多少粒麦子?

S = 1 + 2 1 + 2 2 + 2 3 + . . . + 2 63 S=1+2^1+2^2+2^3+...+2^{63} S=1+21+22+23+...+263

转换一下

S = 2 64 − 1 S=2^{64}-1 S=2641

据专辑统计,每一麦粒的平均重量约 41.9 毫克,那么这些麦粒的总重量是:

18446744073709551615 × 41.9 = 772918576688430212668.5 (毫克) ≈ 7729 (亿吨) 18446744073709551615\times41.9=772918576688430212668.5(毫克)\approx7729(亿吨) 18446744073709551615×41.9=772918576688430212668.5(毫克)7729(亿吨)

全世界人口按 60 亿计算,每人可以分到 128 吨!

我们称这样的函数为爆炸增量函数,想一想,如果算法时间复杂度是 O ( 2 n ) O(2^n) O(2n)会怎样?随着 n 的增长,这个算法会不会“爆掉”?

常见的算法时间复杂度分类:

  1. 常数阶:运行的次数是一个常数,如 5、20、100。常数阶算法时间复杂度通常用 O ( 1 ) O(1) O(1)表示。
  2. 多项式阶:很多算法时间复杂度是多项式,通常用 O ( n ) 、 O ( n 2 ) 、 O ( n 3 ) O(n)、O(n^2)、O(n^3) O(n)O(n2)O(n3)等表示。
  3. 指数阶:指数阶时间复杂度运行效率极差,程序员往往像躲“恶魔”一样避开它。常见的有 O ( 2 n ) 、 O ( n ! ) 、 O ( n n ) O(2^n)、O(n!)、O(n^n) O(2n)O(n!)O(nn)等。使用这样的算法要慎重,例如上面的趣味故事。
  4. 对数阶:时间复杂度运行效率较高,常见的有 O ( log ⁡ n ) 、 O ( n log ⁡ n ) O({\log}n)、O(n{\log}n) O(logn)O(nlogn)等。

常见时间复杂度函数曲线如图:

在这里插入图片描述

从图中可以看出,指数阶增量随着x的增加而急剧增加,而对数阶增加缓慢。它们之间的关系为:

O ( 1 ) < O ( log ⁡ n ) < O ( n ) < O ( n log ⁡ n ) < O ( n 2 ) < O ( n 3 ) < O ( 2 n ) < O ( n ! ) < O ( n n ) O(1)<O(\log{n})<O(n)<O(n\log{n})<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(n^n) O(1)<O(logn)<O(n)<O(nlogn)<O(n2)<O(n3)<O(2n)<O(n!)<O(nn)

我们在设计算法时要注意算法复杂度增量的问题,尽量避免爆炸级增量。

趣味故事:兔子序列(斐波那契数列)

f ( n ) { 1 , n = 1 1 , n = 2 f ( n − 2 ) + f ( n − 1 ) , n > 2 f(n) \begin{cases} 1, &n=1 \\ 1, &n=2 \\ f(n-2)+f(n-1), &n>2 \end{cases} f(n) 1,1,f(n2)+f(n1),n=1n=2n>2

递归实现:

#include <QCoreApplication>
#include <QTime>

#include <iostream>

using namespace std;

long double fib(int n) {
    long double temp;
    if (n < 1) {
        return -1;
    } else if (n == 1 || n == 2) {
        return 1;
    } else {
        return fib(n - 1) + fib(n - 2);
    }
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    int n = 0;
    cout << "Please input n:" << endl;
    cin >> n;

    QTime timer;
    timer.start();

    int fibn = fib(n);

    cout << "fibn:" << fibn << endl;
    cout << "total time:" << timer.elapsed() << endl;

    return a.exec();
}

但实际你自己输入试试后就会发现,效率十分低,因为它会重复计算很多,看一下 n=50 时候的时间。

在这里插入图片描述

看到这个时间,应该吓一跳吧。如果 n 再大一点的话更吓人!那我们就不使用递归了,换一种算法吧。

循环实现

long double fib(int n) {
    if (n < 1) {
        return -1;
    } else if (n == 1 || n == 2) {
        return 1;
    }

    int s1 = 1;
    int s2 = 1;
    
    for (int i = 3; i <= n; i++) {
        s2 = s1 + s2; // 辗转相加法
        s1 = s2 - s1; // 记录前一项
    }
   return s2;
}

我们使用了若干个辅助变量,迭代辗转相加,每次记录前一项,时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( 1 ) O(1) O(1),是不是比递归好太多了。是不是还有更好的算法呢?那肯定是有的,大家可以自行去研究一下。

数据结构与算法

瑞士著名的科学家 N.Wirth 教授曾提出:数据结构+算法=程序

数据结构与算法之间存在着密切的关系。算法是一种解决问题的方法或步骤,它们通过操作数据结构来实现。算法可以实现各种功能,如插入、排序、搜索、图遍历等。不同的算法对于不同的问题具有不同的时间复杂度和空间复杂度。因此,选择合适的数据结构和算法对程序的性能至关重要。

数据结构与算法的重要性:

  • 它们可以提高程序的执行效率。通过选择适当的数据结构和算法,我们可以降低时间和空间的消耗,减少程序的运行时间。这对于大规模数据处理和复杂应用程序来说尤为重要。

  • 它们有助于提高代码的可读性和可维护性。良好的数据结构和算法设计可以使代码更加清晰和易于理解。这可以帮助开发人员更好地理解代码逻辑,减少出错的可能性,并且方便代码的维护和拓展。

  • 数据结构与算法也是衡量编程能力的重要指标之一。熟练掌握数据结构与算法的知识和技巧,可以提高我们解决实际问题的能力,并且在面试和竞争中具备一定的优势。
    们可以提高程序的执行效率。通过选择适当的数据结构和算法,我们可以降低时间和空间的消耗,减少程序的运行时间。这对于大规模数据处理和复杂应用程序来说尤为重要。

  • 它们有助于提高代码的可读性和可维护性。良好的数据结构和算法设计可以使代码更加清晰和易于理解。这可以帮助开发人员更好地理解代码逻辑,减少出错的可能性,并且方便代码的维护和拓展。

  • 数据结构与算法也是衡量编程能力的重要指标之一。熟练掌握数据结构与算法的知识和技巧,可以提高我们解决实际问题的能力,并且在面试和竞争中具备一定的优势。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/723106.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

期权卖方到期可以不平仓?期权卖方高胜率策略的实战技巧

期权是一种金融衍生品&#xff0c;它给予买方在未来某个时间以特定价格买入或卖出某种资产的权利&#xff0c;而不是义务。期权的卖方则承担了相应的义务&#xff0c;即在买方行使期权时按照约定的价格交割资产。期权的价格叫做期权费&#xff0c;它由期权的内在价值和时间价值…

【设计模式】第二十二章:中介者模式详解及应用案例

系列文章 【设计模式】七大设计原则 【设计模式】第一章&#xff1a;单例模式 【设计模式】第二章&#xff1a;工厂模式 【设计模式】第三章&#xff1a;建造者模式 【设计模式】第四章&#xff1a;原型模式 【设计模式】第五章&#xff1a;适配器模式 【设计模式】第六章&…

怎么用迅捷视频转换器将MP4格式视频转成AVI格式

我们平时看视频的时候&#xff0c;会发现视频都有不同的格式&#xff0c;例如MP4、AVI、MKV等等。其中AVI是一种音频视频交错格式&#xff0c;就是可以将视频和音频交织在一起进行同步播放&#xff0c;这种视频格式的优点是可以跨多个平台使用&#xff0c;在日常生活和工作中&a…

CSDN创作常用操作说明

CSDN创作 目录标题文本样式列表图片连接代码表格UML图Mermaid流程图Flowchart流程图classDiagram类图快捷键 目录 创建目录的方式&#xff1a; [TOC](目录)标题 # 一级标题 ## 二级标题 ### 三级标题 #### 四级标题 ##### 五级标题 ###### 六级标题文本样式 **加粗文本** ~…

NDK编译ffmpeg包含硬件加速vulkan和mediacodec

NDK编译ffmpeg包含硬件加速vulkan和mediacodec flyfish ffmpeg&#xff1a;ffmpeg-6.0 NDK&#xff1a;android-ndk-r25c 硬件加速&#xff1a;vulkan 和 mediacodec target CPU&#xff1a;armv8-a host&#xff1a;Ubuntu 22.04 因为这里要编译硬件加速版本的ffmpeg-6.0&a…

微服务学习2——利用nacos实现服务治理

&#xff08;本文参考黑马程序员项目&#xff09; 个人仓库地址&#xff1a;https://gitee.com/jkangle/springboot-exercise.git 1.当前项目中存在的问题 不同微服务之间的调用通过硬编码的形式&#xff0c;这样可能在需要打量修改的时候出现问题&#xff0c;因此引入了服务…

新版Grafana仪表盘

一 Grafana 是什么 Grafana 是一个开源的指标量监测和可视化工具&#xff0c;常用于展示基础设施的时序数据和应用 程序运行分析。 官网指路&#xff1a; https://grafana.com/ 与前文相关的两个概念&#xff1a; 1&#xff09;数据源&#xff08;Datasource&#xff09;&…

Xcode 15 beta 3 (15A5195k) 发布下载 - Apple 平台 IDE

Xcode 15 beta 3 (15A5195k) 发布下载 - Apple 平台 IDE (visonOS 1 beta 已发布) 7 月 5 日&#xff08;北京时间今日凌晨&#xff09;已发布。 IDE for iOS/iPadOS/macOS/watchOS/tvOS/visonOS 请访问原文链接&#xff1a;https://sysin.org/blog/apple-xcode-15/&#xf…

macOS Sonoma 14 beta 3 (23A5286g) ISO、IPSW、PKG 下载

macOS Sonoma 14 beta 3 (23A5286g) ISO、IPSW、PKG 下载&#xff0c;7 月 5 日&#xff08;北京时间今日凌晨&#xff09;已发布 本站下载的 macOS 软件包&#xff0c;既可以拖拽到 Applications&#xff08;应用程序&#xff09;下直接安装&#xff0c;也可以制作启动 U 盘安…

【PyQt5】构建强大的Python图形用户界面应用程序 -- 入门指南

作者主页&#xff1a;爱笑的男孩。的博客_CSDN博客-深度学习,活动,python领域博主爱笑的男孩。擅长深度学习,活动,python,等方面的知识,爱笑的男孩。关注算法,python,计算机视觉,图像处理,深度学习,pytorch,神经网络,opencv领域.https://blog.csdn.net/Code_and516?typeblog个…

微服务学习3——利用sentinel实现服务器的容错

1.Sentinel服务器容错 &#xff08;本文参考黑马程序员项目&#xff09; 个人仓库地址&#xff1a;https://gitee.com/jkangle/springboot-exercise.git 在服务器中&#xff0c;由于网络原因可能会出现线程阻塞的情况&#xff0c;当线程阻塞的时候如果有大量的请求涌入&#x…

echarts滚动条样式修改

1.修改的样式如下&#xff1a; 2.相关代码 // 基于准备好的dom&#xff0c;初始化echarts实例 const myChart echarts.init(this.$refs.tasksChart) // 绘制图表 myChart.setOption({grid: {top: 4%,left: 12%,right: 4%,bottom: 23%},// tooltip: {// formatter: {b} {c…

【ElasticSearch】JavaRestClient实现索引库和文档的增删改查

文章目录 一、RestClient1、什么是RestClient2、导入demo工程3、数据结构分析与索引库创建4、初始化JavaRestClient 二、RestClient操作索引库1、创建索引库2、删除索引库3、判断索引库是否存在 三、RestClient操作文档1、新增文档2、查询文档3、删除文档4、修改文档5、批量导入…

视觉SLAM-光流法

文章目录 目录 前言 &#x1f31f;光流法的基本原理 &#x1f31f;OpenCV中的光流法实现 &#x1f31f;光流法的应用 &#x1f31f;代码实现 &#x1f349;OpenCV代码 &#x1f349;OpenCV代码 &#x1f31f;总结 前言 当我们观察一个视频或连续帧的图像时&#xff0c…

【Bubbliiiing视频记录】Pytorch 搭建自己的Unet语义分割平台

来源 b站 地址 什么是语义分割 语义分割&#xff1a;对图像每个像素点进行分类 常见神经网络处理过程&#xff1a;Encoder提取特征&#xff0c;接着Docoder恢复成原图大小的图片 UNet整体结构 分为三个部分 主干特征提取部分&#xff1a; 卷积和最大池化的堆叠获得五个初…

Snail-Camunda

gitee地址&#xff1a;snail-camunda 当前版本&#xff1a;V1.0 &#x1f496;&#x1f496;&#x1f496;希望大家动动发财的小手帮忙star一下&#xff0c;感谢&#xff01; ⭐项目介绍 本项目是对Camunda接口…

data和filter协议文件包含

实验目的 通过本实验&#xff0c;了解php封装伪协议&#xff0c;掌握filter协议和data协议的用法 实验环境 操作机&#xff1a;kali 靶机&#xff1a;Windows Server 2003 实验地址&#xff1a;http://靶机ip/exp/include2/filter/ http://靶机ip/exp/include/include3.php…

【C++ OJ练习】1.求和

1.题目链接 求123...n_牛客题霸_牛客网 2.解题思路 利用C构造函数的特性 既然不能使用循环 那么我们可以定义n个对象 就会调用n次构造函数 去代替循环 每次调用的时候进行加法的计算 3.代码 class Sum { public:Sum(){_sum _i;_i;}static void Init(){_i 1;_sum 0;}st…

ruoyi若依 组织架构设计--[ 菜单管理 ]

ruoyi若依 组织架构设计--[ 菜单管理 ] 1. 关于ruoyi组织架构各个表的设计2. 从产品的角度考虑 [ 菜单管理 ]2.1菜单树List页面2.2 菜单树新增2.3 菜单树修改2.4 删除菜单 1. 关于ruoyi组织架构各个表的设计 1.部门表 ancestors字段。 添加这个字段&#xff0c;方便列举所有子…

用maven安装Netty

Netty简单介绍 官网&#xff1a;https://netty.io/index.html Netty是一个异步的、事件驱动的网络应用框架&#xff0c;既可用于开发高性能的服务端&#xff0c;也可用于开发客户端。 Netty是一个NIO的客户端和服务端框架&#xff0c;用于快速、容易地开发网络应用&#xff0c…