尚未完成,全部内容,当做一个知识点梳理还算可以
排序:
直接插入排序:
思想:每次选择一个数,从一组数的第二个数开始一直到最后一个,每次从选择的这个数开始向前,如果遍历到的数大于目前我选择的数,那么令遍历到的数向后移动一位。
复杂度:平均 n2 正序:n 逆序:n2
稳定性:稳定
代码:
void insertsort(int a[],int n)
{
int j,temp,i;
for(i=1;i<n;i++)
{
temp=a[i];
for(j=i-1;j>=0&&temp<a[j];j--)
a[j+1]=a[j];
a[j+1]=temp;
}
}
希尔排序(跳跃式插入排序)
思想:在直接插入排序的基础上利用二进制拆分对区间进行拆分。
复杂度: 平均 n*log2n 正序:n1.3 最坏情况:n2
稳定性:不稳定
void mysort::shellsort(int a[],int n)
{
int j,d,i,temp;
for(d=n/2;d>=1;d/=2)
{
for(i=d;i<n;i++)
{
temp=a[i];
for(j=i-d;j>=0&&a[j]>temp;j-=d)
a[j+d]=a[j];
a[j+d]=temp;
}
}
}
冒泡排序
思想:每一次必然能放置一个最大值到最后位置,那么第一次范围就是1-n,然后n不断减1,每一次遍历都要对比所有范围内的数据,并且把范围内的最大值放到最末尾,有点像选择排序
改进:我们不妨设置一个变量e,存储每一次遍历后最大值放到哪里了,比如第三次遍历就放到了n-5的位置那么显然就能避免两次遍历
稳定性:稳定
复杂度:平均 :n2 正序:n 逆序:n2
void mysort::Bubblesort(int a[],int n)
{
int j,e,bound,temp;
e=n-1;
while(e)
{
bound=e;
e=0;
for(j=0;j<bound;j++)
{
if(a[j]>a[j+1])
{
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
e=j;
}
}
}
}
选择排序
思想:每次选一个最小的放到最前面,范围从1到n不断缩小至n-1到n
复杂度: 对初始序列并不敏感 遍历复杂度均为:n2 但是注意,初始序列仍会对交换这一操作产生影响。
稳定性:稳定
void selectsort(int a[],int n)
{
int pos=0;
for(int i=0;i<n;i++)
{
pos=i;
for(int j=i+1;j<n;j++)
{
if(a[pos]>a[i])
{
pos=j;
}
}
if(pos!=i)
{
swap(a[pos],a[i]);
}
}
}
堆排序
思想:建立根堆
根堆:就是完全二叉树,初始堆是层序建立的,后调整为大根堆或小根堆
调整:从最后一个不为叶子的节点开始,保证左右子节点权值均小于(大根堆)或大于(小根堆)根节点。
动图表示:
复杂度:对初始序列并不敏感 nlog2n
稳定性:不稳定
代码:
void mysort::heapsort(int n,int a[])
{
int i,temp;
for(i=ceil(n/2)-1;i>=0;i--)
{
modify(i,a,n-1);
}
for(i=1;i<n;i++)
{
temp=a[0];
a[0]=a[n-i];
a[n-i]=temp;
modify(0,a,n-i-1);
}
}
void mysort::modify(int k,int a[],int last)
{
int i,j,temp;
i=k,j=2*i+1;
while(j<=last)
{
if(j<last&&a[j]<a[j+1])j++;
if(a[i]>a[j])break;
else
{
temp=a[i];a[i]=a[j];a[j]=temp;
i=j;
j=2*i+1;
}
}
}
快速排序(轴值排序)
思想:每次选定第一个数为轴值(通常是这样的),调整轴值位置到左方均小于轴值和右方均大于轴值
复杂度: 平均:nlog2n 最好:nlog2n 正序或者逆序: n2
代码
int mysort::partition1(int f,int l,int a[])
{
int i=f;
int j=l;
int temp;
while(i<j)
{
while(i<j&&a[i]<=a[j])j--;
if(i<j)
{
temp=a[i];
a[i]=a[j];
a[j]=temp;
i++;
}
while(i<j&&a[i]<=a[j])i++;
if(i<j)
{
temp=a[i];
a[i]=a[j];
a[j]=temp;
j--;
}
}
return i;
}
void mysort::quicksort(int a[],int first,int last)
{
if(first>=last)
{
return;
}
else
{
int p=partition1(first,last,a);
quicksort(a,first,p-1);
quicksort(a,p+1,last);
}
}
不难看出,我们最优秀的快速排序实际上是基于划分的递归.
二路归并排序(二路分治排序)
这个考程序的概率低,暂且不搞代码了
思想:分治
复杂度: 对初始序列不敏感 n*log2n
基数排序
查找
考点:查找长度(成功,失败),二叉排序数(建立),二叉平衡树(调整,LL,RR,LR,RL),B数基本概念(阶数与分支),哈希(基本概念,建立-冲突-堆积)
平衡二叉树:
1.第一步确定类型
找到引起不平衡节点,找到最小不平衡子树,从最小不平衡子树的树根向引发点走两步
2.旋转
RR LL型旋转一次,LR,RL型旋转两次(第一次在最小不平衡子树的下一个节点上做一次普通旋转,然后再在原本最小不平衡子树上做一次普通旋转)
旋转,以此节点为待旋转点,旋转方向所有子树层次下降1,待旋转点和非旋转方向子树上升1;
图论
极有可能设计到的编程:BFS DFS遍历图
其他考点:Prim(按点寻最小生成),Kruskal(按边寻最小生成),Dijkstra(暴力最短路径),Floyd(背包DP寻找最短路径),AOV网和拓扑排序,AOE网和关键路径,这些考点在考研和期末考试掌握思想,了解程序即可。
邻接矩阵存储:
BFS:
///图的存储:邻接矩阵存储,vis数组为标记数组,vertexnum为节点树,edge[][]记录了点之间的边信息
void BFS(int n)///从n开始BFS遍历,
{
bool vis[vertexnum]=false;
int q[vertexnum];
int rear=first=-1,temp;
q[++rear]=n;
while(rear!=first)
{
temp=q[++first];
cout<<temp<<endl;
vis[temp]=true;
for(int i=0;i<vertexnum;i++)
{
if(!vis[i]&&edge[i][j])
{
q[++rear]=i;
}
}
}
}
DFS:
bool vis[vertexnum];
void DFS(int n)///从n开始BFS遍历,
{
vis[n]=true;
cout<<n<<endl;
for(int i=0;i<vertexnum;i++)
{
if(!vis[i]&&edge[n][i])
{
DFS(i);
}
}
}
链表存储(小概率,但是很重要,也很可能会考)
BFS
重点:这个需要理解链表图的结构
struct vertex
{
int vertex;
edge *first;
}adjlist[vertexnum];
struct edge
{
int vertex;
edge *next;
};
bool vis[vertexnum];
void BFS(int n)///从n开始BFS遍历,
{
bool vis[vertexnum]=false;
int q[vertexnum];
int rear=first=-1;
int temp;
q[++rear]=n;
while(rear!=first)
{
temp=q[++first];
cout<<temp<<endl;
vis[temp]=true;
edge *p=nullptr;
p=adjlist[temp].first;
while(p!=nullptr)
{
if(!vis[p->vertex])
q[++rear]=p->vertex;
p=p->next;
}
}
}
DFS
void DFS(int n)
{
cout<<n<<endl;
vis[n]=true;
edge *p=nullptr;
p=adjlist[n].first;
while(p!=nullptr)
{
if(!vis[p->vertex])
DFS(p->vertex);
p=p->next;
}
}
拓扑排序与AOV网
高大上的名字看上去感觉好像是什么高深的东西,实际上就是个 等级排序和时间顺序表。
解释一下:比如我们要做一锅汤,那么给菜改刀,点火,放菜,放水,上菜等等都是有先后顺序的,总不可能先上菜再给菜改刀吧?那么每个时间就有了优先级(谁是谁的前提事件)
AOV网就是描述这种事件顺序的网络,拓扑排序就是根据优先级进行的排序
特别注意
1.a,(b,c),d、这种情况,也就是b,c同级,那么abcd或acbd都是可行的顺序。
2.拓扑排序必须是有向无环图
AOE网和关键路径
围绕四个问题,点的最早发生时间,点的最迟发生时间,边的最早发生时间,边的最迟发生时间
字符串和多维数组
无编程考点
其他考点:KMP的next数组计算,KMP匹配过程,特殊矩阵地址变换(一般就是围绕等差等比数列,属于概念+高中基础知识,还有行列有限的转换)
树和二叉树
我这次期末必考程序:二叉树后序遍历的逆序。
常考高频:二叉树遍历,树深度,叶子节点树(可以说,就是考了个二叉树遍历,掌握个递归就完了,偶尔还会考考二叉树构造)
其他考点:森林,数,二叉树之间的转换(孩子兄弟表示法),哈夫曼树(合法哈夫曼树的两个判定),线索二叉树(二叉链表,左子右父),树的遍历,树的建立(已知中序+前/后序构建二叉树)
不常考考点:并查集,其他表示法
二叉树的构建
struct node
{
int a;
node *lc,*rc;
};
class tree
{
node *root;
public:
void porder()
{
}
node *creat()
{
int a;
node *p;
cin>>a;
if(a=='#')
p=nullptr;
else
{
p=new node;
p->a=a;
p->lc=creat();
p->rc=creat();
}
return p;
}
tree()
{
root=creat();
}
};
前序遍历
void porder(node *t)
{
if(t==nullptr)
return;
else
{
cout<<t->a<<endl;
porder(t->lc);
porder(t->rc);
}
}
中后序略
层序遍历
void lorder()
{
node *q[100],*p=nullptr;
int front1=-1,rear=-1;
if(root==nullptr)
{
return;
}
q[++rear]=root;
while(rear!=front1)
{
p=q[++front1];
cout<<p->a<<endl;
if(p->lc!=nullptr)
q[++rear]=p->lc;
if(p->rc!=nullptr)
q[++rear]=p->rc;
}
}
树深度
int treed(node *t)
{
int lh,rh,max1;
if(t!=nullptr)
{
lh=treed(t->lc);
rh=treed(t->rc);
max1=lh>rh?lh:rh;
return(max1+1);
}
return 0;
}
来张全家福
struct node
{
char c;
node *lc,*rc;
};
class tree
{
private:
node *root;
public:
node *creat()
{
node *p=nullptr;
char a;
cin>>a;
if(a=='#')
p=nullptr;
else
{
p=new node;
p->c=a;
p->lc=creat();
p->rc=creat();
}
return p;
}
node *Root()
{
return this->root;
}
tree()
{
root=creat();
}
int treed(node *t)
{
int lh=0,rh=0,max1=0;
if(t==nullptr)
return 0;
else
{
lh=treed(t->lc);
rh=treed(t->rc);
max1=rh>lh?rh:lh;
return (max1+1);
}
}
void preorder(node *t)
{
if(t==nullptr)
return ;
else
{
cout<<t->c<<endl;
preorder(t->lc);
preorder(t->rc);
}
}
void lorder()
{
node *q[100],*p=nullptr;
int front1=-1,rear=-1;
q[++rear]=root;
while(rear!=front1)
{
p=q[++front1];
if(p->lc!=nullptr)
q[++rear]=p->lc;
if(p->rc!=nullptr)
q[++rear]=p->rc;
}
}
};
栈和队列:
可能涉及到程序:栈和队列的实现
其他考点:括号匹配问题,表达式问题,双端队列和两栈共享空间问题
线性表:
必考程序:单链表的基本操作
其他考点:约瑟夫环,双链表,循环链表
目前尚不熟悉考点:
所有编程考点都再过一遍
四个排序
图的两个存储下的两种遍历(共四个遍历)
二叉树遍历
栈,线性栈,链表栈,共享空间栈
队列,线性队列,链表队列,循环队列,*双端队列(最后有时间就看看)
单链表
老师指出的部分章末习题