数据结构笔试题的笔记

来源:互联网 发布:淘宝买家号可以开店吗 编辑:程序博客网 时间:2024/06/08 17:05

1.存储密度的概念

存储密度=单链表数据项所占空间/结点所占空间;一般情况下,因为结点中包含数据项和指针,所以正常而言密度是小于1的。

2.链队不是链表

对于链队而言,删除操作只能在对头操作,而插入只能在对位操作,这里需要注意的是当链队中只有一个元素的时候,那么在进行删除的时候,她的头尾指针都是需要修改的

3.链表不能随机访问任何一个元素

4.顺序表

对于顺序表而言,每次进行删除某一个位置的元素(非末尾元素),都必须将后面的元素向前移,填补空缺

5.线性表(List)–一种数据结构

线性表:有序除头尾外其他每个节点有且仅有一个前继和一个后继表中的元素类型都相同
线性表(ADT)根据物理结构又分为顺序存储结构(元素连续存储、随机存取结构)和链式存储结构(元素分散存储);
顺序存储结构:指的是用一段地址连续的存储单元依次存储线性表的数据元素。线性表的顺序存储结构的存取操作复杂度为O(1),插入、删除操作复杂度为O(n),所以顺序存储结构的线性表适合存取不适合增删。
链式存储结构:指的是用一组任意的存储单元存储线性表的数据元素,这组存储单元可以是连续的,也可以是不连续的。这里注意和顺序存储结构的区别,因为顺序存储结构是存储在相连地址的存储单元中,所以一个元素的下个元素就是该元素地址的下一个地址的元素,不需要存储它的后继的位置信息,而链式存储结构就一样了,由于它不要求连续的存储单元,所以它必须额外存储它的后继的地址单元。【注意:单链表的插入】如果将s插入到p的后面,应该是这样的s.next=p.next;p.next=s这两个语句千万能调换,否则链表将变成p–>s–>s而不是p–>s–>p.next的效果;C语言还有用数组来描述链表,这种方式称为静态链表。

6.链表的效率

表头*插入和删除速度很快,仅需要改变一两个引用,所以话费O(1)的时间。就平均而言,查找、删除和在指定节点后面插入都需要O(n)次比较,虽然在数组中也是比较O(n)次,但是链表仍然快一些,因为链表的删除不需要移动元素*。

7.二叉树

普通的二叉搜索树可以快速的找到给定关键字的数据,并且可以快速的插入和删除数据项,但是树插入的如果是有序数(正序或者逆序)的话,她的快速查找(插入、删除)的能力就会丧失了,因为此时它就变成非平衡树,非平衡树是没有快速查找的能力的。

8.红黑树

当插入节点时,要遵循红-黑规则,这时候插入的话树就是平衡的。红黑规则如下:(这里提一下平衡树的概念:一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树)
1.每个节点要么红色、要么黑色
2.根节点总是黑色的
3.如果节点是红色的,则她的子节点必须是黑色的(反之未必为真)
4.从根结点到叶节点或者空子节点(空子节点指的是一个有右子节点的节点的可能接左节点的位置,或者是有左子节点的节点可能接右子节点的位置,简单的说就是已经有一个子节点的父节点的另一个空着的自己子节点位置)的每一条路径必须包含相同数量的黑色节点(也称为黑色高度:从根结点到指定节点路径上黑色节点的数目)

如果红黑树的规则被违背了,那么就要执行修改操作,有两种方式修改:改变节点颜色、执行旋转操作,这里以右旋为例说明其中操作过程,左子节点移动到父节点位置,父节点移动到她的右子节点的位置,右子节点移动到下移。

在红黑树中插入节点的时候总是红色节点

9.存储结构

存储结构分为如下4种:
1.随机存取:可以随意直接存取任意一个元素。如数组可以通过下直接存取元素、如内存可以通过地址直接访问任意一个空间。
2.顺序存取:只能从前向后逐个访问。如链表必须从表头开始向后逐渐访问。
3.索引存取:为某个关键字建立索引,从所有的表中得到地址,再直接访问。索引存取多用于数据管理过程中。
4.散列存储:是简历散列表,相当于索引。

10.哈夫曼编码

1.首先统计出权值(通常之字符串中以出现的频率作为权值)
2.选取两个根节点权值最小的节点构成最小的树,他们的根节点为两个节点权值之和,然后不断的加入剩余权值中最小的节点,他们的根节点为他们权值之和,注意这里的左节点比右节点小,不断构造即可
3.编码的时,规定一下左方向为0,又方向为1,访问至也叶节点的01组合就是该字符的编码。
小例子:

11.海量数据,有限时间内找出指定要求的数据

1.问题一:1千万有重复的短信,以文本形式保存,再5分钟内中出重复次数最多的10条记录;
方案:数据库的办法无法满足这样的搜索效率,可以用哈希表,将所有短信分组,边扫描边建散列表。第一次扫描,取首、尾直接,中间任意两个字节作为Hash Code,插入hash table中并记录地址、信息长度和重复次数。相同的hash code且等长就疑似相同做一下比较,相同记录只进行一次放入hashtable的操作,以后直接将重复次数加1即可。第二次扫描hashtable,用线性时间选择可以在O(n)级别上完成前指定条件的前10条记录搜索。分组后每组中的top10必须保证各不相同(用hash保证),也可以按照hash值的大小来分类。

12.求复杂度

问题:20个数组,每个数组里中500个树,升序排列,求这1000个数中最大的500个,这种情况的复杂度是多少?
解答:求一组数据中最大的几个,很明显用堆排序,复杂度为O(nlogn),故本题答案500log(20)

13.算法的时间复杂度

13.1推导O(n)的法则:
1.用常数1取代所有的加法常数
2.然后之保留1步骤之后的最高阶项
3.将2步骤后的最高阶项的参数改为1即可
【注意】常见复杂度的效率:O(1)>O(logn)>O(n)

13.2常用的O(…)举例
常数阶:即像普通的单次或可见次的四则运算,如sum = a + b;
线性阶:普通的for循环,如for(int i=0;i<n;i++){...}可见i是从0到n-1总共循环了n次,所以它的复杂度为O(n);
对数阶:常常是指不断乘2的循环操作,如while(count<n) {count = count *2;}可以发现count的值在循环执行了x次之后的值变为2^x,那么当2^x>=n时,循环结束,故循环了以2为底的n次,计算机默认以2为底,故可以写成O(logn)的形式;
平方阶:平方阶可以理解为普通的线性阶的嵌套,如for(int i=0;i<n;i++) {for(int j=0;j<n;j++) {...} }这种情况的复杂度就为O(n^2);
综合

for(int i=0;i<n;i++) {    for(int j=i;j<n;j++) {        //普通加和运算....    }}

上面的算法复杂度为多少呢?
【解析】复杂度就是运行次数的简化,那就看,当i=0时,j是从0到n-1,运行n次;
当i=1时,j是从1到n-1,运行n-1次;

当i=n-1是,j是从n-1到n-1,运行1次;
将上面的加和就是运行次数了S=n*n+(-1)n(n-1)/2=(n^2)/2+n/2;根据O(…)推导规则,无常数项、保留最高阶项并将其参数改为1:O(n^2);

14.算法的定义

算法是解决特定问题的求解步骤的描述,特性:有穷性、确定性、可行性、输入、输出

15.栈与队列(他们都是线性表)

栈:是仅限定在表尾进行插入或者删除操作的线性表后进先出(LIFO)
队列:也是线性表,但只允许在一端进行插入,删除操作则只能在另一端操作,先进先出(FIFO),其中队列的链式存储结构其实就是普通的单链表,只不过他只能头进尾出,简称链队列。

16.串的匹配

串的匹配就是指从一个串中查找与另一个串一样的子串,如在“abcfg”中查找“cfg”.
朴素模式匹配:直接从主串的第1位开始遍历子串的长度,中间发现不符合直接pass,继续从主串的第2位遍历,直到匹配完成或者主串遍历完。效率低下
KMP模式匹配:很好的解决了朴素模式匹配中回溯的问题,从而提高了效率。该算法的关键是next[]数组,指的子串中各个位置的j值变化数组,定义如下这里写图片描述,这里举几个例子,若子串为abcdex,那么next[]={0,1,1,1,1,1};若子串为abcabx,那么next[]={0,1,1,1,2,3};若子串为ababaaaba,那么next[]={0,1,1,2,3,4,2,2,3};若子串为aaaaaaaab,那么next[]={0,1,2,3,4,5,6,7,8};
【注意】next[]数组是KMP算法的关键,这里next[1]=0,是死的,然后看第j号元素之前的元素(即第1到第j-1个元素),两步骤:1.将第1到第j-1个元素分成两个子串,两者可重叠(但不完全重叠),但是必须满足第一个子串必须重第1个元素开始,第二个子串以第j-1个子串结尾,使他们完全相等(记为str1和str2相等)2. 一般情况下,next[j]就为str1和str2相等的子串队中长度最长的子串长度+1.

17.树

【定义】树是n个节点的有限集,在任何一个非空树中,有且仅有一个根节点,而且子树之间是除根节点外没有任何交互。
常用概念:
1.度–指的是该节点拥有的子树个数,即直系自己子节点的个数。其中叶子结点的度为0,树的度则是指所有节点中度最大的节点的度。
2.满二叉树–所有分支节点(除了根节点和叶节点以外的节点都叫分支节点)都存在左子树和右子树,而且所有的叶节点都在同一层上(这一点以前还真没注意);
3.完全二叉树–编号为i的节点与同样深度的满二叉树中编号为i的节点在二叉树中的位置相同。

17.1二叉树
【性质】
1.第i层上的至多有2^(i-1)个节点
2.深度为k的二叉树总节点树最多为(2^i)-1
3.若叶节点有n0个,度为2的节点有n1个,那么n0 = n1+1;
【遍历】
二叉树利用Stack实现中序、后序遍历以及利用前序和中序推导后序遍历的问题要勤加练习。

17.2哈夫曼树
主要用于压缩,具体见上文

18.图

【定义】图是由顶点的有穷非空集合和顶点之间的边的即可组成,通常表示成G(V,E),其中G表示一个图,V表示图G中顶点的集合,E表示G中边的集合。【注意】图的话不允许顶点集合为空。
【分类】
1.无向图:图中任两个顶点之间的连线是无向的(无向边),用无序偶对表示(A,B),因为无序,所以A、B两者的顺序是可以互换。
2.有向图:类似的若两个顶点间的连线是又方向的(称为有向边或者弧),这样的图就是有向图了,用有序偶

19.查找

查找分为静态查找和动态查找。静态查找:只作查找操作;动态查找:查找过程中参杂了插入或者删除的操作。

1.二叉排序树:左孩子的值小于根节点的值,右孩子的值大于根节点的值

2.散列表:散列技术是在记录存储位置和它的关键字之间建立一个确定的对应关系f,使得每个关键字key对应一个存储位置f(key)。将f(x)称为散列函数(也叫哈希函数),采用散列技术将记录存储在一块连续的存储空间(称为哈希地址)中,这块连续的存储空间称为散列表(或哈希表)。散列技术既是一种存储方法也是一种查找方法。散列技术不适用于同一关键字对应多条记录的情况,也不适用于范围查找(比如在一组数据中查找20到30之间的数据),也不用于查找最值。理想情况下,应该是每个关键字通过哈希函数计算出来的地址都是不一样的。但是通常会出现f(key1)=f(key2)的情况(我们称之为冲突)。
冲突的解决方法
1.开放地址法:一旦发生冲突,就去寻找下一个空的散列地址,只要散列地址足够大,空的散列地址就总能找到,那么记录就可是放到该地址中即可。
2.再哈希法(再散列函数法):实现准备了多个哈希函数,如果发生冲突了就直接换一个哈希函数
3.链地址法:散列表的每个单元中存储了一个个链表的指针,将元素都存放在一个个的链表中,查找的时候先从链表地址进入,再遍历对应的链表即可。

原创粉丝点击