• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
思想人生从关注生活开始
博客园    首页    新随笔    联系   管理    订阅  订阅

什么是数据结构-常用算法快速入门

抽象

数据结构是在计算机中排列和存储数据以便有效使用它的一种有意义的方式。

本文的范围

说到范围,现在也是放下期望的好时机:

  • 我们从讨论数据结构的类型开始
  • 然后我们简要讨论抽象数据类型
  • 接下来,我们进入标准数据结构操作
  • 探索数据结构的一般优势
  • 最后,解决学习数据结构的重要性

思考

数据结构提供了管理大型数据集(如数据库或互联网索引服务)的方法。

让我们来看看现实生活中的类比...

如果您在杂货店购物,您会期望相关物品位于同一区域,例如水果和蔬菜区域、肉类区域、乳制品区域等。这些项目可以根据其价格等进一步组织。

这种有意义的项目结构有助于企业高效运营。因为您(或任何人)永远不会访问(或重新访问)一家凌乱的商店,在那里需要很长时间才能找到您需要的每一件物品。😔

同样,您也不想使用慢速计算机,搜索旧照片大约需要一天的时间。这就是为什么我们有一个称为“文件系统”的高效数据结构,它将所述数据组织并存储到从根目录开始的层次结构中。

虽然文件系统是一种更高级的数据结构,但它确实试图解决任何数据结构试图解决的基本问题,即存储、组织和维护数据的有效方式。

现在,在继续之前,我们需要确保在谈论某些术语时我们在同一页面上。

基本术语

  • 数据 - 表示可能导致上下文信息的原子值或事实集合,例如单位值 40 或诸如 [(35, 19)、(35, 18)、(30, 18)、(29, 18)、(29, 17)] 之类的集合在孤立的情况下没有意义,但仍然被称为数据。只有当我们关联各自的背景时,例如每公斤苹果的价格。还是 5 天温度预测,我们是否利用原始数据中的信息。
  • 数据库 - 有组织的数据记录,以便有效地使用它,但通常存储在硬盘或永久存储器中,而不是通常存储在RAM或易失性存储器中的数据结构。
  • 算法 - 是一组分步说明,用于执行诸如制作煎蛋卷,打橄榄球,检查素数和阅读本文之类的操作。从洗衣机到自动驾驶汽车,再到曾经采取的每一个确定性行动都可以用算法来表达。
  • 渐近复杂性 - 确定算法在应用于数据结构时计算(相对于输入)的速度。

需要注意的是,我们将主要讨论非原始数据结构;我的意思是你会看到的!😀

数据结构的类型

您可能听说过与数组或链表关联的数据结构。

但是是什么使数组成为数组,它与链表或树有什么不同?

野外有多少种不同的数据结构?🤨

好吧,我在这里告诉您,主要有两种类型的数据结构,即

基元数据结构(也称为内置数据类型)只能存储一种类型的数据。你知道整数,浮点数,字符,指针,诸如此类的东西。

另一方面,非原始数据结构可以存储多种类型的数据。例如,数组、链表、堆栈、队列、树、图形等。这些通常称为派生数据类型。

让我们来看看它的概貌

 

 

 

如您所见,非原始数据结构进一步分为线性和非线性。

线性数据结构再次根据它们是静态的还是动态的进行分类。

如果这还不够,堆栈和队列也可以互换地称为 ADT,而不是具体的数据结构!

等一下,什么!😯

让我们退后一步,首先讨论线性与非线性。

线性数据结构

顾名思义,它的数据必须以线性顺序构建。这意味着没有层次结构,元素通过指针或连续的内存位置按顺序保存在一起。通俗地说,每个元素似乎都以线性方式相互连接。

让我们举一个场景,假设我们想存储我们购买的所有杂货的价格。因此,我们可以分配一个大小为“n”的连续内存块,其中“n”是指我们购买的物品数量。

数组

在这里,数组可能是一个合适的数据结构,因为它只是类似数据类型(如 int、float、char 等)的集合。

由于价格可能是浮动的,我们可以将它们存储在一个数组中,如下所示:

float prices[4] = [20.4, 32.3, 4.5, 27.1];

数组最酷的地方在于它通过从零开始的索引为您提供对每个元素的持续访问。 🙅🏻

为了获得第三个元素的价格,我们可以说价格[2]。

现在,如何存储我们将要购买但提前不知道数量的所有杂货的价格!

由于数组要求您提前指定大小,因此在这里这样的尝试将是徒劳的。

在前面的情况下,请注意,我们必须通过指定 n = 4 来声明大小。我的意思是,你可以争论创建一个足够大的数组,这样我们就永远不会用完空间。

例如,将数组的大小设置为商店中的项目总数或其他东西。然而,直觉表明这将非常低效。另外,请记住,数据结构的唯一目的是通过仔细组织数据来提高效率。

链表

与其提前分配连续的内存块,不如将数据包装在一个节点中,该节点会吐出一个引用,我们可以用来指向下一个节点。

瞧,我们有一个链接节点列表与链表。唉,我们失去了索引!

我们谈论的数据结构越多,你就越会发现没有灵丹妙药,相反,一切都是权衡。

线性数据结构主要分为静态和动态两大类。

  • 静态数据结构 - 此处的数据结构的大小在编译时在内存中分配,从而使分配的大小固定。这导致需要提前知道此类数据结构的最大大小,因为内存无法在以后重新分配。这就是为什么它们被称为静态。
  • 动态数据结构 - 此处的大小在运行时分配,使其灵活。由于内存始终可以根据要求重新分配,因此这些数据结构称为动态。

我认为,可以说,数组是静态数据结构,而链表是动态的!

非线性数据结构

非线性数据结构不是按顺序排列的,因为此类数据结构的每个元素都可以有多个路径来连接到其他元素或形成层次结构。

让我们回到文件系统的例子。可视化它给人的印象是一个颠倒的树状结构,它以父文件夹、子文件夹等的形式保留层次结构。

那么,我们如何使用数据结构构建这样的文件系统呢?

显然,通过使用树状数据结构(又名树)(双关语)。🌲

树

树确实是最重要的数据结构之一,其元素(即节点)之间具有层次结构关系,这些节点通过链接(又称边)连接。如果有帮助,请将树视为链表,但有两个或多个指针。

但是,与循环链表不同,树没有任何循环, ♻

因为如果我们可以像这样循环浏览我们的目录,那就没有任何意义了,

cd ./Desktop/myFolder/Desktop/...

例如,首先搜索计算机中不存在的图片永远不会终止并崩溃整个系统。

 

例如,首先搜索计算机中不存在的图片永远不会终止并崩溃整个系统。

但在某些情况下,我们确实需要这样的循环,或者情况可能有点复杂。

在社交媒体的背景下,这样的表达方式似乎并非闻所未闻;

“我是阳光,小乔朋友的朋友,既然你也跟着小乔,我在想也许我们可以成为朋友,请接受我的请求......”

什么样的数据结构可以对这些错综复杂的关系进行建模?🔍

图

图形包含的节点和边很像树,但更优越和通用。它可以如此强大,以至于它在数学中有一个专门的分支,名为“图论”。😋

图形可以在树的顶部具有循环、不相交和各种灵活性。因此,重要的是要记住,一棵树属于一个特殊的图表类别。

 

 

呵呵,好多...

我希望您已经清楚地了解线性和非线性数据结构之间的主要区别。

但它并不止于此,我们可以通过实现通用对应物来混合匹配并进一步构建越来越多的利基数据结构。

例如,哈希映射可能是实现关联数组抽象数据类型的最有用(有争议的)数据结构,该结构可以将键映射到值。反过来,哈希映射通常建立在链表之上。👁

链表还可以直接实现其他抽象数据类型,例如堆栈和队列。

但是这种抽象数据类型是什么?🤨

抽象数据类型 (ADT)

在计算机科学中,我们经常谈论对接口的抽象和编程。

例如,您无需了解汽车工程即可将汽车开到杂货店。您只需要知道如何驾驶,因为制造商已经抽象出汽车发动机和其他内部机制的所有复杂性。对于驾驶,您确实可以获得方向盘和换档等接口,以便与汽车进行交互。

同样,每个数据结构都有一个相应的接口,称为抽象数据类型或 ADT。简单地说,抽象数据类型只寻址接口,数据结构实现该接口。

队列

例如,队列是一个 ADT,它必须保持元素的先进先出 (FIFO) 顺序。它只是意味着,第一个进入队列的人将是第一个退出队列的人。

队列 ADT 的这种想法可能受到杂货店柜台前的真实站立队列或类似场景的启发。

栈

另一方面,堆栈是符合元素后进先出(LIFO)顺序的ADT的另一个示例。

这个ADT的想法可能受到现实世界的一堆书的启发。📙

 

基本操作

通过讨论数组、链表、堆栈、队列、树、图、哈希图等几种数据结构,我们已经涵盖了很多内容,并且可能暗示了它们各自的用例,但从未真正了解细节。

比如,他们是如何运作的?

好吧,事实证明几乎所有的数据结构都支持一些关键操作......我们接下来要探索的!

搜索

放下手,最有用的操作!如果你不能搜索一个元素,你怎么能做任何事情?

好吧,如果这听起来很模糊,可以这样想——你在杂货店(出于某种原因,我痴迷于杂货店),你正在把物品放入购物车。

在这里,像 50 卢比巧克力棒这样的项目将是您的数据,购物车本身就是一个数据结构。假设你后来忘记了你是否选择了巧克力棒。

你怎么能确定你是否无法搜索?🔎

现在,你可能会声称你的记忆力很敏锐(不像我),你记得把物品放在购物车里,但你怎么能把它展示给柜台呢?

如果您无法搜索它,您怎么能访问它?(周到的锻炼,试一试! 💡

遍历

遍历意味着以某种特定顺序循环访问数据结构。

在数组中,您可以在恒定时间内访问一个元素,即 O(1),前提是您事先知道它的位置!

但这并不意味着您可以在恒定的时间内搜索它。

您仍然需要从第一个索引开始并搜索它。因此,为了搜索,您需要遍历。🏃‍♂️

因此,我们得出结论,遍历也与搜索一样有用。

插入

插入基本上意味着将一个或多个元素插入到数据结构中。元素可以插入到开头、结尾或任何指定位置。

在某些数据结构中,您甚至不需要指定位置,例如在堆中插入。

插入是一个基本操作,因为如果您无法在数据结构中插入任何内容,为什么还要费心呢?

购物车🛒的存在是有原因的,以帮助存储要购买的物品。为了存储它,您必须插入它。

删除

完成购物后,我们需要从购物车中删除商品,将它们展示给柜台,然后将其放入我们的包中(另一种数据结构)。

现在,想象一下我们没有这个操作,所以我们永远无法从购物车中取出任何物品。

似乎是一个我不想生活的悲惨世界!

但是你可以争辩说,你不需要删除数组中的数字来使用它!

因为我们可以访问这样的元素:

float chocolate_bar = cart[35];
eat(chocolate_bar);

好吧,你把我带到了那里!

因此,根据chocolate_bar的数据类型,有两种可能的情况:

  1. 访问它会创建巧克力棒的另一个副本,然后你吃它,但这不太可能,因为它违反了能量守恒定律。
  2. 吃掉购物车本身的巧克力棒,只留下包装纸。

第二种情况是实用的,但效率极低,这与数据结构的存在相矛盾。

我的意思是你可以这样做,但使用支持删除的购物车可能会更好,你可以使用其他数据结构,比如吃盘🍽子和垃圾箱🗑来处理包装纸。

更新

这个建立在搜索和插入的基础上,例如,您突然意识到您购买了错误的巧克力棒,因此您在购物车中搜索了错误的巧克力棒并将其替换为正确的巧克力棒。

现在您可能会说,替换也可以被视为建立在删除和插入之上的操作。

但事实并非如此!

我知道这很奇怪,我的意思是左右谈论违反保护法!

但在这里,我们达到了将物理世界与二元世界类比的极限!

当我说替换时,我的意思是神奇地让旧酒吧消失并通过以下方式改变它的位置:

cart[35] = better_chocolate_bar;

在这里,我们只是搜索了推车,然后发现它在位置 35 上,并用better_chololate杆代替了它。✍🏻

排序

这是一个非常高级的数据结构操作,由于数组的恒定访问和线性排序,数组对于这种操作非常有效。

链表也可以通过操作指针进行排序,因此也可以是树。

一种称为二叉搜索树的特殊排序二叉树是最有用的数据结构之一。

我的意思是,您可以想象并可能欣赏一家杂货店根据价格从左到右将所有类似的商品分类在过道中。

所以,如果你渴望一个昂贵的巧克力棒,你确切地知道该看哪个方向!➡️

合并

这不是一个基本的操作,事实上,它使用其他基本操作来帮助促进所述过程,例如通过操作指针将两个链表合并为一个,或将两个 BST 合并为一个。

从这个角度来看,将两个购物车中的物品放入一个较大的购物车中可能是合并的情况。🛒➕🛒= 🛒

合并也用于最著名的排序算法之一,即合并排序(多么原始)。

数据结构的优势

如果没有使用数据结构的固有好处,我以前的咆哮都没有意义。

但我必须告诉你,这些优点是通用的,并且符合每个数据结构,所以让我们检查一下:

  • 效率 - 所有这些不同的数据结构的存在都是有原因的,即促进各种用例的数据的有效存储和检索。

    例如,按键搜索值比数组更适合哈希映射。

    树更有可能有效地对任何文件系统进行建模,但对于在社交媒体应用程序中表示关系则不有效。

  • 抽象 - 每个数据结构都以操作的形式提供其各自抽象数据类型独有的干净接口,这使得其内部实现对开发人员隐藏。

    你不需要知道STL的unordered_map是如何在幕后工作的,就可以在C++中使用它编写应用程序,你只需要知道它支持哪些操作以及如何利用它来发挥自己的优势?

  • 组合 - 基本数据结构可以组合在一起,以构建更多利基和复杂的数据结构。

    在数据库管理系统中,索引通常使用基于B树的B+树来实现 - 一种特殊的n元自平衡树数据结构。

    事实上,你可以把数据库本身看作是这个巨大的复合数据结构,即使程序已经运行,也能存储数据。

为什么我们需要学习数据结构❓

这是一个合理的问题,因为生活中的许多事情都很重要,但并不是每个人都需要学习一切。 🤗

话虽如此,如果你渴望成为一名软件工程师、机器学习工程师、数据科学家或攻读计算机科学博士学位,你需要了解你的数据结构(以及处理这些数据结构的算法)。

了解数据结构的必要性也可能是一个自我实现的预言,尽管出于错误的原因,但每一点都在发生。

让我解析一下,以便于上下文理解 —

  • 数据结构很重要,所以公司在面试中问他们,要通过它,我们必须学习它。但另一种看待这个问题的方式是——数据结构很重要,所以我们必须学习它们来提高我们解决问题的能力,并在我们各自的工作或破解技术面试中变得更好。

无论你选择哪个镜头都取决于你,但它并不能消除这样一个事实,即数据结构确实是最重要的主题之一,在软件和计算机科学(以及技术面试)中具有重大影响。

 

posted @ 2023-04-12 13:21  JackYang  阅读(188)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3