存储各数据块的应用场景(深入讲解块设备的主要数据结构)
存储各数据块的应用场景(深入讲解块设备的主要数据结构)(3)索引存储:在存储时,还附加建立索引表,索引表中的每一项称为索引项,索引项的一般形式是(关键字,地址)优点:检索速度快缺点:索引表占用存储空间,并且插入和删除一个数据时,对应的索引项也要插入和删除,会耗费较多的时间(2)链式存储:逻辑上相邻的两个元素的物理位置不一定相邻,每个结点用一个指针来找到下一个结点的位置。优点:插入和删除很方便缺点:随机读取时不方便,需要从第一个结点开始遍历动态规划是将一个大问题划分成若干个子问题,问题之间存在重叠,从上到下,求解整体最优解,每一次的求解会对下一次的问题造成影响,最终的最优解不一定包含每次的最优解,但是一定有部分最优解。经典例子是求最长子串。分治算法是将一个大问题划分成若干个和大问题相似的子问题,再对子问题进行递归求解,最终合并得到最后的结果。特点是大问题的划分与子问题相似,并且每个问题之间是相互独立的。经典例子是二路归并排序、快速排序答:(1)
=1.算法的时间复杂度= :
答:在程序中反复执行的语句的执行次数被称为语句的频度,时间复杂度就是所有语句频度之和的数量级,而所有语句的频度之和与程序最内层循环的频度是同一个数量级,所以算法的时间复杂度是最内层循环的频度的数量级
=补充:算法设计的步骤= :
1.建立数据模型
2.确定数据结构与算法
3.选用语言
4.调试并运行
答:程序在运行时所占的空间
直接插入排序的空间复杂度是O(1),递归的空间复杂度是O(n)
答:贪心算法是指从上到下,每次都求解局部最优解的算法,特点是每次求解最优解,但是最终的结果不一定是最优,经典例子是背包问题。
动态规划是将一个大问题划分成若干个子问题,问题之间存在重叠,从上到下,求解整体最优解,每一次的求解会对下一次的问题造成影响,最终的最优解不一定包含每次的最优解,但是一定有部分最优解。经典例子是求最长子串。
分治算法是将一个大问题划分成若干个和大问题相似的子问题,再对子问题进行递归求解,最终合并得到最后的结果。特点是大问题的划分与子问题相似,并且每个问题之间是相互独立的。经典例子是二路归并排序、快速排序
=4.数据的存储结构= :
答:
(1)顺序存储:逻辑上相邻的两个元素的物理位置也相邻。
优点:能够随机存取。
缺点:插入删除需要移动大量的元素,不方便。
(2)链式存储:逻辑上相邻的两个元素的物理位置不一定相邻,每个结点用一个指针来找到下一个结点的位置。
优点:插入和删除很方便
缺点:随机读取时不方便,需要从第一个结点开始遍历
(3)索引存储:在存储时,还附加建立索引表,索引表中的每一项称为索引项,索引项的一般形式是(关键字,地址)
优点:检索速度快
缺点:索引表占用存储空间,并且插入和删除一个数据时,对应的索引项也要插入和删除,会耗费较多的时间
(4)哈希存储:通过函数,根据数据的元素的关键字计算该元素的地址
优点:检索、增加和删除结点的操作比较快
缺点:可能会出现元素存储单元的冲突,解决冲突又需要增加时间和空间的开销
更多linux内核视频教程文档资料免费领取后台私信【内核】自行获取.
=5.循环比递归的效率一定高吗= ?
答:循环和递归能够实现相互转换,且各自有自己的优缺点,判断谁的效率高是没有绝对的答案的。
递归:
优点:代码简洁清晰、容易实现
缺点:当递归次数很多时,需要增加额外的堆栈处理,有可能产生堆栈溢出的现象
循环:
优点:结构简单,速度快,效率高
缺点:不容易理解,编写复杂代码时会比较困难
答:顺序表和链表可以从四个大的方向去比较。
(1)存取(读取)方式:顺序表能够随机读取和顺序读取,而链表只能按顺序读取
(2)查找:如果是按值查找并且表无序时,顺序表和链表的时间复杂度都是O(n),如果表有序,则可以用折半查找法,时间复杂度是O(nlog2n);如果是按序号查找,则顺序表支持随机查找,时间复杂度是O(1),而链表的时间复杂度是O(n)
(3)插入和删除:顺序表插入和删除需要移动大量的元素,时间复杂度是O(n),链表的插入和删除只需要修改指针的位置,时间复杂度是O(1)
(4)空间分配:顺序表的空间分配分为静态分配和动态分配,静态内存分配时,很容易导致内存溢出或者是浪费,而动态内存分配时,有时候不存在一大块连续的存储空间,导致分配失败,并且需要移动大量的元素,效率低。
而链表是直接在需要的时候申请内存,只要有内存就能够分配,操作灵活、高效。
答:头指针是指在第一个结点之前的指针,它是一个链表存在的标志,是必须存在必不可少的。
头结点是第一个结点之前的结点,它是为了方面在第一个结点之前进行元素的插入和删除操作,它不是必须的,并且数据域也可以不存放信息。
答:栈是只能在一端进行插入和删除的线性表,插入和删除都在栈顶进行,它的特点是“先进后出”。常用于浏览器的回退或者是括号的匹配问题,递归问题,但是递归问题要注意堆栈的溢出现象
队列是在一端插入在另一端删除的线性表,插入的那端是队尾,删除的那端是队首,特点是“先进先出”,在层次遍历和BFS算法、狄杰斯特拉算法中使用到
=9.共享栈= :
答:利用栈底位置不变的特性,让两个顺序栈共享同一个一维数组空间,将两个栈的栈底分别设在共享空间的两端,两个栈顶向共享空间延伸。
答:有两种区分方式:
第一种:牺牲一个单元来区分队空和队满
队空的标志是 队首指针 = = 队尾指针;
队满的标志是(队尾指针 1)%maxsize ==队首指针
第二种: 类型中增设表示元素数据的内存单元
队空:元素的个数为0
队满:元素的个数为Maxsize
答:(1)如果是左括号,则入栈
(2)如果是右括号,则判断当前栈是否为空,如果为空,则不匹配,不为空,则看是否与栈顶的左括号匹配,如果匹配,则栈顶元素出栈
(2)最终所有的元素都进栈和出栈完毕,检查栈是否为空,如果不为空,则说明还有多余的左括号没有匹配,因此括号匹配失败,如果为空,则括号匹配成功。
答:扫描表达式的每一项
(1)如果是操作数,则进栈
(2)如果是运算符,则从栈中退出两个元素,进行出栈,并且将得到的结果入栈
(3)表达式的所有项都扫描完后,最后栈顶存放的元素就是最终的结果。
答:若在一个函数、一个过程或者一个数据结构的定义中直接或者间接的调用了它自身,则这个函数、这个过程、这个数据结构称为是递归定义的,简称为递归。
递归问题只需要少数的代码就能够描述出解题过程中所需要的多次重复计算,大大减少了程序的代码量,递归所用到的是系统管理栈,但是通常情况下,每次递归都要保留现场,空间复杂度为O(n),效率不高,并且当递归次数过深的时候,容易出现堆栈溢出的现象。
将递归转化成非递归算法,也是用栈来实现的。相比起递归算法的系统管理栈,需要建一个自己管理的栈。
答:首先根结点入队,接着队根结点的子结点进行预处理,等预处理完后,根结点出队,接着刚刚处理的子结点入队,这部分的子结点又进行预处理,直到所有的结点都入队出队处理完毕。
答:有两个方面的应用:
(1)解决了主机和外部设备之间速度不匹配的问题
以主机和打印机为例,主机输出数据的速度比打印机输出数据的速度要快很多,由于速度不匹配,直接把输出的数据给打印机肯定是不行的,于是需要设置一个缓冲区,主机将一部分要打印的数据写入缓冲区,写满后就暂停输出,转去做其他的事情,而打印机就从缓冲区中按照先进先出的原则依次取出数据并打印出来,打印完后向主机发出请求。这里的打印缓冲区就是一个队列。
(2)CPU资源的竞争
答:在一个多终端的计算机系统中,多个用户需要CPU各自运行自己的程序,分别通过各自的终端向操作系统提出占用CPU的请求。操作系统按照每个请求在时间上的先后顺序,将他们排成一个队列,每次把CPU分配给队首请求的用户使用。当相应的程序运行结束或者用完规定的时间间隔后,令其出队,再把CPU分配给新的队首请求的用户使用。
答:针对特殊的矩阵进行压缩存储
对称矩阵:含有大量相同元素的矩阵
稀疏矩阵、上(下)三角矩阵:含有大量0元素的矩阵
压缩思想:矩阵中相同的数据元素(包括元素0)只存储一个
=17.串的模式匹配= :
串的模式匹配指子串在主串中的位置。
暴力匹配算法:从主串的第一个字符开始,与子串的第一个字符比较,一旦出现不匹配的字符,则主串往后移动一个位置,子串移动子串的第一个位置,并与主串对齐
KMP算法:暴力匹配的弊端就是,没有充分利用已经匹配了的串的信息,好的解决方法应该是在模式串中找到最长的子串,并且记录到next[]数组中
KMP算法的步骤
(1)主串S和模式串T进行比较,并设起始的下标为i和j
(2)如果S[i]==T[j] 则继续比较,并且i和j自增1
(3)当s[I]!=T[j]时,将j=next[j];将模式串右移,直到与主串对齐;如果j == -1,则主串往后移动一个单位,i ;j ,j又回到模式串的第一个位置
答:在实现函数调用的时候,系统底层就是用栈来保护现场的;具体来说,每次调用函数时,会把当前函数的局部变量和返回地址都压栈保存起来,当系统调用结束返回时,再把局部变量从栈中弹出来;
递归的核心就是重复的函数调用,如果要变成非递归,就需要自己实现栈的数据结构来保存一些状态变量,这其实就是模拟函数的调用。
堆:是一种特殊的完全二叉树,叶子结点的值大于或者小于根结点的值
(PS:完全二叉树是指第n-1层,每一层的结点数是2^(n-1) 最后一层的结点可以不放满,但是必须是从左至右放的)
堆排序:最好、最坏、平均时间复杂度是O(nlogn)
思想:(以大根堆为例)将待排序的构造成一个大根堆,此时最大的元素就是根结点的元素,这时候,将这个元素与末尾的元素进行交换,然后再将剩下的n-1个元素构造成一个大根堆,就会形成一个有序 区。
步骤:
(1)构造初始堆
a.建立一个完全二叉树
b.从最后一个非叶子结点开始调整,一旦比根结点大,则与根结点进行交换,最终最大的元素位于根结点的位置上
(2)将堆顶元素与末尾元素进行交换,末尾的元素值最大
(3)重新调整结构,使其满足堆定义,然后继续交换堆顶元素当前末尾元素,反复执行 调整步骤,直到整个序列有序。
导读-最新发表 - 内核技术中文网 - 构建全国最权威的内核技术交流分享论坛
转载地址:一篇看懂块设备的主要数据结构! - 圈点 - 内核技术中文网 - 构建全国最权威的内核技术交流分享论坛