数据结构与算法


一 数据结构

1.1 线性结构

1.1.1 数组

  • 掌握:熟练掌握数组的创建、访问(随机访问和遍历)、插入和删除操作。了解不同编程语言中数组的实现细节,如在 Java 中数组是定长的,而在 Python 中可以使用列表来模拟动态数组。
  • 理解:明白数组在内存中是连续存储的,这使得随机访问效率很高,但插入和删除元素时(特别是在中间位置)需要移动大量元素,时间复杂度较高。例如,在一个有序数组中插入一个元素,平均需要移动 n/2 个元素(n 为数组长度)。

1.1.2 链表

  • 掌握:能熟练实现单链表、双链表和循环链表的基本操作,包括节点的创建、插入、删除和链表的遍历。例如,在单链表中删除指定节点,需要找到该节点的前一个节点来修改指针。
  • 理解:理解链表的优点是插入和删除操作相对灵活,不需要移动大量元素,时间复杂度为 O (1)(在已知节点位置的情况下)。但链表不支持随机访问,要访问第 n 个元素需要遍历 n 个节点,时间复杂度为 O (n)。

1.2 非线性结构

1.2.1 栈和队列

  • 掌握:清楚栈(先进后出)和队列(先进先出)的操作特性,能够使用数组或链表实现栈和队列。例如,在解决括号匹配问题时可以使用栈,将左括号依次入栈,遇到右括号时与栈顶元素进行匹配。
  • 理解:明白栈在函数调用、表达式求值等场景中的应用,队列在任务调度、缓冲等方面的作用。比如在操作系统中,进程调度队列就是一个典型的队列应用场景。

1.2.2 树

树的高度: 从根节点到叶子节点最长路径上的节点数

  • 二叉树: 二叉树是一种特殊的树结构,它的每个节点最多有两个子节点。二叉树具有一些特殊的性质,如满二叉树(所有层的节点数都达到最大值)和完全二叉树(除了最后一层外,其他层的节点数都达到最大值,且最后一层的节点从左到右依次排列)。

    二叉树的遍历方式包括前序遍历(根节点 - 左子树 - 右子树)、中序遍历(左子树 - 根节点 - 右子树)、后序遍历(左子树 - 右子树 - 根节点)。这些遍历方式在不同的应用场景中有重要作用,例如在表达式求值、构建二叉搜索树等方面。

  • 二叉搜索树(BST):
    二叉搜索树是一种有序的二叉树,对于树中的任意节点,其左子树中的所有节点值都小于该节点值,其右子树中的所有节点值都大于该节点值。这使得在二叉搜索树中进行搜索、插入和删除操作的平均时间复杂度为 O (log n)。

    然而,二叉搜索树可能会出现不平衡的情况,导致最坏情况下的时间复杂度退化为 O (n)。为了解决这个问题,引入了平衡二叉树。

  • 平衡二叉树: 平衡二叉树是一种特殊的二叉搜索树,它的左右子树的高度差绝对值不超过 1。常见的平衡二叉树包括 AVL 树和红黑树。

    在插入和删除节点时,需要通过旋转操作来调整树的平衡。红黑树则是一种更复杂的平衡二叉树,它通过一些特定的颜色规则和旋转操作来保证树的平衡。红黑树在插入和删除节点时的旋转操作相对较少,因此在实际应用中更为广泛,例如在 C++ 的 STL 中的map和set底层实现就是基于红黑树。

  • B 树: B 树是一种多路平衡查找树,它的每个节点可以有多个子节点(通常称为阶,m 阶 B 树表示每个节点最多有 m - 1 个关键字和 m 个子节点)。B 树适合用于磁盘等外部存储设备上的数据存储和检索,因为它可以减少磁盘 I/O 次数。

  • B + 树: B + 树是 B 树的一种变体,它在 B 树的基础上进行了优化。非叶子节点只存储索引信息,所有的关键字都存储在叶子节点中;叶子节点之间通过指针连接,形成一个有序链表;每个叶子节点包含了关键字和指向对应数据记录的指针。

  • 哈夫曼树: 哈夫曼树是一种带权路径长度最短的二叉树,也称为最优二叉树。它通常用于数据压缩领域,例如哈夫曼编码。通过给每个字符分配一个基于哈夫曼树的编码,可以实现高效的数据压缩。

1.2.3 图

  • 图的基本概念

    • 图是由顶点(vertex)和边(edge)组成的一种数据结构。边可以是有向的(directed)或无向的(undirected)。例如,在一个社交网络中,可以将每个用户看作一个顶点,用户之间的朋友关系看作无向边;在一个流程图中,各个步骤可以看作顶点,步骤之间的先后顺序可以看作有向边。

    • 图的表示方法主要有邻接矩阵(adjacency matrix)和邻接表(adjacency list)。邻接矩阵是一个二维数组,用于表示顶点之间的连接关系;邻接表则是一个链表数组,每个链表存储与一个顶点相邻的顶点信息。

  • 图的遍历

    • 深度优先搜索(DFS)通常使用栈(递归本质上利用了系统栈)来存储待探索的节点。它先深入到图的某一分支,直到不能再深入才回溯。例如,在一个迷宫问题中,可以将迷宫中的每个位置看作一个顶点,相邻位置之间的通道看作边,使用深度优先搜索来寻找从起点到终点的路径。
    • 广度优先搜索(BFS)使用队列来存储节点。它按照距离起始节点的远近,一层一层地向外扩展探索节点。

二 算法

时间复杂度:衡量算法运行时间随输入规模增长的增长趋势。例如,一个算法的时间复杂度为O(n的平方)意味着当输入规模n增大时,算法运行时间大致以n的平方的速度增长。通过分析时间复杂度,可以比较不同算法在处理大规模数据时的效率。
空间复杂度:表示算法运行过程中所需的额外存储空间与输入规模之间的关系。

2.1 排序算法

  • 冒泡排序、选择排序、插入排序:这三种算法是简单直观的排序算法。冒泡排序通过反复交换相邻元素,将最大(或最小)元素逐步 “冒泡” 到数组的一端;选择排序在每一轮选择未排序部分的最小(或最大)元素,放到已排序部分的末尾;插入排序则是将未排序元素逐个插入到已排序部分的合适位置。它们的时间复杂度均为O(n的平方),适用于小规模数据的排序或者作为更复杂排序算法的组成部分。

  • 快速排序:快速排序基于分治策略,选择一个基准元素,将数组分为两部分,小于基准和大于基准的元素分别放在两边,然后对这两部分递归地进行排序;快速排序的平均时间复杂度为O(nlogn),最坏情况为O(n的平方);

  • 快速排序:建立在归并操作上的一种有效的排序算法,是采用分治法(Divide and Conquer)的一个非常典型的应用。

    • 分治策略:将一个数组分成两个子数组,然后对每个子数组继续细分,直到每个子数组只包含一个元素(这是最小规模的子问题,因为一个元素的数组本身就是有序的)。
      例如,对于数组 [8, 4, 5, 7, 1, 3, 6, 2],首先将其分为 [8, 4, 5, 7] 和 [1, 3, 6, 2] 两个子数组,然后继续将 [8, 4, 5, 7] 分为 [8, 4] 和 [5, 7],将 [1, 3, 6, 2] 分为 [1, 3] 和 [6, 2],以此类推,直到每个子数组只有一个元素。

    • 合并过程:当子数组被细分到只有一个元素后,开始两两合并这些有序的子数组,使得合并后的数组仍然有序。
      例如,将 [8] 和 [4] 合并为 [4, 8],将 [5] 和 [7] 合并为 [5, 7],然后再将 [4, 8] 和 [5, 7] 合并为 [4, 5, 7, 8]。

    • 合时间复杂度:归并排序的时间复杂度是 。无论数组的初始顺序如何,归并排序都会将数组不断地分割和合并,每次分割都会使问题规模减半,而每次合并操作的时间复杂度与子数组的总长度成正比。

    • 合空间复杂度:归并排序的空间复杂度是 ,因为在合并过程中需要额外的空间来存储临时的有序数组。

    • 算法稳定性:合归并排序是一种稳定的排序算法。在合并两个子数组时,如果两个元素相等,那么在合并后的数组中它们的相对顺序保持不变。例如,如果原数组中有两个相同的元素,在排序后它们的顺序与在原数组中的顺序相同。

2.2 搜索算法

  • 线性搜索:简单地从数组的一端开始,逐个元素地检查,直到找到目标元素或者遍历完整个数组。它的时间复杂度为O(n),适用于无序数组或者不知道数组是否有序的情况。
  • 二分搜索:要求数组是有序的,通过不断将搜索区间缩小一半来查找目标元素。每次比较中间元素与目标元素的大小关系,从而确定目标元素在左半区间还是右半区间。它的时间复杂度为O(logn),大大提高了搜索效率。

2.3 贪心算法

贪心算法在每一步选择中都采取当前状态下的最优决策。比如在活动选择问题中,每次选择结束时间最早的活动,从而在有限的时间内安排最多的活动。但贪心算法并不总是能得到最优解,需要满足一定的贪心选择性质和最优子结构性质。

2.4 动态规划算法

动态规划是解决多阶段最优化问题的一种方法。它将原问题分解为若干个子问题,保存子问题的解以避免重复计算。例如在计算斐波那契数列时,如果使用递归方式会有大量重复计算,而使用动态规划可以将计算过的中间结果保存起来,提高效率。其核心是状态转移方程,通过定义合适的状态和状态之间的转移关系来求解问题。

2.5 回溯算法

回溯算法是一种穷举搜索的方法,通过深度优先搜索的方式遍历所有可能的解空间。在搜索过程中,当发现当前路径不可能得到解时,就回溯到上一步,尝试其他的选择。例如在解决数独问题、八皇后问题等组合优化问题中经常使用回溯算法。

2.6 A * 算法的应用

A * 算法结合了 Dijkstra 算法和启发式搜索的思想。它在评估每个节点的优先级时,不仅考虑从起点到当前节点的实际代价,还考虑一个启发式函数对从当前节点到目标节点代价的估计值。

在物流中的体现:在物流配送过程中,当需要从一个配送点前往另一个特定的配送点时,A算法可以更智能地规划路径。启发式函数可以根据实际情况进行定义,比如使用两点之间的直线距离作为启发式信息(因为直线距离通常是两点间最短路径的下限)。在搜索过程中,A算法会优先探索那些具有较低综合代价(从起点到当前节点的实际代价 + 启发式估计值)的节点。这样可以更快地找到一条较优的路径,特别是在复杂的道路网络中,能够更高效地引导配送车辆朝着目标配送点前进,减少探索的盲目性,提高配送效率。同时,通过优化路径,也能降低车辆的油耗、磨损等成本。

2.7 最短路径算法

  • Dijkstra 算法是一种用于计算图中一个节点到其他所有节点最短路径的贪心算法。它从源节点开始,逐步探索相邻节点,并更新到每个节点的最短距离。

    在物流中的体现:在物流配送系统中,以仓库所在的配送点作为源节点,算法会依次考察从源节点出发能够直接到达的配送点(即相邻节点),计算到达这些配送点的距离(如果只考虑距离因素,就是实际的地理距离;如果考虑时间成本,可能还需要结合道路的通行速度等因素)。然后,将这些距离与之前记录的到其他配送点的最短距离进行比较,如果新计算的距离更短,则更新最短距离。随着算法的推进,不断地将新的配送点纳入到已探索的范围中,直到所有的配送点都被探索完毕。这样就能得到从仓库到各个配送点的最短路径信息,配送车辆可以根据这些信息选择最佳的配送路线,减少不必要的行驶距离,从而降低物流成本,提高效率。

  • Floyd - Warshall 算法用于求解图中任意两点之间的最短路径问题,它可以处理带负权边的图,但不能处理存在负权回路的图。例如,在一个航班航线图中,将各个机场看作顶点,航线的价格看作边的权值,使用 Floyd - Warshall 算法可以找到任意两个机场之间的最便宜的航班组合。

2.8 最小生成树算法**

  • Prim 算法从图的任意一个顶点开始,每次选择与当前生成树相连的权值最小的边,将其加入生成树中,直到所有顶点都被包含在生成树中。Prim 算法适用于边比较密集的图。例如,在一个电力网络规划中,将各个村庄看作顶点,村庄之间铺设电线的成本看作边的权值,使用 Prim 算法可以找到连接所有村庄且成本最小的电线铺设方案。
  • Kruskal 算法将图中的所有边按照权值从小到大排序,然后依次选择边加入生成树中,但要保证加入的边不会形成回路,直到生成树包含了图中的所有顶点。Kruskal 算法适用于边比较稀疏的图。例如,在一个通信网络建设中,将各个通信基站看作顶点,基站之间建立通信链路的成本看作边的权值,使用 Kruskal 算法可以找到连接所有基站且成本最小的通信链路布局。

2.9 加密算法

2.9.1 对称加密算法

  • DES(Data Encryption Standard):这是一种较旧的对称加密算法,密钥长度为 56 位。由于其密钥长度相对较短,安全性逐渐受到挑战,但在一些旧的系统中可能仍在使用。
  • 3DES(Triple DES):是对 DES 的改进,使用三个不同的密钥对数据进行三次加密,提高了安全性。它的密钥长度为 168 位(实际上有效密钥长度为 112 位)。
  • AES(Advanced Encryption Standard):目前广泛使用的对称加密算法,密钥长度可以是 128 位、192 位或 256 位。AES 具有高效、安全的特点,被广泛应用于各种安全领域。

2.9.2 非对称加密算法

  • RSA(Rivest-Shamir-Adleman):一种非常流行的非对称加密算法,它使用一对密钥,即公钥和私钥。公钥用于加密数据,私钥用于解密数据。RSA 密钥长度可以根据安全需求进行选择,一般为 1024 位、2048 位或更高。
  • DSA(Digital Signature Algorithm):主要用于数字签名,但也可以用于加密。DSA 使用一对密钥,与 RSA 类似,但它的主要用途是生成数字签名,以确保数据的完整性和真实性。

2.9.3 哈希算法

  • MD5(Message Digest 5):一种广泛使用的哈希算法,它将任意长度的消息压缩成 128 位的哈希值。然而,由于 MD5 存在安全漏洞,现在不建议用于安全关键的应用。
  • SHA-1(Secure Hash Algorithm 1):也是一种哈希算法,生成 160 位的哈希值。与 MD5 一样,SHA-1 也存在安全问题,逐渐被更安全的哈希算法所取代。
  • SHA-256、SHA-384、SHA-512:这些是更安全的哈希算法,分别生成 256 位、384 位和 512 位的哈希值。它们在安全性方面比 MD5 和 SHA-1 有了很大的提高,被广泛应用于各种安全领域。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值