FDS 重点梳理
一、 堆栈和队列 (Stack and Queue)
1. 堆栈:入栈/出栈 (Array-based Stack)
#define MAX_SIZE 100
typedef struct {
int data[MAX_SIZE];
int top;
} Stack;
void initStack(Stack *S) {
S->top = -1;
}
// 入栈 (Push)
int push(Stack *S, int val) {
if (S->top == MAX_SIZE - 1) return 0; // 栈满
S->data[++(S->top)] = val;
return 1;
}
// 出栈 (Pop)
int pop(Stack *S, int *val) {
if (S->top == -1) return 0; // 栈空
*val = S->data[(S->top)--];
return 1;
}
2. 队列:入队列/出队列 (Circular Queue)
typedef struct {
int data[MAX_SIZE];
int front;
int rear;
} Queue;
void initQueue(Queue *Q) {
Q->front = Q->rear = 0;
}
// 入队列 (Enqueue)
int enqueue(Queue *Q, int val) {
if ((Q->rear + 1) % MAX_SIZE == Q->front) return 0; // 队满 (牺牲一个单元)
Q->data[Q->rear] = val;
Q->rear = (Q->rear + 1) % MAX_SIZE;
return 1;
}
// 出队列 (Dequeue)
int dequeue(Queue *Q, int *val) {
if (Q->front == Q->rear) return 0; // 队空
*val = Q->data[Q->front];
Q->front = (Q->front + 1) % MAX_SIZE;
return 1;
}
二、 树 (Tree)
1. 二叉树的遍历 (Traversals)
typedef struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
} TreeNode;
// 递归:先/中/后序 (Preorder, Inorder, Postorder)
void preorder(TreeNode* root) {
if (!root) return;
printf("%d ", root->val); // 先序
preorder(root->left);
preorder(root->right);
}
void inorder(TreeNode* root) {
if (!root) return;
inorder(root->left);
printf("%d ", root->val); // 中序
inorder(root->right);
}
void postorder(TreeNode* root) {
if (!root) return;
postorder(root->left);
postorder(root->right);
printf("%d ", root->val); // 后序
}
// 非递归中序遍历 (利用前面的栈)
void inorderNonRecursive(TreeNode* root) {
TreeNode* stack[MAX_SIZE];
int top = -1;
TreeNode* curr = root;
while (curr != NULL || top != -1) {
while (curr != NULL) {
stack[++top] = curr; // 一直向左走并入栈
curr = curr->left;
}
if (top != -1) {
curr = stack[top--]; // 出栈并访问
printf("%d ", curr->val);
curr = curr->right; // 转向右子树
}
}
}
2. 堆 (Min-Heap):插入、删除
#define MAX_HEAP 100
typedef struct {
int data[MAX_HEAP];
int size;
} MinHeap;
// 插入 (Up-heap / Percolate up)
void insertHeap(MinHeap *H, int val) {
int i = ++(H->size); // 放在末尾
// i/2 是父节点。如果比父节点小,则父节点下移
for (; i > 1 && val < H->data[i / 2]; i /= 2) {
H->data[i] = H->data[i / 2];
}
H->data[i] = val;
}
// 删除最小元素 (Down-heap / Percolate down)
int deleteMin(MinHeap *H) {
int minItem = H->data[1]; // 根节点是最小的
int lastItem = H->data[H->size--]; // 取出最后一个元素
int child, i;
// 从根节点开始向下过滤
for (i = 1; i * 2 <= H->size; i = child) {
child = i * 2;
// 找到左右儿子中较小的一个
if (child != H->size && H->data[child + 1] < H->data[child])
child++;
if (lastItem > H->data[child])
H->data[i] = H->data[child]; // 小儿子上移
else
break;
}
H->data[i] = lastItem;
return minItem;
}
3. 二分查找树 (BST):查找、插入、删除
// 查找 (FindMin / FindMax)
TreeNode* findMin(TreeNode* root) {
if (root == NULL) return NULL;
while (root->left != NULL) root = root->left;
return root;
}
// 插入 (Insert)
TreeNode* insertBST(TreeNode* root, int val) {
if (root == NULL) {
root = (TreeNode*)malloc(sizeof(TreeNode));
root->val = val; root->left = root->right = NULL;
} else if (val < root->val) {
root->left = insertBST(root->left, val);
} else if (val > root->val) {
root->right = insertBST(root->right, val);
}
return root;
}
// 删除 (Delete)
TreeNode* deleteBST(TreeNode* root, int val) {
if (root == NULL) return NULL;
if (val < root->val) root->left = deleteBST(root->left, val);
else if (val > root->val) root->right = deleteBST(root->right, val);
else { // 找到节点
if (root->left && root->right) { // 有两个孩子
TreeNode* temp = findMin(root->right); // 找右子树最小值替换
root->val = temp->val;
root->right = deleteBST(root->right, root->val);
} else { // 只有一个孩子或无孩子
TreeNode* temp = root;
if (root->left == NULL) root = root->right;
else if (root->right == NULL) root = root->left;
free(temp);
}
}
return root;
}
4. 线段树 (Segment Tree):建树、查询、更新 (区间求和为例)
int tree[MAX_SIZE * 4];
int arr[MAX_SIZE];
// 建树
void buildSegTree(int node, int start, int end) {
if (start == end) {
tree[node] = arr[start];
return;
}
int mid = (start + end) / 2;
int leftNode = 2 * node;
int rightNode = 2 * node + 1;
buildSegTree(leftNode, start, mid);
buildSegTree(rightNode, mid + 1, end);
tree[node] = tree[leftNode] + tree[rightNode];
}
// 查询 (Query)
int querySegTree(int node, int start, int end, int L, int R) {
if (R < start || L > end) return 0; // 完全不在区间内
if (L <= start && end <= R) return tree[node]; // 完全包含
int mid = (start + end) / 2;
return querySegTree(2 * node, start, mid, L, R) +
querySegTree(2 * node + 1, mid + 1, end, L, R);
}
// 更新 (单点更新 Update)
void updateSegTree(int node, int start, int end, int idx, int val) {
if (start == end) {
tree[node] = val;
arr[idx] = val;
return;
}
int mid = (start + end) / 2;
if (start <= idx && idx <= mid)
updateSegTree(2 * node, start, mid, idx, val);
else
updateSegTree(2 * node + 1, mid + 1, end, idx, val);
tree[node] = tree[2 * node] + tree[2 * node + 1];
}
三、 图 (Graph)
1. 图的 DFS 与 BFS (基于邻接矩阵表示)
#define MAX_V 100
int G[MAX_V][MAX_V];
int visited[MAX_V];
int V; // 顶点数
// 深度优先搜索 (DFS)
void DFS(int v) {
visited[v] = 1;
printf("%d ", v);
for (int i = 0; i < V; i++) {
if (G[v][i] && !visited[i]) {
DFS(i);
}
}
}
// 广度优先搜索 (BFS)
void BFS(int start) {
int q[MAX_V], front = 0, rear = 0;
q[rear++] = start;
visited[start] = 1;
while (front < rear) {
int v = q[front++];
printf("%d ", v);
for (int i = 0; i < V; i++) {
if (G[v][i] && !visited[i]) {
visited[i] = 1;
q[rear++] = i;
}
}
}
}
2. Dijkstra Algorithm & Unweighted Shortest Path & Topological Sort
#define INF 999999
// 无权最短路径 (Unweighted Shortest Path - 本质是 BFS)
void unweighted(int start, int dist[]) {
int q[MAX_V], front = 0, rear = 0;
for(int i=0; i<V; i++) dist[i] = INF;
dist[start] = 0;
q[rear++] = start;
while(front < rear) {
int v = q[front++];
for(int w=0; w<V; w++) {
if(G[v][w] && dist[w] == INF) {
dist[w] = dist[v] + 1;
q[rear++] = w;
}
}
}
}
// 迪杰斯特拉算法 (Dijkstra - 有权图单源最短路)
void Dijkstra(int start, int dist[]) {
int known[MAX_V] = {0};
for (int i = 0; i < V; i++) dist[i] = INF;
dist[start] = 0;
for (int i = 0; i < V; i++) {
// 找未知集合中距离最小的顶点
int minD = INF, v = -1;
for (int j = 0; j < V; j++) {
if (!known[j] && dist[j] < minD) {
minD = dist[j]; v = j;
}
}
if (v == -1) break;
known[v] = 1;
// 更新邻接点
for (int w = 0; w < V; w++) {
if (!known[w] && G[v][w] > 0) {
if (dist[v] + G[v][w] < dist[w]) {
dist[w] = dist[v] + G[v][w];
}
}
}
}
}
// 拓扑排序 (Topological Sort)
void TopSort(int indegree[]) {
int q[MAX_V], front = 0, rear = 0;
int count = 0;
// 将所有入度为0的顶点入队
for (int i = 0; i < V; i++) {
if (indegree[i] == 0) q[rear++] = i;
}
while (front < rear) {
int v = q[front++];
printf("%d ", v);
count++;
// 将所有邻接点入度减1
for (int w = 0; w < V; w++) {
if (G[v][w]) {
if (--indegree[w] == 0) q[rear++] = w;
}
}
}
if (count != V) printf("Graph has a cycle!\n");
}
四、 排序 (Sorting)
void swap(int *a, int *b) { int t = *a; *a = *b; *b = t; }
// 1. 基本插入排序 (Insertion Sort)
void insertionSort(int arr[], int n) {
for (int i = 1; i < n; i++) {
int temp = arr[i];
int j;
for (j = i; j > 0 && arr[j - 1] > temp; j--) {
arr[j] = arr[j - 1];
}
arr[j] = temp;
}
}
// 2. 希尔排序 (Shell Sort)
void shellSort(int arr[], int n) {
for (int gap = n / 2; gap > 0; gap /= 2) {
for (int i = gap; i < n; i++) {
int temp = arr[i];
int j;
for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) {
arr[j] = arr[j - gap];
}
arr[j] = temp;
}
}
}
// 3. 冒泡排序 (Bubble Sort)
void bubbleSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
int flag = 0; // 优化:无交换则已排序
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
swap(&arr[j], &arr[j + 1]);
flag = 1;
}
}
if (!flag) break;
}
}
// 4. 快速排序 (Quick Sort)
void quickSort(int arr[], int left, int right) {
if (left >= right) return;
int pivot = arr[left];
int i = left, j = right;
while (i < j) {
while (i < j && arr[j] >= pivot) j--;
arr[i] = arr[j];
while (i < j && arr[i] <= pivot) i++;
arr[j] = arr[i];
}
arr[i] = pivot;
quickSort(arr, left, i - 1);
quickSort(arr, i + 1, right);
}
// 5. 归并排序 (Merge Sort)
void merge(int arr[], int tmp[], int L, int R, int RightEnd) {
int LeftEnd = R - 1;
int tmpPos = L;
int numElements = RightEnd - L + 1;
while (L <= LeftEnd && R <= RightEnd) {
if (arr[L] <= arr[R]) tmp[tmpPos++] = arr[L++];
else tmp[tmpPos++] = arr[R++];
}
while (L <= LeftEnd) tmp[tmpPos++] = arr[L++];
while (R <= RightEnd) tmp[tmpPos++] = arr[R++];
for (int i = 0; i < numElements; i++, RightEnd--)
arr[RightEnd] = tmp[RightEnd];
}
void mSort(int arr[], int tmp[], int left, int right) {
if (left < right) {
int center = (left + right) / 2;
mSort(arr, tmp, left, center);
mSort(arr, tmp, center + 1, right);
merge(arr, tmp, left, center + 1, right);
}
}
void mergeSort(int arr[], int n) {
int *tmp = (int*)malloc(n * sizeof(int));
if (tmp != NULL) {
mSort(arr, tmp, 0, n - 1);
free(tmp);
}
}
// 6. 堆排序 (Heap Sort)
void percDown(int arr[], int i, int n) {
int child, tmp;
for (tmp = arr[i]; i * 2 + 1 < n; i = child) {
child = i * 2 + 1; // 左儿子 (0-indexed)
if (child != n - 1 && arr[child + 1] > arr[child]) child++;
if (tmp < arr[child]) arr[i] = arr[child];
else break;
}
arr[i] = tmp;
}
void heapSort(int arr[], int n) {
// 建立 Max-Heap
for (int i = n / 2 - 1; i >= 0; i--) percDown(arr, i, n);
// 排序
for (int i = n - 1; i > 0; i--) {
swap(&arr[0], &arr[i]); // 最大值放最后
percDown(arr, 0, i); // 调整剩余堆
}
}
五、 并查集 (Disjoint Set)
1. 路径压缩 (Path Compression) 与 按秩/大小合并 (Union-by-Size/Height)
#define MAX_SET 100
int parent[MAX_SET]; // 初始化时,parent[i] = -1 (代表它是根,且树大小为1)
// 查找并进行路径压缩 (Path Compression)
int find(int x) {
if (parent[x] < 0) return x; // 找到根
else {
// 递归寻找根并将当前节点直接连到根上
return parent[x] = find(parent[x]);
}
}
// 按大小合并 (Union-by-size)
void unionBySize(int root1, int root2) {
// root1 和 root2 是 find() 找到的根节点索引
if (root1 == root2) return;
// parent 数组存的是负的 size 数值
if (parent[root2] < parent[root1]) { // root2 的 size 更大 (更负)
parent[root2] += parent[root1]; // 更新规模
parent[root1] = root2; // root1 连到 root2 上
} else {
parent[root1] += parent[root2];
parent[root2] = root1;
}
}
// 按高度合并 (Union-by-height / rank)
void unionByHeight(int root1, int root2) {
if (root1 == root2) return;
// parent 数组存的是负的高度的估计值 (rank)
if (parent[root2] < parent[root1]) { // root2 更深
parent[root1] = root2;
} else {
if (parent[root1] == parent[root2]) {
parent[root1]--; // 高度相同,作为新根的 root1 高度 + 1 (变得更负)
}
parent[root2] = root1;
}
}