mirror of
https://github.com/krahets/hello-algo.git
synced 2025-11-03 13:43:06 +08:00
Bug fixes and improvements (#1318)
* Sync zh and zh-hant versions * Update en/README.md * Add a Q&A for chapter of introduction * Update the callout headers * Sync zh ang zh-hant versions * Bug fixes
This commit is contained in:
@ -12,7 +12,7 @@
|
||||
vector<Vertex *> graphBFS(GraphAdjList &graph, Vertex *startVet) {
|
||||
// 頂點走訪序列
|
||||
vector<Vertex *> res;
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
unordered_set<Vertex *> visited = {startVet};
|
||||
// 佇列用於實現 BFS
|
||||
queue<Vertex *> que;
|
||||
|
||||
@ -25,7 +25,7 @@ void dfs(GraphAdjList &graph, unordered_set<Vertex *> &visited, vector<Vertex *>
|
||||
vector<Vertex *> graphDFS(GraphAdjList &graph, Vertex *startVet) {
|
||||
// 頂點走訪序列
|
||||
vector<Vertex *> res;
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
unordered_set<Vertex *> visited;
|
||||
dfs(graph, visited, res, startVet);
|
||||
return res;
|
||||
|
||||
@ -12,7 +12,7 @@ public class graph_bfs {
|
||||
List<Vertex> GraphBFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 頂點走訪序列
|
||||
List<Vertex> res = [];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
HashSet<Vertex> visited = [startVet];
|
||||
// 佇列用於實現 BFS
|
||||
Queue<Vertex> que = new();
|
||||
|
||||
@ -26,7 +26,7 @@ public class graph_dfs {
|
||||
List<Vertex> GraphDFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 頂點走訪序列
|
||||
List<Vertex> res = [];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
HashSet<Vertex> visited = [];
|
||||
DFS(graph, visited, res, startVet);
|
||||
return res;
|
||||
|
||||
@ -14,7 +14,7 @@ List<Vertex> graphBFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 使用鄰接表來表示圖,以便獲取指定頂點的所有鄰接頂點
|
||||
// 頂點走訪序列
|
||||
List<Vertex> res = [];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
Set<Vertex> visited = {};
|
||||
visited.add(startVet);
|
||||
// 佇列用於實現 BFS
|
||||
|
||||
@ -30,7 +30,7 @@ void dfs(
|
||||
List<Vertex> graphDFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 頂點走訪序列
|
||||
List<Vertex> res = [];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
Set<Vertex> visited = {};
|
||||
dfs(graph, visited, res, startVet);
|
||||
return res;
|
||||
|
||||
@ -13,7 +13,7 @@ import (
|
||||
func graphBFS(g *graphAdjList, startVet Vertex) []Vertex {
|
||||
// 頂點走訪序列
|
||||
res := make([]Vertex, 0)
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
visited := make(map[Vertex]struct{})
|
||||
visited[startVet] = struct{}{}
|
||||
// 佇列用於實現 BFS, 使用切片模擬佇列
|
||||
|
||||
@ -28,7 +28,7 @@ func dfs(g *graphAdjList, visited map[Vertex]struct{}, res *[]Vertex, vet Vertex
|
||||
func graphDFS(g *graphAdjList, startVet Vertex) []Vertex {
|
||||
// 頂點走訪序列
|
||||
res := make([]Vertex, 0)
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
visited := make(map[Vertex]struct{})
|
||||
dfs(g, visited, &res, startVet)
|
||||
// 返回頂點走訪序列
|
||||
|
||||
@ -9,7 +9,7 @@ func twoSumBruteForce(nums []int, target int) []int {
|
||||
size := len(nums)
|
||||
// 兩層迴圈,時間複雜度為 O(n^2)
|
||||
for i := 0; i < size-1; i++ {
|
||||
for j := i + 1; i < size; j++ {
|
||||
for j := i + 1; j < size; j++ {
|
||||
if nums[i]+nums[j] == target {
|
||||
return []int{i, j}
|
||||
}
|
||||
|
||||
@ -15,7 +15,7 @@ public class graph_bfs {
|
||||
static List<Vertex> graphBFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 頂點走訪序列
|
||||
List<Vertex> res = new ArrayList<>();
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
Set<Vertex> visited = new HashSet<>();
|
||||
visited.add(startVet);
|
||||
// 佇列用於實現 BFS
|
||||
|
||||
@ -28,7 +28,7 @@ public class graph_dfs {
|
||||
static List<Vertex> graphDFS(GraphAdjList graph, Vertex startVet) {
|
||||
// 頂點走訪序列
|
||||
List<Vertex> res = new ArrayList<>();
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
Set<Vertex> visited = new HashSet<>();
|
||||
dfs(graph, visited, res, startVet);
|
||||
return res;
|
||||
|
||||
@ -12,7 +12,7 @@ const { Vertex } = require('../modules/Vertex');
|
||||
function graphBFS(graph, startVet) {
|
||||
// 頂點走訪序列
|
||||
const res = [];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
const visited = new Set();
|
||||
visited.add(startVet);
|
||||
// 佇列用於實現 BFS
|
||||
|
||||
@ -27,7 +27,7 @@ function dfs(graph, visited, res, vet) {
|
||||
function graphDFS(graph, startVet) {
|
||||
// 頂點走訪序列
|
||||
const res = [];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
const visited = new Set();
|
||||
dfs(graph, visited, res, startVet);
|
||||
return res;
|
||||
|
||||
63
zh-hant/codes/javascript/test_all.js
Normal file
63
zh-hant/codes/javascript/test_all.js
Normal file
@ -0,0 +1,63 @@
|
||||
import { bold, brightRed } from 'jsr:@std/fmt/colors';
|
||||
import { expandGlob } from 'jsr:@std/fs';
|
||||
import { relative, resolve } from 'jsr:@std/path';
|
||||
|
||||
/**
|
||||
* @typedef {import('jsr:@std/fs').WalkEntry} WalkEntry
|
||||
* @type {WalkEntry[]}
|
||||
*/
|
||||
const entries = [];
|
||||
|
||||
for await (const entry of expandGlob(
|
||||
resolve(import.meta.dirname, './chapter_*/*.js')
|
||||
)) {
|
||||
entries.push(entry);
|
||||
}
|
||||
|
||||
/** @type {{ status: Promise<Deno.CommandStatus>; stderr: ReadableStream<Uint8Array>; }[]} */
|
||||
const processes = [];
|
||||
|
||||
for (const file of entries) {
|
||||
const execute = new Deno.Command('node', {
|
||||
args: [relative(import.meta.dirname, file.path)],
|
||||
cwd: import.meta.dirname,
|
||||
stdin: 'piped',
|
||||
stdout: 'piped',
|
||||
stderr: 'piped',
|
||||
});
|
||||
|
||||
const process = execute.spawn();
|
||||
processes.push({ status: process.status, stderr: process.stderr });
|
||||
}
|
||||
|
||||
const results = await Promise.all(
|
||||
processes.map(async (item) => {
|
||||
const status = await item.status;
|
||||
return { status, stderr: item.stderr };
|
||||
})
|
||||
);
|
||||
|
||||
/** @type {ReadableStream<Uint8Array>[]} */
|
||||
const errors = [];
|
||||
|
||||
for (const result of results) {
|
||||
if (!result.status.success) {
|
||||
errors.push(result.stderr);
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Tested ${entries.length} files`);
|
||||
console.log(`Found exception in ${errors.length} files`);
|
||||
|
||||
if (errors.length) {
|
||||
console.log();
|
||||
|
||||
for (const error of errors) {
|
||||
const reader = error.getReader();
|
||||
const { value } = await reader.read();
|
||||
const decoder = new TextDecoder();
|
||||
console.log(`${bold(brightRed('error'))}: ${decoder.decode(value)}`);
|
||||
}
|
||||
|
||||
throw new Error('Test failed');
|
||||
}
|
||||
@ -14,7 +14,7 @@ import java.util.*
|
||||
fun graphBFS(graph: GraphAdjList, startVet: Vertex): MutableList<Vertex?> {
|
||||
// 頂點走訪序列
|
||||
val res = mutableListOf<Vertex?>()
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
val visited = HashSet<Vertex>()
|
||||
visited.add(startVet)
|
||||
// 佇列用於實現 BFS
|
||||
|
||||
@ -31,7 +31,7 @@ fun dfs(
|
||||
fun graphDFS(graph: GraphAdjList, startVet: Vertex?): MutableList<Vertex?> {
|
||||
// 頂點走訪序列
|
||||
val res = mutableListOf<Vertex?>()
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
val visited = HashSet<Vertex?>()
|
||||
dfs(graph, visited, res, startVet)
|
||||
return res
|
||||
|
||||
@ -18,7 +18,7 @@ def graph_bfs(graph: GraphAdjList, start_vet: Vertex) -> list[Vertex]:
|
||||
# 使用鄰接表來表示圖,以便獲取指定頂點的所有鄰接頂點
|
||||
# 頂點走訪序列
|
||||
res = []
|
||||
# 雜湊表,用於記錄已被訪問過的頂點
|
||||
# 雜湊集合,用於記錄已被訪問過的頂點
|
||||
visited = set[Vertex]([start_vet])
|
||||
# 佇列用於實現 BFS
|
||||
que = deque[Vertex]([start_vet])
|
||||
|
||||
@ -29,7 +29,7 @@ def graph_dfs(graph: GraphAdjList, start_vet: Vertex) -> list[Vertex]:
|
||||
# 使用鄰接表來表示圖,以便獲取指定頂點的所有鄰接頂點
|
||||
# 頂點走訪序列
|
||||
res = []
|
||||
# 雜湊表,用於記錄已被訪問過的頂點
|
||||
# 雜湊集合,用於記錄已被訪問過的頂點
|
||||
visited = set[Vertex]()
|
||||
dfs(graph, visited, res, start_vet)
|
||||
return res
|
||||
|
||||
@ -18,7 +18,7 @@ class ArrayStack:
|
||||
|
||||
def is_empty(self) -> bool:
|
||||
"""判斷堆疊是否為空"""
|
||||
return self._size == 0
|
||||
return self.size() == 0
|
||||
|
||||
def push(self, item: int):
|
||||
"""入堆疊"""
|
||||
|
||||
@ -22,7 +22,7 @@ class ArrayBinaryTree:
|
||||
"""串列容量"""
|
||||
return len(self._tree)
|
||||
|
||||
def val(self, i: int) -> int:
|
||||
def val(self, i: int) -> int | None:
|
||||
"""獲取索引為 i 節點的值"""
|
||||
# 若索引越界,則返回 None ,代表空位
|
||||
if i < 0 or i >= self.size():
|
||||
|
||||
116
zh-hant/codes/ruby/chapter_graph/graph_adjacency_list.rb
Normal file
116
zh-hant/codes/ruby/chapter_graph/graph_adjacency_list.rb
Normal file
@ -0,0 +1,116 @@
|
||||
=begin
|
||||
File: graph_adjacency_list.rb
|
||||
Created Time: 2024-04-25
|
||||
Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com)
|
||||
=end
|
||||
|
||||
require_relative '../utils/vertex'
|
||||
|
||||
### 基於鄰接表實現的無向圖類別 ###
|
||||
class GraphAdjList
|
||||
attr_reader :adj_list
|
||||
|
||||
### 建構子 ###
|
||||
def initialize(edges)
|
||||
# 鄰接表,key:頂點,value:該頂點的所有鄰接頂點
|
||||
@adj_list = {}
|
||||
# 新增所有頂點和邊
|
||||
for edge in edges
|
||||
add_vertex(edge[0])
|
||||
add_vertex(edge[1])
|
||||
add_edge(edge[0], edge[1])
|
||||
end
|
||||
end
|
||||
|
||||
### 獲取頂點數量 ###
|
||||
def size
|
||||
@adj_list.length
|
||||
end
|
||||
|
||||
### 新增邊 ###
|
||||
def add_edge(vet1, vet2)
|
||||
raise ArgumentError if !@adj_list.include?(vet1) || !@adj_list.include?(vet2)
|
||||
|
||||
@adj_list[vet1] << vet2
|
||||
@adj_list[vet2] << vet1
|
||||
end
|
||||
|
||||
### 刪除邊 ###
|
||||
def remove_edge(vet1, vet2)
|
||||
raise ArgumentError if !@adj_list.include?(vet1) || !@adj_list.include?(vet2)
|
||||
|
||||
# 刪除邊 vet1 - vet2
|
||||
@adj_list[vet1].delete(vet2)
|
||||
@adj_list[vet2].delete(vet1)
|
||||
end
|
||||
|
||||
### 新增頂點 ###
|
||||
def add_vertex(vet)
|
||||
return if @adj_list.include?(vet)
|
||||
|
||||
# 在鄰接表中新增一個新鏈結串列
|
||||
@adj_list[vet] = []
|
||||
end
|
||||
|
||||
### 刪除頂點 ###
|
||||
def remove_vertex(vet)
|
||||
raise ArgumentError unless @adj_list.include?(vet)
|
||||
|
||||
# 在鄰接表中刪除頂點 vet 對應的鏈結串列
|
||||
@adj_list.delete(vet)
|
||||
# 走訪其他頂點的鏈結串列,刪除所有包含 vet 的邊
|
||||
for vertex in @adj_list
|
||||
@adj_list[vertex.first].delete(vet) if @adj_list[vertex.first].include?(vet)
|
||||
end
|
||||
end
|
||||
|
||||
### 列印鄰接表 ###
|
||||
def __print__
|
||||
puts '鄰接表 ='
|
||||
for vertex in @adj_list
|
||||
tmp = @adj_list[vertex.first].map { |v| v.val }
|
||||
puts "#{vertex.first.val}: #{tmp},"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
### Driver Code ###
|
||||
if __FILE__ == $0
|
||||
# 初始化無向圖
|
||||
v = vals_to_vets([1, 3, 2, 5, 4])
|
||||
edges = [
|
||||
[v[0], v[1]],
|
||||
[v[0], v[3]],
|
||||
[v[1], v[2]],
|
||||
[v[2], v[3]],
|
||||
[v[2], v[4]],
|
||||
[v[3], v[4]],
|
||||
]
|
||||
graph = GraphAdjList.new(edges)
|
||||
puts "\n初始化後,圖為"
|
||||
graph.__print__
|
||||
|
||||
# 新增邊
|
||||
# 頂點 1,2 即 v[0],v[2]
|
||||
graph.add_edge(v[0], v[2])
|
||||
puts "\n新增邊 1-2 後,圖為"
|
||||
graph.__print__
|
||||
|
||||
# 刪除邊
|
||||
# 頂點 1,3 即 v[0],v[1]
|
||||
graph.remove_edge(v[0], v[1])
|
||||
puts "\n刪除邊 1-3 後,圖為"
|
||||
graph.__print__
|
||||
|
||||
# 新增頂點
|
||||
v5 = Vertex.new(6)
|
||||
graph.add_vertex(v5)
|
||||
puts "\n新增頂點 6 後,圖為"
|
||||
graph.__print__
|
||||
|
||||
# 刪除頂點
|
||||
# 頂點 3 即 v[1]
|
||||
graph.remove_vertex(v[1])
|
||||
puts "\n刪除頂點 3 後,圖為"
|
||||
graph.__print__
|
||||
end
|
||||
116
zh-hant/codes/ruby/chapter_graph/graph_adjacency_matrix.rb
Normal file
116
zh-hant/codes/ruby/chapter_graph/graph_adjacency_matrix.rb
Normal file
@ -0,0 +1,116 @@
|
||||
=begin
|
||||
File: graph_adjacency_matrix.rb
|
||||
Created Time: 2024-04-25
|
||||
Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com)
|
||||
=end
|
||||
|
||||
require_relative '../utils/print_util'
|
||||
|
||||
### 基於鄰接矩陣實現的無向圖類別 ###
|
||||
class GraphAdjMat
|
||||
def initialize(vertices, edges)
|
||||
### 建構子 ###
|
||||
# 頂點串列,元素代表“頂點值”,索引代表“頂點索引”
|
||||
@vertices = []
|
||||
# 鄰接矩陣,行列索引對應“頂點索引”
|
||||
@adj_mat = []
|
||||
# 新增頂點
|
||||
vertices.each { |val| add_vertex(val) }
|
||||
# 新增邊
|
||||
# 請注意,edges 元素代表頂點索引,即對應 vertices 元素索引
|
||||
edges.each { |e| add_edge(e[0], e[1]) }
|
||||
end
|
||||
|
||||
### 獲取頂點數量 ###
|
||||
def size
|
||||
@vertices.length
|
||||
end
|
||||
|
||||
### 新增頂點 ###
|
||||
def add_vertex(val)
|
||||
n = size
|
||||
# 向頂點串列中新增新頂點的值
|
||||
@vertices << val
|
||||
# 在鄰接矩陣中新增一行
|
||||
new_row = Array.new(n, 0)
|
||||
@adj_mat << new_row
|
||||
# 在鄰接矩陣中新增一列
|
||||
@adj_mat.each { |row| row << 0 }
|
||||
end
|
||||
|
||||
### 刪除頂點 ###
|
||||
def remove_vertex(index)
|
||||
raise IndexError if index >= size
|
||||
|
||||
# 在頂點串列中移除索引 index 的頂點
|
||||
@vertices.delete_at(index)
|
||||
# 在鄰接矩陣中刪除索引 index 的行
|
||||
@adj_mat.delete_at(index)
|
||||
# 在鄰接矩陣中刪除索引 index 的列
|
||||
@adj_mat.each { |row| row.delete_at(index) }
|
||||
end
|
||||
|
||||
### 新增邊 ###
|
||||
def add_edge(i, j)
|
||||
# 參數 i, j 對應 vertices 元素索引
|
||||
# 索引越界與相等處理
|
||||
if i < 0 || j < 0 || i >= size || j >= size || i == j
|
||||
raise IndexError
|
||||
end
|
||||
# 在無向圖中,鄰接矩陣關於主對角線對稱,即滿足 (i, j) == (j, i)
|
||||
@adj_mat[i][j] = 1
|
||||
@adj_mat[j][i] = 1
|
||||
end
|
||||
|
||||
### 刪除邊 ###
|
||||
def remove_edge(i, j)
|
||||
# 參數 i, j 對應 vertices 元素索引
|
||||
# 索引越界與相等處理
|
||||
if i < 0 || j < 0 || i >= size || j >= size || i == j
|
||||
raise IndexError
|
||||
end
|
||||
@adj_mat[i][j] = 0
|
||||
@adj_mat[j][i] = 0
|
||||
end
|
||||
|
||||
### 列印鄰接矩陣 ###
|
||||
def __print__
|
||||
puts "頂點串列 = #{@vertices}"
|
||||
puts '鄰接矩陣 ='
|
||||
print_matrix(@adj_mat)
|
||||
end
|
||||
end
|
||||
|
||||
### Driver Code ###
|
||||
if __FILE__ == $0
|
||||
# 初始化無向圖
|
||||
# 請注意,edges 元素代表頂點索引,即對應 vertices 元素索引
|
||||
vertices = [1, 3, 2, 5, 4]
|
||||
edges = [[0, 1], [0, 3], [1, 2], [2, 3], [2, 4], [3, 4]]
|
||||
graph = GraphAdjMat.new(vertices, edges)
|
||||
puts "\n初始化後,圖為"
|
||||
graph.__print__
|
||||
|
||||
# 新增邊
|
||||
# 頂點 1, 2 的索引分別為 0, 2
|
||||
graph.add_edge(0, 2)
|
||||
puts "\n新增邊 1-2 後,圖為"
|
||||
graph.__print__
|
||||
|
||||
# 刪除邊
|
||||
# 定點 1, 3 的索引分別為 0, 1
|
||||
graph.remove_edge(0, 1)
|
||||
puts "\n刪除邊 1-3 後,圖為"
|
||||
graph.__print__
|
||||
|
||||
# 新增頂點
|
||||
graph.add_vertex(6)
|
||||
puts "\n新增頂點 6 後,圖為"
|
||||
graph.__print__
|
||||
|
||||
# 刪除頂點
|
||||
# 頂點 3 的索引為 1
|
||||
graph.remove_vertex(1)
|
||||
puts "\n刪除頂點 3 後,圖為"
|
||||
graph.__print__
|
||||
end
|
||||
61
zh-hant/codes/ruby/chapter_graph/graph_bfs.rb
Normal file
61
zh-hant/codes/ruby/chapter_graph/graph_bfs.rb
Normal file
@ -0,0 +1,61 @@
|
||||
=begin
|
||||
File: graph_bfs.rb
|
||||
Created Time: 2024-04-25
|
||||
Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com)
|
||||
=end
|
||||
|
||||
require 'set'
|
||||
require_relative './graph_adjacency_list'
|
||||
require_relative '../utils/vertex'
|
||||
|
||||
### 廣度優先走訪 ###
|
||||
def graph_bfs(graph, start_vet)
|
||||
# 使用鄰接表來表示圖,以便獲取指定頂點的所有鄰接頂點
|
||||
# 頂點走訪序列
|
||||
res = []
|
||||
# 雜湊集合,用於記錄已被訪問過的頂點
|
||||
visited = Set.new([start_vet])
|
||||
# 佇列用於實現 BFS
|
||||
que = [start_vet]
|
||||
# 以頂點 vet 為起點,迴圈直至訪問完所有頂點
|
||||
while que.length > 0
|
||||
vet = que.shift # 佇列首頂點出隊
|
||||
res << vet # 記錄訪問頂點
|
||||
# 走訪該頂點的所有鄰接頂點
|
||||
for adj_vet in graph.adj_list[vet]
|
||||
next if visited.include?(adj_vet) # 跳過已被訪問的頂點
|
||||
que << adj_vet # 只入列未訪問的頂點
|
||||
visited.add(adj_vet) # 標記該頂點已被訪問
|
||||
end
|
||||
end
|
||||
# 返回頂點走訪序列
|
||||
res
|
||||
end
|
||||
|
||||
### Driver Code ###
|
||||
if __FILE__ == $0
|
||||
# 初始化無向圖
|
||||
v = vals_to_vets([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
|
||||
edges = [
|
||||
[v[0], v[1]],
|
||||
[v[0], v[3]],
|
||||
[v[1], v[2]],
|
||||
[v[1], v[4]],
|
||||
[v[2], v[5]],
|
||||
[v[3], v[4]],
|
||||
[v[3], v[6]],
|
||||
[v[4], v[5]],
|
||||
[v[4], v[7]],
|
||||
[v[5], v[8]],
|
||||
[v[6], v[7]],
|
||||
[v[7], v[8]],
|
||||
]
|
||||
graph = GraphAdjList.new(edges)
|
||||
puts "\n初始化後,圖為"
|
||||
graph.__print__
|
||||
|
||||
# 廣度優先走訪
|
||||
res = graph_bfs(graph, v.first)
|
||||
puts "\n廣度優先便利(BFS)頂點序列為"
|
||||
p vets_to_vals(res)
|
||||
end
|
||||
54
zh-hant/codes/ruby/chapter_graph/graph_dfs.rb
Normal file
54
zh-hant/codes/ruby/chapter_graph/graph_dfs.rb
Normal file
@ -0,0 +1,54 @@
|
||||
=begin
|
||||
File: graph_dfs.rb
|
||||
Created Time: 2024-04-25
|
||||
Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com)
|
||||
=end
|
||||
|
||||
require 'set'
|
||||
require_relative './graph_adjacency_list'
|
||||
require_relative '../utils/vertex'
|
||||
|
||||
### 深度優先走訪輔助函式 ###
|
||||
def dfs(graph, visited, res, vet)
|
||||
res << vet # 記錄訪問頂點
|
||||
visited.add(vet) # 標記該頂點已被訪問
|
||||
# 走訪該頂點的所有鄰接頂點
|
||||
for adj_vet in graph.adj_list[vet]
|
||||
next if visited.include?(adj_vet) # 跳過已被訪問的頂點
|
||||
# 遞迴訪問鄰接頂點
|
||||
dfs(graph, visited, res, adj_vet)
|
||||
end
|
||||
end
|
||||
|
||||
### 深度優先走訪 ###
|
||||
def graph_dfs(graph, start_vet)
|
||||
# 使用鄰接表來表示圖,以便獲取指定頂點的所有鄰接頂點
|
||||
# 頂點走訪序列
|
||||
res = []
|
||||
# 雜湊集合,用於記錄已被訪問過的頂點
|
||||
visited = Set.new
|
||||
dfs(graph, visited, res, start_vet)
|
||||
res
|
||||
end
|
||||
|
||||
### Driver Code ###
|
||||
if __FILE__ == $0
|
||||
# 初始化無向圖
|
||||
v = vals_to_vets([0, 1, 2, 3, 4, 5, 6])
|
||||
edges = [
|
||||
[v[0], v[1]],
|
||||
[v[0], v[3]],
|
||||
[v[1], v[2]],
|
||||
[v[2], v[5]],
|
||||
[v[4], v[5]],
|
||||
[v[5], v[6]],
|
||||
]
|
||||
graph = GraphAdjList.new(edges)
|
||||
puts "\n初始化後,圖為"
|
||||
graph.__print__
|
||||
|
||||
# 深度優先走訪
|
||||
res = graph_dfs(graph, v[0])
|
||||
puts "\n深度優先走訪(DFS)頂點序列為"
|
||||
p vets_to_vals(res)
|
||||
end
|
||||
147
zh-hant/codes/ruby/chapter_heap/my_heap.rb
Normal file
147
zh-hant/codes/ruby/chapter_heap/my_heap.rb
Normal file
@ -0,0 +1,147 @@
|
||||
=begin
|
||||
File: my_heap.rb
|
||||
Created Time: 2024-04-19
|
||||
Author: Blue Bean (lonnnnnnner@gmail.com)
|
||||
=end
|
||||
|
||||
require_relative '../utils/print_util'
|
||||
|
||||
### 大頂堆積 ###
|
||||
class MaxHeap
|
||||
attr_reader :max_heap
|
||||
|
||||
### 建構子,根據輸入串列建堆積 ###
|
||||
def initialize(nums)
|
||||
# 將串列元素原封不動新增進堆積
|
||||
@max_heap = nums
|
||||
# 堆積化除葉節點以外的其他所有節點
|
||||
parent(size - 1).downto(0) do |i|
|
||||
sift_down(i)
|
||||
end
|
||||
end
|
||||
|
||||
### 獲取左子節點的索引 ###
|
||||
def left(i)
|
||||
2 * i + 1
|
||||
end
|
||||
|
||||
### 獲取右子節點的索引 ###
|
||||
def right(i)
|
||||
2 * i + 2
|
||||
end
|
||||
|
||||
### 獲取父節點的索引 ###
|
||||
def parent(i)
|
||||
(i - 1) / 2 # 向下整除
|
||||
end
|
||||
|
||||
### 交換元素 ###
|
||||
def swap(i, j)
|
||||
@max_heap[i], @max_heap[j] = @max_heap[j], @max_heap[i]
|
||||
end
|
||||
|
||||
### 獲取堆積大小 ###
|
||||
def size
|
||||
@max_heap.length
|
||||
end
|
||||
|
||||
### 判斷堆積是否為空 ###
|
||||
def is_empty?
|
||||
size == 0
|
||||
end
|
||||
|
||||
### 訪問堆積頂元素 ###
|
||||
def peek
|
||||
@max_heap[0]
|
||||
end
|
||||
|
||||
### 元素入堆積 ###
|
||||
def push(val)
|
||||
# 新增節點
|
||||
@max_heap << val
|
||||
# 從底至頂堆積化
|
||||
sift_up(size - 1)
|
||||
end
|
||||
|
||||
### 從節點 i 開始,從底至頂堆積化 ###
|
||||
def sift_up(i)
|
||||
loop do
|
||||
# 獲取節點 i 的父節點
|
||||
p = parent(i)
|
||||
# 當“越過根節點”或“節點無須修復”時,結束堆積化
|
||||
break if p < 0 || @max_heap[i] <= @max_heap[p]
|
||||
# 交換兩節點
|
||||
swap(i, p)
|
||||
# 迴圈向上堆積化
|
||||
i = p
|
||||
end
|
||||
end
|
||||
|
||||
### 元素出堆積 ###
|
||||
def pop
|
||||
# 判空處理
|
||||
raise IndexError, "堆積為空" if is_empty?
|
||||
# 交換根節點與最右葉節點(交換首元素與尾元素)
|
||||
swap(0, size - 1)
|
||||
# 刪除節點
|
||||
val = @max_heap.pop
|
||||
# 從頂至底堆積化
|
||||
sift_down(0)
|
||||
# 返回堆積頂元素
|
||||
val
|
||||
end
|
||||
|
||||
### 從節點 i 開始,從頂至底堆積化 ###
|
||||
def sift_down(i)
|
||||
loop do
|
||||
# 判斷節點 i, l, r 中值最大的節點,記為 ma
|
||||
l, r, ma = left(i), right(i), i
|
||||
ma = l if l < size && @max_heap[l] > @max_heap[ma]
|
||||
ma = r if r < size && @max_heap[r] > @max_heap[ma]
|
||||
|
||||
# 若節點 i 最大或索引 l, r 越界,則無須繼續堆積化,跳出
|
||||
break if ma == i
|
||||
|
||||
# 交換兩節點
|
||||
swap(i, ma)
|
||||
# 迴圈向下堆積化
|
||||
i = ma
|
||||
end
|
||||
end
|
||||
|
||||
### 列印堆積(二元樹)###
|
||||
def __print__
|
||||
print_heap(@max_heap)
|
||||
end
|
||||
end
|
||||
|
||||
### Driver Code ###
|
||||
if __FILE__ == $0
|
||||
# 初始化大頂堆積
|
||||
max_heap = MaxHeap.new([9, 8, 6, 6, 7, 5, 2, 1, 4, 3, 6, 2])
|
||||
puts "\n輸入串列並建堆積後"
|
||||
max_heap.__print__
|
||||
|
||||
# 獲取堆積頂元素
|
||||
peek = max_heap.peek
|
||||
puts "\n堆積頂元素為 #{peek}"
|
||||
|
||||
# 元素入堆積
|
||||
val = 7
|
||||
max_heap.push(val)
|
||||
puts "\n元素 #{val} 入堆積後"
|
||||
max_heap.__print__
|
||||
|
||||
# 堆積頂元素出堆積
|
||||
peek = max_heap.pop
|
||||
puts "\n堆積頂元素 #{peek} 出堆積後"
|
||||
max_heap.__print__
|
||||
|
||||
# 獲取堆積大小
|
||||
size = max_heap.size
|
||||
puts "\n堆積元素數量為 #{size}"
|
||||
|
||||
# 判斷堆積是否為空
|
||||
is_empty = max_heap.is_empty?
|
||||
puts "\n堆積是否為空 #{is_empty}"
|
||||
end
|
||||
64
zh-hant/codes/ruby/chapter_heap/top_k.rb
Normal file
64
zh-hant/codes/ruby/chapter_heap/top_k.rb
Normal file
@ -0,0 +1,64 @@
|
||||
=begin
|
||||
File: top_k.rb
|
||||
Created Time: 2024-04-19
|
||||
Author: Blue Bean (lonnnnnnner@gmail.com)
|
||||
=end
|
||||
|
||||
require_relative "./my_heap"
|
||||
|
||||
### 元素入堆積 ###
|
||||
def push_min_heap(heap, val)
|
||||
# 元素取反
|
||||
heap.push(-val)
|
||||
end
|
||||
|
||||
### 元素出堆積 ###
|
||||
def pop_min_heap(heap)
|
||||
# 元素取反
|
||||
-heap.pop
|
||||
end
|
||||
|
||||
### 訪問堆積頂元素 ###
|
||||
def peek_min_heap(heap)
|
||||
# 元素取反
|
||||
-heap.peek
|
||||
end
|
||||
|
||||
### 取出堆積中元素 ###
|
||||
def get_min_heap(heap)
|
||||
# 將堆積中所有元素取反
|
||||
heap.max_heap.map { |x| -x }
|
||||
end
|
||||
|
||||
### 基於堆積查詢陣列中最大的 k 個元素 ###
|
||||
def top_k_heap(nums, k)
|
||||
# 初始化小頂堆積
|
||||
# 請注意:我們將堆積中所有元素取反,從而用大頂堆積來模擬小頂堆積
|
||||
max_heap = MaxHeap.new([])
|
||||
|
||||
# 將陣列的前 k 個元素入堆積
|
||||
for i in 0...k
|
||||
push_min_heap(max_heap, nums[i])
|
||||
end
|
||||
|
||||
# 從第 k+1 個元素開始,保持堆積的長度為 k
|
||||
for i in k...nums.length
|
||||
# 若當前元素大於堆積頂元素,則將堆積頂元素出堆積、當前元素入堆積
|
||||
if nums[i] > peek_min_heap(max_heap)
|
||||
pop_min_heap(max_heap)
|
||||
push_min_heap(max_heap, nums[i])
|
||||
end
|
||||
end
|
||||
|
||||
get_min_heap(max_heap)
|
||||
end
|
||||
|
||||
### Driver Code ###
|
||||
if __FILE__ == $0
|
||||
nums = [1, 7, 6, 3, 2]
|
||||
k = 3
|
||||
|
||||
res = top_k_heap(nums, k)
|
||||
puts "最大的 #{k} 個元素為"
|
||||
print_heap(res)
|
||||
end
|
||||
@ -4,6 +4,15 @@ Created Time: 2024-03-18
|
||||
Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com)
|
||||
=end
|
||||
|
||||
require_relative "./tree_node"
|
||||
|
||||
### 列印矩陣 ###
|
||||
def print_matrix(mat)
|
||||
s = []
|
||||
mat.each { |arr| s << " #{arr.to_s}" }
|
||||
puts "[\n#{s.join(",\n")}\n]"
|
||||
end
|
||||
|
||||
### 列印鏈結串列 ###
|
||||
def print_linked_list(head)
|
||||
list = []
|
||||
@ -61,3 +70,11 @@ end
|
||||
def print_hash_map(hmap)
|
||||
hmap.entries.each { |key, value| puts "#{key} -> #{value}" }
|
||||
end
|
||||
|
||||
### 列印堆積 ###
|
||||
def print_heap(heap)
|
||||
puts "堆積的陣列表示:#{heap}"
|
||||
puts "堆積的樹狀表示:"
|
||||
root = arr_to_tree(heap)
|
||||
print_tree(root)
|
||||
end
|
||||
|
||||
24
zh-hant/codes/ruby/utils/vertex.rb
Normal file
24
zh-hant/codes/ruby/utils/vertex.rb
Normal file
@ -0,0 +1,24 @@
|
||||
=begin
|
||||
File: vertex.rb
|
||||
Created Time: 2024-04-25
|
||||
Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com)
|
||||
=end
|
||||
|
||||
### 頂點類別 ###
|
||||
class Vertex
|
||||
attr_accessor :val
|
||||
|
||||
def initialize(val)
|
||||
@val = val
|
||||
end
|
||||
end
|
||||
|
||||
### 輸入值串列 vals ,返回頂點串列 vets ###
|
||||
def vals_to_vets(vals)
|
||||
Array.new(vals.length) { |i| Vertex.new(vals[i]) }
|
||||
end
|
||||
|
||||
### 輸入頂點串列 vets, 返回值串列 vals ###
|
||||
def vets_to_vals(vets)
|
||||
Array.new(vets.length) { |i| vets[i].val }
|
||||
end
|
||||
@ -15,7 +15,7 @@ use std::collections::{HashSet, VecDeque};
|
||||
fn graph_bfs(graph: GraphAdjList, start_vet: Vertex) -> Vec<Vertex> {
|
||||
// 頂點走訪序列
|
||||
let mut res = vec![];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
let mut visited = HashSet::new();
|
||||
visited.insert(start_vet);
|
||||
// 佇列用於實現 BFS
|
||||
|
||||
@ -31,7 +31,7 @@ fn dfs(graph: &GraphAdjList, visited: &mut HashSet<Vertex>, res: &mut Vec<Vertex
|
||||
fn graph_dfs(graph: GraphAdjList, start_vet: Vertex) -> Vec<Vertex> {
|
||||
// 頂點走訪序列
|
||||
let mut res = vec![];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
let mut visited = HashSet::new();
|
||||
dfs(&graph, &mut visited, &mut res, start_vet);
|
||||
|
||||
|
||||
@ -96,7 +96,7 @@ impl MaxHeap {
|
||||
// 交換根節點與最右葉節點(交換首元素與尾元素)
|
||||
self.swap(0, self.size() - 1);
|
||||
// 刪除節點
|
||||
let val = self.max_heap.remove(self.size() - 1);
|
||||
let val = self.max_heap.pop().unwrap();
|
||||
// 從頂至底堆積化
|
||||
self.sift_down(0);
|
||||
// 返回堆積頂元素
|
||||
|
||||
@ -12,7 +12,7 @@ import utils
|
||||
func graphBFS(graph: GraphAdjList, startVet: Vertex) -> [Vertex] {
|
||||
// 頂點走訪序列
|
||||
var res: [Vertex] = []
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
var visited: Set<Vertex> = [startVet]
|
||||
// 佇列用於實現 BFS
|
||||
var que: [Vertex] = [startVet]
|
||||
|
||||
@ -26,7 +26,7 @@ func dfs(graph: GraphAdjList, visited: inout Set<Vertex>, res: inout [Vertex], v
|
||||
func graphDFS(graph: GraphAdjList, startVet: Vertex) -> [Vertex] {
|
||||
// 頂點走訪序列
|
||||
var res: [Vertex] = []
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
var visited: Set<Vertex> = []
|
||||
dfs(graph: graph, visited: &visited, res: &res, vet: startVet)
|
||||
return res
|
||||
|
||||
@ -12,7 +12,7 @@ import { Vertex } from '../modules/Vertex';
|
||||
function graphBFS(graph: GraphAdjList, startVet: Vertex): Vertex[] {
|
||||
// 頂點走訪序列
|
||||
const res: Vertex[] = [];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
const visited: Set<Vertex> = new Set();
|
||||
visited.add(startVet);
|
||||
// 佇列用於實現 BFS
|
||||
|
||||
@ -31,7 +31,7 @@ function dfs(
|
||||
function graphDFS(graph: GraphAdjList, startVet: Vertex): Vertex[] {
|
||||
// 頂點走訪序列
|
||||
const res: Vertex[] = [];
|
||||
// 雜湊表,用於記錄已被訪問過的頂點
|
||||
// 雜湊集合,用於記錄已被訪問過的頂點
|
||||
const visited: Set<Vertex> = new Set();
|
||||
dfs(graph, visited, res, startVet);
|
||||
return res;
|
||||
|
||||
Reference in New Issue
Block a user