From 02df24e87436a1ef3c3d6db8fa00fad4074eae0f Mon Sep 17 00:00:00 2001 From: krahets Date: Wed, 15 Feb 2023 21:48:22 +0800 Subject: [PATCH] build --- chapter_graph/graph_operations.md | 184 +++++++++++++++++++++++++++++- chapter_heap/heap.md | 131 +++++++++++++++++++-- 2 files changed, 302 insertions(+), 13 deletions(-) diff --git a/chapter_graph/graph_operations.md b/chapter_graph/graph_operations.md index 15db2ccb2..7b29161b2 100644 --- a/chapter_graph/graph_operations.md +++ b/chapter_graph/graph_operations.md @@ -508,7 +508,104 @@ comments: true === "C#" ```csharp title="graph_adjacency_matrix.cs" - [class]{GraphAdjMat}-[func]{} + /* 基于邻接矩阵实现的无向图类 */ + class GraphAdjMat + { + List vertices; // 顶点列表,元素代表“顶点值”,索引代表“顶点索引” + List> adjMat; // 邻接矩阵,行列索引对应“顶点索引” + + /* 构造函数 */ + public GraphAdjMat(int[] vertices, int[][] edges) + { + this.vertices = new List(); + this.adjMat = new List>(); + // 添加顶点 + foreach (int val in vertices) + { + addVertex(val); + } + // 添加边 + // 请注意,edges 元素代表顶点索引,即对应 vertices 元素索引 + foreach (int[] e in edges) + { + addEdge(e[0], e[1]); + } + } + + /* 获取顶点数量 */ + public int size() + { + return vertices.Count; + } + + /* 添加顶点 */ + public void addVertex(int val) + { + int n = size(); + // 向顶点列表中添加新顶点的值 + vertices.Add(val); + // 在邻接矩阵中添加一行 + List newRow = new List(n); + for (int j = 0; j < n; j++) + { + newRow.Add(0); + } + adjMat.Add(newRow); + // 在邻接矩阵中添加一列 + foreach (List row in adjMat) + { + row.Add(0); + } + } + + /* 删除顶点 */ + public void removeVertex(int index) + { + if (index >= size()) + throw new IndexOutOfRangeException(); + // 在顶点列表中移除索引 index 的顶点 + vertices.RemoveAt(index); + // 在邻接矩阵中删除索引 index 的行 + adjMat.RemoveAt(index); + // 在邻接矩阵中删除索引 index 的列 + foreach (List row in adjMat) + { + row.RemoveAt(index); + } + } + + /* 添加边 */ + // 参数 i, j 对应 vertices 元素索引 + public void addEdge(int i, int j) + { + // 索引越界与相等处理 + if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) + throw new IndexOutOfRangeException(); + // 在无向图中,邻接矩阵沿主对角线对称,即满足 (i, j) == (j, i) + adjMat[i][j] = 1; + adjMat[j][i] = 1; + } + + /* 删除边 */ + // 参数 i, j 对应 vertices 元素索引 + public void removeEdge(int i, int j) + { + // 索引越界与相等处理 + if (i < 0 || j < 0 || i >= size() || j >= size() || i == j) + throw new IndexOutOfRangeException(); + adjMat[i][j] = 0; + adjMat[j][i] = 0; + } + + /* 打印邻接矩阵 */ + public void print() + { + Console.Write("顶点列表 = "); + PrintUtil.PrintList(vertices); + Console.WriteLine("邻接矩阵 ="); + PrintUtil.printMatrix(adjMat); + } + } ``` === "Swift" @@ -643,8 +740,7 @@ comments: true ```java title="graph_adjacency_list.java" /* 基于邻接表实现的无向图类 */ class GraphAdjList { - // 邻接表,使用哈希表来代替链表,以提升删除边、删除顶点的效率 - // 请注意,adjList 中的元素是 Vertex 对象 + // 邻接表,key: 顶点,value:该顶点的所有邻接结点 Map> adjList; /* 构造方法 */ @@ -1054,7 +1150,87 @@ comments: true === "C#" ```csharp title="graph_adjacency_list.cs" - [class]{GraphAdjList}-[func]{} + /* 基于邻接表实现的无向图类 */ + class GraphAdjList + { + // 邻接表,key: 顶点,value:该顶点的所有邻接结点 + Dictionary> adjList; + + /* 构造函数 */ + public GraphAdjList(Vertex[][] edges) + { + this.adjList = new Dictionary>(); + // 添加所有顶点和边 + foreach (Vertex[] edge in edges) + { + addVertex(edge[0]); + addVertex(edge[1]); + addEdge(edge[0], edge[1]); + } + } + + /* 获取顶点数量 */ + public int size() + { + return adjList.Count; + } + + /* 添加边 */ + public void addEdge(Vertex vet1, Vertex vet2) + { + if (!adjList.ContainsKey(vet1) || !adjList.ContainsKey(vet2) || vet1 == vet2) + throw new InvalidOperationException(); + // 添加边 vet1 - vet2 + adjList[vet1].Add(vet2); + adjList[vet2].Add(vet1); + } + + /* 删除边 */ + public void removeEdge(Vertex vet1, Vertex vet2) + { + if (!adjList.ContainsKey(vet1) || !adjList.ContainsKey(vet2) || vet1 == vet2) + throw new InvalidOperationException(); + // 删除边 vet1 - vet2 + adjList[vet1].Remove(vet2); + adjList[vet2].Remove(vet1); + } + + /* 添加顶点 */ + public void addVertex(Vertex vet) + { + if (adjList.ContainsKey(vet)) + return; + // 在邻接表中添加一个新链表 + adjList.Add(vet, new List()); + } + + /* 删除顶点 */ + public void removeVertex(Vertex vet) + { + if (!adjList.ContainsKey(vet)) + throw new InvalidOperationException(); + // 在邻接表中删除顶点 vet 对应的链表 + adjList.Remove(vet); + // 遍历其它顶点的链表,删除所有包含 vet 的边 + foreach (List list in adjList.Values) + { + list.Remove(vet); + } + } + + /* 打印邻接表 */ + public void print() + { + Console.WriteLine("邻接表 ="); + foreach (KeyValuePair> entry in adjList) + { + List tmp = new List(); + foreach (Vertex vertex in entry.Value) + tmp.Add(vertex.Val); + Console.WriteLine(entry.Key.Val + ": [" + string.Join(", ", tmp) + "],"); + } + } + } ``` === "Swift" diff --git a/chapter_heap/heap.md b/chapter_heap/heap.md index 8d9b5f146..b24758aa5 100644 --- a/chapter_heap/heap.md +++ b/chapter_heap/heap.md @@ -226,7 +226,38 @@ comments: true === "C#" ```csharp title="heap.cs" + /* 初始化堆 */ + // 初始化小顶堆 + PriorityQueue minHeap = new PriorityQueue(); + // 初始化大顶堆(使用 lambda 表达式修改 Comparator 即可) + PriorityQueue maxHeap = new PriorityQueue(Comparer.Create((x, y) => y - x)); + /* 元素入堆 */ + maxHeap.Enqueue(1, 1); + maxHeap.Enqueue(3, 3); + maxHeap.Enqueue(2, 2); + maxHeap.Enqueue(5, 5); + maxHeap.Enqueue(4, 4); + + /* 获取堆顶元素 */ + int peek = maxHeap.Peek();//5 + + /* 堆顶元素出堆 */ + // 出堆元素会形成一个从大到小的序列 + peek = maxHeap.Dequeue(); // 5 + peek = maxHeap.Dequeue(); // 4 + peek = maxHeap.Dequeue(); // 3 + peek = maxHeap.Dequeue(); // 2 + peek = maxHeap.Dequeue(); // 1 + + /* 获取堆大小 */ + int size = maxHeap.Count; + + /* 判断堆是否为空 */ + bool isEmpty = maxHeap.Count == 0; + + /* 输入列表并建堆 */ + minHeap = new PriorityQueue(new List<(int, int)> { (1, 1), (3, 3), (2, 2), (5, 5), (4, 4), }); ``` === "Swift" @@ -372,11 +403,23 @@ comments: true === "C#" ```csharp title="my_heap.cs" - [class]{MaxHeap}-[func]{left} + /* 获取左子结点索引 */ + int left(int i) + { + return 2 * i + 1; + } - [class]{MaxHeap}-[func]{right} + /* 获取右子结点索引 */ + int right(int i) + { + return 2 * i + 2; + } - [class]{MaxHeap}-[func]{parent} + /* 获取父结点索引 */ + int parent(int i) + { + return (i - 1) / 2; // 向下整除 + } ``` === "Swift" @@ -482,7 +525,11 @@ comments: true === "C#" ```csharp title="my_heap.cs" - [class]{MaxHeap}-[func]{peek} + /* 访问堆顶元素 */ + int peek() + { + return maxHeap[0]; + } ``` === "Swift" @@ -680,9 +727,31 @@ comments: true === "C#" ```csharp title="my_heap.cs" - [class]{MaxHeap}-[func]{push} + /* 元素入堆 */ + void push(int val) + { + // 添加结点 + maxHeap.Add(val); + // 从底至顶堆化 + siftUp(size() - 1); + } - [class]{MaxHeap}-[func]{siftUp} + /* 从结点 i 开始,从底至顶堆化 */ + void siftUp(int i) + { + while (true) + { + // 获取结点 i 的父结点 + int p = parent(i); + // 若“越过根结点”或“结点无需修复”,则结束堆化 + if (p < 0 || maxHeap[i] <= maxHeap[p]) + break; + // 交换两结点 + swap(i, p); + // 循环向上堆化 + i = p; + } + } ``` === "Swift" @@ -990,9 +1059,42 @@ comments: true === "C#" ```csharp title="my_heap.cs" - [class]{MaxHeap}-[func]{poll} + /* 元素出堆 */ + int poll() + { + // 判空处理 + if (isEmpty()) + throw new IndexOutOfRangeException(); + // 交换根结点与最右叶结点(即交换首元素与尾元素) + swap(0, size() - 1); + // 删除结点 + int val = maxHeap.Last(); + maxHeap.RemoveAt(size() - 1); + // 从顶至底堆化 + siftDown(0); + // 返回堆顶元素 + return val; + } - [class]{MaxHeap}-[func]{siftDown} + /* 从结点 i 开始,从顶至底堆化 */ + void siftDown(int i) + { + while (true) + { + // 判断结点 i, l, r 中值最大的结点,记为 ma + int l = left(i), r = right(i), ma = i; + if (l < size() && maxHeap[l] > maxHeap[ma]) + ma = l; + if (r < size() && maxHeap[r] > maxHeap[ma]) + ma = r; + // 若“结点 i 最大”或“越过叶结点”,则结束堆化 + if (ma == i) break; + // 交换两结点 + swap(i, ma); + // 循环向下堆化 + i = ma; + } + } ``` === "Swift" @@ -1169,7 +1271,18 @@ comments: true === "C#" ```csharp title="my_heap.cs" - [class]{MaxHeap}-[func]{MaxHeap} + /* 构造函数,根据输入列表建堆 */ + MaxHeap(IEnumerable nums) + { + // 将列表元素原封不动添加进堆 + maxHeap = new List(nums); + // 堆化除叶结点以外的其他所有结点 + var size = parent(this.size() - 1); + for (int i = size; i >= 0; i--) + { + siftDown(i); + } + } ``` === "Swift"