一些考前注意事项
-
先连后断
-
线性表:无
-
顺序栈:顺序栈的指针top指向栈顶元素的下一个位置
-
中缀转前缀:人算手动加括号,运算符提到括号之前;机算两个栈,从右向左入栈
-
中缀转后缀:人算手动加括号,运算符提到括号之后;机算两个栈,从左向右入栈
-
顺序队列:非空时,头指针指向队列头元素,尾指针指向为元素的下一个位置
-
循环队列:队头队尾指针进1进行取模运算,对空条件
front==rear
,队满条件(rear+1) % maxsize==front
-
子串的KMP算法:脑算:next[j]为拿出0-j-1的字符,长为j-1,j-2,…,1挨个试,首尾子串相等,最终的长度就是next[j]的值,next[0]=-1
- 递归算法:初始化后,取k=next[j-1],k>0且t[k]!=t[j-1],令k=next[k],直至k<=0,此时next[j]只能为1/0,否则next[j]=k+1;
-
稀疏矩阵:
- 三元组表(行(行小先存)、列(行相同列小先存)、值)
- 十字链表存储(两个一维数组存储行链表和列链表的头指针,节点存行、列、值、和指向下和右的指针)
- 矩阵转置快速算法(三元组表存储):求原矩阵每列非零元素个数,记录为num数组,
++num[M.data[t].col]
,cpot数组存放第col列中第一个非零元的序号cpot[col]=cpot[col-1]+num[col-1]
,循环原矩阵元素p,取q=cpot[M.data[p].col]
,p与q对应数据交换,++cpot[col]
。
-
广义表(原子节点(标志域0,原子值),表节点(标志域1,表头指针(可以表节点,可以原子节点),表尾指针(空或表节点)))
- 表头:当广义表LS非空时,称第一个元素为LS的表头;
- 表尾:称广义表LS中除去表头后其余元素组成的广义表为LS的表尾。
-
线索二叉树存储结构同通过(lTag,rTag)控制(lchild,rchild)指向结点的孩子还是结点的前驱,后继
-
普通树的存储结构
- 双亲表示法
- 孩子表示法
- 多重链表(多个指针)
- 孩子链表(一个孩子一个链表,每个链表的头指针成一个线性表)
- 孩子兄弟表示法(可转换任意树为二叉树)
-
图的存储结构
- 邻接矩阵(一个顶点数组,一个二维数组)
- (逆)邻接表(每个顶点的弧成单链表、顶点成数组)
- 有向图十字链表(顶点成数组(每顶点有指向以该顶点为头,为尾的边的两个指针),边(弧头结点弧尾结点的信息,两个指向下一个共头,共尾的边的指针))
- 无向图邻接多重表(顶点成数组(有指向一边的指针),边(标记是否被访问,两个顶点信息,两个指向下一个共点的边的指针))
- 边表(每个顶点一个链表,包含以该顶点为起点的所有边)
-
图搜索有三类节点:访问过的节点,访问过节点的直接邻接点(搜索边界),其它未访问过节点
-
图为边无权或等权时,广度优先搜索一定能找到最短路径,深度优先搜索不一定能找到最短路径
-
图搜索目标为路径空间复杂度 O ( n ) O(n) O(n),时间复杂度 O ( n + e ) O(n+e) O(n+e),图搜索目标为节点,检查顶点数组即可,平均查找时间为 ( n + 1 ) / 2 (n+1)/2 (n+1)/2,空间需求 O ( 1 ) O(1) O(1)。
-
深度(广度)优先遍历,时间复杂度:邻接矩阵 O ( n 2 ) O(n^2) O(n2),邻接表 O ( n + e ) O(n+e) O(n+e)
-
无向图连通分量(深度优先搜索遍历),有向图强连通分量(深度优先生成森林后根遍历编号,改变每边的顺序,从编号最大顶点深度优先搜索,不断循环该过程,每次都从未被访问的最大编号顶点)
-
最小生成树(prim算法(边和点) O ( n 2 ) O(n^2) O(n2),Kruskal算法(边) O ( e l o g e ) O(eloge) O(eloge))
-
AOV网络顶点表示活动,有向边表示先后次序;AOE网络边表示活动,顶点表示事件,每个事件表示其前的所有活动完成,其后的活动可以开始
-
拓扑有序序列检测AOV,AOE是否有有向环
-
拓扑排序:每次输出入度为0顶点,并删除该顶点发出的边,直至无顶点( O ( n + e ) O(n+e) O(n+e))
-
AOE找关键路径算法:拓扑排序得到的序列算出 v e ( i ) 早 , v l ( i ) 晚 ve(i)早,vl(i)晚 ve(i)早,vl(i)晚,早大晚小,相等关键( O ( n + e ) O(n+e) O(n+e))
-
最短路径:(某点) D i j k s t r a Dijkstra Dijkstra算法( O ( n 2 ) O(n^2) O(n2)),(所有点) F l o y d Floyd Floyd算法(关联矩阵+Path矩阵 O ( n 3 ) O(n^3) O(n3))
-
顺序查找表从后往前找,因为第一个数据为哨兵即所要查找的数据,等概率查找成功 A S L = n + 1 2 ASL=\frac{n+1}{2} ASL=2n+1,查找不成功时 A S L = 3 4 ( n + 1 ) ASL=\frac{3}{4}(n+1) ASL=43(n+1)
-
有序查找表折半查找时间复杂度 O ( l o g n ) O(logn) O(logn), n > 50 n>50 n>50, A S L ≈ l o g 2 ( n + 1 ) − 1 ASL\approx log_2(n+1)-1 ASL≈log2(n+1)−1
-
索引查找表 A S L = L b + L w ASL=L_b+L_w ASL=Lb+Lw,长为 n n n的表平均分 b b b块,每块 s = n b s=\frac{n}{b} s=bn,折半查找确定块位置 A S L b s = l o g 2 ( n s + 1 ) + s 2 ASL_{bs}=log_2(\frac{n}{s}+1)+\frac{s}{2} ASLbs=log2(sn+1)+2s,顺序查找确定块位置 A S L b s = 1 2 ( n s + s ) + 1 ASL_{bs}=\frac{1}{2}(\frac{n}{s}+s)+1 ASLbs=21(sn+s)+1
-
查找 插入 删除 无序顺序表 O(n) O(1) O(n) 无序线性链表 O(n) O(1) O(1) 有序顺序表 O(logn) O(n) O(n) 有序线性链表 O(n) O(n) O(n) 静态查找树表 O(nlogn) O(nlogn) O(nlogn) -
二叉排序树插入和删除都依赖于查找函数 A S L = 2 n + 1 n l o g 2 n + C = O ( l o g n ) ASL=2\frac{n+1}{n}log_2n+C=O(logn) ASL=2nn+1log2n+C=O(logn)
- 删除时为叶子结点,直接删除
- 删除时只有单子树,双亲指向该节点的单子树
- 删除时有双子树,中序遍历后用被删除节点的前驱替代之
-
平衡二叉排序树(AVL) 平均查找长度和 l o g 2 n log_2n log2n时一个量级 O ( l o g n ) O(logn) O(logn)
- LL型(右旋):左深
- RR型(左旋):右深
- LR型(左右旋):左子树左旋后成LL型,右旋
- RL型(右左旋):右子树右旋后成RR型,左旋
-
m m m阶 B − B^- B−树:必须有 m m m棵子树的节点,叶子结点在同一层,根至少两棵子树,非叶节点至少 ┌ m 2 ┐ \ulcorner\frac{m}{2}\urcorner ┌2m┐棵子树
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9qQHeP4T-1642165224462)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20220113101802419.png)]
- 插入需要看情况分裂(叶子节点关键字数<m-1,直接插,=m-1,分裂)
- 删除同 A V L T r e e AVLTree AVLTree(注意非叶节点至少 ┌ m 2 ┐ \ulcorner\frac{m}{2}\urcorner ┌2m┐棵子树,注意合并)
-
B + B^+ B+树:只用叶子结点存储记录(叶节点包含全部关键字信息以及这些关键字记录的指针并构成关键字从小到大的链接),非叶节点可看成索引(只含子树最大(或最小)关键字),下图为 3 阶 B + 树 3阶B^+树 3阶B+树
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4q8JoxNH-1642165224466)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20220113102609356.png)]
- 叶结点上插入,叶节点包含超过 m m m个关键字,分裂
- 叶结点上删除,叶节点过小时( < ┌ m 2 ┐ <\ulcorner\frac{m}{2}\urcorner <┌2m┐),合并
-
哈希函数
- 直接定址法:线性函数
- 平方取中法:关键字平方值的中间几位做存储地址
- 随机数法:以关键字为随机数种子
- 数字分析法:分析所有关键字,提取分布均匀若干位组合成地址
- 折叠法:移位叠加(分割后相加),间界叠加(分割后来回折送相加)
- 除留余数法:对关键字求余
-
冲突处理方法(装载因子 α = n m \alpha=\frac{n}{m} α=mn, m m m表长, n n n记录个数)
- 开放地址法
- 线性探测再散列 A S L ≈ 1 2 ( 1 + 1 1 − α ) ASL\approx\frac{1}{2}(1+\frac{1}{1-\alpha}) ASL≈21(1+1−α1)
- 平方探测再散列( 1 2 , − 1 2 , 2 2 , − 2 2 . . . 1^2,-1^2,2^2,-2^2... 12,−12,22,−22...) A S L ≈ − 1 α l n ( 1 − α ) ASL\approx-\frac{1}{\alpha}ln(1-\alpha) ASL≈−α1ln(1−α)
- 伪随机探测再散列 A S L ≈ 1 + α 2 ASL\approx1+\frac{\alpha}{2} ASL≈1+2α
- 链地址法
- 再哈希法
- 建立公共溢出区
- 开放地址法
基础概念
-
数据元素是由数据项组成的,数据元素是数据的基本单位。数据项是数据的最小单位。
-
数据结构是指数据元素以及它们之间计算方法。
-
计算机所处理的数据集一般具备某种内在联系,这是指元素和元素之间存在某种关系。
-
数据的逻辑结构是指数据元素之间逻辑关系的整体。
-
在存储数据时,通常不仅要存储各数据元素的值,而且还要存储数据元素之间的关系。
-
数据的逻辑结构可以分为线性结构和非线性结构两类。
-
数据采用链式存储结构时,要求每个结点占用一片连续的存储区域。
-
计算机中算法指的是解决某一问题的有限运算序列,它必须具备输入、输出、可行性、有穷性和确定性。
-
算法分析的主要任务是分析算法的执行时间和问题规模之间的关系。
-
在数据的存储结构中,一个存储结点存储一个数据元素。
-
数据结构的基本存储方法是顺序存储方法、链式存储方法、索引存储方法和散列存储方法
-
程序一定是算法。F
-
算法最终必须由计算机程序实现。F
-
为解决某问题的算法等同于对应的程序。F
-
数据集是由一些类型相同的数据元素构成的。T
-
任何数据结构都具各3个基木运算:插入、删除和查找。F
-
集合与线性表的区别在于是否按关键字排序。F
-
抽象数据类型(ADT)包括定义和实现两方面,其中定义是独立于实现的,定义仅给出一个ADT 的逻辑特性,不必考虑如何在计算机中实现。T
-
在决定选取何种存储结构时,一般不考虑(A)。
- A.各结点的值如何
- B.结点个数的多少
- C.对数据有哪些运算
- D.所用的编程语言实现这种结构是否方便。
-
分析下列算法的时间复杂度,并写出过程
-
void func(int n) { int i = 1, k = 100; while (i<n) { k++; i += 2; } } //求解 /* 设while循环语句执行的次数为m,i从1开始每次递增2,最后取值为1+2m 有:i = 1+2m < n,即 m<(n-1)/2 = O(n),所以,该算法的时间复杂度为0(n)。 */
-
void func(int n) { int i, j, x = O; for (i = 1; i < n; i++) for (j = i + 1; j <= n; j++) x++; } //求解 /* 设x++语句执行次数为m,则: m = (n-1) + (n-2) + ... + 2 + 1 = n*(n-1)/2 该算法的时间复杂度为O(n2)。 */
-
int s=O,i,j,k; for (i=O;i<=n;i++) for (j=O; j<=i; j++) for (k=O;k<j;k++] S++; //求解 /* 该算法的基本操作是语句s++,其频度: T(n) = 求和(i(i+1)/2),其中i从0到n = 1/2(n(n+1)(2n+1)/6+n(n+1)/2) 则该程序段的时间复杂度为O(n3)。 */
-
void func(int n) { int i=O,s=O; while (s<n) { i++; S=s+i; } } //求解 /* 对于while循环语句,设执行的次数为m,i从0开始递增l,直到m一1为止 有s=0+1+2+…+m-l=m(m-1)/2,并满足s=m(m-1)/2<n,则有m≤sqrt(n) 所以,该算法的时间复杂度为O(sqrt(n))。 */
-
void mergesort(int i,int j) { int m; if (i!=j) { m=(i+j)/2; mergesort(i,m); mergesort(m+l,j); merge(i,j,m); } /*其中,mergesort()用于数组a[n](n=2k,这里的k为正整数)的归并排序,调用该算法的方式为mergesort(0,n-1):merge()用于两个有序子序列的合并,是非递归函数,它的时间复杂度为O(n)。*/ //求解 /* T(n)=2T(n/2)+O(n)=T(n/2)+cn 令n=2^k T(2^k) = 2T(2^(k-1))+c2^(k-1))+c2^k = 2(2T(2^(k-2))+c2^(k-1))+c2^k = 2^2T(2^(k-2))+2c2^k ... =2^kT(1)+kc2^k ---> l=k=log_2(n) ---> T(n)=O(nlog_2(n)) */
-
i = 0; while(i<=n) i = i * 3; //求解 /* 该算法的基本操作是语句i=i*3,设执行了k次 3^k <= n---> k <= log_3(n) ---->O(log_3(n)) 则该程序段的时间复杂度为O(log_3(n))。 */
-
线性结构
-
设有两个长度为n的单链表,结点类型相同,若以h1为首结点的链表是非循环的,以h2为首结点指针的链表是循环的,则 B 。
- A.对于两个链表来说,删除第一个结点的操作,其时间复杂度都是O(1)
- B.对于两个链表来说,删除最后一个结点的操作,其时间复杂度都是O(n)
- C.循环链表要比非循环链表占用更多的内存空间
- D. h1和h2是不同类型的变量
-
若某表最常用的操作是在最后一个结点之后插入一个结点或删除最后一个结点,则采用(D)存储方式最节省运算时间。
- A.单链表
- B.给出表头指针的单循环链表
- C.双链表
- D.带头结点的双循环链表
-
在一个长度为n(n>1)的单链表上,设有头和尾两个指针,执行(B)操作与链表的长度有关。
-
A.删除单链表中的第一个元素
-
B.删除单链表中的最后一个元素
-
C.在单链表第一个元素前插入一个元素
-
D.在单链表最后一个元素后插入一个新元素
-
-
如果对线性表的操作只有两种,即删除第一个元素,在最后一个元素的后面插入新元素,则最好使用(B)。
-
A.只有表头指针没有表尾指针的循环单链表
-
B.只有表尾指针没有表头指针的循环单链表
-
C.非循环双链表
-
D.循环双链表
-
-
线性表的顺序存储结构是一种(A)。
- A.随机存取的存储结构
- B.顺序存取的存储结构
- C.索引存取的存储结构
- D. Hash存取的存储结构
-
下述哪一条是顺序存储结构的优点© 。
- A 插入运算方便
- B 可方便地用于各种逻辑结构的存储表示
- C 存储密度大
- D 删除运算方便
-
在顺序表中插入或删除一个数据元素,需要平均移动n/2或(n-1)/2个数据元素,移动数据元素的个数与插入或删除该元素的位置有关。
-
根据线性表的链式存储结构中每一个结点包含的指针个数,将线性链表分成单链表和多重链表。
-
线性表中每个元素都有一个直接前驱和一个直接后继。 F
-
静态链表的存储空间在运算中可以改变大小。F
-
设计一个高效算法,从顺序表中删除所有元素值为x的元素,要求空间复杂度为O(1)。注:需要考虑有多个X,并且每次需要移动后面的其他元素。
-
void delete(int a[],ElemType x) //a 为已知顺序表,x为待删除的元素 { int i,j=0; for(i=0;i<N;i++) if(a[i]!=x) a[j++]=a[i]; }
-
栈和队列
-
已知一个栈的进栈序列是l,2,3,…,n,其输出序列的第一个元素是i,则第j个出栈元素是(D) 。
- A. i
- B. n-i
- C. j-i+1
- D.不确定
-
环形队列qu的队满条件是©。
-
A.(qu. rear+1)%MaxSize==(qu. front+1)%MaxSize
-
B.(qu. rear+1)%MaxSize==qu. front+1
-
C.(qu. rear+1)%MaxSize==qu. front
-
D. qu. rear==qu. front
-
-
设环形队列中数组的下标是0~N-1,其头、尾指针分别为f和r,则其元素个数为(D) 。
- A. r-f
- B. r-f-1
- C. (r-f)%N+1
- D. (r-f+N)%N
-
假设一个链队的队头和队尾指针分别为front和rear,则判断队空的条件是(D)。
-
A. front==rear
-
B. front!=NULL
-
C. rear!=NULL
-
D. front==NULL
-
-
对于链队,在进行删除操作时(D) 。
- A.仅修改头指针
- B.仅修改尾指针
- C.头、尾指针都要修改
- D.头、尾指针可能都要修改
-
向一个栈顶指针为h 的带头结点的链栈中插入指针s 所指的结点时,应执行(D)操作。
- A h->next=s ;
- B s->next=h ;
- C s->next=h ;h =s ;
- D s->next=h->next ;h->next=s ;
-
若将n阶下三角矩阵A按列优先顺序压缩存放在一维数组B[1..n(n+1)/2]中,第一个非零元素 a 1 , 1 a_{1,1} a1,1存于B[O]中,则应存放到B[k]中的非零元素 a i , j a_{i,j} ai,j(1≤i≤n,1≤j≤i)的下标i、j与k的对应关系是(B)。
- A. j ( 2 n − j + 1 ) 2 + i − j \frac{j(2n-j+1)}{2}+i-j 2j(2n−j+1)+i−j
- B. ( j − 1 ) ( 2 n − j + 1 ) 2 + i − j \frac{(j-1)(2n-j+1)}{2}+i-j 2(j−1)(2n−j+1)+i−j
- C. i ( 2 n − i + 1 ) 2 + j − i \frac{i(2n-i+1)}{2}+j-i 2i(2n−i+1)+j−i
- D. i ( 2 n − i + 2 ) 2 + j − i \frac{i(2n-i+2)}{2}+j-i 2i(2n−i+2)+j−i
-
设二维数组A[1… m,1… n]按行存储在数组B中,则二维数组元素A[i,j]在一维数组B中的下标为(A)
- A n*(i-1)+j
- B n*(i-1)+j-1
- C i*(j-1)
- D j*m+i-1
-
若栈采用顺序存储方式存储,现两栈共享空间V[1 m],top[1]、top[2]分别代表第1和第2个栈的栈顶,栈1的底在V[1],栈2的底在V[m],则栈满的条件是(B)。
- A.|top[2]-top[1]|=0
- B. top[1]+1=top[2]
- C. top[1]+top[2]=m
- D. top[1]=top[2]
-
设输入序列为n个不同数,则经过栈的作用后可以得到 C 2 n n n + 1 \frac{C_{2n}^n}{n+1} n+1C2nn种不同的输出序列。
-
无论是顺序队,还是链队,进队、出队操作的时间复杂度都是O(1)。 T
串及广义表
-
设有两个串p和q,求q在p中首次出现的位置的运算称为(B)。
- A.连接
- B. 模式匹配
- C.求子串
- D.求串长
-
广义表的长度是最大括号内逗号数量+1,深度是括号的重数。
-
广义表的表头可以是元素可以是表,表尾必须是广义表
-
求广义表的深度
-
int GList_GetDepth(GList L) { if(!L->Tag) return 0; else if(!L) return 1; m=GList_GetDepth(L->ptr.hp)+1; n=GList_GetDepth(L->ptr.tp); return m>n?m:n; }
-
-
求矩阵 A m × n A_{m\times n} Am×n的马鞍点
-
void Get_Saddle(int A[m][n]) { for(i=0;i<m;i++) { for(min=A[i][0],j=0;j<n;j++) { if(A[i][j]<min) min=A[i][j]; } for(j=0;j<n;j++) { if(A[i][j]==min) { for(flag=1,k=0;k<m;k++) { if(min<A[k][j]) flag=0; if(flag) printf("%d",A[i][j]); } } } } }
-
树
-
如果二叉树T2是由有序树T1转换而来的二叉树,那么T1中结点的先序就是T2中结点的(A)。
- A.先序
- B.中序
- C.后序
- D.层次序
-
如果二叉树T2是由有序树T1转换而来的二叉树,那么T1中结点的后序就是T2中结点的(A)。
- A.先序
- B.中序
- C.后序
- D.层次序
-
某二叉树的先序遍历序列和后序遍历序列正好相反,则该二叉树一定是(D)。
-
A.空树或只有一个结点
-
B.完全二叉树
-
C.二叉排序树
-
D.高度等于其结点数
-
-
任何一棵二叉树的叶子结点在先序、中序和后序遍历序列中的相对次序(A)。
- A.不发生改变
- B.发生改变
- C.不能确定
- D.以上都不对
-
若二叉树采用二叉链存储结构,要交换其所有分支结点的左、右子树位置,利
用©遍历方法最合适。
- A.先序
- B.中序
- C.后序
- D.按层次
-
二叉链表存储二叉树。在这种存储结构中,n个结点的二叉树共有2n个指针域,其中有n-1个指针域是存放了地址,有n+1个指针是空指针。
-
二叉树的先序序列和中序序列相同的条件是任何结点至多只有右子树。
-
二叉树的后序序列和中序序列相同的条件是任何结点至多只有左子树。
-
设哈夫曼树中共有n个结点,则该哈夫曼树中有0个度数为1的结点。
-
由一棵二叉树的先序序列和后序序列可以惟一确定它。F
-
树中元素之间是多对多的关系。F
-
哈夫曼树是带权路径长度最短的树,路径上权值较大的结点离根较近。T
-
具有n 个结点的二叉排序树有多种,其中树高最小的二叉排序树是最佳的。T
-
写出求二叉树各结点层数的算法,假定主调语句用法如:level(root, 1)。
-
typedef struct Bnode //结点类型定义 { element_type data; //值域 int layer; struct Bnode *Lson, *Rson; //指向左右儿子的链域 }Bnode, *Bptr; // 结点类型名,和指针类型名 void level(Bptr p,int i) { if(p==NULL) return; p->layer=i; level(p->Lson,i+1); level(p->Rson,i+1); }
-
-
孩子兄弟链表统计树的深度
-
int GetDepth_CSTree(CSTree T) { if(!T) return 0; else { for(maxd=0,p=T->firstchild;p;p=p->nextsib) { if((d=GetDepth_CSTree(p))>maxd) { maxd=d; } } return maxd + 1; } }
-
-
编写按层次顺序遍历二叉树
-
void LayerOrder(BiTree T) { InitQueue(Q); EnQueue(Q,T); while(!QueueEmpty(Q)) { DeQueue(Q,p); visit(p); if(p->lchild) EnQueue(Q,p->lchild); if(p->rchild) EnQueue(Q,p->rchild); } }
-
-
写出求二叉树各结点的高度的算法,假定主调语句用法如:h=high(root)。
-
typedef struct Bnode //结点类型定义 { element_type data; //值域 int height; struct Bnode *Lson, *Rson; //指向左右儿子的链域 }Bnode, *Bptr; // 结点类型名,和指针类型名 int high(Bptr p) { if(p==NULL) return 0; //空树的高度等于0 i=high(p->Lson); j=high(p->Rson); p->height=(i>j)? i+1: j+1; //求出结点高度 return (p->height); }
-
-
编写算法输出给定结点a所有子孙,假定主调语句用法。如:found=0;descents(root,a)。
-
typedef struct Bnode //结点类型定义 { element_type data; //值域 struct Bnode *Lson, *Rson; //指向左右儿子的链域 }Bnode, *Bptr; // 结点类型名,和指针类型名 void descents(Bptr p,element_type a) { if(p==NULL|| found==3 ) return; if(p->data==a) found=1; if(found==1) printf("%4d",p->data); descents(p->Lson,a); descents(p->Rson,a); if(p->data==a) found=3; }
-
-
写出下列函数的功能
-
int AE(BTNode *b) { int num1,num2; if (b==NULL) return 0; else if (b->lchild==NULL && b->rchild==NULL) return 1; else { num1=AE(b->lchild); num2=AE(b->rchild); return (num1+num2+1); } } /* 函数名:AE; 1) 功能: 求根节点为b的二叉树的结点个数; 2) 输入参数: *b为待求节点数的树的根节点,也可以为子树的子根节点; 3) 输出参数:如果树为空,返回0,否则返回所求树的实际的节点总数。 */
-
int AF(BTNode *b) { int num1,num2; if (b==NULL) return 0; else if (b->lchild==NULL && b->rchild==NULL) return 1; else { num1=AF(b->lchild); num2=AF(b->rchild); return (num1+num2); } } /* 函数名:AF; 1) 功能: 求根节点为b的二叉树的叶子结点个数; 2) 输入参数: *b为待求叶子个数的树的根节点,也可以为子树的子根节点; 3) 输出参数:如果树为空,返回0,否则返回所求树的实际的叶子节点总数。 */
-
图
-
采用邻接表存储的图的深度优先遍历算法类似于二叉树的(A)。
- A.先序遍历
- B.中序遍历
- C.后序遍历
- D.按层遍历
-
采用邻接表存储的图的广度优先遍历算法类似于二叉树的(D)。
- A.先序遍历
- B.中序遍历
- C.后序遍历
- D.按层遍历
-
任何一个无向连通图的最小生成树(A)。
- A.有一棵或多棵
- B.只有一棵
- C.一定有多棵
- D.可能不存在
-
判定一个有向图是否存在回路,除了可以利用拓扑排序方法外,还可以用(D)。
-
A.求关键路径的方法
-
B.求最短路径的Dijkstra方法
-
C. 求最短路径的方法
-
D. 求图遍历的方法(深)
-
-
下面不正确的说法是©。
(1)求从指定源点到其余各顶点的Dijkstra最短路径算法中弧上权值可以为负值。(2)利用Dijkstra算法求所有不同顶点对的最短路径的算法时间为O(n^3)(图用邻接矩阵表示)。(3)利用Floyd算法求每个不同顶点对的算法中允许弧上的权值为负,但不能有权之和为负的回径。
-
A.(1)、(2)、(3)
-
B.(1)
-
C.(1)、(3)
-
D.(2)、(3)
-
-
如果含n个顶点的图形成一个环,则它有n棵生成树。
-
设图G有n个顶点和e条边,采用邻接矩阵存储,则拓扑排序算法的时间复杂度为O(n+e)。
-
求最小生成树的克鲁斯卡尔算法的时间复杂度为 O ( e l o g 2 e ) O(elog_2e) O(elog2e),它对稀疏图较为适合。
-
若一个有向图的邻接矩阵中对角线以下元素均为零,则该图的拓扑有序序列必定存在。T
-
拓扑排序是按AOE 网中每个结点事件的最早发生时间对结点进行排序。F
-
编写一个算法将一个无向图的邻接矩阵转换成邻接表。
-
//解先设置一个空的邻接表,然后在邻接矩阵上查找值不为0的元素,找到后创建表结点并在邻接表对应的单链表中插入该结点。算法如下: void mattolist (AdjMaxix a,AdjList *&g) { int i,j,n; n=a.n; ArcNode *p; for (i=0; i<n;i++) g [i]->firstarc=NULL; for (i=0; i<n; i++) for (j=n-1; j>=0; j--) if (a.edges[i] [j] !=0) { p=(ArcNode *)malloc(sizeof(ArcNode)); p->adjvex=j ; p->nextarc=g[i]->firstarc; g[i]->firstarc=p; } }
-
-
假设图用邻接矩阵表示,设计一个算法,判定从顶点 v i v_i vi到顶点 v j v_j vj是否可达。
-
//解可通过递归的深度遍历米实现。定义递归算法connected(adj,i,j,c),其功能是:如果顶点vi到顶点vj可达,则c返回1,否则c返回0。检查邻接矩阵的第i行,如果vk是vi的相邻的未访问顶点,则调用connected(adj,k,j,c)。算法如下: int visited [MAXVEX] ; void connected(AdjMaxix adj,int i,int j,int &c) { int k; if (i==j) c=1; else { k=0; c=0; while(k<adj.n && c==0) { if(adj.edges[i][k]==1 && visited[k]==0) { visited[k] =1; connected (adj, k, j, c); } else k++; } } }
-
-
拓扑排序算法
-
void count_indegree(ALGraph *G) { int k; ArcNode *p; for (k=0;k<G->vexnum;k++) G->vertices[k].indegree=0; //顶点入度初始化 for(k=0;k<G->vexnum;k++) { p=G->vertices[k].firstarc; while (p!=NULL) { //顶点入度统计 G->vertices[p->adjvex].indegree++; p=p->nextarc; } } } int Topologic_Sort(ALGraph *G, int topol[]) { //顶点的拓扑序列保存在一维数组topol中 int k, no, vex_no, top=0, count=0, boolean=1; int stack[MAX_VEX]; //用作堆栈 ArcNode *p; count_indegree(G); //统计各顶点的入度 for (k=0;k<G->vexnum;k++) if (G->vertices[k].indegree==0) stack[top++]=k; do { if (top==0) boolean=0; else { no=stack[top--]; //栈顶元素出栈 topol[count++]=no; //记录顶点序列 p=G->vertices[no].firstarc; while (p!=NULL) { //删除以顶点为尾的弧 vex_no=p->adjvex; G->vertices[vex_no].indegree--; if(G->vertices[vex_no].indegree==0) stack[top++]=vex_no; p=p->nextarc; } // end while } //end if }while(boolean==1); if (count<G->vexnum) return(-1); else return(1); }
-
查找表
-
若有18个元素的有序表存放在一维数组A[19]中,第一个元素放A[1]中,现进行二分查找,则查找A[3]的比较序列的下标依次为(D)
-
(A) 1,2,3
-
(B) 9,5,2,3
-
© 9,5,3
-
(D) 9,4,2,3
-
-
设有序表中有 n n n个元素,则用二分查找查找元素最多需要比较 └ l o g 2 n ┘ + 1 \llcorner log_2n\lrcorner+1 └log2n┘+1次。
-
为了能有效地应用HASH查找技术,必须解决的两个问题是构造好的hash函数和确定解决冲突方法。
-
顺序查找法适合于存储结构为(B)的线性表。
- A 散列存储
- B 顺序存储或链式存储
- C 压缩存储
- D 索引存储
-
二叉树为二叉排序树的充分必要条件是其任一结点的值均大于其左孩子的值、小于其右孩子的值。F
-
下面关于B树和B+树的叙述中,不正确的结论是(A)。
-
A B树和B+树都能有效的支持顺序查找
-
B B树和B+树都能有效的支持随机查找
-
C B树和B+树都是平衡的多叉树
-
D B树和B+树都可用于文件索引结构
-
-
以下说法错误的是(B)。
-
A.散列法存储的思想是由关键字值决定数据的存储地址
-
B.散列表的结点中只包含数据元素自身的信息,不包含指针。
-
C.负载因子是散列表的一个重要参数,它反映了散列表的饱满程度。
-
D.散列表的查找效率主要取决于散列表构造时选取的散列函数和处理冲突的方法。
-
-
在各种查找方法中,平均查找长度与结点个数n 无关的查找方法是散列查找。
-
散列法存储的思想是由关键字值决定数据的存储地址。T
-
递归算法二叉排序树中从大到小输出不小于x的值
-
void PrintNTL(AVLTree T, int x) { if(T->lchild) printNTL(T->lchild, x); if(T->lchild < x) exit(); printf("%d", T->data); if(T->rchild); printNTL(T->rchild, x); }
-
-
合并二叉排序树
-
void BSTree_Merge(BiTree &T, BiTree &S) { if(S->lchild) BSTree_Merge(T,s->lchild); if(S->rchild) BSTree_Merge(T,s->rchild); Insert_Node(T,S); } void Insert_Node(BiTree &T, BTNode* S) { if(S->data > T->data) { if(!T->rchild) T->rchild = S; else Insert_Node(T->rchild, S); } else if(S->data < T->data) { if(!T->lchild) T->lchild = S; else Insert_Node(T->lchild, S); } S->lchild=NULL; S->rchild=NULL; }
-