这里主要是记录各类数据结构的结构体, 对于具体实现和讲解往后回会以连接形式提供, 这里只提供一个思惟树, 创建一个数据结构的思惟体系, 后续更新欢迎关注 GitHub.node
typedef struct {
ElemType * elem;
int length;
int listsize;
} SqList;复制代码
typedef struct LNode {
ElemType data;
struct LNode * next;
} LNode, * LinkList;复制代码
typedef struct {
ElemType data;
int cur; // 游标指向下一个元素的数组下标
} component, SlinkList[MAXSIZE];复制代码
typedef struct DuLNode{
ElemType data;
struct DuLNode * prior;
struct DuLNode * next;
} DuLNode, * DuLinkList;复制代码
typedef struct {
SELemType * base;
SElemType * top;##### int stacksize;
} SqStack;复制代码
应用: 主要是利用先进后出的特性git
数制转换github
括号匹配检测面试
行编辑程序算法
迷宫非递归求解数组
表达式求值数据结构
Hanoi塔问题curl
typedef struct QNode {
QElemType data;
struct QNode * next;
} QNode, * QueuePtr;
typedef struct {
QueuePtr front;
QueuePtr rear;
} LinkQueue;复制代码
typedef struct {
QElemType * base;
int front;
int rear;
} SqQueue;复制代码
typedef unsigned char SString[MAXSTRLEN + 1];
SString s;复制代码
typedef struct {
char * ch;
int length;
}HString;复制代码
typedef struct Chunk{
char ch[CHUNKSIZE];
struct Chunk * next;
} Chunk;
typedef struct {
Chunk * head;
Chunk * tail;
int curlen;
} LString;复制代码
应用函数
- 子串定位 (KMP)
typedef struct {
ElemType * base;
int dim; // 数组维数
int * bounds; // 维界基址
int * constants; // 印象函数常量基址
} Array;复制代码
讨论稀疏矩阵的存储优化
typedef struct {
int i;
int j;
ElemType e;
} Triple;
typedef struct {
Triple data[MAXSIZE + 1];
int mu; // 行
int nu; // 列
int tu; // 非零个数
}TSMatrix;复制代码
typedef struct {
Triple data[MAXSIZE + 1];
int rpos[MAXRC + 1]; // 各行第一个非零元素位置表
int mu, nu, tu;
} RLSMatrix;复制代码
typedef struct OLNode {
int i;
int j;
ElemType e;
struct OLNode * right; // 该非零元素所在行的右链域
struct OLNode * down; // 该非零元素所在列的下链域
} OLNode, * OLink;
typedef struct {
OLink * rhead; // 行链表头指针地址
OLink * chead; // 列链表头指针地址
int mu, nu, tu;
} CrossLink;复制代码
表中有表
typedef enum { ATOM, LIST } ElemTag; // 0 : 原子, 1 : 子表
typedef struct GLNode {
ElemTag tag;
union {
AtomType atom;
struct {
struct GLNode * hp; // 表头
struct GLNode * tp; // 表尾
} ptr; // 表节点指针域
};
} * GList;复制代码
typedef enum { ATOM, LIST } ElemTag; // 0 : 原子, 1 : 子表
typedef struct GLNode {
ElemTag tag;
union {
AtomType atom;
struct {
struct GLNode * hp; // 表头
} ptr; // 表节点指针域
};
struct GLNode * tp; // 表尾, 至关于 next.
} * GList;复制代码
数组, 利用下标寻址
typedef TElemType SqBiTree[MAX_TREE_SIZE];复制代码
typedef struct BiTNode {
TElemType data;
struct BiTNode * lchild;
struct BiTNode * rchild;
} BiTNode, * BiTree;复制代码
根节点 -> 左子树 -> 右子树
左子树 -> 根节点 -> 右子树
左子树 -> 右子树 -> 根节点
算数表达式 a + b * (c - d) - e / f
前缀表达式-先序遍历(逆波兰 : - + a * b - cd / ef)
中缀表达式-中序遍历(原表达式 : a + b * (c - d) - e / f)
后缀表达式-后续遍历(逆波兰式 : abcd - * + ef / -)
保存比遍历过程当中的节点相关性结果
前驱后继节点和左右孩子指示
lchild LTag data RTag rchild LTag 0 : lchild 域指示左孩子 1 : lchild 域指示前驱节点
RTag 0 : rchild 域指示右孩子 1 : rchild 域指示后继节点
typedef enum PointerTag {Link, Thread}; // 0 : 指针 1 : 线索
typedef struct BiThrNode {
TElemType data;
struct BiThrNode * lchild;
struct BiThrNode * rchild;
PointerTag LTag;
PointerTag RTag;
} BiThrNode, * BiThrTree;复制代码
typedef struct PTNode {
TElemType data;
int parent;
} PTNode;
typedef struct {
PTNode nodes[MAX_TREE_SIZE];
int r; // 根的位置
int n; // 节点数
} PTree;复制代码
typedef struct CTNode { // 孩子节点
struct CTNode * next;
int child;
} * ChildPtr;
typedef struct {
TElemType data;
ChildPtr firstchild; // 孩子链表头指针
} CTBox;
typedef struct {
CTBox nodes[MAX_TREE_SIZE];
int r; // 根的位置
int n; // 节点数
} CTree;复制代码
typedef struct CSNode {
ElemType data;
struct CSNode * firstchild;
struct CSNode * nextsibling;
} CSNode, * CSTree;复制代码
左孩子右兄弟(左右是对二叉树而言, 孩子兄弟是对森林而言, 下面同理)
左孩子转换成孩子, 右孩子转换成兄弟
第一棵树的根
先序遍历第一棵树中根节点的子树森林
先序遍历除第一棵树剩余的树构成的森林
中序遍历第一棵树中根节点的子树森林
第一棵树的根
中序遍历除第一棵树剩余的树构成的森林
typedef enum {DG, DN, UDG, UDN} GraphKind; // {有向图, 有向网, 无向图, 无向网}
typedef struct ArcCell {
VRType adj; // 顶点相关类型. 无权图 : 1/0 表示相邻与否 带权图 : 权值信息
InfoType * info; // 该弧相关的指针
} ArcCell, AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
typedef struct {
VertexType vexs[MAX_VERTEX_NUM]; // 顶点向量
AdjMatrix arcs; // 邻接矩阵
int vexnum; // 顶点数
int arcnum; // 弧数
GraphKind kind; // 图的种类标志
} MGraph;复制代码
表节点
adjvex nextarc info 头结点
data firstarc
typedef struct ArcNode {
int adjvex; // 该弧所指向顶点位置
struct ArcNode * nextarc; // 指向下一条弧的指针
InfoType * info; // 该弧相关信息的指针
} ArcNode;
typedef struct VNode {
VertexType data; // 顶点信息
ArcNode * firstarc; // 指向第一条依附该顶点的弧的指针
} VNode, AdjList[MAX_VERTEX_NUM];
typedef struct {
AdjList vertices;
int vexnum; // 顶点数
int arcnum; // 弧数
int kind; // 种类标记
} ALGraph;复制代码
弧节点
tailvex headvex hlink tlink info 顶点节点
data firstin firstout
typedef struct ArcBox {
int tailvex; // 该弧的尾顶点位置
int headvex; // 该弧的头顶点位置
struct ArcBox * hlink; // 弧头相同的弧的链域
struct ArcBox * tlink; // 弧尾相同的弧的链域
InfoType * info; // 该弧相关信息指针
} ArcBox;
typedef struct VexNode {
VertexType data;
ArcBox * firstin; // 指向该节点第一条入弧
ArcBox * firstout; // 指向该节点第一条出弧
} VexNode;
typedef struct {
VexNode xlist[MAX_VERTEX_NUM]; // 表头向量
int vexnum; // 有向图的当前顶点数
int arcnum; // 有向图的当前弧数
} OLGraph;复制代码
每一条边用一个节点表示
mark ivex ilink jvex jlink info 每一个顶点用一个节点表示
data firstedge
typedef enum {unvisited, visited} VisitIf;
typedef struct EBox {
VisitIf mark; // 访问标记
int ivex; // 依附顶点位置
int jvex; // 依附顶点位置
struct EBox * ilink; // 依附顶点的下一边
struct EBox * jlink; // 依附顶点的下一边
InfoType * info; // 该边的信息指针
} EBox;
typedef struct VexBox {
VertexType data;
EBox * firstedge; // 指向第一条依附该顶点的边
} VexBox;
typedef struct {
VexBox adjmulist[MAX_VERTEX_NUM];
int vexnum; // 无向图的顶点数
int edgenum; // 无向图的边数
} AMLGraph复制代码
以迷宫为例子(面试中被问到, 印象比较深入). 深度优先就是一条路走到黑, 因此返回的第一条路径不保证是最优解.
Boolean visited[MAX]; // 访问标志数组
Status (* VisiteFunc) (int v); // 韩阿叔变量
void DFSTraverse(Graph G, Status (* Visit)(int v)) { // 深度优先遍历
VisitFunc = Visit; // 使用全局变量 VisitFunc, 使 DFS 没必要设置函数指针参数
for (v = 0; v < G.vexnum; ++v) {
visited[v] = FALSE; // 访问数组标志初始化
}
for (v = 0; v < G.vexnum; ++v) {
if (!visited[v]) {
DFS(G, v); // 对未访问的顶点调用 DFS
}
}
}
void DFS(Graph G, int v) { // 从第 v 个顶点出发递归的深度优先遍历图 G.
visited[v] = TRUE;
VisitFunc(v); // 访问第 v 个顶点
for (w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w)) {
if (!visited[w]) {
DFS(G, w); // 对 v 的还没有访问的邻接顶点 w 递归调用 DFS.
}
}
}复制代码
有点层序遍历的意思, 在遍历完全部状况下(能够进行算法优化, 对有些状况进行舍弃)能够得出最优解.
void BFSTraverse(Graph G, Status (* Visit) (int v)) {
for (v= 0; v < G.vexnum; ++v) {
visited[v] = FALSE;
}
InitQueue(Q);
for (v = 0; v < G.vexnum; ++v) {
if (!visited[v]) {
visited[v] = TRUE;
Visit(v);
EnQueue(Q, v);
while (!QueueEmpty(Q)) {
DeQueue(Q, u);
for (w = FirstAdjVex(G, u); w >= 0; w = NextAdjVex(G, u, w)) {
// w 为 u 还没有访问的邻接顶点
if (!visited[w]) {
visited[w] = TRUE;
Visit(w);
EnQueue(Q, w);
} // if
} // for
} // while
} // if
} // for
} // BFSTraverse复制代码
// 如下待填
以点为主: 主要是分为两个集合, 一个是已加入的节点, 另外一个是未加入节点. 在未加入的节点集合中找到一个离已加入集合最近的节点加入. 直至全部节点被加入.
以边为主: 初始条件是把图的全部边去除变成 V 个连通图. 而后每次找一条代价最小的边加入, 确保每加入一条边连通图个数都减小一个(也就是确保无环路)。直至成一个连通图时就是最小生成树.
主要是维护一个表和一个已加入路径集合, 表记录从原点到每个点的当前最小权值. 若是已加入路径集合中的点经过某条路径对未加入集合中的点的最小权值有影响则更新该节点权值. 最后在每次更新完成后判断目前未加入集合中的最小权值节点加入集合, 再对该节点的边所达的节点作如上判断. 最终能够求出起点到每个点的全部最短路径.
主要是判断通过该点到达的临时目点的权值和该点目前权值(能够不考虑是否已经通过, 可是循环只会扫一遍因此没有什么影响)的大小来判断是否更新权值.
关键路径和拓扑排序 (KeyWord : 松弛)