【填空题】考研数据结构填空题整理
数据结构填空题
题源来自《算法与数据结构考研试题精析》
一、概论
-
在数据结构中,数据的逻辑结构分 线性结构 和 线性结构 。
-
链接存储的特点是利用 指针 来表示数据元之间的逻辑关系。
-
数据的物理结构包括 数据元素 的表示和 数据元素间关系 的表示。
-
对于给定的n个元素,可以构造出的逻辑结构有 集合 、 线性结构 、 树形结构 、 图结构 四种。
-
数据结构由数据的 逻辑结构 、 存储结构 和 运算 三部分组成。
-
一个数据结构在计算机中的 表示 称为存储结构。
-
数据的逻辑结构是指 数据的组织形式,即数据元素之间逻辑关系的总体。
-
数据结构是研讨数据的 逻辑结构 和 物理结构 ,以及它们之间的相互关系,并对与这种结构定义相应的 操作 ,设计出相应的 算法 。
-
抽象数据类型的定义仅取决于它的一组 逻辑特性 ,而与 在计算机内部如若表示和实现 无关,即不论其内部结构如何变化,只要它的 数学特性 不变,都不影响其外部使用。
二、线性表
-
在单链表中设置头结点的作用是 有头结点后,插入元素和删除元素的算法统一了,不再需要判断是否在第一个元素之前插入和删除第一个元素。
-
根据线性表的链式存储结构中每一个结点包含的指针个数,将线性链表分成 单链表 和 双链表 ;而又根据指针的连接方式,链表又可分成 链表 和 静态链表 。
-
链接存储的特点是利用 指针 来表示数据元素之间的逻辑关系。
-
顺序存储结构是通过 结点物理上相邻 表示元素之间的关系的;链式存储结构是通过 结点指针 表示元素之间的关系的。
-
循环单链表的最大优点是: 从任一结点出发都可访问到链表中每一个元素 。
-
指针p指向单链表的某个结点,在指针p所指结点之前插入s所指结点。操作序列: s->next=p->next;p->next=s;p->data<-->s->data 。这里用交换两结点数据的办法达到在结点前插入结点的目的。
-
判断带头结点的双循环链表L仅有一个元素结点的条件是 L->next->next=L&&L->prior->prior==L&&L->next!=L 。
-
带头结点的双循环链表L为空表的条件是: L->next==L&&L->prior=L 。
-
判断带头结点的单循环链表L仅有一个元素结点的条件是 L->next->next=L&& L-next!=L 。
三、栈和队列
-
在栈的ADT定义中,除初始化操作外,其他基本操作的初始条件都要求 栈已存在 。
-
栈是 操作受限 的线性表,其运算遵循的原则 后进先出 。
-
堆栈是一种操作受限的线性表,它只能在线性表的 一端 进行插入和删除操作,对栈的访问是按照 后进先出 的原则进行的。
-
向栈中压入元素的操作是先 进栈 ,后 退栈 。
-
当两个栈共享一存储区时,栈利用一维数组stack(1,n)表示,两栈顶指针为top[1]与top[2],则当栈1空时,top[1]为 0 ,栈2空时,top[2]为 n+1 ,栈满时为 top[1]+1=top[2] 。
-
顺序栈S的GetTop(s,e)操作是用e返回s的栈顶元素。则操作正确的是 e = *(s.top)。
-
栈是一种操作受限的线性表,它只能在线性表的 栈顶 进行操作和删除。
-
判断顺序栈是否为空的条件是 s->top == -1 ;判断顺序栈是否为满的条件是 s.top == maxsize -1 。
-
两个栈共享空间时栈满的条件 两栈顶指针相邻 。
-
为了增加内存空间的利用率和减少溢出的可能性,由两个栈共享一片连续的空间时,应将两栈的 栈底 分别设在内存空间的两端,这样只有当 两栈顶指针相邻 时才产生溢出。
-
多个栈共存时,最好用 链式存储结构 作为存储结构。
-
队列只允许在表的一端插入,插入的一端叫队尾,删除的一端叫队头。
-
顺序栈用data[1..n]存储数据,栈顶指针是top,则值为x的元素入栈的操作是 if(top!=n) data[++top]=x;
-
在按算符优先法求解表达式3-1+5x2时,最先执行的运算是 减法运算 ,最后执行的运算是 加法运算
-
循环队列是队列的一种 顺序 存储结构。
-
循环队列的引入,目的是为了克服 假溢出时大量移动数据元素 。
-
在循环队列中,队列长度为n,存储位置从0到n-1编号,以rear指示实际的队尾元素,现要在此队列中插入一个新元素,新元素的位置是 rear=(rear+1)%n 。
-
已知链队列的头尾指针分别是f和r,则将值x入队的操作序列是 new(s);s->data=x;s->next=r->next;r->next=s;r=s;
-
区分循环队列的满与空,只有两种方法,它们是 牺牲一个存储单元 和 设标记 。
-
循环队列用数组A[0..m-1]存放其元素值,已知其头尾指针分别是front和rear,则当前队列的元素个数是 (rear-front+m)%m 。
-
用循环链表表示的队列长度为n,若只设头指针,则出队和入队的时间复杂度分别是 O(1) 和 O(n) ;若只设尾指针,则出队和入队的时间复杂度分别是 O(1) 和 O(1) 。
-
设循环队列容量为Q,当rear<front时,队列长度为 (rear-front+Q)%Q 。
-
已知一循环队列的存储空间为[m..n],其中n>m,队头和队尾指针分别为front和rear,则此循环队列判满的条件是 front==(rear+1)%(n-m+1) 。
四、树和二叉树
-
树在计算机内的表示方式有 双亲链表表示法 , 孩子链表表示法 , 孩子兄弟表示法 。
-
在二叉树中,指针p所指结点为叶子结点的条件是 p->lchild==null && p->rchlid=-null 。
-
已知完全二又树的第8层(根结点的层次为0)有240个结点,则整个完全二叉树的叶子结点数是 248 。
-
一个无序的元素序列可以通过构造一棵二叉排序树而变成一个有序的元素序列 (√)
-
在顺序存储的二又树中,编号为 i 和 j 的两个结点处在同一层的条件是 用顺序存储结构存储二叉树时,要按完全二又树的形式存储,非完全二叉树存储时,要加“虚结点”。设编号为i和j的结点在顺序存储中的下标为s和t,则结点i和j在同一层上的条件是log2sHlogzt]。 。
-
若按层次顺序将一棵有n个结点的完全二叉树的所有结点从1到n编号,那么结点 i 没有右兄弟的条件为 2*i+1>n 。
-
对于一个具有n个结点的二叉树,当它为一棵 完全 二叉树时具有最小高度,当它为一棵 只有一个叶子结点的二叉树 时,具有最大高度。
-
先序遍历森林时,首先访问森林中第一棵树的 根结点 。
-
前序遍历树林正好等同于按 前序 遍历对应的二叉树,后序遍历树林正好等同于按 中序 遍历对应的二叉树。
-
二又树的先序序列和中序序列相同的条件是 任何结点至多只有右子女的二叉树 。
-
在一棵存储结构为三叉链表的二叉树中,若有一个结点是它的双亲的左子女,且它的双亲有右子女,则这个结点在后序遍历中的后继结点是 双亲的右子树中最左下的叶子结点 。
-
线索二元树的左线索指向其 前驱 ,右线索指向其 后继 。
-
在线索二叉树中,T所指结点没有左子树的充要条件是 T->ltag =1 。
-
哈夫曼树是 带权路径长度最小的二叉树,又称最优二叉树 。
-
中缀式a+b3+4(c-d)对应的前缀式为++ab34-cd ,若a=1,b=2,c=3d-4,则后缀式 db/cca-b+ 的运算结果为18 。
-
已知完全二又树的第8层(根结点的层次为0)有240个结点,则整个完全二又树的叶子结点数是 248 。
-
深度为H的完全二叉树至少有 2^(H-1) 个结点;至多有 2^H-1 个结点;H和结点总数N之间的关系是 H=[log2N]+1 。
-
完全二叉树结点的平衡因子取值只可能为 1,0,-1 。
-
完全二叉树的存储结构通常采用顺序存储结构。(T)
-
在有N个元素的最大堆中,随机访问任意键值的操作可以在O(logN)时间完成。(F)
-
哈夫曼编码是一种最优的前缀码。对一个给定的字符集及其字符频率,其哈夫曼编码不一定是唯一的,但是每个字符的哈夫曼码的长度一定是唯一的。(F)
五、图
-
若一个具有n个顶点、e条边的无向图是一个森林,则该森林中必有 n-e 棵树。
-
完全图是任意两个顶点之间存在边 ;连通图是任意两个顶点之间都有路径 。
-
有向树定义:一个顶点的入度为0,其余顶点的入度均为 1 的有向图。
-
在数据结构中,线性结构、树形结构和图形结构数据元素之间分别存在 一对一 、 一对多 和 多对多 的联系。
-
n个顶点的连通图至少有 n-1 条边。n个顶点的强连通图最少有 n 条边。
-
在无向图中,调用遍历函数(BFS 或 DFS)的次数为连通分量的个数。
-
A^3【m】[n]表示从顶点 m 到顶点 n 长度为 3 的路径一共有 A^3【m】[n]条
-
有向图G的强连通分量是指 有向图的极大强连通子图 。
-
n个顶点的无向连通图的连通分量个数为 1 个。
-
n个顶点的连通无向图,其边的条数至少为 n-1 。
-
对于一个具有n个顶点的无向连通图,它包含的连通分量的个数为 1 个。
-
如果具有n个顶点的图是一个环,则它有 n 棵生成树。
-
最小生成树不唯一。当带权无向连通图G 的各边权值不等时 或 G只有结点数减1条边时,MST唯一。
-
Prim算法求最小生成树的时间复杂度是 O(V^2) 。
-
Kruskal算法求最小生成树的时间复杂度是 O(E*logE) ,所以更适合用于 稀疏图。
-
若无向图满足 n个顶点n-1条边的无向连通图 ,则该图是树。
-
n个顶点的无向图的邻接矩阵至少有 0 个非零元素;n个顶点的有向图是强连通图至少有 n 条边。
-
N个顶点的连通图用邻接矩阵表示时,该矩阵至少有 2(N-1) 个非零元素。
-
邻接矩阵法的广度优先生成树及深度优先生成树唯一,邻接表法的不唯一。
-
无向图G有16条边,有3个4度顶点,4个3度顶点,其余顶点的度均小于3,则图G至少有 11 个顶点。
-
已知一个图的邻接矩阵表示,删除所有从第i个结点出发的边的方法是 将第i个非零元素都变为零元素。 。
-
在一个无向图的的邻接表中,若表结点的个数是m,则图中边的条数是 m/2 条。
-
图的多重邻接表表示法中,表中结点的数目是图中边的边数。 (√)
-
遍历图的过程实质上是 查找顶点的邻接点的过程 ,breath-first search遍历图的时间复杂度 O(n+e) ;depth-first search遍历图的时间复杂度 O(n+e) ,两者不同之处在于 访问顶点的顺序不同 ,反映在数据结构上的差别是 队列和栈 。
-
为了实现图的广度优先搜索,除了一个标志数组标志已访问的图的结点外,还需 队列 以存放被访问的结点以实现遍历。
-
Dikstar算法是按距离源点路径的长度小的次序产生一点到其余各定点最短路径的算法。
-
在拓扑分类中,拓扑序列的最后一个顶点必定是的顶点 出度为0
-
拓扑排序是按AOE网中每个结点事件的最早事件对结点的进行排序。(×)
-
若网中有几条关键路径,提高一条关键路径上的活动速度,不能导致整个工程缩短工期。(×)
-
AOV网中,结点表示 活动 ,边表示 活动间的优先关系 。AOE网中,结点表示 事件 ,边表示 活动 。
-
AOE网中,完成工程的最短时间是 从源点到汇点的最长路径的长度。
-
在AOE(Activity On Edge)网中,从源点到汇点路径上各个活动的时间总和最长路径称为 关键路径 。
-
AOE-网工程工期为关键活动上的权之和。(T) 工期为起点到终点的最大路径长度。
-
在AOV网中,存在环意味着 某项活动以自己为先决条件 ,这是 荒谬 的;对程序的数据流图来说,它表明存在 死循环 。
-
当一个AOV网用邻接表表示时,可按下列方法进行拓扑排序。
(1)查邻接表中入度为 零 的顶点,并进;
(2)若栈不空,则①输出栈顶元素巧,并退栈;②查i的直接后继k,对以入度处理,处理方法是 Vk入度减1, ,若入度为 零 ,则进栈;
(3)若栈空时,输出顶点数小于图的顶点数,说明有 环 ,否则拓扑排序完成。
六、数组
-
对特殊矩阵压缩可以降低运算的复杂度。 (√)
-
稀疏矩阵一般的压缩存储方法主要有两种,即 三元组存储 和 十字链表 。
七、查找
-
散列法存储的思想是由关键字值决定数据的存储地址。(×)
-
在哈希查找方法中,要解决两方面的问题,它们分别是 哈希函数的选择 及 冲突的解决。
-
在散列表中,评判一个散列函数优劣的两个主要条件是 计算简单 和 散列之后得到的元素分布均匀 。
-
一般线性表顺序查找,查找成功的平均查找长度为 (n+1)/2 ,查找失败的平均查找长度为 n+1 。
-
有序线性表顺序查找,查找失败时不一定要遍历整个线性表,查找成功的平均查找长度也为 (n+1)/2 ,但查找失败的平均查找长度为 n/2+n/n+(n+1) 。
-
采用分块查找时,数组的组织方式为 数据分成若干块,每块内数据不必有序,但块间必须有序,每块内最大的数据组成索引块。
-
对有65025个元素的有序顺序表建立索引顺序结构,在最好情况下查找到表中已有元素最多需要执行 (16) 次关键字比较。解析: 每个索引块大小为 (根号下65025) = 255,块间与块内均使用折半查找 log255+1 = 16次,比较次数=块间+块内。若使用顺序查找,则进行 255+1 = 256次。
八、算法填空
斐波那契数列递归与非递归实现
//递归实现
int Fib(int n){
if(n==0)
return 0;
else if(n==1)
return 1;
else
return Fib(n-1) + Fib(n-2);
}
//非递归实现
int Fib(int n){
if(n==0)
return 0;
else if(n==1)
return 1;
int a = 0;
int b = 1;
for (int i = 1; i < n; i++){
int temp = a;
a = b;
b = temp + a;
}
return b;
}
中序遍历非递归算法
void InOrder2(BiTree T){
InitStack(S);
BiTree p = T;
while(p ||!isEmpty(S)){
if(p){
Push(S,p);
p = p->lchild;
}
else
{
Pop(S,p);
visit(p);
p=p->rchild;
}
}
}
层次遍历
void levelOrder(BiTree T){
InitQueue(Q);
BiTree p;
EnQueue(Q,T);
while(!isEmpty(Q)){
DeQueue(Q,p);
visit(p);
if(p->lchild != NULL)
EnQueue(Q,P->lchild);
if(p->rchild!=NULL)
EnQueue(Q,p->rchild);
}
}
线索二叉树
线索二叉树结点结构
typedef struct ThreadNode{
ElemType data;
struct ThreadNode *lchild.*rchild;
int ltag,rtag;
}ThreadNode,*ThreadTree;
中序线索二叉树线索化
void InThread(ThreadTree &p,ThreadTree &pre){
if(p!=NULL){
InThread(p->lchild,pre);
if(p->lchild == NULL){
p->lchild = pre;
p->ltag = 1;
}
if(pre!=NULL && p->rchild == NULL){
p->rchild = p;
p->rtag = 1;
}
pre = p;
InThread(p->rchild,pre);
}
}
折半查找
int Binary_Search(SeqList L, ElemType key){
int low = 0, high = L.TableLen-1,mid;
while(low<=high){
mid = (low+high)/2;
if(L.elel[mid] == key)
return mid;
else if(L.elem[mid]>key)
high = mid-1;
else
low = mid+1;
}
return -1;
}
广度优先搜索
bool visited[MAX_TREE_SIZE];
void BFSTraverse(Graph G){
for(int i=0;i<G.vexnum;i++)
visited[i] = FALSE;
InitQueue(Q);
for(int i;i<G.vexnum;i++)
BFS(G,i);
}
void BFS(Graph G,int v){
visit(v);
visited[v] = TRUE;
EnQueue(Q,v);
while(!isEmpty(Q)){
DeQueue(Q,v);
for(w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w))
if(!visited[w]){
visited[w];
visited[w] = TRUE;
EnQueue(Q,w);
}
}
}
无权图单源最短路径——广搜应用
void BFS_MIN_Distance(Graph G,int u){
for(int i=0;i<G.vexnum;i++)
d[i] = MAX;
visited[u] = TRUE;
d[u] = 0;
EnQueue(Q,u);
while(!isEmpty(Q)){
DeQueue(Q,u);
for(w = FirstNeighbor(G,u);w>=0;w=NextNeighbor(G,u,w))
if(!visit[w]){
visited[w] = TRUE;
d[w] = d[u] +1;
EnQueue(Q,w);
}
}
}
深度优先搜索
bool visited[MAX_TREE_SIZE];
void DFSTraverse(Graph G){
for(int i=0;i<G.vexnum; i++)
visited[i] = FALSE;
for(int i=0;i<G.vexnum; i++)
if(!visited[i])
DFS(G,i);
}
void DFS(Graph G,int v){
visit(v);
visited[v] = TRUE;
for(w=FirstNeighbor(G,v); w>=0; w=NextNeighbor(G,v,w))
if(!visited[w])
DFS(G,w);
}
拓扑排序
bool TopologicalSort(Graph G){
InitStack(S);
for(int i=0; i<G.vexnum; i++)
Push(S,i);
int count = 0;
while(!isEmpty(S)){
Pop(S,i);
print[count++] = i;
for(p = G.Vertices[i].firstarc; p; p=p->nextarc){
v = p->adjvex;
if(!(--indegree[v]))
Push(S,v);
}
}
if(count < G.vexnum)
return false;
else
return true;
}
Prim算法——最小生成树
void MST_Prim(Graph G){
int min_weight[G.vexnum];
int adjvex[G.vexnum];
for(int i=0; i<G.vexnum; i++){
min_weight[i] = G.Edge[0][i];
adjvex[i] = 0;
}
int min_arc;
int min_vex;
for(int i=1; i<G.vexnum; i++){
min_arc = MAX;
for(int j=1; j<G.vexnum; j++)
if(min_weight[j]!=0 && min_weight[j]< min_arc{
min_arc = min_weight[j];
min_vex = j;
}
min_weight[min_vex] = 0;
for(int j=0; j<G.vexnum; j++){
if(min_weight[j]!=0 && G.Edge[min_arc]< min_weight[j]{
min_weight[j] = G.Edge[min_arc][j];
adjvex[j] = min_arc;
}
}
}
}
Kruskal算法——最小生成树
typedef struct Edge{
int a,b;
int weight;
};
void MST_Kruskal(Graph G,Edge* edges,int* parent){
heap_sort(edges);
Initial(parent);
for(int i=0; i<G.arcnum;i++){
int a_root = Find(parent,edges[i].a);
int b_root = Find(parent,edges[i].b);
if(a_root != b_root)
Union(parent,a_root,b_root);
}
}
//法二
typedef struct
{
int a,b;
int w;
}Road;
Road road[maxSize];
int v[maxSize];
int getRoot(int a)
{
while (a != v[a]) a = v[a];
return a;
}
void Kruskal(MGrapg g,int &sum,Road road[])
{
int i;
int N,E,a,b;
N = g.n;
E = g.e;
sum = 0;
for(i=0;i<N;++i) v[i] = i;
sort(road,E);
for(i=0;i<E;++i)
{
a = getRoot(road[i].a);
b = getRoot(road[i].b);
if(a!=b)
{
v[a] = b;
sum += road[i].w
}
}
}
Dijkstra算法——最短路径
void Dijkstra(Graph G,int v){
int s[G.vexnum];
int path[G.vexnum];
int dist[G.vexnum];
for(int i=0;i<G.vexnum;i++){
dist[i] = G.edge[v][i];
s[i] = 0;
if(G.edge[v][i] < MAX)
path[i] = v;
else
path[i] = -1;
}
s[v] = 1;
path[v] = -1;
for(i=0;i<G.vexnum;i++){
int min = MAX;
int u;
for(int j=0;j<G.vexnum; j++)
if(s[j]==0 && dist[j]<min){
min = dist[j];
u = j;
}
s[u] = 1;
for(int j=0;j<G.vexnum;j++)
if(s[j]==0 && dist[u]+G.Edge[u][j]<dist[j]){
dist[j] = dist[u]+G.Edges[u][i];
path[j] = u;
}
}
}
Floyd算法——最短路径
void Floyd(Graph G){
int A[G.vexnum][G.vexnum];
for(int i=0;j<G.vexnum;j++)
for(int j=0;j<G.vexnum;j++)
A[i][j] = G.edge[i][j];
for(int k=0;k<G.vexnum;k++)
for(int i=0;j<G.vexnum;j++)
for(int j=0;j<G.vexnum;j++)
if(A[i][j] > A[i][k]+A[k][j])
A[i][j] = A[i][k] + A[k][j];
}
大根堆的建立
void BuildMaxHeap(ElemType A[],int len){
for(int i=len/2; i>0 ;i--)
AdjustDown(A,i,len);
}
void AdjustDonw(ElemType A[],int k,int len){
A[0] = A[k];
for(int i=2*k;i<=len;i*=2){
if(i<len && A[i]<A[i+1])
i++;
else{
A[k] = A[i];
k=i;
}
}
A[k] = A[0];
}
void HeapSort(ElemType A[],int len){
BuildMaxHeap(A,len);
for(int i=len;i>1;i--){
Swap(A[i],A[1]);
AdjustDown(A,1,i-1);
}
}