数据结构

数据结构

数组

优点:可以随机访问

​ 随机访问是数组的强项,因为它们的元素在内存中是连续排列的。这种连续的排列方式使得数组中的任何元素能够在O(1)的时间内通过其索引访问。

缺点:编译时就确定了大小,插入删除的复杂度高都为o(n)便于查找某个元素(二分法)

链表

优点:易于插入和删除元素,可以动态的分配空间

​ 链表,除了销毁链表操作外,其他的操作都具有O(1)的运行时复杂度。

缺点:但是不能随机访问只能顺序访问查找元素不方便(必须遍历链表)

​ 想得到指向链表中某个特定元素的指针其代价是很高的。例如,在最坏的情况下,可能需要遍历整个链表,此时的开销就是O(n),这里n代表链表中的元素个数。

链表的例子:页帧管理

​ 虚拟内存是一种地址空间的映射机制,它允许进程(运行的程序)不必完全加载到物理内存(系统的实际内存)中也可以得到运行。这种方式的一个优点是进程可以使用比系统实际所允许的物理内存大得多的地址空间。另一个优点是多个进程能够共享系统的内存以并发的每一个进程都有它自己的页表,将它的虚拟地址空间中的页映射到物理内存中的页帧上。当某个进程引用一个虚拟地址时,页表中的某项需要检查并决定该页关联到哪个物理页帧上(见图5-5)。当进程引用一个不在物理页帧上的虚拟地址时,会导致系统产生一个页错误并为之在物理内存中分配一个页帧。

​ 某些时候我们不得不面对必须去替换某些页面到交换磁盘的情况,那么,最适合操作系统替换的页面应该就是在未来最长的一段时间内都不会再次访问的那些页面,使用最近最少使用算法(LeastRecentlyUsed),或者LRU页面替换法。

​ 当需要某个页帧时,操作系统就使用它维护的循环链表以及引用值来判断哪些页面应该释放其页帧。为了确定这一点,开始遍历链表直到找到一个引用值为0的元素。当遍历每一个页面时,操作系统将页面的引用值从1重设回0。一旦它遇到引用值为0的元素,它就找到了一个自从上次遍历链表以来都没有被系统访问过的页面,因此这个页面就是最近最少使用的页面。那么这个页面就在物理内存中和新的页面置换,新的页面被插入链表中原来页面的位置。如果自从算法上次运行以来,所有的页面都被访问过了,那么操作系统就完整地遍历了一次链表,此时就置换它开始的页面。

栈(后进先出)和队列(先进先出)就是链表的一种

栈和队列的一些应用:

队列

事件处理:

​ 在实时系统中,当事件频繁发生时,系统往往并没有完全准备好去处理它们。而队列可以记录事件的信息,并在稍后将发生的事件按接收顺序一一处理。

c函数的调用

​ 当在C程序中调用一个函数时,一个包含调用信息的活动记录被压入一个栈中,这个栈称为程序栈。当此函数结束时,它的活动记录会从程序栈中弹出。栈是记录函数调用过程的完美模型,因为函数的调用过程与函数的返回过程是相反的,这与栈的特性相吻合。

哈希表

​ 支持一种最有效的检索方法:散列。从根本上来说,一个哈希表包含一个数组,通过特殊的索引值(键)来访问数组中的元素。哈希表的主要思想是通过一个哈希函数,在所有可能的键与槽位之间建立一张映射表。哈希函数每次接受一个键将返回与键相对应的哈希编码或哈希值。键的数据类型可能多种多样,但哈希值的类型只能是整型。

链式哈希表从根本上来说是由一组链表构成。每个链表都可以看做一个“桶”,我们将所有的元素通过散列的方式放到具体的不同的桶中(见图8-1)。插入元素时,首先将其键传入一个哈希函数(该过程称为哈希键),函数通过散列的方式告知元素属于哪个“桶”,然后在相应的链表头插入元素。查找或删除元素时,用同样的方式先找到元素的“桶”,然后遍历相应的链表,直到发现我们想要查找的元素。

选择哈希函数

取余法

h(k)=k mod m 或者乘法

在这里插入图片描述

​ 链式哈希表是一种用来实现符号表的好方法,因为除了它能高效地存放和检索信息之外,事实上它还能用来存储无限量的数据。为了能够更加有效地管理程序中的符号信息,编译器通常使用一种叫做符号表的数据结构。

开地址哈希表的描述(数组构成)

​ 在开地址哈希表中,元素存放在表本身中。这种特性对于某些依赖于固定大小表的应用来说非常有用。在开地址哈希表中解决冲突的方法就是探查这个表,直到找到一个可以放置元素的槽。线性探查的优点是简单,而且它对m没有限制,这样就可以保证所有的槽位最终都可能探查到。这种过度的探查会降低表的性能。

​ 双散列最有效地探查开地址哈希表的方法之一,就是通过计算两个辅助哈希函数哈希编码的和来得到哈希编码。双散列的优点是,它能够在表中探查并产生较好的元素分布(见图8-3)。其缺点是,必须限制m的值,这样才能保证在一系列探查中访问表中所有槽之后才会再次探查任何槽。

二叉树

​ 二叉树是一种将结点按照层次结构组织起来的数据结构,每个结点最多只有两个与它直接相关联的子结点。二叉树中的每一个结点都包含3部分:一个数据成员和两个左右指针。通过这种3个成员的结构体,将每个结点的左右指针分别指向该结点的子结点,以此来构建一棵二叉树。

​ 如果满足树的所有叶子结点都在同一层上,或者所有叶子结点都在最后两层上,且倒数第二层是满的,则这棵树是平衡的。

4种周游算法
  1. 先序遍历:根左右
  2. 中序遍历:左根右
  3. 后序遍历:左右根
  4. 层遍历:首先访问树的根,然后依次向下层处理,按照从左到右的顺序访问每层的结点。
二叉搜索树

​ 二叉搜索树是由二叉树组成的专用于查找和搜索目的的高效数据结构,因为在最坏的情况下,只需要查找一个分支上的数据就可以了,而不用检索每一个数据。因此,查找操作的复杂度是O(lgn),这里n代表树中的结点个数。

​ 是一棵二叉树,通常其子结点存储的值比父结点的值小。所以,根结点是树中最大的结点。成为了我最大值堆。子节点比父节点大的,根节点最小,成为最小值堆。

优先队列

​ 优先队列将数据按照优先级顺序排列。一个优先队列由许多有序的元素构成,所以优先级最高的元素可以有效而快速地确定。

​ 最常用而简单的方法就是维护一个有序数据集。在这个有序数据集中,优先级最高的元素位于数据集的头部。然而,插入或提取元素之后必须重新排列数据集,这是一个复杂度为O(n)的操作(n为数据集元素的个数)。因此,更好的方法就用一个局部有序的堆来实现优先队列。插入或提取数据之后重新排列堆的复杂度仅为O(lgn)。

应用:包裹分拣

​ 优先队列是用来管理包裹的最佳方法,因为某些场合,我们只关心下一个优先级最高的包裹是哪一个。这样,可以避免维护包裹完全有序的系统开销。

​ 一种灵活的数据结构,一般作为一种模型用来定义对象之间的关联或联系。图由两种类型的元素组成:顶点和边。顶点代表对象,边则建立起对象之间的关系或关联。

​ 我们主要通过邻接表链表结构来表示图。链表中的每个结构体都包含两个成员:一个顶点以及与该顶点相邻接的一个顶点集合。图中的两个重要关系是邻接和关联。顶点的入度指的是以该顶点为终点的边的数目。而顶点的出度指的是以该顶点为起点的边的数目。在无向图中,顶点的度就是与该顶点相关联的边的数目。

​ 没有重复顶点的路径称为简单路径。环是指路径包含相同的顶点两次或两次以上。如果它的每个顶点都能通过某条路径到达其他顶点,那么我们称它为连通的。如果移除某个顶点将使得图或某分支失去连通性,则称该顶点为关结点。如果移除某条边会使得图失去连通性,则称该边为桥。

广度优先搜索

​ 广度优先搜索在进一步探索图中的顶点之前先访问当前顶点的所有邻接结点。

常用来解决最小生成树以及最短路径问题

深度优先搜索

​ 深度优先搜索在搜索过程中每当访问到某个顶点后,需要递归地访问此顶点的所有未访问过的相邻顶点。因而,这种搜索将尽可能深地持续探索,直到无法继续为止。

​ 应用环检测以及拓扑排序。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值