线性表
顺序表
定义
| 1 | 
 | 
逆置
| 1 | //逆置 | 
删除
| 1 | //删除所有介于s和t之间的结点 | 
逆置的应用
| 1 | //将a1,a2...am,b1,b2...bn交换为序列b1,b2..bn,a1,a2...am | 
链表
定义
| 1 | 
 | 
初始化
| 1 | //创造一个空的线性表 | 
查找
| 1 | //从第一个位置起查找与e匹配的数据元素,若存在则返回该数据元素的位置 | 
插入
| 1 | //在单链表的第i个数据元素之前插入新的数据元素 | 
删除
| 1 | //在单链表中删除第i个数据元素并用数据变量e返回其值 | 
栈和队列
栈
| 1 | 
 | 
队列
| 1 | 
 | 
stack&queue 头文件
| 1 | 
 | 
树
二叉链表
定义
| 1 | 
 | 
遍历
先序遍历
| 1 | //先序遍历二叉树(递归) | 
中序遍历
| 1 | //中序遍历二叉树(递归) | 
后序遍历
| 1 | //后序遍历二叉树(递归) | 
层序遍历
| 1 | //层序遍历 | 
深度
| 1 | //求二叉树的深度(递归) | 
构建二叉树
先序 + 中序
| 1 | //按先序和中序次序建立二叉树 | 
中序 + 后序
| 1 | BTNode* CreateBinaryTree4(Elemtype_t ch1[],Elemtype_t ch2[],int postL,int postR, | 
中序 + 层序
| 1 | //中序+层序 | 
打印 x 的祖先
| 1 | //打印结点值为x的所有祖先节点 | 
查找指定结点
| 1 | //返回二叉树中元素值为e的结点指针 | 
其他操作
交换二叉树的左右节点
| 1 | //交换二叉树的左右节点 | 
判断完全二叉树
| 1 | //判断二叉树是否是完全二叉树 | 
复制一颗二叉树
| 1 | //复制一颗二叉树 | 
统计叶结点个数
| 1 | //统计树的叶结点个数 | 
二叉搜索树 (BST)
查找
| 1 | //二叉搜索树动态查找 | 
删除
| 1 | //删除 | 
平衡二叉树 (AVL)
平衡二叉树的插入
| 1 | 
 | 
其他操作
判断是否为平衡二叉树
| 1 | //暴力解法是对每个结点计算左右子树高度求平衡因子 | 
堆 (优先队列)
大根堆的初始化
| 1 | struct HNode{ | 
大根堆的插入
| 1 | //大根堆的插入 | 
大根堆删除最大值
| 1 | //大根堆删除最大值 | 
二叉树调整为最大堆
| 1 | //二叉树调整为最大堆 | 
哈夫曼树
| 1 | typedef struct HTNode *HuffmanTree; | 
图
图的存储
邻接矩阵
| 1 | 
 | 
邻接表
| 1 | //通用版基础定义方法 | 
| 1 | //利用vector快速构建 | 
十字链表
| 1 | 
 | 
* 邻接多重表
图的遍历
| 1 | const int MAXV=1000; | 
DFS
- 伪代码描述
| 1 | void DFS(int u){ //u为起点 | 
- 邻接矩阵
| 1 | int n,G[MAXV][MAXV]{INF}; //n为当前图的顶点总数 | 
- 邻接表
| 1 | vector <int> Adj[MAXV]; //和定义中不一样的是,这里压入的数表示其相邻的结点 | 
- 遍历函数
| 1 | void BFSTrave(){ //这个函数是必要的,因为图不一定是连通的,所以一定要判断所有的顶点 | 
BFS
- 伪代码描述
| 1 | void BFS(int u){ //u为起点 | 
- 邻接矩阵
| 1 | int n,G[MAXV][MAXV]; | 
- 邻接表
| 1 | vector <int> G[MAXV]; | 
- 遍历函数
| 1 | void BFSTrave(){ | 
最短路径
| 1 | const int MAXV 1000; //最大顶点数 | 
Dijkstra
- 伪代码描述
| 1 | Dijkstra(G,d[],s){ //G为图,d为源点,s为起点 | 
- 邻接矩阵
| 1 | int n,G[MAXV][MAXV]; | 
- 邻接表
| 1 | struct Node { | 
- 一些改进 - 保存每个节点最短路径的前驱节点并用递归的方法输出最短路径
 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18- //在更新每个节点的最短距离(d[i])时记录前驱 
 //临界矩阵的部分调整
 pre[MAXV] //保存每个节点的前驱节点
 for(int v=0;v
 if(vis[v]==flase&&G[u][v]!=INF&&d[u]+G[u][v]
 d[v]=d[u]+G[u][v];
 pre[v]=u;
 }
 }
 //此时可以递归的输出最短路径
 void DFS(int s,int v){ //s为起点,v为当前节点
 if(s==v){
 printf("%d\n",s);
 return;
 }
 DFS(s,pre[v]);
 printf("%d\n",v);
 }- 多条最短路径问题 - 同上只需在更新节点最短路径的时候略作调整进行相应的判断 - 可以新增一个数组来表示边权、点权和最短路径条数 - 给每条边在增加一条边权(二维数组 cost 记录边权,c [] 记录最小花费)
 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- for(int v=0;v
 if(vis[v]==false&&G[u][v]!=INF){
 if(d[u]+G[u][v]
 d[v]=d[u]+G[u][v];
 c[v]=c[u]+cost[u][v];
 pre[v]=u;
 }else if(d[u]+G[u][v]==d[v]&&c[u]+cost[u][v]
 c[v]=c[u]+cost[u][v];
 pre[v]=u;
 }
 }
 }- 给每个顶点增加一个点权(weight [] 记录点权,w [] 为路径上的最大点权和)
 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- for(int v=0;v
 if(vis[v]==false&&G[u][v]!=INF){
 if(d[u]+G[u][v]
 d[v]=d[u]+G[u][v];
 w[v]=w[u]+weight[v];
 pre[u]=v;
 }else if(d[u]+G[u][v]==d[v]&&w[u]+weight[v]>w[v]){
 w[v]=w[u]+weight[v];
 pre[v]=u;
 }
 }
 }- 到达每个顶点的最短路径条数(用 num [] 保存)
 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10- for(int v=0;v
 if(vis[v]==false&&G[u][v]!=INF){
 if(d[u]+G[u][v]
 d[v]=d[u]+G[u][v];
 num[v]=num[u];
 }else if(d[u]+G[u][v]==d[v]){
 num[v]+=num[u];
 }
 }
 }
 
Bellman-Ford
- 伪代码描述 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- for(i=0;i - -1 ;i++){ //进n-1轮操作,其中n为顶点数
 for(u的所有邻接边u->v){
 if(d[u]+length[u->v]
 d[v]=d[u]+length[u->v]
 }
 }
 //如果图中有负环,则d还能进行更新,返回false
 for(u的所有邻接边u->v){
 if(d[u]+length[u->v]
 return false;
 return true;
 }
- 邻接表 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28- struct Node{ 
 int v,dis;
 }
 vector- G[MAXV] 
 int n;
 int d[MAXV];
 bool Bellman(int s){
 fill(d,d+MAXV,INF);
 d[s]=0;
 for(int i=0;i- -1 ;i++){
 for(int u=0;u
 for(int j=0;j
 int v=G[u][j].v;
 int dis=G[u][j].dis;
 if(d[u]+dis
 d[v]=d[u]+dis;
 }
 }
 }
 for(int u=0;u
 for(int j=0;j
 int v=G[u][j].v;
 int dis=G[u][j].dis;
 if(d[u]+dis
 return false;
 }
 }
SPFA
- 伪代码描述 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22- bool SPFA(G,d[],s){ 
 int Queue[maxn];
 int front=rear=0;
 int inq[maxn];
 初始化inq、num、d;
 源点s入队;
 while(队列非空){
 取出队首元素u;
 for(u的所有邻接边u->v){
 if(d[u]+dis
 d[v]=d[u]+dis;
 if(v当前不在队列){
 v入队;
 if(v入队次数大于n-1){
 return;//有可达负环
 }
 }
 }
 }
 }
 return;//达到最优
 }
- 邻接表 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34- vector - Adj[MAXN]; 
 int n,num[MAXN],d[MAXN];
 bool inq[MAXN];
 bool SPFA(int s){
 fill(d,d+MAXN,INF);
 fill(inq,inq+MAXN,false);
 fill(num,num+MAXN,0);
 queue <int> Q;
 Q.push(s);
 inq[s] = true;
 num[s]++;
 d[s] = 0;
 while(!Q.empty()){
 int u = Q.front();
 Q.pop();
 inq[u] = false;
 for(int i=0;i
 int v = Adj[u][i].v;
 int dis = Adj[u][i].dis;
 if(d[u]+dis
 d[v] = d[u]+dis;
 if(!inq[v]){
 Q.push(v);
 inq[v] = true;
 num[v]++;
 if(num[v]>n-1)
 return false; //进入队列n次,说明有负环
 }
 }
 }
 }
 return true;
 }
Floyd
- 外代码描述 - 1 
 2
 3
 4- 枚举所有顶点k 
 枚举所有以k为中介点的顶底对i和j
 if(dis[i][k]+dis[k][j]
 更新dis[i][j]
- 邻接矩阵 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11- //Floyd解决全源最短路径问题 
 int n,m;
 int dis[MAXV][MAXV]
 void Floyd(){
 for(int k=0;k
 for(int i=0;i
 for(int j=0;j
 if(dis[i][k]!=INF&&dis[k][j]!=INF&&dis[i][k]+dis[k][j]
 dis[i][j]=dis[i][k]+dis[k][j];
 }
最小生成树
Prim
- 伪代码描述 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12- Dijkstra(G,d[],s){ //G为图,d为源点,s为起点 
 初始化
 for(循环n次){
 u = d[u]中最小且未被访问过的点;
 将u标记为已经被访问;
 将d[u]加入最小边权和;
 for(从u出发能到达的所有顶点v){
 if(v未被访问并且以u为中介使d[v]更优)
 更新d[v] //这里的更新与最优与Dijkstra中是不一样的,但整个算法是一致的
 }
 }
 }
- 邻接矩阵 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23- int n,G[MAXV][MAXV]; 
 int d[MAXV];
 bool vis[MAXV]={false};
 int dijkstra(int s){
 int ans;
 fill(d,d+MAXV,INF);
 d[s]=0;
 for(int i=0;i
 int u=-1,MIN=INF;
 for(int j=0;j
 if(vis[j]==false&&d[j]
 u=j;
 MIN=d[j];
 }
 if(u==-1) return; //这里是不连通的情况
 vis[u]=true;
 ans += d[u];
 for(int v=0;v
 if(vis[v]==flase&&G[u][v]!=INF&&G[u][v]
 d[v]=G[u][v] //这就是前面说的不一样的地方
 }
 }
Kruskal
- 伪代码描述 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10- int Kruskal(){ 
 for(从小到大枚举所有的边){
 if(当前测试边的顶点在不同的两个连接块中){
 将该测试边加入最小生成树;
 ans+=此边权值;
 最小生成树的边数加1;
 当边数为n-1是结束循环;
 }
 }
 }
- 并查集实现 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45- struct Edge{ 
 int u,v;//边的两个端点编号
 int cost;//边权
 }E[maxn];
 int father[maxn];//并查集数组
 int FindFather(int x){
 int z,a=x;
 while(x!=father[x]){
 x=father[x];
 }
 //路径压缩
 while(a!=father[a]){
 z=a;
 a=father[a];
 father[z]=x;
 }
 return x;
 }
 int Kruskal(int n,int m){//参数n为顶点个数,m为图的边数,函数返回边权之和
 int ans=0,NumEdge=0;//ans为所求边权之和,NumEdge为当前生成树的边数
 int i;
 int faU,faV;
 //查并集初始化
 for(i=1;i<=n;i++){< span>
 father[i]=i;
 }
 //按边权大小排序
 for(i=0;i
 faU=findFather(E[i].u);
 faV=findFather(E[i].v);//查询测试边的两个端点所在集合的根节点
 if(faU!=faV){//如果不在一个集合内
 father[faU]=faV;//合并集合,把测试边加入最小生成树中
 ans+=E[i].cost;//边权之和计算
 NumEdge++;//当前生成树的边数加一
 if(NumEdge==n-1){
 break;//边数等于顶点数减一时结束算法
 }
 }
 }
 if(NumEdge!=n-1){
 return -1;//无法连通时返回-1
 }else{
 return ans;//返回最小生成树的边权之和
 }
 }
拓扑排序
- 邻接表 - 1 
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26- vector<int> G[MAXN]; 
 int n,m,inDegree[MAXN];
 bool topologicalSort(){
 int num = 0;
 queue<int> q;
 for(int i=0;i
 if(inDegree[i] == 0){
 q.push(i);
 }
 }
 while(!q.empty()){
 int u = q.front();
 q.pop();
 for(int i=0;i
 int v = G[u][i];
 inDereee[v]--;
 if(inDegree[v] == 0){
 q.push(v);
 }
 }
 G[u].clear();
 num++;
 }
 if(num == n) return true;
 else return false;
 }
* 关键路径
查找
顺序查找
| 1 | int SeqSearch(SeqList L,Elemtype key){ | 
折半查找
| 1 | int BinarySearch(SeqList L,Elemtype key){ | 
排序
插入排序
直接插入排序
| 1 | void InsertSort(Elemtype A[],int n){ | 
折半插入排序
| 1 | //折半插入排序 | 
希尔排序
| 1 | //希尔插入排序 | 
交换排序
冒泡排序
| 1 | //冒泡排序 | 
快速排序
| 1 | //快速排序 | 
选择排序
简单选择排序
| 1 | //简单选择排序 | 
堆排序
| 1 | //堆排序 | 
归并排序
二路归并排序
| 1 | //归并排序 | 
