数据结构复习
-
数据结构分为:线性结构、非线性结构
-
什么是完全二叉树?
如果一棵二叉树,只有最下面的两层节点度数小于2,其余各层结点度数都等于2,并且最下面一层节点都集中该层的最左边的若干位置上,则此二叉树为完全二叉树。
-
判断时间复杂度
- 时间复杂度为 O (1),代码只被执行一次。
- 时间复杂度为 O (n),比如常见的遍历算法。 也就是一个for循环的时间复杂度。
- O(n^2)就是嵌套for循环,就是两个for循环,是不是相当于运行了n*n次。比如冒泡和选择排序。
- 再比如 O (logn),( log 是以 2 为底)。二分搜索就是 O (logn) 的算法,每找一次排除一半的可能。
- O (nlogn) 同理,就是 n 乘以 logn,归并排序就是 典型的例子。
时间复杂度顺序:O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(2^n) < O(n!) < O(n^n)。
-
链表的优点缺点
优点:由于链表上的元素在空间存储上内存地址不连续。所以随机增删元素的时候不会有大量元素位移,因此随机增删效率较高。
-
广度优先为什么用队列
需要一层一层的遍历,相邻节点需要确定顺序,因此需要一个数据结构进行存储和操作,先遍历的结点先背存储,满足先进先出(first in first out)刚好队列满足这个条件。
-
解释栈顶、栈底、进栈、出栈
栈顶:表中允许进行插入删除的一端叫做栈顶
栈底:表的另一端
进栈:插入运算
出栈:删除运算
-
什么是插入排序,分哪几种
基本思想:每一步待排序记录,按其排序码大小,插入到前面已排序的文中适当位置,直至全部记录插入完为止。
分为:直接、二分、表、shell
-
先序(中序)画二叉树
-
哈夫曼树(构建,电文编码,计算WPL)
wpl:所有叶子节点的路劲乘以他的权重之和
哈夫曼树的构建:n个结点需要进行n-1次合并,每次合并都产生一个新的结点,所以最终的Huffman树共有2n-1个结点。
哈夫曼编码
- 最小生成树
生成树:所有顶点均由边连接在一起,但不存在回路的图称为生成树。
一个有n个顶点的连通图的生成树有n-1条边;
- 普里姆、克鲁斯卡尔(画图)
普里姆
基本思想:首先选取图中任意一个顶点 v 作为生成树的根,之后继续往生成树中添加顶点 w,则在顶点 w 和顶点 v 之间必须有边,且该边上的权值应在所有和 v 相邻接的边中属最小。
//初态
mst[5] = {{0,1,10},{0,2,∞},{0,3,∞},{0,4,19},{0,5,21}}
mst[5] = {{0,1,10},{0,2,∞},{0,3,∞},{0,4,19},{0,5,21}}
mst[5] = {{0,1,10},{1,2,5},{1,3,6},{0,4,19},{1,5,11}}
mst[5] = {{0,1,10},{1,2,5},{1,3,6},{0,4,19},{1,5,11}}
mst[5] = {{0,1,10},{1,2,5},{1,3,6},{1,5,11},{3,4,18}}
mst[5] = {{0,1,10},{1,2,5},{1,3,6},{1,5,11},{3,4,18}}
克鲁斯卡尔
连通分量 = {A},{B},{C},{D},{E},{F}
连通分量 = {A},{B,E},{C},{D},{F}
连通分量 = {A,F},{B,E},{C},{D}
连通分量 = {A,F},{B,E},{C,D}
连通分量 = {A,F,C,D},{B,E}
连通分量 = {A,F,C,D,B,E}
- 图深度优先代码和广度优先
ADT Graph is /*重点关心图中结点和边的处理*/
operations
Graph createGraph (void)
创建一个空图
int isNullGraph (Graph g )
判断图g是否空图,是则返回1,否则返回0
Vertex firstVertex (Graph g )
找图中的第一个顶点
Vertex nextVertex (Graph g , Vertex vi )
找图中顶点vi的下一个顶点
PVertex searchVertex (Graph g , Vertex vi )
在图中查找顶点
Graph addVertex (Graph g , Vertex vi )
在图g中增加一个顶点
Graph deleteVertex (Graph g , Vertex v )
在图g中删除一个顶点和与该顶点相关联的所有边
Graph deleteEdge (Graph g , Vertex vi , Vertex vj )
在图g中删除一条边e(<vi,vj>或者(vi,vj) )
Graph addEdge (Graph g , Vertex vi , Vertex vj )
在图g中增加一条边<vi,vj>或者(vi,vj)
int findEdge (Graph g , Vertex vi , Vertex vj )
判断图g中是否存在一条指定边<vi,vj>或者(vi,vj)
Vertex firstAdjacent (Graph g , Vertex v )
找图g中与顶点v相邻的第一个顶点
/*v与返回顶点构成的边也称为与v相关联的第一条边。*/
Vertex nextAdjacent (Graph g , Vertex vi , Vertex vj )
找图g中与vi相邻的,相对相邻顶点vj的下一个相邻顶点
end ADT Graph
深度优先
void dft(Graph g){
Vertex v;
for(v=firstVertex(g);v!=NULL;v=nextVertex(g,v)){
if(v.mark == FALSE){
dfs(g,v);
}
}
}
void dfs(Graph g,Vertex v){
Vertex v1;
v.mark = TRUE;
for(v1=firstAdjacent(g,v);v1!=NULL;v1=nextAdjacent(g,v,v1)){
if(v1.mark == FALSE)
dfs(g,v1);
}
}
广度优先
void bft(Graph g){
Vertex v;
for(v=firstVertex(g);v!=NULL;v=nextVertex(g,v)){
if(v.mark == FALSE){
bfs(g,v);
}
}
}
void bfs(Graph g, Vertex V) {
Vertex v1, v2;
Queue q= createEmptyQueue();
enQueue(q,v);
while(!isEmptyQueue(q)){
v1=frontQueue(q); deQueue(q);
if(v1.mark==TRUE); continue;
v1.mark=TRUE;
v2=firstAdjacent(g,v1);
while(v2!=NULL){
if(v2.mark==FALSE) enQueue(q,v2);
v2=nextAdjacent(g,v1,v2);}
}
}
- 二分查找代码
int arr[]={3,9,8};
int Search_Bin (int arr[],int k,int low,int high)
{
if(low > high){
return -1;
}
int mid = (low+high)/2;
if(arr[mid]==k){
return mid;
}else if(k<arr[mid]){
high = mid-1;
Search_Bin(arr,k,low,high);
}else{
low = mid+1;
Search_Bin(arr,k,low,high);
}
}
- 临接矩阵表示法
**邻接矩阵表示的特点**
无向图的邻接矩阵对称,可压缩存储;有n个顶点的无向图需存储空间为n(n-1)/2。
有向图邻接矩阵不一定对称;有n个顶点的有向图需存储空间为n²。
无向图中顶点Vi的度TD(Vi)是邻接矩阵A中第i行元素之和。
有向图中,
顶点Vi的出度是A中第i行元素之和。
顶点Vi的入度是A中第i列元素之和。
**邻接矩阵的优缺点**
优点:容易判定顶点间有无边(弧)和计算顶点的度(出度、入度)。
缺点:边数较少时,空间浪费较大。
-
哈希
-
冒泡排序(过程)
-
堆排序基本思想
-
简述数据结构分类特点(画线性结构的选一个和非线性的选一个画)
链表:链表是一种物理存储上非连续,数据元素的逻辑顺序通过链表中的指针链接次序,实现的一种线性存储结构。有数据域和指针域
图是一种:数据元素间存在多对多关系的数据结构加上一组基本操作构成的抽象数据类型
-
二分查找的次数
就是判断mid被比较了多少次
-
图的边
- 含有n个顶点的无相完全图有n*(n-1)/2条
- 含有n个顶点的有向完全图有n*(n-1)条
-
用栈判断回文代码
#include<stdio.h> #include<string.h> #include<stdlib.h> #define StackSize 100 //假定预分配的栈空间最多为100个元素 typedef char DataType;//假定栈元素的数据类型为字符 typedef struct { DataType data[StackSize]; int top; }SeqStack; void Init(SeqStack *&s) { s=(SeqStack *)malloc(sizeof(SeqStack)); s->top=-1; } //初始化栈 void push(SeqStack *s,DataType e) { if( s->top == StackSize ) { printf("栈满\n"); } else { s->top++; s->data[s->top]=e; } } //入栈 DataType pop(SeqStack *s) { if( s->top == -1 ) { printf("栈空\n"); return '\0'; } return (s->data[s->top--]); } //出栈 int main() { SeqStack *s; int i=0,length,mid,flag=1; char str[StackSize],y,z; printf("请输入需要判断回文的字符串:\n"); gets(str); length = strlen(str); mid = length/2-1; //mid为字符串中间字符的下标 Init(s); for( i=0; i<length/2; i++) { push(s,str[i]); } //入栈 if( length%2 != 0 ) mid += 1; //判断字符串长度是奇数还是偶数,当为奇数时从中间下一个开始比较 for( i=1; i<=length/2; i++) { if( str[mid+i] == pop(s) ) { flag = 1; } else { flag = 0; break; } } if( flag == 1 ) printf("该字符串为回文\n"); else printf("该字符串不是回文"); return 0; }
palindrome
#include<stdio.h> #include<string.h> int palindrome(char* ch) { char* front = ch; char* tail = ch + strlen(ch) - 1; while (front < tail) { if (*front != *tail) { return 0; } front++; tail++; } return 1;
}