不辜负我辛辛苦苦复习了一天,数据结构最后考了95.......挺遗憾的没考满分。
一.基本概念
1.逻辑结构就是数据元素间的逻辑关系,而不是数据元素内部的数据项之间的关系
2.数据的(逻辑结构)包括集合、线性结构、树形结构和图形结构四种基本类型
3.数据在计算机内存中的表示是指(数据的存储结构) 。
4.数据的逻辑结构是数据元素间关系的描述
5.数据结构是一门研究非数值计算的程序设计问题中计算机的(操作对象)以及它们之间的关系和运算等的学科
6.与数据元素本身的形式、内容、相对位置、个数无关的是数据的(逻辑结构 )
7.算法分析的两个主要方面是时间复杂度和空间复杂度的分析
8.计算机算法必须具备输入、输出和(可行性、确定性和有穷性)等五个特性
9.计算机算法指的是(解决问题的有限运算序列)
10.
1+2+3+......+i = n
n = (i+1)i/2所以 n的根号阶
二.顺序表操作
1.在顺序表中逻辑上相邻的元素,其对应的物理位置也是相邻的
2.所谓随机存取,就是通过首地址和元素的位序号值可以在O(1)的时间内找到指定的元素
3.若长度为n的线性表采用顺序存储结构,那么删除它的第i个数据元素之前,需要它一次向前移动(n-i)个数据元素。
4.
答案:n-i-1;上个题的i等于本题 i+1;
5.将两个结点数都为N且都从小到大有序的单向链表合并成一个从小到大有序的单向链表,那么可能的最少比较次数是:N
一个比另一个大,小的那个每个都和另一个表的第一个比。
6.将长度为n的单链表连接在长度为m的单链表之后的算法的时间复杂度为 o(n):先遍历m,然后把n拼接到m的尾部
//插入
Status ListInsert_Sq(SqList &L, int pos, ElemType e)
{
if(pos <= 0 || pos > L.length+1) return ERROR;
L.length++;
int *p = L.elem;
int *q;
if(pos >= L.listsize) {
L.elem = (int*)realloc(L.elem, sizeof(int)*(L.listsize+30));
L.listsize+=20;
}
p = L.elem + pos;
q = L.elem + L.length;
while(p < q)
{
*q = *(q-1);
q--;
}
*q = e;
return OK;
}
//删除
Status ListDelete_Sq(SqList &L, int pos, ElemType &e)
{
if(pos <= 0 || pos >= L.length+1)return ERROR;
L.length--;
int *p = L.elem+pos;
e = *p;
int *q = L.elem+L.length;
while(p <= q)
{
*p = *(p+1);
p++;
}
return OK;
}
//查找定位
int ListLocate_Sq(SqList L, ElemType e)
{
for(int i = 1; i <= L.length; i++)
{
int *p = L.elem+i;
if(*p == e){
return i;
}
}
return 0;
}
//输出
void ListPrint_Sq(SqList L)
{
for(int i = 1; i <= L.length; i++)
{
int *p = L.elem+i;
if(i!=1) printf(" ");
printf("%d",*p);
}
printf("\n");
}
三.链表
2.头插法
void ListReverse_L(LinkList &L)
{
LinkList p = L->next;
LinkList q = L->next;
while(p)
{
LinkList t = p->next;
LinkList tt = L->next;
L->next = p;
p->next = tt;//2
p = t;//2
}
if(q)
q->next = NULL;
}
3. 两个有序链表的交集
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000;
int a[maxn],b[maxn];
int main()
{
int c;
int num1 = 0;
int num2 = 0;
while(~scanf("%d",&c)&&c!=-1)
{
a[num1++] = c;
}
while(~scanf("%d",&c)&&c!=-1)
{
b[num2++] = c;
}
//1234556
//1111111234
int ans[maxn];
int sum = 0;
int n1 = 0;
int n2 = 0;
while(n1 < num1 && n2 < num2)
{
if(a[n1]==b[n2])
{
ans[sum++] = a[n1];
n1++;
n2++;
}
else if(a[n1] < b[n2])
{
n1++;
}
else if(a[n1]>b[n2])
{
n2++;
}
}
for(int i = 0; i < sum; i++)
{
if(i) printf(" ");
printf("%d",ans[i]);
}
}
四.栈
1.
2.数组模拟栈,堆栈操作合法性
#include<iostream>
#include<cstring>
#include<cstdlib>
using namespace std;
struct node
{
int a[1000];
int siz;
};
node p;
int isempty()
{
if(p.siz > 0)return 0;
else return 1;
}
int push(int x)
{
p.a[++p.siz] = x;
}
int pop()
{
return p.a[p.siz--];
}
int main()
{
int n;
scanf("%d",&n);
while(n--)
{
int ma;
scanf("%d",&ma);
p.siz = 0;
char str[105];
scanf("%s",str);
int flag = 1;
for(int i = 0; i < strlen(str); i++)
{
if(str[i] == 'S')
{
if(p.siz==ma) {
flag = 0;
break;
}
else push(1);
}
else if(str[i]=='X')
{
if(!isempty())
{
pop();
}
else
{
flag = 0;
break;
}
}
}
if(!isempty()) flag = 0;
if(flag)printf("YES\n");
else printf("NO\n");
}
}
五.广义表
1.设有一个10阶的对称矩阵A,采用压缩存储方式,以行序为主存储,a11为第一元素,其存储地址为1,每个元素占一个地址空间,则a85的地址为 (33)
1+2+3+4+5+6+7+5 = 33;
2.将一个A[1..100,1..100]的三对角矩阵,按行优先存入一维数组B[1‥298]中,A中元素A6665(即该元素下标i=66,j=65),在B数组中的位置K为()
三对角矩阵如图
66行,前面1行2个,剩余64行3个,(66,66)为对角线,则(66,65)是第一个,故2+64*3+1 = 195;
3.广义表A=(a,b,(c,d),(e,(f,g))),则式子Head(Tail(Head(Tail(Tail(A)))))的值为()
ps:tail是去掉第一个元素之后剩余的,head是取出来的第一个
第一步:(b,(c,d),(e,(f,g)))
第二步:((c,d),(e,(f,g)))
第三步:(c,d);
第四步:(d);
第五步:d;
4.设有数组A[i,j],数组的每个元素长度为3字节,i的值为1 到8 ,j的值为1 到10,数组从内存首地址BA开始顺序存放,当用以列为主存放时,元素A[5,8]的存储首地址为()。 (2分)
以列为主存储!
BA+3*(7*8+5-1) = BA+180;
六.kmp
kmp的next值就是前缀和后缀的最大匹配长度
nextval同样是匹配,如果匹配成功,则位于后面的字符的next继承匹配成功的字符的nextval值,如果不成,保持不变
例如:第一行是next,第二行nextval
ababaaababaa
011234223456
ababaabab
011234234
010104101
七.树和二叉树
1.设树T的度为4,其中度为1、2、3、4的结点个数分别为4、2、1、1。则T中有多少个叶子结点?
树的节点数等于所有点的度之和+1;即1*4+2*2+3*1+4*1+1 = 16;叶子节点是度为零的节点,即总结点减去不为零的节点:16-4-2-1-1 = 8;
2.某二叉树的后序和中序遍历序列正好一样,则该二叉树中的任何结点一定都无右孩子。
因为后序遍历是:左右根,中序遍历:左根右 两者相同则没有右子树。
3.已知一棵二叉树的先序遍历结果是ABC, 则CAB不可能是中序遍历结果
按照线序遍历,a是根,在中序遍历中,c在a左侧,b在a右侧,则先序应当是acb,矛盾。
4.
5.
若一个结点是某二叉树的中序遍历序列的后一个结点,则它必是该树的前序遍历序列中的后一个结点。 (2分)
解析:画图分析即可,考虑只有两个节点的无右子树的二叉树,中序遍历的后一个节点是根节点,而根节点在前 序遍历中一定是在开头的
6.
AB都是叶子节点,若前序AB则A在B左侧,中序遍历A也必在B左侧
7.
答案21.节点数 2*2+3*3+4*4+1 = 30,叶子数30-2-3-4 = 21;
8.如果一棵非空k(k≥2)叉树T中每个非叶子结点都有k个孩子,则称T为正则k叉树。若T的高度为h(单结点的树h=1),则T的结点数最多为(k的h次方−1)/(k−1),如果一棵非空k(k≥2)叉树T中每个非叶子结点都有k个孩子,则称T为正则k叉树。若T的高度为h(单结点的树h=1),则T的结点数最少为k(h−1)+1
9.
二叉树中第5层(根的层号为1)上的结点个数多为:
10.
满二叉树:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点二叉树。
完全二叉树:一棵二叉树至多只有最下面的一层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树
平衡二叉树:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树
11
.
c = a+b;所以不选c。
12.二叉树/树/森林转换
https://blog.youkuaiyun.com/linraise/article/details/11745559
13.
完全二叉树度为1的节点只有0或1个,其余都是度为0或2的节点
设度为2的有m个
假如有1个度为1的,1102 = 1+2m+1;m = 550;则叶子节点=1102-550-1=551;
假如0个,1102=2*m+1,不存在。
13.
第六层8个叶节点,剩余24个每个两个子节点,则第七层有48个,1+2+4+8+16+32+48=111
14.
八.图
1.如果无向图G必须进行两次广度优先搜索才能访问其所有顶点,则G一定有2个连通分量
2.
无向图保证任何情况下都是联通的,最少的边的情况是:除了一个顶点之外,其余顶点形成一个完全图,此定点与完全图中间有桥。则完全图边n*(n-1)/2 =36(n == 9),加1为37;
3.
第二行意为v1-v0,v1-v3两条边。
图如下
4.
5.有n个顶点的强连通图最多有n(n-1)条边,最少有n条边:强连通图为有向图,故n(n-1),最少n条边,方向都相同
6.邻接表存储图的广度优先遍历
void BFS ( LGraph Graph, Vertex S, void (*Visit)(Vertex) )
{
int queue[1010];
int l=0,r=0;
queue[r++]=S;
(*Visit)(S);
Visited[S]=true;
PtrToAdjVNode tmp;
while(l!=r)
{
tmp=Graph->G[queue[l++]].FirstEdge;
while(tmp)
{
Vertex pos=tmp->AdjV;
if(!Visited[pos])
{
Visit(pos);
Visited[pos]=true;
queue[r++]=pos;
}
tmp=tmp->Next;
}
}
}
7.深度优先遍历
void DFS( MGraph Graph, Vertex V, void (*Visit)(Vertex) )
{
if(!Visited[V]) {
(*Visit)(V);
Visited[V] = true;
for(int i = 0; i < Graph->Nv; i++)
{
if(Graph->G[V][i] == 1)
DFS(Graph, i, Visit);
}
}
return ;
}
8.
计算S到V短路径的递推式是:count[V] = count[V] + count[S]。可得A答案比较合适
9.
10.
三四正确,若ca之间最短路径小于七,则d(ba)=bc+ca<10
九.队列
1.所谓“循环队列”是指用循环数组表示的队列
2.
front和rear是m-1,size是m
十.期中考试
1.
2.
十一.b树
1.用二分查找从100个有序整数中查找某数,最坏情况下需要比较的次数
log2n上取整
2.折半向上取整
向下取整
3.二叉搜索树插入:插入在叶子节点
删除,只有一个子树,用唯一的子树代替,
两个子树,则用右子树最左孩子代替,然后执行删除右子树最左孩子
装填因子定义为:α= 填入表中的元素个数 / 散列表的长度
查找成功时的平均查找长度=表中每个元素查找成功时的比较次数之和/表中元素个数;
计算查找不成功的次数就直接找关键字到第一个地址上关键字为空的距离即可。除以表长